diff options
author | Matt A. Tobin <email@mattatobin.com> | 2020-04-17 05:01:17 -0400 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2020-04-17 05:01:17 -0400 |
commit | d3d3ff14bc779f0975c277546c62801174e1358c (patch) | |
tree | 8b5de5f34019b97ad0b3c155c270a810608cd775 /dom | |
parent | 37ba06ebcede3b8f029728d591add35e0d41f3f8 (diff) | |
download | uxp-d3d3ff14bc779f0975c277546c62801174e1358c.tar.gz |
Bug 1330843 - Allow JS to create NAC pseudo-elements
Tag mcp-graveyard/UXP#1375
Diffstat (limited to 'dom')
-rw-r--r-- | dom/base/nsContentUtils.cpp | 13 | ||||
-rw-r--r-- | dom/base/nsContentUtils.h | 6 | ||||
-rw-r--r-- | dom/base/nsDocument.cpp | 49 | ||||
-rw-r--r-- | dom/webidl/Document.webidl | 3 |
4 files changed, 70 insertions, 1 deletions
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 6a819818c1..c53b3d834d 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -9871,3 +9871,16 @@ nsContentUtils::IsLocalRefURL(const nsString& aString) return false; } + +/* static */ Element* +nsContentUtils::GetClosestNonNativeAnonymousAncestor(Element* aElement) +{ + MOZ_ASSERT(aElement); + MOZ_ASSERT(aElement->IsNativeAnonymous()); + + Element* e = aElement; + while (e && e->IsNativeAnonymous()) { + e = e->GetParentElement(); + } + return e; +} diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 3f1a255043..4ccc1aa253 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2762,6 +2762,12 @@ public: static bool IsWebComponentsEnabled() { return sIsWebComponentsEnabled; } + /** + * Walks up the tree from aElement until it finds an element that is + * not native anonymous content. aElement must be NAC itself. + */ + static Element* GetClosestNonNativeAnonymousAncestor(Element* aElement); + static bool IsCustomElementsEnabled() { return sIsCustomElementsEnabled; } diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 45c80ca7f6..d0e861b1a7 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -5378,6 +5378,20 @@ nsDocument::GetCustomElementRegistry() return registry.forget(); } +// We only support pseudo-elements with two colons in this function. +static CSSPseudoElementType +GetPseudoElementType(const nsString& aString, ErrorResult& aRv) +{ + MOZ_ASSERT(!aString.IsEmpty(), "GetPseudoElementType aString should be non-null"); + if (aString.Length() <= 2 || aString[0] != ':' || aString[1] != ':') { + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); + return CSSPseudoElementType::NotPseudo; + } + nsCOMPtr<nsIAtom> pseudo = NS_Atomize(Substring(aString, 1)); + return nsCSSPseudoElements::GetPseudoType(pseudo, + nsCSSProps::EnabledState::eInUASheets); +} + already_AddRefed<Element> nsDocument::CreateElement(const nsAString& aTagName, const ElementCreationOptionsOrString& aOptions, @@ -5395,10 +5409,36 @@ nsDocument::CreateElement(const nsAString& aTagName, } const nsString* is = nullptr; + CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo; + if (aOptions.IsElementCreationOptions()) { + const ElementCreationOptions& options = + aOptions.GetAsElementCreationOptions(); + + if (CustomElementRegistry::IsCustomElementEnabled() && + options.mIs.WasPassed()) { + is = &options.mIs.Value(); + } + + // Check 'pseudo' and throw an exception if it's not one allowed + // with CSS_PSEUDO_ELEMENT_IS_JS_CREATED_NAC. + if (options.mPseudo.WasPassed()) { + pseudoType = GetPseudoElementType(options.mPseudo.Value(), rv); + if (rv.Failed() || + pseudoType == CSSPseudoElementType::NotPseudo || + !nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType)) { + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } + } + } RefPtr<Element> elem = CreateElem( needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is); + if (pseudoType != CSSPseudoElementType::NotPseudo) { + elem->SetPseudoElementType(pseudoType); + } + if (is) { elem->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true); } @@ -5413,8 +5453,8 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI, { *aReturn = nullptr; ElementCreationOptionsOrString options; - options.SetAsString(); + options.SetAsString(); ErrorResult rv; nsCOMPtr<Element> element = CreateElementNS(aNamespaceURI, aQualifiedName, options, rv); @@ -5439,6 +5479,13 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI, } const nsString* is = nullptr; + if (CustomElementRegistry::IsCustomElementEnabled() && + aOptions.IsElementCreationOptions()) { + const ElementCreationOptions& options = aOptions.GetAsElementCreationOptions(); + if (options.mIs.WasPassed()) { + is = &options.mIs.Value(); + } + } nsCOMPtr<Element> element; rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl index b28903ae23..cad6e1c396 100644 --- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -17,6 +17,9 @@ enum VisibilityState { "hidden", "visible", "prerender" }; /* https://dom.spec.whatwg.org/#dictdef-elementcreationoptions */ dictionary ElementCreationOptions { DOMString is; + + [ChromeOnly] + DOMString pseudo; }; /* http://dom.spec.whatwg.org/#interface-document */ |