tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsHtml5TreeOperation.cpp (46672B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 sw=2 et tw=78: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "nsHtml5TreeOperation.h"
      8 #include "mozAutoDocUpdate.h"
      9 #include "mozilla/CycleCollectedJSContext.h"
     10 #include "mozilla/Likely.h"
     11 #include "mozilla/dom/Comment.h"
     12 #include "mozilla/dom/CustomElementRegistry.h"
     13 #include "mozilla/dom/DocGroup.h"
     14 #include "mozilla/dom/DocumentFragment.h"
     15 #include "mozilla/dom/DocumentType.h"
     16 #include "mozilla/dom/Element.h"
     17 #include "mozilla/dom/LinkStyle.h"
     18 #include "mozilla/dom/HTMLFormElement.h"
     19 #include "mozilla/dom/HTMLImageElement.h"
     20 #include "mozilla/dom/HTMLTemplateElement.h"
     21 #include "mozilla/dom/MutationObservers.h"
     22 #include "mozilla/dom/ShadowRoot.h"
     23 #include "mozilla/dom/Text.h"
     24 #include "nsAttrName.h"
     25 #include "nsContentCreatorFunctions.h"
     26 #include "nsContentUtils.h"
     27 #include "nsDocElementCreatedNotificationRunner.h"
     28 #include "nsEscape.h"
     29 #include "nsGenericHTMLElement.h"
     30 #include "nsHtml5AutoPauseUpdate.h"
     31 #include "nsHtml5DocumentMode.h"
     32 #include "nsHtml5HtmlAttributes.h"
     33 #include "nsHtml5SVGLoadDispatcher.h"
     34 #include "nsHtml5TreeBuilder.h"
     35 #include "nsIFormControl.h"
     36 #include "nsIMutationObserver.h"
     37 #include "nsINode.h"
     38 #include "nsIProtocolHandler.h"
     39 #include "nsIScriptElement.h"
     40 #include "nsISupportsImpl.h"
     41 #include "nsIURI.h"
     42 #include "nsNetUtil.h"
     43 #include "nsTextNode.h"
     44 #include "js/ColumnNumber.h"  // JS::ColumnNumberOneOrigin
     45 
     46 using namespace mozilla;
     47 using namespace mozilla::dom;
     48 
     49 // If you are adding fields to a tree op and this static assert fails,
     50 // please consider reordering the fields to avoid excess padding or,
     51 // if that doesn't help, splitting a rare operation into multiple
     52 // tree ops before allowing the size of all operations to get larger.
     53 static_assert(sizeof(nsHtml5TreeOperation) <= 56);
     54 
     55 /**
     56 * Helper class that opens a notification batch if the current doc
     57 * is different from the executor doc.
     58 */
     59 class MOZ_STACK_CLASS nsHtml5OtherDocUpdate {
     60 public:
     61  nsHtml5OtherDocUpdate(Document* aCurrentDoc, Document* aExecutorDoc) {
     62    MOZ_ASSERT(aCurrentDoc, "Node has no doc?");
     63    MOZ_ASSERT(aExecutorDoc, "Executor has no doc?");
     64    if (MOZ_LIKELY(aCurrentDoc == aExecutorDoc)) {
     65      mDocument = nullptr;
     66    } else {
     67      mDocument = aCurrentDoc;
     68      aCurrentDoc->BeginUpdate();
     69    }
     70  }
     71 
     72  ~nsHtml5OtherDocUpdate() {
     73    if (MOZ_UNLIKELY(mDocument)) {
     74      mDocument->EndUpdate();
     75    }
     76  }
     77 
     78 private:
     79  RefPtr<Document> mDocument;
     80 };
     81 
     82 nsHtml5TreeOperation::nsHtml5TreeOperation() : mOperation(uninitialized()) {
     83  MOZ_COUNT_CTOR(nsHtml5TreeOperation);
     84 }
     85 
     86 nsHtml5TreeOperation::~nsHtml5TreeOperation() {
     87  MOZ_COUNT_DTOR(nsHtml5TreeOperation);
     88 
     89  struct TreeOperationMatcher {
     90    void operator()(const opAppend& aOperation) {}
     91 
     92    void operator()(const opDetach& aOperation) {}
     93 
     94    void operator()(const opAppendChildrenToNewParent& aOperation) {}
     95 
     96    void operator()(const opFosterParent& aOperation) {}
     97 
     98    void operator()(const opAppendToDocument& aOperation) {}
     99 
    100    void operator()(const opAddAttributes& aOperation) {
    101      delete aOperation.mAttributes;
    102    }
    103 
    104    void operator()(const nsHtml5DocumentMode& aMode) {}
    105 
    106    void operator()(const opCreateHTMLElement& aOperation) {
    107      aOperation.mName->Release();
    108      delete aOperation.mAttributes;
    109    }
    110 
    111    void operator()(const opCreateSVGElement& aOperation) {
    112      aOperation.mName->Release();
    113      delete aOperation.mAttributes;
    114    }
    115 
    116    void operator()(const opCreateMathMLElement& aOperation) {
    117      aOperation.mName->Release();
    118      delete aOperation.mAttributes;
    119    }
    120 
    121    void operator()(const opSetFormElement& aOperation) {}
    122 
    123    void operator()(const opAppendText& aOperation) {
    124      delete[] aOperation.mBuffer;
    125    }
    126 
    127    void operator()(const opFosterParentText& aOperation) {
    128      delete[] aOperation.mBuffer;
    129    }
    130 
    131    void operator()(const opAppendComment& aOperation) {
    132      delete[] aOperation.mBuffer;
    133    }
    134 
    135    void operator()(const opAppendCommentToDocument& aOperation) {
    136      delete[] aOperation.mBuffer;
    137    }
    138 
    139    void operator()(const opAppendDoctypeToDocument& aOperation) {
    140      aOperation.mName->Release();
    141      delete aOperation.mStringPair;
    142    }
    143 
    144    void operator()(const opGetDocumentFragmentForTemplate& aOperation) {}
    145 
    146    void operator()(const opSetDocumentFragmentForTemplate& aOperation) {}
    147 
    148    void operator()(const opGetShadowRootFromHost& aOperation) {}
    149 
    150    void operator()(const opGetFosterParent& aOperation) {}
    151 
    152    void operator()(const opMarkAsBroken& aOperation) {}
    153 
    154    void operator()(const opRunScriptThatMayDocumentWriteOrBlock& aOperation) {}
    155 
    156    void operator()(
    157        const opRunScriptThatCannotDocumentWriteOrBlock& aOperation) {}
    158 
    159    void operator()(const opPreventScriptExecution& aOperation) {}
    160 
    161    void operator()(const opDoneAddingChildren& aOperation) {}
    162 
    163    void operator()(const opDoneCreatingElement& aOperation) {}
    164 
    165    void operator()(const opUpdateCharsetSource& aOperation) {}
    166 
    167    void operator()(const opCharsetSwitchTo& aOperation) {}
    168 
    169    void operator()(const opUpdateStyleSheet& aOperation) {}
    170 
    171    void operator()(const opProcessOfflineManifest& aOperation) {
    172      free(aOperation.mUrl);
    173    }
    174 
    175    void operator()(const opMarkMalformedIfScript& aOperation) {}
    176 
    177    void operator()(const opStreamEnded& aOperation) {}
    178 
    179    void operator()(const opSetStyleLineNumber& aOperation) {}
    180 
    181    void operator()(const opSetScriptLineAndColumnNumberAndFreeze& aOperation) {
    182    }
    183 
    184    void operator()(const opSvgLoad& aOperation) {}
    185 
    186    void operator()(const opMaybeComplainAboutCharset& aOperation) {}
    187 
    188    void operator()(const opMaybeComplainAboutDeepTree& aOperation) {}
    189 
    190    void operator()(const opAddClass& aOperation) {}
    191 
    192    void operator()(const opAddViewSourceHref& aOperation) {
    193      delete[] aOperation.mBuffer;
    194    }
    195 
    196    void operator()(const opAddViewSourceBase& aOperation) {
    197      delete[] aOperation.mBuffer;
    198    }
    199 
    200    void operator()(const opAddErrorType& aOperation) {
    201      if (aOperation.mName) {
    202        aOperation.mName->Release();
    203      }
    204      if (aOperation.mOther) {
    205        aOperation.mOther->Release();
    206      }
    207    }
    208 
    209    void operator()(const opAddLineNumberId& aOperation) {}
    210 
    211    void operator()(const opShallowCloneInto& aOperation) {}
    212 
    213    void operator()(const opStartLayout& aOperation) {}
    214 
    215    void operator()(const opEnableEncodingMenu& aOperation) {}
    216 
    217    void operator()(const opMicrotaskCheckpoint& aOperation) {}
    218 
    219    void operator()(const uninitialized& aOperation) {
    220      NS_WARNING("Uninitialized tree op.");
    221    }
    222  };
    223 
    224  mOperation.match(TreeOperationMatcher());
    225 }
    226 
    227 nsresult nsHtml5TreeOperation::AppendTextToTextNode(
    228    const char16_t* aBuffer, uint32_t aLength, Text* aTextNode,
    229    nsHtml5DocumentBuilder* aBuilder) {
    230  MOZ_ASSERT(aTextNode, "Got null text node.");
    231  MOZ_ASSERT(aBuilder);
    232  MOZ_ASSERT(aBuilder->IsInDocUpdate());
    233  uint32_t oldLength = aTextNode->TextLength();
    234  CharacterDataChangeInfo info = {true, oldLength, oldLength, aLength,
    235                                  MutationEffectOnScript::KeepTrustWorthiness};
    236  MutationObservers::NotifyCharacterDataWillChange(aTextNode, info);
    237 
    238  nsresult rv = aTextNode->AppendText(aBuffer, aLength, false);
    239  NS_ENSURE_SUCCESS(rv, rv);
    240 
    241  MutationObservers::NotifyCharacterDataChanged(aTextNode, info);
    242  return rv;
    243 }
    244 
    245 nsresult nsHtml5TreeOperation::AppendText(const char16_t* aBuffer,
    246                                          uint32_t aLength, nsIContent* aParent,
    247                                          nsHtml5DocumentBuilder* aBuilder) {
    248  nsresult rv = NS_OK;
    249  nsIContent* lastChild = aParent->GetLastChild();
    250  if (lastChild && lastChild->IsText()) {
    251    nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), aBuilder->GetDocument());
    252    return AppendTextToTextNode(aBuffer, aLength, lastChild->GetAsText(),
    253                                aBuilder);
    254  }
    255 
    256  nsNodeInfoManager* nodeInfoManager = aParent->OwnerDoc()->NodeInfoManager();
    257  RefPtr<nsTextNode> text = new (nodeInfoManager) nsTextNode(nodeInfoManager);
    258  NS_ASSERTION(text, "Infallible malloc failed?");
    259  rv = text->SetText(aBuffer, aLength, false);
    260  NS_ENSURE_SUCCESS(rv, rv);
    261 
    262  return Append(text, aParent, aBuilder);
    263 }
    264 
    265 nsresult nsHtml5TreeOperation::Append(nsIContent* aNode, nsIContent* aParent,
    266                                      nsHtml5DocumentBuilder* aBuilder) {
    267  MOZ_ASSERT(aBuilder);
    268  MOZ_ASSERT(aBuilder->IsInDocUpdate());
    269  ErrorResult rv;
    270  Document* ownerDoc = aParent->OwnerDoc();
    271  nsHtml5OtherDocUpdate update(ownerDoc, aBuilder->GetDocument());
    272  aParent->AppendChildTo(aNode, false, rv);
    273  if (!rv.Failed() && !ownerDoc->DOMNotificationsSuspended()) {
    274    aNode->SetParserHasNotified();
    275    MutationObservers::NotifyContentAppended(
    276        aParent, aNode, {MutationEffectOnScript::KeepTrustWorthiness});
    277  }
    278  return rv.StealNSResult();
    279 }
    280 
    281 nsresult nsHtml5TreeOperation::Append(nsIContent* aNode, nsIContent* aParent,
    282                                      FromParser aFromParser,
    283                                      nsHtml5DocumentBuilder* aBuilder) {
    284  Maybe<nsHtml5AutoPauseUpdate> autoPause;
    285  Maybe<AutoCEReaction> autoCEReaction;
    286  DocGroup* docGroup = aParent->OwnerDoc()->GetDocGroup();
    287  if (docGroup && aFromParser != FROM_PARSER_FRAGMENT) {
    288    autoCEReaction.emplace(docGroup->CustomElementReactionsStack(), nullptr);
    289  }
    290  nsresult rv = Append(aNode, aParent, aBuilder);
    291  // Pause the parser only when there are reactions to be invoked to avoid
    292  // pausing parsing too aggressive.
    293  if (autoCEReaction.isSome() && docGroup &&
    294      docGroup->CustomElementReactionsStack()
    295          ->IsElementQueuePushedForCurrentRecursionDepth()) {
    296    autoPause.emplace(aBuilder);
    297  }
    298  return rv;
    299 }
    300 
    301 nsresult nsHtml5TreeOperation::AppendToDocument(
    302    nsIContent* aNode, nsHtml5DocumentBuilder* aBuilder) {
    303  MOZ_ASSERT(aBuilder);
    304  MOZ_ASSERT(aBuilder->GetDocument() == aNode->OwnerDoc());
    305  MOZ_ASSERT(aBuilder->IsInDocUpdate());
    306 
    307  ErrorResult rv;
    308  Document* doc = aBuilder->GetDocument();
    309  doc->AppendChildTo(aNode, false, rv);
    310  if (rv.ErrorCodeIs(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR)) {
    311    aNode->SetParserHasNotified();
    312    return NS_OK;
    313  }
    314  if (rv.Failed()) {
    315    return rv.StealNSResult();
    316  }
    317 
    318  if (!doc->DOMNotificationsSuspended()) {
    319    aNode->SetParserHasNotified();
    320    MutationObservers::NotifyContentInserted(
    321        doc, aNode, {MutationEffectOnScript::KeepTrustWorthiness});
    322  }
    323 
    324  NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
    325               "Someone forgot to block scripts");
    326  if (aNode->IsElement()) {
    327    nsContentUtils::AddScriptRunner(
    328        new nsDocElementCreatedNotificationRunner(doc));
    329  }
    330  return NS_OK;
    331 }
    332 
    333 static bool IsElementOrTemplateContent(nsINode* aNode) {
    334  if (aNode) {
    335    if (aNode->IsElement()) {
    336      return true;
    337    }
    338    if (aNode->IsDocumentFragment()) {
    339      // Check if the node is a template content.
    340      nsIContent* fragHost = aNode->AsDocumentFragment()->GetHost();
    341      if (fragHost && fragHost->IsTemplateElement()) {
    342        return true;
    343      }
    344    }
    345  }
    346  return false;
    347 }
    348 
    349 void nsHtml5TreeOperation::Detach(nsIContent* aNode,
    350                                  nsHtml5DocumentBuilder* aBuilder) {
    351  MOZ_ASSERT(aBuilder);
    352  MOZ_ASSERT(aBuilder->IsInDocUpdate());
    353  nsCOMPtr<nsINode> parent = aNode->GetParentNode();
    354  if (parent) {
    355    nsHtml5OtherDocUpdate update(parent->OwnerDoc(), aBuilder->GetDocument());
    356    parent->RemoveChildNode(aNode, true, nullptr, nullptr,
    357                            MutationEffectOnScript::KeepTrustWorthiness);
    358  }
    359 }
    360 
    361 nsresult nsHtml5TreeOperation::AppendChildrenToNewParent(
    362    nsIContent* aNode, nsIContent* aParent, nsHtml5DocumentBuilder* aBuilder) {
    363  MOZ_ASSERT(aBuilder);
    364  MOZ_ASSERT(aBuilder->IsInDocUpdate());
    365  nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), aBuilder->GetDocument());
    366 
    367  bool didAppend = false;
    368  while (aNode->HasChildren()) {
    369    nsCOMPtr<nsIContent> child = aNode->GetFirstChild();
    370    aNode->RemoveChildNode(child, true, nullptr, nullptr,
    371                           MutationEffectOnScript::KeepTrustWorthiness);
    372 
    373    ErrorResult rv;
    374    aParent->AppendChildTo(child, false, rv);
    375    if (rv.Failed()) {
    376      return rv.StealNSResult();
    377    }
    378    didAppend = true;
    379  }
    380  if (didAppend) {
    381    MutationObservers::NotifyContentAppended(
    382        aParent, aParent->GetLastChild(),
    383        {MutationEffectOnScript::KeepTrustWorthiness});
    384  }
    385  return NS_OK;
    386 }
    387 
    388 nsresult nsHtml5TreeOperation::FosterParent(nsIContent* aNode,
    389                                            nsIContent* aParent,
    390                                            nsIContent* aTable,
    391                                            nsHtml5DocumentBuilder* aBuilder) {
    392  MOZ_ASSERT(aBuilder);
    393  MOZ_ASSERT(aBuilder->IsInDocUpdate());
    394  nsIContent* foster = aTable->GetParent();
    395 
    396  if (IsElementOrTemplateContent(foster)) {
    397    nsHtml5OtherDocUpdate update(foster->OwnerDoc(), aBuilder->GetDocument());
    398 
    399    ErrorResult rv;
    400    foster->InsertChildBefore(aNode, aTable, false, rv);
    401    if (rv.Failed()) {
    402      return rv.StealNSResult();
    403    }
    404 
    405    MutationObservers::NotifyContentInserted(
    406        foster, aNode, {MutationEffectOnScript::KeepTrustWorthiness});
    407    return NS_OK;
    408  }
    409 
    410  return Append(aNode, aParent, aBuilder);
    411 }
    412 
    413 nsresult nsHtml5TreeOperation::AddAttributes(nsIContent* aNode,
    414                                             nsHtml5HtmlAttributes* aAttributes,
    415                                             nsHtml5DocumentBuilder* aBuilder) {
    416  MOZ_ASSERT(aNode->IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::html));
    417 
    418  Element* node = aNode->AsElement();
    419  nsHtml5OtherDocUpdate update(node->OwnerDoc(), aBuilder->GetDocument());
    420 
    421  int32_t len = aAttributes->getLength();
    422  for (int32_t i = len; i > 0;) {
    423    --i;
    424    nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i);
    425    int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
    426    if (!node->HasAttr(nsuri, localName) &&
    427        !(nsuri == kNameSpaceID_None && localName == nsGkAtoms::nonce)) {
    428      nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
    429      nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i);
    430 
    431      // If value is already an atom, use it directly to avoid string
    432      // allocation.
    433      nsAtom* valAtom = val.MaybeAsAtom();
    434      if (valAtom) {
    435        node->SetAttr(nsuri, localName, prefix, valAtom, nullptr, true);
    436      } else {
    437        nsString value;  // Not Auto, because using it to hold nsStringBuffer*
    438        val.ToString(value);
    439        node->SetAttr(nsuri, localName, prefix, value, true);
    440      }
    441      // XXX what to do with nsresult?
    442    }
    443  }
    444  return NS_OK;
    445 }
    446 
    447 void nsHtml5TreeOperation::SetHTMLElementAttributes(
    448    Element* aElement, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes) {
    449  int32_t len = aAttributes->getLength();
    450  aElement->TryReserveAttributeCount((uint32_t)len);
    451  if (aAttributes->getDuplicateAttributeError()) {
    452    aElement->SetParserHadDuplicateAttributeError();
    453  }
    454  for (int32_t i = 0; i < len; i++) {
    455    nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
    456    nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i);
    457    if (localName == nsGkAtoms::_class) {
    458      nsAtom* klass = val.MaybeAsAtom();
    459      if (klass) {
    460        aElement->SetClassAttrFromParser(klass);
    461        continue;
    462      }
    463    }
    464 
    465    nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i);
    466    int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
    467 
    468    // If value is already an atom, use it directly to avoid string allocation.
    469    nsAtom* valAtom = val.MaybeAsAtom();
    470    if (valAtom) {
    471      aElement->SetAttr(nsuri, localName, prefix, valAtom, nullptr, false);
    472    } else {
    473      nsString value;  // Not Auto, because using it to hold nsStringBuffer*
    474      val.ToString(value);
    475      aElement->SetAttr(nsuri, localName, prefix, value, false);
    476    }
    477  }
    478 }
    479 
    480 nsIContent* nsHtml5TreeOperation::CreateHTMLElement(
    481    nsAtom* aName, nsHtml5HtmlAttributes* aAttributes, FromParser aFromParser,
    482    nsNodeInfoManager* aNodeInfoManager, nsHtml5DocumentBuilder* aBuilder,
    483    HTMLContentCreatorFunction aCreator) {
    484  RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
    485      aName, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE);
    486  NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
    487 
    488  Document* document = nodeInfo->GetDocument();
    489  RefPtr<nsAtom> isAtom;
    490  if (aAttributes) {
    491    nsHtml5String is = aAttributes->getValue(nsHtml5AttributeName::ATTR_IS);
    492    if (is) {
    493      nsAutoString isValue;
    494      is.ToString(isValue);
    495      isAtom = NS_Atomize(isValue);
    496    }
    497  }
    498 
    499  const bool isCustomElement = aCreator == NS_NewCustomElement || isAtom;
    500  CustomElementDefinition* customElementDefinition = nullptr;
    501  if (isCustomElement && aFromParser != FROM_PARSER_FRAGMENT) {
    502    RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
    503    RefPtr<nsAtom> typeAtom =
    504        aCreator == NS_NewCustomElement ? tagAtom : isAtom;
    505 
    506    MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName()));
    507    customElementDefinition = nsContentUtils::LookupCustomElementDefinition(
    508        document, nodeInfo->NameAtom(), nodeInfo->NamespaceID(), typeAtom);
    509  }
    510 
    511  auto DoCreateElement = [&](HTMLContentCreatorFunction aCreator) -> Element* {
    512    nsCOMPtr<Element> newElement;
    513    if (aCreator) {
    514      newElement = aCreator(nodeInfo.forget(), aFromParser);
    515    } else {
    516      NS_NewHTMLElement(getter_AddRefs(newElement), nodeInfo.forget(),
    517                        aFromParser, isAtom, customElementDefinition);
    518    }
    519 
    520    MOZ_ASSERT(newElement, "Element creation created null pointer.");
    521    Element* element = newElement.get();
    522    aBuilder->HoldElement(newElement.forget());
    523 
    524    if (auto* linkStyle = LinkStyle::FromNode(*element)) {
    525      linkStyle->DisableUpdates();
    526    }
    527 
    528    if (!aAttributes) {
    529      return element;
    530    }
    531 
    532    SetHTMLElementAttributes(element, aName, aAttributes);
    533    return element;
    534  };
    535 
    536  if (customElementDefinition) {
    537    // This will cause custom element constructors to run.
    538    AutoSetThrowOnDynamicMarkupInsertionCounter
    539        throwOnDynamicMarkupInsertionCounter(document);
    540    nsHtml5AutoPauseUpdate autoPauseContentUpdate(aBuilder);
    541    {
    542      nsAutoMicroTask mt;
    543    }
    544    AutoCEReaction autoCEReaction(
    545        document->GetDocGroup()->CustomElementReactionsStack(), nullptr);
    546    return DoCreateElement(nullptr);
    547  }
    548  return DoCreateElement(isCustomElement ? nullptr : aCreator);
    549 }
    550 
    551 nsIContent* nsHtml5TreeOperation::CreateSVGElement(
    552    nsAtom* aName, nsHtml5HtmlAttributes* aAttributes, FromParser aFromParser,
    553    nsNodeInfoManager* aNodeInfoManager, nsHtml5DocumentBuilder* aBuilder,
    554    SVGContentCreatorFunction aCreator) {
    555  nsCOMPtr<nsIContent> newElement;
    556  if (MOZ_LIKELY(aNodeInfoManager->SVGEnabled())) {
    557    RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
    558        aName, nullptr, kNameSpaceID_SVG, nsINode::ELEMENT_NODE);
    559    MOZ_ASSERT(nodeInfo, "Got null nodeinfo.");
    560 
    561    DebugOnly<nsresult> rv =
    562        aCreator(getter_AddRefs(newElement), nodeInfo.forget(), aFromParser);
    563    MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
    564  } else {
    565    RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
    566        aName, nullptr, kNameSpaceID_disabled_SVG, nsINode::ELEMENT_NODE);
    567    MOZ_ASSERT(nodeInfo, "Got null nodeinfo.");
    568 
    569    // The mismatch between NS_NewXMLElement and SVGContentCreatorFunction
    570    // argument types is annoying.
    571    nsCOMPtr<Element> xmlElement;
    572    DebugOnly<nsresult> rv =
    573        NS_NewXMLElement(getter_AddRefs(xmlElement), nodeInfo.forget());
    574    MOZ_ASSERT(NS_SUCCEEDED(rv) && xmlElement);
    575    newElement = xmlElement;
    576  }
    577 
    578  Element* newContent = newElement->AsElement();
    579  aBuilder->HoldElement(newElement.forget());
    580 
    581  if (MOZ_UNLIKELY(aName == nsGkAtoms::style)) {
    582    if (auto* linkStyle = LinkStyle::FromNode(*newContent)) {
    583      linkStyle->DisableUpdates();
    584    }
    585  }
    586 
    587  if (!aAttributes) {
    588    return newContent;
    589  }
    590 
    591  if (aAttributes->getDuplicateAttributeError()) {
    592    newContent->SetParserHadDuplicateAttributeError();
    593  }
    594 
    595  int32_t len = aAttributes->getLength();
    596  for (int32_t i = 0; i < len; i++) {
    597    nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
    598    nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i);
    599    if (localName == nsGkAtoms::_class) {
    600      nsAtom* klass = val.MaybeAsAtom();
    601      if (klass) {
    602        newContent->SetClassAttrFromParser(klass);
    603        continue;
    604      }
    605    }
    606 
    607    nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i);
    608    int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
    609 
    610    // If value is already an atom, use it directly to avoid string allocation.
    611    nsAtom* valAtom = val.MaybeAsAtom();
    612    if (valAtom) {
    613      newContent->SetAttr(nsuri, localName, prefix, valAtom, nullptr, false);
    614    } else {
    615      nsString value;  // Not Auto, because using it to hold nsStringBuffer*
    616      val.ToString(value);
    617      newContent->SetAttr(nsuri, localName, prefix, value, false);
    618    }
    619  }
    620  return newContent;
    621 }
    622 
    623 nsIContent* nsHtml5TreeOperation::CreateMathMLElement(
    624    nsAtom* aName, nsHtml5HtmlAttributes* aAttributes,
    625    nsNodeInfoManager* aNodeInfoManager, nsHtml5DocumentBuilder* aBuilder) {
    626  nsCOMPtr<Element> newElement;
    627  if (MOZ_LIKELY(aNodeInfoManager->MathMLEnabled())) {
    628    RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
    629        aName, nullptr, kNameSpaceID_MathML, nsINode::ELEMENT_NODE);
    630    NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
    631 
    632    DebugOnly<nsresult> rv =
    633        NS_NewMathMLElement(getter_AddRefs(newElement), nodeInfo.forget());
    634    MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
    635  } else {
    636    RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
    637        aName, nullptr, kNameSpaceID_disabled_MathML, nsINode::ELEMENT_NODE);
    638    NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
    639 
    640    DebugOnly<nsresult> rv =
    641        NS_NewXMLElement(getter_AddRefs(newElement), nodeInfo.forget());
    642    MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
    643  }
    644 
    645  Element* newContent = newElement;
    646  aBuilder->HoldElement(newElement.forget());
    647 
    648  if (!aAttributes) {
    649    return newContent;
    650  }
    651 
    652  if (aAttributes->getDuplicateAttributeError()) {
    653    newContent->SetParserHadDuplicateAttributeError();
    654  }
    655 
    656  int32_t len = aAttributes->getLength();
    657  for (int32_t i = 0; i < len; i++) {
    658    nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
    659    nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i);
    660    if (localName == nsGkAtoms::_class) {
    661      nsAtom* klass = val.MaybeAsAtom();
    662      if (klass) {
    663        newContent->SetClassAttrFromParser(klass);
    664        continue;
    665      }
    666    }
    667 
    668    nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i);
    669    int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
    670 
    671    // If value is already an atom, use it directly to avoid string allocation.
    672    nsAtom* valAtom = val.MaybeAsAtom();
    673    if (valAtom) {
    674      newContent->SetAttr(nsuri, localName, prefix, valAtom, nullptr, false);
    675    } else {
    676      nsString value;  // Not Auto, because using it to hold nsStringBuffer*
    677      val.ToString(value);
    678      newContent->SetAttr(nsuri, localName, prefix, value, false);
    679    }
    680  }
    681  return newContent;
    682 }
    683 
    684 void nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aForm,
    685                                          nsIContent* aParent) {
    686  RefPtr formElement = HTMLFormElement::FromNodeOrNull(aForm);
    687  NS_ASSERTION(formElement,
    688               "The form element doesn't implement HTMLFormElement.");
    689  nsCOMPtr<nsIFormControl> formControl = nsIFormControl::FromNodeOrNull(aNode);
    690  if (formControl &&
    691      formControl->ControlType() !=
    692          FormControlType::FormAssociatedCustomElement &&
    693      !aNode->AsElement()->HasAttr(nsGkAtoms::form) &&
    694      aForm->SubtreeRoot() == aParent->SubtreeRoot()) {
    695    formControl->SetForm(formElement);
    696  } else if (auto* image = HTMLImageElement::FromNodeOrNull(aNode)) {
    697    image->SetForm(formElement);
    698  }
    699 }
    700 
    701 nsresult nsHtml5TreeOperation::FosterParentText(
    702    nsIContent* aStackParent, char16_t* aBuffer, uint32_t aLength,
    703    nsIContent* aTable, nsHtml5DocumentBuilder* aBuilder) {
    704  MOZ_ASSERT(aBuilder);
    705  MOZ_ASSERT(aBuilder->IsInDocUpdate());
    706  nsresult rv = NS_OK;
    707  nsIContent* foster = aTable->GetParent();
    708 
    709  if (IsElementOrTemplateContent(foster)) {
    710    nsHtml5OtherDocUpdate update(foster->OwnerDoc(), aBuilder->GetDocument());
    711 
    712    nsIContent* previousSibling = aTable->GetPreviousSibling();
    713    if (previousSibling && previousSibling->IsText()) {
    714      return AppendTextToTextNode(aBuffer, aLength,
    715                                  previousSibling->GetAsText(), aBuilder);
    716    }
    717 
    718    nsNodeInfoManager* nodeInfoManager =
    719        aStackParent->OwnerDoc()->NodeInfoManager();
    720    RefPtr<nsTextNode> text = new (nodeInfoManager) nsTextNode(nodeInfoManager);
    721    NS_ASSERTION(text, "Infallible malloc failed?");
    722    rv = text->SetText(aBuffer, aLength, false);
    723    NS_ENSURE_SUCCESS(rv, rv);
    724 
    725    ErrorResult error;
    726    foster->InsertChildBefore(text, aTable, false, error);
    727    if (error.Failed()) {
    728      return error.StealNSResult();
    729    }
    730 
    731    MutationObservers::NotifyContentInserted(
    732        foster, text, {MutationEffectOnScript::KeepTrustWorthiness});
    733    return rv;
    734  }
    735 
    736  return AppendText(aBuffer, aLength, aStackParent, aBuilder);
    737 }
    738 
    739 nsresult nsHtml5TreeOperation::AppendComment(nsIContent* aParent,
    740                                             char16_t* aBuffer, int32_t aLength,
    741                                             nsHtml5DocumentBuilder* aBuilder) {
    742  nsNodeInfoManager* nodeInfoManager = aParent->OwnerDoc()->NodeInfoManager();
    743  RefPtr<Comment> comment = new (nodeInfoManager) Comment(nodeInfoManager);
    744  NS_ASSERTION(comment, "Infallible malloc failed?");
    745  nsresult rv = comment->SetText(aBuffer, aLength, false);
    746  NS_ENSURE_SUCCESS(rv, rv);
    747 
    748  return Append(comment, aParent, aBuilder);
    749 }
    750 
    751 nsresult nsHtml5TreeOperation::AppendCommentToDocument(
    752    char16_t* aBuffer, int32_t aLength, nsHtml5DocumentBuilder* aBuilder) {
    753  RefPtr<Comment> comment = new (aBuilder->GetNodeInfoManager())
    754      Comment(aBuilder->GetNodeInfoManager());
    755  NS_ASSERTION(comment, "Infallible malloc failed?");
    756  nsresult rv = comment->SetText(aBuffer, aLength, false);
    757  NS_ENSURE_SUCCESS(rv, rv);
    758 
    759  return AppendToDocument(comment, aBuilder);
    760 }
    761 
    762 nsresult nsHtml5TreeOperation::AppendDoctypeToDocument(
    763    nsAtom* aName, const nsAString& aPublicId, const nsAString& aSystemId,
    764    nsHtml5DocumentBuilder* aBuilder) {
    765  // Adapted from nsXMLContentSink
    766  // Create a new doctype node
    767  RefPtr<DocumentType> docType =
    768      NS_NewDOMDocumentType(aBuilder->GetNodeInfoManager(), aName, aPublicId,
    769                            aSystemId, VoidString());
    770  return AppendToDocument(docType, aBuilder);
    771 }
    772 
    773 nsIContent* nsHtml5TreeOperation::GetDocumentFragmentForTemplate(
    774    nsIContent* aNode) {
    775  auto* tempElem = static_cast<HTMLTemplateElement*>(aNode);
    776  return tempElem->Content();
    777 }
    778 
    779 void nsHtml5TreeOperation::SetDocumentFragmentForTemplate(
    780    nsIContent* aNode, nsIContent* aDocumentFragment) {
    781  auto* tempElem = static_cast<HTMLTemplateElement*>(aNode);
    782  tempElem->SetContent(static_cast<DocumentFragment*>(aDocumentFragment));
    783 }
    784 
    785 nsIContent* nsHtml5TreeOperation::GetFosterParent(nsIContent* aTable,
    786                                                  nsIContent* aStackParent) {
    787  nsIContent* tableParent = aTable->GetParent();
    788  return IsElementOrTemplateContent(tableParent) ? tableParent : aStackParent;
    789 }
    790 
    791 void nsHtml5TreeOperation::PreventScriptExecution(nsIContent* aNode) {
    792  nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
    793  if (sele) {
    794    sele->PreventExecution();
    795  } else {
    796    MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
    797               "Node didn't QI to script, but SVG wasn't disabled.");
    798  }
    799 }
    800 
    801 void nsHtml5TreeOperation::DoneAddingChildren(nsIContent* aNode) {
    802  aNode->DoneAddingChildren(aNode->HasParserNotified());
    803 }
    804 
    805 void nsHtml5TreeOperation::DoneCreatingElement(nsIContent* aNode) {
    806  aNode->DoneCreatingElement();
    807 }
    808 
    809 void nsHtml5TreeOperation::SvgLoad(nsIContent* aNode) {
    810  nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(aNode);
    811  if (NS_FAILED(aNode->OwnerDoc()->Dispatch(event.forget()))) {
    812    NS_WARNING("failed to dispatch svg load dispatcher");
    813  }
    814 }
    815 
    816 void nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode) {
    817  nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
    818  if (sele) {
    819    // Make sure to serialize this script correctly, for nice round tripping.
    820    sele->SetIsMalformed();
    821  }
    822 }
    823 
    824 nsresult nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
    825                                       nsIContent** aScriptElement,
    826                                       bool* aInterrupted, bool* aStreamEnded) {
    827  struct TreeOperationMatcher {
    828    TreeOperationMatcher(nsHtml5TreeOpExecutor* aBuilder,
    829                         nsIContent** aScriptElement, bool* aInterrupted,
    830                         bool* aStreamEnded)
    831        : mBuilder(aBuilder),
    832          mScriptElement(aScriptElement),
    833          mInterrupted(aInterrupted),
    834          mStreamEnded(aStreamEnded) {}
    835 
    836    nsHtml5TreeOpExecutor* mBuilder;
    837    nsIContent** mScriptElement;
    838    bool* mInterrupted;
    839    bool* mStreamEnded;
    840 
    841    nsresult operator()(const opAppend& aOperation) {
    842      return Append(*(aOperation.mChild), *(aOperation.mParent),
    843                    aOperation.mFromNetwork, mBuilder);
    844    }
    845 
    846    nsresult operator()(const opDetach& aOperation) {
    847      Detach(*(aOperation.mElement), mBuilder);
    848      return NS_OK;
    849    }
    850 
    851    nsresult operator()(const opAppendChildrenToNewParent& aOperation) {
    852      nsCOMPtr<nsIContent> node = *(aOperation.mOldParent);
    853      nsIContent* parent = *(aOperation.mNewParent);
    854      return AppendChildrenToNewParent(node, parent, mBuilder);
    855    }
    856 
    857    nsresult operator()(const opFosterParent& aOperation) {
    858      nsIContent* node = *(aOperation.mChild);
    859      nsIContent* parent = *(aOperation.mStackParent);
    860      nsIContent* table = *(aOperation.mTable);
    861      return FosterParent(node, parent, table, mBuilder);
    862    }
    863 
    864    nsresult operator()(const opAppendToDocument& aOperation) {
    865      nsresult rv = AppendToDocument(*(aOperation.mContent), mBuilder);
    866      mBuilder->PauseDocUpdate(mInterrupted);
    867      return rv;
    868    }
    869 
    870    nsresult operator()(const opAddAttributes& aOperation) {
    871      nsIContent* node = *(aOperation.mElement);
    872      nsHtml5HtmlAttributes* attributes = aOperation.mAttributes;
    873      return AddAttributes(node, attributes, mBuilder);
    874    }
    875 
    876    nsresult operator()(const nsHtml5DocumentMode& aMode) {
    877      mBuilder->SetDocumentMode(aMode);
    878      return NS_OK;
    879    }
    880 
    881    nsresult operator()(const opCreateHTMLElement& aOperation) {
    882      nsIContent** target = aOperation.mContent;
    883      HTMLContentCreatorFunction creator = aOperation.mCreator;
    884      nsAtom* name = aOperation.mName;
    885      nsHtml5HtmlAttributes* attributes = aOperation.mAttributes;
    886      nsIContent* intendedParent =
    887          aOperation.mIntendedParent ? *(aOperation.mIntendedParent) : nullptr;
    888 
    889      // intendedParent == nullptr is a special case where the
    890      // intended parent is the document.
    891      nsNodeInfoManager* nodeInfoManager =
    892          intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
    893                         : mBuilder->GetNodeInfoManager();
    894 
    895      *target = CreateHTMLElement(name, attributes, aOperation.mFromNetwork,
    896                                  nodeInfoManager, mBuilder, creator);
    897      return NS_OK;
    898    }
    899 
    900    nsresult operator()(const opCreateSVGElement& aOperation) {
    901      nsIContent** target = aOperation.mContent;
    902      SVGContentCreatorFunction creator = aOperation.mCreator;
    903      nsAtom* name = aOperation.mName;
    904      nsHtml5HtmlAttributes* attributes = aOperation.mAttributes;
    905      nsIContent* intendedParent =
    906          aOperation.mIntendedParent ? *(aOperation.mIntendedParent) : nullptr;
    907 
    908      // intendedParent == nullptr is a special case where the
    909      // intended parent is the document.
    910      nsNodeInfoManager* nodeInfoManager =
    911          intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
    912                         : mBuilder->GetNodeInfoManager();
    913 
    914      *target = CreateSVGElement(name, attributes, aOperation.mFromNetwork,
    915                                 nodeInfoManager, mBuilder, creator);
    916      return NS_OK;
    917    }
    918 
    919    nsresult operator()(const opCreateMathMLElement& aOperation) {
    920      nsIContent** target = aOperation.mContent;
    921      nsAtom* name = aOperation.mName;
    922      nsHtml5HtmlAttributes* attributes = aOperation.mAttributes;
    923      nsIContent* intendedParent =
    924          aOperation.mIntendedParent ? *(aOperation.mIntendedParent) : nullptr;
    925 
    926      // intendedParent == nullptr is a special case where the
    927      // intended parent is the document.
    928      nsNodeInfoManager* nodeInfoManager =
    929          intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
    930                         : mBuilder->GetNodeInfoManager();
    931 
    932      *target =
    933          CreateMathMLElement(name, attributes, nodeInfoManager, mBuilder);
    934      return NS_OK;
    935    }
    936 
    937    nsresult operator()(const opSetFormElement& aOperation) {
    938      SetFormElement(*(aOperation.mContent), *(aOperation.mFormElement),
    939                     *(aOperation.mIntendedParent));
    940      return NS_OK;
    941    }
    942 
    943    nsresult operator()(const opAppendText& aOperation) {
    944      nsIContent* parent = *aOperation.mParent;
    945      char16_t* buffer = aOperation.mBuffer;
    946      uint32_t length = aOperation.mLength;
    947      return AppendText(buffer, length, parent, mBuilder);
    948    }
    949 
    950    nsresult operator()(const opFosterParentText& aOperation) {
    951      nsIContent* stackParent = *aOperation.mStackParent;
    952      char16_t* buffer = aOperation.mBuffer;
    953      uint32_t length = aOperation.mLength;
    954      nsIContent* table = *aOperation.mTable;
    955      return FosterParentText(stackParent, buffer, length, table, mBuilder);
    956    }
    957 
    958    nsresult operator()(const opAppendComment& aOperation) {
    959      nsIContent* parent = *aOperation.mParent;
    960      char16_t* buffer = aOperation.mBuffer;
    961      uint32_t length = aOperation.mLength;
    962      return AppendComment(parent, buffer, length, mBuilder);
    963    }
    964 
    965    nsresult operator()(const opAppendCommentToDocument& aOperation) {
    966      char16_t* buffer = aOperation.mBuffer;
    967      int32_t length = aOperation.mLength;
    968      return AppendCommentToDocument(buffer, length, mBuilder);
    969    }
    970 
    971    nsresult operator()(const opAppendDoctypeToDocument& aOperation) {
    972      nsAtom* name = aOperation.mName;
    973      nsHtml5TreeOperationStringPair* pair = aOperation.mStringPair;
    974      nsString publicId;
    975      nsString systemId;
    976      pair->Get(publicId, systemId);
    977      return AppendDoctypeToDocument(name, publicId, systemId, mBuilder);
    978    }
    979 
    980    nsresult operator()(const opGetDocumentFragmentForTemplate& aOperation) {
    981      nsIContent* node = *(aOperation.mTemplate);
    982      *(aOperation.mFragHandle) = GetDocumentFragmentForTemplate(node);
    983      return NS_OK;
    984    }
    985 
    986    nsresult operator()(const opSetDocumentFragmentForTemplate& aOperation) {
    987      SetDocumentFragmentForTemplate(*aOperation.mTemplate,
    988                                     *aOperation.mFragment);
    989      return NS_OK;
    990    }
    991 
    992    nsresult operator()(const opGetShadowRootFromHost& aOperation) {
    993      nsIContent* root = nsContentUtils::AttachDeclarativeShadowRoot(
    994          *aOperation.mHost, aOperation.mShadowRootMode,
    995          aOperation.mShadowRootIsClonable,
    996          aOperation.mShadowRootIsSerializable,
    997          aOperation.mShadowRootDelegatesFocus,
    998          aOperation.mShadowRootReferenceTarget);
    999      if (root) {
   1000        *aOperation.mFragHandle = root;
   1001        return NS_OK;
   1002      }
   1003 
   1004      // We failed to attach a new shadow root, so instead attach a template
   1005      // element and return its content.
   1006      nsHtml5TreeOperation::Append(*aOperation.mTemplateNode, *aOperation.mHost,
   1007                                   mBuilder);
   1008      *aOperation.mFragHandle =
   1009          static_cast<HTMLTemplateElement*>(*aOperation.mTemplateNode)
   1010              ->Content();
   1011      nsContentUtils::LogSimpleConsoleError(
   1012          u"Failed to attach Declarative Shadow DOM."_ns, "DOM"_ns,
   1013          mBuilder->GetDocument()->IsInPrivateBrowsing(),
   1014          mBuilder->GetDocument()->IsInChromeDocShell());
   1015      return NS_OK;
   1016    }
   1017 
   1018    nsresult operator()(const opGetFosterParent& aOperation) {
   1019      nsIContent* table = *(aOperation.mTable);
   1020      nsIContent* stackParent = *(aOperation.mStackParent);
   1021      nsIContent* fosterParent = GetFosterParent(table, stackParent);
   1022      *aOperation.mParentHandle = fosterParent;
   1023      return NS_OK;
   1024    }
   1025 
   1026    nsresult operator()(const opMarkAsBroken& aOperation) {
   1027      return aOperation.mResult;
   1028    }
   1029 
   1030    nsresult operator()(
   1031        const opRunScriptThatMayDocumentWriteOrBlock& aOperation) {
   1032      nsIContent* node = *(aOperation.mElement);
   1033      nsAHtml5TreeBuilderState* snapshot = aOperation.mBuilderState;
   1034      if (snapshot) {
   1035        mBuilder->InitializeDocWriteParserState(snapshot,
   1036                                                aOperation.mLineNumber);
   1037      }
   1038      *mScriptElement = node;
   1039      return NS_OK;
   1040    }
   1041 
   1042    nsresult operator()(
   1043        const opRunScriptThatCannotDocumentWriteOrBlock& aOperation) {
   1044      mBuilder->RunScript(*(aOperation.mElement), false);
   1045      return NS_OK;
   1046    }
   1047 
   1048    nsresult operator()(const opPreventScriptExecution& aOperation) {
   1049      PreventScriptExecution(*(aOperation.mElement));
   1050      return NS_OK;
   1051    }
   1052 
   1053    nsresult operator()(const opDoneAddingChildren& aOperation) {
   1054      nsIContent* node = *(aOperation.mElement);
   1055      node->DoneAddingChildren(node->HasParserNotified());
   1056      return NS_OK;
   1057    }
   1058 
   1059    nsresult operator()(const opDoneCreatingElement& aOperation) {
   1060      DoneCreatingElement(*(aOperation.mElement));
   1061      return NS_OK;
   1062    }
   1063 
   1064    nsresult operator()(const opUpdateCharsetSource& aOperation) {
   1065      mBuilder->UpdateCharsetSource(aOperation.mCharsetSource);
   1066      return NS_OK;
   1067    }
   1068 
   1069    nsresult operator()(const opCharsetSwitchTo& aOperation) {
   1070      auto encoding = WrapNotNull(aOperation.mEncoding);
   1071      mBuilder->NeedsCharsetSwitchTo(encoding, aOperation.mCharsetSource,
   1072                                     (uint32_t)aOperation.mLineNumber);
   1073      return NS_OK;
   1074    }
   1075 
   1076    nsresult operator()(const opUpdateStyleSheet& aOperation) {
   1077      mBuilder->UpdateStyleSheet(*(aOperation.mElement));
   1078      return NS_OK;
   1079    }
   1080 
   1081    nsresult operator()(const opProcessOfflineManifest& aOperation) {
   1082      // TODO: remove this
   1083      return NS_OK;
   1084    }
   1085 
   1086    nsresult operator()(const opMarkMalformedIfScript& aOperation) {
   1087      MarkMalformedIfScript(*(aOperation.mElement));
   1088      return NS_OK;
   1089    }
   1090 
   1091    nsresult operator()(const opStreamEnded& aOperation) {
   1092      *mStreamEnded = true;
   1093      return NS_OK;
   1094    }
   1095 
   1096    nsresult operator()(const opSetStyleLineNumber& aOperation) {
   1097      nsIContent* node = *(aOperation.mContent);
   1098      if (auto* linkStyle = LinkStyle::FromNode(*node)) {
   1099        linkStyle->SetLineNumber(aOperation.mLineNumber);
   1100      } else {
   1101        MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
   1102                   "Node didn't QI to style, but SVG wasn't disabled.");
   1103      }
   1104      return NS_OK;
   1105    }
   1106 
   1107    nsresult operator()(
   1108        const opSetScriptLineAndColumnNumberAndFreeze& aOperation) {
   1109      nsIContent* node = *(aOperation.mContent);
   1110      nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node);
   1111      if (sele) {
   1112        sele->SetScriptLineNumber(aOperation.mLineNumber);
   1113        sele->SetScriptColumnNumber(
   1114            JS::ColumnNumberOneOrigin(aOperation.mColumnNumber));
   1115        sele->FreezeExecutionAttrs(node->OwnerDoc());
   1116      } else {
   1117        MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
   1118                   "Node didn't QI to script, but SVG wasn't disabled.");
   1119      }
   1120      return NS_OK;
   1121    }
   1122 
   1123    nsresult operator()(const opSvgLoad& aOperation) {
   1124      SvgLoad(*(aOperation.mElement));
   1125      return NS_OK;
   1126    }
   1127 
   1128    nsresult operator()(const opMaybeComplainAboutCharset& aOperation) {
   1129      char* msgId = aOperation.mMsgId;
   1130      bool error = aOperation.mError;
   1131      int32_t lineNumber = aOperation.mLineNumber;
   1132      mBuilder->MaybeComplainAboutCharset(msgId, error, (uint32_t)lineNumber);
   1133      return NS_OK;
   1134    }
   1135 
   1136    nsresult operator()(const opMaybeComplainAboutDeepTree& aOperation) {
   1137      mBuilder->MaybeComplainAboutDeepTree((uint32_t)aOperation.mLineNumber);
   1138      return NS_OK;
   1139    }
   1140 
   1141    nsresult operator()(const opAddClass& aOperation) {
   1142      Element* element = (*(aOperation.mElement))->AsElement();
   1143      char16_t* str = aOperation.mClass;
   1144      nsDependentString depStr(str);
   1145      // See viewsource.css for the possible classes
   1146      nsAutoString klass;
   1147      element->GetAttr(nsGkAtoms::_class, klass);
   1148      if (!klass.IsEmpty()) {
   1149        klass.Append(' ');
   1150        klass.Append(depStr);
   1151        element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
   1152      } else {
   1153        element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, depStr, true);
   1154      }
   1155      return NS_OK;
   1156    }
   1157 
   1158    nsresult operator()(const opAddViewSourceHref& aOperation) {
   1159      Element* element = (*aOperation.mElement)->AsElement();
   1160      char16_t* buffer = aOperation.mBuffer;
   1161      int32_t length = aOperation.mLength;
   1162      nsDependentString relative(buffer, length);
   1163 
   1164      Document* doc = mBuilder->GetDocument();
   1165 
   1166      auto encoding = doc->GetDocumentCharacterSet();
   1167      nsCOMPtr<nsIURI> uri;
   1168      nsresult rv = NS_NewURI(getter_AddRefs(uri), relative, encoding,
   1169                              mBuilder->GetViewSourceBaseURI());
   1170      NS_ENSURE_SUCCESS(rv, NS_OK);
   1171 
   1172      // Reuse the fix for bug 467852
   1173      // URLs that execute script (e.g. "javascript:" URLs) should just be
   1174      // ignored.  There's nothing reasonable we can do with them, and allowing
   1175      // them to execute in the context of the view-source window presents a
   1176      // security risk.  Just return the empty string in this case.
   1177      bool openingExecutesScript = false;
   1178      rv = NS_URIChainHasFlags(uri,
   1179                               nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT,
   1180                               &openingExecutesScript);
   1181      if (NS_FAILED(rv) || openingExecutesScript) {
   1182        return NS_OK;
   1183      }
   1184 
   1185      nsAutoCString viewSourceUrl;
   1186 
   1187      // URLs that return data (e.g. "http:" URLs) should be prefixed with
   1188      // "view-source:".  URLs that don't return data should just be returned
   1189      // undecorated.
   1190      if (!nsContentUtils::IsExternalProtocol(uri)) {
   1191        viewSourceUrl.AssignLiteral("view-source:");
   1192      }
   1193 
   1194      nsAutoCString spec;
   1195      rv = uri->GetSpec(spec);
   1196      NS_ENSURE_SUCCESS(rv, rv);
   1197 
   1198      viewSourceUrl.Append(spec);
   1199 
   1200      nsAutoString utf16;
   1201      CopyUTF8toUTF16(viewSourceUrl, utf16);
   1202 
   1203      element->SetAttr(kNameSpaceID_None, nsGkAtoms::href, utf16, true);
   1204      return NS_OK;
   1205    }
   1206 
   1207    nsresult operator()(const opAddViewSourceBase& aOperation) {
   1208      nsDependentString baseUrl(aOperation.mBuffer, aOperation.mLength);
   1209      mBuilder->AddBase(baseUrl);
   1210      return NS_OK;
   1211    }
   1212 
   1213    nsresult operator()(const opAddErrorType& aOperation) {
   1214      Element* element = (*(aOperation.mElement))->AsElement();
   1215      char* msgId = aOperation.mMsgId;
   1216      nsAtom* atom = aOperation.mName;
   1217      nsAtom* otherAtom = aOperation.mOther;
   1218      // See viewsource.css for the possible classes in addition to "error".
   1219      nsAutoString klass;
   1220      element->GetAttr(nsGkAtoms::_class, klass);
   1221      if (!klass.IsEmpty()) {
   1222        klass.AppendLiteral(" error");
   1223        element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
   1224      } else {
   1225        element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, u"error"_ns,
   1226                         true);
   1227      }
   1228 
   1229      nsresult rv;
   1230      nsAutoString message;
   1231      if (otherAtom) {
   1232        rv = nsContentUtils::FormatLocalizedString(
   1233            message, nsContentUtils::eHTMLPARSER_PROPERTIES, msgId,
   1234            nsDependentAtomString(atom), nsDependentAtomString(otherAtom));
   1235        NS_ENSURE_SUCCESS(rv, NS_OK);
   1236      } else if (atom) {
   1237        rv = nsContentUtils::FormatLocalizedString(
   1238            message, nsContentUtils::eHTMLPARSER_PROPERTIES, msgId,
   1239            nsDependentAtomString(atom));
   1240        NS_ENSURE_SUCCESS(rv, NS_OK);
   1241      } else {
   1242        rv = nsContentUtils::GetLocalizedString(
   1243            nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, message);
   1244        NS_ENSURE_SUCCESS(rv, NS_OK);
   1245      }
   1246 
   1247      nsAutoString title;
   1248      element->GetAttr(nsGkAtoms::title, title);
   1249      if (!title.IsEmpty()) {
   1250        title.Append('\n');
   1251        title.Append(message);
   1252        element->SetAttr(kNameSpaceID_None, nsGkAtoms::title, title, true);
   1253      } else {
   1254        element->SetAttr(kNameSpaceID_None, nsGkAtoms::title, message, true);
   1255      }
   1256      return rv;
   1257    }
   1258 
   1259    nsresult operator()(const opAddLineNumberId& aOperation) {
   1260      Element* element = (*(aOperation.mElement))->AsElement();
   1261      int32_t lineNumber = aOperation.mLineNumber;
   1262      nsAutoString val(u"line"_ns);
   1263      val.AppendInt(lineNumber);
   1264      element->SetAttr(kNameSpaceID_None, nsGkAtoms::id, val, true);
   1265      return NS_OK;
   1266    }
   1267 
   1268    nsresult operator()(const opShallowCloneInto& aOperation) {
   1269      nsIContent* src = *aOperation.mSrc;
   1270      ErrorResult rv;
   1271      RefPtr<nsINode> clone = src->CloneNode(false, rv);
   1272      if (NS_WARN_IF(rv.Failed())) {
   1273        return rv.StealNSResult();
   1274      }
   1275      *aOperation.mDst = clone->AsContent();
   1276      mBuilder->HoldElement(clone.forget().downcast<nsIContent>());
   1277      return Append(*aOperation.mDst, *aOperation.mIntendedParent,
   1278                    aOperation.mFromParser, mBuilder);
   1279    }
   1280 
   1281    nsresult operator()(const opStartLayout& aOperation) {
   1282      mBuilder->StartLayout(
   1283          mInterrupted);  // this causes a notification flush anyway
   1284      return NS_OK;
   1285    }
   1286 
   1287    nsresult operator()(const opEnableEncodingMenu& aOperation) {
   1288      Document* doc = mBuilder->GetDocument();
   1289      doc->EnableEncodingMenu();
   1290      return NS_OK;
   1291    }
   1292 
   1293    nsresult operator()(const opMicrotaskCheckpoint& aOperation) {
   1294      nsHtml5AutoPauseUpdate autoPauseContentUpdate(mBuilder);
   1295      nsAutoMicroTask mt;
   1296      return NS_OK;
   1297    }
   1298 
   1299    nsresult operator()(const uninitialized& aOperation) {
   1300      MOZ_CRASH("uninitialized");
   1301      return NS_OK;
   1302    }
   1303  };
   1304 
   1305  return mOperation.match(TreeOperationMatcher(aBuilder, aScriptElement,
   1306                                               aInterrupted, aStreamEnded));
   1307 }