content/xml/document/src/nsXMLContentSink.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/xml/document/src/nsXMLContentSink.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1648 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=78: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "nsCOMPtr.h"
    1.11 +#include "nsXMLContentSink.h"
    1.12 +#include "nsIParser.h"
    1.13 +#include "nsIDocument.h"
    1.14 +#include "nsIDOMDocument.h"
    1.15 +#include "nsIDOMDocumentType.h"
    1.16 +#include "nsIContent.h"
    1.17 +#include "nsIURI.h"
    1.18 +#include "nsNetUtil.h"
    1.19 +#include "nsIDocShell.h"
    1.20 +#include "nsIStyleSheetLinkingElement.h"
    1.21 +#include "nsIDOMComment.h"
    1.22 +#include "nsIDOMCDATASection.h"
    1.23 +#include "DocumentType.h"
    1.24 +#include "nsHTMLParts.h"
    1.25 +#include "nsCRT.h"
    1.26 +#include "nsCSSStyleSheet.h"
    1.27 +#include "mozilla/css/Loader.h"
    1.28 +#include "nsGkAtoms.h"
    1.29 +#include "nsContentUtils.h"
    1.30 +#include "nsIScriptContext.h"
    1.31 +#include "nsNameSpaceManager.h"
    1.32 +#include "nsIServiceManager.h"
    1.33 +#include "nsIScriptSecurityManager.h"
    1.34 +#include "nsIContentViewer.h"
    1.35 +#include "prtime.h"
    1.36 +#include "prlog.h"
    1.37 +#include "prmem.h"
    1.38 +#include "nsRect.h"
    1.39 +#include "nsIWebNavigation.h"
    1.40 +#include "nsIScriptElement.h"
    1.41 +#include "nsScriptLoader.h"
    1.42 +#include "nsStyleLinkElement.h"
    1.43 +#include "nsReadableUtils.h"
    1.44 +#include "nsUnicharUtils.h"
    1.45 +#include "nsICookieService.h"
    1.46 +#include "nsIPrompt.h"
    1.47 +#include "nsIChannel.h"
    1.48 +#include "nsIPrincipal.h"
    1.49 +#include "nsXMLPrettyPrinter.h"
    1.50 +#include "nsNodeInfoManager.h"
    1.51 +#include "nsContentCreatorFunctions.h"
    1.52 +#include "nsIContentPolicy.h"
    1.53 +#include "nsContentPolicyUtils.h"
    1.54 +#include "nsError.h"
    1.55 +#include "nsIDOMProcessingInstruction.h"
    1.56 +#include "nsNodeUtils.h"
    1.57 +#include "nsIScriptGlobalObject.h"
    1.58 +#include "nsIHTMLDocument.h"
    1.59 +#include "mozAutoDocUpdate.h"
    1.60 +#include "nsMimeTypes.h"
    1.61 +#include "nsHtml5SVGLoadDispatcher.h"
    1.62 +#include "nsTextNode.h"
    1.63 +#include "mozilla/dom/CDATASection.h"
    1.64 +#include "mozilla/dom/Comment.h"
    1.65 +#include "mozilla/dom/Element.h"
    1.66 +#include "mozilla/dom/ProcessingInstruction.h"
    1.67 +
    1.68 +using namespace mozilla::dom;
    1.69 +
    1.70 +// XXX Open Issues:
    1.71 +// 1) what's not allowed - We need to figure out which HTML tags
    1.72 +//    (prefixed with a HTML namespace qualifier) are explicitly not
    1.73 +//    allowed (if any).
    1.74 +// 2) factoring code with nsHTMLContentSink - There's some amount of
    1.75 +//    common code between this and the HTML content sink. This will
    1.76 +//    increase as we support more and more HTML elements. How can code
    1.77 +//    from the code be factored?
    1.78 +
    1.79 +nsresult
    1.80 +NS_NewXMLContentSink(nsIXMLContentSink** aResult,
    1.81 +                     nsIDocument* aDoc,
    1.82 +                     nsIURI* aURI,
    1.83 +                     nsISupports* aContainer,
    1.84 +                     nsIChannel* aChannel)
    1.85 +{
    1.86 +  NS_PRECONDITION(nullptr != aResult, "null ptr");
    1.87 +  if (nullptr == aResult) {
    1.88 +    return NS_ERROR_NULL_POINTER;
    1.89 +  }
    1.90 +  nsXMLContentSink* it = new nsXMLContentSink();
    1.91 +  
    1.92 +  nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
    1.93 +  nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
    1.94 +  NS_ENSURE_SUCCESS(rv, rv);
    1.95 +  
    1.96 +  return CallQueryInterface(it, aResult);
    1.97 +}
    1.98 +
    1.99 +nsXMLContentSink::nsXMLContentSink()
   1.100 +  : mConstrainSize(true),
   1.101 +    mPrettyPrintXML(true)
   1.102 +{
   1.103 +}
   1.104 +
   1.105 +nsXMLContentSink::~nsXMLContentSink()
   1.106 +{
   1.107 +  if (mText) {
   1.108 +    PR_Free(mText);  //  Doesn't null out, unlike PR_FREEIF
   1.109 +  }
   1.110 +}
   1.111 +
   1.112 +nsresult
   1.113 +nsXMLContentSink::Init(nsIDocument* aDoc,
   1.114 +                       nsIURI* aURI,
   1.115 +                       nsISupports* aContainer,
   1.116 +                       nsIChannel* aChannel)
   1.117 +{
   1.118 +  nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
   1.119 +  NS_ENSURE_SUCCESS(rv, rv);
   1.120 +
   1.121 +  aDoc->AddObserver(this);
   1.122 +  mIsDocumentObserver = true;
   1.123 +
   1.124 +  if (!mDocShell) {
   1.125 +    mPrettyPrintXML = false;
   1.126 +  }
   1.127 +  
   1.128 +  mState = eXMLContentSinkState_InProlog;
   1.129 +  mDocElement = nullptr;
   1.130 +
   1.131 +  return NS_OK;
   1.132 +}
   1.133 +
   1.134 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink)
   1.135 +  NS_INTERFACE_MAP_ENTRY(nsIContentSink)
   1.136 +  NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
   1.137 +  NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
   1.138 +  NS_INTERFACE_MAP_ENTRY(nsITransformObserver)
   1.139 +NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
   1.140 +
   1.141 +NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink)
   1.142 +NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink)
   1.143 +
   1.144 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink)
   1.145 +
   1.146 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink,
   1.147 +                                                  nsContentSink)
   1.148 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentHead)
   1.149 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocElement)
   1.150 +  for (uint32_t i = 0, count = tmp->mContentStack.Length(); i < count; i++) {
   1.151 +    const StackNode& node = tmp->mContentStack.ElementAt(i);
   1.152 +    cb.NoteXPCOMChild(node.mContent);
   1.153 +  }
   1.154 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1.155 +
   1.156 +// nsIContentSink
   1.157 +NS_IMETHODIMP
   1.158 +nsXMLContentSink::WillParse(void)
   1.159 +{
   1.160 +  return WillParseImpl();
   1.161 +}
   1.162 +
   1.163 +NS_IMETHODIMP
   1.164 +nsXMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
   1.165 +{
   1.166 +  WillBuildModelImpl();
   1.167 +
   1.168 +  // Notify document that the load is beginning
   1.169 +  mDocument->BeginLoad();
   1.170 +
   1.171 +  // Check for correct load-command for maybe prettyprinting
   1.172 +  if (mPrettyPrintXML) {
   1.173 +    nsAutoCString command;
   1.174 +    GetParser()->GetCommand(command);
   1.175 +    if (!command.EqualsLiteral("view")) {
   1.176 +      mPrettyPrintXML = false;
   1.177 +    }
   1.178 +  }
   1.179 +  
   1.180 +  return NS_OK;
   1.181 +}
   1.182 +
   1.183 +bool
   1.184 +nsXMLContentSink::CanStillPrettyPrint()
   1.185 +{
   1.186 +  return mPrettyPrintXML &&
   1.187 +         (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot);
   1.188 +}
   1.189 +
   1.190 +nsresult
   1.191 +nsXMLContentSink::MaybePrettyPrint()
   1.192 +{
   1.193 +  if (!CanStillPrettyPrint()) {
   1.194 +    mPrettyPrintXML = false;
   1.195 +
   1.196 +    return NS_OK;
   1.197 +  }
   1.198 +
   1.199 +  // stop observing in order to avoid crashing when replacing content
   1.200 +  mDocument->RemoveObserver(this);
   1.201 +  mIsDocumentObserver = false;
   1.202 +
   1.203 +  // Reenable the CSSLoader so that the prettyprinting stylesheets can load
   1.204 +  if (mCSSLoader) {
   1.205 +    mCSSLoader->SetEnabled(true);
   1.206 +  }
   1.207 +  
   1.208 +  nsRefPtr<nsXMLPrettyPrinter> printer;
   1.209 +  nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer));
   1.210 +  NS_ENSURE_SUCCESS(rv, rv);
   1.211 +
   1.212 +  bool isPrettyPrinting;
   1.213 +  rv = printer->PrettyPrint(mDocument, &isPrettyPrinting);
   1.214 +  NS_ENSURE_SUCCESS(rv, rv);
   1.215 +
   1.216 +  mPrettyPrinting = isPrettyPrinting;
   1.217 +  return NS_OK;
   1.218 +}
   1.219 +
   1.220 +static void
   1.221 +CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
   1.222 +                 nsIDocumentTransformer* aProcessor,
   1.223 +                 nsIDocument* aDocument)
   1.224 +{
   1.225 +  nsAutoString target, data;
   1.226 +  aPi->GetTarget(target);
   1.227 +
   1.228 +  // Check for namespace declarations
   1.229 +  if (target.EqualsLiteral("xslt-param-namespace")) {
   1.230 +    aPi->GetData(data);
   1.231 +    nsAutoString prefix, namespaceAttr;
   1.232 +    nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix,
   1.233 +                                            prefix);
   1.234 +    if (!prefix.IsEmpty() &&
   1.235 +        nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
   1.236 +                                                namespaceAttr)) {
   1.237 +      aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
   1.238 +    }
   1.239 +  }
   1.240 +
   1.241 +  // Check for actual parameters
   1.242 +  else if (target.EqualsLiteral("xslt-param")) {
   1.243 +    aPi->GetData(data);
   1.244 +    nsAutoString name, namespaceAttr, select, value;
   1.245 +    nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name,
   1.246 +                                            name);
   1.247 +    nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
   1.248 +                                            namespaceAttr);
   1.249 +    if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) {
   1.250 +      select.SetIsVoid(true);
   1.251 +    }
   1.252 +    if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) {
   1.253 +      value.SetIsVoid(true);
   1.254 +    }
   1.255 +    if (!name.IsEmpty()) {
   1.256 +      nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
   1.257 +      aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc);
   1.258 +    }
   1.259 +  }
   1.260 +}
   1.261 +
   1.262 +NS_IMETHODIMP
   1.263 +nsXMLContentSink::DidBuildModel(bool aTerminated)
   1.264 +{
   1.265 +  if (!mParser) {
   1.266 +    // If mParser is null, this parse has already been terminated and must
   1.267 +    // not been terminated again. However, nsDocument may still think that
   1.268 +    // the parse has not been terminated and call back into here in the case
   1.269 +    // where the XML parser has finished but the XSLT transform associated
   1.270 +    // with the document has not.
   1.271 +    return NS_OK;
   1.272 +  }
   1.273 +
   1.274 +  DidBuildModelImpl(aTerminated);
   1.275 +
   1.276 +  if (mXSLTProcessor) {
   1.277 +    // stop observing in order to avoid crashing when replacing content
   1.278 +    mDocument->RemoveObserver(this);
   1.279 +    mIsDocumentObserver = false;
   1.280 +
   1.281 +    // Check for xslt-param and xslt-param-namespace PIs
   1.282 +    for (nsIContent* child = mDocument->GetFirstChild();
   1.283 +         child;
   1.284 +         child = child->GetNextSibling()) {
   1.285 +      if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
   1.286 +        nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
   1.287 +        CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
   1.288 +      }
   1.289 +      else if (child->IsElement()) {
   1.290 +        // Only honor PIs in the prolog
   1.291 +        break;
   1.292 +      }
   1.293 +    }
   1.294 +
   1.295 +    nsCOMPtr<nsIDOMDocument> currentDOMDoc(do_QueryInterface(mDocument));
   1.296 +    mXSLTProcessor->SetSourceContentModel(currentDOMDoc);
   1.297 +    // Since the processor now holds a reference to us we drop our reference
   1.298 +    // to it to avoid owning cycles
   1.299 +    mXSLTProcessor = nullptr;
   1.300 +  }
   1.301 +  else {
   1.302 +    // Kick off layout for non-XSLT transformed documents.
   1.303 +
   1.304 +    // Check if we want to prettyprint
   1.305 +    MaybePrettyPrint();
   1.306 +
   1.307 +    bool startLayout = true;
   1.308 +    
   1.309 +    if (mPrettyPrinting) {
   1.310 +      NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
   1.311 +      
   1.312 +      // We're pretty-printing now.  See whether we should wait up on
   1.313 +      // stylesheet loads
   1.314 +      if (mDocument->CSSLoader()->HasPendingLoads() &&
   1.315 +          NS_SUCCEEDED(mDocument->CSSLoader()->AddObserver(this))) {
   1.316 +        // wait for those sheets to load
   1.317 +        startLayout = false;
   1.318 +      }
   1.319 +    }
   1.320 +    
   1.321 +    if (startLayout) {
   1.322 +      StartLayout(false);
   1.323 +
   1.324 +      ScrollToRef();
   1.325 +    }
   1.326 +
   1.327 +    mDocument->RemoveObserver(this);
   1.328 +    mIsDocumentObserver = false;
   1.329 +
   1.330 +    mDocument->EndLoad();
   1.331 +  }
   1.332 +
   1.333 +  DropParserAndPerfHint();
   1.334 +
   1.335 +  return NS_OK;
   1.336 +}
   1.337 +
   1.338 +NS_IMETHODIMP
   1.339 +nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument)
   1.340 +{
   1.341 +  NS_ENSURE_ARG(aResultDocument);
   1.342 +
   1.343 +  nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aResultDocument);
   1.344 +  if (htmlDoc) {
   1.345 +    htmlDoc->SetDocWriteDisabled(true);
   1.346 +  }
   1.347 +
   1.348 +  nsCOMPtr<nsIContentViewer> contentViewer;
   1.349 +  mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
   1.350 +  if (contentViewer) {
   1.351 +    return contentViewer->SetDocumentInternal(aResultDocument, true);
   1.352 +  }
   1.353 +  return NS_OK;
   1.354 +}
   1.355 +
   1.356 +NS_IMETHODIMP
   1.357 +nsXMLContentSink::OnTransformDone(nsresult aResult,
   1.358 +                                  nsIDocument* aResultDocument)
   1.359 +{
   1.360 +  NS_ASSERTION(NS_FAILED(aResult) || aResultDocument,
   1.361 +               "Don't notify about transform success without a document.");
   1.362 +
   1.363 +  nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aResultDocument);
   1.364 +
   1.365 +  nsCOMPtr<nsIContentViewer> contentViewer;
   1.366 +  mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
   1.367 +
   1.368 +  if (NS_FAILED(aResult) && contentViewer) {
   1.369 +    // Transform failed.
   1.370 +    if (domDoc) {
   1.371 +      aResultDocument->SetMayStartLayout(false);
   1.372 +      // We have an error document.
   1.373 +      contentViewer->SetDOMDocument(domDoc);
   1.374 +    }
   1.375 +    else {
   1.376 +      // We don't have an error document, display the
   1.377 +      // untransformed source document.
   1.378 +      nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument);
   1.379 +      contentViewer->SetDOMDocument(document);
   1.380 +    }
   1.381 +  }
   1.382 +
   1.383 +  nsCOMPtr<nsIDocument> originalDocument = mDocument;
   1.384 +  if (NS_SUCCEEDED(aResult) || aResultDocument) {
   1.385 +    // Transform succeeded or it failed and we have an error
   1.386 +    // document to display.
   1.387 +    mDocument = aResultDocument;
   1.388 +    nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
   1.389 +    if (htmlDoc) {
   1.390 +      htmlDoc->SetDocWriteDisabled(false);
   1.391 +    }
   1.392 +  }
   1.393 +
   1.394 +  // Notify document observers that all the content has been stuck
   1.395 +  // into the document.  
   1.396 +  // XXX do we need to notify for things like PIs?  Or just the
   1.397 +  // documentElement?
   1.398 +  nsIContent *rootElement = mDocument->GetRootElement();
   1.399 +  if (rootElement) {
   1.400 +    NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
   1.401 +                 "rootElement not in doc?");
   1.402 +    mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
   1.403 +    nsNodeUtils::ContentInserted(mDocument, rootElement,
   1.404 +                                 mDocument->IndexOf(rootElement));
   1.405 +    mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
   1.406 +  }
   1.407 +
   1.408 +  // Start the layout process
   1.409 +  StartLayout(false);
   1.410 +
   1.411 +  ScrollToRef();
   1.412 +
   1.413 +  originalDocument->EndLoad();
   1.414 +
   1.415 +  return NS_OK;
   1.416 +}
   1.417 +
   1.418 +NS_IMETHODIMP
   1.419 +nsXMLContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
   1.420 +                                   bool aWasAlternate,
   1.421 +                                   nsresult aStatus)
   1.422 +{
   1.423 +  if (!mPrettyPrinting) {
   1.424 +    return nsContentSink::StyleSheetLoaded(aSheet, aWasAlternate, aStatus);
   1.425 +  }
   1.426 +
   1.427 +  if (!mDocument->CSSLoader()->HasPendingLoads()) {
   1.428 +    mDocument->CSSLoader()->RemoveObserver(this);
   1.429 +    StartLayout(false);
   1.430 +    ScrollToRef();
   1.431 +  }
   1.432 +
   1.433 +  return NS_OK;
   1.434 +}
   1.435 +
   1.436 +NS_IMETHODIMP
   1.437 +nsXMLContentSink::WillInterrupt(void)
   1.438 +{
   1.439 +  return WillInterruptImpl();
   1.440 +}
   1.441 +
   1.442 +NS_IMETHODIMP
   1.443 +nsXMLContentSink::WillResume(void)
   1.444 +{
   1.445 +  return WillResumeImpl();
   1.446 +}
   1.447 +
   1.448 +NS_IMETHODIMP
   1.449 +nsXMLContentSink::SetParser(nsParserBase* aParser)
   1.450 +{
   1.451 +  NS_PRECONDITION(aParser, "Should have a parser here!");
   1.452 +  mParser = aParser;
   1.453 +  return NS_OK;
   1.454 +}
   1.455 +
   1.456 +nsresult
   1.457 +nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
   1.458 +                                nsINodeInfo* aNodeInfo, uint32_t aLineNumber,
   1.459 +                                nsIContent** aResult, bool* aAppendContent,
   1.460 +                                FromParser aFromParser)
   1.461 +{
   1.462 +  NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
   1.463 +
   1.464 +  *aResult = nullptr;
   1.465 +  *aAppendContent = true;
   1.466 +  nsresult rv = NS_OK;
   1.467 +
   1.468 +  nsCOMPtr<nsINodeInfo> ni = aNodeInfo;
   1.469 +  nsCOMPtr<Element> content;
   1.470 +  rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
   1.471 +  NS_ENSURE_SUCCESS(rv, rv);
   1.472 +
   1.473 +  if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
   1.474 +      || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
   1.475 +    ) {
   1.476 +    nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
   1.477 +    sele->SetScriptLineNumber(aLineNumber);
   1.478 +    sele->SetCreatorParser(GetParser());
   1.479 +    mConstrainSize = false;
   1.480 +  }
   1.481 +
   1.482 +  // XHTML needs some special attention
   1.483 +  if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
   1.484 +    mPrettyPrintHasFactoredElements = true;
   1.485 +  }
   1.486 +  else {
   1.487 +    // If we care, find out if we just used a special factory.
   1.488 +    if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
   1.489 +        mPrettyPrintXML) {
   1.490 +      mPrettyPrintHasFactoredElements =
   1.491 +        nsContentUtils::NameSpaceManager()->
   1.492 +          HasElementCreator(aNodeInfo->NamespaceID());
   1.493 +    }
   1.494 +
   1.495 +    if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
   1.496 +      content.forget(aResult);
   1.497 +
   1.498 +      return NS_OK;
   1.499 +    }
   1.500 +  }
   1.501 +
   1.502 +  if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
   1.503 +      aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
   1.504 +      aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
   1.505 +    nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
   1.506 +    if (ssle) {
   1.507 +      ssle->InitStyleLinkElement(false);
   1.508 +      if (aFromParser) {
   1.509 +        ssle->SetEnableUpdates(false);
   1.510 +      }
   1.511 +      if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
   1.512 +        ssle->SetLineNumber(aFromParser ? aLineNumber : 0);
   1.513 +      }
   1.514 +    }
   1.515 +  } 
   1.516 +
   1.517 +  content.forget(aResult);
   1.518 +
   1.519 +  return NS_OK;
   1.520 +}
   1.521 +
   1.522 +
   1.523 +nsresult
   1.524 +nsXMLContentSink::CloseElement(nsIContent* aContent)
   1.525 +{
   1.526 +  NS_ASSERTION(aContent, "missing element to close");
   1.527 +
   1.528 +  nsINodeInfo *nodeInfo = aContent->NodeInfo();
   1.529 +
   1.530 +  // Some HTML nodes need DoneAddingChildren() called to initialize
   1.531 +  // properly (eg form state restoration).
   1.532 +  if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
   1.533 +       (nodeInfo->NameAtom() == nsGkAtoms::select ||
   1.534 +        nodeInfo->NameAtom() == nsGkAtoms::textarea ||
   1.535 +        nodeInfo->NameAtom() == nsGkAtoms::video ||
   1.536 +        nodeInfo->NameAtom() == nsGkAtoms::audio ||
   1.537 +        nodeInfo->NameAtom() == nsGkAtoms::object ||
   1.538 +        nodeInfo->NameAtom() == nsGkAtoms::applet))
   1.539 +      || nodeInfo->NameAtom() == nsGkAtoms::title
   1.540 +      ) {
   1.541 +    aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
   1.542 +  }
   1.543 +  
   1.544 +  if (IsMonolithicContainer(nodeInfo)) {
   1.545 +    mInMonolithicContainer--;
   1.546 +  }
   1.547 +
   1.548 +  if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
   1.549 +      !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
   1.550 +    return NS_OK;
   1.551 +  }
   1.552 +
   1.553 +  if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
   1.554 +      || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
   1.555 +    ) {
   1.556 +    mConstrainSize = true; 
   1.557 +    nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
   1.558 +
   1.559 +    if (mPreventScriptExecution) {
   1.560 +      sele->PreventExecution();
   1.561 +      return NS_OK;
   1.562 +    }
   1.563 +
   1.564 +    // Always check the clock in nsContentSink right after a script
   1.565 +    StopDeflecting();
   1.566 +
   1.567 +    // Now tell the script that it's ready to go. This may execute the script
   1.568 +    // or return true, or neither if the script doesn't need executing.
   1.569 +    bool block = sele->AttemptToExecute();
   1.570 +
   1.571 +    // If the parser got blocked, make sure to return the appropriate rv.
   1.572 +    // I'm not sure if this is actually needed or not.
   1.573 +    if (mParser && !mParser->IsParserEnabled()) {
   1.574 +      // XXX The HTML sink doesn't call BlockParser here, why do we?
   1.575 +      GetParser()->BlockParser();
   1.576 +      block = true;
   1.577 +    }
   1.578 +
   1.579 +    return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
   1.580 +  }
   1.581 +  
   1.582 +  nsresult rv = NS_OK;
   1.583 +  if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
   1.584 +           // Need to check here to make sure this meta tag does not set
   1.585 +           // mPrettyPrintXML to false when we have a special root!
   1.586 +           (!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
   1.587 +    rv = ProcessMETATag(aContent);
   1.588 +  }
   1.589 +  else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
   1.590 +           nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
   1.591 +           nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
   1.592 +    nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
   1.593 +    if (ssle) {
   1.594 +      ssle->SetEnableUpdates(true);
   1.595 +      bool willNotify;
   1.596 +      bool isAlternate;
   1.597 +      rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
   1.598 +                                  &willNotify,
   1.599 +                                  &isAlternate);
   1.600 +      if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
   1.601 +        ++mPendingSheetCount;
   1.602 +        mScriptLoader->AddExecuteBlocker();
   1.603 +      }
   1.604 +    }
   1.605 +    // Look for <link rel="dns-prefetch" href="hostname">
   1.606 +    // and look for <link rel="next" href="hostname"> like in HTML sink
   1.607 +    if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
   1.608 +      nsAutoString relVal;
   1.609 +      aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
   1.610 +      if (!relVal.IsEmpty()) {
   1.611 +        uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal);
   1.612 +        bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
   1.613 +        if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
   1.614 +          nsAutoString hrefVal;
   1.615 +          aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
   1.616 +          if (!hrefVal.IsEmpty()) {
   1.617 +            PrefetchHref(hrefVal, aContent, hasPrefetch);
   1.618 +          }
   1.619 +        }
   1.620 +        if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
   1.621 +          nsAutoString hrefVal;
   1.622 +          aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
   1.623 +          if (!hrefVal.IsEmpty()) {
   1.624 +            PrefetchDNS(hrefVal);
   1.625 +          }
   1.626 +        }
   1.627 +      }
   1.628 +    }
   1.629 +  }
   1.630 +
   1.631 +  return rv;
   1.632 +}  
   1.633 +
   1.634 +nsresult
   1.635 +nsXMLContentSink::AddContentAsLeaf(nsIContent *aContent)
   1.636 +{
   1.637 +  nsresult result = NS_OK;
   1.638 +
   1.639 +  if ((eXMLContentSinkState_InProlog == mState) ||
   1.640 +      (eXMLContentSinkState_InEpilog == mState)) {
   1.641 +    NS_ASSERTION(mDocument, "Fragments have no prolog or epilog");
   1.642 +    mDocument->AppendChildTo(aContent, false);
   1.643 +  }
   1.644 +  else {
   1.645 +    nsCOMPtr<nsIContent> parent = GetCurrentContent();
   1.646 +
   1.647 +    if (parent) {
   1.648 +      result = parent->AppendChildTo(aContent, false);
   1.649 +    }
   1.650 +  }
   1.651 +  return result;
   1.652 +}
   1.653 +
   1.654 +// Create an XML parser and an XSL content sink and start parsing
   1.655 +// the XSL stylesheet located at the given URI.
   1.656 +nsresult
   1.657 +nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
   1.658 +{
   1.659 +  nsCOMPtr<nsIDocumentTransformer> processor =
   1.660 +    do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt");
   1.661 +  if (!processor) {
   1.662 +    // No XSLT processor available, continue normal document loading
   1.663 +    return NS_OK;
   1.664 +  }
   1.665 +
   1.666 +  processor->Init(mDocument->NodePrincipal());
   1.667 +  processor->SetTransformObserver(this);
   1.668 +
   1.669 +  nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
   1.670 +  if (!loadGroup) {
   1.671 +    return NS_ERROR_FAILURE;
   1.672 +  }
   1.673 +
   1.674 +  if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, loadGroup))) {
   1.675 +    mXSLTProcessor.swap(processor);
   1.676 +  }
   1.677 +
   1.678 +  // Intentionally ignore errors here, we should continue loading the
   1.679 +  // XML document whether we're able to load the XSLT stylesheet or
   1.680 +  // not.
   1.681 +
   1.682 +  return NS_OK;
   1.683 +}
   1.684 +
   1.685 +nsresult
   1.686 +nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
   1.687 +                                   const nsSubstring& aHref,
   1.688 +                                   bool aAlternate,
   1.689 +                                   const nsSubstring& aTitle,
   1.690 +                                   const nsSubstring& aType,
   1.691 +                                   const nsSubstring& aMedia)
   1.692 +{
   1.693 +  nsresult rv = NS_OK;
   1.694 +  mPrettyPrintXML = false;
   1.695 +
   1.696 +  nsAutoCString cmd;
   1.697 +  if (mParser)
   1.698 +    GetParser()->GetCommand(cmd);
   1.699 +  if (cmd.EqualsASCII(kLoadAsData))
   1.700 +    return NS_OK; // Do not load stylesheets when loading as data
   1.701 +
   1.702 +  NS_ConvertUTF16toUTF8 type(aType);
   1.703 +  if (type.EqualsIgnoreCase(TEXT_XSL) ||
   1.704 +      type.EqualsIgnoreCase(APPLICATION_XSLT_XML) ||
   1.705 +      type.EqualsIgnoreCase(TEXT_XML) ||
   1.706 +      type.EqualsIgnoreCase(APPLICATION_XML)) {
   1.707 +    if (aAlternate) {
   1.708 +      // don't load alternate XSLT
   1.709 +      return NS_OK;
   1.710 +    }
   1.711 +    // LoadXSLStyleSheet needs a mDocShell.
   1.712 +    if (!mDocShell)
   1.713 +      return NS_OK;
   1.714 +
   1.715 +    nsCOMPtr<nsIURI> url;
   1.716 +    rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
   1.717 +                   mDocument->GetDocBaseURI());
   1.718 +    NS_ENSURE_SUCCESS(rv, rv);
   1.719 +
   1.720 +    // Do security check
   1.721 +    nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
   1.722 +    rv = secMan->
   1.723 +      CheckLoadURIWithPrincipal(mDocument->NodePrincipal(), url,
   1.724 +                                nsIScriptSecurityManager::ALLOW_CHROME);
   1.725 +    NS_ENSURE_SUCCESS(rv, NS_OK);
   1.726 +
   1.727 +    // Do content policy check
   1.728 +    int16_t decision = nsIContentPolicy::ACCEPT;
   1.729 +    rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XSLT,
   1.730 +                                   url,
   1.731 +                                   mDocument->NodePrincipal(),
   1.732 +                                   aElement,
   1.733 +                                   type,
   1.734 +                                   nullptr,
   1.735 +                                   &decision,
   1.736 +                                   nsContentUtils::GetContentPolicy(),
   1.737 +                                   nsContentUtils::GetSecurityManager());
   1.738 +
   1.739 +    NS_ENSURE_SUCCESS(rv, rv);
   1.740 +
   1.741 +    if (NS_CP_REJECTED(decision)) {
   1.742 +      return NS_OK;
   1.743 +    }
   1.744 +
   1.745 +    return LoadXSLStyleSheet(url);
   1.746 +  }
   1.747 +
   1.748 +  // Let nsContentSink deal with css.
   1.749 +  rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
   1.750 +                                       aTitle, aType, aMedia);
   1.751 +
   1.752 +  // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
   1.753 +  // pending sheets.
   1.754 +  
   1.755 +  return rv;
   1.756 +}
   1.757 +
   1.758 +NS_IMETHODIMP 
   1.759 +nsXMLContentSink::SetDocumentCharset(nsACString& aCharset)
   1.760 +{
   1.761 +  if (mDocument) {
   1.762 +    mDocument->SetDocumentCharacterSet(aCharset);
   1.763 +  }
   1.764 +  
   1.765 +  return NS_OK;
   1.766 +}
   1.767 +
   1.768 +nsISupports *
   1.769 +nsXMLContentSink::GetTarget()
   1.770 +{
   1.771 +  return mDocument;
   1.772 +}
   1.773 +
   1.774 +bool
   1.775 +nsXMLContentSink::IsScriptExecuting()
   1.776 +{
   1.777 +  return IsScriptExecutingImpl();
   1.778 +}
   1.779 +
   1.780 +nsresult
   1.781 +nsXMLContentSink::FlushText(bool aReleaseTextNode)
   1.782 +{
   1.783 +  nsresult rv = NS_OK;
   1.784 +
   1.785 +  if (mTextLength != 0) {
   1.786 +    if (mLastTextNode) {
   1.787 +      if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) {
   1.788 +        mLastTextNodeSize = 0;
   1.789 +        mLastTextNode = nullptr;
   1.790 +        FlushText(aReleaseTextNode);
   1.791 +      } else {
   1.792 +        bool notify = HaveNotifiedForCurrentContent();
   1.793 +        // We could probably always increase mInNotification here since
   1.794 +        // if AppendText doesn't notify it shouldn't trigger evil code.
   1.795 +        // But just in case it does, we don't want to mask any notifications.
   1.796 +        if (notify) {
   1.797 +          ++mInNotification;
   1.798 +        }
   1.799 +        rv = mLastTextNode->AppendText(mText, mTextLength, notify);
   1.800 +        if (notify) {
   1.801 +          --mInNotification;
   1.802 +        }
   1.803 +
   1.804 +        mLastTextNodeSize += mTextLength;
   1.805 +        mTextLength = 0;
   1.806 +      }
   1.807 +    } else {
   1.808 +      nsRefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager);
   1.809 +
   1.810 +      mLastTextNode = textContent;
   1.811 +      
   1.812 +      // Set the text in the text node
   1.813 +      textContent->SetText(mText, mTextLength, false);
   1.814 +      mLastTextNodeSize += mTextLength;
   1.815 +      mTextLength = 0;
   1.816 +
   1.817 +      // Add text to its parent
   1.818 +      rv = AddContentAsLeaf(textContent);
   1.819 +    }
   1.820 +  }
   1.821 +
   1.822 +  if (aReleaseTextNode) {
   1.823 +    mLastTextNodeSize = 0;
   1.824 +    mLastTextNode = nullptr;
   1.825 +  }
   1.826 +  
   1.827 +  return rv;
   1.828 +}
   1.829 +
   1.830 +nsIContent*
   1.831 +nsXMLContentSink::GetCurrentContent()
   1.832 +{
   1.833 +  if (mContentStack.Length() == 0) {
   1.834 +    return nullptr;
   1.835 +  }
   1.836 +  return GetCurrentStackNode()->mContent;
   1.837 +}
   1.838 +
   1.839 +StackNode*
   1.840 +nsXMLContentSink::GetCurrentStackNode()
   1.841 +{
   1.842 +  int32_t count = mContentStack.Length();
   1.843 +  return count != 0 ? &mContentStack[count-1] : nullptr;
   1.844 +}
   1.845 +
   1.846 +
   1.847 +nsresult
   1.848 +nsXMLContentSink::PushContent(nsIContent *aContent)
   1.849 +{
   1.850 +  NS_PRECONDITION(aContent, "Null content being pushed!");
   1.851 +  StackNode *sn = mContentStack.AppendElement();
   1.852 +  NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
   1.853 +
   1.854 +  sn->mContent = aContent;
   1.855 +  sn->mNumFlushed = 0;
   1.856 +  return NS_OK;
   1.857 +}
   1.858 +
   1.859 +void
   1.860 +nsXMLContentSink::PopContent()
   1.861 +{
   1.862 +  int32_t count = mContentStack.Length();
   1.863 +
   1.864 +  if (count == 0) {
   1.865 +    NS_WARNING("Popping empty stack");
   1.866 +    return;
   1.867 +  }
   1.868 +
   1.869 +  mContentStack.RemoveElementAt(count - 1);
   1.870 +}
   1.871 +
   1.872 +bool
   1.873 +nsXMLContentSink::HaveNotifiedForCurrentContent() const
   1.874 +{
   1.875 +  uint32_t stackLength = mContentStack.Length();
   1.876 +  if (stackLength) {
   1.877 +    const StackNode& stackNode = mContentStack[stackLength - 1];
   1.878 +    nsIContent* parent = stackNode.mContent;
   1.879 +    return stackNode.mNumFlushed == parent->GetChildCount();
   1.880 +  }
   1.881 +  return true;
   1.882 +}
   1.883 +
   1.884 +void
   1.885 +nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
   1.886 +{
   1.887 +  // XXXbz if aIgnorePendingSheets is true, what should we do when
   1.888 +  // mXSLTProcessor or CanStillPrettyPrint()?
   1.889 +  if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) {
   1.890 +    return;
   1.891 +  }
   1.892 +  StartLayout(aIgnorePendingSheets);
   1.893 +}
   1.894 +
   1.895 +////////////////////////////////////////////////////////////////////////
   1.896 +
   1.897 +bool
   1.898 +nsXMLContentSink::SetDocElement(int32_t aNameSpaceID,
   1.899 +                                nsIAtom* aTagName,
   1.900 +                                nsIContent *aContent)
   1.901 +{
   1.902 +  if (mDocElement)
   1.903 +    return false;
   1.904 +
   1.905 +  // check for root elements that needs special handling for
   1.906 +  // prettyprinting
   1.907 +  if ((aNameSpaceID == kNameSpaceID_XBL &&
   1.908 +       aTagName == nsGkAtoms::bindings) ||
   1.909 +      (aNameSpaceID == kNameSpaceID_XSLT &&
   1.910 +       (aTagName == nsGkAtoms::stylesheet ||
   1.911 +        aTagName == nsGkAtoms::transform))) {
   1.912 +    mPrettyPrintHasSpecialRoot = true;
   1.913 +    if (mPrettyPrintXML) {
   1.914 +      // In this case, disable script execution, stylesheet
   1.915 +      // loading, and auto XLinks since we plan to prettyprint.
   1.916 +      mDocument->ScriptLoader()->SetEnabled(false);
   1.917 +      if (mCSSLoader) {
   1.918 +        mCSSLoader->SetEnabled(false);
   1.919 +      }
   1.920 +    }        
   1.921 +  }
   1.922 +
   1.923 +  mDocElement = aContent;
   1.924 +  nsresult rv = mDocument->AppendChildTo(mDocElement, NotifyForDocElement());
   1.925 +  if (NS_FAILED(rv)) {
   1.926 +    // If we return false here, the caller will bail out because it won't
   1.927 +    // find a parent content node to append to, which is fine.
   1.928 +    return false;
   1.929 +  }
   1.930 +
   1.931 +  if (aTagName == nsGkAtoms::html &&
   1.932 +      aNameSpaceID == kNameSpaceID_XHTML) {
   1.933 +    ProcessOfflineManifest(aContent);
   1.934 +  }
   1.935 +
   1.936 +  return true;
   1.937 +}
   1.938 +
   1.939 +NS_IMETHODIMP
   1.940 +nsXMLContentSink::HandleStartElement(const char16_t *aName,
   1.941 +                                     const char16_t **aAtts,
   1.942 +                                     uint32_t aAttsCount,
   1.943 +                                     int32_t aIndex,
   1.944 +                                     uint32_t aLineNumber)
   1.945 +{
   1.946 +  return HandleStartElement(aName, aAtts, aAttsCount, aIndex, aLineNumber,
   1.947 +                            true);
   1.948 +}
   1.949 +
   1.950 +nsresult
   1.951 +nsXMLContentSink::HandleStartElement(const char16_t *aName,
   1.952 +                                     const char16_t **aAtts,
   1.953 +                                     uint32_t aAttsCount,
   1.954 +                                     int32_t aIndex,
   1.955 +                                     uint32_t aLineNumber,
   1.956 +                                     bool aInterruptable)
   1.957 +{
   1.958 +  NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
   1.959 +  NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
   1.960 +  // Adjust aAttsCount so it's the actual number of attributes
   1.961 +  aAttsCount /= 2;
   1.962 +
   1.963 +  nsresult result = NS_OK;
   1.964 +  bool appendContent = true;
   1.965 +  nsCOMPtr<nsIContent> content;
   1.966 +
   1.967 +  // XXX Hopefully the parser will flag this before we get
   1.968 +  // here. If we're in the epilog, there should be no
   1.969 +  // new elements
   1.970 +  PR_ASSERT(eXMLContentSinkState_InEpilog != mState);
   1.971 +
   1.972 +  FlushText();
   1.973 +  DidAddContent();
   1.974 +
   1.975 +  mState = eXMLContentSinkState_InDocumentElement;
   1.976 +
   1.977 +  int32_t nameSpaceID;
   1.978 +  nsCOMPtr<nsIAtom> prefix, localName;
   1.979 +  nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
   1.980 +                                 getter_AddRefs(localName), &nameSpaceID);
   1.981 +
   1.982 +  if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName, aLineNumber)) {
   1.983 +    return NS_OK;
   1.984 +  }
   1.985 +  
   1.986 +  nsCOMPtr<nsINodeInfo> nodeInfo;
   1.987 +  nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
   1.988 +                                           nsIDOMNode::ELEMENT_NODE);
   1.989 +
   1.990 +  result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
   1.991 +                         getter_AddRefs(content), &appendContent,
   1.992 +                         FROM_PARSER_NETWORK);
   1.993 +  NS_ENSURE_SUCCESS(result, result);
   1.994 +
   1.995 +  // Have to do this before we push the new content on the stack... and have to
   1.996 +  // do that before we set attributes, call BindToTree, etc.  Ideally we'd push
   1.997 +  // on the stack inside CreateElement (which is effectively what the HTML sink
   1.998 +  // does), but that's hard with all the subclass overrides going on.
   1.999 +  nsCOMPtr<nsIContent> parent = GetCurrentContent();
  1.1000 +  
  1.1001 +  result = PushContent(content);
  1.1002 +  NS_ENSURE_SUCCESS(result, result);
  1.1003 +
  1.1004 +  // Set the ID attribute atom on the node info object for this node
  1.1005 +  // This must occur before the attributes are added so the name
  1.1006 +  // of the id attribute is known.
  1.1007 +  if (aIndex != -1 && NS_SUCCEEDED(result)) {
  1.1008 +    nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
  1.1009 +
  1.1010 +    if (IDAttr) {
  1.1011 +      nodeInfo->SetIDAttributeAtom(IDAttr);
  1.1012 +    }
  1.1013 +  }
  1.1014 +
  1.1015 +  // Set the attributes on the new content element
  1.1016 +  result = AddAttributes(aAtts, content);
  1.1017 +
  1.1018 +  if (NS_OK == result) {
  1.1019 +    // Store the element 
  1.1020 +    if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
  1.1021 +      NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
  1.1022 +
  1.1023 +      parent->AppendChildTo(content, false);
  1.1024 +    }
  1.1025 +  }
  1.1026 +
  1.1027 +  // Some HTML nodes need DoneCreatingElement() called to initialize
  1.1028 +  // properly (eg form state restoration).
  1.1029 +  if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML) {
  1.1030 +    if (nodeInfo->NameAtom() == nsGkAtoms::input ||
  1.1031 +        nodeInfo->NameAtom() == nsGkAtoms::button ||
  1.1032 +        nodeInfo->NameAtom() == nsGkAtoms::menuitem ||
  1.1033 +        nodeInfo->NameAtom() == nsGkAtoms::audio ||
  1.1034 +        nodeInfo->NameAtom() == nsGkAtoms::video) {
  1.1035 +      content->DoneCreatingElement();
  1.1036 +    } else if (nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) {
  1.1037 +      mCurrentHead = content;
  1.1038 +    }
  1.1039 +  }
  1.1040 +
  1.1041 +  if (IsMonolithicContainer(nodeInfo)) {
  1.1042 +    mInMonolithicContainer++;
  1.1043 +  }
  1.1044 +
  1.1045 +  if (content != mDocElement && !mCurrentHead) {
  1.1046 +    // This isn't the root and we're not inside an XHTML <head>.
  1.1047 +    // Might need to start layout
  1.1048 +    MaybeStartLayout(false);
  1.1049 +  }
  1.1050 +
  1.1051 +  if (content == mDocElement) {
  1.1052 +    NotifyDocElementCreated(mDocument);
  1.1053 +  }
  1.1054 +
  1.1055 +  return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
  1.1056 +                                                  result;
  1.1057 +}
  1.1058 +
  1.1059 +NS_IMETHODIMP
  1.1060 +nsXMLContentSink::HandleEndElement(const char16_t *aName)
  1.1061 +{
  1.1062 +  return HandleEndElement(aName, true);
  1.1063 +}
  1.1064 +
  1.1065 +nsresult
  1.1066 +nsXMLContentSink::HandleEndElement(const char16_t *aName,
  1.1067 +                                   bool aInterruptable)
  1.1068 +{
  1.1069 +  nsresult result = NS_OK;
  1.1070 +
  1.1071 +  // XXX Hopefully the parser will flag this before we get
  1.1072 +  // here. If we're in the prolog or epilog, there should be
  1.1073 +  // no close tags for elements.
  1.1074 +  PR_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
  1.1075 +
  1.1076 +  FlushText();
  1.1077 +
  1.1078 +  StackNode* sn = GetCurrentStackNode();
  1.1079 +  if (!sn) {
  1.1080 +    return NS_ERROR_UNEXPECTED;
  1.1081 +  }
  1.1082 +
  1.1083 +  nsCOMPtr<nsIContent> content;
  1.1084 +  sn->mContent.swap(content);
  1.1085 +  uint32_t numFlushed = sn->mNumFlushed;
  1.1086 +
  1.1087 +  PopContent();
  1.1088 +  NS_ASSERTION(content, "failed to pop content");
  1.1089 +#ifdef DEBUG
  1.1090 +  // Check that we're closing the right thing
  1.1091 +  nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom;
  1.1092 +  int32_t debugNameSpaceID;
  1.1093 +  nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
  1.1094 +                                 getter_AddRefs(debugTagAtom),
  1.1095 +                                 &debugNameSpaceID);
  1.1096 +  NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID),
  1.1097 +               "Wrong element being closed");
  1.1098 +#endif  
  1.1099 +
  1.1100 +  result = CloseElement(content);
  1.1101 +
  1.1102 +  if (mCurrentHead == content) {
  1.1103 +    mCurrentHead = nullptr;
  1.1104 +  }
  1.1105 +  
  1.1106 +  if (mDocElement == content) {
  1.1107 +    // XXXbz for roots that don't want to be appended on open, we
  1.1108 +    // probably need to deal here.... (and stop appending them on open).
  1.1109 +    mState = eXMLContentSinkState_InEpilog;
  1.1110 +
  1.1111 +    // We might have had no occasion to start layout yet.  Do so now.
  1.1112 +    MaybeStartLayout(false);
  1.1113 +  }
  1.1114 +
  1.1115 +  int32_t stackLen = mContentStack.Length();
  1.1116 +  if (mNotifyLevel >= stackLen) {
  1.1117 +    if (numFlushed < content->GetChildCount()) {
  1.1118 +    	  NotifyAppend(content, numFlushed);
  1.1119 +    }
  1.1120 +    mNotifyLevel = stackLen - 1;
  1.1121 +  }
  1.1122 +  DidAddContent();
  1.1123 +
  1.1124 +  if (content->IsSVG(nsGkAtoms::svg)) {
  1.1125 +    FlushTags();
  1.1126 +    nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content);
  1.1127 +    if (NS_FAILED(NS_DispatchToMainThread(event))) {
  1.1128 +      NS_WARNING("failed to dispatch svg load dispatcher");
  1.1129 +    }
  1.1130 +  }
  1.1131 +
  1.1132 +  return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
  1.1133 +                                                  result;
  1.1134 +}
  1.1135 +
  1.1136 +NS_IMETHODIMP 
  1.1137 +nsXMLContentSink::HandleComment(const char16_t *aName)
  1.1138 +{
  1.1139 +  FlushText();
  1.1140 +
  1.1141 +  nsRefPtr<Comment> comment = new Comment(mNodeInfoManager);
  1.1142 +  comment->SetText(nsDependentString(aName), false);
  1.1143 +  nsresult rv = AddContentAsLeaf(comment);
  1.1144 +  DidAddContent();
  1.1145 +
  1.1146 +  return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1.1147 +}
  1.1148 +
  1.1149 +NS_IMETHODIMP 
  1.1150 +nsXMLContentSink::HandleCDataSection(const char16_t *aData, 
  1.1151 +                                     uint32_t aLength)
  1.1152 +{
  1.1153 +  // XSLT doesn't differentiate between text and cdata and wants adjacent
  1.1154 +  // textnodes merged, so add as text.
  1.1155 +  if (mXSLTProcessor) {
  1.1156 +    return AddText(aData, aLength);
  1.1157 +  }
  1.1158 +
  1.1159 +  FlushText();
  1.1160 +  
  1.1161 +  nsRefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager);
  1.1162 +  cdata->SetText(aData, aLength, false);
  1.1163 +  nsresult rv = AddContentAsLeaf(cdata);
  1.1164 +  DidAddContent();
  1.1165 +
  1.1166 +  return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1.1167 +}
  1.1168 +
  1.1169 +NS_IMETHODIMP
  1.1170 +nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset, 
  1.1171 +                                    const nsAString & aName, 
  1.1172 +                                    const nsAString & aSystemId, 
  1.1173 +                                    const nsAString & aPublicId,
  1.1174 +                                    nsISupports* aCatalogData)
  1.1175 +{
  1.1176 +  FlushText();
  1.1177 +
  1.1178 +  nsresult rv = NS_OK;
  1.1179 +
  1.1180 +  NS_ASSERTION(mDocument, "Shouldn't get here from a document fragment");
  1.1181 +
  1.1182 +  nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
  1.1183 +  NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
  1.1184 +
  1.1185 +  // Create a new doctype node
  1.1186 +  nsCOMPtr<nsIDOMDocumentType> docType;
  1.1187 +  rv = NS_NewDOMDocumentType(getter_AddRefs(docType), mNodeInfoManager,
  1.1188 +                             name, aPublicId, aSystemId, aSubset);
  1.1189 +  if (NS_FAILED(rv) || !docType) {
  1.1190 +    return rv;
  1.1191 +  }
  1.1192 +
  1.1193 +  if (aCatalogData && mCSSLoader && mDocument) {
  1.1194 +    // bug 124570 - we only expect additional agent sheets for now -- ignore
  1.1195 +    // exit codes, error are not fatal here, just that the stylesheet won't apply
  1.1196 +    nsCOMPtr<nsIURI> uri(do_QueryInterface(aCatalogData));
  1.1197 +    if (uri) {
  1.1198 +      nsRefPtr<nsCSSStyleSheet> sheet;
  1.1199 +      mCSSLoader->LoadSheetSync(uri, true, true, getter_AddRefs(sheet));
  1.1200 +
  1.1201 +#ifdef DEBUG
  1.1202 +      nsAutoCString uriStr;
  1.1203 +      uri->GetSpec(uriStr);
  1.1204 +      printf("Loading catalog stylesheet: %s ... %s\n", uriStr.get(), sheet.get() ? "Done" : "Failed");
  1.1205 +#endif
  1.1206 +      if (sheet) {
  1.1207 +        mDocument->BeginUpdate(UPDATE_STYLE);
  1.1208 +        mDocument->AddCatalogStyleSheet(sheet);
  1.1209 +        mDocument->EndUpdate(UPDATE_STYLE);
  1.1210 +      }
  1.1211 +    }
  1.1212 +  }
  1.1213 +
  1.1214 +  nsCOMPtr<nsIContent> content = do_QueryInterface(docType);
  1.1215 +  NS_ASSERTION(content, "doctype isn't content?");
  1.1216 +
  1.1217 +  rv = mDocument->AppendChildTo(content, false);
  1.1218 +  DidAddContent();
  1.1219 +  return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1.1220 +}
  1.1221 +
  1.1222 +NS_IMETHODIMP
  1.1223 +nsXMLContentSink::HandleCharacterData(const char16_t *aData, 
  1.1224 +                                      uint32_t aLength)
  1.1225 +{
  1.1226 +  return HandleCharacterData(aData, aLength, true);
  1.1227 +}
  1.1228 +
  1.1229 +nsresult
  1.1230 +nsXMLContentSink::HandleCharacterData(const char16_t *aData, uint32_t aLength,
  1.1231 +                                      bool aInterruptable)
  1.1232 +{
  1.1233 +  nsresult rv = NS_OK;
  1.1234 +  if (aData && mState != eXMLContentSinkState_InProlog &&
  1.1235 +      mState != eXMLContentSinkState_InEpilog) {
  1.1236 +    rv = AddText(aData, aLength);
  1.1237 +  }
  1.1238 +  return aInterruptable && NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1.1239 +}
  1.1240 +
  1.1241 +NS_IMETHODIMP
  1.1242 +nsXMLContentSink::HandleProcessingInstruction(const char16_t *aTarget, 
  1.1243 +                                              const char16_t *aData)
  1.1244 +{
  1.1245 +  FlushText();
  1.1246 +
  1.1247 +  const nsDependentString target(aTarget);
  1.1248 +  const nsDependentString data(aData);
  1.1249 +
  1.1250 +  nsCOMPtr<nsIContent> node =
  1.1251 +    NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data);
  1.1252 +
  1.1253 +  nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node));
  1.1254 +  if (ssle) {
  1.1255 +    ssle->InitStyleLinkElement(false);
  1.1256 +    ssle->SetEnableUpdates(false);
  1.1257 +    mPrettyPrintXML = false;
  1.1258 +  }
  1.1259 +
  1.1260 +  nsresult rv = AddContentAsLeaf(node);
  1.1261 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1262 +  DidAddContent();
  1.1263 +
  1.1264 +  if (ssle) {
  1.1265 +    // This is an xml-stylesheet processing instruction... but it might not be
  1.1266 +    // a CSS one if the type is set to something else.
  1.1267 +    ssle->SetEnableUpdates(true);
  1.1268 +    bool willNotify;
  1.1269 +    bool isAlternate;
  1.1270 +    rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
  1.1271 +                                &willNotify,
  1.1272 +                                &isAlternate);
  1.1273 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1274 +    
  1.1275 +    if (willNotify) {
  1.1276 +      // Successfully started a stylesheet load
  1.1277 +      if (!isAlternate && !mRunsToCompletion) {
  1.1278 +        ++mPendingSheetCount;
  1.1279 +        mScriptLoader->AddExecuteBlocker();
  1.1280 +      }
  1.1281 +
  1.1282 +      return NS_OK;
  1.1283 +    }
  1.1284 +  }
  1.1285 +
  1.1286 +  // If it's not a CSS stylesheet PI...
  1.1287 +  nsAutoString type;
  1.1288 +  nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
  1.1289 +
  1.1290 +  if (mState != eXMLContentSinkState_InProlog ||
  1.1291 +      !target.EqualsLiteral("xml-stylesheet") ||
  1.1292 +      type.IsEmpty()                          ||
  1.1293 +      type.LowerCaseEqualsLiteral("text/css")) {
  1.1294 +    return DidProcessATokenImpl();
  1.1295 +  }
  1.1296 +
  1.1297 +  nsAutoString href, title, media;
  1.1298 +  bool isAlternate = false;
  1.1299 +
  1.1300 +  // If there was no href, we can't do anything with this PI
  1.1301 +  if (!ParsePIData(data, href, title, media, isAlternate)) {
  1.1302 +      return DidProcessATokenImpl();
  1.1303 +  }
  1.1304 +
  1.1305 +  rv = ProcessStyleLink(node, href, isAlternate, title, type, media);
  1.1306 +  return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1.1307 +}
  1.1308 +
  1.1309 +/* static */
  1.1310 +bool
  1.1311 +nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref,
  1.1312 +                              nsString &aTitle, nsString &aMedia,
  1.1313 +                              bool &aIsAlternate)
  1.1314 +{
  1.1315 +  // If there was no href, we can't do anything with this PI
  1.1316 +  if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) {
  1.1317 +    return false;
  1.1318 +  }
  1.1319 +
  1.1320 +  nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle);
  1.1321 +
  1.1322 +  nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia);
  1.1323 +
  1.1324 +  nsAutoString alternate;
  1.1325 +  nsContentUtils::GetPseudoAttributeValue(aData,
  1.1326 +                                          nsGkAtoms::alternate,
  1.1327 +                                          alternate);
  1.1328 +
  1.1329 +  aIsAlternate = alternate.EqualsLiteral("yes");
  1.1330 +
  1.1331 +  return true;
  1.1332 +}
  1.1333 +
  1.1334 +NS_IMETHODIMP
  1.1335 +nsXMLContentSink::HandleXMLDeclaration(const char16_t *aVersion,
  1.1336 +                                       const char16_t *aEncoding,
  1.1337 +                                       int32_t aStandalone)
  1.1338 +{
  1.1339 +  mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone);
  1.1340 +
  1.1341 +  return DidProcessATokenImpl();
  1.1342 +}
  1.1343 +
  1.1344 +NS_IMETHODIMP
  1.1345 +nsXMLContentSink::ReportError(const char16_t* aErrorText, 
  1.1346 +                              const char16_t* aSourceText,
  1.1347 +                              nsIScriptError *aError,
  1.1348 +                              bool *_retval)
  1.1349 +{
  1.1350 +  NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
  1.1351 +  nsresult rv = NS_OK;
  1.1352 +
  1.1353 +  // The expat driver should report the error.  We're just cleaning up the mess.
  1.1354 +  *_retval = true;
  1.1355 +  
  1.1356 +  mPrettyPrintXML = false;
  1.1357 +
  1.1358 +  mState = eXMLContentSinkState_InProlog;
  1.1359 +
  1.1360 +  // XXX need to stop scripts here -- hsivonen
  1.1361 +
  1.1362 +  // stop observing in order to avoid crashing when removing content
  1.1363 +  mDocument->RemoveObserver(this);
  1.1364 +  mIsDocumentObserver = false;
  1.1365 +
  1.1366 +  // Clear the current content and
  1.1367 +  // prepare to set <parsererror> as the document root
  1.1368 +  nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mDocument));
  1.1369 +  if (node) {
  1.1370 +    for (;;) {
  1.1371 +      nsCOMPtr<nsIDOMNode> child, dummy;
  1.1372 +      node->GetLastChild(getter_AddRefs(child));
  1.1373 +      if (!child)
  1.1374 +        break;
  1.1375 +      node->RemoveChild(child, getter_AddRefs(dummy));
  1.1376 +    }
  1.1377 +  }
  1.1378 +  mDocElement = nullptr;
  1.1379 +
  1.1380 +  // Clear any buffered-up text we have.  It's enough to set the length to 0.
  1.1381 +  // The buffer itself is allocated when we're created and deleted in our
  1.1382 +  // destructor, so don't mess with it.
  1.1383 +  mTextLength = 0;
  1.1384 +
  1.1385 +  if (mXSLTProcessor) {
  1.1386 +    // Get rid of the XSLT processor.
  1.1387 +    mXSLTProcessor->CancelLoads();
  1.1388 +    mXSLTProcessor = nullptr;
  1.1389 +  }
  1.1390 +
  1.1391 +  // release the nodes on stack
  1.1392 +  mContentStack.Clear();
  1.1393 +  mNotifyLevel = 0;
  1.1394 +
  1.1395 +  rv = HandleProcessingInstruction(MOZ_UTF16("xml-stylesheet"),
  1.1396 +                                   MOZ_UTF16("href=\"chrome://global/locale/intl.css\" type=\"text/css\""));
  1.1397 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1398 +
  1.1399 +  const char16_t* noAtts[] = { 0, 0 };
  1.1400 +
  1.1401 +  NS_NAMED_LITERAL_STRING(errorNs,
  1.1402 +                          "http://www.mozilla.org/newlayout/xml/parsererror.xml");
  1.1403 +
  1.1404 +  nsAutoString parsererror(errorNs);
  1.1405 +  parsererror.Append((char16_t)0xFFFF);
  1.1406 +  parsererror.AppendLiteral("parsererror");
  1.1407 +  
  1.1408 +  rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, (uint32_t)-1,
  1.1409 +                          false);
  1.1410 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1411 +
  1.1412 +  rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false);
  1.1413 +  NS_ENSURE_SUCCESS(rv, rv);  
  1.1414 +  
  1.1415 +  nsAutoString sourcetext(errorNs);
  1.1416 +  sourcetext.Append((char16_t)0xFFFF);
  1.1417 +  sourcetext.AppendLiteral("sourcetext");
  1.1418 +
  1.1419 +  rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, (uint32_t)-1,
  1.1420 +                          false);
  1.1421 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1422 +  
  1.1423 +  rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText), false);
  1.1424 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1425 +  
  1.1426 +  rv = HandleEndElement(sourcetext.get(), false);
  1.1427 +  NS_ENSURE_SUCCESS(rv, rv); 
  1.1428 +  
  1.1429 +  rv = HandleEndElement(parsererror.get(), false);
  1.1430 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1431 +
  1.1432 +  FlushTags();
  1.1433 +
  1.1434 +  return NS_OK;
  1.1435 +}
  1.1436 +
  1.1437 +nsresult
  1.1438 +nsXMLContentSink::AddAttributes(const char16_t** aAtts,
  1.1439 +                                nsIContent* aContent)
  1.1440 +{
  1.1441 +  // Add tag attributes to the content attributes
  1.1442 +  nsCOMPtr<nsIAtom> prefix, localName;
  1.1443 +  while (*aAtts) {
  1.1444 +    int32_t nameSpaceID;
  1.1445 +    nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
  1.1446 +                                   getter_AddRefs(localName), &nameSpaceID);
  1.1447 +
  1.1448 +    // Add attribute to content
  1.1449 +    aContent->SetAttr(nameSpaceID, localName, prefix,
  1.1450 +                      nsDependentString(aAtts[1]), false);
  1.1451 +    aAtts += 2;
  1.1452 +  }
  1.1453 +
  1.1454 +  return NS_OK;
  1.1455 +}
  1.1456 +
  1.1457 +#define NS_ACCUMULATION_BUFFER_SIZE 4096
  1.1458 +
  1.1459 +nsresult
  1.1460 +nsXMLContentSink::AddText(const char16_t* aText, 
  1.1461 +                          int32_t aLength)
  1.1462 +{
  1.1463 +  // Create buffer when we first need it
  1.1464 +  if (0 == mTextSize) {
  1.1465 +    mText = (char16_t *) PR_MALLOC(sizeof(char16_t) * NS_ACCUMULATION_BUFFER_SIZE);
  1.1466 +    if (nullptr == mText) {
  1.1467 +      return NS_ERROR_OUT_OF_MEMORY;
  1.1468 +    }
  1.1469 +    mTextSize = NS_ACCUMULATION_BUFFER_SIZE;
  1.1470 +  }
  1.1471 +
  1.1472 +  // Copy data from string into our buffer; flush buffer when it fills up
  1.1473 +  int32_t offset = 0;
  1.1474 +  while (0 != aLength) {
  1.1475 +    int32_t amount = mTextSize - mTextLength;
  1.1476 +    if (0 == amount) {
  1.1477 +      // XSLT wants adjacent textnodes merged.
  1.1478 +      if (mConstrainSize && !mXSLTProcessor) {
  1.1479 +        nsresult rv = FlushText();
  1.1480 +        if (NS_OK != rv) {
  1.1481 +          return rv;
  1.1482 +        }
  1.1483 +
  1.1484 +        amount = mTextSize - mTextLength;
  1.1485 +      }
  1.1486 +      else {
  1.1487 +        mTextSize += aLength;
  1.1488 +        mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize);
  1.1489 +        if (nullptr == mText) {
  1.1490 +          mTextSize = 0;
  1.1491 +
  1.1492 +          return NS_ERROR_OUT_OF_MEMORY;
  1.1493 +        }
  1.1494 +
  1.1495 +        amount = aLength;
  1.1496 +      }
  1.1497 +    }
  1.1498 +    if (amount > aLength) {
  1.1499 +      amount = aLength;
  1.1500 +    }
  1.1501 +    memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount);
  1.1502 +    mTextLength += amount;
  1.1503 +    offset += amount;
  1.1504 +    aLength -= amount;
  1.1505 +  }
  1.1506 +
  1.1507 +  return NS_OK;
  1.1508 +}
  1.1509 +
  1.1510 +void
  1.1511 +nsXMLContentSink::FlushPendingNotifications(mozFlushType aType)
  1.1512 +{
  1.1513 +  // Only flush tags if we're not doing the notification ourselves
  1.1514 +  // (since we aren't reentrant)
  1.1515 +  if (!mInNotification) {
  1.1516 +    if (mIsDocumentObserver) {
  1.1517 +      // Only flush if we're still a document observer (so that our child
  1.1518 +      // counts should be correct).
  1.1519 +      if (aType >= Flush_ContentAndNotify) {
  1.1520 +        FlushTags();
  1.1521 +      }
  1.1522 +      else {
  1.1523 +        FlushText(false);
  1.1524 +      }
  1.1525 +    }
  1.1526 +    if (aType >= Flush_InterruptibleLayout) {
  1.1527 +      // Make sure that layout has started so that the reflow flush
  1.1528 +      // will actually happen.
  1.1529 +      MaybeStartLayout(true);
  1.1530 +    }
  1.1531 +  }
  1.1532 +}
  1.1533 +
  1.1534 +/**
  1.1535 + * NOTE!! Forked from SinkContext. Please keep in sync.
  1.1536 + *
  1.1537 + * Flush all elements that have been seen so far such that
  1.1538 + * they are visible in the tree. Specifically, make sure
  1.1539 + * that they are all added to their respective parents.
  1.1540 + * Also, do notification at the top for all content that
  1.1541 + * has been newly added so that the frame tree is complete.
  1.1542 + */
  1.1543 +nsresult
  1.1544 +nsXMLContentSink::FlushTags()
  1.1545 +{
  1.1546 +  mDeferredFlushTags = false;
  1.1547 +  bool oldBeganUpdate = mBeganUpdate;
  1.1548 +  uint32_t oldUpdates = mUpdatesInNotification;
  1.1549 +
  1.1550 +  mUpdatesInNotification = 0;
  1.1551 +  ++mInNotification;
  1.1552 +  {
  1.1553 +    // Scope so we call EndUpdate before we decrease mInNotification
  1.1554 +    mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, true);
  1.1555 +    mBeganUpdate = true;
  1.1556 +
  1.1557 +    // Don't release last text node in case we need to add to it again
  1.1558 +    FlushText(false);
  1.1559 +
  1.1560 +    // Start from the base of the stack (growing downward) and do
  1.1561 +    // a notification from the node that is closest to the root of
  1.1562 +    // tree for any content that has been added.
  1.1563 +
  1.1564 +    int32_t stackPos;
  1.1565 +    int32_t stackLen = mContentStack.Length();
  1.1566 +    bool flushed = false;
  1.1567 +    uint32_t childCount;
  1.1568 +    nsIContent* content;
  1.1569 +
  1.1570 +    for (stackPos = 0; stackPos < stackLen; ++stackPos) {
  1.1571 +      content = mContentStack[stackPos].mContent;
  1.1572 +      childCount = content->GetChildCount();
  1.1573 +
  1.1574 +      if (!flushed && (mContentStack[stackPos].mNumFlushed < childCount)) {
  1.1575 +        NotifyAppend(content, mContentStack[stackPos].mNumFlushed);
  1.1576 +        flushed = true;
  1.1577 +      }
  1.1578 +
  1.1579 +      mContentStack[stackPos].mNumFlushed = childCount;
  1.1580 +    }
  1.1581 +    mNotifyLevel = stackLen - 1;
  1.1582 +  }
  1.1583 +  --mInNotification;
  1.1584 +
  1.1585 +  if (mUpdatesInNotification > 1) {
  1.1586 +    UpdateChildCounts();
  1.1587 +  }
  1.1588 +
  1.1589 +  mUpdatesInNotification = oldUpdates;
  1.1590 +  mBeganUpdate = oldBeganUpdate;
  1.1591 +  
  1.1592 +  return NS_OK;
  1.1593 +}
  1.1594 +
  1.1595 +/**
  1.1596 + * NOTE!! Forked from SinkContext. Please keep in sync.
  1.1597 + */
  1.1598 +void
  1.1599 +nsXMLContentSink::UpdateChildCounts()
  1.1600 +{
  1.1601 +  // Start from the top of the stack (growing upwards) and see if any
  1.1602 +  // new content has been appended. If so, we recognize that reflows
  1.1603 +  // have been generated for it and we should make sure that no
  1.1604 +  // further reflows occur.  Note that we have to include stackPos == 0
  1.1605 +  // to properly notify on kids of <html>.
  1.1606 +  int32_t stackLen = mContentStack.Length();
  1.1607 +  int32_t stackPos = stackLen - 1;
  1.1608 +  while (stackPos >= 0) {
  1.1609 +    StackNode & node = mContentStack[stackPos];
  1.1610 +    node.mNumFlushed = node.mContent->GetChildCount();
  1.1611 +
  1.1612 +    stackPos--;
  1.1613 +  }
  1.1614 +  mNotifyLevel = stackLen - 1;
  1.1615 +}
  1.1616 +
  1.1617 +bool
  1.1618 +nsXMLContentSink::IsMonolithicContainer(nsINodeInfo* aNodeInfo)
  1.1619 +{
  1.1620 +  return ((aNodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
  1.1621 +          (aNodeInfo->NameAtom() == nsGkAtoms::tr ||
  1.1622 +           aNodeInfo->NameAtom() == nsGkAtoms::select ||
  1.1623 +           aNodeInfo->NameAtom() == nsGkAtoms::object ||
  1.1624 +           aNodeInfo->NameAtom() == nsGkAtoms::applet)) ||
  1.1625 +          (aNodeInfo->NamespaceID() == kNameSpaceID_MathML &&
  1.1626 +          (aNodeInfo->NameAtom() == nsGkAtoms::math))
  1.1627 +          );
  1.1628 +}
  1.1629 +
  1.1630 +void
  1.1631 +nsXMLContentSink::ContinueInterruptedParsingIfEnabled()
  1.1632 +{
  1.1633 +  if (mParser && mParser->IsParserEnabled()) {
  1.1634 +    GetParser()->ContinueInterruptedParsing();
  1.1635 +  }
  1.1636 +}
  1.1637 +
  1.1638 +void
  1.1639 +nsXMLContentSink::ContinueInterruptedParsingAsync()
  1.1640 +{
  1.1641 +  nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
  1.1642 +    &nsXMLContentSink::ContinueInterruptedParsingIfEnabled);
  1.1643 +
  1.1644 +  NS_DispatchToCurrentThread(ev);
  1.1645 +}
  1.1646 +
  1.1647 +nsIParser*
  1.1648 +nsXMLContentSink::GetParser()
  1.1649 +{
  1.1650 +  return static_cast<nsIParser*>(mParser.get());
  1.1651 +}

mercurial