зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
e5a567ca54
Коммит
27380b996e
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче