forked from mirrors/gecko-dev
		
	 8925ee2d3d
			
		
	
	
		8925ee2d3d
		
	
	
	
	
		
			
			Much like BindToTree. This will be useful because I need to pass more information through UnbindFromTree() to speed up dir=auto for bug 1874040. Differential Revision: https://phabricator.services.mozilla.com/D202215
		
			
				
	
	
		
			467 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			467 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "mozilla/dom/HTMLElement.h"
 | |
| 
 | |
| #include "mozilla/EventDispatcher.h"
 | |
| #include "mozilla/PresState.h"
 | |
| #include "mozilla/dom/CustomElementRegistry.h"
 | |
| #include "mozilla/dom/ElementInternalsBinding.h"
 | |
| #include "mozilla/dom/FormData.h"
 | |
| #include "mozilla/dom/FromParser.h"
 | |
| #include "mozilla/dom/HTMLElementBinding.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsGenericHTMLElement.h"
 | |
| #include "nsILayoutHistoryState.h"
 | |
| 
 | |
| namespace mozilla::dom {
 | |
| 
 | |
| HTMLElement::HTMLElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
 | |
|                          FromParser aFromParser)
 | |
|     : nsGenericHTMLFormElement(std::move(aNodeInfo)) {
 | |
|   if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
 | |
|     AddStatesSilently(ElementState::HAS_DIR_ATTR_LIKE_AUTO);
 | |
|   }
 | |
| 
 | |
|   InhibitRestoration(!(aFromParser & FROM_PARSER_NETWORK));
 | |
| }
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLElement, nsGenericHTMLFormElement)
 | |
| 
 | |
| // QueryInterface implementation for HTMLElement
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLElement)
 | |
|   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIFormControl, GetElementInternals())
 | |
|   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIConstraintValidation, GetElementInternals())
 | |
| NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLFormElement)
 | |
| 
 | |
| NS_IMPL_ADDREF_INHERITED(HTMLElement, nsGenericHTMLFormElement)
 | |
| NS_IMPL_RELEASE_INHERITED(HTMLElement, nsGenericHTMLFormElement)
 | |
| 
 | |
| NS_IMPL_ELEMENT_CLONE(HTMLElement)
 | |
| 
 | |
| JSObject* HTMLElement::WrapNode(JSContext* aCx,
 | |
|                                 JS::Handle<JSObject*> aGivenProto) {
 | |
|   return dom::HTMLElement_Binding::Wrap(aCx, this, aGivenProto);
 | |
| }
 | |
| 
 | |
| void HTMLElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
 | |
|   if (IsDisabledForEvents(aVisitor.mEvent)) {
 | |
|     // Do not process any DOM events if the element is disabled
 | |
|     aVisitor.mCanHandle = false;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   nsGenericHTMLFormElement::GetEventTargetParent(aVisitor);
 | |
| }
 | |
| 
 | |
| nsINode* HTMLElement::GetScopeChainParent() const {
 | |
|   if (IsFormAssociatedCustomElements()) {
 | |
|     auto* form = GetFormInternal();
 | |
|     if (form) {
 | |
|       return form;
 | |
|     }
 | |
|   }
 | |
|   return nsGenericHTMLFormElement::GetScopeChainParent();
 | |
| }
 | |
| 
 | |
