From 24189770aa06518a0801bf71313eb7eedd0d31a9 Mon Sep 17 00:00:00 2001 From: FranklinDM Date: Sat, 11 Mar 2023 16:42:18 +0800 Subject: [PATCH] Issue #2158 - Part 2: Handle and expose preload link destination to DOM This also defines known preload destinations and ensures it is reflected in JS. --- dom/base/Link.cpp | 52 +++++++++++++++++++++++++++++++ dom/base/Link.h | 2 ++ dom/base/nsContentSink.cpp | 14 +++++++-- dom/base/nsContentSink.h | 3 +- dom/base/nsGkAtomList.h | 1 + dom/base/nsStyleLinkElement.cpp | 2 ++ dom/base/nsStyleLinkElement.h | 3 +- dom/base/nsTreeSanitizer.cpp | 1 + dom/html/HTMLLinkElement.cpp | 14 +++++++++ dom/html/HTMLLinkElement.h | 5 +++ dom/webidl/HTMLLinkElement.webidl | 6 ++++ 11 files changed, 98 insertions(+), 5 deletions(-) diff --git a/dom/base/Link.cpp b/dom/base/Link.cpp index e0cd4ed71d..2a0b926086 100644 --- a/dom/base/Link.cpp +++ b/dom/base/Link.cpp @@ -26,6 +26,47 @@ namespace mozilla { namespace dom { +enum Destination : uint8_t +{ + DESTINATION_INVALID, + DESTINATION_AUDIO, + DESTINATION_AUDIOWORKLET, + DESTINATION_DOCUMENT, + DESTINATION_EMBED, + DESTINATION_FONT, + DESTINATION_FRAME, + DESTINATION_IFRAME, + DESTINATION_IMAGE, + DESTINATION_JSON, + DESTINATION_MANIFEST, + DESTINATION_OBJECT, + DESTINATION_REPORT, + DESTINATION_SCRIPT, + DESTINATION_SERVICEWORKER, + DESTINATION_SHAREDWORKER, + DESTINATION_STYLE, + DESTINATION_TRACK, + DESTINATION_VIDEO, + DESTINATION_WEBIDENTITY, + DESTINATION_WORKER, + DESTINATION_XSLT, + DESTINATION_FETCH +}; + +static const nsAttrValue::EnumTable kDestinationAttributeTable[] = { + { "", DESTINATION_INVALID }, + { "audio", DESTINATION_AUDIO }, + { "font", DESTINATION_FONT }, + { "image", DESTINATION_IMAGE }, + { "script", DESTINATION_SCRIPT }, + { "style", DESTINATION_STYLE }, + { "track", DESTINATION_TRACK }, + { "video", DESTINATION_VIDEO }, + { "fetch", DESTINATION_FETCH }, + { "json", DESTINATION_JSON }, + { nullptr, 0 } +}; + Link::Link(Element *aElement) : mElement(aElement) , mHistory(services::GetHistoryService()) @@ -635,6 +676,17 @@ Link::SetHrefAttribute(nsIURI *aURI) NS_ConvertUTF8toUTF16(href), true); } +/* static */ void +Link::ParseDestinationValue(const nsAString& aValue, + nsAttrValue& aResult) +{ + // Invalid values are treated as an empty string. + aResult.ParseEnumValue(aValue, + kDestinationAttributeTable, + false, + &kDestinationAttributeTable[0]); +} + size_t Link::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { diff --git a/dom/base/Link.h b/dom/base/Link.h index 7a0828e122..cb4beeadb7 100644 --- a/dom/base/Link.h +++ b/dom/base/Link.h @@ -119,6 +119,8 @@ public: void TryDNSPrefetchPreconnectOrPrefetch(); void CancelPrefetch(); + static void ParseDestinationValue(const nsAString& aValue, nsAttrValue& aResult); + protected: virtual ~Link(); diff --git a/dom/base/nsContentSink.cpp b/dom/base/nsContentSink.cpp index d8760db70c..299c5a5c56 100644 --- a/dom/base/nsContentSink.cpp +++ b/dom/base/nsContentSink.cpp @@ -471,6 +471,7 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData) nsAutoString media; nsAutoString anchor; nsAutoString crossOrigin; + nsAutoString destination; crossOrigin.SetIsVoid(true); @@ -653,6 +654,11 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData) crossOrigin = value; crossOrigin.StripWhitespace(); } + } else if (attr.LowerCaseEqualsLiteral("as")) { + if (destination.IsEmpty()) { + destination = value; + destination.StripWhitespace(); + } } } } @@ -666,7 +672,7 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData) rv = ProcessLink(anchor, href, rel, // prefer RFC 5987 variant over non-I18zed version titleStar.IsEmpty() ? title : titleStar, - type, media, crossOrigin); + type, media, crossOrigin, destination); } href.Truncate(); @@ -676,6 +682,7 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData) media.Truncate(); anchor.Truncate(); crossOrigin.SetIsVoid(true); + destination.Truncate(); seenParameters = false; } @@ -688,7 +695,7 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData) rv = ProcessLink(anchor, href, rel, // prefer RFC 5987 variant over non-I18zed version titleStar.IsEmpty() ? title : titleStar, - type, media, crossOrigin); + type, media, crossOrigin, destination); } return rv; @@ -699,7 +706,8 @@ nsresult nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref, const nsSubstring& aRel, const nsSubstring& aTitle, const nsSubstring& aType, const nsSubstring& aMedia, - const nsSubstring& aCrossOrigin) + const nsSubstring& aCrossOrigin, + const nsSubstring& aDestination) { uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(aRel, mDocument->NodePrincipal()); diff --git a/dom/base/nsContentSink.h b/dom/base/nsContentSink.h index 4140a3f19f..61f72dfc5c 100644 --- a/dom/base/nsContentSink.h +++ b/dom/base/nsContentSink.h @@ -153,7 +153,8 @@ protected: nsresult ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref, const nsSubstring& aRel, const nsSubstring& aTitle, const nsSubstring& aType, - const nsSubstring& aMedia, const nsSubstring& aCrossOrigin); + const nsSubstring& aMedia, const nsSubstring& aCrossOrigin, + const nsSubstring& aDestination); virtual nsresult ProcessStyleLink(nsIContent* aElement, const nsSubstring& aHref, diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 9622b21d3e..de1a4927be 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -110,6 +110,7 @@ GK_ATOM(archive, "archive") GK_ATOM(area, "area") GK_ATOM(arrow, "arrow") GK_ATOM(article, "article") +GK_ATOM(as, "as") GK_ATOM(ascending, "ascending") GK_ATOM(aside, "aside") GK_ATOM(aspectRatio, "aspect-ratio") diff --git a/dom/base/nsStyleLinkElement.cpp b/dom/base/nsStyleLinkElement.cpp index 0fbdbd5860..cfc074ba28 100644 --- a/dom/base/nsStyleLinkElement.cpp +++ b/dom/base/nsStyleLinkElement.cpp @@ -174,6 +174,8 @@ static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal) return nsStyleLinkElement::eHTMLIMPORT; else if (aLink.EqualsLiteral("preconnect")) return nsStyleLinkElement::ePRECONNECT; + else if (aLink.EqualsLiteral("preload")) + return nsStyleLinkElement::ePRELOAD; else return 0; } diff --git a/dom/base/nsStyleLinkElement.h b/dom/base/nsStyleLinkElement.h index 79ac6abbaa..a76cd8a6b2 100644 --- a/dom/base/nsStyleLinkElement.h +++ b/dom/base/nsStyleLinkElement.h @@ -64,7 +64,8 @@ public: eNEXT = 0x00000008, eALTERNATE = 0x00000010, eHTMLIMPORT = 0x00000020, - ePRECONNECT = 0x00000040 + ePRECONNECT = 0x00000040, + ePRELOAD = 0x00000080 }; // The return value is a bitwise or of 0 or more RelValues. diff --git a/dom/base/nsTreeSanitizer.cpp b/dom/base/nsTreeSanitizer.cpp index 970e4386b9..ea35c39ba2 100644 --- a/dom/base/nsTreeSanitizer.cpp +++ b/dom/base/nsTreeSanitizer.cpp @@ -151,6 +151,7 @@ nsIAtom** const kAttributesHTML[] = { &nsGkAtoms::accesskey, &nsGkAtoms::action, &nsGkAtoms::alt, + &nsGkAtoms::as, &nsGkAtoms::autocomplete, &nsGkAtoms::autofocus, &nsGkAtoms::autoplay, diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp index b8e859cc00..9778922196 100644 --- a/dom/html/HTMLLinkElement.cpp +++ b/dom/html/HTMLLinkElement.cpp @@ -242,6 +242,11 @@ HTMLLinkElement::ParseAttribute(int32_t aNamespaceID, return true; } + if (aAttribute == nsGkAtoms::as) { + ParseDestinationValue(aValue, aResult); + return true; + } + if (aAttribute == nsGkAtoms::sizes) { aResult.ParseAtomArray(aValue); return true; @@ -374,6 +379,8 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, aName == nsGkAtoms::title || aName == nsGkAtoms::media || aName == nsGkAtoms::type || + aName == nsGkAtoms::as || + aName == nsGkAtoms::crossorigin || (LINK_DISABLED && aName == nsGkAtoms::disabled))) { bool dropSheet = false; if (aName == nsGkAtoms::rel) { @@ -471,6 +478,7 @@ static const DOMTokenListSupportedToken sSupportedRelValues[] = { "preconnect", "icon", "search", + "preload", nullptr }; @@ -602,6 +610,12 @@ HTMLLinkElement::WrapNode(JSContext* aCx, JS::Handle aGivenProto) return HTMLLinkElementBinding::Wrap(aCx, this, aGivenProto); } +void +HTMLLinkElement::GetAs(nsAString& aResult) +{ + GetEnumAttr(nsGkAtoms::as, EmptyCString().get(), aResult); +} + already_AddRefed HTMLLinkElement::GetImport() { diff --git a/dom/html/HTMLLinkElement.h b/dom/html/HTMLLinkElement.h index aca16d56a4..c7742478e3 100644 --- a/dom/html/HTMLLinkElement.h +++ b/dom/html/HTMLLinkElement.h @@ -127,6 +127,11 @@ public: { SetHTMLAttr(nsGkAtoms::hreflang, aHreflang, aRv); } + void GetAs(nsAString& aResult); + void SetAs(const nsAString& aAs, ErrorResult& aRv) + { + SetAttr(nsGkAtoms::as, aAs, aRv); + } nsDOMTokenList* Sizes() { return GetTokenList(nsGkAtoms::sizes); diff --git a/dom/webidl/HTMLLinkElement.webidl b/dom/webidl/HTMLLinkElement.webidl index 0089ab84e6..11149ce6b6 100644 --- a/dom/webidl/HTMLLinkElement.webidl +++ b/dom/webidl/HTMLLinkElement.webidl @@ -59,3 +59,9 @@ partial interface HTMLLinkElement { [CEReactions, SetterThrows] attribute DOMString integrity; }; + +//https://w3c.github.io/preload/ +partial interface HTMLLinkElement { + [SetterThrows, Pure] + attribute DOMString as; +};