From e69829766c0263a37a6c895b3897fe8f77fc1376 Mon Sep 17 00:00:00 2001 From: longsonr Date: Tue, 29 Apr 2025 03:35:00 +0000 Subject: [PATCH] Bug 1847712 - support fetchpriority for SVG image, feImage and script elements r=emilio Differential Revision: https://phabricator.services.mozilla.com/D246863 --- dom/base/Element.cpp | 31 ++++++++++++++++++ dom/base/Element.h | 5 +++ dom/html/HTMLImageElement.cpp | 2 +- dom/html/HTMLLinkElement.cpp | 2 +- dom/html/HTMLScriptElement.cpp | 2 +- dom/html/nsGenericHTMLElement.cpp | 32 ------------------- dom/html/nsGenericHTMLElement.h | 5 --- dom/svg/SVGFEImageElement.cpp | 19 ++++++++--- dom/svg/SVGFEImageElement.h | 9 ++++++ dom/svg/SVGImageElement.cpp | 10 ++++++ dom/svg/SVGImageElement.h | 9 ++++++ dom/svg/SVGScriptElement.cpp | 21 ++++++++---- dom/svg/SVGScriptElement.h | 4 +++ dom/webidl/SVGFEImageElement.webidl | 2 ++ dom/webidl/SVGImageElement.webidl | 2 ++ dom/webidl/SVGScriptElement.webidl | 2 ++ parser/html/nsHtml5TreeBuilderCppSupplement.h | 25 ++++++--------- .../attr-image-fetchpriority.html.ini | 2 ++ .../attr-script-fetchpriority.html.ini | 2 ++ .../fetchpriority/support/image-tests-data.js | 4 +-- .../support/script-tests-data.js | 16 +++++----- .../module-script-dynamic-insertion.h2.html | 7 ---- .../script-dynamic-insertion.h2.html | 12 +++---- .../embedded/attr-image-fetchpriority.html | 27 ++++++++++++++++ .../scripted/attr-script-fetchpriority.html | 27 ++++++++++++++++ 25 files changed, 187 insertions(+), 92 deletions(-) create mode 100644 testing/web-platform/meta/svg/embedded/attr-image-fetchpriority.html.ini create mode 100644 testing/web-platform/meta/svg/scripted/attr-script-fetchpriority.html.ini create mode 100644 testing/web-platform/tests/svg/embedded/attr-image-fetchpriority.html create mode 100644 testing/web-platform/tests/svg/scripted/attr-script-fetchpriority.html diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 917ab2b0041e..6b8c4d3b91e2 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -1148,6 +1148,37 @@ Element::Loading Element::LoadingState() const { return static_cast(val->GetEnumValue()); } +namespace { +// . +static constexpr nsAttrValue::EnumTable kFetchPriorityEnumTable[] = { + {kFetchPriorityAttributeValueHigh, FetchPriority::High}, + {kFetchPriorityAttributeValueLow, FetchPriority::Low}, + {kFetchPriorityAttributeValueAuto, FetchPriority::Auto}, + {nullptr, 0}}; + +// . +static const nsAttrValue::EnumTable* + kFetchPriorityEnumTableInvalidValueDefault = &kFetchPriorityEnumTable[2]; +} // namespace + +void Element::ParseFetchPriority(const nsAString& aValue, + nsAttrValue& aResult) { + aResult.ParseEnumValue(aValue, kFetchPriorityEnumTable, + false /* aCaseSensitive */, + kFetchPriorityEnumTableInvalidValueDefault); +} + +FetchPriority Element::GetFetchPriority() const { + const nsAttrValue* fetchpriorityAttribute = + GetParsedAttr(nsGkAtoms::fetchpriority); + if (fetchpriorityAttribute) { + MOZ_ASSERT(fetchpriorityAttribute->Type() == nsAttrValue::eEnum); + return FetchPriority(fetchpriorityAttribute->GetEnumValue()); + } + + return FetchPriority::Auto; +} + //---------------------------------------------------------------------- void Element::AddToIdTable(nsAtom* aId) { diff --git a/dom/base/Element.h b/dom/base/Element.h index 02e17c8a04ea..0958952c9d53 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -145,6 +145,7 @@ template class Optional; enum class CallerType : uint32_t; enum class ReferrerPolicy : uint8_t; +enum class FetchPriority : uint8_t; } // namespace dom } // namespace mozilla @@ -2216,6 +2217,10 @@ class Element : public FragmentOrElement { MOZ_CAN_RUN_SCRIPT nsresult PostHandleEventForLinks(EventChainPostVisitor& aVisitor); + mozilla::dom::FetchPriority GetFetchPriority() const; + + static void ParseFetchPriority(const nsAString& aValue, nsAttrValue& aResult); + public: /** * Check if this element is a link. This matches the CSS definition of the diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index 626c6bdafc36..421a8fc4d842 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -1295,7 +1295,7 @@ void HTMLImageElement::SetDensity(double aDensity) { } FetchPriority HTMLImageElement::GetFetchPriorityForImage() const { - return nsGenericHTMLElement::GetFetchPriority(); + return Element::GetFetchPriority(); } } // namespace mozilla::dom diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp index a8fb61e6dbe9..82ccb1b47fad 100644 --- a/dom/html/HTMLLinkElement.cpp +++ b/dom/html/HTMLLinkElement.cpp @@ -397,7 +397,7 @@ Maybe HTMLLinkElement::GetStyleSheetInfo() { alternate ? HasAlternateRel::Yes : HasAlternateRel::No, IsInline::No, mExplicitlyEnabled ? IsExplicitlyEnabled::Yes : IsExplicitlyEnabled::No, - GetFetchPriority(), + Element::GetFetchPriority(), }); } diff --git a/dom/html/HTMLScriptElement.cpp b/dom/html/HTMLScriptElement.cpp index 42654a6fa44d..1251f6f45ae5 100644 --- a/dom/html/HTMLScriptElement.cpp +++ b/dom/html/HTMLScriptElement.cpp @@ -318,7 +318,7 @@ CORSMode HTMLScriptElement::GetCORSMode() const { } FetchPriority HTMLScriptElement::GetFetchPriority() const { - return nsGenericHTMLElement::GetFetchPriority(); + return Element::GetFetchPriority(); } mozilla::dom::ReferrerPolicy HTMLScriptElement::GetReferrerPolicy() { diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index c0df6922290a..4e06753eb5d3 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -211,38 +211,6 @@ FetchPriority nsGenericHTMLElement::ToFetchPriority(const nsAString& aValue) { return FetchPriority(attrValue.GetEnumValue()); } -namespace { -// . -static constexpr nsAttrValue::EnumTable kFetchPriorityEnumTable[] = { - {kFetchPriorityAttributeValueHigh, FetchPriority::High}, - {kFetchPriorityAttributeValueLow, FetchPriority::Low}, - {kFetchPriorityAttributeValueAuto, FetchPriority::Auto}, - {nullptr, 0}}; - -// . -static const nsAttrValue::EnumTable* - kFetchPriorityEnumTableInvalidValueDefault = &kFetchPriorityEnumTable[2]; -} // namespace - -FetchPriority nsGenericHTMLElement::GetFetchPriority() const { - const nsAttrValue* fetchpriorityAttribute = - GetParsedAttr(nsGkAtoms::fetchpriority); - if (fetchpriorityAttribute) { - MOZ_ASSERT(fetchpriorityAttribute->Type() == nsAttrValue::eEnum); - return FetchPriority(fetchpriorityAttribute->GetEnumValue()); - } - - return FetchPriority::Auto; -} - -/* static */ -void nsGenericHTMLElement::ParseFetchPriority(const nsAString& aValue, - nsAttrValue& aResult) { - aResult.ParseEnumValue(aValue, kFetchPriorityEnumTable, - false /* aCaseSensitive */, - kFetchPriorityEnumTableInvalidValueDefault); -} - void nsGenericHTMLElement::AddToNameTable(nsAtom* aName) { MOZ_ASSERT(HasName(), "Node doesn't have name?"); Document* doc = GetUncomposedDoc(); diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h index a435a1b520aa..5e588267990a 100644 --- a/dom/html/nsGenericHTMLElement.h +++ b/dom/html/nsGenericHTMLElement.h @@ -750,11 +750,6 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase { SetHTMLAttr(nsGkAtoms::fetchpriority, aFetchPriority); } - protected: - mozilla::dom::FetchPriority GetFetchPriority() const; - - static void ParseFetchPriority(const nsAString& aValue, nsAttrValue& aResult); - private: /** * Add/remove this element to the documents name cache diff --git a/dom/svg/SVGFEImageElement.cpp b/dom/svg/SVGFEImageElement.cpp index 664e4d42acd7..4e8ea0f3b672 100644 --- a/dom/svg/SVGFEImageElement.cpp +++ b/dom/svg/SVGFEImageElement.cpp @@ -9,6 +9,7 @@ #include "mozilla/SVGObserverUtils.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/BindContext.h" +#include "mozilla/dom/FetchPriority.h" #include "mozilla/dom/SVGFEImageElementBinding.h" #include "mozilla/dom/SVGFilterElement.h" #include "mozilla/dom/UserActivation.h" @@ -105,10 +106,15 @@ bool SVGFEImageElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, const nsAString& aValue, nsIPrincipal* aMaybeScriptedPrincipal, nsAttrValue& aResult) { - if (aNamespaceID == kNameSpaceID_None && - aAttribute == nsGkAtoms::crossorigin) { - ParseCORSValue(aValue, aResult); - return true; + if (aNamespaceID == kNameSpaceID_None) { + if (aAttribute == nsGkAtoms::crossorigin) { + ParseCORSValue(aValue, aResult); + return true; + } + if (aAttribute == nsGkAtoms::fetchpriority) { + ParseFetchPriority(aValue, aResult); + return true; + } } return SVGFEImageElementBase::ParseAttribute( aNamespaceID, aAttribute, aValue, aMaybeScriptedPrincipal, aResult); @@ -204,6 +210,11 @@ CORSMode SVGFEImageElement::GetCORSMode() { return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin)); } +void SVGFEImageElement::GetFetchPriority(nsAString& aFetchPriority) const { + GetEnumAttr(nsGkAtoms::fetchpriority, kFetchPriorityAttributeValueAuto, + aFetchPriority); +} + //---------------------------------------------------------------------- // nsIDOMSVGFEImageElement methods diff --git a/dom/svg/SVGFEImageElement.h b/dom/svg/SVGFEImageElement.h index 4df686d2d58f..0437316cb676 100644 --- a/dom/svg/SVGFEImageElement.h +++ b/dom/svg/SVGFEImageElement.h @@ -93,6 +93,11 @@ class SVGFEImageElement final : public SVGFEImageElementBase, SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError); } + void GetFetchPriority(nsAString& aFetchPriority) const; + void SetFetchPriority(const nsAString& aFetchPriority) { + SetAttr(nsGkAtoms::fetchpriority, aFetchPriority, IgnoreErrors()); + } + private: void DidAnimateAttribute(int32_t aNameSpaceID, nsAtom* aAttribute) override; nsresult LoadSVGImage(bool aForce, bool aNotify); @@ -107,6 +112,10 @@ class SVGFEImageElement final : public SVGFEImageElementBase, // Override for nsImageLoadingContent. nsIContent* AsContent() override { return this; } + FetchPriority GetFetchPriorityForImage() const override { + return Element::GetFetchPriority(); + } + enum { RESULT, HREF, XLINK_HREF }; SVGAnimatedString mStringAttributes[3]; static StringInfo sStringInfo[3]; diff --git a/dom/svg/SVGImageElement.cpp b/dom/svg/SVGImageElement.cpp index a4fd143393cc..635f6abe4679 100644 --- a/dom/svg/SVGImageElement.cpp +++ b/dom/svg/SVGImageElement.cpp @@ -13,6 +13,7 @@ #include "nsNetUtil.h" #include "imgINotificationObserver.h" #include "mozilla/dom/Document.h" +#include "mozilla/dom/FetchPriority.h" #include "mozilla/dom/SVGImageElementBinding.h" #include "mozilla/dom/SVGLengthBinding.h" #include "mozilla/dom/UserActivation.h" @@ -181,6 +182,11 @@ CORSMode SVGImageElement::GetCORSMode() { return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin)); } +void SVGImageElement::GetFetchPriority(nsAString& aFetchPriority) const { + GetEnumAttr(nsGkAtoms::fetchpriority, kFetchPriorityAttributeValueAuto, + aFetchPriority); +} + //---------------------------------------------------------------------- // nsIContent methods: @@ -197,6 +203,10 @@ bool SVGImageElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, return aResult.ParseEnumValue(aValue, kDecodingTable, false, kDecodingTableDefault); } + if (aAttribute == nsGkAtoms::fetchpriority) { + ParseFetchPriority(aValue, aResult); + return true; + } } return SVGImageElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue, diff --git a/dom/svg/SVGImageElement.h b/dom/svg/SVGImageElement.h index 591179b3a9df..aac34fad5448 100644 --- a/dom/svg/SVGImageElement.h +++ b/dom/svg/SVGImageElement.h @@ -90,6 +90,11 @@ class SVGImageElement final : public SVGImageElementBase, SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError); } + void GetFetchPriority(nsAString& aFetchPriority) const; + void SetFetchPriority(const nsAString& aFetchPriority) { + SetAttr(nsGkAtoms::fetchpriority, aFetchPriority, IgnoreErrors()); + } + void SetDecoding(const nsAString& aDecoding, ErrorResult& aError) { SetAttr(nsGkAtoms::decoding, aDecoding, aError); } @@ -114,6 +119,10 @@ class SVGImageElement final : public SVGImageElementBase, // Override for nsImageLoadingContent. nsIContent* AsContent() override { return this; } + FetchPriority GetFetchPriorityForImage() const override { + return Element::GetFetchPriority(); + } + enum { ATTR_X, ATTR_Y, ATTR_WIDTH, ATTR_HEIGHT }; SVGAnimatedLength mLengthAttributes[4]; static LengthInfo sLengthInfo[4]; diff --git a/dom/svg/SVGScriptElement.cpp b/dom/svg/SVGScriptElement.cpp index 04a4723d579c..ecdfe3c5008a 100644 --- a/dom/svg/SVGScriptElement.cpp +++ b/dom/svg/SVGScriptElement.cpp @@ -203,10 +203,15 @@ bool SVGScriptElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, const nsAString& aValue, nsIPrincipal* aMaybeScriptedPrincipal, nsAttrValue& aResult) { - if (aNamespaceID == kNameSpaceID_None && - aAttribute == nsGkAtoms::crossorigin) { - ParseCORSValue(aValue, aResult); - return true; + if (aNamespaceID == kNameSpaceID_None) { + if (aAttribute == nsGkAtoms::crossorigin) { + ParseCORSValue(aValue, aResult); + return true; + } + if (aAttribute == nsGkAtoms::fetchpriority) { + ParseFetchPriority(aValue, aResult); + return true; + } } return SVGScriptElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue, @@ -217,9 +222,13 @@ CORSMode SVGScriptElement::GetCORSMode() const { return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin)); } +void SVGScriptElement::GetFetchPriority(nsAString& aFetchPriority) const { + GetEnumAttr(nsGkAtoms::fetchpriority, kFetchPriorityAttributeValueAuto, + aFetchPriority); +} + FetchPriority SVGScriptElement::GetFetchPriority() const { - // . - return FetchPriority::Auto; + return Element::GetFetchPriority(); } } // namespace mozilla::dom diff --git a/dom/svg/SVGScriptElement.h b/dom/svg/SVGScriptElement.h index e768605bb356..cb11c9bacf70 100644 --- a/dom/svg/SVGScriptElement.h +++ b/dom/svg/SVGScriptElement.h @@ -70,6 +70,10 @@ class SVGScriptElement final : public SVGScriptElementBase, void GetCrossOrigin(nsAString& aCrossOrigin); void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError); already_AddRefed Href(); + void GetFetchPriority(nsAString& aFetchPriority) const; + void SetFetchPriority(const nsAString& aFetchPriority) { + SetAttr(nsGkAtoms::fetchpriority, aFetchPriority, IgnoreErrors()); + } protected: ~SVGScriptElement() = default; diff --git a/dom/webidl/SVGFEImageElement.webidl b/dom/webidl/SVGFEImageElement.webidl index e6f451919531..b05d994eb909 100644 --- a/dom/webidl/SVGFEImageElement.webidl +++ b/dom/webidl/SVGFEImageElement.webidl @@ -16,6 +16,8 @@ interface SVGFEImageElement : SVGElement { readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio; [SetterThrows] attribute DOMString? crossOrigin; + [Pref="network.fetchpriority.enabled"] + attribute DOMString fetchPriority; }; SVGFEImageElement includes SVGFilterPrimitiveStandardAttributes; diff --git a/dom/webidl/SVGImageElement.webidl b/dom/webidl/SVGImageElement.webidl index f2dd6596952d..fd1805896956 100644 --- a/dom/webidl/SVGImageElement.webidl +++ b/dom/webidl/SVGImageElement.webidl @@ -24,6 +24,8 @@ interface SVGImageElement : SVGGraphicsElement { readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio; [SetterThrows] attribute DOMString? crossOrigin; + [Pref="network.fetchpriority.enabled"] + attribute DOMString fetchPriority; [CEReactions, SetterThrows] attribute DOMString decoding; [NewObject] diff --git a/dom/webidl/SVGScriptElement.webidl b/dom/webidl/SVGScriptElement.webidl index 914bfd606ed3..97dd682dd8e8 100644 --- a/dom/webidl/SVGScriptElement.webidl +++ b/dom/webidl/SVGScriptElement.webidl @@ -19,6 +19,8 @@ interface SVGScriptElement : SVGElement { attribute boolean defer; [SetterThrows] attribute DOMString? crossOrigin; + [Pref="network.fetchpriority.enabled"] + attribute DOMString fetchPriority; }; SVGScriptElement includes SVGURIReference; diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index 2c9d2b52c45a..9c41d88d13b4 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -547,22 +547,21 @@ nsIContentHandle* nsHtml5TreeBuilder::createElement( } break; case kNameSpaceID_SVG: - if (nsGkAtoms::image == aName) { + if (nsGkAtoms::image == aName || nsGkAtoms::feImage == aName) { nsHtml5String url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); if (!url) { 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; + nsHtml5String crossOrigin = + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); + nsHtml5String fetchPriority = + aAttributes->getValue(nsHtml5AttributeName::ATTR_FETCHPRIORITY); mSpeculativeLoadQueue.AppendElement()->InitImage( - url, nullptr, nullptr, nullptr, nullptr, nullptr, false, - fetchPriority); + url, crossOrigin, /* aMedia = */ nullptr, nullptr, nullptr, + nullptr, false, fetchPriority); } } else if (nsGkAtoms::script == aName) { nsHtml5TreeOperation* treeOp = @@ -621,14 +620,8 @@ nsIContentHandle* nsHtml5TreeBuilder::createElement( aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); nsHtml5String referrerPolicy = aAttributes->getValue( nsHtml5AttributeName::ATTR_REFERRERPOLICY); - - // Bug 1847712: SVG's ` + + + + + + + + + + + diff --git a/testing/web-platform/tests/svg/scripted/attr-script-fetchpriority.html b/testing/web-platform/tests/svg/scripted/attr-script-fetchpriority.html new file mode 100644 index 000000000000..2f73e1e59a8a --- /dev/null +++ b/testing/web-platform/tests/svg/scripted/attr-script-fetchpriority.html @@ -0,0 +1,27 @@ + +Fetch Priority - SVG Script element + + + + + + + + + + + +