gecko-dev/parser/html/nsHtml5SpeculativeLoad.cpp
Frédéric Wang b005b82248 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
2024-02-27 06:33:48 +00:00

143 lines
5.4 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsHtml5SpeculativeLoad.h"
#include "mozilla/Encoding.h"
#include "nsHtml5TreeOpExecutor.h"
using namespace mozilla;
nsHtml5SpeculativeLoad::nsHtml5SpeculativeLoad()
: mOpCode(eSpeculativeLoadUninitialized),
mIsAsync(false),
mIsDefer(false),
mIsLinkPreload(false),
mIsError(false),
mEncoding(nullptr) {
MOZ_COUNT_CTOR(nsHtml5SpeculativeLoad);
new (&mCharsetOrSrcset) nsString;
}
nsHtml5SpeculativeLoad::~nsHtml5SpeculativeLoad() {
MOZ_COUNT_DTOR(nsHtml5SpeculativeLoad);
NS_ASSERTION(mOpCode != eSpeculativeLoadUninitialized,
"Uninitialized speculative load.");
if (!(mOpCode == eSpeculativeLoadSetDocumentCharset ||
mOpCode == eSpeculativeLoadMaybeComplainAboutCharset)) {
mCharsetOrSrcset.~nsString();
}
}
void nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor) {
switch (mOpCode) {
case eSpeculativeLoadBase:
aExecutor->SetSpeculationBase(mUrlOrSizes);
break;
case eSpeculativeLoadCSP:
aExecutor->AddSpeculationCSP(
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity);
break;
case eSpeculativeLoadMetaReferrer:
aExecutor->UpdateReferrerInfoFromMeta(mReferrerPolicyOrIntegrity);
break;
case eSpeculativeLoadImage:
aExecutor->PreloadImage(
mUrlOrSizes, mCrossOrigin, mMedia, mCharsetOrSrcset,
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity,
mReferrerPolicyOrIntegrity, mIsLinkPreload, mFetchPriority);
break;
case eSpeculativeLoadOpenPicture:
aExecutor->PreloadOpenPicture();
break;
case eSpeculativeLoadEndPicture:
aExecutor->PreloadEndPicture();
break;
case eSpeculativeLoadPictureSource:
aExecutor->PreloadPictureSource(
mCharsetOrSrcset, mUrlOrSizes,
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity,
mMedia);
break;
case eSpeculativeLoadScript:
aExecutor->PreloadScript(
mUrlOrSizes, mCharsetOrSrcset,
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity,
mCrossOrigin, mMedia, mNonce, mFetchPriority,
mReferrerPolicyOrIntegrity, mScriptReferrerPolicy, false, mIsAsync,
mIsDefer, mIsLinkPreload);
break;
case eSpeculativeLoadScriptFromHead:
aExecutor->PreloadScript(
mUrlOrSizes, mCharsetOrSrcset,
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity,
mCrossOrigin, mMedia, mNonce, mFetchPriority,
mReferrerPolicyOrIntegrity, mScriptReferrerPolicy, true, mIsAsync,
mIsDefer, mIsLinkPreload);
break;
case eSpeculativeLoadStyle:
aExecutor->PreloadStyle(
mUrlOrSizes, mCharsetOrSrcset, mCrossOrigin, mMedia,
mReferrerPolicyOrIntegrity, mNonce,
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity,
mIsLinkPreload, mFetchPriority);
break;
case eSpeculativeLoadManifest:
// TODO: remove this
break;
case eSpeculativeLoadSetDocumentCharset: {
MOZ_ASSERT(mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Length() == 1,
"Unexpected charset source string");
nsCharsetSource enumSource =
(nsCharsetSource)
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.First();
aExecutor->SetDocumentCharsetAndSource(WrapNotNull(mEncoding),
enumSource);
if (mCommitEncodingSpeculation) {
aExecutor->CommitToInternalEncoding();
}
} break;
case eSpeculativeLoadSetDocumentMode: {
NS_ASSERTION(mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Length() == 1,
"Unexpected document mode string");
nsHtml5DocumentMode mode =
(nsHtml5DocumentMode)
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.First();
aExecutor->SetDocumentMode(mode);
} break;
case eSpeculativeLoadPreconnect:
aExecutor->Preconnect(mUrlOrSizes, mCrossOrigin);
break;
case eSpeculativeLoadFont:
aExecutor->PreloadFont(mUrlOrSizes, mCrossOrigin, mMedia,
mReferrerPolicyOrIntegrity, mFetchPriority);
break;
case eSpeculativeLoadFetch:
aExecutor->PreloadFetch(mUrlOrSizes, mCrossOrigin, mMedia,
mReferrerPolicyOrIntegrity, mFetchPriority);
break;
case eSpeculativeLoadMaybeComplainAboutCharset: {
MOZ_ASSERT(mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.Length() == 2,
"Unexpected line number string");
uint32_t high =
(uint32_t)
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.CharAt(0);
uint32_t low =
(uint32_t)
mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity
.CharAt(1);
uint32_t line = (high << 16) | low;
aExecutor->MaybeComplainAboutCharset(mMsgId, mIsError, (int32_t)line);
} break;
default:
MOZ_ASSERT_UNREACHABLE("Bogus speculative load.");
break;
}
}