Bug 1404420: Add custom element support to XUL. r=edgar, r=smaug

MozReview-Commit-ID: BietEX2gOoG

--HG--
extra : rebase_source : 6fd9a732a21f2c048d37c3f7139cd18503148767
This commit is contained in:
Dave Townsend 2017-10-10 15:25:10 -07:00
Родитель e5a567ca54
Коммит 27380b996e
21 изменённых файлов: 360 добавлений и 190 удалений

Просмотреть файл

@ -158,10 +158,12 @@ namespace {
class MOZ_RAII AutoConstructionStackEntry final
{
public:
AutoConstructionStackEntry(nsTArray<RefPtr<nsGenericHTMLElement>>& aStack,
nsGenericHTMLElement* aElement)
AutoConstructionStackEntry(nsTArray<RefPtr<Element>>& aStack,
Element* aElement)
: mStack(aStack)
{
MOZ_ASSERT(aElement->IsHTMLElement() || aElement->IsXULElement());
mIndex = mStack.Length();
mStack.AppendElement(aElement);
}
@ -174,7 +176,7 @@ public:
}
private:
nsTArray<RefPtr<nsGenericHTMLElement>>& mStack;
nsTArray<RefPtr<Element>>& mStack;
uint32_t mIndex;
};
@ -917,8 +919,7 @@ CustomElementRegistry::Upgrade(Element* aElement,
}
// Step 5.
AutoConstructionStackEntry acs(aDefinition->mConstructionStack,
nsGenericHTMLElement::FromContent(aElement));
AutoConstructionStackEntry acs(aDefinition->mConstructionStack, aElement);
// Step 6 and step 7.
DoUpgrade(aElement, aDefinition->mConstructor, aRv);

Просмотреть файл

@ -174,7 +174,7 @@ struct CustomElementDefinition
UniquePtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
// A construction stack. Use nullptr to represent an "already constructed marker".
nsTArray<RefPtr<nsGenericHTMLElement>> mConstructionStack;
nsTArray<RefPtr<Element>> mConstructionStack;
// The document custom element order.
uint32_t mDocOrder;

Просмотреть файл

