forked from mirrors/gecko-dev
		
	Looks like some users use it, and it's not too much effort to support. This is somewhat simpler, and IMO better than what existed before bug 1514655 because: * It doesn't regress bidi rendering when the pref is disabled (before, the pref would prevent plaintext.css from applying altogether). * It's consistent with the way view-source docs work. * It doesn't use non-standard stylesheet APIs to toggle the stylesheet (bug 1260720). Differential Revision: https://phabricator.services.mozilla.com/D37742 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			1659 lines
		
	
	
	
		
			57 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1659 lines
		
	
	
	
		
			57 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set ts=2 sw=2 et tw=78: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "nsError.h"
 | 
						|
#include "nsNodeUtils.h"
 | 
						|
#include "mozilla/CheckedInt.h"
 | 
						|
#include "mozilla/Likely.h"
 | 
						|
#include "mozilla/UniquePtr.h"
 | 
						|
 | 
						|
nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder)
 | 
						|
    : mode(0),
 | 
						|
      originalMode(0),
 | 
						|
      framesetOk(false),
 | 
						|
      tokenizer(nullptr),
 | 
						|
      scriptingEnabled(false),
 | 
						|
      needToDropLF(false),
 | 
						|
      fragment(false),
 | 
						|
      contextName(nullptr),
 | 
						|
      contextNamespace(kNameSpaceID_None),
 | 
						|
      contextNode(nullptr),
 | 
						|
      templateModePtr(0),
 | 
						|
      stackNodesIdx(0),
 | 
						|
      numStackNodes(0),
 | 
						|
      currentPtr(0),
 | 
						|
      listPtr(0),
 | 
						|
      formPointer(nullptr),
 | 
						|
      headPointer(nullptr),
 | 
						|
      charBufferLen(0),
 | 
						|
      quirks(false),
 | 
						|
      isSrcdocDocument(false),
 | 
						|
      mBuilder(aBuilder),
 | 
						|
      mViewSource(nullptr),
 | 
						|
      mOpSink(nullptr),
 | 
						|
      mHandles(nullptr),
 | 
						|
      mHandlesUsed(0),
 | 
						|
      mSpeculativeLoadStage(nullptr),
 | 
						|
      mBroken(NS_OK),
 | 
						|
      mCurrentHtmlScriptIsAsyncOrDefer(false),
 | 
						|
      mPreventScriptExecution(false)
 | 
						|
#ifdef DEBUG
 | 
						|
      ,
 | 
						|
      mActive(false)
 | 
						|
#endif
 | 
						|
{
 | 
						|
  MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
 | 
						|
}
 | 
						|
 | 
						|
nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
 | 
						|
                                       nsHtml5TreeOpStage* aStage)
 | 
						|
    : mode(0),
 | 
						|
      originalMode(0),
 | 
						|
      framesetOk(false),
 | 
						|
      tokenizer(nullptr),
 | 
						|
      scriptingEnabled(false),
 | 
						|
      needToDropLF(false),
 | 
						|
      fragment(false),
 | 
						|
      contextName(nullptr),
 | 
						|
      contextNamespace(kNameSpaceID_None),
 | 
						|
      contextNode(nullptr),
 | 
						|
      templateModePtr(0),
 | 
						|
      stackNodesIdx(0),
 | 
						|
      numStackNodes(0),
 | 
						|
      currentPtr(0),
 | 
						|
      listPtr(0),
 | 
						|
      formPointer(nullptr),
 | 
						|
      headPointer(nullptr),
 | 
						|
      charBufferLen(0),
 | 
						|
      quirks(false),
 | 
						|
      isSrcdocDocument(false),
 | 
						|
      mBuilder(nullptr),
 | 
						|
      mViewSource(nullptr),
 | 
						|
      mOpSink(aOpSink),
 | 
						|
      mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH]),
 | 
						|
      mHandlesUsed(0),
 | 
						|
      mSpeculativeLoadStage(aStage),
 | 
						|
      mBroken(NS_OK),
 | 
						|
      mCurrentHtmlScriptIsAsyncOrDefer(false),
 | 
						|
      mPreventScriptExecution(false)
 | 
						|
#ifdef DEBUG
 | 
						|
      ,
 | 
						|
      mActive(false)
 | 
						|
#endif
 | 
						|
{
 | 
						|
  MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
 | 
						|
}
 | 
						|
 | 
						|
nsHtml5TreeBuilder::~nsHtml5TreeBuilder() {
 | 
						|
  MOZ_COUNT_DTOR(nsHtml5TreeBuilder);
 | 
						|
  NS_ASSERTION(!mActive,
 | 
						|
               "nsHtml5TreeBuilder deleted without ever calling end() on it!");
 | 
						|
  mOpQueue.Clear();
 | 
						|
}
 | 
						|
 | 
						|
