From b005b822487744b82acce40fdefb7e674343b79d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Tue, 27 Feb 2024 06:33:48 +0000 Subject: [PATCH] Bug 1872657 - Add fetchpriority support for ``. r=valentin,smaug,manuel This patch adds fetchpriority support for `` and equivalent HTTP Link header. The fetchpriority value is passed from where the link is parsed down to `NewImageChannel` where the priority is initially set. Currently, the default equals PRIORITY_LOW, but is decreased a bit if LOAD_BACKGROUND flag is set (this is always the case for link preload images, see `imgLoader::LoadImage`). Later, the priority can be increased again depending on the category (see `imgRequest::BoostPriority`). In order to minimize the changes, the new calculation is to keep the initial setting to PRIORITY_LOW, adjust it using a new `network.fetchpriority.adjustments.*` preference depending on the fetchpriority attributes, and then preserve further adjustments for LOAD_BACKGROUND and `BoostPriority`. For the default value `fetchpriority=auto`, there is no adjustment i.e. we continue to start with PRIORITY_LOW. `fetchpriority=low/high` are respectively mapped to PRIORITY_LOW/PRIORITY_HIGH which is simple and consistent with the "Image" cases from Google's web.dev article https://web.dev/articles/fetch-priority. These values could of course be revised in the future after more experiments. This change is covered by the following tests below. The expectations is modified to match what is described above (i.e. map to PRIORITY_LOW or PRIORITY_HIGH with adjustment due to LOAD_BACKGROUND): - `link-initial-preload-image.h2.html` - `link-dynamic-preload-image.h2.html` - `kPipeHeaderPreloadImageLinks` Based on a patch by Mirko Brodesser (mbrodesser@igalia.com) Differential Revision: https://phabricator.services.mozilla.com/D197493 --- dom/base/Document.cpp | 13 ++-- dom/base/Document.h | 5 +- dom/base/nsContentUtils.cpp | 5 +- dom/base/nsContentUtils.h | 5 +- image/imgLoader.cpp | 77 +++++++++++-------- image/imgLoader.h | 22 +++--- layout/generic/nsImageFrame.cpp | 3 +- modules/libpref/init/StaticPrefList.yaml | 20 +++++ parser/html/nsHtml5SpeculativeLoad.cpp | 2 +- parser/html/nsHtml5SpeculativeLoad.h | 3 +- parser/html/nsHtml5TreeBuilderCppSupplement.h | 28 ++++++- parser/html/nsHtml5TreeOpExecutor.cpp | 5 +- parser/html/nsHtml5TreeOpExecutor.h | 3 +- .../fetchpriority/fetchpriority.h2.html.ini | 9 --- .../fetchpriority-adjustments.html | 1 + .../fetchpriority/support/link-tests-data.js | 8 +- uriloader/preload/PreloadService.cpp | 12 +-- uriloader/preload/PreloadService.h | 3 +- widget/IconLoader.cpp | 6 +- 19 files changed, 149 insertions(+), 81 deletions(-) diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index 2078e286b316..7a998c8a35cd 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -12394,7 +12394,8 @@ already_AddRefed Document::ResolvePreloadImage( void Document::PreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr, ReferrerPolicyEnum aReferrerPolicy, bool aIsImgSet, - bool aLinkPreload, uint64_t aEarlyHintPreloaderId) { + bool aLinkPreload, uint64_t aEarlyHintPreloaderId, + const nsAString& aFetchPriority) { nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL | nsContentUtils::CORSModeToLoadImageFlags( Element::StringToCORSMode(aCrossOriginAttr)); @@ -12415,7 +12416,8 @@ void Document::PreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr, nsresult rv = nsContentUtils::LoadImage( aUri, static_cast(this), this, NodePrincipal(), 0, referrerInfo, nullptr /* no observer */, loadFlags, initiator, getter_AddRefs(request), - policyType, false /* urgent */, aLinkPreload, aEarlyHintPreloaderId); + policyType, false /* urgent */, aLinkPreload, aEarlyHintPreloaderId, + nsGenericHTMLElement::ToFetchPriority(aFetchPriority)); // Pin image-reference to avoid evicting it from the img-cache before // the "real" load occurs. Unpinned in DispatchContentLoadedEvents and @@ -12428,7 +12430,8 @@ void Document::PreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr, void Document::MaybePreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr, ReferrerPolicyEnum aReferrerPolicy, - bool aIsImgSet, bool aLinkPreload) { + bool aIsImgSet, bool aLinkPreload, + const nsAString& aFetchPriority) { const CORSMode corsMode = dom::Element::StringToCORSMode(aCrossOriginAttr); if (aLinkPreload) { // Check if the image was already preloaded in this document to avoid @@ -12437,7 +12440,7 @@ void Document::MaybePreLoadImage(nsIURI* aUri, PreloadHashKey::CreateAsImage(aUri, NodePrincipal(), corsMode); if (!mPreloadService.PreloadExists(key)) { PreLoadImage(aUri, aCrossOriginAttr, aReferrerPolicy, aIsImgSet, - aLinkPreload, 0); + aLinkPreload, 0, aFetchPriority); } return; } @@ -12451,7 +12454,7 @@ void Document::MaybePreLoadImage(nsIURI* aUri, // Image not in cache - trigger preload PreLoadImage(aUri, aCrossOriginAttr, aReferrerPolicy, aIsImgSet, aLinkPreload, - 0); + 0, aFetchPriority); } void Document::MaybePreconnect(nsIURI* aOrigURI, mozilla::CORSMode aCORSMode) { diff --git a/dom/base/Document.h b/dom/base/Document.h index 6a2bd55a9caa..75cffe66be3d 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -2930,10 +2930,11 @@ class Document : public nsINode, */ void MaybePreLoadImage(nsIURI* uri, const nsAString& aCrossOriginAttr, ReferrerPolicyEnum aReferrerPolicy, bool aIsImgSet, - bool aLinkPreload); + bool aLinkPreload, const nsAString& aFetchPriority); void PreLoadImage(nsIURI* uri, const nsAString& aCrossOriginAttr, ReferrerPolicyEnum aReferrerPolicy, bool aIsImgSet, - bool aLinkPreload, uint64_t aEarlyHintPreloaderId); + bool aLinkPreload, uint64_t aEarlyHintPreloaderId, + const nsAString& aFetchPriority); /** * Called by images to forget an image preload when they start doing diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index d849b1392780..b668e3f86b00 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -4004,7 +4004,8 @@ nsresult nsContentUtils::LoadImage( int32_t aLoadFlags, const nsAString& initiatorType, imgRequestProxy** aRequest, nsContentPolicyType aContentPolicyType, bool aUseUrgentStartForChannel, bool aLinkPreload, - uint64_t aEarlyHintPreloaderId) { + uint64_t aEarlyHintPreloaderId, + mozilla::dom::FetchPriority aFetchPriority) { MOZ_ASSERT(aURI, "Must have a URI"); MOZ_ASSERT(aContext, "Must have a context"); MOZ_ASSERT(aLoadingDocument, "Must have a document"); @@ -4041,7 +4042,7 @@ nsresult nsContentUtils::LoadImage( initiatorType, /* the load initiator */ aUseUrgentStartForChannel, /* urgent-start flag */ aLinkPreload, /* initiator */ - aEarlyHintPreloaderId, aRequest); + aEarlyHintPreloaderId, aFetchPriority, aRequest); } // static diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 95744fe8315b..38736f979ba2 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -39,6 +39,7 @@ #include "mozilla/UniquePtr.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/FromParser.h" +#include "mozilla/dom/FetchPriority.h" #include "mozilla/fallible.h" #include "mozilla/gfx/Point.h" #include "nsCOMPtr.h" @@ -1026,7 +1027,9 @@ class nsContentUtils { nsContentPolicyType aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE, bool aUseUrgentStartForChannel = false, bool aLinkPreload = false, - uint64_t aEarlyHintPreloaderId = 0); + uint64_t aEarlyHintPreloaderId = 0, + mozilla::dom::FetchPriority aFetchPriority = + mozilla::dom::FetchPriority::Auto); /** * Obtain an image loader that respects the given document/channel's privacy diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index 737d99ff1512..eeb90cf374ac 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -32,6 +32,7 @@ #include "mozilla/StaticPrefs_network.h" #include "mozilla/StoragePrincipalHelper.h" #include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/FetchPriority.h" #include "mozilla/dom/nsMixedContentBlocker.h" #include "mozilla/image/ImageMemoryReporter.h" #include "mozilla/layers/CompositorManagerChild.h" @@ -815,6 +816,28 @@ static bool ValidateSecurityInfo(imgRequest* aRequest, /* aSendCSPViolationReports */ false); } +static void AdjustPriorityForImages(nsIChannel* aChannel, + nsLoadFlags aLoadFlags, + FetchPriority aFetchPriority) { + // Image channels are loaded by default with reduced priority. + if (nsCOMPtr supportsPriority = + do_QueryInterface(aChannel)) { + int32_t priority = nsISupportsPriority::PRIORITY_LOW; + + // Adjust priority according to fetchpriorty attribute. + if (StaticPrefs::network_fetchpriority_enabled()) { + priority += FETCH_PRIORITY_ADJUSTMENT_FOR(images, aFetchPriority); + } + + // Further reduce priority for background loads + if (aLoadFlags & nsIRequest::LOAD_BACKGROUND) { + ++priority; + } + + supportsPriority->AdjustPriority(priority); + } +} + static nsresult NewImageChannel( nsIChannel** aResult, // If aForcePrincipalCheckForCacheEntry is true, then we will @@ -828,7 +851,8 @@ static nsresult NewImageChannel( nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup, nsLoadFlags aLoadFlags, nsContentPolicyType aPolicyType, nsIPrincipal* aTriggeringPrincipal, nsINode* aRequestingNode, - bool aRespectPrivacy, uint64_t aEarlyHintPreloaderId) { + bool aRespectPrivacy, uint64_t aEarlyHintPreloaderId, + FetchPriority aFetchPriority) { MOZ_ASSERT(aResult); nsresult rv; @@ -948,17 +972,7 @@ static nsresult NewImageChannel( } } - // Image channels are loaded by default with reduced priority. - nsCOMPtr p = do_QueryInterface(*aResult); - if (p) { - uint32_t priority = nsISupportsPriority::PRIORITY_LOW; - - if (aLoadFlags & nsIRequest::LOAD_BACKGROUND) { - ++priority; // further reduce priority for background loads - } - - p->AdjustPriority(priority); - } + AdjustPriorityForImages(*aResult, aLoadFlags, aFetchPriority); // Create a new loadgroup for this new channel, using the old group as // the parent. The indirection keeps the channel insulated from cancels, @@ -1715,7 +1729,8 @@ bool imgLoader::ValidateRequestWithNewChannel( uint64_t aInnerWindowId, nsLoadFlags aLoadFlags, nsContentPolicyType aLoadPolicyType, imgRequestProxy** aProxyRequest, nsIPrincipal* aTriggeringPrincipal, CORSMode aCORSMode, bool aLinkPreload, - uint64_t aEarlyHintPreloaderId, bool* aNewChannelCreated) { + uint64_t aEarlyHintPreloaderId, FetchPriority aFetchPriority, + bool* aNewChannelCreated) { // now we need to insert a new channel request object in between the real // request and the proxy that basically delays loading the image until it // gets a 304 or figures out that this needs to be a new request @@ -1758,11 +1773,11 @@ bool imgLoader::ValidateRequestWithNewChannel( // cache. nsCOMPtr newChannel; bool forcePrincipalCheck; - rv = - NewImageChannel(getter_AddRefs(newChannel), &forcePrincipalCheck, aURI, - aInitialDocumentURI, aCORSMode, aReferrerInfo, aLoadGroup, - aLoadFlags, aLoadPolicyType, aTriggeringPrincipal, - aLoadingDocument, mRespectPrivacy, aEarlyHintPreloaderId); + rv = NewImageChannel(getter_AddRefs(newChannel), &forcePrincipalCheck, aURI, + aInitialDocumentURI, aCORSMode, aReferrerInfo, + aLoadGroup, aLoadFlags, aLoadPolicyType, + aTriggeringPrincipal, aLoadingDocument, mRespectPrivacy, + aEarlyHintPreloaderId, aFetchPriority); if (NS_FAILED(rv)) { return false; } @@ -1841,7 +1856,7 @@ void imgLoader::NotifyObserversForCachedImage( imgCacheEntry* aEntry, imgRequest* request, nsIURI* aURI, nsIReferrerInfo* aReferrerInfo, Document* aLoadingDocument, nsIPrincipal* aTriggeringPrincipal, CORSMode aCORSMode, - uint64_t aEarlyHintPreloaderId) { + uint64_t aEarlyHintPreloaderId, FetchPriority aFetchPriority) { if (aEntry->HasNotified()) { return; } @@ -1860,7 +1875,7 @@ void imgLoader::NotifyObserversForCachedImage( getter_AddRefs(newChannel), &forcePrincipalCheck, aURI, nullptr, aCORSMode, aReferrerInfo, nullptr, 0, nsIContentPolicy::TYPE_INTERNAL_IMAGE, aTriggeringPrincipal, - aLoadingDocument, mRespectPrivacy, aEarlyHintPreloaderId); + aLoadingDocument, mRespectPrivacy, aEarlyHintPreloaderId, aFetchPriority); if (NS_FAILED(rv)) { return; } @@ -1885,7 +1900,8 @@ bool imgLoader::ValidateEntry( nsLoadFlags aLoadFlags, nsContentPolicyType aLoadPolicyType, bool aCanMakeNewChannel, bool* aNewChannelCreated, imgRequestProxy** aProxyRequest, nsIPrincipal* aTriggeringPrincipal, - CORSMode aCORSMode, bool aLinkPreload, uint64_t aEarlyHintPreloaderId) { + CORSMode aCORSMode, bool aLinkPreload, uint64_t aEarlyHintPreloaderId, + FetchPriority aFetchPriority) { LOG_SCOPE(gImgLog, "imgLoader::ValidateEntry"); // If the expiration time is zero, then the request has not gotten far enough @@ -2013,13 +2029,13 @@ bool imgLoader::ValidateEntry( request, aURI, aInitialDocumentURI, aReferrerInfo, aLoadGroup, aObserver, aLoadingDocument, innerWindowID, aLoadFlags, aLoadPolicyType, aProxyRequest, aTriggeringPrincipal, aCORSMode, aLinkPreload, - aEarlyHintPreloaderId, aNewChannelCreated); + aEarlyHintPreloaderId, aFetchPriority, aNewChannelCreated); } if (!validateRequest) { - NotifyObserversForCachedImage(aEntry, request, aURI, aReferrerInfo, - aLoadingDocument, aTriggeringPrincipal, - aCORSMode, aEarlyHintPreloaderId); + NotifyObserversForCachedImage( + aEntry, request, aURI, aReferrerInfo, aLoadingDocument, + aTriggeringPrincipal, aCORSMode, aEarlyHintPreloaderId, aFetchPriority); } return !validateRequest; @@ -2174,7 +2190,7 @@ imgLoader::LoadImageXPCOM( 0, aLoadGroup, aObserver, aLoadingDocument, aLoadingDocument, aLoadFlags, aCacheKey, aContentPolicyType, u""_ns, /* aUseUrgentStartForChannel */ false, /* aListPreload */ false, - 0, &proxy); + 0, FetchPriority::Auto, &proxy); *_retval = proxy; return rv; } @@ -2233,7 +2249,7 @@ nsresult imgLoader::LoadImage( nsISupports* aCacheKey, nsContentPolicyType aContentPolicyType, const nsAString& initiatorType, bool aUseUrgentStartForChannel, bool aLinkPreload, uint64_t aEarlyHintPreloaderId, - imgRequestProxy** _retval) { + FetchPriority aFetchPriority, imgRequestProxy** _retval) { VerifyCacheSizes(); NS_ASSERTION(aURI, "imgLoader::LoadImage -- NULL URI pointer"); @@ -2386,7 +2402,7 @@ nsresult imgLoader::LoadImage( aLoadGroup, aObserver, aLoadingDocument, requestFlags, aContentPolicyType, true, &newChannelCreated, _retval, aTriggeringPrincipal, corsmode, aLinkPreload, - aEarlyHintPreloaderId)) { + aEarlyHintPreloaderId, aFetchPriority)) { request = entry->GetRequest(); // If this entry has no proxies, its request has no reference to the @@ -2436,7 +2452,7 @@ nsresult imgLoader::LoadImage( aInitialDocumentURI, corsmode, aReferrerInfo, aLoadGroup, requestFlags, aContentPolicyType, aTriggeringPrincipal, aContext, mRespectPrivacy, - aEarlyHintPreloaderId); + aEarlyHintPreloaderId, aFetchPriority); if (NS_FAILED(rv)) { return NS_ERROR_FAILURE; } @@ -2650,7 +2666,8 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel* channel, if (ValidateEntry(entry, uri, nullptr, nullptr, nullptr, aObserver, aLoadingDocument, requestFlags, policyType, false, - nullptr, nullptr, nullptr, corsMode, false, 0)) { + nullptr, nullptr, nullptr, corsMode, false, 0, + FetchPriority::Auto)) { request = entry->GetRequest(); } else { nsCOMPtr cacheChan(do_QueryInterface(channel)); diff --git a/image/imgLoader.h b/image/imgLoader.h index c5155067903d..742351792533 100644 --- a/image/imgLoader.h +++ b/image/imgLoader.h @@ -37,6 +37,7 @@ class imgMemoryReporter; namespace mozilla { namespace dom { class Document; +enum class FetchPriority : uint8_t; } } // namespace mozilla @@ -238,7 +239,8 @@ class imgLoader final : public imgILoader, nsLoadFlags aLoadFlags, nsISupports* aCacheKey, nsContentPolicyType aContentPolicyType, const nsAString& initiatorType, bool aUseUrgentStartForChannel, bool aLinkPreload, - uint64_t aEarlyHintPreloaderId, imgRequestProxy** _retval); + uint64_t aEarlyHintPreloaderId, + mozilla::dom::FetchPriority aFetchPriority, imgRequestProxy** _retval); [[nodiscard]] nsresult LoadImageWithChannel( nsIChannel* channel, imgINotificationObserver* aObserver, @@ -349,7 +351,8 @@ class imgLoader final : public imgILoader, bool aCanMakeNewChannel, bool* aNewChannelCreated, imgRequestProxy** aProxyRequest, nsIPrincipal* aTriggeringPrincipal, mozilla::CORSMode, - bool aLinkPreload, uint64_t aEarlyHintPreloaderId); + bool aLinkPreload, uint64_t aEarlyHintPreloaderId, + mozilla::dom::FetchPriority aFetchPriority); bool ValidateRequestWithNewChannel( imgRequest* request, nsIURI* aURI, nsIURI* aInitialDocumentURI, @@ -359,15 +362,14 @@ class imgLoader final : public imgILoader, nsLoadFlags aLoadFlags, nsContentPolicyType aContentPolicyType, imgRequestProxy** aProxyRequest, nsIPrincipal* aLoadingPrincipal, mozilla::CORSMode, bool aLinkPreload, uint64_t aEarlyHintPreloaderId, - bool* aNewChannelCreated); + mozilla::dom::FetchPriority aFetchPriority, bool* aNewChannelCreated); - void NotifyObserversForCachedImage(imgCacheEntry* aEntry, imgRequest* request, - nsIURI* aURI, - nsIReferrerInfo* aReferrerInfo, - mozilla::dom::Document* aLoadingDocument, - nsIPrincipal* aLoadingPrincipal, - mozilla::CORSMode, - uint64_t aEarlyHintPreloaderId); + void NotifyObserversForCachedImage( + imgCacheEntry* aEntry, imgRequest* request, nsIURI* aURI, + nsIReferrerInfo* aReferrerInfo, mozilla::dom::Document* aLoadingDocument, + nsIPrincipal* aTriggeringPrincipal, mozilla::CORSMode, + uint64_t aEarlyHintPreloaderId, + mozilla::dom::FetchPriority aFetchPriority); // aURI may be different from imgRequest's URI in the case of blob URIs, as we // can share requests with different URIs. nsresult CreateNewProxyForRequest(imgRequest* aRequest, nsIURI* aURI, diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index e0a6243ed2ad..ddeff68f23b4 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -18,6 +18,7 @@ #include "mozilla/DebugOnly.h" #include "mozilla/Encoding.h" #include "mozilla/HTMLEditor.h" +#include "mozilla/dom/FetchPriority.h" #include "mozilla/dom/ImageTracker.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Helpers.h" @@ -268,7 +269,7 @@ BrokenImageIcon::BrokenImageIcon(const nsImageFrame& aFrame) { loadFlags, nullptr, contentPolicyType, u""_ns, false, /* aUseUrgentStartForChannel */ false, /* aLinkPreload */ - 0, getter_AddRefs(mImage)); + 0, FetchPriority::Auto, getter_AddRefs(mImage)); Unused << NS_WARN_IF(NS_FAILED(rv)); } diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 4e54ae1d3c53..23d03397d58b 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -11993,6 +11993,26 @@ value: 0 mirror: always +# Adjustments to apply to the internal priority of and with +# respect to the case when network.fetchpriority is disabled. +# - When the flag is disabled, Gecko currently sets priority to LOW. +# - When the flag is enabled, it respectively maps to LOW/LOW/HIGH. +# The image code can currently further adjust the priority for image load, see +# imgRequest::BoostPriority and AdjustPriorityForImages. +- name: network.fetchpriority.adjustments.images.low + type: int32_t + value: 0 + mirror: always +- name: network.fetchpriority.adjustments.images.high + type: int32_t + value: -20 + mirror: always +- name: network.fetchpriority.adjustments.images.auto + type: int32_t + value: 0 + mirror: always + # Enables `` tag and `Link: rel=preconnect` response header # handling. - name: network.preconnect diff --git a/parser/html/nsHtml5SpeculativeLoad.cpp b/parser/html/nsHtml5SpeculativeLoad.cpp index b85c31f655c6..4ddc15b957ab 100644 --- a/parser/html/nsHtml5SpeculativeLoad.cpp +++ b/parser/html/nsHtml5SpeculativeLoad.cpp @@ -45,7 +45,7 @@ void nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor) { aExecutor->PreloadImage( mUrlOrSizes, mCrossOrigin, mMedia, mCharsetOrSrcset, mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity, - mReferrerPolicyOrIntegrity, mIsLinkPreload); + mReferrerPolicyOrIntegrity, mIsLinkPreload, mFetchPriority); break; case eSpeculativeLoadOpenPicture: aExecutor->PreloadOpenPicture(); diff --git a/parser/html/nsHtml5SpeculativeLoad.h b/parser/html/nsHtml5SpeculativeLoad.h index d53d3a5b46cc..61ec92e6a4e9 100644 --- a/parser/html/nsHtml5SpeculativeLoad.h +++ b/parser/html/nsHtml5SpeculativeLoad.h @@ -75,7 +75,7 @@ class nsHtml5SpeculativeLoad { inline void InitImage(nsHtml5String aUrl, nsHtml5String aCrossOrigin, nsHtml5String aMedia, nsHtml5String aReferrerPolicy, nsHtml5String aSrcset, nsHtml5String aSizes, - bool aLinkPreload) { + bool aLinkPreload, nsHtml5String aFetchPriority) { MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadImage; @@ -92,6 +92,7 @@ class nsHtml5SpeculativeLoad { aSizes.ToString( mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity); mIsLinkPreload = aLinkPreload; + aFetchPriority.ToString(mFetchPriority); } inline void InitFont(nsHtml5String aUrl, nsHtml5String aCrossOrigin, diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index f39f456663d1..2eb7fa91ee52 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -215,9 +215,16 @@ nsIContentHandle* nsHtml5TreeBuilder::createElement( nsHtml5AttributeName::ATTR_REFERRERPOLICY); nsHtml5String sizes = aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES); + + // TODO: support the fetchpriority attribute in bug 1839313. + // Meanwhile the empty string is used since it's mapped to the + // auto state + // (https://html.spec.whatwg.org/#fetch-priority-attribute). + auto fetchPriority = nsHtml5String::EmptyString(); + mSpeculativeLoadQueue.AppendElement()->InitImage( url, crossOrigin, /* aMedia = */ nullptr, referrerPolicy, - srcset, sizes, false); + srcset, sizes, false, fetchPriority); } } else if (nsGkAtoms::source == aName) { nsHtml5String srcset = @@ -435,7 +442,7 @@ nsIContentHandle* nsHtml5TreeBuilder::createElement( nsHtml5AttributeName::ATTR_IMAGESIZES); mSpeculativeLoadQueue.AppendElement()->InitImage( url, crossOrigin, media, referrerPolicy, srcset, sizes, - true); + true, fetchPriority); } else if (as.LowerCaseEqualsASCII("font")) { mSpeculativeLoadQueue.AppendElement()->InitFont( url, crossOrigin, media, referrerPolicy, fetchPriority); @@ -487,8 +494,14 @@ nsIContentHandle* nsHtml5TreeBuilder::createElement( nsHtml5String url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER); if (url) { + // Fetch priority is not supported for video. Nullptr will map to + // the auto state + // (https://html.spec.whatwg.org/#fetch-priority-attribute). + auto fetchPriority = nullptr; + mSpeculativeLoadQueue.AppendElement()->InitImage( - url, nullptr, nullptr, nullptr, nullptr, nullptr, false); + url, nullptr, nullptr, nullptr, nullptr, nullptr, false, + fetchPriority); } } else if (nsGkAtoms::style == aName) { mImportScanner.Start(); @@ -543,8 +556,15 @@ nsIContentHandle* nsHtml5TreeBuilder::createElement( url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); } if (url) { + // Currently SVG's `` element lacks support for + // `fetchpriority`, see bug 1847712. Hence passing nullptr which + // maps to the auto state + // (https://html.spec.whatwg.org/#fetch-priority-attribute). + auto fetchPriority = nullptr; + mSpeculativeLoadQueue.AppendElement()->InitImage( - url, nullptr, nullptr, nullptr, nullptr, nullptr, false); + url, nullptr, nullptr, nullptr, nullptr, nullptr, false, + fetchPriority); } } else if (nsGkAtoms::script == aName) { nsHtml5TreeOperation* treeOp = diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index 3cb38dcf28a5..f2c47c42a6b6 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -1261,7 +1261,8 @@ void nsHtml5TreeOpExecutor::PreloadStyle( void nsHtml5TreeOpExecutor::PreloadImage( const nsAString& aURL, const nsAString& aCrossOrigin, const nsAString& aMedia, const nsAString& aSrcset, const nsAString& aSizes, - const nsAString& aImageReferrerPolicy, bool aLinkPreload) { + const nsAString& aImageReferrerPolicy, bool aLinkPreload, + const nsAString& aFetchPriority) { nsCOMPtr baseURI = BaseURIForPreload(); bool isImgSet = false; nsCOMPtr uri = @@ -1270,7 +1271,7 @@ void nsHtml5TreeOpExecutor::PreloadImage( // use document wide referrer policy mDocument->MaybePreLoadImage(uri, aCrossOrigin, GetPreloadReferrerPolicy(aImageReferrerPolicy), - isImgSet, aLinkPreload); + isImgSet, aLinkPreload, aFetchPriority); } } diff --git a/parser/html/nsHtml5TreeOpExecutor.h b/parser/html/nsHtml5TreeOpExecutor.h index 3a8225614770..169fa5a703a6 100644 --- a/parser/html/nsHtml5TreeOpExecutor.h +++ b/parser/html/nsHtml5TreeOpExecutor.h @@ -260,7 +260,8 @@ class nsHtml5TreeOpExecutor final void PreloadImage(const nsAString& aURL, const nsAString& aCrossOrigin, const nsAString& aMedia, const nsAString& aSrcset, const nsAString& aSizes, - const nsAString& aImageReferrerPolicy, bool aLinkPreload); + const nsAString& aImageReferrerPolicy, bool aLinkPreload, + const nsAString& aFetchPriority); void PreloadOpenPicture(); diff --git a/testing/web-platform/mozilla/meta/fetch/fetchpriority/fetchpriority.h2.html.ini b/testing/web-platform/mozilla/meta/fetch/fetchpriority/fetchpriority.h2.html.ini index d2ed4028dee8..e87dcd4c44e0 100644 --- a/testing/web-platform/mozilla/meta/fetch/fetchpriority/fetchpriority.h2.html.ini +++ b/testing/web-platform/mozilla/meta/fetch/fetchpriority/fetchpriority.h2.html.ini @@ -1,15 +1,6 @@ [fetchpriority.h2.html] lsan-allowed: [mozilla::net::AddStaticElement, InitializeStaticHeaders, mozilla::net::nvFIFO::nvFIFO, mozilla::net::Http2BaseCompressor::Http2BaseCompressor] # https://bugzilla.mozilla.org/show_bug.cgi?id=1759310 prefs: [network.fetchpriority.enabled:true] - [link-initial-preload-image.h2.html: test different 'fetchpriority' values] - expected: FAIL - - [link-dynamic-preload-image.h2.html: test different 'fetchpriority' values] - expected: FAIL - - [link-header.h2.html?pipe=|header(Link,; rel=preload; as=image; fetchpriority=low,True)|header(Link,; rel=preload; as=image; fetchpriority=high,True)|header(Link,; rel=preload; as=image; fetchpriority=auto,True)|header(Link,; rel=preload; as=image,True): test different 'fetchpriority' values] - expected: FAIL - [image-dynamic-load.h2.html: test different 'fetchpriority' values] expected: FAIL diff --git a/testing/web-platform/mozilla/tests/fetch/fetchpriority/fetchpriority-adjustments.html b/testing/web-platform/mozilla/tests/fetch/fetchpriority/fetchpriority-adjustments.html index 3027cddf310c..71bfbcc0b587 100644 --- a/testing/web-platform/mozilla/tests/fetch/fetchpriority/fetchpriority-adjustments.html +++ b/testing/web-platform/mozilla/tests/fetch/fetchpriority/fetchpriority-adjustments.html @@ -18,6 +18,7 @@ "link-preload-style": SpecialPowers.Ci.nsISupportsPriority.PRIORITY_HIGHEST, "non-deferred-style": SpecialPowers.Ci.nsISupportsPriority.PRIORITY_NORMAL, "global-fetch-api": SpecialPowers.Ci.nsISupportsPriority.PRIORITY_NORMAL, + "images": SpecialPowers.Ci.nsISupportsPriority.PRIORITY_LOW, }; for (const name in prioritiesWhenFetchpriorityDisabled) { let adjustments = {}; diff --git a/testing/web-platform/mozilla/tests/fetch/fetchpriority/support/link-tests-data.js b/testing/web-platform/mozilla/tests/fetch/fetchpriority/support/link-tests-data.js index d20de07fbabf..1606894e2e1e 100644 --- a/testing/web-platform/mozilla/tests/fetch/fetchpriority/support/link-tests-data.js +++ b/testing/web-platform/mozilla/tests/fetch/fetchpriority/support/link-tests-data.js @@ -113,16 +113,16 @@ const kExpectedRequestsOfLinkPreloadFontDisabled = [ const kExpectedRequestsOfLinkPreloadImage = [ { fileNameAndSuffix: "dummy.image?1", - internalPriority: SpecialPowers.Ci.nsISupportsPriority.PRIORITY_LOW + internalPriority: SpecialPowers.Ci.nsISupportsPriority.PRIORITY_LOW + 1 }, { fileNameAndSuffix: "dummy.image?2", - internalPriority: SpecialPowers.Ci.nsISupportsPriority.PRIORITY_HIGH + internalPriority: SpecialPowers.Ci.nsISupportsPriority.PRIORITY_HIGH + 1 }, { fileNameAndSuffix: "dummy.image?3", - internalPriority: SpecialPowers.Ci.nsISupportsPriority.PRIORITY_LOW + internalPriority: SpecialPowers.Ci.nsISupportsPriority.PRIORITY_LOW + 1 }, { fileNameAndSuffix: "dummy.image?4", - internalPriority: SpecialPowers.Ci.nsISupportsPriority.PRIORITY_LOW + internalPriority: SpecialPowers.Ci.nsISupportsPriority.PRIORITY_LOW + 1 }, ]; diff --git a/uriloader/preload/PreloadService.cpp b/uriloader/preload/PreloadService.cpp index 845c06ef3392..48cf9a364cee 100644 --- a/uriloader/preload/PreloadService.cpp +++ b/uriloader/preload/PreloadService.cpp @@ -226,7 +226,8 @@ PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce( break; } } else if (aAs.LowerCaseEqualsASCII("image")) { - PreloadImage(uri, aCORS, aReferrerPolicy, isImgSet, aEarlyHintPreloaderId); + PreloadImage(uri, aCORS, aReferrerPolicy, isImgSet, aEarlyHintPreloaderId, + aFetchPriority); } else if (aAs.LowerCaseEqualsASCII("font")) { PreloadFont(uri, aCORS, aReferrerPolicy, aEarlyHintPreloaderId, aFetchPriority); @@ -258,10 +259,11 @@ void PreloadService::PreloadScript( void PreloadService::PreloadImage(nsIURI* aURI, const nsAString& aCrossOrigin, const nsAString& aImageReferrerPolicy, bool aIsImgSet, - uint64_t aEarlyHintPreloaderId) { - mDocument->PreLoadImage(aURI, aCrossOrigin, - PreloadReferrerPolicy(aImageReferrerPolicy), - aIsImgSet, true, aEarlyHintPreloaderId); + uint64_t aEarlyHintPreloaderId, + const nsAString& aFetchPriority) { + mDocument->PreLoadImage( + aURI, aCrossOrigin, PreloadReferrerPolicy(aImageReferrerPolicy), + aIsImgSet, true, aEarlyHintPreloaderId, aFetchPriority); } void PreloadService::PreloadFont(nsIURI* aURI, const nsAString& aCrossOrigin, diff --git a/uriloader/preload/PreloadService.h b/uriloader/preload/PreloadService.h index 5f6566ea34cc..79f5e7b6d137 100644 --- a/uriloader/preload/PreloadService.h +++ b/uriloader/preload/PreloadService.h @@ -90,7 +90,8 @@ class PreloadService { void PreloadImage(nsIURI* aURI, const nsAString& aCrossOrigin, const nsAString& aImageReferrerPolicy, bool aIsImgSet, - uint64_t aEarlyHintPreloaderId); + uint64_t aEarlyHintPreloaderId, + const nsAString& aFetchPriority); void PreloadFont(nsIURI* aURI, const nsAString& aCrossOrigin, const nsAString& aReferrerPolicy, diff --git a/widget/IconLoader.cpp b/widget/IconLoader.cpp index 5c0488e3e21e..41d2a29bc741 100644 --- a/widget/IconLoader.cpp +++ b/widget/IconLoader.cpp @@ -9,6 +9,7 @@ #include "imgLoader.h" #include "imgRequestProxy.h" #include "mozilla/dom/Document.h" +#include "mozilla/dom/FetchPriority.h" #include "nsContentUtils.h" #include "nsIContent.h" #include "nsIContentPolicy.h" @@ -63,7 +64,7 @@ nsresult IconLoader::LoadIcon(nsIURI* aIconURI, nsINode* aNode, nullptr, nsIRequest::LOAD_NORMAL, nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE, u""_ns, /* aUseUrgentStartForChannel */ false, /* aLinkPreload */ false, 0, - getter_AddRefs(mIconRequest)); + dom::FetchPriority::Auto, getter_AddRefs(mIconRequest)); } else { // TODO: nsIContentPolicy::TYPE_INTERNAL_IMAGE may not be the correct // policy. See bug 1691868 for more details. @@ -72,7 +73,8 @@ nsresult IconLoader::LoadIcon(nsIURI* aIconURI, nsINode* aNode, aNode, document, nsIRequest::LOAD_NORMAL, nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE, u""_ns, /* aUseUrgentStartForChannel */ false, - /* aLinkPreload */ false, 0, getter_AddRefs(mIconRequest)); + /* aLinkPreload */ false, 0, dom::FetchPriority::Auto, + getter_AddRefs(mIconRequest)); } if (NS_FAILED(rv)) { return rv;