summaryrefslogtreecommitdiff
path: root/dom
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2020-04-17 05:01:17 -0400
committerMatt A. Tobin <email@mattatobin.com>2020-04-17 05:01:17 -0400
commitd3d3ff14bc779f0975c277546c62801174e1358c (patch)
tree8b5de5f34019b97ad0b3c155c270a810608cd775 /dom
parent37ba06ebcede3b8f029728d591add35e0d41f3f8 (diff)
downloaduxp-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.cpp13
-rw-r--r--dom/base/nsContentUtils.h6
-rw-r--r--dom/base/nsDocument.cpp49
-rw-r--r--dom/webidl/Document.webidl3
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 */