Bug 1460962 - Support customized built-in element in XUL r=smaug

This patch enables us to specify a custom element type with |is| attribute
or property when creating a XUL element. Because non-dashed names are valid
custom element names in XUL (bug 1446247), other checks has to modified
accordingly.

The checks I am settling with are
1) Forbids the custom built-in element names to be a non-dashed name.
2) Forbids the custom built-in element to extend a dashed built-in element name.

This also ensures the custom built-in element types don't take on the same
name as the element name it extends.

MozReview-Commit-ID: GCQ9RnfvvrC
This commit is contained in:
Timothy Guan-tin Chien
2018-05-11 12:44:46 -07:00
parent a81b172c03
commit eddbf08f39
10 changed files with 368 additions and 48 deletions

View File

@@ -766,22 +766,42 @@ CustomElementRegistry::Define(const nsAString& aName,
* definition in this specification), then throw a "NotSupportedError"
* DOMException.
* 3. Set localName to extends.
*
* Special note for XUL elements:
*
* For step 7.1, we'll subject XUL to the same rules as HTML, so that a
* custom built-in element will not be extending from a dashed name.
* Step 7.2 is disregarded. But, we do check if the name is a dashed name
* (i.e. step 2) given that there is no reason for a custom built-in element
* type to take on a non-dashed name.
* This also ensures the name of the built-in custom element type can never
* be the same as the built-in element name, so we don't break the assumption
* elsewhere.
*/
nsAutoString localName(aName);
if (aOptions.mExtends.WasPassed()) {
RefPtr<nsAtom> extendsAtom(NS_Atomize(aOptions.mExtends.Value()));
if (nsContentUtils::IsCustomElementName(extendsAtom, nameSpaceID)) {
if (nsContentUtils::IsCustomElementName(extendsAtom, kNameSpaceID_XHTML)) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
// bgsound and multicol are unknown html element.
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(extendsAtom);
if (tag == eHTMLTag_userdefined ||
tag == eHTMLTag_bgsound ||
tag == eHTMLTag_multicol) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
if (nameSpaceID == kNameSpaceID_XHTML) {
// bgsound and multicol are unknown html element.
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(extendsAtom);
if (tag == eHTMLTag_userdefined ||
tag == eHTMLTag_bgsound ||
tag == eHTMLTag_multicol) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
} else { // kNameSpaceID_XUL
// As stated above, ensure the name of the customized built-in element
// (the one that goes to the |is| attribute) is a dashed name.
if (!nsContentUtils::IsNameWithDash(nameAtom)) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
}
localName.Assign(aOptions.mExtends.Value());

View File

@@ -4278,10 +4278,27 @@ Element::SetCustomElementData(CustomElementData* aData)
#if DEBUG
nsAtom* name = NodeInfo()->NameAtom();
nsAtom* type = aData->GetCustomElementType();
if (nsContentUtils::IsCustomElementName(name, NodeInfo()->NamespaceID())) {
MOZ_ASSERT(type == name);
} else {
MOZ_ASSERT(type != name);
if (NodeInfo()->NamespaceID() == kNameSpaceID_XHTML) {
if (nsContentUtils::IsCustomElementName(name, kNameSpaceID_XHTML)) {
MOZ_ASSERT(type == name);
} else {
MOZ_ASSERT(type != name);
}
} else { // kNameSpaceID_XUL
// Check to see if the tag name is a dashed name.
if (nsContentUtils::IsNameWithDash(name)) {
// Assert that a tag name with dashes is always an autonomous custom
// element.
MOZ_ASSERT(type == name);
} else {
// Could still be an autonomous custom element with a non-dashed tag name.
// Need the check below for sure.
if (type != name) {
// Assert that the name of the built-in custom element type is always
// a dashed name.
MOZ_ASSERT(nsContentUtils::IsNameWithDash(type));
}
}
}
#endif
slots->mCustomElementData = aData;

View File

@@ -62,7 +62,9 @@ NS_NewMathMLElement(mozilla::dom::Element** aResult,
nsresult
NS_NewXULElement(mozilla::dom::Element** aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser);
mozilla::dom::FromParser aFromParser,
nsAtom* aIsAtom = nullptr,
mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
void
NS_TrustedNewXULElement(mozilla::dom::Element** aResult,

View File

@@ -3183,13 +3183,8 @@ nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult,
// static
bool
nsContentUtils::IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID)
nsContentUtils::IsNameWithDash(nsAtom* aName)
{
// Allow non-dashed names in XUL for XBL to Custom Element migrations.
if (aNameSpaceID == kNameSpaceID_XUL) {
return true;
}
// A valid custom element name is a sequence of characters name which
// must match the PotentialCustomElementName production:
// PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)*
@@ -3239,6 +3234,19 @@ nsContentUtils::IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID)
}
}
return hasDash;
}
// static
bool
nsContentUtils::IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID)
{
// Allow non-dashed names in XUL for XBL to Custom Element migrations.
if (aNameSpaceID == kNameSpaceID_XUL) {
return true;
}
bool hasDash = IsNameWithDash(aName);
if (!hasDash) {
return false;
}
@@ -9886,8 +9894,22 @@ nsContentUtils::NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* a
tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
isCustomElementName = (tag == eHTMLTag_userdefined &&
nsContentUtils::IsCustomElementName(name, kNameSpaceID_XHTML));
} else {
isCustomElementName = nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL);
} else { // kNameSpaceID_XUL
if (aIsAtom) {
// Make sure the customized built-in element to be constructed confirms
// to our naming requirement, i.e. [is] must be a dashed name and
// the tag name must not.
// if so, set isCustomElementName to false to kick off all the logics
// that pick up aIsAtom.
if (nsContentUtils::IsNameWithDash(aIsAtom) &&
!nsContentUtils::IsNameWithDash(name)) {
isCustomElementName = false;
} else {
isCustomElementName = nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL);
}
} else {
isCustomElementName = nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL);
}
}
RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
@@ -9956,9 +9978,11 @@ nsContentUtils::NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* a
// CustomElementData setup, if not we will hit the assertion in
// SetCustomElementData().
// Built-in element
MOZ_ASSERT(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
"Custom built-in XUL elements are not supported yet.");
*aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
*aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
} else {
NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()));
}
(*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
if (synchronousCustomElements) {
CustomElementRegistry::Upgrade(*aResult, definition, rv);

View File

@@ -703,6 +703,11 @@ public:
nsIDocument* aDocument,
nsIURI* aBaseURI);
/**
* Returns true if |aName| is a name with dashes.
*/
static bool IsNameWithDash(nsAtom* aName);
/**
* Returns true if |aName| is a valid name to be registered via
* customElements.define.

View File

@@ -186,13 +186,13 @@ NS_NewElement(Element** aResult,
{
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
int32_t ns = ni->NamespaceID();
RefPtr<nsAtom> isAtom = aIs ? NS_Atomize(*aIs) : nullptr;
if (ns == kNameSpaceID_XHTML) {
RefPtr<nsAtom> isAtom = aIs ? NS_Atomize(*aIs) : nullptr;
return NS_NewHTMLElement(aResult, ni.forget(), aFromParser, isAtom);
}
#ifdef MOZ_XUL
if (ns == kNameSpaceID_XUL) {
return NS_NewXULElement(aResult, ni.forget(), aFromParser);
return NS_NewXULElement(aResult, ni.forget(), aFromParser, isAtom);
}
#endif
if (ns == kNameSpaceID_MathML) {

View File

@@ -48,6 +48,7 @@
#include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/HTMLEmbedElementBinding.h"
#include "mozilla/dom/XULElementBinding.h"
#include "mozilla/dom/XULPopupElementBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ResolveSystemBinding.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"
@@ -3807,25 +3808,32 @@ HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
}
} else {
// Step 5.
// If the definition is for a customized built-in element, the localName
// should be one of the ones defined in the specification for this interface.
constructorGetterCallback cb;
if (ns == kNameSpaceID_XHTML) {
// Step 5.
// If the definition is for a customized built-in element, the localName
// should be one of the ones defined in the specification for this interface.
tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
if (tag == eHTMLTag_userdefined) {
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
}
// Customized built-in elements are not supported for XUL yet.
if (ns == kNameSpaceID_XUL) {
return Throw(aCx, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
MOZ_ASSERT(tag <= NS_HTML_TAG_MAX, "tag is out of bounds");
// If the definition is for a customized built-in element, the active
// function should be the localname's element interface.
cb = sConstructorGetterCallback[tag];
} else { // kNameSpaceID_XUL
if (definition->mLocalName == nsGkAtoms::menupopup ||
definition->mLocalName == nsGkAtoms::popup ||
definition->mLocalName == nsGkAtoms::panel ||
definition->mLocalName == nsGkAtoms::tooltip) {
cb = XULPopupElementBinding::GetConstructorObject;
} else {
cb = XULElementBinding::GetConstructorObject;
}
}
tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
if (tag == eHTMLTag_userdefined) {
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
}
MOZ_ASSERT(tag <= NS_HTML_TAG_MAX, "tag is out of bounds");
// If the definition is for a customized built-in element, the active
// function should be the localname's element interface.
constructorGetterCallback cb = sConstructorGetterCallback[tag];
if (!cb) {
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
}

View File

@@ -29,9 +29,44 @@
class TestWithoutDash extends XULElement { }
customElements.define("testwithoutdash", TestWithoutDash);
function runTest() {
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
class TestWithoutDashExtended extends TestWithoutDash {
constructor() {
super();
}
connectedCallback() {
this.textContent = "quux";
}
}
customElements.define("testwithoutdash-extended", TestWithoutDashExtended, { extends: "testwithoutdash" });
class TestCustomBuiltInElement extends XULElement {
constructor() {
super();
}
connectedCallback() {
this.textContent = "baz";
}
}
customElements.define("test-built-in-element",
TestCustomBuiltInElement, { extends: "axulelement" });
class TestPopupExtendElement extends XULPopupElement {
constructor() {
super();
}
connectedCallback() {
this.textContent = "quuz";
}
}
customElements.define("test-popup-extend",
TestPopupExtendElement, { extends: "popup" });
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
function basicCustomElementCreate() {
let element = document.createElementNS(XUL_NS, "test-custom-element");
document.querySelector("#content").appendChild(element);
is(element.textContent, "foo", "Should have set the textContent");
@@ -50,14 +85,209 @@
document.querySelector("#content").appendChild(element3);
is(element3.textContent, "foo", "Should have set the textContent");
ok(element3 instanceof TestCustomElement, "Should be an instance of TestCustomElement");
}
function parserBasicElementUpgrade() {
let element4 = document.getElementById("element4");
is(element4.textContent, "foo",
"Parser should have instantiated the custom element.");
ok(element4 instanceof TestCustomElement, "Should be an instance of TestCustomElement");
}
function tagNameWithoutDash() {
let element5 = document.getElementById("element5");
ok(element5 instanceof TestWithoutDash, "Should be an instance of TestWithoutDash");
}
function upgradeAfterDefine() {
class TestCustomElement1 extends XULElement {
constructor() {
super();
}
connectedCallback() {
this.textContent = "bar";
}
}
let element = document.createElementNS(XUL_NS, "test-custom-element-1");
ok(!(element instanceof TestCustomElement1), "Should not be an instance of TestCustomElement1");
customElements.define("test-custom-element-1", TestCustomElement1);
ok(!(element instanceof TestCustomElement1), "Should not be an instance of TestCustomElement1");
document.querySelector("#content").appendChild(element);
ok(element instanceof TestCustomElement1, "Should be upgraded to an instance of TestCustomElement1");
is(element.textContent, "bar", "Should have set the textContent");
}
function basicElementCreateBuiltIn() {
let element = document.createElementNS(XUL_NS, "axulelement", { is: "test-built-in-element" });
ok(element instanceof TestCustomBuiltInElement, "Should be an instance of TestCustomBuiltInElement");
is(element.getAttribute("is"), "test-built-in-element", "The |is| attribute of the created element should be the extended type.");
document.querySelector("#content").appendChild(element);
is(element.textContent, "baz", "Should have set the textContent");
let element2 = element.cloneNode(false);
is(element2.localName, "axulelement", "Should see the right tag");
is(element2.getAttribute("is"), "test-built-in-element", "The |is| attribute of the created element should be the extended type.");
is(element2.textContent, "", "Shouldn't have cloned the textContent");
document.querySelector("#content").appendChild(element2);
is(element2.textContent, "baz", "Should have set the textContent");
ok(element2 instanceof TestCustomBuiltInElement, "Should be an instance of TestCustomBuiltInElement");
let element3 = new TestCustomBuiltInElement();
is(element3.localName, "axulelement", "Should see the right tag");
is(element3.textContent, "", "Shouldn't have been inserted yet");
is(element3.namespaceURI, XUL_NS, "Should have set the right namespace");
document.querySelector("#content").appendChild(element3);
is(element3.textContent, "baz", "Should have set the textContent");
ok(element3 instanceof TestCustomBuiltInElement, "Should be an instance of TestCustomBuiltInElement");
}
function parserBasicElementUpgradeBuiltIn() {
let element = document.getElementById("element6");
is(element.textContent, "baz",
"Parser should have instantiated the custom element.");
ok(element instanceof TestCustomBuiltInElement, "Should be an instance of TestCustomBuiltInElement");
}
function subclassElementCreateBuiltIn() {
let element = document.createElementNS(XUL_NS, "popup", { is: "test-popup-extend" });
ok(element instanceof TestPopupExtendElement, "Should be an instance of TestPopupExtendElement");
is(element.getAttribute("is"), "test-popup-extend", "The |is| attribute of the created element should be the extended type.");
document.querySelector("#content").appendChild(element);
is(element.textContent, "quuz", "Should have set the textContent");
let element2 = element.cloneNode(false);
is(element2.localName, "popup", "Should see the right tag");
is(element2.getAttribute("is"), "test-popup-extend", "The |is| attribute of the created element should be the extended type.");
is(element2.textContent, "", "Shouldn't have cloned the textContent");
document.querySelector("#content").appendChild(element2);
is(element2.textContent, "quuz", "Should have set the textContent");
ok(element2 instanceof TestPopupExtendElement, "Should be an instance of TestPopupExtendElement");
let element3 = new TestPopupExtendElement();
is(element3.localName, "popup", "Should see the right tag");
is(element3.textContent, "", "Shouldn't have been inserted yet");
is(element3.namespaceURI, XUL_NS, "Should have set the right namespace");
document.querySelector("#content").appendChild(element3);
is(element3.textContent, "quuz", "Should have set the textContent");
ok(element3 instanceof TestPopupExtendElement, "Should be an instance of TestPopupExtendElement");
}
function parserSubclassElementUpgradeBuiltIn() {
let element = document.getElementById("element7");
is(element.textContent, "quuz",
"Parser should have instantiated the custom element.");
ok(element instanceof TestPopupExtendElement, "Should be an instance of TestPopupExtendElement");
}
function upgradeAfterDefineBuiltIn() {
class TestCustomBuiltInElement1 extends XULElement {
constructor() {
super();
}
connectedCallback() {
this.textContent = "qux";
}
}
let element = document.createElementNS(XUL_NS, "axulelement", { is: "test-built-in-element-1" });
ok(!(element instanceof TestCustomBuiltInElement1), "Should not be an instance of TestCustomBuiltInElement1");
customElements.define("test-built-in-element-1",
TestCustomBuiltInElement1, { extends: "axulelement" });
ok(!(element instanceof TestCustomBuiltInElement1), "Should not be an instance of TestCustomBuiltInElement1");
document.querySelector("#content").appendChild(element);
ok(element instanceof TestCustomBuiltInElement1, "Should be upgraded to an instance of TestCustomBuiltInElement1");
is(element.textContent, "qux", "Should have set the textContent");
}
function throwForInvalidBuiltInName() {
try {
// <axulelement is="testwithoutdashbuiltin" /> is not allowed;
// built-in type names need dashes.
customElements.define(
"testwithoutdashbuiltin", class extends XULElement {}, { extends: "axulelement" });
ok(false, "Built-in type name without dash should be rejected.");
} catch (e) {
ok(true, "Built-in type name without dash is rejected.");
}
try {
// <test-built-in-element-2 is="test-custom-element-2" /> is not allowed;
// built-in type tag names forbid dashes
customElements.define(
"test-built-in-element-2", class extends XULElement {}, { extends: "test-custom-element-2" });
ok(false, "Extending from a name with dash should be rejected.");
} catch (e) {
ok(true, "Extending from a name with dash is rejected.");
}
}
function extendingWithoutDashCustomElement() {
let element = document.createElementNS(XUL_NS, "testwithoutdash", { is: "testwithoutdash-extended" });
ok(element instanceof TestWithoutDashExtended, "Should be an instance of TestWithoutDashExtended");
ok(element instanceof TestWithoutDash, "Should be an instance of TestWithoutDash");
is(element.getAttribute("is"), "testwithoutdash-extended", "The |is| attribute of the created element should be the extended type.");
document.querySelector("#content").appendChild(element);
is(element.textContent, "quux", "Should have set the textContent");
let element2 = element.cloneNode(false);
is(element2.localName, "testwithoutdash", "Should see the right tag");
is(element2.getAttribute("is"), "testwithoutdash-extended", "The |is| attribute of the created element should be the extended type.");
is(element2.textContent, "", "Shouldn't have cloned the textContent");
document.querySelector("#content").appendChild(element2);
is(element2.textContent, "quux", "Should have set the textContent");
ok(element2 instanceof TestWithoutDashExtended, "Should be an instance of TestWithoutDashExtended");
ok(element2 instanceof TestWithoutDash, "Should be an instance of TestWithoutDash");
let element3 = new TestWithoutDashExtended();
is(element3.localName, "testwithoutdash", "Should see the right tag");
is(element3.textContent, "", "Shouldn't have been inserted yet");
is(element3.namespaceURI, XUL_NS, "Should have set the right namespace");
document.querySelector("#content").appendChild(element3);
is(element3.textContent, "quux", "Should have set the textContent");
ok(element3 instanceof TestWithoutDashExtended, "Should be an instance of TestWithoutDashExtended");
ok(element3 instanceof TestWithoutDash, "Should be an instance of TestWithoutDash");
}
function nonCustomElementCreate() {
// All of these should be created as plain XUL elements without hitting
// any assertions.
let elements = [
document.createElementNS(XUL_NS, "axulelement", { is: "test-custom-element" }),
document.createElementNS(XUL_NS, "axulelement", { is: "testwithoutdash" }),
document.createElementNS(XUL_NS, "axulelement", { is: "test-custom-element-1" }),
document.createElementNS(XUL_NS, "name-with-dash", { is: "name-with-dash" }),
document.createElementNS(XUL_NS, "name-with-dash", { is: "another-name-with-dash" }),
document.createElementNS(XUL_NS, "testwithoutdash-extended"),
document.createElementNS(XUL_NS, "test-built-in-element"),
document.createElementNS(XUL_NS, "test-popup-extend"),
document.createElementNS(XUL_NS, "test-built-in-element-1")];
for (let element of elements) {
is(Object.getPrototypeOf(element), XULElement.prototype,
`<${element.localName} is="${element.getAttribute("is")}" /> should not be a custom element.`);
}
}
function runTest() {
basicCustomElementCreate();
parserBasicElementUpgrade();
tagNameWithoutDash();
upgradeAfterDefine();
basicElementCreateBuiltIn();
parserBasicElementUpgradeBuiltIn();
subclassElementCreateBuiltIn();
parserSubclassElementUpgradeBuiltIn();
upgradeAfterDefineBuiltIn();
throwForInvalidBuiltInName();
extendingWithoutDashCustomElement();
nonCustomElementCreate();
SimpleTest.finish();
}
@@ -69,6 +299,8 @@
<div id="content" style="display: none">
<test-custom-element id="element4" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
<testwithoutdash id="element5" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
<axulelement id="element6" is="test-built-in-element" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
<popup id="element7" is="test-popup-extend" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
</div>
<pre id="test"></pre>
</body>

View File

@@ -190,7 +190,10 @@ nsXULElement::CreateFromPrototype(nsXULPrototypeElement* aPrototype,
{
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
nsCOMPtr<Element> baseElement;
NS_NewXULElement(getter_AddRefs(baseElement), ni.forget(), dom::FROM_PARSER_NETWORK);
NS_NewXULElement(getter_AddRefs(baseElement),
ni.forget(),
dom::FROM_PARSER_NETWORK,
aPrototype->mIsAtom);
if (baseElement) {
nsXULElement* element = FromNode(baseElement);
@@ -265,7 +268,8 @@ nsXULElement::CreateFromPrototype(nsXULPrototypeElement* aPrototype,
nsresult
NS_NewXULElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
FromParser aFromParser)
FromParser aFromParser, nsAtom* aIsAtom,
mozilla::dom::CustomElementDefinition* aDefinition)
{
RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
@@ -279,7 +283,7 @@ NS_NewXULElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& a
return NS_ERROR_NOT_AVAILABLE;
}
return nsContentUtils::NewXULOrHTMLElement(aResult, nodeInfo, aFromParser, nullptr, nullptr);
return nsContentUtils::NewXULOrHTMLElement(aResult, nodeInfo, aFromParser, aIsAtom, aDefinition);
}
void
@@ -2291,6 +2295,12 @@ nsXULPrototypeElement::SetAttrAt(uint32_t aPos, const nsAString& aValue,
// emptystring as id.
mAttributes[aPos].mValue.ParseAtom(aValue);
return NS_OK;
} else if (mAttributes[aPos].mName.Equals(nsGkAtoms::is)) {
// Store is as atom.
mAttributes[aPos].mValue.ParseAtom(aValue);
mIsAtom = mAttributes[aPos].mValue.GetAtomValue();
return NS_OK;
} else if (mAttributes[aPos].mName.Equals(nsGkAtoms::_class)) {
mHasClassAttribute = true;

View File

@@ -150,7 +150,8 @@ public:
mHasIdAttribute(false),
mHasClassAttribute(false),
mHasStyleAttribute(false),
mAttributes(nullptr)
mAttributes(nullptr),
mIsAtom(nullptr)
{
}
@@ -193,6 +194,7 @@ public:
uint32_t mHasClassAttribute:1;
uint32_t mHasStyleAttribute:1;
nsXULPrototypeAttribute* mAttributes; // [OWNER]
RefPtr<nsAtom> mIsAtom;
};
namespace mozilla {