diff options
Diffstat (limited to 'dom/base/nsDocument.cpp')
-rw-r--r-- | dom/base/nsDocument.cpp | 179 |
1 files changed, 123 insertions, 56 deletions
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index afe88a454..293e48eb0 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -1329,7 +1329,8 @@ nsIDocument::nsIDocument() mFrameRequestCallbacksScheduled(false), mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS), mPartID(0), - mUserHasInteracted(false) + mUserHasInteracted(false), + mThrowOnDynamicMarkupInsertionCounter(0) { SetIsInDocument(); @@ -5395,18 +5396,14 @@ nsDocument::CreateElement(const nsAString& aTagName, } const nsString* is = nullptr; - if (aOptions.IsElementCreationOptions()) { - // Throw NotFoundError if 'is' is not-null and definition is null - is = CheckCustomElementName(aOptions.GetAsElementCreationOptions(), - needsLowercase ? lcTagName : aTagName, mDefaultElementType, rv); - if (rv.Failed()) { - return nullptr; - } - } RefPtr<Element> elem = CreateElem( needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is); + if (is) { + elem->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true); + } + return elem.forget(); } @@ -5443,14 +5440,6 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI, } const nsString* is = nullptr; - if (aOptions.IsElementCreationOptions()) { - // Throw NotFoundError if 'is' is not-null and definition is null - is = CheckCustomElementName(aOptions.GetAsElementCreationOptions(), - aQualifiedName, nodeInfo->NamespaceID(), rv); - if (rv.Failed()) { - return nullptr; - } - } nsCOMPtr<Element> element; rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), @@ -5459,6 +5448,10 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI, return nullptr; } + if (is) { + element->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true); + } + return element.forget(); } @@ -5681,24 +5674,70 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* } nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName)); - CustomElementDefinition* definition = registry->mCustomDefinitions.Get(typeAtom); + CustomElementDefinition* definition = + registry->mCustomDefinitions.GetWeak(typeAtom); if (!definition) { return true; } - nsDependentAtomString localName(definition->mLocalName); + RefPtr<Element> element; + + // We integrate with construction stack and do prototype swizzling here, so + // 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 = + definition->mConstructionStack; + if (constructionStack.Length()) { + element = constructionStack.LastElement(); + NS_ENSURE_TRUE(element != ALEADY_CONSTRUCTED_MARKER, false); + + // Do prototype swizzling if dom reflector exists. + JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper()); + if (reflector) { + Maybe<JSAutoCompartment> ac; + JS::Rooted<JSObject*> prototype(aCx, definition->mPrototype); + if (element->NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(prototype))) { + ac.emplace(aCx, reflector); + if (!JS_WrapObject(aCx, &prototype) || + !JS_SetPrototype(aCx, reflector, prototype)) { + return false; + } + } else { + // We want to set the custom prototype in the compartment where it was + // registered. We store the prototype from define() without unwrapped, + // hence the prototype's compartment is the compartment where it was + // registered. + // In the case that |reflector| and |prototype| are in different + // compartments, this will set the prototype on the |reflector|'s wrapper + // and thus only visible in the wrapper's compartment, since we know + // reflector's principal does not subsume prototype's in this case. + ac.emplace(aCx, prototype); + if (!JS_WrapObject(aCx, &reflector) || + !JS_SetPrototype(aCx, reflector, prototype)) { + return false; + } + } - nsCOMPtr<Element> element = - document->CreateElem(localName, nullptr, kNameSpaceID_XHTML); - NS_ENSURE_TRUE(element, true); + // Wrap into current context. + if (!JS_WrapObject(aCx, &reflector)) { + return false; + } - if (definition->mLocalName != typeAtom) { - // This element is a custom element by extension, thus we need to - // do some special setup. For non-extended custom elements, this happens - // when the element is created. - nsContentUtils::SetupCustomElement(element, &elemName); + args.rval().setObject(*reflector); + return true; + } + } else { + nsDependentAtomString localName(definition->mLocalName); + element = + document->CreateElem(localName, nullptr, kNameSpaceID_XHTML, + (definition->mLocalName != typeAtom) ? &elemName + : nullptr); + NS_ENSURE_TRUE(element, false); } + // The prototype setup happens in Element::WrapObject(). + nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval()); NS_ENSURE_SUCCESS(rv, true); @@ -5710,7 +5749,7 @@ nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject) { JS::Rooted<JSObject*> obj(aCx, aObject); - if (Preferences::GetBool("dom.webcomponents.enabled")) { + if (nsContentUtils::IsWebComponentsEnabled()) { return true; } @@ -5726,7 +5765,7 @@ nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject) bool nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo) { - if (Preferences::GetBool("dom.webcomponents.enabled")) { + if (nsContentUtils::IsWebComponentsEnabled()) { return true; } @@ -5770,6 +5809,8 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType, return; } + AutoCEReaction ceReaction(this->GetDocGroup()->CustomElementReactionsStack(), + aCx); // Unconditionally convert TYPE to lowercase. nsAutoString lcType; nsContentUtils::ASCIIToLower(aType, lcType); @@ -6536,6 +6577,49 @@ nsIDocument::GetHtmlChildElement(nsIAtom* aTag) return nullptr; } +nsGenericHTMLElement* +nsIDocument::GetBody() +{ + Element* html = GetHtmlElement(); + if (!html) { + return nullptr; + } + + for (nsIContent* child = html->GetFirstChild(); + child; + child = child->GetNextSibling()) { + if (child->IsHTMLElement(nsGkAtoms::body) || + child->IsHTMLElement(nsGkAtoms::frameset)) { + return static_cast<nsGenericHTMLElement*>(child); + } + } + + return nullptr; +} + +void +nsIDocument::SetBody(nsGenericHTMLElement* newBody, ErrorResult& rv) +{ + nsCOMPtr<Element> root = GetRootElement(); + + // The body element must be either a body tag or a frameset tag. And we must + // have a root element to be able to add kids to it. + if (!newBody || + !newBody->IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset) || + !root) { + rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); + return; + } + + // Use DOM methods so that we pass through the appropriate security checks. + nsCOMPtr<Element> currentBody = GetBody(); + if (currentBody) { + root->ReplaceChild(*newBody, *currentBody, rv); + } else { + root->AppendChild(*newBody, rv); + } +} + Element* nsDocument::GetTitleElement() { @@ -12526,8 +12610,12 @@ MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData) nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument* aDoc) { - mMicroTaskLevel = nsContentUtils::MicroTaskLevel(); - nsContentUtils::SetMicroTaskLevel(0); + mMicroTaskLevel = 0; + CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); + if (ccjs) { + mMicroTaskLevel = ccjs->MicroTaskLevel(); + ccjs->SetMicroTaskLevel(0); + } if (aDoc) { if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) { if (nsCOMPtr<nsPIDOMWindowOuter> top = win->GetTop()) { @@ -12543,7 +12631,10 @@ nsAutoSyncOperation::~nsAutoSyncOperation() for (int32_t i = 0; i < mDocuments.Count(); ++i) { mDocuments[i]->SetIsInSyncOperation(false); } - nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel); + CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); + if (ccjs) { + ccjs->SetMicroTaskLevel(mMicroTaskLevel); + } } gfxUserFontSet* @@ -12713,30 +12804,6 @@ nsIDocument::UpdateStyleBackendType() #endif } -const nsString* -nsDocument::CheckCustomElementName(const ElementCreationOptions& aOptions, - const nsAString& aLocalName, - uint32_t aNamespaceID, - ErrorResult& rv) -{ - // only check aOptions if 'is' is passed and the webcomponents preference - // is enabled - if (!aOptions.mIs.WasPassed() || - !CustomElementRegistry::IsCustomElementEnabled()) { - return nullptr; - } - - const nsString* is = &aOptions.mIs.Value(); - - // Throw NotFoundError if 'is' is not-null and definition is null - if (!nsContentUtils::LookupCustomElementDefinition(this, aLocalName, - aNamespaceID, is)) { - rv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); - } - - return is; -} - Selection* nsIDocument::GetSelection(ErrorResult& aRv) { |