content/xml/document/src/nsXMLContentSink.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=78: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsCOMPtr.h"
     8 #include "nsXMLContentSink.h"
     9 #include "nsIParser.h"
    10 #include "nsIDocument.h"
    11 #include "nsIDOMDocument.h"
    12 #include "nsIDOMDocumentType.h"
    13 #include "nsIContent.h"
    14 #include "nsIURI.h"
    15 #include "nsNetUtil.h"
    16 #include "nsIDocShell.h"
    17 #include "nsIStyleSheetLinkingElement.h"
    18 #include "nsIDOMComment.h"
    19 #include "nsIDOMCDATASection.h"
    20 #include "DocumentType.h"
    21 #include "nsHTMLParts.h"
    22 #include "nsCRT.h"
    23 #include "nsCSSStyleSheet.h"
    24 #include "mozilla/css/Loader.h"
    25 #include "nsGkAtoms.h"
    26 #include "nsContentUtils.h"
    27 #include "nsIScriptContext.h"
    28 #include "nsNameSpaceManager.h"
    29 #include "nsIServiceManager.h"
    30 #include "nsIScriptSecurityManager.h"
    31 #include "nsIContentViewer.h"
    32 #include "prtime.h"
    33 #include "prlog.h"
    34 #include "prmem.h"
    35 #include "nsRect.h"
    36 #include "nsIWebNavigation.h"
    37 #include "nsIScriptElement.h"
    38 #include "nsScriptLoader.h"
    39 #include "nsStyleLinkElement.h"
    40 #include "nsReadableUtils.h"
    41 #include "nsUnicharUtils.h"
    42 #include "nsICookieService.h"
    43 #include "nsIPrompt.h"
    44 #include "nsIChannel.h"
    45 #include "nsIPrincipal.h"
    46 #include "nsXMLPrettyPrinter.h"
    47 #include "nsNodeInfoManager.h"
    48 #include "nsContentCreatorFunctions.h"
    49 #include "nsIContentPolicy.h"
    50 #include "nsContentPolicyUtils.h"
    51 #include "nsError.h"
    52 #include "nsIDOMProcessingInstruction.h"
    53 #include "nsNodeUtils.h"
    54 #include "nsIScriptGlobalObject.h"
    55 #include "nsIHTMLDocument.h"
    56 #include "mozAutoDocUpdate.h"
    57 #include "nsMimeTypes.h"
    58 #include "nsHtml5SVGLoadDispatcher.h"
    59 #include "nsTextNode.h"
    60 #include "mozilla/dom/CDATASection.h"
    61 #include "mozilla/dom/Comment.h"
    62 #include "mozilla/dom/Element.h"
    63 #include "mozilla/dom/ProcessingInstruction.h"
    65 using namespace mozilla::dom;
    67 // XXX Open Issues:
    68 // 1) what's not allowed - We need to figure out which HTML tags
    69 //    (prefixed with a HTML namespace qualifier) are explicitly not
    70 //    allowed (if any).
    71 // 2) factoring code with nsHTMLContentSink - There's some amount of
    72 //    common code between this and the HTML content sink. This will
    73 //    increase as we support more and more HTML elements. How can code
    74 //    from the code be factored?
    76 nsresult
    77 NS_NewXMLContentSink(nsIXMLContentSink** aResult,
    78                      nsIDocument* aDoc,
    79                      nsIURI* aURI,
    80                      nsISupports* aContainer,
    81                      nsIChannel* aChannel)
    82 {
    83   NS_PRECONDITION(nullptr != aResult, "null ptr");
    84   if (nullptr == aResult) {
    85     return NS_ERROR_NULL_POINTER;
    86   }
    87   nsXMLContentSink* it = new nsXMLContentSink();
    89   nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
    90   nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
    91   NS_ENSURE_SUCCESS(rv, rv);
    93   return CallQueryInterface(it, aResult);
    94 }
    96 nsXMLContentSink::nsXMLContentSink()
    97   : mConstrainSize(true),
    98     mPrettyPrintXML(true)
    99 {
   100 }
   102 nsXMLContentSink::~nsXMLContentSink()
   103 {
   104   if (mText) {
   105     PR_Free(mText);  //  Doesn't null out, unlike PR_FREEIF
   106   }
   107 }
   109 nsresult
   110 nsXMLContentSink::Init(nsIDocument* aDoc,
   111                        nsIURI* aURI,
   112                        nsISupports* aContainer,
   113                        nsIChannel* aChannel)
   114 {
   115   nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
   116   NS_ENSURE_SUCCESS(rv, rv);
   118   aDoc->AddObserver(this);
   119   mIsDocumentObserver = true;
   121   if (!mDocShell) {
   122     mPrettyPrintXML = false;
   123   }
   125   mState = eXMLContentSinkState_InProlog;
   126   mDocElement = nullptr;
   128   return NS_OK;
   129 }
   131 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink)
   132   NS_INTERFACE_MAP_ENTRY(nsIContentSink)
   133   NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
   134   NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
   135   NS_INTERFACE_MAP_ENTRY(nsITransformObserver)
   136 NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
   138 NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink)
   139 NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink)
   141 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink)
   143 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink,
   144                                                   nsContentSink)
   145   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentHead)
   146   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocElement)
   147   for (uint32_t i = 0, count = tmp->mContentStack.Length(); i < count; i++) {
   148     const StackNode& node = tmp->mContentStack.ElementAt(i);
   149     cb.NoteXPCOMChild(node.mContent);
   150   }
   151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   153 // nsIContentSink
   154 NS_IMETHODIMP
   155 nsXMLContentSink::WillParse(void)
   156 {
   157   return WillParseImpl();
   158 }
   160 NS_IMETHODIMP
   161 nsXMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
   162 {
   163   WillBuildModelImpl();
   165   // Notify document that the load is beginning
   166   mDocument->BeginLoad();
   168   // Check for correct load-command for maybe prettyprinting
   169   if (mPrettyPrintXML) {
   170     nsAutoCString command;
   171     GetParser()->GetCommand(command);
   172     if (!command.EqualsLiteral("view")) {
   173       mPrettyPrintXML = false;
   174     }
   175   }
   177   return NS_OK;
   178 }
   180 bool
   181 nsXMLContentSink::CanStillPrettyPrint()
   182 {
   183   return mPrettyPrintXML &&
   184          (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot);
   185 }
   187 nsresult
   188 nsXMLContentSink::MaybePrettyPrint()
   189 {
   190   if (!CanStillPrettyPrint()) {
   191     mPrettyPrintXML = false;
   193     return NS_OK;
   194   }
   196   // stop observing in order to avoid crashing when replacing content
   197   mDocument->RemoveObserver(this);
   198   mIsDocumentObserver = false;
   200   // Reenable the CSSLoader so that the prettyprinting stylesheets can load
   201   if (mCSSLoader) {
   202     mCSSLoader->SetEnabled(true);
   203   }
   205   nsRefPtr<nsXMLPrettyPrinter> printer;
   206   nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer));
   207   NS_ENSURE_SUCCESS(rv, rv);
   209   bool isPrettyPrinting;
   210   rv = printer->PrettyPrint(mDocument, &isPrettyPrinting);
   211   NS_ENSURE_SUCCESS(rv, rv);
   213   mPrettyPrinting = isPrettyPrinting;
   214   return NS_OK;
   215 }
   217 static void
   218 CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
   219                  nsIDocumentTransformer* aProcessor,
   220                  nsIDocument* aDocument)
   221 {
   222   nsAutoString target, data;
   223   aPi->GetTarget(target);
   225   // Check for namespace declarations
   226   if (target.EqualsLiteral("xslt-param-namespace")) {
   227     aPi->GetData(data);
   228     nsAutoString prefix, namespaceAttr;
   229     nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix,
   230                                             prefix);
   231     if (!prefix.IsEmpty() &&
   232         nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
   233                                                 namespaceAttr)) {
   234       aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
   235     }
   236   }
   238   // Check for actual parameters
   239   else if (target.EqualsLiteral("xslt-param")) {
   240     aPi->GetData(data);
   241     nsAutoString name, namespaceAttr, select, value;
   242     nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name,
   243                                             name);
   244     nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
   245                                             namespaceAttr);
   246     if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) {
   247       select.SetIsVoid(true);
   248     }
   249     if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) {
   250       value.SetIsVoid(true);
   251     }
   252     if (!name.IsEmpty()) {
   253       nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
   254       aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc);
   255     }
   256   }
   257 }
   259 NS_IMETHODIMP
   260 nsXMLContentSink::DidBuildModel(bool aTerminated)
   261 {
   262   if (!mParser) {
   263     // If mParser is null, this parse has already been terminated and must
   264     // not been terminated again. However, nsDocument may still think that
   265     // the parse has not been terminated and call back into here in the case
   266     // where the XML parser has finished but the XSLT transform associated
   267     // with the document has not.
   268     return NS_OK;
   269   }
   271   DidBuildModelImpl(aTerminated);
   273   if (mXSLTProcessor) {
   274     // stop observing in order to avoid crashing when replacing content
   275     mDocument->RemoveObserver(this);
   276     mIsDocumentObserver = false;
   278     // Check for xslt-param and xslt-param-namespace PIs
   279     for (nsIContent* child = mDocument->GetFirstChild();
   280          child;
   281          child = child->GetNextSibling()) {
   282       if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
   283         nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
   284         CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
   285       }
   286       else if (child->IsElement()) {
   287         // Only honor PIs in the prolog
   288         break;
   289       }
   290     }
   292     nsCOMPtr<nsIDOMDocument> currentDOMDoc(do_QueryInterface(mDocument));
   293     mXSLTProcessor->SetSourceContentModel(currentDOMDoc);
   294     // Since the processor now holds a reference to us we drop our reference
   295     // to it to avoid owning cycles
   296     mXSLTProcessor = nullptr;
   297   }
   298   else {
   299     // Kick off layout for non-XSLT transformed documents.
   301     // Check if we want to prettyprint
   302     MaybePrettyPrint();
   304     bool startLayout = true;
   306     if (mPrettyPrinting) {
   307       NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
   309       // We're pretty-printing now.  See whether we should wait up on
   310       // stylesheet loads
   311       if (mDocument->CSSLoader()->HasPendingLoads() &&
   312           NS_SUCCEEDED(mDocument->CSSLoader()->AddObserver(this))) {
   313         // wait for those sheets to load
   314         startLayout = false;
   315       }
   316     }
   318     if (startLayout) {
   319       StartLayout(false);
   321       ScrollToRef();
   322     }
   324     mDocument->RemoveObserver(this);
   325     mIsDocumentObserver = false;
   327     mDocument->EndLoad();
   328   }
   330   DropParserAndPerfHint();
   332   return NS_OK;
   333 }
   335 NS_IMETHODIMP
   336 nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument)
   337 {
   338   NS_ENSURE_ARG(aResultDocument);
   340   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aResultDocument);
   341   if (htmlDoc) {
   342     htmlDoc->SetDocWriteDisabled(true);
   343   }
   345   nsCOMPtr<nsIContentViewer> contentViewer;
   346   mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
   347   if (contentViewer) {
   348     return contentViewer->SetDocumentInternal(aResultDocument, true);
   349   }
   350   return NS_OK;
   351 }
   353 NS_IMETHODIMP
   354 nsXMLContentSink::OnTransformDone(nsresult aResult,
   355                                   nsIDocument* aResultDocument)
   356 {
   357   NS_ASSERTION(NS_FAILED(aResult) || aResultDocument,
   358                "Don't notify about transform success without a document.");
   360   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aResultDocument);
   362   nsCOMPtr<nsIContentViewer> contentViewer;
   363   mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
   365   if (NS_FAILED(aResult) && contentViewer) {
   366     // Transform failed.
   367     if (domDoc) {
   368       aResultDocument->SetMayStartLayout(false);
   369       // We have an error document.
   370       contentViewer->SetDOMDocument(domDoc);
   371     }
   372     else {
   373       // We don't have an error document, display the
   374       // untransformed source document.
   375       nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument);
   376       contentViewer->SetDOMDocument(document);
   377     }
   378   }
   380   nsCOMPtr<nsIDocument> originalDocument = mDocument;
   381   if (NS_SUCCEEDED(aResult) || aResultDocument) {
   382     // Transform succeeded or it failed and we have an error
   383     // document to display.
   384     mDocument = aResultDocument;
   385     nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
   386     if (htmlDoc) {
   387       htmlDoc->SetDocWriteDisabled(false);
   388     }
   389   }
   391   // Notify document observers that all the content has been stuck
   392   // into the document.  
   393   // XXX do we need to notify for things like PIs?  Or just the
   394   // documentElement?
   395   nsIContent *rootElement = mDocument->GetRootElement();
   396   if (rootElement) {
   397     NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
   398                  "rootElement not in doc?");
   399     mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
   400     nsNodeUtils::ContentInserted(mDocument, rootElement,
   401                                  mDocument->IndexOf(rootElement));
   402     mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
   403   }
   405   // Start the layout process
   406   StartLayout(false);
   408   ScrollToRef();
   410   originalDocument->EndLoad();
   412   return NS_OK;
   413 }
   415 NS_IMETHODIMP
   416 nsXMLContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
   417                                    bool aWasAlternate,
   418                                    nsresult aStatus)
   419 {
   420   if (!mPrettyPrinting) {
   421     return nsContentSink::StyleSheetLoaded(aSheet, aWasAlternate, aStatus);
   422   }
   424   if (!mDocument->CSSLoader()->HasPendingLoads()) {
   425     mDocument->CSSLoader()->RemoveObserver(this);
   426     StartLayout(false);
   427     ScrollToRef();
   428   }
   430   return NS_OK;
   431 }
   433 NS_IMETHODIMP
   434 nsXMLContentSink::WillInterrupt(void)
   435 {
   436   return WillInterruptImpl();
   437 }
   439 NS_IMETHODIMP
   440 nsXMLContentSink::WillResume(void)
   441 {
   442   return WillResumeImpl();
   443 }
   445 NS_IMETHODIMP
   446 nsXMLContentSink::SetParser(nsParserBase* aParser)
   447 {
   448   NS_PRECONDITION(aParser, "Should have a parser here!");
   449   mParser = aParser;
   450   return NS_OK;
   451 }
   453 nsresult
   454 nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
   455                                 nsINodeInfo* aNodeInfo, uint32_t aLineNumber,
   456                                 nsIContent** aResult, bool* aAppendContent,
   457                                 FromParser aFromParser)
   458 {
   459   NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
   461   *aResult = nullptr;
   462   *aAppendContent = true;
   463   nsresult rv = NS_OK;
   465   nsCOMPtr<nsINodeInfo> ni = aNodeInfo;
   466   nsCOMPtr<Element> content;
   467   rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
   468   NS_ENSURE_SUCCESS(rv, rv);
   470   if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
   471       || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
   472     ) {
   473     nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
   474     sele->SetScriptLineNumber(aLineNumber);
   475     sele->SetCreatorParser(GetParser());
   476     mConstrainSize = false;
   477   }
   479   // XHTML needs some special attention
   480   if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
   481     mPrettyPrintHasFactoredElements = true;
   482   }
   483   else {
   484     // If we care, find out if we just used a special factory.
   485     if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
   486         mPrettyPrintXML) {
   487       mPrettyPrintHasFactoredElements =
   488         nsContentUtils::NameSpaceManager()->
   489           HasElementCreator(aNodeInfo->NamespaceID());
   490     }
   492     if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
   493       content.forget(aResult);
   495       return NS_OK;
   496     }
   497   }
   499   if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
   500       aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
   501       aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
   502     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
   503     if (ssle) {
   504       ssle->InitStyleLinkElement(false);
   505       if (aFromParser) {
   506         ssle->SetEnableUpdates(false);
   507       }
   508       if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
   509         ssle->SetLineNumber(aFromParser ? aLineNumber : 0);
   510       }
   511     }
   512   } 
   514   content.forget(aResult);
   516   return NS_OK;
   517 }
   520 nsresult
   521 nsXMLContentSink::CloseElement(nsIContent* aContent)
   522 {
   523   NS_ASSERTION(aContent, "missing element to close");
   525   nsINodeInfo *nodeInfo = aContent->NodeInfo();
   527   // Some HTML nodes need DoneAddingChildren() called to initialize
   528   // properly (eg form state restoration).
   529   if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
   530        (nodeInfo->NameAtom() == nsGkAtoms::select ||
   531         nodeInfo->NameAtom() == nsGkAtoms::textarea ||
   532         nodeInfo->NameAtom() == nsGkAtoms::video ||
   533         nodeInfo->NameAtom() == nsGkAtoms::audio ||
   534         nodeInfo->NameAtom() == nsGkAtoms::object ||
   535         nodeInfo->NameAtom() == nsGkAtoms::applet))
   536       || nodeInfo->NameAtom() == nsGkAtoms::title
   537       ) {
   538     aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
   539   }
   541   if (IsMonolithicContainer(nodeInfo)) {
   542     mInMonolithicContainer--;
   543   }
   545   if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
   546       !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
   547     return NS_OK;
   548   }
   550   if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
   551       || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
   552     ) {
   553     mConstrainSize = true; 
   554     nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
   556     if (mPreventScriptExecution) {
   557       sele->PreventExecution();
   558       return NS_OK;
   559     }
   561     // Always check the clock in nsContentSink right after a script
   562     StopDeflecting();
   564     // Now tell the script that it's ready to go. This may execute the script
   565     // or return true, or neither if the script doesn't need executing.
   566     bool block = sele->AttemptToExecute();
   568     // If the parser got blocked, make sure to return the appropriate rv.
   569     // I'm not sure if this is actually needed or not.
   570     if (mParser && !mParser->IsParserEnabled()) {
   571       // XXX The HTML sink doesn't call BlockParser here, why do we?
   572       GetParser()->BlockParser();
   573       block = true;
   574     }
   576     return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
   577   }
   579   nsresult rv = NS_OK;
   580   if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
   581            // Need to check here to make sure this meta tag does not set
   582            // mPrettyPrintXML to false when we have a special root!
   583            (!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
   584     rv = ProcessMETATag(aContent);
   585   }
   586   else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
   587            nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
   588            nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
   589     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
   590     if (ssle) {
   591       ssle->SetEnableUpdates(true);
   592       bool willNotify;
   593       bool isAlternate;
   594       rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
   595                                   &willNotify,
   596                                   &isAlternate);
   597       if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
   598         ++mPendingSheetCount;
   599         mScriptLoader->AddExecuteBlocker();
   600       }
   601     }
   602     // Look for <link rel="dns-prefetch" href="hostname">
   603     // and look for <link rel="next" href="hostname"> like in HTML sink
   604     if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
   605       nsAutoString relVal;
   606       aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
   607       if (!relVal.IsEmpty()) {
   608         uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal);
   609         bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
   610         if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
   611           nsAutoString hrefVal;
   612           aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
   613           if (!hrefVal.IsEmpty()) {
   614             PrefetchHref(hrefVal, aContent, hasPrefetch);
   615           }
   616         }
   617         if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
   618           nsAutoString hrefVal;
   619           aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
   620           if (!hrefVal.IsEmpty()) {
   621             PrefetchDNS(hrefVal);
   622           }
   623         }
   624       }
   625     }
   626   }
   628   return rv;
   629 }  
   631 nsresult
   632 nsXMLContentSink::AddContentAsLeaf(nsIContent *aContent)
   633 {
   634   nsresult result = NS_OK;
   636   if ((eXMLContentSinkState_InProlog == mState) ||
   637       (eXMLContentSinkState_InEpilog == mState)) {
   638     NS_ASSERTION(mDocument, "Fragments have no prolog or epilog");
   639     mDocument->AppendChildTo(aContent, false);
   640   }
   641   else {
   642     nsCOMPtr<nsIContent> parent = GetCurrentContent();
   644     if (parent) {
   645       result = parent->AppendChildTo(aContent, false);
   646     }
   647   }
   648   return result;
   649 }
   651 // Create an XML parser and an XSL content sink and start parsing
   652 // the XSL stylesheet located at the given URI.
   653 nsresult
   654 nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
   655 {
   656   nsCOMPtr<nsIDocumentTransformer> processor =
   657     do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt");
   658   if (!processor) {
   659     // No XSLT processor available, continue normal document loading
   660     return NS_OK;
   661   }
   663   processor->Init(mDocument->NodePrincipal());
   664   processor->SetTransformObserver(this);
   666   nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
   667   if (!loadGroup) {
   668     return NS_ERROR_FAILURE;
   669   }
   671   if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, loadGroup))) {
   672     mXSLTProcessor.swap(processor);
   673   }
   675   // Intentionally ignore errors here, we should continue loading the
   676   // XML document whether we're able to load the XSLT stylesheet or
   677   // not.
   679   return NS_OK;
   680 }
   682 nsresult
   683 nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
   684                                    const nsSubstring& aHref,
   685                                    bool aAlternate,
   686                                    const nsSubstring& aTitle,
   687                                    const nsSubstring& aType,
   688                                    const nsSubstring& aMedia)
   689 {
   690   nsresult rv = NS_OK;
   691   mPrettyPrintXML = false;
   693   nsAutoCString cmd;
   694   if (mParser)
   695     GetParser()->GetCommand(cmd);
   696   if (cmd.EqualsASCII(kLoadAsData))
   697     return NS_OK; // Do not load stylesheets when loading as data
   699   NS_ConvertUTF16toUTF8 type(aType);
   700   if (type.EqualsIgnoreCase(TEXT_XSL) ||
   701       type.EqualsIgnoreCase(APPLICATION_XSLT_XML) ||
   702       type.EqualsIgnoreCase(TEXT_XML) ||
   703       type.EqualsIgnoreCase(APPLICATION_XML)) {
   704     if (aAlternate) {
   705       // don't load alternate XSLT
   706       return NS_OK;
   707     }
   708     // LoadXSLStyleSheet needs a mDocShell.
   709     if (!mDocShell)
   710       return NS_OK;
   712     nsCOMPtr<nsIURI> url;
   713     rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
   714                    mDocument->GetDocBaseURI());
   715     NS_ENSURE_SUCCESS(rv, rv);
   717     // Do security check
   718     nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
   719     rv = secMan->
   720       CheckLoadURIWithPrincipal(mDocument->NodePrincipal(), url,
   721                                 nsIScriptSecurityManager::ALLOW_CHROME);
   722     NS_ENSURE_SUCCESS(rv, NS_OK);
   724     // Do content policy check
   725     int16_t decision = nsIContentPolicy::ACCEPT;
   726     rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XSLT,
   727                                    url,
   728                                    mDocument->NodePrincipal(),
   729                                    aElement,
   730                                    type,
   731                                    nullptr,
   732                                    &decision,
   733                                    nsContentUtils::GetContentPolicy(),
   734                                    nsContentUtils::GetSecurityManager());
   736     NS_ENSURE_SUCCESS(rv, rv);
   738     if (NS_CP_REJECTED(decision)) {
   739       return NS_OK;
   740     }
   742     return LoadXSLStyleSheet(url);
   743   }
   745   // Let nsContentSink deal with css.
   746   rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
   747                                        aTitle, aType, aMedia);
   749   // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
   750   // pending sheets.
   752   return rv;
   753 }
   755 NS_IMETHODIMP 
   756 nsXMLContentSink::SetDocumentCharset(nsACString& aCharset)
   757 {
   758   if (mDocument) {
   759     mDocument->SetDocumentCharacterSet(aCharset);
   760   }
   762   return NS_OK;
   763 }
   765 nsISupports *
   766 nsXMLContentSink::GetTarget()
   767 {
   768   return mDocument;
   769 }
   771 bool
   772 nsXMLContentSink::IsScriptExecuting()
   773 {
   774   return IsScriptExecutingImpl();
   775 }
   777 nsresult
   778 nsXMLContentSink::FlushText(bool aReleaseTextNode)
   779 {
   780   nsresult rv = NS_OK;
   782   if (mTextLength != 0) {
   783     if (mLastTextNode) {
   784       if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) {
   785         mLastTextNodeSize = 0;
   786         mLastTextNode = nullptr;
   787         FlushText(aReleaseTextNode);
   788       } else {
   789         bool notify = HaveNotifiedForCurrentContent();
   790         // We could probably always increase mInNotification here since
   791         // if AppendText doesn't notify it shouldn't trigger evil code.
   792         // But just in case it does, we don't want to mask any notifications.
   793         if (notify) {
   794           ++mInNotification;
   795         }
   796         rv = mLastTextNode->AppendText(mText, mTextLength, notify);
   797         if (notify) {
   798           --mInNotification;
   799         }
   801         mLastTextNodeSize += mTextLength;
   802         mTextLength = 0;
   803       }
   804     } else {
   805       nsRefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager);
   807       mLastTextNode = textContent;
   809       // Set the text in the text node
   810       textContent->SetText(mText, mTextLength, false);
   811       mLastTextNodeSize += mTextLength;
   812       mTextLength = 0;
   814       // Add text to its parent
   815       rv = AddContentAsLeaf(textContent);
   816     }
   817   }
   819   if (aReleaseTextNode) {
   820     mLastTextNodeSize = 0;
   821     mLastTextNode = nullptr;
   822   }
   824   return rv;
   825 }
   827 nsIContent*
   828 nsXMLContentSink::GetCurrentContent()
   829 {
   830   if (mContentStack.Length() == 0) {
   831     return nullptr;
   832   }
   833   return GetCurrentStackNode()->mContent;
   834 }
   836 StackNode*
   837 nsXMLContentSink::GetCurrentStackNode()
   838 {
   839   int32_t count = mContentStack.Length();
   840   return count != 0 ? &mContentStack[count-1] : nullptr;
   841 }
   844 nsresult
   845 nsXMLContentSink::PushContent(nsIContent *aContent)
   846 {
   847   NS_PRECONDITION(aContent, "Null content being pushed!");
   848   StackNode *sn = mContentStack.AppendElement();
   849   NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
   851   sn->mContent = aContent;
   852   sn->mNumFlushed = 0;
   853   return NS_OK;
   854 }
   856 void
   857 nsXMLContentSink::PopContent()
   858 {
   859   int32_t count = mContentStack.Length();
   861   if (count == 0) {
   862     NS_WARNING("Popping empty stack");
   863     return;
   864   }
   866   mContentStack.RemoveElementAt(count - 1);
   867 }
   869 bool
   870 nsXMLContentSink::HaveNotifiedForCurrentContent() const
   871 {
   872   uint32_t stackLength = mContentStack.Length();
   873   if (stackLength) {
   874     const StackNode& stackNode = mContentStack[stackLength - 1];
   875     nsIContent* parent = stackNode.mContent;
   876     return stackNode.mNumFlushed == parent->GetChildCount();
   877   }
   878   return true;
   879 }
   881 void
   882 nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
   883 {
   884   // XXXbz if aIgnorePendingSheets is true, what should we do when
   885   // mXSLTProcessor or CanStillPrettyPrint()?
   886   if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) {
   887     return;
   888   }
   889   StartLayout(aIgnorePendingSheets);
   890 }
   892 ////////////////////////////////////////////////////////////////////////
   894 bool
   895 nsXMLContentSink::SetDocElement(int32_t aNameSpaceID,
   896                                 nsIAtom* aTagName,
   897                                 nsIContent *aContent)
   898 {
   899   if (mDocElement)
   900     return false;
   902   // check for root elements that needs special handling for
   903   // prettyprinting
   904   if ((aNameSpaceID == kNameSpaceID_XBL &&
   905        aTagName == nsGkAtoms::bindings) ||
   906       (aNameSpaceID == kNameSpaceID_XSLT &&
   907        (aTagName == nsGkAtoms::stylesheet ||
   908         aTagName == nsGkAtoms::transform))) {
   909     mPrettyPrintHasSpecialRoot = true;
   910     if (mPrettyPrintXML) {
   911       // In this case, disable script execution, stylesheet
   912       // loading, and auto XLinks since we plan to prettyprint.
   913       mDocument->ScriptLoader()->SetEnabled(false);
   914       if (mCSSLoader) {
   915         mCSSLoader->SetEnabled(false);
   916       }
   917     }        
   918   }
   920   mDocElement = aContent;
   921   nsresult rv = mDocument->AppendChildTo(mDocElement, NotifyForDocElement());
   922   if (NS_FAILED(rv)) {
   923     // If we return false here, the caller will bail out because it won't
   924     // find a parent content node to append to, which is fine.
   925     return false;
   926   }
   928   if (aTagName == nsGkAtoms::html &&
   929       aNameSpaceID == kNameSpaceID_XHTML) {
   930     ProcessOfflineManifest(aContent);
   931   }
   933   return true;
   934 }
   936 NS_IMETHODIMP
   937 nsXMLContentSink::HandleStartElement(const char16_t *aName,
   938                                      const char16_t **aAtts,
   939                                      uint32_t aAttsCount,
   940                                      int32_t aIndex,
   941                                      uint32_t aLineNumber)
   942 {
   943   return HandleStartElement(aName, aAtts, aAttsCount, aIndex, aLineNumber,
   944                             true);
   945 }
   947 nsresult
   948 nsXMLContentSink::HandleStartElement(const char16_t *aName,
   949                                      const char16_t **aAtts,
   950                                      uint32_t aAttsCount,
   951                                      int32_t aIndex,
   952                                      uint32_t aLineNumber,
   953                                      bool aInterruptable)
   954 {
   955   NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
   956   NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
   957   // Adjust aAttsCount so it's the actual number of attributes
   958   aAttsCount /= 2;
   960   nsresult result = NS_OK;
   961   bool appendContent = true;
   962   nsCOMPtr<nsIContent> content;
   964   // XXX Hopefully the parser will flag this before we get
   965   // here. If we're in the epilog, there should be no
   966   // new elements
   967   PR_ASSERT(eXMLContentSinkState_InEpilog != mState);
   969   FlushText();
   970   DidAddContent();
   972   mState = eXMLContentSinkState_InDocumentElement;
   974   int32_t nameSpaceID;
   975   nsCOMPtr<nsIAtom> prefix, localName;
   976   nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
   977                                  getter_AddRefs(localName), &nameSpaceID);
   979   if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName, aLineNumber)) {
   980     return NS_OK;
   981   }
   983   nsCOMPtr<nsINodeInfo> nodeInfo;
   984   nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
   985                                            nsIDOMNode::ELEMENT_NODE);
   987   result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
   988                          getter_AddRefs(content), &appendContent,
   989                          FROM_PARSER_NETWORK);
   990   NS_ENSURE_SUCCESS(result, result);
   992   // Have to do this before we push the new content on the stack... and have to
   993   // do that before we set attributes, call BindToTree, etc.  Ideally we'd push
   994   // on the stack inside CreateElement (which is effectively what the HTML sink
   995   // does), but that's hard with all the subclass overrides going on.
   996   nsCOMPtr<nsIContent> parent = GetCurrentContent();
   998   result = PushContent(content);
   999   NS_ENSURE_SUCCESS(result, result);
  1001   // Set the ID attribute atom on the node info object for this node
  1002   // This must occur before the attributes are added so the name
  1003   // of the id attribute is known.
  1004   if (aIndex != -1 && NS_SUCCEEDED(result)) {
  1005     nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
  1007     if (IDAttr) {
  1008       nodeInfo->SetIDAttributeAtom(IDAttr);
  1012   // Set the attributes on the new content element
  1013   result = AddAttributes(aAtts, content);
  1015   if (NS_OK == result) {
  1016     // Store the element 
  1017     if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
  1018       NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
  1020       parent->AppendChildTo(content, false);
  1024   // Some HTML nodes need DoneCreatingElement() called to initialize
  1025   // properly (eg form state restoration).
  1026   if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML) {
  1027     if (nodeInfo->NameAtom() == nsGkAtoms::input ||
  1028         nodeInfo->NameAtom() == nsGkAtoms::button ||
  1029         nodeInfo->NameAtom() == nsGkAtoms::menuitem ||
  1030         nodeInfo->NameAtom() == nsGkAtoms::audio ||
  1031         nodeInfo->NameAtom() == nsGkAtoms::video) {
  1032       content->DoneCreatingElement();
  1033     } else if (nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) {
  1034       mCurrentHead = content;
  1038   if (IsMonolithicContainer(nodeInfo)) {
  1039     mInMonolithicContainer++;
  1042   if (content != mDocElement && !mCurrentHead) {
  1043     // This isn't the root and we're not inside an XHTML <head>.
  1044     // Might need to start layout
  1045     MaybeStartLayout(false);
  1048   if (content == mDocElement) {
  1049     NotifyDocElementCreated(mDocument);
  1052   return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
  1053                                                   result;
  1056 NS_IMETHODIMP
  1057 nsXMLContentSink::HandleEndElement(const char16_t *aName)
  1059   return HandleEndElement(aName, true);
  1062 nsresult
  1063 nsXMLContentSink::HandleEndElement(const char16_t *aName,
  1064                                    bool aInterruptable)
  1066   nsresult result = NS_OK;
  1068   // XXX Hopefully the parser will flag this before we get
  1069   // here. If we're in the prolog or epilog, there should be
  1070   // no close tags for elements.
  1071   PR_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
  1073   FlushText();
  1075   StackNode* sn = GetCurrentStackNode();
  1076   if (!sn) {
  1077     return NS_ERROR_UNEXPECTED;
  1080   nsCOMPtr<nsIContent> content;
  1081   sn->mContent.swap(content);
  1082   uint32_t numFlushed = sn->mNumFlushed;
  1084   PopContent();
  1085   NS_ASSERTION(content, "failed to pop content");
  1086 #ifdef DEBUG
  1087   // Check that we're closing the right thing
  1088   nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom;
  1089   int32_t debugNameSpaceID;
  1090   nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
  1091                                  getter_AddRefs(debugTagAtom),
  1092                                  &debugNameSpaceID);
  1093   NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID),
  1094                "Wrong element being closed");
  1095 #endif  
  1097   result = CloseElement(content);
  1099   if (mCurrentHead == content) {
  1100     mCurrentHead = nullptr;
  1103   if (mDocElement == content) {
  1104     // XXXbz for roots that don't want to be appended on open, we
  1105     // probably need to deal here.... (and stop appending them on open).
  1106     mState = eXMLContentSinkState_InEpilog;
  1108     // We might have had no occasion to start layout yet.  Do so now.
  1109     MaybeStartLayout(false);
  1112   int32_t stackLen = mContentStack.Length();
  1113   if (mNotifyLevel >= stackLen) {
  1114     if (numFlushed < content->GetChildCount()) {
  1115     	  NotifyAppend(content, numFlushed);
  1117     mNotifyLevel = stackLen - 1;
  1119   DidAddContent();
  1121   if (content->IsSVG(nsGkAtoms::svg)) {
  1122     FlushTags();
  1123     nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content);
  1124     if (NS_FAILED(NS_DispatchToMainThread(event))) {
  1125       NS_WARNING("failed to dispatch svg load dispatcher");
  1129   return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
  1130                                                   result;
  1133 NS_IMETHODIMP 
  1134 nsXMLContentSink::HandleComment(const char16_t *aName)
  1136   FlushText();
  1138   nsRefPtr<Comment> comment = new Comment(mNodeInfoManager);
  1139   comment->SetText(nsDependentString(aName), false);
  1140   nsresult rv = AddContentAsLeaf(comment);
  1141   DidAddContent();
  1143   return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1146 NS_IMETHODIMP 
  1147 nsXMLContentSink::HandleCDataSection(const char16_t *aData, 
  1148                                      uint32_t aLength)
  1150   // XSLT doesn't differentiate between text and cdata and wants adjacent
  1151   // textnodes merged, so add as text.
  1152   if (mXSLTProcessor) {
  1153     return AddText(aData, aLength);
  1156   FlushText();
  1158   nsRefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager);
  1159   cdata->SetText(aData, aLength, false);
  1160   nsresult rv = AddContentAsLeaf(cdata);
  1161   DidAddContent();
  1163   return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1166 NS_IMETHODIMP
  1167 nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset, 
  1168                                     const nsAString & aName, 
  1169                                     const nsAString & aSystemId, 
  1170                                     const nsAString & aPublicId,
  1171                                     nsISupports* aCatalogData)
  1173   FlushText();
  1175   nsresult rv = NS_OK;
  1177   NS_ASSERTION(mDocument, "Shouldn't get here from a document fragment");
  1179   nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
  1180   NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
  1182   // Create a new doctype node
  1183   nsCOMPtr<nsIDOMDocumentType> docType;
  1184   rv = NS_NewDOMDocumentType(getter_AddRefs(docType), mNodeInfoManager,
  1185                              name, aPublicId, aSystemId, aSubset);
  1186   if (NS_FAILED(rv) || !docType) {
  1187     return rv;
  1190   if (aCatalogData && mCSSLoader && mDocument) {
  1191     // bug 124570 - we only expect additional agent sheets for now -- ignore
  1192     // exit codes, error are not fatal here, just that the stylesheet won't apply
  1193     nsCOMPtr<nsIURI> uri(do_QueryInterface(aCatalogData));
  1194     if (uri) {
  1195       nsRefPtr<nsCSSStyleSheet> sheet;
  1196       mCSSLoader->LoadSheetSync(uri, true, true, getter_AddRefs(sheet));
  1198 #ifdef DEBUG
  1199       nsAutoCString uriStr;
  1200       uri->GetSpec(uriStr);
  1201       printf("Loading catalog stylesheet: %s ... %s\n", uriStr.get(), sheet.get() ? "Done" : "Failed");
  1202 #endif
  1203       if (sheet) {
  1204         mDocument->BeginUpdate(UPDATE_STYLE);
  1205         mDocument->AddCatalogStyleSheet(sheet);
  1206         mDocument->EndUpdate(UPDATE_STYLE);
  1211   nsCOMPtr<nsIContent> content = do_QueryInterface(docType);
  1212   NS_ASSERTION(content, "doctype isn't content?");
  1214   rv = mDocument->AppendChildTo(content, false);
  1215   DidAddContent();
  1216   return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1219 NS_IMETHODIMP
  1220 nsXMLContentSink::HandleCharacterData(const char16_t *aData, 
  1221                                       uint32_t aLength)
  1223   return HandleCharacterData(aData, aLength, true);
  1226 nsresult
  1227 nsXMLContentSink::HandleCharacterData(const char16_t *aData, uint32_t aLength,
  1228                                       bool aInterruptable)
  1230   nsresult rv = NS_OK;
  1231   if (aData && mState != eXMLContentSinkState_InProlog &&
  1232       mState != eXMLContentSinkState_InEpilog) {
  1233     rv = AddText(aData, aLength);
  1235   return aInterruptable && NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1238 NS_IMETHODIMP
  1239 nsXMLContentSink::HandleProcessingInstruction(const char16_t *aTarget, 
  1240                                               const char16_t *aData)
  1242   FlushText();
  1244   const nsDependentString target(aTarget);
  1245   const nsDependentString data(aData);
  1247   nsCOMPtr<nsIContent> node =
  1248     NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data);
  1250   nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node));
  1251   if (ssle) {
  1252     ssle->InitStyleLinkElement(false);
  1253     ssle->SetEnableUpdates(false);
  1254     mPrettyPrintXML = false;
  1257   nsresult rv = AddContentAsLeaf(node);
  1258   NS_ENSURE_SUCCESS(rv, rv);
  1259   DidAddContent();
  1261   if (ssle) {
  1262     // This is an xml-stylesheet processing instruction... but it might not be
  1263     // a CSS one if the type is set to something else.
  1264     ssle->SetEnableUpdates(true);
  1265     bool willNotify;
  1266     bool isAlternate;
  1267     rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
  1268                                 &willNotify,
  1269                                 &isAlternate);
  1270     NS_ENSURE_SUCCESS(rv, rv);
  1272     if (willNotify) {
  1273       // Successfully started a stylesheet load
  1274       if (!isAlternate && !mRunsToCompletion) {
  1275         ++mPendingSheetCount;
  1276         mScriptLoader->AddExecuteBlocker();
  1279       return NS_OK;
  1283   // If it's not a CSS stylesheet PI...
  1284   nsAutoString type;
  1285   nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
  1287   if (mState != eXMLContentSinkState_InProlog ||
  1288       !target.EqualsLiteral("xml-stylesheet") ||
  1289       type.IsEmpty()                          ||
  1290       type.LowerCaseEqualsLiteral("text/css")) {
  1291     return DidProcessATokenImpl();
  1294   nsAutoString href, title, media;
  1295   bool isAlternate = false;
  1297   // If there was no href, we can't do anything with this PI
  1298   if (!ParsePIData(data, href, title, media, isAlternate)) {
  1299       return DidProcessATokenImpl();
  1302   rv = ProcessStyleLink(node, href, isAlternate, title, type, media);
  1303   return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1306 /* static */
  1307 bool
  1308 nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref,
  1309                               nsString &aTitle, nsString &aMedia,
  1310                               bool &aIsAlternate)
  1312   // If there was no href, we can't do anything with this PI
  1313   if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) {
  1314     return false;
  1317   nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle);
  1319   nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia);
  1321   nsAutoString alternate;
  1322   nsContentUtils::GetPseudoAttributeValue(aData,
  1323                                           nsGkAtoms::alternate,
  1324                                           alternate);
  1326   aIsAlternate = alternate.EqualsLiteral("yes");
  1328   return true;
  1331 NS_IMETHODIMP
  1332 nsXMLContentSink::HandleXMLDeclaration(const char16_t *aVersion,
  1333                                        const char16_t *aEncoding,
  1334                                        int32_t aStandalone)
  1336   mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone);
  1338   return DidProcessATokenImpl();
  1341 NS_IMETHODIMP
  1342 nsXMLContentSink::ReportError(const char16_t* aErrorText, 
  1343                               const char16_t* aSourceText,
  1344                               nsIScriptError *aError,
  1345                               bool *_retval)
  1347   NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
  1348   nsresult rv = NS_OK;
  1350   // The expat driver should report the error.  We're just cleaning up the mess.
  1351   *_retval = true;
  1353   mPrettyPrintXML = false;
  1355   mState = eXMLContentSinkState_InProlog;
  1357   // XXX need to stop scripts here -- hsivonen
  1359   // stop observing in order to avoid crashing when removing content
  1360   mDocument->RemoveObserver(this);
  1361   mIsDocumentObserver = false;
  1363   // Clear the current content and
  1364   // prepare to set <parsererror> as the document root
  1365   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mDocument));
  1366   if (node) {
  1367     for (;;) {
  1368       nsCOMPtr<nsIDOMNode> child, dummy;
  1369       node->GetLastChild(getter_AddRefs(child));
  1370       if (!child)
  1371         break;
  1372       node->RemoveChild(child, getter_AddRefs(dummy));
  1375   mDocElement = nullptr;
  1377   // Clear any buffered-up text we have.  It's enough to set the length to 0.
  1378   // The buffer itself is allocated when we're created and deleted in our
  1379   // destructor, so don't mess with it.
  1380   mTextLength = 0;
  1382   if (mXSLTProcessor) {
  1383     // Get rid of the XSLT processor.
  1384     mXSLTProcessor->CancelLoads();
  1385     mXSLTProcessor = nullptr;
  1388   // release the nodes on stack
  1389   mContentStack.Clear();
  1390   mNotifyLevel = 0;
  1392   rv = HandleProcessingInstruction(MOZ_UTF16("xml-stylesheet"),
  1393                                    MOZ_UTF16("href=\"chrome://global/locale/intl.css\" type=\"text/css\""));
  1394   NS_ENSURE_SUCCESS(rv, rv);
  1396   const char16_t* noAtts[] = { 0, 0 };
  1398   NS_NAMED_LITERAL_STRING(errorNs,
  1399                           "http://www.mozilla.org/newlayout/xml/parsererror.xml");
  1401   nsAutoString parsererror(errorNs);
  1402   parsererror.Append((char16_t)0xFFFF);
  1403   parsererror.AppendLiteral("parsererror");
  1405   rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, (uint32_t)-1,
  1406                           false);
  1407   NS_ENSURE_SUCCESS(rv, rv);
  1409   rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false);
  1410   NS_ENSURE_SUCCESS(rv, rv);  
  1412   nsAutoString sourcetext(errorNs);
  1413   sourcetext.Append((char16_t)0xFFFF);
  1414   sourcetext.AppendLiteral("sourcetext");
  1416   rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, (uint32_t)-1,
  1417                           false);
  1418   NS_ENSURE_SUCCESS(rv, rv);
  1420   rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText), false);
  1421   NS_ENSURE_SUCCESS(rv, rv);
  1423   rv = HandleEndElement(sourcetext.get(), false);
  1424   NS_ENSURE_SUCCESS(rv, rv); 
  1426   rv = HandleEndElement(parsererror.get(), false);
  1427   NS_ENSURE_SUCCESS(rv, rv);
  1429   FlushTags();
  1431   return NS_OK;
  1434 nsresult
  1435 nsXMLContentSink::AddAttributes(const char16_t** aAtts,
  1436                                 nsIContent* aContent)
  1438   // Add tag attributes to the content attributes
  1439   nsCOMPtr<nsIAtom> prefix, localName;
  1440   while (*aAtts) {
  1441     int32_t nameSpaceID;
  1442     nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
  1443                                    getter_AddRefs(localName), &nameSpaceID);
  1445     // Add attribute to content
  1446     aContent->SetAttr(nameSpaceID, localName, prefix,
  1447                       nsDependentString(aAtts[1]), false);
  1448     aAtts += 2;
  1451   return NS_OK;
  1454 #define NS_ACCUMULATION_BUFFER_SIZE 4096
  1456 nsresult
  1457 nsXMLContentSink::AddText(const char16_t* aText, 
  1458                           int32_t aLength)
  1460   // Create buffer when we first need it
  1461   if (0 == mTextSize) {
  1462     mText = (char16_t *) PR_MALLOC(sizeof(char16_t) * NS_ACCUMULATION_BUFFER_SIZE);
  1463     if (nullptr == mText) {
  1464       return NS_ERROR_OUT_OF_MEMORY;
  1466     mTextSize = NS_ACCUMULATION_BUFFER_SIZE;
  1469   // Copy data from string into our buffer; flush buffer when it fills up
  1470   int32_t offset = 0;
  1471   while (0 != aLength) {
  1472     int32_t amount = mTextSize - mTextLength;
  1473     if (0 == amount) {
  1474       // XSLT wants adjacent textnodes merged.
  1475       if (mConstrainSize && !mXSLTProcessor) {
  1476         nsresult rv = FlushText();
  1477         if (NS_OK != rv) {
  1478           return rv;
  1481         amount = mTextSize - mTextLength;
  1483       else {
  1484         mTextSize += aLength;
  1485         mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize);
  1486         if (nullptr == mText) {
  1487           mTextSize = 0;
  1489           return NS_ERROR_OUT_OF_MEMORY;
  1492         amount = aLength;
  1495     if (amount > aLength) {
  1496       amount = aLength;
  1498     memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount);
  1499     mTextLength += amount;
  1500     offset += amount;
  1501     aLength -= amount;
  1504   return NS_OK;
  1507 void
  1508 nsXMLContentSink::FlushPendingNotifications(mozFlushType aType)
  1510   // Only flush tags if we're not doing the notification ourselves
  1511   // (since we aren't reentrant)
  1512   if (!mInNotification) {
  1513     if (mIsDocumentObserver) {
  1514       // Only flush if we're still a document observer (so that our child
  1515       // counts should be correct).
  1516       if (aType >= Flush_ContentAndNotify) {
  1517         FlushTags();
  1519       else {
  1520         FlushText(false);
  1523     if (aType >= Flush_InterruptibleLayout) {
  1524       // Make sure that layout has started so that the reflow flush
  1525       // will actually happen.
  1526       MaybeStartLayout(true);
  1531 /**
  1532  * NOTE!! Forked from SinkContext. Please keep in sync.
  1534  * Flush all elements that have been seen so far such that
  1535  * they are visible in the tree. Specifically, make sure
  1536  * that they are all added to their respective parents.
  1537  * Also, do notification at the top for all content that
  1538  * has been newly added so that the frame tree is complete.
  1539  */
  1540 nsresult
  1541 nsXMLContentSink::FlushTags()
  1543   mDeferredFlushTags = false;
  1544   bool oldBeganUpdate = mBeganUpdate;
  1545   uint32_t oldUpdates = mUpdatesInNotification;
  1547   mUpdatesInNotification = 0;
  1548   ++mInNotification;
  1550     // Scope so we call EndUpdate before we decrease mInNotification
  1551     mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, true);
  1552     mBeganUpdate = true;
  1554     // Don't release last text node in case we need to add to it again
  1555     FlushText(false);
  1557     // Start from the base of the stack (growing downward) and do
  1558     // a notification from the node that is closest to the root of
  1559     // tree for any content that has been added.
  1561     int32_t stackPos;
  1562     int32_t stackLen = mContentStack.Length();
  1563     bool flushed = false;
  1564     uint32_t childCount;
  1565     nsIContent* content;
  1567     for (stackPos = 0; stackPos < stackLen; ++stackPos) {
  1568       content = mContentStack[stackPos].mContent;
  1569       childCount = content->GetChildCount();
  1571       if (!flushed && (mContentStack[stackPos].mNumFlushed < childCount)) {
  1572         NotifyAppend(content, mContentStack[stackPos].mNumFlushed);
  1573         flushed = true;
  1576       mContentStack[stackPos].mNumFlushed = childCount;
  1578     mNotifyLevel = stackLen - 1;
  1580   --mInNotification;
  1582   if (mUpdatesInNotification > 1) {
  1583     UpdateChildCounts();
  1586   mUpdatesInNotification = oldUpdates;
  1587   mBeganUpdate = oldBeganUpdate;
  1589   return NS_OK;
  1592 /**
  1593  * NOTE!! Forked from SinkContext. Please keep in sync.
  1594  */
  1595 void
  1596 nsXMLContentSink::UpdateChildCounts()
  1598   // Start from the top of the stack (growing upwards) and see if any
  1599   // new content has been appended. If so, we recognize that reflows
  1600   // have been generated for it and we should make sure that no
  1601   // further reflows occur.  Note that we have to include stackPos == 0
  1602   // to properly notify on kids of <html>.
  1603   int32_t stackLen = mContentStack.Length();
  1604   int32_t stackPos = stackLen - 1;
  1605   while (stackPos >= 0) {
  1606     StackNode & node = mContentStack[stackPos];
  1607     node.mNumFlushed = node.mContent->GetChildCount();
  1609     stackPos--;
  1611   mNotifyLevel = stackLen - 1;
  1614 bool
  1615 nsXMLContentSink::IsMonolithicContainer(nsINodeInfo* aNodeInfo)
  1617   return ((aNodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
  1618           (aNodeInfo->NameAtom() == nsGkAtoms::tr ||
  1619            aNodeInfo->NameAtom() == nsGkAtoms::select ||
  1620            aNodeInfo->NameAtom() == nsGkAtoms::object ||
  1621            aNodeInfo->NameAtom() == nsGkAtoms::applet)) ||
  1622           (aNodeInfo->NamespaceID() == kNameSpaceID_MathML &&
  1623           (aNodeInfo->NameAtom() == nsGkAtoms::math))
  1624           );
  1627 void
  1628 nsXMLContentSink::ContinueInterruptedParsingIfEnabled()
  1630   if (mParser && mParser->IsParserEnabled()) {
  1631     GetParser()->ContinueInterruptedParsing();
  1635 void
  1636 nsXMLContentSink::ContinueInterruptedParsingAsync()
  1638   nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
  1639     &nsXMLContentSink::ContinueInterruptedParsingIfEnabled);
  1641   NS_DispatchToCurrentThread(ev);
  1644 nsIParser*
  1645 nsXMLContentSink::GetParser()
  1647   return static_cast<nsIParser*>(mParser.get());

mercurial