tor-browser

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

nsHtml5TreeBuilderCppSupplement.h (82228B)


      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 "ErrorList.h"
      8 #include "nsError.h"
      9 #include "nsHtml5AttributeName.h"
     10 #include "nsHtml5HtmlAttributes.h"
     11 #include "nsHtml5String.h"
     12 #include "nsNetUtil.h"
     13 #include "mozilla/dom/FetchPriority.h"
     14 #include "mozilla/dom/ShadowRoot.h"
     15 #include "mozilla/dom/ShadowRootBinding.h"
     16 #include "mozilla/glean/ParserHtmlMetrics.h"
     17 #include "mozilla/CheckedInt.h"
     18 #include "mozilla/Likely.h"
     19 #include "mozilla/StaticPrefs_dom.h"
     20 #include "mozilla/StaticPrefs_network.h"
     21 #include "mozilla/UniquePtr.h"
     22 #include "mozilla/UniquePtrExtensions.h"
     23 
     24 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder)
     25    : mode(0),
     26      originalMode(0),
     27      framesetOk(false),
     28      tokenizer(nullptr),
     29      scriptingEnabled(false),
     30      needToDropLF(false),
     31      fragment(false),
     32      contextName(nullptr),
     33      contextNamespace(kNameSpaceID_None),
     34      contextNode(nullptr),
     35      templateModePtr(0),
     36      stackNodesIdx(0),
     37      numStackNodes(0),
     38      currentPtr(0),
     39      listPtr(0),
     40      formPointer(nullptr),
     41      headPointer(nullptr),
     42      charBufferLen(0),
     43      quirks(false),
     44      forceNoQuirks(false),
     45      allowDeclarativeShadowRoots(false),
     46      keepBuffer(false),
     47      mBuilder(aBuilder),
     48      mViewSource(nullptr),
     49      mOpSink(nullptr),
     50      mHandles(nullptr),
     51      mHandlesUsed(0),
     52      mSpeculativeLoadStage(nullptr),
     53      mBroken(NS_OK),
     54      mCurrentHtmlScriptCannotDocumentWriteOrBlock(false),
     55      mPreventScriptExecution(false),
     56      mGenerateSpeculativeLoads(false),
     57      mHasSeenImportMap(false)
     58 #ifdef DEBUG
     59      ,
     60      mActive(false)
     61 #endif
     62 {
     63  MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
     64 }
     65 
     66 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
     67                                       nsHtml5TreeOpStage* aStage,
     68                                       bool aGenerateSpeculativeLoads)
     69    : mode(0),
     70      originalMode(0),
     71      framesetOk(false),
     72      tokenizer(nullptr),
     73      scriptingEnabled(false),
     74      needToDropLF(false),
     75      fragment(false),
     76      contextName(nullptr),
     77      contextNamespace(kNameSpaceID_None),
     78      contextNode(nullptr),
     79      templateModePtr(0),
     80      stackNodesIdx(0),
     81      numStackNodes(0),
     82      currentPtr(0),
     83      listPtr(0),
     84      formPointer(nullptr),
     85      headPointer(nullptr),
     86      charBufferLen(0),
     87      quirks(false),
     88      forceNoQuirks(false),
     89      allowDeclarativeShadowRoots(false),
     90      keepBuffer(false),
     91      mBuilder(nullptr),
     92      mViewSource(nullptr),
     93      mOpSink(aOpSink),
     94      mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH]),
     95      mHandlesUsed(0),
     96      mSpeculativeLoadStage(aStage),
     97      mBroken(NS_OK),
     98      mCurrentHtmlScriptCannotDocumentWriteOrBlock(false),
     99      mPreventScriptExecution(false),
    100      mGenerateSpeculativeLoads(aGenerateSpeculativeLoads),
    101      mHasSeenImportMap(false)
    102 #ifdef DEBUG
    103      ,
    104      mActive(false)
    105 #endif
    106 {
    107  MOZ_ASSERT(!(!aStage && aGenerateSpeculativeLoads),
    108             "Must not generate speculative loads without a stage");
    109  MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
    110 }
    111 
    112 nsHtml5TreeBuilder::~nsHtml5TreeBuilder() {
    113  MOZ_COUNT_DTOR(nsHtml5TreeBuilder);
    114  NS_ASSERTION(!mActive,
    115               "nsHtml5TreeBuilder deleted without ever calling end() on it!");
    116  mOpQueue.Clear();
    117 }
    118 
    119 static void getTypeString(nsHtml5String& aType, nsAString& aTypeString) {
    120  aType.ToString(aTypeString);
    121 
    122  // Since `typeString` after trimming and lowercasing is only checked
    123  // for "module" and " importmap", we don't need to remember
    124  // pre-trimming emptiness here.
    125 
    126  // ASCII whitespace https://infra.spec.whatwg.org/#ascii-whitespace:
    127  // U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE.
    128  static const char kASCIIWhitespace[] = "\t\n\f\r ";
    129  aTypeString.Trim(kASCIIWhitespace);
    130 }
    131 
    132 nsIContentHandle* nsHtml5TreeBuilder::createElement(
    133    int32_t aNamespace, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes,
    134    nsIContentHandle* aIntendedParent, nsHtml5ContentCreatorFunction aCreator) {
    135  MOZ_ASSERT(aAttributes, "Got null attributes.");
    136  MOZ_ASSERT(aName, "Got null name.");
    137  MOZ_ASSERT(aNamespace == kNameSpaceID_XHTML ||
    138                 aNamespace == kNameSpaceID_SVG ||
    139                 aNamespace == kNameSpaceID_MathML,
    140             "Bogus namespace.");
    141 
    142  if (mBuilder) {
    143    nsIContent* intendedParent =
    144        aIntendedParent ? static_cast<nsIContent*>(aIntendedParent) : nullptr;
    145 
    146    // intendedParent == nullptr is a special case where the
    147    // intended parent is the document.
    148    nsNodeInfoManager* nodeInfoManager =
    149        intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
    150                       : mBuilder->GetNodeInfoManager();
    151 
    152    nsIContent* elem;
    153    if (aNamespace == kNameSpaceID_XHTML) {
    154      elem = nsHtml5TreeOperation::CreateHTMLElement(
    155          aName, aAttributes, mozilla::dom::FROM_PARSER_FRAGMENT,
    156          nodeInfoManager, mBuilder, aCreator.html);
    157    } else if (aNamespace == kNameSpaceID_SVG) {
    158      elem = nsHtml5TreeOperation::CreateSVGElement(
    159          aName, aAttributes, mozilla::dom::FROM_PARSER_FRAGMENT,
    160          nodeInfoManager, mBuilder, aCreator.svg);
    161    } else {
    162      MOZ_ASSERT(aNamespace == kNameSpaceID_MathML);
    163      elem = nsHtml5TreeOperation::CreateMathMLElement(
    164          aName, aAttributes, nodeInfoManager, mBuilder);
    165    }
    166    if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() &&
    167                     aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) {
    168      delete aAttributes;
    169    }
    170    return elem;
    171  }
    172 
    173  nsIContentHandle* content = AllocateContentHandle();
    174  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
    175  if (MOZ_UNLIKELY(!treeOp)) {
    176    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
    177    return nullptr;
    178  }
    179 
    180  if (aNamespace == kNameSpaceID_XHTML) {
    181    opCreateHTMLElement opeation(
    182        content, aName, aAttributes, aCreator.html, aIntendedParent,
    183        (!!mSpeculativeLoadStage) ? mozilla::dom::FROM_PARSER_NETWORK
    184                                  : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE);
    185    treeOp->Init(mozilla::AsVariant(opeation));
    186  } else if (aNamespace == kNameSpaceID_SVG) {
    187    opCreateSVGElement operation(
    188        content, aName, aAttributes, aCreator.svg, aIntendedParent,
    189        (!!mSpeculativeLoadStage) ? mozilla::dom::FROM_PARSER_NETWORK
    190                                  : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE);
    191    treeOp->Init(mozilla::AsVariant(operation));
    192  } else {
    193    // kNameSpaceID_MathML
    194    opCreateMathMLElement operation(content, aName, aAttributes,
    195                                    aIntendedParent);
    196    treeOp->Init(mozilla::AsVariant(operation));
    197  }
    198 
    199  // mSpeculativeLoadStage is non-null only in the off-the-main-thread
    200  // tree builder, which handles the network stream
    201 
    202  // Start wall of code for speculative loading and line numbers
    203 
    204  if (mGenerateSpeculativeLoads && mode != IN_TEMPLATE) {
    205    switch (aNamespace) {
    206      case kNameSpaceID_XHTML:
    207        if (nsGkAtoms::img == aName) {
    208          nsHtml5String loading =
    209              aAttributes->getValue(nsHtml5AttributeName::ATTR_LOADING);
    210          if (!loading.LowerCaseEqualsASCII("lazy")) {
    211            nsHtml5String url =
    212                aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
    213            nsHtml5String srcset =
    214                aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
    215            nsHtml5String crossOrigin =
    216                aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
    217            nsHtml5String referrerPolicy = aAttributes->getValue(
    218                nsHtml5AttributeName::ATTR_REFERRERPOLICY);
    219            nsHtml5String sizes =
    220                aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
    221            nsHtml5String fetchPriority =
    222                aAttributes->getValue(nsHtml5AttributeName::ATTR_FETCHPRIORITY);
    223            nsHtml5String type =
    224                aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
    225            mSpeculativeLoadQueue.AppendElement()->InitImage(
    226                url, crossOrigin, /* aMedia = */ nullptr, referrerPolicy,
    227                srcset, sizes, false, fetchPriority, type);
    228          }
    229        } else if (nsGkAtoms::source == aName) {
    230          nsHtml5String srcset =
    231              aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
    232          // Sources without srcset cannot be selected. The source could also be
    233          // for a media element, but in that context doesn't use srcset.  See
    234          // comments in nsHtml5SpeculativeLoad.h about <picture> preloading
    235          if (srcset) {
    236            nsHtml5String sizes =
    237                aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
    238            nsHtml5String type =
    239                aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
    240            nsHtml5String media =
    241                aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA);
    242            mSpeculativeLoadQueue.AppendElement()->InitPictureSource(
    243                srcset, sizes, type, media);
    244          }
    245        } else if (nsGkAtoms::script == aName) {
    246          nsHtml5TreeOperation* treeOp =
    247              mOpQueue.AppendElement(mozilla::fallible);
    248          if (MOZ_UNLIKELY(!treeOp)) {
    249            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
    250                NS_ERROR_OUT_OF_MEMORY);
    251            return nullptr;
    252          }
    253          opSetScriptLineAndColumnNumberAndFreeze operation(
    254              content, tokenizer->getLineNumber(),
    255              // NOTE: tokenizer->getColumnNumber() points '>'.
    256              tokenizer->getColumnNumber() + 1);
    257          treeOp->Init(mozilla::AsVariant(operation));
    258 
    259          nsHtml5String type =
    260              aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
    261          nsAutoString typeString;
    262          getTypeString(type, typeString);
    263 
    264          bool isModule = typeString.LowerCaseEqualsASCII("module");
    265          bool importmap = typeString.LowerCaseEqualsASCII("importmap");
    266          bool async = false;
    267          bool defer = false;
    268          bool nomodule =
    269              aAttributes->contains(nsHtml5AttributeName::ATTR_NOMODULE);
    270 
    271          // For microtask semantics, we need to queue either
    272          // `opRunScriptThatMayDocumentWriteOrBlock` or
    273          // `opRunScriptThatCannotDocumentWriteOrBlock` for every script
    274          // element--even ones that we already know won't run.
    275          // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` controls which
    276          // kind of operation is used for an HTML script, and this is the
    277          // place where `mCurrentHtmlScriptCannotDocumentWriteOrBlock`
    278          // needs to be set correctly.
    279          //
    280          // Non-async, non-defer classic scripts that will run MUST use
    281          // `opRunScriptThatMayDocumentWriteOrBlock` in order to run
    282          // the more complex code that
    283          // 1. is able to resume the HTML parse after a parser-blocking
    284          //    scripts no longer blocks the parser
    285          // 2. is able to receive more content to parse on the main thread
    286          //    via document.write
    287          // 3. is able to throw away off-the-main-thread parsing results
    288          //    if what's document.written on the main thread invalidates
    289          //    the speculation.
    290          //
    291          // Async and defer classic scripts as well as module scripts and
    292          // importmaps MUST use `opRunScriptThatCannotDocumentWriteOrBlock`.
    293          // This is necessary particularly because the relevant main-thread
    294          // code assumes it doesn't need to deal with resuming the HTML
    295          // parse some time afterwards, so using a tree operation with
    296          // mismatching expectations regarding that responsibility may
    297          // cause the HTML parse to stall.
    298          //
    299          // Various scripts that won't actually run work with either type
    300          // of tree op in the sense that the HTML parse won't stall.
    301          // However, in the case where a script cannot block or insert
    302          // data to the HTML parser via document.write, unnecessary use
    303          // of `opRunScriptThatMayDocumentWriteOrBlock` instead of
    304          // `opRunScriptThatCannotDocumentWriteOrBlock` causes the HTML
    305          // parser to enter the speculative mode when doing so isn't
    306          // actually required.
    307          //
    308          // Ideally, we would check for `type`/`language` attribute
    309          // combinations that are known to cause non-execution as well as
    310          // ScriptLoader::IsScriptEventHandler equivalent. That way, we
    311          // wouldn't unnecessarily speculate after scripts that won't
    312          // execute. https://bugzilla.mozilla.org/show_bug.cgi?id=1848311
    313 
    314          if (importmap) {
    315            // If we see an importmap, we don't want to later start speculative
    316            // loads for modulepreloads, since such load might finish before
    317            // the importmap is created. This also applies to module scripts so
    318            // that any modulepreload integrity checks can be performed before
    319            // the modules scripts are loaded.
    320            // This state is not part of speculation rollback: If an importmap
    321            // is seen speculatively and the speculation is rolled back, the
    322            // importmap is still considered seen.
    323            // TODO: Sync importmap seenness between the main thread and the
    324            // parser thread.
    325            // https://bugzilla.mozilla.org/show_bug.cgi?id=1848312
    326            mHasSeenImportMap = true;
    327          }
    328          nsHtml5String url =
    329              aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
    330          if (url) {
    331            async = aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC);
    332            defer = aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER);
    333            if ((isModule && !mHasSeenImportMap) ||
    334                (!isModule && !importmap && !nomodule)) {
    335              nsHtml5String charset =
    336                  aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
    337              nsHtml5String crossOrigin =
    338                  aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
    339              nsHtml5String nonce =
    340                  aAttributes->getValue(nsHtml5AttributeName::ATTR_NONCE);
    341              nsHtml5String fetchPriority = aAttributes->getValue(
    342                  nsHtml5AttributeName::ATTR_FETCHPRIORITY);
    343              nsHtml5String integrity =
    344                  aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
    345              nsHtml5String referrerPolicy = aAttributes->getValue(
    346                  nsHtml5AttributeName::ATTR_REFERRERPOLICY);
    347              mSpeculativeLoadQueue.AppendElement()->InitScript(
    348                  url, charset, type, crossOrigin, /* aMedia = */ nullptr,
    349                  nonce, fetchPriority, integrity, referrerPolicy,
    350                  mode == nsHtml5TreeBuilder::IN_HEAD, async, defer, false);
    351            }
    352          }
    353          // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` MUST be computed to
    354          // match the ScriptLoader-perceived kind of the script regardless of
    355          // enqueuing a speculative load. Scripts with the `nomodule` attribute
    356          // never block or document.write: Either the attribute prevents a
    357          // classic script execution or is ignored on a module script or
    358          // importmap.
    359          mCurrentHtmlScriptCannotDocumentWriteOrBlock =
    360              isModule || importmap || async || defer || nomodule;
    361        } else if (nsGkAtoms::link == aName) {
    362          nsHtml5String rel =
    363              aAttributes->getValue(nsHtml5AttributeName::ATTR_REL);
    364          // Not splitting on space here is bogus but the old parser didn't even
    365          // do a case-insensitive check.
    366          if (rel) {
    367            if (rel.LowerCaseEqualsASCII("stylesheet")) {
    368              nsHtml5String url =
    369                  aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
    370              if (url &&
    371                  !aAttributes->getValue(nsHtml5AttributeName::ATTR_DISABLED)) {
    372                nsHtml5String charset =
    373                    aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
    374                nsHtml5String crossOrigin = aAttributes->getValue(
    375                    nsHtml5AttributeName::ATTR_CROSSORIGIN);
    376                nsHtml5String nonce =
    377                    aAttributes->getValue(nsHtml5AttributeName::ATTR_NONCE);
    378                nsHtml5String integrity =
    379                    aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
    380                nsHtml5String referrerPolicy = aAttributes->getValue(
    381                    nsHtml5AttributeName::ATTR_REFERRERPOLICY);
    382                nsHtml5String media =
    383                    aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA);
    384                nsHtml5String fetchPriority = aAttributes->getValue(
    385                    nsHtml5AttributeName::ATTR_FETCHPRIORITY);
    386                mSpeculativeLoadQueue.AppendElement()->InitStyle(
    387                    url, charset, crossOrigin, media, referrerPolicy, nonce,
    388                    integrity, false, fetchPriority);
    389              }
    390            } else if (rel.LowerCaseEqualsASCII("preconnect")) {
    391              nsHtml5String url =
    392                  aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
    393              if (url) {
    394                nsHtml5String crossOrigin = aAttributes->getValue(
    395                    nsHtml5AttributeName::ATTR_CROSSORIGIN);
    396                mSpeculativeLoadQueue.AppendElement()->InitPreconnect(
    397                    url, crossOrigin);
    398              }
    399            } else if (rel.LowerCaseEqualsASCII("preload")) {
    400              nsHtml5String url =
    401                  aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
    402              if (url) {
    403                nsHtml5String as =
    404                    aAttributes->getValue(nsHtml5AttributeName::ATTR_AS);
    405                nsHtml5String charset =
    406                    aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
    407                nsHtml5String crossOrigin = aAttributes->getValue(
    408                    nsHtml5AttributeName::ATTR_CROSSORIGIN);
    409                nsHtml5String nonce =
    410                    aAttributes->getValue(nsHtml5AttributeName::ATTR_NONCE);
    411                nsHtml5String integrity =
    412                    aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
    413                nsHtml5String referrerPolicy = aAttributes->getValue(
    414                    nsHtml5AttributeName::ATTR_REFERRERPOLICY);
    415                nsHtml5String media =
    416                    aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA);
    417                nsHtml5String fetchPriority = aAttributes->getValue(
    418                    nsHtml5AttributeName::ATTR_FETCHPRIORITY);
    419 
    420                // Note that respective speculative loaders for scripts and
    421                // styles check all additional attributes to be equal to use the
    422                // speculative load.  So, if any of them is specified and the
    423                // preload has to take the expected effect, those attributes
    424                // must also be specified on the actual tag to use the preload.
    425                // Omitting an attribute on both will make the values equal
    426                // (empty) and thus use the preload.
    427                if (as.LowerCaseEqualsASCII("script")) {
    428                  nsHtml5String type =
    429                      aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
    430                  mSpeculativeLoadQueue.AppendElement()->InitScript(
    431                      url, charset, type, crossOrigin, media, nonce,
    432                      /* aFetchPriority */ fetchPriority, integrity,
    433                      referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD,
    434                      false, false, true);
    435                } else if (as.LowerCaseEqualsASCII("style")) {
    436                  mSpeculativeLoadQueue.AppendElement()->InitStyle(
    437                      url, charset, crossOrigin, media, referrerPolicy, nonce,
    438                      integrity, true, fetchPriority);
    439                } else if (as.LowerCaseEqualsASCII("image")) {
    440                  nsHtml5String srcset = aAttributes->getValue(
    441                      nsHtml5AttributeName::ATTR_IMAGESRCSET);
    442                  nsHtml5String sizes = aAttributes->getValue(
    443                      nsHtml5AttributeName::ATTR_IMAGESIZES);
    444                  nsHtml5String type =
    445                      aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
    446                  mSpeculativeLoadQueue.AppendElement()->InitImage(
    447                      url, crossOrigin, media, referrerPolicy, srcset, sizes,
    448                      true, fetchPriority, type);
    449                } else if (as.LowerCaseEqualsASCII("font")) {
    450                  mSpeculativeLoadQueue.AppendElement()->InitFont(
    451                      url, crossOrigin, media, referrerPolicy, fetchPriority);
    452                } else if (as.LowerCaseEqualsASCII("fetch")) {
    453                  mSpeculativeLoadQueue.AppendElement()->InitFetch(
    454                      url, crossOrigin, media, referrerPolicy, fetchPriority);
    455                }
    456                // Other "as" values will be supported later.
    457              }
    458            } else if (mozilla::StaticPrefs::network_modulepreload() &&
    459                       rel.LowerCaseEqualsASCII("modulepreload") &&
    460                       !mHasSeenImportMap) {
    461              nsHtml5String url =
    462                  aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
    463              if (url && url.Length() != 0) {
    464                nsHtml5String as =
    465                    aAttributes->getValue(nsHtml5AttributeName::ATTR_AS);
    466                nsAutoString asString;
    467                as.ToString(asString);
    468                if (mozilla::net::IsScriptLikeOrInvalid(asString)) {
    469                  nsHtml5String charset =
    470                      aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
    471                  RefPtr<nsAtom> moduleType = nsGkAtoms::_module;
    472                  nsHtml5String type =
    473                      nsHtml5String::FromAtom(moduleType.forget());
    474                  nsHtml5String crossOrigin = aAttributes->getValue(
    475                      nsHtml5AttributeName::ATTR_CROSSORIGIN);
    476                  nsHtml5String media =
    477                      aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA);
    478                  nsHtml5String nonce =
    479                      aAttributes->getValue(nsHtml5AttributeName::ATTR_NONCE);
    480                  nsHtml5String integrity = aAttributes->getValue(
    481                      nsHtml5AttributeName::ATTR_INTEGRITY);
    482                  nsHtml5String referrerPolicy = aAttributes->getValue(
    483                      nsHtml5AttributeName::ATTR_REFERRERPOLICY);
    484                  nsHtml5String fetchPriority = aAttributes->getValue(
    485                      nsHtml5AttributeName::ATTR_FETCHPRIORITY);
    486 
    487                  mSpeculativeLoadQueue.AppendElement()->InitScript(
    488                      url, charset, type, crossOrigin, media, nonce,
    489                      /* aFetchPriority */ fetchPriority, integrity,
    490                      referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD,
    491                      false, false, true);
    492                }
    493              }
    494            }
    495          }
    496        } else if (nsGkAtoms::video == aName) {
    497          nsHtml5String url =
    498              aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
    499          if (url) {
    500            // Fetch priority is not supported for video. Nullptr will map to
    501            // the auto state
    502            // (https://html.spec.whatwg.org/#fetch-priority-attribute).
    503            auto fetchPriority = nullptr;
    504 
    505            mSpeculativeLoadQueue.AppendElement()->InitImage(
    506                url, nullptr, nullptr, nullptr, nullptr, nullptr, false,
    507                fetchPriority, nullptr);
    508          }
    509        } else if (nsGkAtoms::style == aName) {
    510          mImportScanner.Start();
    511          nsHtml5TreeOperation* treeOp =
    512              mOpQueue.AppendElement(mozilla::fallible);
    513          if (MOZ_UNLIKELY(!treeOp)) {
    514            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
    515                NS_ERROR_OUT_OF_MEMORY);
    516            return nullptr;
    517          }
    518          opSetStyleLineNumber operation(content, tokenizer->getLineNumber());
    519          treeOp->Init(mozilla::AsVariant(operation));
    520        } else if (nsGkAtoms::html == aName) {
    521          nsHtml5String url =
    522              aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
    523          mSpeculativeLoadQueue.AppendElement()->InitManifest(url);
    524        } else if (nsGkAtoms::base == aName) {
    525          nsHtml5String url =
    526              aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
    527          if (url) {
    528            mSpeculativeLoadQueue.AppendElement()->InitBase(url);
    529          }
    530        } else if (nsGkAtoms::meta == aName) {
    531          if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
    532                  "content-security-policy",
    533                  aAttributes->getValue(
    534                      nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
    535            nsHtml5String csp =
    536                aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
    537            if (csp) {
    538              mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(csp);
    539            }
    540          } else if (nsHtml5Portability::
    541                         lowerCaseLiteralEqualsIgnoreAsciiCaseString(
    542                             "referrer",
    543                             aAttributes->getValue(
    544                                 nsHtml5AttributeName::ATTR_NAME))) {
    545            nsHtml5String referrerPolicy =
    546                aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
    547            if (referrerPolicy) {
    548              mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy(
    549                  referrerPolicy);
    550            }
    551          }
    552        }
    553        break;
    554      case kNameSpaceID_SVG:
    555        if (nsGkAtoms::image == aName || nsGkAtoms::feImage == aName) {
    556          nsHtml5String url =
    557              aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
    558          if (!url) {
    559            url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
    560          }
    561          if (url) {
    562            nsHtml5String crossOrigin =
    563                aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
    564            nsHtml5String fetchPriority =
    565                aAttributes->getValue(nsHtml5AttributeName::ATTR_FETCHPRIORITY);
    566 
    567            mSpeculativeLoadQueue.AppendElement()->InitImage(
    568                url, crossOrigin, /* aMedia = */ nullptr, nullptr, nullptr,
    569                nullptr, false, fetchPriority, nullptr);
    570          }
    571        } else if (nsGkAtoms::script == aName) {
    572          nsHtml5TreeOperation* treeOp =
    573              mOpQueue.AppendElement(mozilla::fallible);
    574          if (MOZ_UNLIKELY(!treeOp)) {
    575            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
    576                NS_ERROR_OUT_OF_MEMORY);
    577            return nullptr;
    578          }
    579          opSetScriptLineAndColumnNumberAndFreeze operation(
    580              content, tokenizer->getLineNumber(),
    581              // NOTE: tokenizer->getColumnNumber() points '>'.
    582              tokenizer->getColumnNumber() + 1);
    583          treeOp->Init(mozilla::AsVariant(operation));
    584 
    585          nsHtml5String type =
    586              aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
    587          nsAutoString typeString;
    588          getTypeString(type, typeString);
    589 
    590          bool isModule = typeString.LowerCaseEqualsASCII("module");
    591          bool importmap = typeString.LowerCaseEqualsASCII("importmap");
    592          bool async = false;
    593          bool defer = false;
    594 
    595          if (importmap) {
    596            // If we see an importmap, we don't want to later start speculative
    597            // loads for modulepreloads, since such load might finish before
    598            // the importmap is created. This also applies to module scripts so
    599            // that any modulepreload integrity checks can be performed before
    600            // the modules scripts are loaded.
    601            // This state is not part of speculation rollback: If an importmap
    602            // is seen speculatively and the speculation is rolled back, the
    603            // importmap is still considered seen.
    604            // TODO: Sync importmap seenness between the main thread and the
    605            // parser thread.
    606            // https://bugzilla.mozilla.org/show_bug.cgi?id=1848312
    607            mHasSeenImportMap = true;
    608          }
    609          nsHtml5String url =
    610              aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
    611          if (!url) {
    612            url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
    613          }
    614          if (url) {
    615            async = aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC);
    616            defer = aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER);
    617            if ((isModule && !mHasSeenImportMap) || (!isModule && !importmap)) {
    618              nsHtml5String type =
    619                  aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
    620              nsHtml5String crossOrigin =
    621                  aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
    622              nsHtml5String nonce =
    623                  aAttributes->getValue(nsHtml5AttributeName::ATTR_NONCE);
    624              nsHtml5String integrity =
    625                  aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
    626              nsHtml5String referrerPolicy = aAttributes->getValue(
    627                  nsHtml5AttributeName::ATTR_REFERRERPOLICY);
    628              nsHtml5String fetchPriority = aAttributes->getValue(
    629                  nsHtml5AttributeName::ATTR_FETCHPRIORITY);
    630 
    631              mSpeculativeLoadQueue.AppendElement()->InitScript(
    632                  url, nullptr, type, crossOrigin, /* aMedia = */ nullptr,
    633                  nonce, fetchPriority, integrity, referrerPolicy,
    634                  mode == nsHtml5TreeBuilder::IN_HEAD, async, defer, false);
    635            }
    636          }
    637          // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` MUST be computed to
    638          // match the ScriptLoader-perceived kind of the script regardless of
    639          // enqueuing a speculative load. Either the attribute prevents a
    640          // classic script execution or is ignored on a module script.
    641          mCurrentHtmlScriptCannotDocumentWriteOrBlock =
    642              isModule || importmap || async || defer;
    643        } else if (nsGkAtoms::style == aName) {
    644          mImportScanner.Start();
    645          nsHtml5TreeOperation* treeOp =
    646              mOpQueue.AppendElement(mozilla::fallible);
    647          if (MOZ_UNLIKELY(!treeOp)) {
    648            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
    649                NS_ERROR_OUT_OF_MEMORY);
    650            return nullptr;
    651          }
    652          opSetStyleLineNumber operation(content, tokenizer->getLineNumber());
    653          treeOp->Init(mozilla::AsVariant(operation));
    654        }
    655        break;
    656    }
    657  } else if (aNamespace != kNameSpaceID_MathML) {
    658    // No speculative loader--just line numbers and defer/async check
    659    if (nsGkAtoms::style == aName) {
    660      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
    661      if (MOZ_UNLIKELY(!treeOp)) {
    662        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
    663        return nullptr;
    664      }
    665      opSetStyleLineNumber operation(content, tokenizer->getLineNumber());
    666      treeOp->Init(mozilla::AsVariant(operation));
    667    } else if (nsGkAtoms::script == aName) {
    668      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
    669      if (MOZ_UNLIKELY(!treeOp)) {
    670        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
    671        return nullptr;
    672      }
    673      opSetScriptLineAndColumnNumberAndFreeze operation(
    674          content, tokenizer->getLineNumber(),
    675          // NOTE: tokenizer->getColumnNumber() points '>'.
    676          tokenizer->getColumnNumber() + 1);
    677      treeOp->Init(mozilla::AsVariant(operation));
    678      if (aNamespace == kNameSpaceID_XHTML) {
    679        // Although we come here in cases where the value of
    680        // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` doesn't actually
    681        // matter, we also come here when parsing document.written content on
    682        // the main thread. In that case, IT MATTERS that
    683        // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` is set correctly,
    684        // so let's just always set it correctly even if it a bit of wasted work
    685        // in the scenarios where no scripts execute and it doesn't matter.
    686        //
    687        // See the comments around generating speculative loads for HTML scripts
    688        // elements for the details of when
    689        // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` needs to be set to
    690        // `true` and when to `false`.
    691 
    692        nsHtml5String type =
    693            aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
    694        nsAutoString typeString;
    695        getTypeString(type, typeString);
    696 
    697        mCurrentHtmlScriptCannotDocumentWriteOrBlock =
    698            typeString.LowerCaseEqualsASCII("module") ||
    699            typeString.LowerCaseEqualsASCII("nomodule") ||
    700            typeString.LowerCaseEqualsASCII("importmap");
    701 
    702        if (!mCurrentHtmlScriptCannotDocumentWriteOrBlock &&
    703            aAttributes->contains(nsHtml5AttributeName::ATTR_SRC)) {
    704          mCurrentHtmlScriptCannotDocumentWriteOrBlock =
    705              (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
    706               aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER));
    707        }
    708      }
    709    } else if (aNamespace == kNameSpaceID_XHTML) {
    710      if (nsGkAtoms::html == aName) {
    711        nsHtml5String url =
    712            aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
    713        nsHtml5TreeOperation* treeOp =
    714            mOpQueue.AppendElement(mozilla::fallible);
    715        if (MOZ_UNLIKELY(!treeOp)) {
    716          MarkAsBrokenAndRequestSuspensionWithoutBuilder(
    717              NS_ERROR_OUT_OF_MEMORY);
    718          return nullptr;
    719        }
    720        if (url) {
    721          nsString
    722              urlString;  // Not Auto, because using it to hold nsStringBuffer*
    723          url.ToString(urlString);
    724          opProcessOfflineManifest operation(ToNewUnicode(urlString));
    725          treeOp->Init(mozilla::AsVariant(operation));
    726        } else {
    727          opProcessOfflineManifest operation(ToNewUnicode(u""_ns));
    728          treeOp->Init(mozilla::AsVariant(operation));
    729        }
    730      } else if (nsGkAtoms::base == aName && mViewSource) {
    731        nsHtml5String url =
    732            aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
    733        if (url) {
    734          mViewSource->AddBase(url);
    735        }
    736      }
    737    }
    738  }
    739 
    740  // End wall of code for speculative loading
    741 
    742  return content;
    743 }
    744 
    745 nsIContentHandle* nsHtml5TreeBuilder::createElement(
    746    int32_t aNamespace, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes,
    747    nsIContentHandle* aFormElement, nsIContentHandle* aIntendedParent,
    748    nsHtml5ContentCreatorFunction aCreator) {
    749  nsIContentHandle* content =
    750      createElement(aNamespace, aName, aAttributes, aIntendedParent, aCreator);
    751  if (aFormElement) {
    752    if (mBuilder) {
    753      nsHtml5TreeOperation::SetFormElement(
    754          static_cast<nsIContent*>(content),
    755          static_cast<nsIContent*>(aFormElement),
    756          static_cast<nsIContent*>(aIntendedParent));
    757    } else {
    758      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
    759      if (MOZ_UNLIKELY(!treeOp)) {
    760        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
    761        return nullptr;
    762      }
    763      opSetFormElement operation(content, aFormElement, aIntendedParent);
    764      treeOp->Init(mozilla::AsVariant(operation));
    765    }
    766  }
    767  return content;
    768 }
    769 
    770 nsIContentHandle* nsHtml5TreeBuilder::createHtmlElementSetAsRoot(
    771    nsHtml5HtmlAttributes* aAttributes) {
    772  nsHtml5ContentCreatorFunction creator;
    773  // <html> uses NS_NewHTMLSharedElement creator
    774  creator.html = NS_NewHTMLSharedElement;
    775  nsIContentHandle* content = createElement(kNameSpaceID_XHTML, nsGkAtoms::html,
    776                                            aAttributes, nullptr, creator);
    777  if (mBuilder) {
    778    nsresult rv = nsHtml5TreeOperation::AppendToDocument(
    779        static_cast<nsIContent*>(content), mBuilder);
    780    if (NS_FAILED(rv)) {
    781      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
    782    }
    783  } else {
    784    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
    785    if (MOZ_UNLIKELY(!treeOp)) {
    786      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
    787      return nullptr;
    788    }
    789    opAppendToDocument operation(content);
    790    treeOp->Init(mozilla::AsVariant(operation));
    791  }
    792  return content;
    793 }
    794 
    795 nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
    796    int32_t aNamespace, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes,
    797    nsIContentHandle* aFormElement, nsIContentHandle* aTable,
    798    nsIContentHandle* aStackParent, nsHtml5ContentCreatorFunction aCreator) {
    799  MOZ_ASSERT(aTable, "Null table");
    800  MOZ_ASSERT(aStackParent, "Null stack parent");
    801 
    802  if (mBuilder) {
    803    // Get the foster parent to use as the intended parent when creating
    804    // the child element.
    805    nsIContent* fosterParent = nsHtml5TreeOperation::GetFosterParent(
    806        static_cast<nsIContent*>(aTable),
    807        static_cast<nsIContent*>(aStackParent));
    808 
    809    nsIContentHandle* child = createElement(
    810        aNamespace, aName, aAttributes, aFormElement, fosterParent, aCreator);
    811 
    812    insertFosterParentedChild(child, aTable, aStackParent);
    813 
    814    return child;
    815  }
    816 
    817  // Tree op to get the foster parent that we use as the intended parent
    818  // when creating the child element.
    819  nsHtml5TreeOperation* fosterParentTreeOp = mOpQueue.AppendElement();
    820  NS_ASSERTION(fosterParentTreeOp, "Tree op allocation failed.");
    821  nsIContentHandle* fosterParentHandle = AllocateContentHandle();
    822  opGetFosterParent operation(aTable, aStackParent, fosterParentHandle);
    823  fosterParentTreeOp->Init(mozilla::AsVariant(operation));
    824 
    825  // Create the element with the correct intended parent.
    826  nsIContentHandle* child =
    827      createElement(aNamespace, aName, aAttributes, aFormElement,
    828                    fosterParentHandle, aCreator);
    829 
    830  // Insert the child into the foster parent.
    831  insertFosterParentedChild(child, aTable, aStackParent);
    832 
    833  return child;
    834 }
    835 
    836 void nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement) {
    837  MOZ_ASSERT(aElement, "Null element");
    838 
    839  if (mBuilder) {
    840    nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement), mBuilder);
    841    return;
    842  }
    843 
    844  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
    845  if (MOZ_UNLIKELY(!treeOp)) {
    846    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
    847    return;
    848  }
    849  opDetach operation(aElement);
    850  treeOp->Init(mozilla::AsVariant(operation));
    851 }
    852 
    853 void nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild,
    854                                       nsIContentHandle* aParent) {
    855  MOZ_ASSERT(aChild, "Null child");
    856  MOZ_ASSERT(aParent, "Null parent");
    857 
    858  if (mBuilder) {
    859    nsresult rv = nsHtml5TreeOperation::Append(
    860        static_cast<nsIContent*>(aChild), static_cast<nsIContent*>(aParent),
    861        mozilla::dom::FROM_PARSER_FRAGMENT, mBuilder);
    862    if (NS_FAILED(rv)) {
    863      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
    864    }
    865    return;
    866  }
    867 
    868  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
    869  if (MOZ_UNLIKELY(!treeOp)) {
    870    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
    871    return;
    872  }
    873 
    874  opAppend operation(aChild, aParent,
    875                     (!!mSpeculativeLoadStage)
    876                         ? mozilla::dom::FROM_PARSER_NETWORK
    877                         : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE);
    878  treeOp->Init(mozilla::AsVariant(operation));
    879 }
    880 
    881 void nsHtml5TreeBuilder::appendChildrenToNewParent(
    882    nsIContentHandle* aOldParent, nsIContentHandle* aNewParent) {
    883  MOZ_ASSERT(aOldParent, "Null old parent");
    884  MOZ_ASSERT(aNewParent, "Null new parent");
    885 
    886  if (mBuilder) {
    887    nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent(
    888        static_cast<nsIContent*>(aOldParent),
    889        static_cast<nsIContent*>(aNewParent), mBuilder);
    890    if (NS_FAILED(rv)) {
    891      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
    892    }
    893    return;
    894  }
    895 
    896  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
    897  if (MOZ_UNLIKELY(!treeOp)) {
    898    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
    899    return;
    900  }
    901  opAppendChildrenToNewParent operation(aOldParent, aNewParent);
    902  treeOp->Init(mozilla::AsVariant(operation));
    903 }
    904 
    905 void nsHtml5TreeBuilder::insertFosterParentedCharacters(
    906    char16_t* aBuffer, int32_t aStart, int32_t aLength,
    907    nsIContentHandle* aTable, nsIContentHandle* aStackParent) {
    908  MOZ_ASSERT(aBuffer, "Null buffer");
    909  MOZ_ASSERT(aTable, "Null table");
    910  MOZ_ASSERT(aStackParent, "Null stack parent");
    911  MOZ_ASSERT(!aStart, "aStart must always be zero.");
    912 
    913  if (mBuilder) {
    914    nsresult rv = nsHtml5TreeOperation::FosterParentText(
    915        static_cast<nsIContent*>(aStackParent),
    916        aBuffer,  // XXX aStart always ignored???
    917        aLength, static_cast<nsIContent*>(aTable), mBuilder);
    918    if (NS_FAILED(rv)) {
    919      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
    920    }
    921    return;
    922  }
    923 
    924  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
    925  if (!bufferCopy) {
    926    // Just assigning mBroken instead of generating tree op. The caller
    927    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
    928    mBroken = NS_ERROR_OUT_OF_MEMORY;
    929    requestSuspension();
    930    return;
    931  }
    932 
    933  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
    934 
    935  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
    936  if (MOZ_UNLIKELY(!treeOp)) {
    937    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
    938    return;
    939  }
    940  opFosterParentText operation(aStackParent, bufferCopy.release(), aTable,
    941                               aLength);
    942  treeOp->Init(mozilla::AsVariant(operation));
    943 }
    944 
    945 void nsHtml5TreeBuilder::insertFosterParentedChild(
    946    nsIContentHandle* aChild, nsIContentHandle* aTable,
    947    nsIContentHandle* aStackParent) {
    948  MOZ_ASSERT(aChild, "Null child");
    949  MOZ_ASSERT(aTable, "Null table");
    950  MOZ_ASSERT(aStackParent, "Null stack parent");
    951 
    952  if (mBuilder) {
    953    nsresult rv = nsHtml5TreeOperation::FosterParent(
    954        static_cast<nsIContent*>(aChild),
    955        static_cast<nsIContent*>(aStackParent),
    956        static_cast<nsIContent*>(aTable), mBuilder);
    957    if (NS_FAILED(rv)) {
    958      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
    959    }
    960    return;
    961  }
    962 
    963  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
    964  if (MOZ_UNLIKELY(!treeOp)) {
    965    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
    966    return;
    967  }
    968  opFosterParent operation(aChild, aStackParent, aTable);
    969  treeOp->Init(mozilla::AsVariant(operation));
    970 }
    971 
    972 void nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent,
    973                                          char16_t* aBuffer, int32_t aStart,
    974                                          int32_t aLength) {
    975  MOZ_ASSERT(aBuffer, "Null buffer");
    976  MOZ_ASSERT(aParent, "Null parent");
    977  MOZ_ASSERT(!aStart, "aStart must always be zero.");
    978 
    979  if (mBuilder) {
    980    nsresult rv = nsHtml5TreeOperation::AppendText(
    981        aBuffer,  // XXX aStart always ignored???
    982        aLength, static_cast<nsIContent*>(aParent), mBuilder);
    983    if (NS_FAILED(rv)) {
    984      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
    985    }
    986    return;
    987  }
    988 
    989  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
    990  if (!bufferCopy) {
    991    // Just assigning mBroken instead of generating tree op. The caller
    992    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
    993    mBroken = NS_ERROR_OUT_OF_MEMORY;
    994    requestSuspension();
    995    return;
    996  }
    997 
    998  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
    999 
   1000  if (mImportScanner.ShouldScan()) {
   1001    nsTArray<nsString> imports =
   1002        mImportScanner.Scan(mozilla::Span(aBuffer, aLength));
   1003    for (nsString& url : imports) {
   1004      mSpeculativeLoadQueue.AppendElement()->InitImportStyle(std::move(url));
   1005    }
   1006  }
   1007 
   1008  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1009  if (MOZ_UNLIKELY(!treeOp)) {
   1010    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1011    return;
   1012  }
   1013  opAppendText operation(aParent, bufferCopy.release(), aLength);
   1014  treeOp->Init(mozilla::AsVariant(operation));
   1015 }
   1016 
   1017 void nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent,
   1018                                       char16_t* aBuffer, int32_t aStart,
   1019                                       int32_t aLength) {
   1020  MOZ_ASSERT(aBuffer, "Null buffer");
   1021  MOZ_ASSERT(aParent, "Null parent");
   1022  MOZ_ASSERT(!aStart, "aStart must always be zero.");
   1023 
   1024  if (mBuilder) {
   1025    nsresult rv = nsHtml5TreeOperation::AppendComment(
   1026        static_cast<nsIContent*>(aParent),
   1027        aBuffer,  // XXX aStart always ignored???
   1028        aLength, mBuilder);
   1029    if (NS_FAILED(rv)) {
   1030      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
   1031    }
   1032    return;
   1033  }
   1034 
   1035  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
   1036  if (!bufferCopy) {
   1037    // Just assigning mBroken instead of generating tree op. The caller
   1038    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
   1039    mBroken = NS_ERROR_OUT_OF_MEMORY;
   1040    requestSuspension();
   1041    return;
   1042  }
   1043 
   1044  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
   1045 
   1046  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1047  if (MOZ_UNLIKELY(!treeOp)) {
   1048    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1049    return;
   1050  }
   1051  opAppendComment operation(aParent, bufferCopy.release(), aLength);
   1052  treeOp->Init(mozilla::AsVariant(operation));
   1053 }
   1054 
   1055 void nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer,
   1056                                                 int32_t aStart,
   1057                                                 int32_t aLength) {
   1058  MOZ_ASSERT(aBuffer, "Null buffer");
   1059  MOZ_ASSERT(!aStart, "aStart must always be zero.");
   1060 
   1061  if (mBuilder) {
   1062    nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument(
   1063        aBuffer,  // XXX aStart always ignored???
   1064        aLength, mBuilder);
   1065    if (NS_FAILED(rv)) {
   1066      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
   1067    }
   1068    return;
   1069  }
   1070 
   1071  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
   1072  if (!bufferCopy) {
   1073    // Just assigning mBroken instead of generating tree op. The caller
   1074    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
   1075    mBroken = NS_ERROR_OUT_OF_MEMORY;
   1076    requestSuspension();
   1077    return;
   1078  }
   1079 
   1080  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
   1081 
   1082  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1083  if (MOZ_UNLIKELY(!treeOp)) {
   1084    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1085    return;
   1086  }
   1087  opAppendCommentToDocument data(bufferCopy.release(), aLength);
   1088  treeOp->Init(mozilla::AsVariant(data));
   1089 }
   1090 
   1091 void nsHtml5TreeBuilder::addAttributesToElement(
   1092    nsIContentHandle* aElement, nsHtml5HtmlAttributes* aAttributes) {
   1093  MOZ_ASSERT(aElement, "Null element");
   1094  MOZ_ASSERT(aAttributes, "Null attributes");
   1095 
   1096  if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
   1097    return;
   1098  }
   1099 
   1100  if (mBuilder) {
   1101    MOZ_ASSERT(
   1102        aAttributes == tokenizer->GetAttributes(),
   1103        "Using attribute other than the tokenizer's to add to body or html.");
   1104    nsresult rv = nsHtml5TreeOperation::AddAttributes(
   1105        static_cast<nsIContent*>(aElement), aAttributes, mBuilder);
   1106    if (NS_FAILED(rv)) {
   1107      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
   1108    }
   1109    return;
   1110  }
   1111 
   1112  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1113  if (MOZ_UNLIKELY(!treeOp)) {
   1114    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1115    return;
   1116  }
   1117  opAddAttributes opeation(aElement, aAttributes);
   1118  treeOp->Init(mozilla::AsVariant(opeation));
   1119 }
   1120 
   1121 void nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement) {
   1122  MOZ_ASSERT(aElement, "Null element");
   1123 
   1124  if (mBuilder) {
   1125    nsHtml5TreeOperation::MarkMalformedIfScript(
   1126        static_cast<nsIContent*>(aElement));
   1127    return;
   1128  }
   1129 
   1130  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1131  if (MOZ_UNLIKELY(!treeOp)) {
   1132    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1133    return;
   1134  }
   1135  opMarkMalformedIfScript operation(aElement);
   1136  treeOp->Init(mozilla::AsVariant(operation));
   1137 }
   1138 
   1139 void nsHtml5TreeBuilder::start(bool fragment) {
   1140  mCurrentHtmlScriptCannotDocumentWriteOrBlock = false;
   1141  mozilla::glean::parsing::svg_unusual_pcdata.AddToDenominator(1);
   1142 
   1143 #ifdef DEBUG
   1144  mActive = true;
   1145 #endif
   1146 }
   1147 
   1148 void nsHtml5TreeBuilder::end() {
   1149  mOpQueue.Clear();
   1150 #ifdef DEBUG
   1151  mActive = false;
   1152 #endif
   1153 }
   1154 
   1155 void nsHtml5TreeBuilder::appendDoctypeToDocument(nsAtom* aName,
   1156                                                 nsHtml5String aPublicId,
   1157                                                 nsHtml5String aSystemId) {
   1158  MOZ_ASSERT(aName, "Null name");
   1159  nsString publicId;  // Not Auto, because using it to hold nsStringBuffer*
   1160  nsString systemId;  // Not Auto, because using it to hold nsStringBuffer*
   1161  aPublicId.ToString(publicId);
   1162  aSystemId.ToString(systemId);
   1163  if (mBuilder) {
   1164    nsresult rv = nsHtml5TreeOperation::AppendDoctypeToDocument(
   1165        aName, publicId, systemId, mBuilder);
   1166    if (NS_FAILED(rv)) {
   1167      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
   1168    }
   1169    return;
   1170  }
   1171 
   1172  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1173  if (MOZ_UNLIKELY(!treeOp)) {
   1174    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1175    return;
   1176  }
   1177  opAppendDoctypeToDocument operation(aName, publicId, systemId);
   1178  treeOp->Init(mozilla::AsVariant(operation));
   1179  // nsXMLContentSink can flush here, but what's the point?
   1180  // It can also interrupt here, but we can't.
   1181 }
   1182 
   1183 void nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsAtom* aName,
   1184                                       nsIContentHandle* aElement) {
   1185  NS_ASSERTION(aNamespace == kNameSpaceID_XHTML ||
   1186                   aNamespace == kNameSpaceID_SVG ||
   1187                   aNamespace == kNameSpaceID_MathML,
   1188               "Element isn't HTML, SVG or MathML!");
   1189  NS_ASSERTION(aName, "Element doesn't have local name!");
   1190  NS_ASSERTION(aElement, "No element!");
   1191  /*
   1192   * The frame constructor uses recursive algorithms, so it can't deal with
   1193   * arbitrarily deep trees. This is especially a problem on Windows where
   1194   * the permitted depth of the runtime stack is rather small.
   1195   *
   1196   * The following is a protection against author incompetence--not against
   1197   * malice. There are other ways to make the DOM deep anyway.
   1198   *
   1199   * The basic idea is that when the tree builder stack gets too deep,
   1200   * append operations no longer append to the node that the HTML parsing
   1201   * algorithm says they should but instead text nodes are append to the last
   1202   * element that was seen before a magic tree builder stack threshold was
   1203   * reached and element and comment nodes aren't appended to the DOM at all.
   1204   *
   1205   * However, for security reasons, non-child descendant text nodes inside an
   1206   * SVG script or style element should not become children. Also, non-cell
   1207   * table elements shouldn't be used as surrogate parents for user experience
   1208   * reasons.
   1209   */
   1210 
   1211  if (MOZ_UNLIKELY(isInSVGOddPCData)) {
   1212    // We are seeing an element that has children, which could not have child
   1213    // elements in HTML, i.e., is parsed as PCDATA in SVG but CDATA in HTML.
   1214    mozilla::glean::parsing::svg_unusual_pcdata.AddToNumerator(1);
   1215  }
   1216  if (MOZ_UNLIKELY(aNamespace == kNameSpaceID_SVG)) {
   1217    if ((aName == nsGkAtoms::style) || (aName == nsGkAtoms::xmp) ||
   1218        (aName == nsGkAtoms::iframe) || (aName == nsGkAtoms::noembed) ||
   1219        (aName == nsGkAtoms::noframes) || (aName == nsGkAtoms::noscript) ||
   1220        (aName == nsGkAtoms::script)) {
   1221      isInSVGOddPCData++;
   1222    }
   1223  }
   1224 
   1225  if (aNamespace != kNameSpaceID_XHTML) {
   1226    return;
   1227  }
   1228  if (aName == nsGkAtoms::body || aName == nsGkAtoms::frameset) {
   1229    if (mBuilder) {
   1230      // InnerHTML and DOMParser shouldn't start layout anyway
   1231      return;
   1232    }
   1233    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1234    if (MOZ_UNLIKELY(!treeOp)) {
   1235      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1236      return;
   1237    }
   1238    treeOp->Init(mozilla::AsVariant(opStartLayout()));
   1239    return;
   1240  }
   1241  if (nsIContent::RequiresDoneCreatingElement(kNameSpaceID_XHTML, aName)) {
   1242    if (mBuilder) {
   1243      nsHtml5TreeOperation::DoneCreatingElement(
   1244          static_cast<nsIContent*>(aElement));
   1245    } else {
   1246      opDoneCreatingElement operation(aElement);
   1247      mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation));
   1248    }
   1249    return;
   1250  }
   1251  if (mGenerateSpeculativeLoads && aName == nsGkAtoms::picture) {
   1252    // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
   1253    mSpeculativeLoadQueue.AppendElement()->InitOpenPicture();
   1254    return;
   1255  }
   1256  if (aName == nsGkAtoms::_template) {
   1257    if (tokenizer->TemplatePushedOrHeadPopped()) {
   1258      requestSuspension();
   1259    }
   1260  }
   1261 }
   1262 
   1263 void nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsAtom* aName,
   1264                                       nsIContentHandle* aElement) {
   1265  NS_ASSERTION(aNamespace == kNameSpaceID_XHTML ||
   1266                   aNamespace == kNameSpaceID_SVG ||
   1267                   aNamespace == kNameSpaceID_MathML,
   1268               "Element isn't HTML, SVG or MathML!");
   1269  NS_ASSERTION(aName, "Element doesn't have local name!");
   1270  NS_ASSERTION(aElement, "No element!");
   1271  if (aNamespace == kNameSpaceID_MathML) {
   1272    return;
   1273  }
   1274  if (MOZ_UNLIKELY(aNamespace == kNameSpaceID_SVG)) {
   1275    if ((aName == nsGkAtoms::style) || (aName == nsGkAtoms::xmp) ||
   1276        (aName == nsGkAtoms::iframe) || (aName == nsGkAtoms::noembed) ||
   1277        (aName == nsGkAtoms::noframes) || (aName == nsGkAtoms::noscript) ||
   1278        (aName == nsGkAtoms::script)) {
   1279      isInSVGOddPCData--;
   1280    }
   1281  }
   1282  // we now have only SVG and HTML
   1283  if (aName == nsGkAtoms::script) {
   1284    if (mPreventScriptExecution) {
   1285      if (mBuilder) {
   1286        nsHtml5TreeOperation::PreventScriptExecution(
   1287            static_cast<nsIContent*>(aElement));
   1288        return;
   1289      }
   1290      opPreventScriptExecution operation(aElement);
   1291      mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation));
   1292      return;
   1293    }
   1294    if (mBuilder) {
   1295      return;
   1296    }
   1297 
   1298    // https://html.spec.whatwg.org/#parsing-main-incdata
   1299    // An end tag whose tag name is "script"
   1300    //  - If the active speculative HTML parser is null and the JavaScript
   1301    // execution context stack is empty, then perform a microtask checkpoint.
   1302    nsHtml5TreeOperation* treeOpMicrotask =
   1303        mOpQueue.AppendElement(mozilla::fallible);
   1304    if (MOZ_UNLIKELY(!treeOpMicrotask)) {
   1305      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1306      return;
   1307    }
   1308    treeOpMicrotask->Init(mozilla::AsVariant(opMicrotaskCheckpoint()));
   1309 
   1310    if (mCurrentHtmlScriptCannotDocumentWriteOrBlock) {
   1311      NS_ASSERTION(
   1312          aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG,
   1313          "Only HTML and SVG scripts may be async/defer.");
   1314      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1315      if (MOZ_UNLIKELY(!treeOp)) {
   1316        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1317        return;
   1318      }
   1319      opRunScriptThatCannotDocumentWriteOrBlock operation(aElement);
   1320      treeOp->Init(mozilla::AsVariant(operation));
   1321      mCurrentHtmlScriptCannotDocumentWriteOrBlock = false;
   1322      return;
   1323    }
   1324    requestSuspension();
   1325    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1326    if (MOZ_UNLIKELY(!treeOp)) {
   1327      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1328      return;
   1329    }
   1330    opRunScriptThatMayDocumentWriteOrBlock operation(aElement, nullptr);
   1331    treeOp->Init(mozilla::AsVariant(operation));
   1332    return;
   1333  }
   1334  // Some nodes need DoneAddingChildren() called to initialize
   1335  // properly (e.g. form state restoration).
   1336  if (nsIContent::RequiresDoneAddingChildren(aNamespace, aName)) {
   1337    if (mBuilder) {
   1338      nsHtml5TreeOperation::DoneAddingChildren(
   1339          static_cast<nsIContent*>(aElement));
   1340      return;
   1341    }
   1342    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1343    if (MOZ_UNLIKELY(!treeOp)) {
   1344      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1345      return;
   1346    }
   1347    opDoneAddingChildren operation(aElement);
   1348    treeOp->Init(mozilla::AsVariant(operation));
   1349    if (aNamespace == kNameSpaceID_XHTML && aName == nsGkAtoms::head) {
   1350      if (tokenizer->TemplatePushedOrHeadPopped()) {
   1351        requestSuspension();
   1352      }
   1353    }
   1354    return;
   1355  }
   1356  if (aName == nsGkAtoms::style ||
   1357      (aNamespace == kNameSpaceID_XHTML && aName == nsGkAtoms::link)) {
   1358    if (mBuilder) {
   1359      MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
   1360                 "Scripts must be blocked.");
   1361      mBuilder->UpdateStyleSheet(static_cast<nsIContent*>(aElement));
   1362      return;
   1363    }
   1364 
   1365    if (aName == nsGkAtoms::style) {
   1366      nsTArray<nsString> imports = mImportScanner.Stop();
   1367      for (nsString& url : imports) {
   1368        mSpeculativeLoadQueue.AppendElement()->InitImportStyle(std::move(url));
   1369      }
   1370    }
   1371 
   1372    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1373    if (MOZ_UNLIKELY(!treeOp)) {
   1374      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1375      return;
   1376    }
   1377    opUpdateStyleSheet operation(aElement);
   1378    treeOp->Init(mozilla::AsVariant(operation));
   1379    return;
   1380  }
   1381  if (aNamespace == kNameSpaceID_SVG) {
   1382    if (aName == nsGkAtoms::svg) {
   1383      if (!scriptingEnabled || mPreventScriptExecution) {
   1384        return;
   1385      }
   1386      if (mBuilder) {
   1387        nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement));
   1388        return;
   1389      }
   1390      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1391      if (MOZ_UNLIKELY(!treeOp)) {
   1392        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1393        return;
   1394      }
   1395      opSvgLoad operation(aElement);
   1396      treeOp->Init(mozilla::AsVariant(operation));
   1397    }
   1398    return;
   1399  }
   1400 
   1401  if (mGenerateSpeculativeLoads && aName == nsGkAtoms::picture) {
   1402    // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
   1403    mSpeculativeLoadQueue.AppendElement()->InitEndPicture();
   1404    return;
   1405  }
   1406 }
   1407 
   1408 void nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf,
   1409                                              int32_t aStart, int32_t aLength) {
   1410  MOZ_RELEASE_ASSERT(charBufferLen + aLength <= charBuffer.length,
   1411                     "About to memcpy past the end of the buffer!");
   1412  memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength);
   1413  charBufferLen += aLength;
   1414 }
   1415 
   1416 // INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits
   1417 // is 2^30. Note that this is counting char16_t units. The underlying
   1418 // bytes will be twice that, but they fit even in 32-bit size_t even
   1419 // if a contiguous chunk of memory of that size is pretty unlikely to
   1420 // be available on a 32-bit system.
   1421 #define MAX_POWER_OF_TWO_IN_INT32 0x40000000
   1422 
   1423 bool nsHtml5TreeBuilder::EnsureBufferSpace(int32_t aLength) {
   1424  // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer
   1425  // so that this method becomes unnecessary.
   1426  mozilla::CheckedInt<int32_t> worstCase(charBufferLen);
   1427  worstCase += aLength;
   1428  if (!worstCase.isValid()) {
   1429    return false;
   1430  }
   1431  if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) {
   1432    return false;
   1433  }
   1434  if (!charBuffer) {
   1435    if (worstCase.value() < MAX_POWER_OF_TWO_IN_INT32) {
   1436      // Add one to round to the next power of two to avoid immediate
   1437      // reallocation once there are a few characters in the buffer.
   1438      worstCase += 1;
   1439    }
   1440    charBuffer = jArray<char16_t, int32_t>::newFallibleJArray(
   1441        mozilla::RoundUpPow2(worstCase.value()));
   1442    if (!charBuffer) {
   1443      return false;
   1444    }
   1445  } else if (worstCase.value() > charBuffer.length) {
   1446    jArray<char16_t, int32_t> newBuf =
   1447        jArray<char16_t, int32_t>::newFallibleJArray(
   1448            mozilla::RoundUpPow2(worstCase.value()));
   1449    if (!newBuf) {
   1450      return false;
   1451    }
   1452    memcpy(newBuf, charBuffer, sizeof(char16_t) * size_t(charBufferLen));
   1453    charBuffer = newBuf;
   1454  }
   1455  return true;
   1456 }
   1457 
   1458 nsIContentHandle* nsHtml5TreeBuilder::AllocateContentHandle() {
   1459  if (MOZ_UNLIKELY(mBuilder)) {
   1460    MOZ_ASSERT_UNREACHABLE("Must never allocate a handle with builder.");
   1461    return nullptr;
   1462  }
   1463  if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) {
   1464    mOldHandles.AppendElement(std::move(mHandles));
   1465    mHandles = mozilla::MakeUnique<nsIContent*[]>(
   1466        NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH);
   1467    mHandlesUsed = 0;
   1468  }
   1469 #ifdef DEBUG
   1470  mHandles[mHandlesUsed] = reinterpret_cast<nsIContent*>(uintptr_t(0xC0DEDBAD));
   1471 #endif
   1472  return &mHandles[mHandlesUsed++];
   1473 }
   1474 
   1475 bool nsHtml5TreeBuilder::HasScriptThatMayDocumentWriteOrBlock() {
   1476  uint32_t len = mOpQueue.Length();
   1477  if (!len) {
   1478    return false;
   1479  }
   1480  return mOpQueue.ElementAt(len - 1).IsRunScriptThatMayDocumentWriteOrBlock();
   1481 }
   1482 
   1483 mozilla::Result<bool, nsresult> nsHtml5TreeBuilder::Flush(bool aDiscretionary) {
   1484  if (MOZ_UNLIKELY(mBuilder)) {
   1485    MOZ_ASSERT_UNREACHABLE("Must never flush with builder.");
   1486    return false;
   1487  }
   1488  if (NS_SUCCEEDED(mBroken)) {
   1489    if (!aDiscretionary || !(charBufferLen && currentPtr >= 0 &&
   1490                             stack[currentPtr]->isFosterParenting())) {
   1491      // Don't flush text on discretionary flushes if the current element on
   1492      // the stack is a foster-parenting element and there's pending text,
   1493      // because flushing in that case would make the tree shape dependent on
   1494      // where the flush points fall.
   1495      flushCharacters();
   1496    }
   1497    FlushLoads();
   1498  }
   1499  if (mOpSink) {
   1500    bool hasOps = !mOpQueue.IsEmpty();
   1501    if (hasOps) {
   1502      // If the builder is broken and mOpQueue is not empty, there must be
   1503      // one op and it must be eTreeOpMarkAsBroken.
   1504      if (NS_FAILED(mBroken)) {
   1505        MOZ_ASSERT(mOpQueue.Length() == 1,
   1506                   "Tree builder is broken with a non-empty op queue whose "
   1507                   "length isn't 1.");
   1508        MOZ_ASSERT(mOpQueue[0].IsMarkAsBroken(),
   1509                   "Tree builder is broken but the op in queue is not marked "
   1510                   "as broken.");
   1511      }
   1512      if (!mOpSink->MoveOpsFrom(mOpQueue)) {
   1513        return mozilla::Err(NS_ERROR_OUT_OF_MEMORY);
   1514      }
   1515    }
   1516    return hasOps;
   1517  }
   1518  // no op sink: throw away ops
   1519  mOpQueue.Clear();
   1520  return false;
   1521 }
   1522 
   1523 void nsHtml5TreeBuilder::FlushLoads() {
   1524  if (MOZ_UNLIKELY(mBuilder)) {
   1525    MOZ_ASSERT_UNREACHABLE("Must never flush loads with builder.");
   1526    return;
   1527  }
   1528  if (!mSpeculativeLoadQueue.IsEmpty()) {
   1529    mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue);
   1530  }
   1531 }
   1532 
   1533 void nsHtml5TreeBuilder::SetDocumentCharset(NotNull<const Encoding*> aEncoding,
   1534                                            nsCharsetSource aCharsetSource,
   1535                                            bool aCommitEncodingSpeculation) {
   1536  MOZ_ASSERT(!mBuilder, "How did we call this with builder?");
   1537  MOZ_ASSERT(mSpeculativeLoadStage,
   1538             "How did we call this without a speculative load stage?");
   1539  mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset(
   1540      aEncoding, aCharsetSource, aCommitEncodingSpeculation);
   1541 }
   1542 
   1543 void nsHtml5TreeBuilder::UpdateCharsetSource(nsCharsetSource aCharsetSource) {
   1544  MOZ_ASSERT(!mBuilder, "How did we call this with builder?");
   1545  MOZ_ASSERT(mSpeculativeLoadStage,
   1546             "How did we call this without a speculative load stage (even "
   1547             "though we don't need it right here)?");
   1548  if (mViewSource) {
   1549    mViewSource->UpdateCharsetSource(aCharsetSource);
   1550    return;
   1551  }
   1552  opUpdateCharsetSource operation(aCharsetSource);
   1553  mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation));
   1554 }
   1555 
   1556 void nsHtml5TreeBuilder::StreamEnded() {
   1557  MOZ_ASSERT(!mBuilder, "Must not call StreamEnded with builder.");
   1558  MOZ_ASSERT(!fragment, "Must not parse fragments off the main thread.");
   1559  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1560  if (MOZ_UNLIKELY(!treeOp)) {
   1561    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1562    return;
   1563  }
   1564  treeOp->Init(mozilla::AsVariant(opStreamEnded()));
   1565 }
   1566 
   1567 void nsHtml5TreeBuilder::NeedsCharsetSwitchTo(
   1568    NotNull<const Encoding*> aEncoding, int32_t aCharsetSource,
   1569    int32_t aLineNumber) {
   1570  if (MOZ_UNLIKELY(mBuilder)) {
   1571    MOZ_ASSERT_UNREACHABLE("Must never switch charset with builder.");
   1572    return;
   1573  }
   1574  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1575  if (MOZ_UNLIKELY(!treeOp)) {
   1576    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1577    return;
   1578  }
   1579  opCharsetSwitchTo opeation(aEncoding, aCharsetSource, aLineNumber);
   1580  treeOp->Init(mozilla::AsVariant(opeation));
   1581 }
   1582 
   1583 void nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId,
   1584                                                   bool aError,
   1585                                                   int32_t aLineNumber) {
   1586  if (MOZ_UNLIKELY(mBuilder)) {
   1587    MOZ_ASSERT_UNREACHABLE("Must never complain about charset with builder.");
   1588    return;
   1589  }
   1590 
   1591  if (mSpeculativeLoadStage) {
   1592    mSpeculativeLoadQueue.AppendElement()->InitMaybeComplainAboutCharset(
   1593        aMsgId, aError, aLineNumber);
   1594  } else {
   1595    opMaybeComplainAboutCharset opeartion(const_cast<char*>(aMsgId), aError,
   1596                                          aLineNumber);
   1597    mOpQueue.AppendElement()->Init(mozilla::AsVariant(opeartion));
   1598  }
   1599 }
   1600 
   1601 void nsHtml5TreeBuilder::TryToEnableEncodingMenu() {
   1602  if (MOZ_UNLIKELY(mBuilder)) {
   1603    MOZ_ASSERT_UNREACHABLE("Must never disable encoding menu with builder.");
   1604    return;
   1605  }
   1606  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   1607  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   1608  treeOp->Init(mozilla::AsVariant(opEnableEncodingMenu()));
   1609 }
   1610 
   1611 void nsHtml5TreeBuilder::AddSnapshotToScript(
   1612    nsAHtml5TreeBuilderState* aSnapshot, int32_t aLine) {
   1613  if (MOZ_UNLIKELY(mBuilder)) {
   1614    MOZ_ASSERT_UNREACHABLE("Must never use snapshots with builder.");
   1615    return;
   1616  }
   1617  MOZ_ASSERT(HasScriptThatMayDocumentWriteOrBlock(),
   1618             "No script to add a snapshot to!");
   1619  MOZ_ASSERT(aSnapshot, "Got null snapshot.");
   1620  mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine);
   1621 }
   1622 
   1623 void nsHtml5TreeBuilder::DropHandles() {
   1624  MOZ_ASSERT(!mBuilder, "Must not drop handles with builder.");
   1625  mOldHandles.Clear();
   1626  mHandlesUsed = 0;
   1627 }
   1628 
   1629 void nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv) {
   1630  if (MOZ_UNLIKELY(mBuilder)) {
   1631    MOZ_ASSERT_UNREACHABLE("Must not call this with builder.");
   1632    return;
   1633  }
   1634  mBroken = aRv;
   1635  mOpQueue.Clear();  // Previous ops don't matter anymore
   1636  opMarkAsBroken operation(aRv);
   1637  mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation));
   1638 }
   1639 
   1640 void nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv) {
   1641  if (mBuilder) {
   1642    MarkAsBrokenAndRequestSuspensionWithBuilder(aRv);
   1643    return;
   1644  }
   1645  mBroken = aRv;
   1646  requestSuspension();
   1647 }
   1648 
   1649 void nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle) {
   1650  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
   1651 
   1652  startTag(nsHtml5ElementName::ELT_META,
   1653           nsHtml5ViewSourceUtils::NewMetaViewportAttributes(), false);
   1654 
   1655  startTag(nsHtml5ElementName::ELT_TITLE,
   1656           nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, false);
   1657 
   1658  // XUL will add the "Source of: " prefix.
   1659  uint32_t length = aTitle.Length();
   1660  if (length > INT32_MAX) {
   1661    length = INT32_MAX;
   1662  }
   1663  characters(aTitle.get(), 0, (int32_t)length);
   1664  endTag(nsHtml5ElementName::ELT_TITLE);
   1665 
   1666  startTag(nsHtml5ElementName::ELT_LINK,
   1667           nsHtml5ViewSourceUtils::NewLinkAttributes(), false);
   1668 
   1669  startTag(nsHtml5ElementName::ELT_BODY,
   1670           nsHtml5ViewSourceUtils::NewBodyAttributes(), false);
   1671 
   1672  StartPlainTextBody();
   1673 }
   1674 
   1675 void nsHtml5TreeBuilder::StartPlainText() {
   1676  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
   1677  setForceNoQuirks(true);
   1678  startTag(nsHtml5ElementName::ELT_LINK,
   1679           nsHtml5PlainTextUtils::NewLinkAttributes(), false);
   1680 
   1681  startTag(nsHtml5ElementName::ELT_BODY,
   1682           nsHtml5PlainTextUtils::NewBodyAttributes(), false);
   1683 
   1684  StartPlainTextBody();
   1685 }
   1686 
   1687 void nsHtml5TreeBuilder::StartPlainTextBody() {
   1688  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
   1689  startTag(nsHtml5ElementName::ELT_PRE, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
   1690           false);
   1691  needToDropLF = false;
   1692 }
   1693 
   1694 // DocumentModeHandler
   1695 void nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m) {
   1696  if (mBuilder) {
   1697    mBuilder->SetDocumentMode(m);
   1698    return;
   1699  }
   1700  if (mSpeculativeLoadStage) {
   1701    mSpeculativeLoadQueue.AppendElement()->InitSetDocumentMode(m);
   1702    return;
   1703  }
   1704  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1705  if (MOZ_UNLIKELY(!treeOp)) {
   1706    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1707    return;
   1708  }
   1709  treeOp->Init(mozilla::AsVariant(m));
   1710 }
   1711 
   1712 nsIContentHandle* nsHtml5TreeBuilder::getDocumentFragmentForTemplate(
   1713    nsIContentHandle* aTemplate) {
   1714  if (mBuilder) {
   1715    return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(
   1716        static_cast<nsIContent*>(aTemplate));
   1717  }
   1718  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1719  if (MOZ_UNLIKELY(!treeOp)) {
   1720    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1721    return nullptr;
   1722  }
   1723  nsIContentHandle* fragHandle = AllocateContentHandle();
   1724  opGetDocumentFragmentForTemplate operation(aTemplate, fragHandle);
   1725  treeOp->Init(mozilla::AsVariant(operation));
   1726  return fragHandle;
   1727 }
   1728 
   1729 void nsHtml5TreeBuilder::setDocumentFragmentForTemplate(
   1730    nsIContentHandle* aTemplate, nsIContentHandle* aFragment) {
   1731  if (mBuilder) {
   1732    nsHtml5TreeOperation::SetDocumentFragmentForTemplate(
   1733        static_cast<nsIContent*>(aTemplate),
   1734        static_cast<nsIContent*>(aFragment));
   1735    return;
   1736  }
   1737 
   1738  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1739  if (MOZ_UNLIKELY(!treeOp)) {
   1740    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1741    return;
   1742  }
   1743  opSetDocumentFragmentForTemplate operation(aTemplate, aFragment);
   1744  treeOp->Init(mozilla::AsVariant(operation));
   1745 }
   1746 
   1747 nsIContentHandle* nsHtml5TreeBuilder::getShadowRootFromHost(
   1748    nsIContentHandle* aHost, nsIContentHandle* aTemplateNode,
   1749    nsHtml5String aShadowRootMode, bool aShadowRootIsClonable,
   1750    bool aShadowRootIsSerializable, bool aShadowRootDelegatesFocus,
   1751    nsHtml5String aShadowRootReferenceTarget) {
   1752  mozilla::dom::ShadowRootMode mode;
   1753  if (aShadowRootMode.LowerCaseEqualsASCII("open")) {
   1754    mode = mozilla::dom::ShadowRootMode::Open;
   1755  } else if (aShadowRootMode.LowerCaseEqualsASCII("closed")) {
   1756    mode = mozilla::dom::ShadowRootMode::Closed;
   1757  } else {
   1758    return nullptr;
   1759  }
   1760 
   1761  nsString shadowRootReferenceTarget;
   1762  aShadowRootReferenceTarget.ToString(shadowRootReferenceTarget);
   1763 
   1764  if (mBuilder) {
   1765    nsIContent* root = nsContentUtils::AttachDeclarativeShadowRoot(
   1766        static_cast<nsIContent*>(aHost), mode, aShadowRootIsClonable,
   1767        aShadowRootIsSerializable, aShadowRootDelegatesFocus,
   1768        shadowRootReferenceTarget);
   1769    if (!root) {
   1770      nsContentUtils::LogSimpleConsoleError(
   1771          u"Failed to attach Declarative Shadow DOM."_ns, "DOM"_ns,
   1772          mBuilder->GetDocument()->IsInPrivateBrowsing(),
   1773          mBuilder->GetDocument()->IsInChromeDocShell());
   1774    }
   1775    return root;
   1776  }
   1777 
   1778  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
   1779  if (MOZ_UNLIKELY(!treeOp)) {
   1780    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
   1781    return nullptr;
   1782  }
   1783  nsIContentHandle* fragHandle = AllocateContentHandle();
   1784  opGetShadowRootFromHost operation(
   1785      aHost, fragHandle, aTemplateNode, mode, aShadowRootIsClonable,
   1786      aShadowRootIsSerializable, aShadowRootDelegatesFocus,
   1787      shadowRootReferenceTarget);
   1788  treeOp->Init(mozilla::AsVariant(operation));
   1789  return fragHandle;
   1790 }
   1791 
   1792 nsIContentHandle* nsHtml5TreeBuilder::getFormPointerForContext(
   1793    nsIContentHandle* aContext) {
   1794  MOZ_ASSERT(mBuilder, "Must have builder.");
   1795  if (!aContext) {
   1796    return nullptr;
   1797  }
   1798 
   1799  MOZ_ASSERT(NS_IsMainThread());
   1800 
   1801  // aContext must always be an element that already exists
   1802  // in the document.
   1803  nsIContent* contextNode = static_cast<nsIContent*>(aContext);
   1804  nsIContent* currentAncestor = contextNode;
   1805 
   1806  // We traverse the ancestors of the context node to find the nearest
   1807  // form pointer. This traversal is why aContext must not be an emtpy handle.
   1808  nsIContent* nearestForm = nullptr;
   1809  while (currentAncestor) {
   1810    if (currentAncestor->IsHTMLElement(nsGkAtoms::form)) {
   1811      nearestForm = currentAncestor;
   1812      break;
   1813    }
   1814    currentAncestor = currentAncestor->GetParent();
   1815  }
   1816 
   1817  if (!nearestForm) {
   1818    return nullptr;
   1819  }
   1820 
   1821  return nearestForm;
   1822 }
   1823 
   1824 // Error reporting
   1825 
   1826 void nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter) {
   1827  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
   1828  mViewSource = aHighlighter;
   1829 }
   1830 
   1831 void nsHtml5TreeBuilder::errDeepTree() {
   1832  if (MOZ_UNLIKELY(mViewSource)) {
   1833    mViewSource->AddErrorToCurrentRun("errDeepTree");
   1834  } else if (!mBuilder) {
   1835    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   1836    MOZ_ASSERT(treeOp, "Tree op allocation failed.");
   1837    opMaybeComplainAboutDeepTree operation(tokenizer->getLineNumber());
   1838    treeOp->Init(mozilla::AsVariant(operation));
   1839  }
   1840 }
   1841 
   1842 void nsHtml5TreeBuilder::errStrayStartTag(nsAtom* aName) {
   1843  if (MOZ_UNLIKELY(mViewSource)) {
   1844    mViewSource->AddErrorToCurrentRun("errStrayStartTag2", aName);
   1845  }
   1846 }
   1847 
   1848 void nsHtml5TreeBuilder::errStrayEndTag(nsAtom* aName) {
   1849  if (MOZ_UNLIKELY(mViewSource)) {
   1850    mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName);
   1851  }
   1852 }
   1853 
   1854 void nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex, nsAtom* aName) {
   1855  if (MOZ_UNLIKELY(mViewSource)) {
   1856    mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName);
   1857  }
   1858 }
   1859 
   1860 void nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex,
   1861                                                    nsAtom* aName) {
   1862  if (MOZ_UNLIKELY(mViewSource)) {
   1863    mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied", aName);
   1864  }
   1865 }
   1866 
   1867 void nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex) {
   1868  if (MOZ_UNLIKELY(mViewSource)) {
   1869    mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell");
   1870  }
   1871 }
   1872 
   1873 void nsHtml5TreeBuilder::errStrayDoctype() {
   1874  if (MOZ_UNLIKELY(mViewSource)) {
   1875    mViewSource->AddErrorToCurrentRun("errStrayDoctype");
   1876  }
   1877 }
   1878 
   1879 void nsHtml5TreeBuilder::errAlmostStandardsDoctype() {
   1880  if (MOZ_UNLIKELY(mViewSource) && !forceNoQuirks) {
   1881    mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype");
   1882  }
   1883 }
   1884 
   1885 void nsHtml5TreeBuilder::errQuirkyDoctype() {
   1886  if (MOZ_UNLIKELY(mViewSource) && !forceNoQuirks) {
   1887    mViewSource->AddErrorToCurrentRun("errQuirkyDoctype");
   1888  }
   1889 }
   1890 
   1891 void nsHtml5TreeBuilder::errNonSpaceInTrailer() {
   1892  if (MOZ_UNLIKELY(mViewSource)) {
   1893    mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer");
   1894  }
   1895 }
   1896 
   1897 void nsHtml5TreeBuilder::errNonSpaceAfterFrameset() {
   1898  if (MOZ_UNLIKELY(mViewSource)) {
   1899    mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset");
   1900  }
   1901 }
   1902 
   1903 void nsHtml5TreeBuilder::errNonSpaceInFrameset() {
   1904  if (MOZ_UNLIKELY(mViewSource)) {
   1905    mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset");
   1906  }
   1907 }
   1908 
   1909 void nsHtml5TreeBuilder::errNonSpaceAfterBody() {
   1910  if (MOZ_UNLIKELY(mViewSource)) {
   1911    mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody");
   1912  }
   1913 }
   1914 
   1915 void nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment() {
   1916  if (MOZ_UNLIKELY(mViewSource)) {
   1917    mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment");
   1918  }
   1919 }
   1920 
   1921 void nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead() {
   1922  if (MOZ_UNLIKELY(mViewSource)) {
   1923    mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead");
   1924  }
   1925 }
   1926 
   1927 void nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsAtom* aName) {
   1928  if (MOZ_UNLIKELY(mViewSource)) {
   1929    mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName);
   1930  }
   1931 }
   1932 
   1933 void nsHtml5TreeBuilder::errStartTagWithoutDoctype() {
   1934  if (MOZ_UNLIKELY(mViewSource) && !forceNoQuirks) {
   1935    mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype");
   1936  }
   1937 }
   1938 
   1939 void nsHtml5TreeBuilder::errNoSelectInTableScope() {
   1940  if (MOZ_UNLIKELY(mViewSource)) {
   1941    mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope");
   1942  }
   1943 }
   1944 
   1945 void nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected() {
   1946  if (MOZ_UNLIKELY(mViewSource)) {
   1947    mViewSource->AddErrorToCurrentRun("errStartSelectWhereEndSelectExpected");
   1948  }
   1949 }
   1950 
   1951 void nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsAtom* aName) {
   1952  if (MOZ_UNLIKELY(mViewSource)) {
   1953    mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName);
   1954  }
   1955 }
   1956 
   1957 void nsHtml5TreeBuilder::errBadStartTagInNoscriptInHead(nsAtom* aName) {
   1958  if (MOZ_UNLIKELY(mViewSource)) {
   1959    mViewSource->AddErrorToCurrentRun("errBadStartTagInNoscriptInHead", aName);
   1960  }
   1961 }
   1962 
   1963 void nsHtml5TreeBuilder::errImage() {
   1964  if (MOZ_UNLIKELY(mViewSource)) {
   1965    mViewSource->AddErrorToCurrentRun("errImage");
   1966  }
   1967 }
   1968 
   1969 void nsHtml5TreeBuilder::errIsindex() {
   1970  if (MOZ_UNLIKELY(mViewSource)) {
   1971    mViewSource->AddErrorToCurrentRun("errIsindex");
   1972  }
   1973 }
   1974 
   1975 void nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsAtom* aName) {
   1976  if (MOZ_UNLIKELY(mViewSource)) {
   1977    mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen2", aName);
   1978  }
   1979 }
   1980 
   1981 void nsHtml5TreeBuilder::errHeadingWhenHeadingOpen() {
   1982  if (MOZ_UNLIKELY(mViewSource)) {
   1983    mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen");
   1984  }
   1985 }
   1986 
   1987 void nsHtml5TreeBuilder::errFramesetStart() {
   1988  if (MOZ_UNLIKELY(mViewSource)) {
   1989    mViewSource->AddErrorToCurrentRun("errFramesetStart");
   1990  }
   1991 }
   1992 
   1993 void nsHtml5TreeBuilder::errNoCellToClose() {
   1994  if (MOZ_UNLIKELY(mViewSource)) {
   1995    mViewSource->AddErrorToCurrentRun("errNoCellToClose");
   1996  }
   1997 }
   1998 
   1999 void nsHtml5TreeBuilder::errStartTagInTable(nsAtom* aName) {
   2000  if (MOZ_UNLIKELY(mViewSource)) {
   2001    mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName);
   2002  }
   2003 }
   2004 
   2005 void nsHtml5TreeBuilder::errFormWhenFormOpen() {
   2006  if (MOZ_UNLIKELY(mViewSource)) {
   2007    mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen");
   2008  }
   2009 }
   2010 
   2011 void nsHtml5TreeBuilder::errTableSeenWhileTableOpen() {
   2012  if (MOZ_UNLIKELY(mViewSource)) {
   2013    mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen");
   2014  }
   2015 }
   2016 
   2017 void nsHtml5TreeBuilder::errStartTagInTableBody(nsAtom* aName) {
   2018  if (MOZ_UNLIKELY(mViewSource)) {
   2019    mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName);
   2020  }
   2021 }
   2022 
   2023 void nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype() {
   2024  if (MOZ_UNLIKELY(mViewSource) && !forceNoQuirks) {
   2025    mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype");
   2026  }
   2027 }
   2028 
   2029 void nsHtml5TreeBuilder::errEndTagAfterBody() {
   2030  if (MOZ_UNLIKELY(mViewSource)) {
   2031    mViewSource->AddErrorToCurrentRun("errEndTagAfterBody");
   2032  }
   2033 }
   2034 
   2035 void nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsAtom* aName) {
   2036  if (MOZ_UNLIKELY(mViewSource)) {
   2037    mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen", aName);
   2038  }
   2039 }
   2040 
   2041 void nsHtml5TreeBuilder::errGarbageInColgroup() {
   2042  if (MOZ_UNLIKELY(mViewSource)) {
   2043    mViewSource->AddErrorToCurrentRun("errGarbageInColgroup");
   2044  }
   2045 }
   2046 
   2047 void nsHtml5TreeBuilder::errEndTagBr() {
   2048  if (MOZ_UNLIKELY(mViewSource)) {
   2049    mViewSource->AddErrorToCurrentRun("errEndTagBr");
   2050  }
   2051 }
   2052 
   2053 void nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsAtom* aName) {
   2054  if (MOZ_UNLIKELY(mViewSource)) {
   2055    mViewSource->AddErrorToCurrentRun("errNoElementToCloseButEndTagSeen",
   2056                                      aName);
   2057  }
   2058 }
   2059 
   2060 void nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsAtom* aName) {
   2061  if (MOZ_UNLIKELY(mViewSource)) {
   2062    mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext", aName);
   2063  }
   2064 }
   2065 
   2066 void nsHtml5TreeBuilder::errNoTableRowToClose() {
   2067  if (MOZ_UNLIKELY(mViewSource)) {
   2068    mViewSource->AddErrorToCurrentRun("errNoTableRowToClose");
   2069  }
   2070 }
   2071 
   2072 void nsHtml5TreeBuilder::errNonSpaceInTable() {
   2073  if (MOZ_UNLIKELY(mViewSource)) {
   2074    mViewSource->AddErrorToCurrentRun("errNonSpaceInTable");
   2075  }
   2076 }
   2077 
   2078 void nsHtml5TreeBuilder::errUnclosedChildrenInRuby() {
   2079  if (MOZ_UNLIKELY(mViewSource)) {
   2080    mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby");
   2081  }
   2082 }
   2083 
   2084 void nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsAtom* aName) {
   2085  if (MOZ_UNLIKELY(mViewSource)) {
   2086    mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby", aName);
   2087  }
   2088 }
   2089 
   2090 void nsHtml5TreeBuilder::errSelfClosing() {
   2091  if (MOZ_UNLIKELY(mViewSource)) {
   2092    mViewSource->AddErrorToCurrentSlash("errSelfClosing");
   2093  }
   2094 }
   2095 
   2096 void nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack() {
   2097  if (MOZ_UNLIKELY(mViewSource)) {
   2098    mViewSource->AddErrorToCurrentRun("errNoCheckUnclosedElementsOnStack");
   2099  }
   2100 }
   2101 
   2102 void nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(
   2103    nsAtom* aName, nsAtom* aOther) {
   2104  if (MOZ_UNLIKELY(mViewSource)) {
   2105    mViewSource->AddErrorToCurrentRun("errEndTagDidNotMatchCurrentOpenElement",
   2106                                      aName, aOther);
   2107  }
   2108 }
   2109 
   2110 void nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsAtom* aName) {
   2111  if (MOZ_UNLIKELY(mViewSource)) {
   2112    mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName);
   2113  }
   2114 }
   2115 
   2116 void nsHtml5TreeBuilder::errEndWithUnclosedElements(nsAtom* aName) {
   2117  if (MOZ_UNLIKELY(mViewSource)) {
   2118    mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName);
   2119  }
   2120 }
   2121 
   2122 void nsHtml5TreeBuilder::errListUnclosedStartTags(int32_t aIgnored) {
   2123  if (MOZ_UNLIKELY(mViewSource)) {
   2124    mViewSource->AddErrorToCurrentRun("errListUnclosedStartTags");
   2125  }
   2126 }