mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 16:22:00 +00:00
b005b82248
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
135 lines
4.0 KiB
C++
135 lines
4.0 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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 "mozilla/widget/IconLoader.h"
|
|
#include "gfxPlatform.h"
|
|
#include "imgIContainer.h"
|
|
#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"
|
|
|
|
using namespace mozilla;
|
|
|
|
namespace mozilla::widget {
|
|
|
|
NS_IMPL_ISUPPORTS(IconLoader, imgINotificationObserver)
|
|
|
|
IconLoader::IconLoader(Listener* aListener) : mListener(aListener) {}
|
|
|
|
IconLoader::~IconLoader() { Destroy(); }
|
|
|
|
void IconLoader::Destroy() {
|
|
if (mIconRequest) {
|
|
mIconRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
|
|
mIconRequest = nullptr;
|
|
}
|
|
mListener = nullptr;
|
|
}
|
|
|
|
nsresult IconLoader::LoadIcon(nsIURI* aIconURI, nsINode* aNode,
|
|
bool aIsInternalIcon) {
|
|
if (mIconRequest) {
|
|
// Another icon request is already in flight. Kill it.
|
|
mIconRequest->CancelWithReason(
|
|
NS_BINDING_ABORTED, "Another icon request is already in flight"_ns);
|
|
mIconRequest = nullptr;
|
|
}
|
|
|
|
if (!aNode) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
RefPtr<mozilla::dom::Document> document = aNode->OwnerDoc();
|
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup = document->GetDocumentLoadGroup();
|
|
if (!loadGroup) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
RefPtr<imgLoader> loader = nsContentUtils::GetImgLoaderForDocument(document);
|
|
if (!loader) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult rv;
|
|
if (aIsInternalIcon) {
|
|
rv = loader->LoadImage(
|
|
aIconURI, nullptr, nullptr, nullptr, 0, loadGroup, this, nullptr,
|
|
nullptr, nsIRequest::LOAD_NORMAL, nullptr,
|
|
nsIContentPolicy::TYPE_INTERNAL_IMAGE, u""_ns,
|
|
/* aUseUrgentStartForChannel */ false, /* aLinkPreload */ false, 0,
|
|
dom::FetchPriority::Auto, getter_AddRefs(mIconRequest));
|
|
} else {
|
|
// TODO: nsIContentPolicy::TYPE_INTERNAL_IMAGE may not be the correct
|
|
// policy. See bug 1691868 for more details.
|
|
rv = loader->LoadImage(
|
|
aIconURI, nullptr, nullptr, aNode->NodePrincipal(), 0, loadGroup, this,
|
|
aNode, document, nsIRequest::LOAD_NORMAL, nullptr,
|
|
nsIContentPolicy::TYPE_INTERNAL_IMAGE, u""_ns,
|
|
/* aUseUrgentStartForChannel */ false,
|
|
/* aLinkPreload */ false, 0, dom::FetchPriority::Auto,
|
|
getter_AddRefs(mIconRequest));
|
|
}
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
//
|
|
// imgINotificationObserver
|
|
//
|
|
|
|
void IconLoader::Notify(imgIRequest* aRequest, int32_t aType,
|
|
const nsIntRect* aData) {
|
|
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
|
|
// Make sure the image loaded successfully.
|
|
uint32_t status = imgIRequest::STATUS_ERROR;
|
|
if (NS_FAILED(aRequest->GetImageStatus(&status)) ||
|
|
(status & imgIRequest::STATUS_ERROR)) {
|
|
mIconRequest->CancelWithReason(NS_BINDING_ABORTED,
|
|
"GetImageStatus failed"_ns);
|
|
mIconRequest = nullptr;
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<imgIContainer> image;
|
|
aRequest->GetImage(getter_AddRefs(image));
|
|
MOZ_ASSERT(image);
|
|
|
|
// Ask the image to decode at its intrinsic size.
|
|
int32_t width = 0, height = 0;
|
|
image->GetWidth(&width);
|
|
image->GetHeight(&height);
|
|
image->RequestDecodeForSize(nsIntSize(width, height),
|
|
imgIContainer::FLAG_HIGH_QUALITY_SCALING);
|
|
}
|
|
|
|
if (aType == imgINotificationObserver::FRAME_COMPLETE) {
|
|
nsCOMPtr<imgIContainer> image;
|
|
aRequest->GetImage(getter_AddRefs(image));
|
|
MOZ_ASSERT(image);
|
|
|
|
if (mListener) {
|
|
mListener->OnComplete(image);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (aType == imgINotificationObserver::DECODE_COMPLETE) {
|
|
if (mIconRequest && mIconRequest == aRequest) {
|
|
mIconRequest->CancelWithReason(NS_BINDING_ABORTED, "DECODE_COMPLETE"_ns);
|
|
mIconRequest = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace mozilla::widget
|