@ -59,7 +59,8 @@ NS_NewMathMLElement(mozilla::dom::Element** aResult,
#ifdef MOZ_XUL
nsresult
NS_NewXULElement(mozilla::dom::Element** aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser);
void
NS_TrustedNewXULElement(nsIContent** aResult,

Просмотреть файл

@ -226,6 +226,7 @@
#include "nsPluginHost.h"
#include "mozilla/HangAnnotations.h"
#include "mozilla/Encoding.h"
#include "nsXULElement.h"
#include "nsIBidiKeyboard.h"
@ -10067,6 +10068,185 @@ nsContentUtils::TryToUpgradeElement(Element* aElement)
}
}
static void
DoCustomElementCreate(Element** aElement, nsIDocument* aDoc, NodeInfo* aNodeInfo,
CustomElementConstructor* aConstructor, ErrorResult& aRv)
{
RefPtr<Element> element =
aConstructor->Construct("Custom Element Create", aRv);
if (aRv.Failed()) {
return;
}
if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
if (!element || !element->IsHTMLElement()) {
aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("HTMLElement"));
return;
}
} else {
if (!element || !element->IsXULElement()) {
aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("XULElement"));
return;
}
}
nsAtom* localName = aNodeInfo->NameAtom();
if (aDoc != element->OwnerDoc() || element->GetParentNode() ||
element->HasChildren() || element->GetAttrCount() ||
element->NodeInfo()->NameAtom() != localName) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
element.forget(aElement);
}
/* static */ nsresult
nsContentUtils::NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* aNodeInfo,
FromParser aFromParser, const nsAString* aIs,
mozilla::dom::CustomElementDefinition* aDefinition)
{
RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
MOZ_ASSERT(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) ||
nodeInfo->NamespaceEquals(kNameSpaceID_XUL),
"Can only create XUL or XHTML elements.");
nsAtom *name = nodeInfo->NameAtom();
RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
RefPtr<nsAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom;
int32_t tag = eHTMLTag_unknown;
bool isCustomElementName = false;
if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
isCustomElementName = (tag == eHTMLTag_userdefined &&
nsContentUtils::IsCustomElementName(name));
} else {
isCustomElementName = nsContentUtils::IsCustomElementName(name);
}
bool isCustomElement = isCustomElementName || aIs;
MOZ_ASSERT_IF(aDefinition, isCustomElement);
// https://dom.spec.whatwg.org/#concept-create-element
// We only handle the "synchronous custom elements flag is set" now.
// For the unset case (e.g. cloning a node), see bug 1319342 for that.
// Step 4.
CustomElementDefinition* definition = aDefinition;
if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement &&
!definition) {
definition =
nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
nodeInfo->LocalName(),
nodeInfo->NamespaceID(),
typeAtom);
}
// It might be a problem that parser synchronously calls constructor, so filed
// bug 1378079 to figure out what we should do for parser case.
if (definition) {
/*
* Synchronous custom elements flag is determined by 3 places in spec,
* 1) create an element for a token, the flag is determined by
* "will execute script" which is not originally created
* for the HTML fragment parsing algorithm.
* 2) createElement and createElementNS, the flag is the same as
* NOT_FROM_PARSER.
* 3) clone a node, our implementation will not go into this function.
* For the unset case which is non-synchronous only applied for
* inner/outerHTML.
*/
bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT ||
aFromParser == dom::NOT_FROM_PARSER;
// Per discussion in https://github.com/w3c/webcomponents/issues/635,
// use entry global in those places that are called from JS APIs and use the
// node document's global object if it is called from parser.
nsIGlobalObject* global;
if (aFromParser == dom::NOT_FROM_PARSER) {
global = GetEntryGlobal();
} else {
global = nodeInfo->GetDocument()->GetScopeObject();
}
if (!global) {
// In browser chrome code, one may have access to a document which doesn't
// have scope object anymore.
return NS_ERROR_FAILURE;
}
AutoEntryScript aes(global, "create custom elements");
JSContext* cx = aes.cx();
ErrorResult rv;
// Step 5.
if (definition->IsCustomBuiltIn()) {
// SetupCustomElement() should be called with an element that don't have
// 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();
(*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
if (synchronousCustomElements) {
CustomElementRegistry::Upgrade(*aResult, definition, rv);
if (rv.MaybeSetPendingException(cx)) {
aes.ReportException();
}
} else {
nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
}
return NS_OK;
}
// Step 6.1.
if (synchronousCustomElements) {
DoCustomElementCreate(aResult, nodeInfo->GetDocument(), nodeInfo,
definition->mConstructor, rv);
if (rv.MaybeSetPendingException(cx)) {
if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(), aFromParser));
} else {
NS_IF_ADDREF(*aResult = new nsXULElement(nodeInfo.forget()));
}
}
return NS_OK;
}
// Step 6.2.
if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
} else {
NS_IF_ADDREF(*aResult = new nsXULElement(nodeInfo.forget()));
}
(*aResult)->SetCustomElementData(new CustomElementData(definition->mType));
nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
return NS_OK;
}
if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
// Per the Custom Element specification, unknown tags that are valid custom
// element names should be HTMLElement instead of HTMLUnknownElement.
if (isCustomElementName) {
NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
} else {
*aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
}
} else {
NS_IF_ADDREF(*aResult = new nsXULElement(nodeInfo.forget()));
}
if (!*aResult) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement) {
(*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
}
return NS_OK;
}
/* static */ CustomElementDefinition*
nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc,
const nsAString& aLocalName,
@ -10075,7 +10255,8 @@ nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc,
{
MOZ_ASSERT(aDoc);
if (aNameSpaceID != kNameSpaceID_XHTML ||
if ((aNameSpaceID != kNameSpaceID_XUL &&
aNameSpaceID != kNameSpaceID_XHTML) ||
!aDoc->GetDocShell()) {
return nullptr;
}
@ -10176,7 +10357,8 @@ nsContentUtils::GetCustomPrototype(nsIDocument* aDoc,
{
MOZ_ASSERT(aDoc);
if (aNamespaceID != kNameSpaceID_XHTML ||
if ((aNamespaceID != kNameSpaceID_XHTML &&
aNamespaceID != kNameSpaceID_XUL) ||
!aDoc->GetDocShell()) {
return;
}

Просмотреть файл

@ -20,6 +20,7 @@
#include "js/TypeDecls.h"
#include "js/Value.h"
#include "js/RootingAPI.h"
#include "mozilla/dom/FromParser.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/EventForwards.h"
#include "mozilla/GuardObjects.h"
@ -3028,6 +3029,14 @@ public:
*/
static void TryToUpgradeElement(Element* aElement);
/**
* Creates a new XUL or XHTML element applying any appropriate custom element
* definition.
*/
static nsresult NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* aNodeInfo,
mozilla::dom::FromParser aFromParser, const nsAString* aIs,
mozilla::dom::CustomElementDefinition* aDefinition);
/**
* Looking up a custom element definition.
* https://html.spec.whatwg.org/#look-up-a-custom-element-definition

Просмотреть файл

@ -6398,7 +6398,7 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
// that old upgrade behavior could also share the new upgrade steps.
// And this old upgrade will be remove at some point (when everything is
// switched to latest custom element spec).
nsTArray<RefPtr<nsGenericHTMLElement>>& constructionStack =
nsTArray<RefPtr<Element>>& constructionStack =
definition->mConstructionStack;
if (constructionStack.Length()) {
element = constructionStack.LastElement();

Просмотреть файл

@ -183,7 +183,7 @@ NS_NewElement(Element** aResult,
}
#ifdef MOZ_XUL
if (ns == kNameSpaceID_XUL) {
return NS_NewXULElement(aResult, ni.forget());
return NS_NewXULElement(aResult, ni.forget(), aFromParser);
}
#endif
if (ns == kNameSpaceID_MathML) {

Просмотреть файл

@ -458,7 +458,7 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
}
if (CustomElementRegistry::IsCustomElementEnabled() &&
clone->IsHTMLElement()) {
(clone->IsHTMLElement() || clone->IsXULElement())) {
// The cloned node may be a custom element that may require
// enqueing upgrade reaction.
Element* cloneElem = clone->AsElement();

Просмотреть файл

@ -46,6 +46,7 @@
#include "mozilla/dom/HTMLEmbedElement.h"
#include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/HTMLEmbedElementBinding.h"
#include "mozilla/dom/XULElementBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ResolveSystemBinding.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"
@ -57,6 +58,7 @@
#include "ipc/ErrorIPCUtils.h"
#include "mozilla/UseCounter.h"
#include "mozilla/dom/DocGroup.h"
#include "nsXULElement.h"
namespace mozilla {
namespace dom {
@ -3548,9 +3550,9 @@ GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj)
}
// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
already_AddRefed<nsGenericHTMLElement>
CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv)
already_AddRefed<Element>
CreateXULOrHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv)
{
// Step 1.
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
@ -3565,6 +3567,11 @@ CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
return nullptr;
}
int32_t ns = doc->GetDefaultNamespaceID();
if (ns != kNameSpaceID_XUL) {
ns = kNameSpaceID_XHTML;
}
RefPtr<mozilla::dom::CustomElementRegistry> registry(window->CustomElements());
if (!registry) {
aRv.Throw(NS_ERROR_UNEXPECTED);
@ -3597,8 +3604,14 @@ CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
if (!definition->IsCustomBuiltIn()) {
// Step 4.
// If the definition is for an autonomous custom element, the active
// function should be HTMLElement.
JS::Rooted<JSObject*> constructor(cx, HTMLElementBinding::GetConstructorObject(cx));
// function should be HTMLElement or XULElement
JS::Rooted<JSObject*> constructor(cx);
if (ns == kNameSpaceID_XUL) {
constructor = XULElementBinding::GetConstructorObject(cx);
} else {
constructor = HTMLElementBinding::GetConstructorObject(cx);
}
if (!constructor) {
aRv.NoteJSContextException(cx);
return nullptr;
@ -3612,6 +3625,13 @@ CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
// Step 5.
// If the definition is for a customized built-in element, the localName
// should be defined in the specification.
// Customized built-in elements are not supported for XUL yet.
if (ns == kNameSpaceID_XUL) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
if (tag == eHTMLTag_userdefined) {
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
@ -3643,7 +3663,7 @@ CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
RefPtr<mozilla::dom::NodeInfo> nodeInfo =
doc->NodeInfoManager()->GetNodeInfo(definition->mLocalName,
nullptr,
kNameSpaceID_XHTML,
ns,
nsIDOMNode::ELEMENT_NODE);
if (!nodeInfo) {
aRv.Throw(NS_ERROR_UNEXPECTED);
@ -3652,16 +3672,20 @@ CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
// Step 6 and Step 7 are in the code output by CGClassConstructor.
// Step 8.
nsTArray<RefPtr<nsGenericHTMLElement>>& constructionStack =
nsTArray<RefPtr<Element>>& constructionStack =
definition->mConstructionStack;
if (constructionStack.IsEmpty()) {
RefPtr<nsGenericHTMLElement> newElement;
if (tag == eHTMLTag_userdefined) {
// Autonomous custom element.
newElement = NS_NewHTMLElement(nodeInfo.forget());
RefPtr<Element> newElement;
if (ns == kNameSpaceID_XUL) {
newElement = new nsXULElement(nodeInfo.forget());
} else {
// Customized built-in element.
newElement = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
if (tag == eHTMLTag_userdefined) {
// Autonomous custom element.
newElement = NS_NewHTMLElement(nodeInfo.forget());
} else {
// Customized built-in element.
newElement = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
}
}
newElement->SetCustomElementData(
@ -3673,7 +3697,7 @@ CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
}
// Step 9.
RefPtr<nsGenericHTMLElement>& element = constructionStack.LastElement();
RefPtr<Element>& element = constructionStack.LastElement();
// Step 10.
if (element == ALEADY_CONSTRUCTED_MARKER) {

Просмотреть файл

@ -3391,11 +3391,11 @@ GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
CustomElementReactionsStack*
GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj);
// This function is expected to be called from the constructor function for an
// HTML element interface; the global/callargs need to be whatever was passed to
// that constructor function.
already_AddRefed<nsGenericHTMLElement>
CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv);
// HTML or XUL element interface; the global/callargs need to be whatever was
// passed to that constructor function.
already_AddRefed<Element>
CreateXULOrHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv);
void
SetDocumentAndPageUseCounter(JSObject* aObject, UseCounter aUseCounter);

Просмотреть файл

@ -1907,11 +1907,11 @@ class CGClassConstructor(CGAbstractStaticMethod):
signatures = self._ctor.signatures()
assert len(signatures) == 1
# Given that HTMLConstructor takes no args, we can just codegen a
# call to CreateHTMLElement() in BindingUtils which reuses the
# call to CreateXULOrHTMLElement() in BindingUtils which reuses the
# factory thing in HTMLContentSink. Then we don't have to implement
# Constructor on all the HTML elements.
callGenerator = CGPerSignatureCall(signatures[0][0], signatures[0][1],
"CreateHTMLElement", True,
"CreateXULOrHTMLElement", True,
self.descriptor, self._ctor,
isConstructor=True)
else:

Просмотреть файл

@ -224,157 +224,17 @@ public:
int32_t mStackPos;
};
static void
DoCustomElementCreate(Element** aElement, nsIDocument* aDoc, nsAtom* aLocalName,
CustomElementConstructor* aConstructor, ErrorResult& aRv)
{
RefPtr<Element> element =
aConstructor->Construct("Custom Element Create", aRv);
if (aRv.Failed()) {
return;
}
if (!element || !element->IsHTMLElement()) {
aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("HTMLElement"));
return;
}
if (aDoc != element->OwnerDoc() || element->GetParentNode() ||
element->HasChildren() || element->GetAttrCount() ||
element->NodeInfo()->NameAtom() != aLocalName) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
element.forget(aElement);
}
nsresult
NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
FromParser aFromParser, const nsAString* aIs,
mozilla::dom::CustomElementDefinition* aDefinition)
{
*aResult = nullptr;
RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
nsAtom *name = nodeInfo->NameAtom();
RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
RefPtr<nsAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom;
NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
"Trying to HTML elements that don't have the XHTML namespace");
"Trying to create HTML elements that don't have the XHTML namespace");
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
bool isCustomElementName = (tag == eHTMLTag_userdefined &&
nsContentUtils::IsCustomElementName(name));
bool isCustomElement = isCustomElementName || aIs;
MOZ_ASSERT_IF(aDefinition, isCustomElement);
// https://dom.spec.whatwg.org/#concept-create-element
// We only handle the "synchronous custom elements flag is set" now.
// For the unset case (e.g. cloning a node), see bug 1319342 for that.
// Step 4.
CustomElementDefinition* definition = aDefinition;
if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement &&
!definition) {
definition =
nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
nodeInfo->LocalName(),
nodeInfo->NamespaceID(),
typeAtom);
}
// It might be a problem that parser synchronously calls constructor, so filed
// bug 1378079 to figure out what we should do for parser case.
if (definition) {
/*
* Synchronous custom elements flag is determined by 3 places in spec,
* 1) create an element for a token, the flag is determined by
* "will execute script" which is not originally created
* for the HTML fragment parsing algorithm.
* 2) createElement and createElementNS, the flag is the same as
* NOT_FROM_PARSER.
* 3) clone a node, our implementation will not go into this function.
* For the unset case which is non-synchronous only applied for
* inner/outerHTML.
*/
bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT ||
aFromParser == dom::NOT_FROM_PARSER;
// Per discussion in https://github.com/w3c/webcomponents/issues/635,
// use entry global in those places that are called from JS APIs and use the
// node document's global object if it is called from parser.
nsIGlobalObject* global;
if (aFromParser == dom::NOT_FROM_PARSER) {
global = GetEntryGlobal();
} else {
global = nodeInfo->GetDocument()->GetScopeObject();
}
if (!global) {
// In browser chrome code, one may have access to a document which doesn't
// have scope object anymore.
return NS_ERROR_FAILURE;
}
AutoEntryScript aes(global, "create custom elements");
JSContext* cx = aes.cx();
ErrorResult rv;
// Step 5.
if (definition->IsCustomBuiltIn()) {
// SetupCustomElement() should be called with an element that don't have
// CustomElementData setup, if not we will hit the assertion in
// SetCustomElementData().
// Built-in element
*aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
(*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
if (synchronousCustomElements) {
CustomElementRegistry::Upgrade(*aResult, definition, rv);
if (rv.MaybeSetPendingException(cx)) {
aes.ReportException();
}
} else {
nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
}
return NS_OK;
}
// Step 6.1.
if (synchronousCustomElements) {
DoCustomElementCreate(aResult, nodeInfo->GetDocument(),
nodeInfo->NameAtom(),
definition->mConstructor, rv);
if (rv.MaybeSetPendingException(cx)) {
NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(), aFromParser));
}
return NS_OK;
}
// Step 6.2.
NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
(*aResult)->SetCustomElementData(new CustomElementData(definition->mType));
nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
return NS_OK;
}
// Per the Custom Element specification, unknown tags that are valid custom
// element names should be HTMLElement instead of HTMLUnknownElement.
if (isCustomElementName) {
NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
} else {
*aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
}
if (!*aResult) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement) {
(*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
}
return NS_OK;
return nsContentUtils::NewXULOrHTMLElement(aResult, nodeInfo, aFromParser, aIs, aDefinition);
}
already_AddRefed<nsGenericHTMLElement>

Просмотреть файл

@ -10,4 +10,5 @@ support-files =
[test_custom_element_upgrade_chrome.html]
support-files =
test_upgrade_page.html
upgrade_tests.js
upgrade_tests.js
[test_xul_custom_element.xul]

Просмотреть файл

@ -0,0 +1,68 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window title="XUL Custom Elements"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="runTest();">
<title>XUL Custom Elements</title>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
class TestCustomElement extends XULElement {
constructor() {
super();
}
connectedCallback() {
this.textContent = "foo";
}
}
customElements.define("test-custom-element", TestCustomElement);
function runTest() {
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let element = document.createElementNS(XUL_NS, "test-custom-element");
document.querySelector("#content").appendChild(element);
is(element.textContent, "foo", "Should have set the textContent");
ok(element instanceof TestCustomElement, "Should be an instance of TestCustomElement");
let element2 = element.cloneNode(false);
is(element2.textContent, "", "Shouldn't have cloned the textContent");
document.querySelector("#content").appendChild(element2);
is(element2.textContent, "foo", "Should have set the textContent");
ok(element2 instanceof TestCustomElement, "Should be an instance of TestCustomElement");
let element3 = new TestCustomElement();
is(element3.localName, "test-custom-element", "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, "foo", "Should have set the textContent");
ok(element3 instanceof TestCustomElement, "Should be an instance of TestCustomElement");
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");
SimpleTest.finish();
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display: none">
<test-custom-element id="element4" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
</div>
<pre id="test"></pre>
</body>
</window>

Просмотреть файл

@ -8,7 +8,7 @@ interface XULControllers;
interface MozRDFCompositeDataSource;
interface MozRDFResource;
[Func="IsChromeOrXBL"]
[HTMLConstructor, Func="IsChromeOrXBL"]
interface XULElement : Element {
// Layout properties
[SetterThrows]

Просмотреть файл

@ -1034,6 +1034,11 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun
rv = NS_NewXMLDocument(getter_AddRefs(doc));
NS_ENSURE_SUCCESS(rv, rv);
// XBL documents must allow XUL and XBL elements in them but the usual check
// only checks if the document is loaded in the system principal which is
// sometimes not the case.
doc->ForceEnableXULXBL();
// Set the style backend type before loading the XBL document. Assume
// gecko if there's no bound document.
doc->SetStyleBackendType(aBoundDocument ? aBoundDocument->GetStyleBackendType()

Просмотреть файл

@ -236,6 +236,12 @@ NS_NewXBLDocument(nsIDOMDocument** aInstancePtrResult,
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> idoc = do_QueryInterface(*aInstancePtrResult);
// XBL documents must allow XUL and XBL elements in them but the usual check
// only checks if the document is loaded in the system principal which is
// sometimes not the case.
idoc->ForceEnableXULXBL();
nsDocument* doc = static_cast<nsDocument*>(idoc.get());
doc->SetLoadedAsInteractiveData(true);
doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);

Просмотреть файл

@ -20,6 +20,7 @@ if CONFIG['MOZ_XUL']:
EXPORTS += [
'nsIXULDocument.h',
'nsXULElement.h',
]
UNIFIED_SOURCES += [

Просмотреть файл

@ -186,8 +186,12 @@ nsXULElement::Create(nsXULPrototypeElement* aPrototype, mozilla::dom::NodeInfo *
bool aIsScriptable, bool aIsRoot)
{
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
RefPtr<nsXULElement> element = new nsXULElement(ni.forget());
if (element) {
nsCOMPtr<Element> baseElement;
NS_NewXULElement(getter_AddRefs(baseElement), ni.forget(), dom::FROM_PARSER_NETWORK);
if (baseElement) {
nsXULElement* element = FromContent(baseElement);
if (aPrototype->mHasIdAttribute) {
element->SetHasID();
}
@ -216,9 +220,11 @@ nsXULElement::Create(nsXULPrototypeElement* aPrototype, mozilla::dom::NodeInfo *
}
}
}
return baseElement.forget().downcast<nsXULElement>();
}
return element.forget();
return nullptr;
}
nsresult
@ -255,20 +261,22 @@ nsXULElement::Create(nsXULPrototypeElement* aPrototype,
}
nsresult
NS_NewXULElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
NS_NewXULElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
FromParser aFromParser)
{
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
NS_PRECONDITION(ni, "need nodeinfo for non-proto Create");
NS_PRECONDITION(nodeInfo, "need nodeinfo for non-proto Create");
nsIDocument* doc = ni->GetDocument();
NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XUL),
"Trying to create XUL elements that don't have the XUL namespace");
nsIDocument* doc = nodeInfo->GetDocument();
if (doc && !doc->AllowXULXBL()) {
return NS_ERROR_NOT_AVAILABLE;
}
NS_ADDREF(*aResult = new nsXULElement(ni.forget()));
return NS_OK;
return nsContentUtils::NewXULOrHTMLElement(aResult, nodeInfo, aFromParser, nullptr, nullptr);
}
void

Просмотреть файл

@ -40,6 +40,7 @@
#include "mozilla/dom/DOMRect.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/DOMString.h"
#include "mozilla/dom/FromParser.h"
class nsIDocument;
class nsXULPrototypeDocument;
@ -799,7 +800,8 @@ protected:
bool BoolAttrIsTrue(nsAtom* aName) const;
friend nsresult
NS_NewXULElement(mozilla::dom::Element** aResult, mozilla::dom::NodeInfo *aNodeInfo);
NS_NewXULElement(mozilla::dom::Element** aResult, mozilla::dom::NodeInfo *aNodeInfo,
mozilla::dom::FromParser aFromParser, const nsAString* aIs);
friend void
NS_TrustedNewXULElement(nsIContent** aResult, mozilla::dom::NodeInfo *aNodeInfo);

Просмотреть файл

@ -21,6 +21,7 @@
#include "nsContentCreatorFunctions.h"
#include "nsContentUtils.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/FromParser.h"
//#define DEBUG_REFLOW
@ -98,7 +99,7 @@ nsDocElementBoxFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = NS_NewXULElement(getter_AddRefs(mPopupgroupContent),
nodeInfo.forget());
nodeInfo.forget(), dom::NOT_FROM_PARSER);
NS_ENSURE_SUCCESS(rv, rv);
if (!aElements.AppendElement(mPopupgroupContent))
@ -110,7 +111,8 @@ nsDocElementBoxFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
nsIDOMNode::ELEMENT_NODE);
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
rv = NS_NewXULElement(getter_AddRefs(mTooltipContent), nodeInfo.forget());
rv = NS_NewXULElement(getter_AddRefs(mTooltipContent), nodeInfo.forget(),
dom::NOT_FROM_PARSER);
NS_ENSURE_SUCCESS(rv, rv);
mTooltipContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_default,