| nsresult HTMLElement::BindToTree(BindContext& aContext, nsINode& aParent) {
 | |
|   nsresult rv = nsGenericHTMLFormElement::BindToTree(aContext, aParent);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   UpdateBarredFromConstraintValidation();
 | |
|   UpdateValidityElementStates(false);
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| void HTMLElement::UnbindFromTree(UnbindContext& aContext) {
 | |
|   nsGenericHTMLFormElement::UnbindFromTree(aContext);
 | |
| 
 | |
|   UpdateBarredFromConstraintValidation();
 | |
|   UpdateValidityElementStates(false);
 | |
| }
 | |
| 
 | |
| void HTMLElement::DoneCreatingElement() {
 | |
|   if (MOZ_UNLIKELY(IsFormAssociatedElement())) {
 | |
|     MaybeRestoreFormAssociatedCustomElementState();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void HTMLElement::SaveState() {
 | |
|   if (MOZ_LIKELY(!IsFormAssociatedElement())) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   auto* internals = GetElementInternals();
 | |
| 
 | |
|   nsCString stateKey = internals->GetStateKey();
 | |
|   if (stateKey.IsEmpty()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsILayoutHistoryState> history = GetLayoutHistory(false);
 | |
|   if (!history) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Get the pres state for this key, if it doesn't exist, create one.
 | |
|   PresState* result = history->GetState(stateKey);
 | |
|   if (!result) {
 | |
|     UniquePtr<PresState> newState = NewPresState();
 | |
|     result = newState.get();
 | |
|     history->AddState(stateKey, std::move(newState));
 | |
|   }
 | |
| 
 | |
|   const auto& state = internals->GetFormState();
 | |
|   const auto& value = internals->GetFormSubmissionValue();
 | |
|   result->contentData() = CustomElementTuple(
 | |
|       nsContentUtils::ConvertToCustomElementFormValue(value),
 | |
|       nsContentUtils::ConvertToCustomElementFormValue(state));
 | |
| }
 | |
| 
 | |
| void HTMLElement::MaybeRestoreFormAssociatedCustomElementState() {
 | |
|   MOZ_ASSERT(IsFormAssociatedElement());
 | |
| 
 | |
|   if (HasFlag(HTML_ELEMENT_INHIBIT_RESTORATION)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   auto* internals = GetElementInternals();
 | |
|   if (internals->GetStateKey().IsEmpty()) {
 | |
|     Document* doc = GetUncomposedDoc();
 | |
|     nsCString stateKey;
 | |
|     nsContentUtils::GenerateStateKey(this, doc, stateKey);
 | |
|     internals->SetStateKey(std::move(stateKey));
 | |
| 
 | |
|     RestoreFormAssociatedCustomElementState();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void HTMLElement::RestoreFormAssociatedCustomElementState() {
 | |
|   MOZ_ASSERT(IsFormAssociatedElement());
 | |
| 
 | |
|   auto* internals = GetElementInternals();
 | |
| 
 | |
|   const nsCString& stateKey = internals->GetStateKey();
 | |
|   if (stateKey.IsEmpty()) {
 | |
|     return;
 | |
|   }
 | |
|   nsCOMPtr<nsILayoutHistoryState> history = GetLayoutHistory(true);
 | |
|   if (!history) {
 | |
|     return;
 | |
|   }
 | |
|   PresState* result = history->GetState(stateKey);
 | |
|   if (!result) {
 | |
|     return;
 | |
|   }
 | |
|   auto& content = result->contentData();
 | |
|   if (content.type() != PresContentData::TCustomElementTuple) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   auto& ce = content.get_CustomElementTuple();
 | |
|   nsCOMPtr<nsIGlobalObject> global = GetOwnerDocument()->GetOwnerGlobal();
 | |
|   internals->RestoreFormValue(
 | |
|       nsContentUtils::ExtractFormAssociatedCustomElementValue(global,
 | |
|                                                               ce.value()),
 | |
|       nsContentUtils::ExtractFormAssociatedCustomElementValue(global,
 | |
|                                                               ce.state()));
 | |
| }
 | |
| 
 | |
| void HTMLElement::InhibitRestoration(bool aShouldInhibit) {
 | |
|   if (aShouldInhibit) {
 | |
|     SetFlags(HTML_ELEMENT_INHIBIT_RESTORATION);
 | |
|   } else {
 | |
|     UnsetFlags(HTML_ELEMENT_INHIBIT_RESTORATION);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void HTMLElement::SetCustomElementDefinition(
 | |
|     CustomElementDefinition* aDefinition) {
 | |
|   nsGenericHTMLFormElement::SetCustomElementDefinition(aDefinition);
 | |
|   // Always create an ElementInternal for form-associated custom element as the
 | |
|   // Form related implementation lives in ElementInternal which implements
 | |
|   // nsIFormControl. It is okay for the attachElementInternal API as there is a
 | |
|   // separated flag for whether attachElementInternal is called.
 | |
|   if (aDefinition && !aDefinition->IsCustomBuiltIn() &&
 | |
|       aDefinition->mFormAssociated) {
 | |
|     CustomElementData* data = GetCustomElementData();
 | |
|     MOZ_ASSERT(data);
 | |
|     auto* internals = data->GetOrCreateElementInternals(this);
 | |
| 
 | |
|     // This is for the case that script constructs a custom element directly,
 | |
|     // e.g. via new MyCustomElement(), where the upgrade steps won't be ran to
 | |
|     // update the disabled state in UpdateFormOwner().
 | |
|     if (data->mState == CustomElementData::State::eCustom) {
 | |
|       UpdateDisabledState(true);
 | |
|     } else if (!HasFlag(HTML_ELEMENT_INHIBIT_RESTORATION)) {
 | |
|       internals->InitializeControlNumber();
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| // https://html.spec.whatwg.org/commit-snapshots/53bc3803433e1c817918b83e8a84f3db900031dd/#dom-attachinternals
 | |
| already_AddRefed<ElementInternals> HTMLElement::AttachInternals(
 | |
|     ErrorResult& aRv) {
 | |
|   CustomElementData* ceData = GetCustomElementData();
 | |
| 
 | |
|   // 1. If element's is value is not null, then throw a "NotSupportedError"
 | |
|   //    DOMException.
 | |
|   if (nsAtom* isAtom = ceData ? ceData->GetIs(this) : nullptr) {
 | |
|     aRv.ThrowNotSupportedError(nsPrintfCString(
 | |
|         "Cannot attach ElementInternals to a customized built-in element "
 | |
|         "'%s'",
 | |
|         NS_ConvertUTF16toUTF8(isAtom->GetUTF16String()).get()));
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   // 2. Let definition be the result of looking up a custom element definition
 | |
|   //    given element's node document, its namespace, its local name, and null
 | |
|   //    as is value.
 | |
|   nsAtom* nameAtom = NodeInfo()->NameAtom();
 | |
|   CustomElementDefinition* definition = nullptr;
 | |
|   if (ceData) {
 | |
|     definition = ceData->GetCustomElementDefinition();
 | |
| 
 | |
|     // If the definition is null, the element possible hasn't yet upgraded.
 | |
|     // Fallback to use LookupCustomElementDefinition to find its definition.
 | |
|     if (!definition) {
 | |
|       definition = nsContentUtils::LookupCustomElementDefinition(
 | |
|           NodeInfo()->GetDocument(), nameAtom, NodeInfo()->NamespaceID(),
 | |
|           ceData->GetCustomElementType());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // 3. If definition is null, then throw an "NotSupportedError" DOMException.
 | |
|   if (!definition) {
 | |
|     aRv.ThrowNotSupportedError(nsPrintfCString(
 | |
|         "Cannot attach ElementInternals to a non-custom element '%s'",
 | |
|         NS_ConvertUTF16toUTF8(nameAtom->GetUTF16String()).get()));
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   // 4. If definition's disable internals is true, then throw a
 | |
|   //    "NotSupportedError" DOMException.
 | |
|   if (definition->mDisableInternals) {
 | |
|     aRv.ThrowNotSupportedError(nsPrintfCString(
 | |
|         "AttachInternal() to '%s' is disabled by disabledFeatures",
 | |
|         NS_ConvertUTF16toUTF8(nameAtom->GetUTF16String()).get()));
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   // If this is not a custom element, i.e. ceData is nullptr, we are unable to
 | |
|   // find a definition and should return earlier above.
 | |
|   MOZ_ASSERT(ceData);
 | |
| 
 | |
|   // 5. If element's attached internals is true, then throw an
 | |
|   //    "NotSupportedError" DOMException.
 | |
|   if (ceData->HasAttachedInternals()) {
 | |
|     aRv.ThrowNotSupportedError(nsPrintfCString(
 | |
|         "AttachInternals() has already been called from '%s'",
 | |
|         NS_ConvertUTF16toUTF8(nameAtom->GetUTF16String()).get()));
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   // 6. If element's custom element state is not "precustomized" or "custom",
 | |
|   //    then throw a "NotSupportedError" DOMException.
 | |
|   if (ceData->mState != CustomElementData::State::ePrecustomized &&
 | |
|       ceData->mState != CustomElementData::State::eCustom) {
 | |
|     aRv.ThrowNotSupportedError(
 | |
|         R"(Custom element state is not "precustomized" or "custom".)");
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   // 7. Set element's attached internals to true.
 | |
|   ceData->AttachedInternals();
 | |
| 
 | |
|   // 8. Create a new ElementInternals instance targeting element, and return it.
 | |
|   return do_AddRef(ceData->GetOrCreateElementInternals(this));
 | |
| }
 | |
| 
 | |
| void HTMLElement::AfterClearForm(bool aUnbindOrDelete) {
 | |
|   // No need to enqueue formAssociated callback if we aren't releasing or
 | |
|   // unbinding from tree, UpdateFormOwner() will handle it.
 | |
|   if (aUnbindOrDelete) {
 | |
|     MOZ_ASSERT(IsFormAssociatedElement());
 | |
|     nsContentUtils::EnqueueLifecycleCallback(
 | |
|         ElementCallbackType::eFormAssociated, this, {});
 | |
|   }
 | |
| }
 | |
| 
 | |
| void HTMLElement::UpdateFormOwner() {
 | |
|   MOZ_ASSERT(IsFormAssociatedElement());
 | |
| 
 | |
|   // If @form is set, the element *has* to be in a composed document,
 | |
|   // otherwise it wouldn't be possible to find an element with the
 | |
|   // corresponding id. If @form isn't set, the element *has* to have a parent,
 | |
|   // otherwise it wouldn't be possible to find a form ancestor. We should not
 | |
|   // call UpdateFormOwner if none of these conditions are fulfilled.
 | |
|   if (HasAttr(nsGkAtoms::form) ? IsInComposedDoc() : !!GetParent()) {
 | |
|     UpdateFormOwner(true, nullptr);
 | |
|   }
 | |
|   UpdateFieldSet(true);
 | |
|   UpdateDisabledState(true);
 | |
|   UpdateBarredFromConstraintValidation();
 | |
|   UpdateValidityElementStates(true);
 | |
| 
 | |
|   MaybeRestoreFormAssociatedCustomElementState();
 | |
| }
 | |
| 
 | |
| bool HTMLElement::IsDisabledForEvents(WidgetEvent* aEvent) {
 | |
|   if (IsFormAssociatedElement()) {
 | |
|     return IsElementDisabledForEvents(aEvent, GetPrimaryFrame());
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void HTMLElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
 | |
|                                const nsAttrValue* aValue,
 | |
|                                const nsAttrValue* aOldValue,
 | |
|                                nsIPrincipal* aMaybeScriptedPrincipal,
 | |
|                                bool aNotify) {
 | |
|   if (aNameSpaceID == kNameSpaceID_None &&
 | |
|       (aName == nsGkAtoms::disabled || aName == nsGkAtoms::readonly)) {
 | |
|     if (aName == nsGkAtoms::disabled) {
 | |
|       // This *has* to be called *before* validity state check because
 | |
|       // UpdateBarredFromConstraintValidation depend on our disabled state.
 | |
|       UpdateDisabledState(aNotify);
 | |
|     }
 | |
|     if (aName == nsGkAtoms::readonly && !!aValue != !!aOldValue) {
 | |
|       UpdateReadOnlyState(aNotify);
 | |
|     }
 | |
|     UpdateBarredFromConstraintValidation();
 | |
|     UpdateValidityElementStates(aNotify);
 | |
|   }
 | |
| 
 | |
|   return nsGenericHTMLFormElement::AfterSetAttr(
 | |
|       aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
 | |
| }
 | |
| 
 | |
| void HTMLElement::UpdateValidityElementStates(bool aNotify) {
 | |
|   AutoStateChangeNotifier notifier(*this, aNotify);
 | |
|   RemoveStatesSilently(ElementState::VALIDITY_STATES);
 | |
|   ElementInternals* internals = GetElementInternals();
 | |
|   if (!internals || !internals->IsCandidateForConstraintValidation()) {
 | |
|     return;
 | |
|   }
 | |
|   if (internals->IsValid()) {
 | |
|     AddStatesSilently(ElementState::VALID | ElementState::USER_VALID);
 | |
|   } else {
 | |
|     AddStatesSilently(ElementState::INVALID | ElementState::USER_INVALID);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void HTMLElement::SetFormInternal(HTMLFormElement* aForm, bool aBindToTree) {
 | |
|   ElementInternals* internals = GetElementInternals();
 | |
|   MOZ_ASSERT(internals);
 | |
|   internals->SetForm(aForm);
 | |
| }
 | |
| 
 | |
| HTMLFormElement* HTMLElement::GetFormInternal() const {
 | |
|   ElementInternals* internals = GetElementInternals();
 | |
|   MOZ_ASSERT(internals);
 | |
|   return internals->GetForm();
 | |
| }
 | |
| 
 | |
| void HTMLElement::SetFieldSetInternal(HTMLFieldSetElement* aFieldset) {
 | |
|   ElementInternals* internals = GetElementInternals();
 | |
|   MOZ_ASSERT(internals);
 | |
|   internals->SetFieldSet(aFieldset);
 | |
| }
 | |
| 
 | |
| HTMLFieldSetElement* HTMLElement::GetFieldSetInternal() const {
 | |
|   ElementInternals* internals = GetElementInternals();
 | |
|   MOZ_ASSERT(internals);
 | |
|   return internals->GetFieldSet();
 | |
| }
 | |
| 
 | |
| bool HTMLElement::CanBeDisabled() const { return IsFormAssociatedElement(); }
 | |
| 
 | |
| bool HTMLElement::DoesReadOnlyApply() const {
 | |
|   return IsFormAssociatedElement();
 | |
| }
 | |
| 
 | |
| void HTMLElement::UpdateDisabledState(bool aNotify) {
 | |
|   bool oldState = IsDisabled();
 | |
|   nsGenericHTMLFormElement::UpdateDisabledState(aNotify);
 | |
|   if (oldState != IsDisabled()) {
 | |
|     MOZ_ASSERT(IsFormAssociatedElement());
 | |
|     LifecycleCallbackArgs args;
 | |
|     args.mDisabled = !oldState;
 | |
|     nsContentUtils::EnqueueLifecycleCallback(ElementCallbackType::eFormDisabled,
 | |
|                                              this, args);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void HTMLElement::UpdateFormOwner(bool aBindToTree, Element* aFormIdElement) {
 | |
|   HTMLFormElement* oldForm = GetFormInternal();
 | |
|   nsGenericHTMLFormElement::UpdateFormOwner(aBindToTree, aFormIdElement);
 | |
|   HTMLFormElement* newForm = GetFormInternal();
 | |
|   if (newForm != oldForm) {
 | |
|     LifecycleCallbackArgs args;
 | |
|     args.mForm = newForm;
 | |
|     nsContentUtils::EnqueueLifecycleCallback(
 | |
|         ElementCallbackType::eFormAssociated, this, args);
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool HTMLElement::IsFormAssociatedElement() const {
 | |
|   CustomElementData* data = GetCustomElementData();
 | |
|   return data && data->IsFormAssociated();
 | |
| }
 | |
| 
 | |
| void HTMLElement::FieldSetDisabledChanged(bool aNotify) {
 | |
|   // This *has* to be called *before* UpdateBarredFromConstraintValidation
 | |
|   // because this function depend on our disabled state.
 | |
|   nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
 | |
| 
 | |
|   UpdateBarredFromConstraintValidation();
 | |
|   UpdateValidityElementStates(aNotify);
 | |
| }
 | |
| 
 | |
| ElementInternals* HTMLElement::GetElementInternals() const {
 | |
|   CustomElementData* data = GetCustomElementData();
 | |
|   if (!data || !data->IsFormAssociated()) {
 | |
|     // If the element is not a form associated custom element, it should not be
 | |
|     // able to be QueryInterfaced to nsIFormControl and could not perform
 | |
|     // the form operation, either, so we return nullptr here.
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   return data->GetElementInternals();
 | |
| }
 | |
| 
 | |
| void HTMLElement::UpdateBarredFromConstraintValidation() {
 | |
|   CustomElementData* data = GetCustomElementData();
 | |
|   if (data && data->IsFormAssociated()) {
 | |
|     ElementInternals* internals = data->GetElementInternals();
 | |
|     MOZ_ASSERT(internals);
 | |
|     internals->UpdateBarredFromConstraintValidation();
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace mozilla::dom
 | |
| 
 | |
| // Here, we expand 'NS_IMPL_NS_NEW_HTML_ELEMENT()' by hand.
 | |
| // (Calling the macro directly (with no args) produces compiler warnings.)
 | |
| nsGenericHTMLElement* NS_NewHTMLElement(
 | |
|     already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
 | |
|     mozilla::dom::FromParser aFromParser) {
 | |
|   RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
 | |
|   auto* nim = nodeInfo->NodeInfoManager();
 | |
|   return new (nim) mozilla::dom::HTMLElement(nodeInfo.forget(), aFromParser);
 | |
| }
 | |
| 
 | |
| // Distinct from the above in order to have function pointer that compared
 | |
| // unequal to a function pointer to the above.
 | |
| nsGenericHTMLElement* NS_NewCustomElement(
 | |
|     already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
 | |
|     mozilla::dom::FromParser aFromParser) {
 | |
|   RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
 | |
|   auto* nim = nodeInfo->NodeInfoManager();
 | |
|   return new (nim) mozilla::dom::HTMLElement(nodeInfo.forget(), aFromParser);
 | |
| }
 |