diff --git a/docshell/base/nsContextMenuInfo.cpp b/docshell/base/nsContextMenuInfo.cpp index 5052dda65550..0df163d38fa2 100644 --- a/docshell/base/nsContextMenuInfo.cpp +++ b/docshell/base/nsContextMenuInfo.cpp @@ -302,7 +302,8 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode* aDOMNode, doc->GetReferrerPolicy(), principal, nullptr, nullptr, nullptr, nullptr, nsIRequest::LOAD_NORMAL, nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE, - EmptyString(), aRequest); + EmptyString(), + /* aUseUrgentStartForChannel */ false, aRequest); } } diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index b463cdb5365a..bc989f0892b2 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -3512,7 +3512,8 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsINode* aContext, imgINotificationObserver* aObserver, int32_t aLoadFlags, const nsAString& initiatorType, imgRequestProxy** aRequest, - uint32_t aContentPolicyType) + uint32_t aContentPolicyType, + bool aUseUrgentStartForChannel) { NS_PRECONDITION(aURI, "Must have a URI"); NS_PRECONDITION(aContext, "Must have a context"); @@ -3551,6 +3552,7 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsINode* aContext, nullptr, /* cache key */ aContentPolicyType, /* content policy type */ initiatorType, /* the load initiator */ + aUseUrgentStartForChannel, /* urgent-start flag */ aRequest); } diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 707fb95c5289..0d418adccbdc 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -769,6 +769,8 @@ public: * @param aLoadFlags the load flags to use. See nsIRequest * @param [aContentPolicyType=nsIContentPolicy::TYPE_INTERNAL_IMAGE] (Optional) * The CP content type to use + * @param aUseUrgentStartForChannel,(Optional) a flag to mark on channel if it + * is triggered by user input events. * @return the imgIRequest for the image load */ static nsresult LoadImage(nsIURI* aURI, @@ -781,7 +783,8 @@ public: int32_t aLoadFlags, const nsAString& initiatorType, imgRequestProxy** aRequest, - uint32_t aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE); + uint32_t aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE, + bool aUseUrgentStartForChannel = false); /** * Obtain an image loader that respects the given document/channel's privacy status. diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index ec1dfa00bd46..2d2659bda401 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -44,6 +44,7 @@ #include "mozAutoDocUpdate.h" #include "mozilla/AsyncEventDispatcher.h" +#include "mozilla/EventStateManager.h" #include "mozilla/EventStates.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/ImageTracker.h" @@ -92,6 +93,7 @@ nsImageLoadingContent::nsImageLoadingContent() mUserDisabled(false), mSuppressed(false), mNewRequestsWillNeedAnimationReset(false), + mUseUrgentStartForChannel(false), mStateChangerDepth(0), mCurrentRequestRegistered(false), mPendingRequestRegistered(false) @@ -884,7 +886,12 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, this, loadFlags, content->LocalName(), getter_AddRefs(req), - policyType); + policyType, + mUseUrgentStartForChannel); + + // Reset the flag to avoid loading from XPCOM or somewhere again else without + // initiated by user interaction. + mUseUrgentStartForChannel = false; // Tell the document to forget about the image preload, if any, for // this URI, now that we might have another imgRequestProxy for it. diff --git a/dom/base/nsImageLoadingContent.h b/dom/base/nsImageLoadingContent.h index 8138151491f1..80e6136eed17 100644 --- a/dom/base/nsImageLoadingContent.h +++ b/dom/base/nsImageLoadingContent.h @@ -455,6 +455,13 @@ protected: */ bool mNewRequestsWillNeedAnimationReset : 1; + /** + * Flag to indicate whether the channel should be mark as urgent-start. + * It should be set in *Element and passed to nsContentUtils::LoadImage. + * True if we want to set nsIClassOfService::UrgentStart to the channel to + * get the response ASAP for better user responsiveness. + */ + bool mUseUrgentStartForChannel; private: /* The number of nested AutoStateChangers currently tracking our state. */ uint8_t mStateChangerDepth; diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index d9af850f40ed..f16af2511753 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -79,9 +79,11 @@ namespace dom { class ImageLoadTask : public Runnable { public: - ImageLoadTask(HTMLImageElement *aElement, bool aAlwaysLoad) + ImageLoadTask(HTMLImageElement *aElement, bool aAlwaysLoad, + bool aUseUrgentStartForChannel) : mElement(aElement) , mAlwaysLoad(aAlwaysLoad) + , mUseUrgentStartForChannel(aUseUrgentStartForChannel) { mDocument = aElement->OwnerDoc(); mDocument->BlockOnload(); @@ -91,6 +93,7 @@ public: { if (mElement->mPendingImageLoadTask == this) { mElement->mPendingImageLoadTask = nullptr; + mElement->mUseUrgentStartForChannel = mUseUrgentStartForChannel; mElement->LoadSelectedImage(true, true, mAlwaysLoad); } mDocument->UnblockOnload(false); @@ -106,6 +109,10 @@ private: RefPtr mElement; nsCOMPtr mDocument; bool mAlwaysLoad; + + // True if we want to set nsIClassOfService::UrgentStart to the channel to + // get the response ASAP for better user responsiveness. + bool mUseUrgentStartForChannel; }; HTMLImageElement::HTMLImageElement(already_AddRefed& aNodeInfo) @@ -410,6 +417,10 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, if (aName == nsGkAtoms::src && aNameSpaceID == kNameSpaceID_None && !aValue) { + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + // SetAttr handles setting src since it needs to catch img.src = // img.src, so we only need to handle the unset case if (InResponsiveMode()) { @@ -424,9 +435,17 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } } else if (aName == nsGkAtoms::srcset && aNameSpaceID == kNameSpaceID_None) { + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + PictureSourceSrcsetChanged(this, attrVal.String(), aNotify); } else if (aName == nsGkAtoms::sizes && aNameSpaceID == kNameSpaceID_None) { + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + PictureSourceSizesChanged(this, attrVal.String(), aNotify); } @@ -505,6 +524,10 @@ HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName, if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) { + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + if (InResponsiveMode()) { if (mResponsiveSelector && mResponsiveSelector->Content() == this) { @@ -562,6 +585,10 @@ HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName, // reload after the attribute has been set if the reload is triggerred by // cross origin changing. if (forceReload) { + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + if (InResponsiveMode()) { // per spec, full selection runs when this changes, even though // it doesn't directly affect the source selection @@ -600,6 +627,10 @@ HTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, mInDocResponsiveContent = true; } + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + // Run selection algorithm when an img element is inserted into a document // in order to react to changes in the environment. See note of // https://html.spec.whatwg.org/multipage/embedded-content.html#img-environment-changes @@ -612,6 +643,10 @@ HTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, // image load task is asynchronous we don't need to take special // care to avoid doing so when being filled by the parser. + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + // FIXME: Bug 660963 it would be nice if we could just have // ClearBrokenState update our state and do it fast... ClearBrokenState(); @@ -830,6 +865,10 @@ HTMLImageElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren) // reaches a stable state. if (!dest->InResponsiveMode() && dest->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) { + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + nsContentUtils::AddScriptRunner( NewRunnableMethod(dest, &HTMLImageElement::MaybeLoadImage)); } @@ -913,7 +952,9 @@ HTMLImageElement::QueueImageLoadTask(bool aAlwaysLoad) if (mPendingImageLoadTask) { alwaysLoad = alwaysLoad || mPendingImageLoadTask->AlwaysLoad(); } - RefPtr task = new ImageLoadTask(this, alwaysLoad); + RefPtr task = new ImageLoadTask(this, + alwaysLoad, + mUseUrgentStartForChannel); // The task checks this to determine if it was the last // queued event, and so earlier tasks are implicitly canceled. mPendingImageLoadTask = task; diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 20653682d213..4733c70f78a7 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -1361,6 +1361,10 @@ HTMLInputElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } else if (aNotify && aName == nsGkAtoms::src && mType == NS_FORM_INPUT_IMAGE) { if (aValue) { + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + LoadImage(aValue->String(), true, aNotify, eImageLoadType_Normal); } else { // Null value means the attr got unset; drop the image @@ -5101,6 +5105,10 @@ HTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, // Our base URI may have changed; claim that our URI changed, and the // nsImageLoadingContent will decide whether a new image load is warranted. if (HasAttr(kNameSpaceID_None, nsGkAtoms::src)) { + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + // FIXME: Bug 660963 it would be nice if we could just have // ClearBrokenState update our state and do it fast... ClearBrokenState(); @@ -5292,6 +5300,10 @@ HTMLInputElement::HandleTypeChange(uint8_t aNewType, bool aNotify) // whether we have an image to load; nsAutoString src; if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) { + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + LoadImage(src, false, aNotify, eImageLoadType_Normal); } } diff --git a/dom/svg/SVGFEImageElement.cpp b/dom/svg/SVGFEImageElement.cpp index 2eb267208862..437b4c605037 100644 --- a/dom/svg/SVGFEImageElement.cpp +++ b/dom/svg/SVGFEImageElement.cpp @@ -6,6 +6,7 @@ #include "mozilla/dom/SVGFEImageElement.h" +#include "mozilla/EventStateManager.h" #include "mozilla/EventStates.h" #include "mozilla/dom/SVGFEImageElementBinding.h" #include "mozilla/dom/SVGFilterElement.h" @@ -91,6 +92,9 @@ SVGFEImageElement::LoadSVGImage(bool aForce, bool aNotify) } } + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); return LoadImage(href, aForce, aNotify, eImageLoadType_Normal); } diff --git a/dom/svg/SVGImageElement.cpp b/dom/svg/SVGImageElement.cpp index b6d5a983660c..a0a0bf99354b 100644 --- a/dom/svg/SVGImageElement.cpp +++ b/dom/svg/SVGImageElement.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/ArrayUtils.h" +#include "mozilla/EventStateManager.h" #include "mozilla/EventStates.h" #include "mozilla/dom/SVGImageElement.h" @@ -133,6 +134,10 @@ SVGImageElement::LoadSVGImage(bool aForce, bool aNotify) if (baseURI && !href.IsEmpty()) NS_MakeAbsoluteURI(href, href, baseURI); + // Mark channel as urgent-start before load image if the image load is + // initaiated by a user interaction. + mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput(); + return LoadImage(href, aForce, aNotify, eImageLoadType_Normal); } diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index 29626727c6b9..419ff1128485 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -30,6 +30,7 @@ #include "nsStreamUtils.h" #include "nsIHttpChannel.h" #include "nsICacheInfoChannel.h" +#include "nsIClassOfService.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIProgressEventSink.h" @@ -2089,6 +2090,7 @@ imgLoader::LoadImageXPCOM(nsIURI* aURI, aCacheKey, aContentPolicyType, EmptyString(), + /* aUseUrgentStartForChannel */ false, &proxy); *_retval = proxy; return rv; @@ -2108,6 +2110,7 @@ imgLoader::LoadImage(nsIURI* aURI, nsISupports* aCacheKey, nsContentPolicyType aContentPolicyType, const nsAString& initiatorType, + bool aUseUrgentStartForChannel, imgRequestProxy** _retval) { MOZ_RELEASE_ASSERT(NS_IsMainThread()); @@ -2277,6 +2280,11 @@ imgLoader::LoadImage(nsIURI* aURI, ("[this=%p] imgLoader::LoadImage -- Created new imgRequest" " [request=%p]\n", this, request.get())); + nsCOMPtr cos(do_QueryInterface(newChannel)); + if (cos && aUseUrgentStartForChannel) { + cos->AddClassFlags(nsIClassOfService::UrgentStart); + } + nsCOMPtr channelLoadGroup; newChannel->GetLoadGroup(getter_AddRefs(channelLoadGroup)); rv = request->Init(aURI, aURI, /* aHadInsecureRedirect = */ false, diff --git a/image/imgLoader.h b/image/imgLoader.h index d01f6e4c255d..a2f64618a159 100644 --- a/image/imgLoader.h +++ b/image/imgLoader.h @@ -307,6 +307,7 @@ public: nsISupports* aCacheKey, nsContentPolicyType aContentPolicyType, const nsAString& initiatorType, + bool aUseUrgentStartForChannel, imgRequestProxy** _retval); MOZ_MUST_USE nsresult diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 5f5233279538..51acf122b652 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -2230,6 +2230,7 @@ nsImageFrame::LoadIcon(const nsAString& aSpec, nullptr, contentPolicyType, EmptyString(), + false, /* aUseUrgentStartForChannel */ aRequest); } diff --git a/widget/cocoa/nsMenuItemIconX.mm b/widget/cocoa/nsMenuItemIconX.mm index 1970eda9672a..00fb6e91a56d 100644 --- a/widget/cocoa/nsMenuItemIconX.mm +++ b/widget/cocoa/nsMenuItemIconX.mm @@ -319,6 +319,7 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI) mLoadingPrincipal, loadGroup, this, mContent, document, nsIRequest::LOAD_NORMAL, nullptr, mContentType, EmptyString(), + /* aUseUrgentStartForChannel */ false, getter_AddRefs(mIconRequest)); if (NS_FAILED(rv)) return rv;