nsIContentHandle* nsHtml5TreeBuilder::createElement(
 | 
						|
    int32_t aNamespace, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes,
 | 
						|
    nsIContentHandle* aIntendedParent, nsHtml5ContentCreatorFunction aCreator) {
 | 
						|
  MOZ_ASSERT(aAttributes, "Got null attributes.");
 | 
						|
  MOZ_ASSERT(aName, "Got null name.");
 | 
						|
  MOZ_ASSERT(aNamespace == kNameSpaceID_XHTML ||
 | 
						|
                 aNamespace == kNameSpaceID_SVG ||
 | 
						|
                 aNamespace == kNameSpaceID_MathML,
 | 
						|
             "Bogus namespace.");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    nsIContent* intendedParent =
 | 
						|
        aIntendedParent ? static_cast<nsIContent*>(aIntendedParent) : nullptr;
 | 
						|
 | 
						|
    // intendedParent == nullptr is a special case where the
 | 
						|
    // intended parent is the document.
 | 
						|
    nsNodeInfoManager* nodeInfoManager =
 | 
						|
        intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
 | 
						|
                       : mBuilder->GetNodeInfoManager();
 | 
						|
 | 
						|
    nsIContent* elem;
 | 
						|
    if (aNamespace == kNameSpaceID_XHTML) {
 | 
						|
      elem = nsHtml5TreeOperation::CreateHTMLElement(
 | 
						|
          aName, aAttributes, mozilla::dom::FROM_PARSER_FRAGMENT,
 | 
						|
          nodeInfoManager, mBuilder, aCreator.html);
 | 
						|
    } else if (aNamespace == kNameSpaceID_SVG) {
 | 
						|
      elem = nsHtml5TreeOperation::CreateSVGElement(
 | 
						|
          aName, aAttributes, mozilla::dom::FROM_PARSER_FRAGMENT,
 | 
						|
          nodeInfoManager, mBuilder, aCreator.svg);
 | 
						|
    } else {
 | 
						|
      MOZ_ASSERT(aNamespace == kNameSpaceID_MathML);
 | 
						|
      elem = nsHtml5TreeOperation::CreateMathMLElement(
 | 
						|
          aName, aAttributes, nodeInfoManager, mBuilder);
 | 
						|
    }
 | 
						|
    if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() &&
 | 
						|
                     aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) {
 | 
						|
      delete aAttributes;
 | 
						|
    }
 | 
						|
    return elem;
 | 
						|
  }
 | 
						|
 | 
						|
  nsIContentHandle* content = AllocateContentHandle();
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  treeOp->Init(aNamespace, aName, aAttributes, content, aIntendedParent,
 | 
						|
               !!mSpeculativeLoadStage, aCreator);
 | 
						|
  // mSpeculativeLoadStage is non-null only in the off-the-main-thread
 | 
						|
  // tree builder, which handles the network stream
 | 
						|
 | 
						|
  // Start wall of code for speculative loading and line numbers
 | 
						|
 | 
						|
  if (mSpeculativeLoadStage) {
 | 
						|
    switch (aNamespace) {
 | 
						|
      case kNameSpaceID_XHTML:
 | 
						|
        if (nsGkAtoms::img == aName) {
 | 
						|
          nsHtml5String url =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
 | 
						|
          nsHtml5String srcset =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
 | 
						|
          nsHtml5String crossOrigin =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
 | 
						|
          nsHtml5String referrerPolicy =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY);
 | 
						|
          nsHtml5String sizes =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
 | 
						|
          mSpeculativeLoadQueue.AppendElement()->InitImage(
 | 
						|
              url, crossOrigin, referrerPolicy, srcset, sizes);
 | 
						|
        } else if (nsGkAtoms::source == aName) {
 | 
						|
          nsHtml5String srcset =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
 | 
						|
          // Sources without srcset cannot be selected. The source could also be
 | 
						|
          // for a media element, but in that context doesn't use srcset.  See
 | 
						|
          // comments in nsHtml5SpeculativeLoad.h about <picture> preloading
 | 
						|
          if (srcset) {
 | 
						|
            nsHtml5String sizes =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
 | 
						|
            nsHtml5String type =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
 | 
						|
            nsHtml5String media =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA);
 | 
						|
            mSpeculativeLoadQueue.AppendElement()->InitPictureSource(
 | 
						|
                srcset, sizes, type, media);
 | 
						|
          }
 | 
						|
        } else if (nsGkAtoms::script == aName) {
 | 
						|
          nsHtml5TreeOperation* treeOp =
 | 
						|
              mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
          if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
 | 
						|
                NS_ERROR_OUT_OF_MEMORY);
 | 
						|
            return nullptr;
 | 
						|
          }
 | 
						|
          treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content,
 | 
						|
                       tokenizer->getLineNumber());
 | 
						|
 | 
						|
          nsHtml5String url =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
 | 
						|
          if (url) {
 | 
						|
            nsHtml5String charset =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
 | 
						|
            nsHtml5String type =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
 | 
						|
            nsHtml5String crossOrigin =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
 | 
						|
            nsHtml5String integrity =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
 | 
						|
            nsHtml5String referrerPolicy = aAttributes->getValue(
 | 
						|
                nsHtml5AttributeName::ATTR_REFERRERPOLICY);
 | 
						|
            bool async =
 | 
						|
                aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC);
 | 
						|
            bool defer =
 | 
						|
                aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER);
 | 
						|
            bool noModule =
 | 
						|
                aAttributes->contains(nsHtml5AttributeName::ATTR_NOMODULE);
 | 
						|
            mSpeculativeLoadQueue.AppendElement()->InitScript(
 | 
						|
                url, charset, type, crossOrigin, integrity, referrerPolicy,
 | 
						|
                mode == nsHtml5TreeBuilder::IN_HEAD, async, defer, noModule);
 | 
						|
            mCurrentHtmlScriptIsAsyncOrDefer = async || defer;
 | 
						|
          }
 | 
						|
        } else if (nsGkAtoms::link == aName) {
 | 
						|
          nsHtml5String rel =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_REL);
 | 
						|
          // Not splitting on space here is bogus but the old parser didn't even
 | 
						|
          // do a case-insensitive check.
 | 
						|
          if (rel) {
 | 
						|
            if (rel.LowerCaseEqualsASCII("stylesheet")) {
 | 
						|
              nsHtml5String url =
 | 
						|
                  aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
 | 
						|
              if (url) {
 | 
						|
                nsHtml5String charset =
 | 
						|
                    aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
 | 
						|
                nsHtml5String crossOrigin = aAttributes->getValue(
 | 
						|
                    nsHtml5AttributeName::ATTR_CROSSORIGIN);
 | 
						|
                nsHtml5String integrity =
 | 
						|
                    aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
 | 
						|
                nsHtml5String referrerPolicy = aAttributes->getValue(
 | 
						|
                    nsHtml5AttributeName::ATTR_REFERRERPOLICY);
 | 
						|
                mSpeculativeLoadQueue.AppendElement()->InitStyle(
 | 
						|
                    url, charset, crossOrigin, referrerPolicy, integrity);
 | 
						|
              }
 | 
						|
            } else if (rel.LowerCaseEqualsASCII("preconnect")) {
 | 
						|
              nsHtml5String url =
 | 
						|
                  aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
 | 
						|
              if (url) {
 | 
						|
                nsHtml5String crossOrigin = aAttributes->getValue(
 | 
						|
                    nsHtml5AttributeName::ATTR_CROSSORIGIN);
 | 
						|
                mSpeculativeLoadQueue.AppendElement()->InitPreconnect(
 | 
						|
                    url, crossOrigin);
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
        } else if (nsGkAtoms::video == aName) {
 | 
						|
          nsHtml5String url =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
 | 
						|
          if (url) {
 | 
						|
            mSpeculativeLoadQueue.AppendElement()->InitImage(
 | 
						|
                url, nullptr, nullptr, nullptr, nullptr);
 | 
						|
          }
 | 
						|
        } else if (nsGkAtoms::style == aName) {
 | 
						|
          nsHtml5TreeOperation* treeOp =
 | 
						|
              mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
          if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
 | 
						|
                NS_ERROR_OUT_OF_MEMORY);
 | 
						|
            return nullptr;
 | 
						|
          }
 | 
						|
          treeOp->Init(eTreeOpSetStyleLineNumber, content,
 | 
						|
                       tokenizer->getLineNumber());
 | 
						|
        } else if (nsGkAtoms::html == aName) {
 | 
						|
          nsHtml5String url =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
 | 
						|
          mSpeculativeLoadQueue.AppendElement()->InitManifest(url);
 | 
						|
        } else if (nsGkAtoms::base == aName) {
 | 
						|
          nsHtml5String url =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
 | 
						|
          if (url) {
 | 
						|
            mSpeculativeLoadQueue.AppendElement()->InitBase(url);
 | 
						|
          }
 | 
						|
        } else if (nsGkAtoms::meta == aName) {
 | 
						|
          if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
 | 
						|
                  "content-security-policy",
 | 
						|
                  aAttributes->getValue(
 | 
						|
                      nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
 | 
						|
            nsHtml5String csp =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
 | 
						|
            if (csp) {
 | 
						|
              mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(csp);
 | 
						|
            }
 | 
						|
          } else if (nsHtml5Portability::
 | 
						|
                         lowerCaseLiteralEqualsIgnoreAsciiCaseString(
 | 
						|
                             "referrer",
 | 
						|
                             aAttributes->getValue(
 | 
						|
                                 nsHtml5AttributeName::ATTR_NAME))) {
 | 
						|
            nsHtml5String referrerPolicy =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
 | 
						|
            if (referrerPolicy) {
 | 
						|
              mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy(
 | 
						|
                  referrerPolicy);
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      case kNameSpaceID_SVG:
 | 
						|
        if (nsGkAtoms::image == aName) {
 | 
						|
          nsHtml5String url =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
 | 
						|
          if (url) {
 | 
						|
            mSpeculativeLoadQueue.AppendElement()->InitImage(
 | 
						|
                url, nullptr, nullptr, nullptr, nullptr);
 | 
						|
          }
 | 
						|
        } else if (nsGkAtoms::script == aName) {
 | 
						|
          nsHtml5TreeOperation* treeOp =
 | 
						|
              mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
          if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
 | 
						|
                NS_ERROR_OUT_OF_MEMORY);
 | 
						|
            return nullptr;
 | 
						|
          }
 | 
						|
          treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content,
 | 
						|
                       tokenizer->getLineNumber());
 | 
						|
 | 
						|
          nsHtml5String url =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
 | 
						|
          if (url) {
 | 
						|
            nsHtml5String type =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
 | 
						|
            nsHtml5String crossOrigin =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
 | 
						|
            nsHtml5String integrity =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
 | 
						|
            nsHtml5String referrerPolicy = aAttributes->getValue(
 | 
						|
                nsHtml5AttributeName::ATTR_REFERRERPOLICY);
 | 
						|
            mSpeculativeLoadQueue.AppendElement()->InitScript(
 | 
						|
                url, nullptr, type, crossOrigin, integrity, referrerPolicy,
 | 
						|
                mode == nsHtml5TreeBuilder::IN_HEAD, false, false, false);
 | 
						|
          }
 | 
						|
        } else if (nsGkAtoms::style == aName) {
 | 
						|
          nsHtml5TreeOperation* treeOp =
 | 
						|
              mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
          if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
 | 
						|
                NS_ERROR_OUT_OF_MEMORY);
 | 
						|
            return nullptr;
 | 
						|
          }
 | 
						|
          treeOp->Init(eTreeOpSetStyleLineNumber, content,
 | 
						|
                       tokenizer->getLineNumber());
 | 
						|
 | 
						|
          nsHtml5String url =
 | 
						|
              aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
 | 
						|
          if (url) {
 | 
						|
            nsHtml5String crossOrigin =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
 | 
						|
            nsHtml5String integrity =
 | 
						|
                aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
 | 
						|
            nsHtml5String referrerPolicy = aAttributes->getValue(
 | 
						|
                nsHtml5AttributeName::ATTR_REFERRERPOLICY);
 | 
						|
            mSpeculativeLoadQueue.AppendElement()->InitStyle(
 | 
						|
                url, nullptr, crossOrigin, referrerPolicy, integrity);
 | 
						|
          }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  } else if (aNamespace != kNameSpaceID_MathML) {
 | 
						|
    // No speculative loader--just line numbers and defer/async check
 | 
						|
    if (nsGkAtoms::style == aName) {
 | 
						|
      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
      if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
        return nullptr;
 | 
						|
      }
 | 
						|
      treeOp->Init(eTreeOpSetStyleLineNumber, content,
 | 
						|
                   tokenizer->getLineNumber());
 | 
						|
    } else if (nsGkAtoms::script == aName) {
 | 
						|
      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
      if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
        return nullptr;
 | 
						|
      }
 | 
						|
      treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content,
 | 
						|
                   tokenizer->getLineNumber());
 | 
						|
      if (aNamespace == kNameSpaceID_XHTML) {
 | 
						|
        mCurrentHtmlScriptIsAsyncOrDefer =
 | 
						|
            aAttributes->contains(nsHtml5AttributeName::ATTR_SRC) &&
 | 
						|
            (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
 | 
						|
             aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER));
 | 
						|
      }
 | 
						|
    } else if (aNamespace == kNameSpaceID_XHTML) {
 | 
						|
      if (nsGkAtoms::html == aName) {
 | 
						|
        nsHtml5String url =
 | 
						|
            aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
 | 
						|
        nsHtml5TreeOperation* treeOp =
 | 
						|
            mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
        if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
          MarkAsBrokenAndRequestSuspensionWithoutBuilder(
 | 
						|
              NS_ERROR_OUT_OF_MEMORY);
 | 
						|
          return nullptr;
 | 
						|
        }
 | 
						|
        if (url) {
 | 
						|
          nsString
 | 
						|
              urlString;  // Not Auto, because using it to hold nsStringBuffer*
 | 
						|
          url.ToString(urlString);
 | 
						|
          treeOp->Init(eTreeOpProcessOfflineManifest, urlString);
 | 
						|
        } else {
 | 
						|
          treeOp->Init(eTreeOpProcessOfflineManifest, EmptyString());
 | 
						|
        }
 | 
						|
      } else if (nsGkAtoms::base == aName && mViewSource) {
 | 
						|
        nsHtml5String url =
 | 
						|
            aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
 | 
						|
        if (url) {
 | 
						|
          mViewSource->AddBase(url);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // End wall of code for speculative loading
 | 
						|
 | 
						|
  return content;
 | 
						|
}
 | 
						|
 | 
						|
nsIContentHandle* nsHtml5TreeBuilder::createElement(
 | 
						|
    int32_t aNamespace, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes,
 | 
						|
    nsIContentHandle* aFormElement, nsIContentHandle* aIntendedParent,
 | 
						|
    nsHtml5ContentCreatorFunction aCreator) {
 | 
						|
  nsIContentHandle* content =
 | 
						|
      createElement(aNamespace, aName, aAttributes, aIntendedParent, aCreator);
 | 
						|
  if (aFormElement) {
 | 
						|
    if (mBuilder) {
 | 
						|
      nsHtml5TreeOperation::SetFormElement(
 | 
						|
          static_cast<nsIContent*>(content),
 | 
						|
          static_cast<nsIContent*>(aFormElement));
 | 
						|
    } else {
 | 
						|
      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
      if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
        return nullptr;
 | 
						|
      }
 | 
						|
      treeOp->Init(eTreeOpSetFormElement, content, aFormElement);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return content;
 | 
						|
}
 | 
						|
 | 
						|
nsIContentHandle* nsHtml5TreeBuilder::createHtmlElementSetAsRoot(
 | 
						|
    nsHtml5HtmlAttributes* aAttributes) {
 | 
						|
  nsHtml5ContentCreatorFunction creator;
 | 
						|
  // <html> uses NS_NewHTMLSharedElement creator
 | 
						|
  creator.html = NS_NewHTMLSharedElement;
 | 
						|
  nsIContentHandle* content = createElement(kNameSpaceID_XHTML, nsGkAtoms::html,
 | 
						|
                                            aAttributes, nullptr, creator);
 | 
						|
  if (mBuilder) {
 | 
						|
    nsresult rv = nsHtml5TreeOperation::AppendToDocument(
 | 
						|
        static_cast<nsIContent*>(content), mBuilder);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
    if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
    treeOp->Init(eTreeOpAppendToDocument, content);
 | 
						|
  }
 | 
						|
  return content;
 | 
						|
}
 | 
						|
 | 
						|
nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
 | 
						|
    int32_t aNamespace, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes,
 | 
						|
    nsIContentHandle* aFormElement, nsIContentHandle* aTable,
 | 
						|
    nsIContentHandle* aStackParent, nsHtml5ContentCreatorFunction aCreator) {
 | 
						|
  MOZ_ASSERT(aTable, "Null table");
 | 
						|
  MOZ_ASSERT(aStackParent, "Null stack parent");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    // Get the foster parent to use as the intended parent when creating
 | 
						|
    // the child element.
 | 
						|
    nsIContent* fosterParent = nsHtml5TreeOperation::GetFosterParent(
 | 
						|
        static_cast<nsIContent*>(aTable),
 | 
						|
        static_cast<nsIContent*>(aStackParent));
 | 
						|
 | 
						|
    nsIContentHandle* child = createElement(
 | 
						|
        aNamespace, aName, aAttributes, aFormElement, fosterParent, aCreator);
 | 
						|
 | 
						|
    insertFosterParentedChild(child, aTable, aStackParent);
 | 
						|
 | 
						|
    return child;
 | 
						|
  }
 | 
						|
 | 
						|
  // Tree op to get the foster parent that we use as the intended parent
 | 
						|
  // when creating the child element.
 | 
						|
  nsHtml5TreeOperation* fosterParentTreeOp = mOpQueue.AppendElement();
 | 
						|
  NS_ASSERTION(fosterParentTreeOp, "Tree op allocation failed.");
 | 
						|
  nsIContentHandle* fosterParentHandle = AllocateContentHandle();
 | 
						|
  fosterParentTreeOp->Init(eTreeOpGetFosterParent, aTable, aStackParent,
 | 
						|
                           fosterParentHandle);
 | 
						|
 | 
						|
  // Create the element with the correct intended parent.
 | 
						|
  nsIContentHandle* child =
 | 
						|
      createElement(aNamespace, aName, aAttributes, aFormElement,
 | 
						|
                    fosterParentHandle, aCreator);
 | 
						|
 | 
						|
  // Insert the child into the foster parent.
 | 
						|
  insertFosterParentedChild(child, aTable, aStackParent);
 | 
						|
 | 
						|
  return child;
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement) {
 | 
						|
  MOZ_ASSERT(aElement, "Null element");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement), mBuilder);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpDetach, aElement);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild,
 | 
						|
                                       nsIContentHandle* aParent) {
 | 
						|
  MOZ_ASSERT(aChild, "Null child");
 | 
						|
  MOZ_ASSERT(aParent, "Null parent");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    nsresult rv = nsHtml5TreeOperation::Append(
 | 
						|
        static_cast<nsIContent*>(aChild), static_cast<nsIContent*>(aParent),
 | 
						|
        mBuilder);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpAppend, aChild, aParent);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::appendChildrenToNewParent(
 | 
						|
    nsIContentHandle* aOldParent, nsIContentHandle* aNewParent) {
 | 
						|
  MOZ_ASSERT(aOldParent, "Null old parent");
 | 
						|
  MOZ_ASSERT(aNewParent, "Null new parent");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent(
 | 
						|
        static_cast<nsIContent*>(aOldParent),
 | 
						|
        static_cast<nsIContent*>(aNewParent), mBuilder);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpAppendChildrenToNewParent, aOldParent, aNewParent);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::insertFosterParentedCharacters(
 | 
						|
    char16_t* aBuffer, int32_t aStart, int32_t aLength,
 | 
						|
    nsIContentHandle* aTable, nsIContentHandle* aStackParent) {
 | 
						|
  MOZ_ASSERT(aBuffer, "Null buffer");
 | 
						|
  MOZ_ASSERT(aTable, "Null table");
 | 
						|
  MOZ_ASSERT(aStackParent, "Null stack parent");
 | 
						|
  MOZ_ASSERT(!aStart, "aStart must always be zero.");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    nsresult rv = nsHtml5TreeOperation::FosterParentText(
 | 
						|
        static_cast<nsIContent*>(aStackParent),
 | 
						|
        aBuffer,  // XXX aStart always ignored???
 | 
						|
        aLength, static_cast<nsIContent*>(aTable), mBuilder);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
 | 
						|
  if (!bufferCopy) {
 | 
						|
    // Just assigning mBroken instead of generating tree op. The caller
 | 
						|
    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
 | 
						|
    mBroken = NS_ERROR_OUT_OF_MEMORY;
 | 
						|
    requestSuspension();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpFosterParentText, bufferCopy.release(), aLength,
 | 
						|
               aStackParent, aTable);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::insertFosterParentedChild(
 | 
						|
    nsIContentHandle* aChild, nsIContentHandle* aTable,
 | 
						|
    nsIContentHandle* aStackParent) {
 | 
						|
  MOZ_ASSERT(aChild, "Null child");
 | 
						|
  MOZ_ASSERT(aTable, "Null table");
 | 
						|
  MOZ_ASSERT(aStackParent, "Null stack parent");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    nsresult rv = nsHtml5TreeOperation::FosterParent(
 | 
						|
        static_cast<nsIContent*>(aChild),
 | 
						|
        static_cast<nsIContent*>(aStackParent),
 | 
						|
        static_cast<nsIContent*>(aTable), mBuilder);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpFosterParent, aChild, aStackParent, aTable);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent,
 | 
						|
                                          char16_t* aBuffer, int32_t aStart,
 | 
						|
                                          int32_t aLength) {
 | 
						|
  MOZ_ASSERT(aBuffer, "Null buffer");
 | 
						|
  MOZ_ASSERT(aParent, "Null parent");
 | 
						|
  MOZ_ASSERT(!aStart, "aStart must always be zero.");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    nsresult rv = nsHtml5TreeOperation::AppendText(
 | 
						|
        aBuffer,  // XXX aStart always ignored???
 | 
						|
        aLength, static_cast<nsIContent*>(aParent), mBuilder);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
 | 
						|
  if (!bufferCopy) {
 | 
						|
    // Just assigning mBroken instead of generating tree op. The caller
 | 
						|
    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
 | 
						|
    mBroken = NS_ERROR_OUT_OF_MEMORY;
 | 
						|
    requestSuspension();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpAppendText, bufferCopy.release(), aLength, aParent);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent,
 | 
						|
                                       char16_t* aBuffer, int32_t aStart,
 | 
						|
                                       int32_t aLength) {
 | 
						|
  MOZ_ASSERT(aBuffer, "Null buffer");
 | 
						|
  MOZ_ASSERT(aParent, "Null parent");
 | 
						|
  MOZ_ASSERT(!aStart, "aStart must always be zero.");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    nsresult rv = nsHtml5TreeOperation::AppendComment(
 | 
						|
        static_cast<nsIContent*>(aParent),
 | 
						|
        aBuffer,  // XXX aStart always ignored???
 | 
						|
        aLength, mBuilder);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
 | 
						|
  if (!bufferCopy) {
 | 
						|
    // Just assigning mBroken instead of generating tree op. The caller
 | 
						|
    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
 | 
						|
    mBroken = NS_ERROR_OUT_OF_MEMORY;
 | 
						|
    requestSuspension();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpAppendComment, bufferCopy.release(), aLength, aParent);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer,
 | 
						|
                                                 int32_t aStart,
 | 
						|
                                                 int32_t aLength) {
 | 
						|
  MOZ_ASSERT(aBuffer, "Null buffer");
 | 
						|
  MOZ_ASSERT(!aStart, "aStart must always be zero.");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument(
 | 
						|
        aBuffer,  // XXX aStart always ignored???
 | 
						|
        aLength, mBuilder);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
 | 
						|
  if (!bufferCopy) {
 | 
						|
    // Just assigning mBroken instead of generating tree op. The caller
 | 
						|
    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
 | 
						|
    mBroken = NS_ERROR_OUT_OF_MEMORY;
 | 
						|
    requestSuspension();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpAppendCommentToDocument, bufferCopy.release(), aLength);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::addAttributesToElement(
 | 
						|
    nsIContentHandle* aElement, nsHtml5HtmlAttributes* aAttributes) {
 | 
						|
  MOZ_ASSERT(aElement, "Null element");
 | 
						|
  MOZ_ASSERT(aAttributes, "Null attributes");
 | 
						|
 | 
						|
  if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    MOZ_ASSERT(
 | 
						|
        aAttributes == tokenizer->GetAttributes(),
 | 
						|
        "Using attribute other than the tokenizer's to add to body or html.");
 | 
						|
    nsresult rv = nsHtml5TreeOperation::AddAttributes(
 | 
						|
        static_cast<nsIContent*>(aElement), aAttributes, mBuilder);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(aElement, aAttributes);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement) {
 | 
						|
  MOZ_ASSERT(aElement, "Null element");
 | 
						|
 | 
						|
  if (mBuilder) {
 | 
						|
    nsHtml5TreeOperation::MarkMalformedIfScript(
 | 
						|
        static_cast<nsIContent*>(aElement));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpMarkMalformedIfScript, aElement);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::start(bool fragment) {
 | 
						|
  mCurrentHtmlScriptIsAsyncOrDefer = false;
 | 
						|
#ifdef DEBUG
 | 
						|
  mActive = true;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::end() {
 | 
						|
  mOpQueue.Clear();
 | 
						|
#ifdef DEBUG
 | 
						|
  mActive = false;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::appendDoctypeToDocument(nsAtom* aName,
 | 
						|
                                                 nsHtml5String aPublicId,
 | 
						|
                                                 nsHtml5String aSystemId) {
 | 
						|
  MOZ_ASSERT(aName, "Null name");
 | 
						|
  nsString publicId;  // Not Auto, because using it to hold nsStringBuffer*
 | 
						|
  nsString systemId;  // Not Auto, because using it to hold nsStringBuffer*
 | 
						|
  aPublicId.ToString(publicId);
 | 
						|
  aSystemId.ToString(systemId);
 | 
						|
  if (mBuilder) {
 | 
						|
    nsresult rv = nsHtml5TreeOperation::AppendDoctypeToDocument(
 | 
						|
        aName, publicId, systemId, mBuilder);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(aName, publicId, systemId);
 | 
						|
  // nsXMLContentSink can flush here, but what's the point?
 | 
						|
  // It can also interrupt here, but we can't.
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsAtom* aName,
 | 
						|
                                       nsIContentHandle* aElement) {
 | 
						|
  NS_ASSERTION(aNamespace == kNameSpaceID_XHTML ||
 | 
						|
                   aNamespace == kNameSpaceID_SVG ||
 | 
						|
                   aNamespace == kNameSpaceID_MathML,
 | 
						|
               "Element isn't HTML, SVG or MathML!");
 | 
						|
  NS_ASSERTION(aName, "Element doesn't have local name!");
 | 
						|
  NS_ASSERTION(aElement, "No element!");
 | 
						|
  /*
 | 
						|
   * The frame constructor uses recursive algorithms, so it can't deal with
 | 
						|
   * arbitrarily deep trees. This is especially a problem on Windows where
 | 
						|
   * the permitted depth of the runtime stack is rather small.
 | 
						|
   *
 | 
						|
   * The following is a protection against author incompetence--not against
 | 
						|
   * malice. There are other ways to make the DOM deep anyway.
 | 
						|
   *
 | 
						|
   * The basic idea is that when the tree builder stack gets too deep,
 | 
						|
   * append operations no longer append to the node that the HTML parsing
 | 
						|
   * algorithm says they should but instead text nodes are append to the last
 | 
						|
   * element that was seen before a magic tree builder stack threshold was
 | 
						|
   * reached and element and comment nodes aren't appended to the DOM at all.
 | 
						|
   *
 | 
						|
   * However, for security reasons, non-child descendant text nodes inside an
 | 
						|
   * SVG script or style element should not become children. Also, non-cell
 | 
						|
   * table elements shouldn't be used as surrogate parents for user experience
 | 
						|
   * reasons.
 | 
						|
   */
 | 
						|
  if (aNamespace != kNameSpaceID_XHTML) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (aName == nsGkAtoms::body || aName == nsGkAtoms::frameset) {
 | 
						|
    if (mBuilder) {
 | 
						|
      // InnerHTML and DOMParser shouldn't start layout anyway
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
    if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    treeOp->Init(eTreeOpStartLayout);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (aName == nsGkAtoms::input || aName == nsGkAtoms::button) {
 | 
						|
    if (mBuilder) {
 | 
						|
      nsHtml5TreeOperation::DoneCreatingElement(
 | 
						|
          static_cast<nsIContent*>(aElement));
 | 
						|
    } else {
 | 
						|
      mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (aName == nsGkAtoms::audio || aName == nsGkAtoms::video ||
 | 
						|
      aName == nsGkAtoms::menuitem) {
 | 
						|
    if (mBuilder) {
 | 
						|
      nsHtml5TreeOperation::DoneCreatingElement(
 | 
						|
          static_cast<nsIContent*>(aElement));
 | 
						|
    } else {
 | 
						|
      mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (mSpeculativeLoadStage && aName == nsGkAtoms::picture) {
 | 
						|
    // mSpeculativeLoadStage is non-null only in the off-the-main-thread
 | 
						|
    // tree builder, which handles the network stream
 | 
						|
    //
 | 
						|
    // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
 | 
						|
    mSpeculativeLoadQueue.AppendElement()->InitOpenPicture();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsAtom* aName,
 | 
						|
                                       nsIContentHandle* aElement) {
 | 
						|
  NS_ASSERTION(aNamespace == kNameSpaceID_XHTML ||
 | 
						|
                   aNamespace == kNameSpaceID_SVG ||
 | 
						|
                   aNamespace == kNameSpaceID_MathML,
 | 
						|
               "Element isn't HTML, SVG or MathML!");
 | 
						|
  NS_ASSERTION(aName, "Element doesn't have local name!");
 | 
						|
  NS_ASSERTION(aElement, "No element!");
 | 
						|
  if (aNamespace == kNameSpaceID_MathML) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  // we now have only SVG and HTML
 | 
						|
  if (aName == nsGkAtoms::script) {
 | 
						|
    if (mPreventScriptExecution) {
 | 
						|
      if (mBuilder) {
 | 
						|
        nsHtml5TreeOperation::PreventScriptExecution(
 | 
						|
            static_cast<nsIContent*>(aElement));
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      mOpQueue.AppendElement()->Init(eTreeOpPreventScriptExecution, aElement);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    if (mBuilder) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    if (mCurrentHtmlScriptIsAsyncOrDefer) {
 | 
						|
      NS_ASSERTION(aNamespace == kNameSpaceID_XHTML,
 | 
						|
                   "Only HTML scripts may be async/defer.");
 | 
						|
      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
      if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      treeOp->Init(eTreeOpRunScriptAsyncDefer, aElement);
 | 
						|
      mCurrentHtmlScriptIsAsyncOrDefer = false;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    requestSuspension();
 | 
						|
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
    if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    treeOp->InitScript(aElement);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (aName == nsGkAtoms::title) {
 | 
						|
    if (mBuilder) {
 | 
						|
      nsHtml5TreeOperation::DoneAddingChildren(
 | 
						|
          static_cast<nsIContent*>(aElement));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
    if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    treeOp->Init(eTreeOpDoneAddingChildren, aElement);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (aName == nsGkAtoms::style ||
 | 
						|
      (aNamespace == kNameSpaceID_XHTML && aName == nsGkAtoms::link)) {
 | 
						|
    if (mBuilder) {
 | 
						|
      MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
 | 
						|
                 "Scripts must be blocked.");
 | 
						|
      mBuilder->UpdateStyleSheet(static_cast<nsIContent*>(aElement));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
    if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    treeOp->Init(eTreeOpUpdateStyleSheet, aElement);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (aNamespace == kNameSpaceID_SVG) {
 | 
						|
    if (aName == nsGkAtoms::svg) {
 | 
						|
      if (mBuilder) {
 | 
						|
        nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement));
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
      if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      treeOp->Init(eTreeOpSvgLoad, aElement);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  // we now have only HTML
 | 
						|
  // Some HTML nodes need DoneAddingChildren() called to initialize
 | 
						|
  // properly (e.g. form state restoration).
 | 
						|
  // XXX expose ElementName group here and do switch
 | 
						|
  if (aName == nsGkAtoms::object || aName == nsGkAtoms::select ||
 | 
						|
      aName == nsGkAtoms::textarea || aName == nsGkAtoms::output ||
 | 
						|
      aName == nsGkAtoms::head) {
 | 
						|
    if (mBuilder) {
 | 
						|
      nsHtml5TreeOperation::DoneAddingChildren(
 | 
						|
          static_cast<nsIContent*>(aElement));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
    if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    treeOp->Init(eTreeOpDoneAddingChildren, aElement);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (aName == nsGkAtoms::meta && !fragment && !mBuilder) {
 | 
						|
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
    if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    treeOp->Init(eTreeOpProcessMeta, aElement);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (mSpeculativeLoadStage && aName == nsGkAtoms::picture) {
 | 
						|
    // mSpeculativeLoadStage is non-null only in the off-the-main-thread
 | 
						|
    // tree builder, which handles the network stream
 | 
						|
    //
 | 
						|
    // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
 | 
						|
    mSpeculativeLoadQueue.AppendElement()->InitEndPicture();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf,
 | 
						|
                                              int32_t aStart, int32_t aLength) {
 | 
						|
  MOZ_RELEASE_ASSERT(charBufferLen + aLength <= charBuffer.length,
 | 
						|
                     "About to memcpy past the end of the buffer!");
 | 
						|
  memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength);
 | 
						|
  charBufferLen += aLength;
 | 
						|
}
 | 
						|
 | 
						|
// INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits
 | 
						|
// is 2^30. Note that this is counting char16_t units. The underlying
 | 
						|
// bytes will be twice that, but they fit even in 32-bit size_t even
 | 
						|
// if a contiguous chunk of memory of that size is pretty unlikely to
 | 
						|
// be available on a 32-bit system.
 | 
						|
#define MAX_POWER_OF_TWO_IN_INT32 0x40000000
 | 
						|
 | 
						|
bool nsHtml5TreeBuilder::EnsureBufferSpace(int32_t aLength) {
 | 
						|
  // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer
 | 
						|
  // so that this method becomes unnecessary.
 | 
						|
  mozilla::CheckedInt<int32_t> worstCase(charBufferLen);
 | 
						|
  worstCase += aLength;
 | 
						|
  if (!worstCase.isValid()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if (!charBuffer) {
 | 
						|
    if (worstCase.value() < MAX_POWER_OF_TWO_IN_INT32) {
 | 
						|
      // Add one to round to the next power of two to avoid immediate
 | 
						|
      // reallocation once there are a few characters in the buffer.
 | 
						|
      worstCase += 1;
 | 
						|
    }
 | 
						|
    charBuffer = jArray<char16_t, int32_t>::newFallibleJArray(
 | 
						|
        mozilla::RoundUpPow2(worstCase.value()));
 | 
						|
    if (!charBuffer) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  } else if (worstCase.value() > charBuffer.length) {
 | 
						|
    jArray<char16_t, int32_t> newBuf =
 | 
						|
        jArray<char16_t, int32_t>::newFallibleJArray(
 | 
						|
            mozilla::RoundUpPow2(worstCase.value()));
 | 
						|
    if (!newBuf) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    memcpy(newBuf, charBuffer, sizeof(char16_t) * size_t(charBufferLen));
 | 
						|
    charBuffer = newBuf;
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
nsIContentHandle* nsHtml5TreeBuilder::AllocateContentHandle() {
 | 
						|
  if (MOZ_UNLIKELY(mBuilder)) {
 | 
						|
    MOZ_ASSERT_UNREACHABLE("Must never allocate a handle with builder.");
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) {
 | 
						|
    mOldHandles.AppendElement(std::move(mHandles));
 | 
						|
    mHandles = mozilla::MakeUnique<nsIContent*[]>(
 | 
						|
        NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH);
 | 
						|
    mHandlesUsed = 0;
 | 
						|
  }
 | 
						|
#ifdef DEBUG
 | 
						|
  mHandles[mHandlesUsed] = reinterpret_cast<nsIContent*>(uintptr_t(0xC0DEDBAD));
 | 
						|
#endif
 | 
						|
  return &mHandles[mHandlesUsed++];
 | 
						|
}
 | 
						|
 | 
						|
bool nsHtml5TreeBuilder::HasScript() {
 | 
						|
  uint32_t len = mOpQueue.Length();
 | 
						|
  if (!len) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return mOpQueue.ElementAt(len - 1).IsRunScript();
 | 
						|
}
 | 
						|
 | 
						|
bool nsHtml5TreeBuilder::Flush(bool aDiscretionary) {
 | 
						|
  if (MOZ_UNLIKELY(mBuilder)) {
 | 
						|
    MOZ_ASSERT_UNREACHABLE("Must never flush with builder.");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if (NS_SUCCEEDED(mBroken)) {
 | 
						|
    if (!aDiscretionary || !(charBufferLen && currentPtr >= 0 &&
 | 
						|
                             stack[currentPtr]->isFosterParenting())) {
 | 
						|
      // Don't flush text on discretionary flushes if the current element on
 | 
						|
      // the stack is a foster-parenting element and there's pending text,
 | 
						|
      // because flushing in that case would make the tree shape dependent on
 | 
						|
      // where the flush points fall.
 | 
						|
      flushCharacters();
 | 
						|
    }
 | 
						|
    FlushLoads();
 | 
						|
  }
 | 
						|
  if (mOpSink) {
 | 
						|
    bool hasOps = !mOpQueue.IsEmpty();
 | 
						|
    if (hasOps) {
 | 
						|
      // If the builder is broken and mOpQueue is not empty, there must be
 | 
						|
      // one op and it must be eTreeOpMarkAsBroken.
 | 
						|
      if (NS_FAILED(mBroken)) {
 | 
						|
        MOZ_ASSERT(mOpQueue.Length() == 1,
 | 
						|
                   "Tree builder is broken with a non-empty op queue whose "
 | 
						|
                   "length isn't 1.");
 | 
						|
        MOZ_ASSERT(mOpQueue[0].IsMarkAsBroken(),
 | 
						|
                   "Tree builder is broken but the op in queue is not marked "
 | 
						|
                   "as broken.");
 | 
						|
      }
 | 
						|
      mOpSink->MoveOpsFrom(mOpQueue);
 | 
						|
    }
 | 
						|
    return hasOps;
 | 
						|
  }
 | 
						|
  // no op sink: throw away ops
 | 
						|
  mOpQueue.Clear();
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::FlushLoads() {
 | 
						|
  if (MOZ_UNLIKELY(mBuilder)) {
 | 
						|
    MOZ_ASSERT_UNREACHABLE("Must never flush loads with builder.");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (!mSpeculativeLoadQueue.IsEmpty()) {
 | 
						|
    mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::SetDocumentCharset(NotNull<const Encoding*> aEncoding,
 | 
						|
                                            int32_t aCharsetSource) {
 | 
						|
  if (mBuilder) {
 | 
						|
    mBuilder->SetDocumentCharsetAndSource(aEncoding, aCharsetSource);
 | 
						|
  } else if (mSpeculativeLoadStage) {
 | 
						|
    mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset(
 | 
						|
        aEncoding, aCharsetSource);
 | 
						|
  } else {
 | 
						|
    mOpQueue.AppendElement()->Init(eTreeOpSetDocumentCharset, aEncoding,
 | 
						|
                                   aCharsetSource);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::StreamEnded() {
 | 
						|
  MOZ_ASSERT(!mBuilder, "Must not call StreamEnded with builder.");
 | 
						|
  MOZ_ASSERT(!fragment, "Must not parse fragments off the main thread.");
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpStreamEnded);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::NeedsCharsetSwitchTo(
 | 
						|
    NotNull<const Encoding*> aEncoding, int32_t aCharsetSource,
 | 
						|
    int32_t aLineNumber) {
 | 
						|
  if (MOZ_UNLIKELY(mBuilder)) {
 | 
						|
    MOZ_ASSERT_UNREACHABLE("Must never switch charset with builder.");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(eTreeOpNeedsCharsetSwitchTo, aEncoding, aCharsetSource,
 | 
						|
               aLineNumber);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId,
 | 
						|
                                                   bool aError,
 | 
						|
                                                   int32_t aLineNumber) {
 | 
						|
  if (MOZ_UNLIKELY(mBuilder)) {
 | 
						|
    MOZ_ASSERT_UNREACHABLE("Must never complain about charset with builder.");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  mOpQueue.AppendElement()->Init(aMsgId, aError, aLineNumber);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::TryToEnableEncodingMenu() {
 | 
						|
  if (MOZ_UNLIKELY(mBuilder)) {
 | 
						|
    MOZ_ASSERT_UNREACHABLE("Must never disable encoding menu with builder.");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
 | 
						|
  NS_ASSERTION(treeOp, "Tree op allocation failed.");
 | 
						|
  treeOp->Init(eTreeOpEnableEncodingMenu);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::AddSnapshotToScript(
 | 
						|
    nsAHtml5TreeBuilderState* aSnapshot, int32_t aLine) {
 | 
						|
  if (MOZ_UNLIKELY(mBuilder)) {
 | 
						|
    MOZ_ASSERT_UNREACHABLE("Must never use snapshots with builder.");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  MOZ_ASSERT(HasScript(), "No script to add a snapshot to!");
 | 
						|
  MOZ_ASSERT(aSnapshot, "Got null snapshot.");
 | 
						|
  mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::DropHandles() {
 | 
						|
  MOZ_ASSERT(!mBuilder, "Must not drop handles with builder.");
 | 
						|
  mOldHandles.Clear();
 | 
						|
  mHandlesUsed = 0;
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv) {
 | 
						|
  if (MOZ_UNLIKELY(mBuilder)) {
 | 
						|
    MOZ_ASSERT_UNREACHABLE("Must not call this with builder.");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  mBroken = aRv;
 | 
						|
  mOpQueue.Clear();  // Previous ops don't matter anymore
 | 
						|
  mOpQueue.AppendElement()->Init(aRv);
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv) {
 | 
						|
  if (mBuilder) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithBuilder(aRv);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  mBroken = aRv;
 | 
						|
  requestSuspension();
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle) {
 | 
						|
  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
 | 
						|
 | 
						|
  startTag(nsHtml5ElementName::ELT_META,
 | 
						|
           nsHtml5ViewSourceUtils::NewMetaViewportAttributes(), false);
 | 
						|
 | 
						|
  startTag(nsHtml5ElementName::ELT_TITLE,
 | 
						|
           nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, false);
 | 
						|
 | 
						|
  // XUL will add the "Source of: " prefix.
 | 
						|
  uint32_t length = aTitle.Length();
 | 
						|
  if (length > INT32_MAX) {
 | 
						|
    length = INT32_MAX;
 | 
						|
  }
 | 
						|
  characters(aTitle.get(), 0, (int32_t)length);
 | 
						|
  endTag(nsHtml5ElementName::ELT_TITLE);
 | 
						|
 | 
						|
  startTag(nsHtml5ElementName::ELT_LINK,
 | 
						|
           nsHtml5ViewSourceUtils::NewLinkAttributes(), false);
 | 
						|
 | 
						|
  startTag(nsHtml5ElementName::ELT_BODY,
 | 
						|
           nsHtml5ViewSourceUtils::NewBodyAttributes(), false);
 | 
						|
 | 
						|
  StartPlainTextBody();
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::StartPlainText() {
 | 
						|
  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
 | 
						|
  startTag(nsHtml5ElementName::ELT_LINK,
 | 
						|
           nsHtml5PlainTextUtils::NewLinkAttributes(), false);
 | 
						|
 | 
						|
  startTag(nsHtml5ElementName::ELT_BODY,
 | 
						|
           nsHtml5PlainTextUtils::NewBodyAttributes(), false);
 | 
						|
 | 
						|
  StartPlainTextBody();
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::StartPlainTextBody() {
 | 
						|
  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
 | 
						|
  startTag(nsHtml5ElementName::ELT_PRE, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
 | 
						|
           false);
 | 
						|
  needToDropLF = false;
 | 
						|
}
 | 
						|
 | 
						|
// DocumentModeHandler
 | 
						|
void nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m) {
 | 
						|
  if (mBuilder) {
 | 
						|
    mBuilder->SetDocumentMode(m);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (mSpeculativeLoadStage) {
 | 
						|
    mSpeculativeLoadQueue.AppendElement()->InitSetDocumentMode(m);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  treeOp->Init(m);
 | 
						|
}
 | 
						|
 | 
						|
nsIContentHandle* nsHtml5TreeBuilder::getDocumentFragmentForTemplate(
 | 
						|
    nsIContentHandle* aTemplate) {
 | 
						|
  if (mBuilder) {
 | 
						|
    return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(
 | 
						|
        static_cast<nsIContent*>(aTemplate));
 | 
						|
  }
 | 
						|
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
 | 
						|
  if (MOZ_UNLIKELY(!treeOp)) {
 | 
						|
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  nsIContentHandle* fragHandle = AllocateContentHandle();
 | 
						|
  treeOp->Init(eTreeOpGetDocumentFragmentForTemplate, aTemplate, fragHandle);
 | 
						|
  return fragHandle;
 | 
						|
}
 | 
						|
 | 
						|
nsIContentHandle* nsHtml5TreeBuilder::getFormPointerForContext(
 | 
						|
    nsIContentHandle* aContext) {
 | 
						|
  MOZ_ASSERT(mBuilder, "Must have builder.");
 | 
						|
  if (!aContext) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
 | 
						|
  // aContext must always be an element that already exists
 | 
						|
  // in the document.
 | 
						|
  nsIContent* contextNode = static_cast<nsIContent*>(aContext);
 | 
						|
  nsIContent* currentAncestor = contextNode;
 | 
						|
 | 
						|
  // We traverse the ancestors of the context node to find the nearest
 | 
						|
  // form pointer. This traversal is why aContext must not be an emtpy handle.
 | 
						|
  nsIContent* nearestForm = nullptr;
 | 
						|
  while (currentAncestor) {
 | 
						|
    if (currentAncestor->IsHTMLElement(nsGkAtoms::form)) {
 | 
						|
      nearestForm = currentAncestor;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    currentAncestor = currentAncestor->GetParent();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!nearestForm) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  return nearestForm;
 | 
						|
}
 | 
						|
 | 
						|
// Error reporting
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter) {
 | 
						|
  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
 | 
						|
  mViewSource = aHighlighter;
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errDeepTree() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errDeepTree");
 | 
						|
  } else if (!mBuilder) {
 | 
						|
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
 | 
						|
    MOZ_ASSERT(treeOp, "Tree op allocation failed.");
 | 
						|
    treeOp->InitDeepTree(tokenizer->getLineNumber());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errStrayStartTag(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errStrayStartTag2", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errStrayEndTag(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex, nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex,
 | 
						|
                                                    nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errStrayDoctype() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errStrayDoctype");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errAlmostStandardsDoctype() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errQuirkyDoctype() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errQuirkyDoctype");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNonSpaceInTrailer() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNonSpaceAfterFrameset() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNonSpaceInFrameset() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNonSpaceAfterBody() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errStartTagWithoutDoctype() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNoSelectInTableScope() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errStartSelectWhereEndSelectExpected");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errBadStartTagInHead(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errBadStartTagInHead2", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errImage() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errImage");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errIsindex() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errIsindex");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errHeadingWhenHeadingOpen() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errFramesetStart() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errFramesetStart");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNoCellToClose() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNoCellToClose");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errStartTagInTable(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errFormWhenFormOpen() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errTableSeenWhileTableOpen() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errStartTagInTableBody(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errEndTagAfterBody() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errEndTagAfterBody");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errGarbageInColgroup() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errGarbageInColgroup");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errEndTagBr() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errEndTagBr");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNoElementToCloseButEndTagSeen",
 | 
						|
                                      aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errTableClosedWhileCaptionOpen() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errTableClosedWhileCaptionOpen");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNoTableRowToClose() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNoTableRowToClose");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNonSpaceInTable() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNonSpaceInTable");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errUnclosedChildrenInRuby() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errSelfClosing() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentSlash("errSelfClosing");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack() {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errNoCheckUnclosedElementsOnStack");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(
 | 
						|
    nsAtom* aName, nsAtom* aOther) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errEndTagDidNotMatchCurrentOpenElement",
 | 
						|
                                      aName, aOther);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsHtml5TreeBuilder::errEndWithUnclosedElements(nsAtom* aName) {
 | 
						|
  if (MOZ_UNLIKELY(mViewSource)) {
 | 
						|
    mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName);
 | 
						|
  }
 | 
						|
}
 |