mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-24 08:07:30 +09:00
implement lazy-loading
This commit is contained in:
parent
8594600d9b
commit
629f4db8fe
5 changed files with 179 additions and 0 deletions
|
|
@ -558,6 +558,7 @@ GK_ATOM(listing, "listing")
|
||||||
GK_ATOM(listitem, "listitem")
|
GK_ATOM(listitem, "listitem")
|
||||||
GK_ATOM(listrows, "listrows")
|
GK_ATOM(listrows, "listrows")
|
||||||
GK_ATOM(load, "load")
|
GK_ATOM(load, "load")
|
||||||
|
GK_ATOM(loading, "loading")
|
||||||
GK_ATOM(loadingprincipal, "loadingprincipal")
|
GK_ATOM(loadingprincipal, "loadingprincipal")
|
||||||
GK_ATOM(localedir, "localedir")
|
GK_ATOM(localedir, "localedir")
|
||||||
GK_ATOM(localName, "local-name")
|
GK_ATOM(localName, "local-name")
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@
|
||||||
#include "mozilla/net/ReferrerPolicy.h"
|
#include "mozilla/net/ReferrerPolicy.h"
|
||||||
|
|
||||||
#include "nsLayoutUtils.h"
|
#include "nsLayoutUtils.h"
|
||||||
|
#include "nsIScrollableFrame.h"
|
||||||
|
#include "nsITimer.h"
|
||||||
|
|
||||||
using namespace mozilla::net;
|
using namespace mozilla::net;
|
||||||
|
|
||||||
|
|
@ -110,6 +112,7 @@ HTMLImageElement::HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
||||||
: nsGenericHTMLElement(aNodeInfo)
|
: nsGenericHTMLElement(aNodeInfo)
|
||||||
, mForm(nullptr)
|
, mForm(nullptr)
|
||||||
, mInDocResponsiveContent(false)
|
, mInDocResponsiveContent(false)
|
||||||
|
, mLazyLoadAlwaysLoad(false)
|
||||||
, mCurrentDensity(1.0)
|
, mCurrentDensity(1.0)
|
||||||
{
|
{
|
||||||
// We start out broken
|
// We start out broken
|
||||||
|
|
@ -118,6 +121,7 @@ HTMLImageElement::HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
||||||
|
|
||||||
HTMLImageElement::~HTMLImageElement()
|
HTMLImageElement::~HTMLImageElement()
|
||||||
{
|
{
|
||||||
|
StopLazyLoadTimer();
|
||||||
DestroyImageLoadingContent();
|
DestroyImageLoadingContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -530,6 +534,15 @@ HTMLImageElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||||
// not). Force a new load of the image with the new referrerpolicy.
|
// not). Force a new load of the image with the new referrerpolicy.
|
||||||
forceReload = true;
|
forceReload = true;
|
||||||
}
|
}
|
||||||
|
} else if (aName == nsGkAtoms::loading &&
|
||||||
|
aNamespaceID == kNameSpaceID_None &&
|
||||||
|
aNotify) {
|
||||||
|
if (ShouldDeferImageLoad()) {
|
||||||
|
EnsureLazyLoadTimer();
|
||||||
|
} else {
|
||||||
|
StopLazyLoadTimer();
|
||||||
|
QueueImageLoadTask(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because we load image synchronously in non-responsive-mode, we need to do
|
// Because we load image synchronously in non-responsive-mode, we need to do
|
||||||
|
|
@ -661,6 +674,8 @@ HTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||||
void
|
void
|
||||||
HTMLImageElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
HTMLImageElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||||
{
|
{
|
||||||
|
StopLazyLoadTimer();
|
||||||
|
|
||||||
if (mForm) {
|
if (mForm) {
|
||||||
if (aNullParent || !FindAncestorForm(mForm)) {
|
if (aNullParent || !FindAncestorForm(mForm)) {
|
||||||
ClearForm(true);
|
ClearForm(true);
|
||||||
|
|
@ -714,6 +729,13 @@ HTMLImageElement::UpdateFormOwner()
|
||||||
void
|
void
|
||||||
HTMLImageElement::MaybeLoadImage()
|
HTMLImageElement::MaybeLoadImage()
|
||||||
{
|
{
|
||||||
|
if (ShouldDeferImageLoad()) {
|
||||||
|
EnsureLazyLoadTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StopLazyLoadTimer();
|
||||||
|
|
||||||
// Our base URI may have changed, or we may have had responsive parameters
|
// Our base URI may have changed, or we may have had responsive parameters
|
||||||
// change while not bound to the tree. Re-parse src/srcset and call LoadImage,
|
// change while not bound to the tree. Re-parse src/srcset and call LoadImage,
|
||||||
// which is a no-op if it resolves to the same effective URI without aForce.
|
// which is a no-op if it resolves to the same effective URI without aForce.
|
||||||
|
|
@ -929,6 +951,15 @@ HTMLImageElement::ClearForm(bool aRemoveFromForm)
|
||||||
void
|
void
|
||||||
HTMLImageElement::QueueImageLoadTask(bool aAlwaysLoad)
|
HTMLImageElement::QueueImageLoadTask(bool aAlwaysLoad)
|
||||||
{
|
{
|
||||||
|
if (ShouldDeferImageLoad()) {
|
||||||
|
mLazyLoadAlwaysLoad = mLazyLoadAlwaysLoad || aAlwaysLoad;
|
||||||
|
EnsureLazyLoadTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLazyLoadAlwaysLoad = false;
|
||||||
|
StopLazyLoadTimer();
|
||||||
|
|
||||||
// If loading is temporarily disabled, we don't want to queue tasks
|
// If loading is temporarily disabled, we don't want to queue tasks
|
||||||
// that may then run when loading is re-enabled.
|
// that may then run when loading is re-enabled.
|
||||||
if (!LoadingEnabled() || !this->OwnerDoc()->IsCurrentActiveDocument()) {
|
if (!LoadingEnabled() || !this->OwnerDoc()->IsCurrentActiveDocument()) {
|
||||||
|
|
@ -948,6 +979,126 @@ HTMLImageElement::QueueImageLoadTask(bool aAlwaysLoad)
|
||||||
nsContentUtils::RunInStableState(task.forget());
|
nsContentUtils::RunInStableState(task.forget());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HTMLImageElement::LazyLoadTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||||
|
{
|
||||||
|
HTMLImageElement* self = static_cast<HTMLImageElement*>(aClosure);
|
||||||
|
self->mLazyLoadTimer = nullptr;
|
||||||
|
self->MaybeLoadImageFromLazyTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
HTMLImageElement::ShouldLazyLoadImage() const
|
||||||
|
{
|
||||||
|
nsAutoString loading;
|
||||||
|
const_cast<HTMLImageElement*>(this)->GetAttr(kNameSpaceID_None, nsGkAtoms::loading, loading);
|
||||||
|
return loading.LowerCaseEqualsLiteral("lazy");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
HTMLImageElement::IsProbablyVisibleForLazyLoad() const
|
||||||
|
{
|
||||||
|
nsIFrame* frame = const_cast<HTMLImageElement*>(this)->GetPrimaryFrame(Flush_Layout);
|
||||||
|
if (!frame) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIDocument* doc = OwnerDoc();
|
||||||
|
if (!doc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIPresShell* presShell = doc->GetShell();
|
||||||
|
if (!presShell) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIScrollableFrame* rootScroll = presShell->GetRootScrollFrameAsScrollable();
|
||||||
|
if (!rootScroll) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIFrame* scrolledFrame = rootScroll->GetScrolledFrame();
|
||||||
|
if (!scrolledFrame) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRect frameRect = frame->GetVisualOverflowRectRelativeToSelf();
|
||||||
|
frameRect.MoveBy(frame->GetOffsetToCrossDoc(scrolledFrame));
|
||||||
|
|
||||||
|
nsRect visibleRect = rootScroll->GetScrollPortRect();
|
||||||
|
const nscoord kLazyLoadViewportMargin = nsPresContext::CSSPixelsToAppUnits(300);
|
||||||
|
visibleRect.Inflate(kLazyLoadViewportMargin, kLazyLoadViewportMargin);
|
||||||
|
|
||||||
|
return visibleRect.Intersects(frameRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
HTMLImageElement::ShouldDeferImageLoad() const
|
||||||
|
{
|
||||||
|
if (!ShouldLazyLoadImage()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsInComposedDoc()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !IsProbablyVisibleForLazyLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HTMLImageElement::EnsureLazyLoadTimer()
|
||||||
|
{
|
||||||
|
if (mLazyLoadTimer || !LoadingEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLazyLoadTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||||
|
if (!mLazyLoadTimer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poll while deferred so scrolling can promote offscreen images into load range.
|
||||||
|
mLazyLoadTimer->InitWithFuncCallback(LazyLoadTimerCallback, this, 250,
|
||||||
|
nsITimer::TYPE_ONE_SHOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HTMLImageElement::StopLazyLoadTimer()
|
||||||
|
{
|
||||||
|
mLazyLoadAlwaysLoad = false;
|
||||||
|
|
||||||
|
if (!mLazyLoadTimer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLazyLoadTimer->Cancel();
|
||||||
|
mLazyLoadTimer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HTMLImageElement::MaybeLoadImageFromLazyTimer()
|
||||||
|
{
|
||||||
|
if (!IsInComposedDoc() || !LoadingEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShouldDeferImageLoad()) {
|
||||||
|
EnsureLazyLoadTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InResponsiveMode()) {
|
||||||
|
bool alwaysLoad = mLazyLoadAlwaysLoad;
|
||||||
|
mLazyLoadAlwaysLoad = false;
|
||||||
|
QueueImageLoadTask(alwaysLoad);
|
||||||
|
} else {
|
||||||
|
mLazyLoadAlwaysLoad = false;
|
||||||
|
MaybeLoadImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
HTMLImageElement::HaveSrcsetOrInPicture()
|
HTMLImageElement::HaveSrcsetOrInPicture()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "imgRequestProxy.h"
|
#include "imgRequestProxy.h"
|
||||||
#include "Units.h"
|
#include "Units.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
#include "nsITimer.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
class EventChainPreVisitor;
|
class EventChainPreVisitor;
|
||||||
|
|
@ -168,6 +169,14 @@ public:
|
||||||
{
|
{
|
||||||
SetHTMLAttr(nsGkAtoms::usemap, aUseMap, aError);
|
SetHTMLAttr(nsGkAtoms::usemap, aUseMap, aError);
|
||||||
}
|
}
|
||||||
|
void GetLoading(nsAString& aLoading)
|
||||||
|
{
|
||||||
|
GetHTMLAttr(nsGkAtoms::loading, aLoading);
|
||||||
|
}
|
||||||
|
void SetLoading(const nsAString& aLoading, ErrorResult& aError)
|
||||||
|
{
|
||||||
|
SetHTMLAttr(nsGkAtoms::loading, aLoading, aError);
|
||||||
|
}
|
||||||
void SetName(const nsAString& aName, ErrorResult& aError)
|
void SetName(const nsAString& aName, ErrorResult& aError)
|
||||||
{
|
{
|
||||||
SetHTMLAttr(nsGkAtoms::name, aName, aError);
|
SetHTMLAttr(nsGkAtoms::name, aName, aError);
|
||||||
|
|
@ -360,6 +369,15 @@ protected:
|
||||||
RefPtr<ResponsiveImageSelector> mResponsiveSelector;
|
RefPtr<ResponsiveImageSelector> mResponsiveSelector;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void LazyLoadTimerCallback(nsITimer* aTimer, void* aClosure);
|
||||||
|
|
||||||
|
bool ShouldLazyLoadImage() const;
|
||||||
|
bool IsProbablyVisibleForLazyLoad() const;
|
||||||
|
bool ShouldDeferImageLoad() const;
|
||||||
|
void EnsureLazyLoadTimer();
|
||||||
|
void StopLazyLoadTimer();
|
||||||
|
void MaybeLoadImageFromLazyTimer();
|
||||||
|
|
||||||
bool SourceElementMatches(nsIContent* aSourceNode);
|
bool SourceElementMatches(nsIContent* aSourceNode);
|
||||||
|
|
||||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||||
|
|
@ -392,6 +410,8 @@ private:
|
||||||
RefPtr<ImageLoadTask> mPendingImageLoadTask;
|
RefPtr<ImageLoadTask> mPendingImageLoadTask;
|
||||||
nsCOMPtr<nsIPrincipal> mSrcTriggeringPrincipal;
|
nsCOMPtr<nsIPrincipal> mSrcTriggeringPrincipal;
|
||||||
nsCOMPtr<nsIPrincipal> mSrcsetTriggeringPrincipal;
|
nsCOMPtr<nsIPrincipal> mSrcsetTriggeringPrincipal;
|
||||||
|
nsCOMPtr<nsITimer> mLazyLoadTimer;
|
||||||
|
bool mLazyLoadAlwaysLoad;
|
||||||
|
|
||||||
// Last URL that was attempted to load by this element.
|
// Last URL that was attempted to load by this element.
|
||||||
nsCOMPtr<nsIURI> mLastSelectedSource;
|
nsCOMPtr<nsIURI> mLastSelectedSource;
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,11 @@ reflectString({
|
||||||
attribute: "useMap",
|
attribute: "useMap",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
reflectString({
|
||||||
|
element: document.createElement("img"),
|
||||||
|
attribute: "loading",
|
||||||
|
})
|
||||||
|
|
||||||
reflectBoolean({
|
reflectBoolean({
|
||||||
element: document.createElement("img"),
|
element: document.createElement("img"),
|
||||||
attribute: "isMap",
|
attribute: "isMap",
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ interface HTMLImageElement : HTMLElement {
|
||||||
attribute DOMString? crossOrigin;
|
attribute DOMString? crossOrigin;
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString useMap;
|
attribute DOMString useMap;
|
||||||
|
[CEReactions, SetterThrows]
|
||||||
|
attribute DOMString loading;
|
||||||
[CEReactions, SetterThrows, Pref="network.http.enablePerElementReferrer"]
|
[CEReactions, SetterThrows, Pref="network.http.enablePerElementReferrer"]
|
||||||
attribute DOMString referrerPolicy;
|
attribute DOMString referrerPolicy;
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue