Bug 1872657 - Add fetchpriority support for <link rel=preload as=image>. r=valentin,smaug,manuel

This patch adds fetchpriority support for `<link rel=preload as=image>`
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
This commit is contained in:
Frédéric Wang 2024-02-27 06:33:48 +00:00
parent 61e25ea963
commit b005b82248
19 changed files with 149 additions and 81 deletions

View File

@ -12394,7 +12394,8 @@ already_AddRefed<nsIURI> 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<nsINode*>(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) {

View File

@ -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

View File

@ -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, /* <link preload> initiator */
aEarlyHintPreloaderId, aRequest);
aEarlyHintPreloaderId, aFetchPriority, aRequest);
}
// static

View File

@ -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

View File

@ -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<nsISupportsPriority> 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<nsISupportsPriority> 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<nsIChannel> 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<nsICacheInfoChannel> cacheChan(do_QueryInterface(channel));

View File

@ -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,

View File

@ -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));
}

View File

@ -11993,6 +11993,26 @@
value: 0
mirror: always
# Adjustments to apply to the internal priority of <link rel=preload as=images
# fetchpriority=low/high/auto> and <img fetchpriority=low/high/auto> 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 `<link rel="preconnect">` tag and `Link: rel=preconnect` response header
# handling.
- name: network.preconnect

View File

@ -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();

View File

@ -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,

View File

@ -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 `<image>` 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 =

View File

@ -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<nsIURI> baseURI = BaseURIForPreload();
bool isImgSet = false;
nsCOMPtr<nsIURI> uri =
@ -1270,7 +1271,7 @@ void nsHtml5TreeOpExecutor::PreloadImage(
// use document wide referrer policy
mDocument->MaybePreLoadImage(uri, aCrossOrigin,
GetPreloadReferrerPolicy(aImageReferrerPolicy),
isImgSet, aLinkPreload);
isImgSet, aLinkPreload, aFetchPriority);
}
}

View File

@ -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();

View File

@ -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,<dummy.image?1>; rel=preload; as=image; fetchpriority=low,True)|header(Link,<dummy.image?2>; rel=preload; as=image; fetchpriority=high,True)|header(Link,<dummy.image?3>; rel=preload; as=image; fetchpriority=auto,True)|header(Link,<dummy.image?4>; rel=preload; as=image,True): test different 'fetchpriority' values]
expected: FAIL
[image-dynamic-load.h2.html: test different 'fetchpriority' values]
expected: FAIL

View File

@ -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 = {};

View File

@ -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
},
];

View File

@ -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,

View File

@ -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,

View File

@ -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;