123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsCOMPtr.h"
- #include "nsXMLContentSink.h"
- #include "nsIParser.h"
- #include "nsIDocument.h"
- #include "nsIDOMDocument.h"
- #include "nsIDOMDocumentType.h"
- #include "nsIContent.h"
- #include "nsIURI.h"
- #include "nsNetUtil.h"
- #include "nsIDocShell.h"
- #include "nsIStyleSheetLinkingElement.h"
- #include "nsIDOMComment.h"
- #include "nsIDOMCDATASection.h"
- #include "DocumentType.h"
- #include "nsHTMLParts.h"
- #include "nsCRT.h"
- #include "mozilla/StyleSheetInlines.h"
- #include "mozilla/css/Loader.h"
- #include "nsGkAtoms.h"
- #include "nsContentUtils.h"
- #include "nsIScriptContext.h"
- #include "nsNameSpaceManager.h"
- #include "nsIServiceManager.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsIContentViewer.h"
- #include "prtime.h"
- #include "mozilla/Logging.h"
- #include "prmem.h"
- #include "nsRect.h"
- #include "nsIWebNavigation.h"
- #include "nsIScriptElement.h"
- #include "nsStyleLinkElement.h"
- #include "nsReadableUtils.h"
- #include "nsUnicharUtils.h"
- #include "nsICookieService.h"
- #include "nsIPrompt.h"
- #include "nsIChannel.h"
- #include "nsIPrincipal.h"
- #include "nsXMLPrettyPrinter.h"
- #include "nsNodeInfoManager.h"
- #include "nsContentCreatorFunctions.h"
- #include "nsIContentPolicy.h"
- #include "nsContentPolicyUtils.h"
- #include "nsError.h"
- #include "nsIDOMProcessingInstruction.h"
- #include "nsNodeUtils.h"
- #include "nsIScriptGlobalObject.h"
- #include "nsIHTMLDocument.h"
- #include "mozAutoDocUpdate.h"
- #include "nsMimeTypes.h"
- #include "nsHtml5SVGLoadDispatcher.h"
- #include "nsTextNode.h"
- #include "mozilla/dom/CDATASection.h"
- #include "mozilla/dom/Comment.h"
- #include "mozilla/dom/Element.h"
- #include "mozilla/dom/HTMLTemplateElement.h"
- #include "mozilla/dom/ProcessingInstruction.h"
- #include "mozilla/dom/ScriptLoader.h"
- using namespace mozilla;
- using namespace mozilla::dom;
- // XXX Open Issues:
- // 1) what's not allowed - We need to figure out which HTML tags
- // (prefixed with a HTML namespace qualifier) are explicitly not
- // allowed (if any).
- // 2) factoring code with nsHTMLContentSink - There's some amount of
- // common code between this and the HTML content sink. This will
- // increase as we support more and more HTML elements. How can code
- // from the code be factored?
- nsresult
- NS_NewXMLContentSink(nsIXMLContentSink** aResult,
- nsIDocument* aDoc,
- nsIURI* aURI,
- nsISupports* aContainer,
- nsIChannel* aChannel)
- {
- NS_PRECONDITION(nullptr != aResult, "null ptr");
- if (nullptr == aResult) {
- return NS_ERROR_NULL_POINTER;
- }
- RefPtr<nsXMLContentSink> it = new nsXMLContentSink();
- nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
- NS_ENSURE_SUCCESS(rv, rv);
- it.forget(aResult);
- return NS_OK;
- }
- nsXMLContentSink::nsXMLContentSink()
- : mTextLength(0)
- , mNotifyLevel(0)
- , mPrettyPrintXML(true)
- , mPrettyPrintHasSpecialRoot(0)
- , mPrettyPrintHasFactoredElements(0)
- , mPrettyPrinting(0)
- , mPreventScriptExecution(0)
- {
- PodArrayZero(mText);
- }
- nsXMLContentSink::~nsXMLContentSink()
- {
- }
- nsresult
- nsXMLContentSink::Init(nsIDocument* aDoc,
- nsIURI* aURI,
- nsISupports* aContainer,
- nsIChannel* aChannel)
- {
- nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
- NS_ENSURE_SUCCESS(rv, rv);
- aDoc->AddObserver(this);
- mIsDocumentObserver = true;
- if (!mDocShell) {
- mPrettyPrintXML = false;
- }
- mState = eXMLContentSinkState_InProlog;
- mDocElement = nullptr;
- return NS_OK;
- }
- NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink)
- NS_INTERFACE_MAP_ENTRY(nsIContentSink)
- NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
- NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
- NS_INTERFACE_MAP_ENTRY(nsITransformObserver)
- NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
- NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink)
- NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink)
- NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink,
- nsContentSink)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentHead)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocElement)
- for (uint32_t i = 0, count = tmp->mContentStack.Length(); i < count; i++) {
- const StackNode& node = tmp->mContentStack.ElementAt(i);
- cb.NoteXPCOMChild(node.mContent);
- }
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentChildren)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
- // nsIContentSink
- NS_IMETHODIMP
- nsXMLContentSink::WillParse(void)
- {
- return WillParseImpl();
- }
- NS_IMETHODIMP
- nsXMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
- {
- WillBuildModelImpl();
- // Notify document that the load is beginning
- mDocument->BeginLoad();
- // Check for correct load-command for maybe prettyprinting
- if (mPrettyPrintXML) {
- nsAutoCString command;
- GetParser()->GetCommand(command);
- if (!command.EqualsLiteral("view")) {
- mPrettyPrintXML = false;
- }
- }
- return NS_OK;
- }
- bool
- nsXMLContentSink::CanStillPrettyPrint()
- {
- return mPrettyPrintXML &&
- (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot);
- }
- nsresult
- nsXMLContentSink::MaybePrettyPrint()
- {
- if (!CanStillPrettyPrint()) {
- mPrettyPrintXML = false;
- return NS_OK;
- }
- // stop observing in order to avoid crashing when replacing content
- mDocument->RemoveObserver(this);
- mIsDocumentObserver = false;
- // Reenable the CSSLoader so that the prettyprinting stylesheets can load
- if (mCSSLoader) {
- mCSSLoader->SetEnabled(true);
- }
- RefPtr<nsXMLPrettyPrinter> printer;
- nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer));
- NS_ENSURE_SUCCESS(rv, rv);
- bool isPrettyPrinting;
- rv = printer->PrettyPrint(mDocument, &isPrettyPrinting);
- NS_ENSURE_SUCCESS(rv, rv);
- mPrettyPrinting = isPrettyPrinting;
- return NS_OK;
- }
- static void
- CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
- nsIDocumentTransformer* aProcessor,
- nsIDocument* aDocument)
- {
- nsAutoString target, data;
- aPi->GetTarget(target);
- // Check for namespace declarations
- if (target.EqualsLiteral("xslt-param-namespace")) {
- aPi->GetData(data);
- nsAutoString prefix, namespaceAttr;
- nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix,
- prefix);
- if (!prefix.IsEmpty() &&
- nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
- namespaceAttr)) {
- aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
- }
- }
- // Check for actual parameters
- else if (target.EqualsLiteral("xslt-param")) {
- aPi->GetData(data);
- nsAutoString name, namespaceAttr, select, value;
- nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name,
- name);
- nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
- namespaceAttr);
- if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) {
- select.SetIsVoid(true);
- }
- if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) {
- value.SetIsVoid(true);
- }
- if (!name.IsEmpty()) {
- nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
- aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc);
- }
- }
- }
- NS_IMETHODIMP
- nsXMLContentSink::DidBuildModel(bool aTerminated)
- {
- if (!mParser) {
- // If mParser is null, this parse has already been terminated and must
- // not been terminated again. However, nsDocument may still think that
- // the parse has not been terminated and call back into here in the case
- // where the XML parser has finished but the XSLT transform associated
- // with the document has not.
- return NS_OK;
- }
- DidBuildModelImpl(aTerminated);
- if (mXSLTProcessor) {
- // stop observing in order to avoid crashing when replacing content
- mDocument->RemoveObserver(this);
- mIsDocumentObserver = false;
- // Check for xslt-param and xslt-param-namespace PIs
- for (nsIContent* child = mDocument->GetFirstChild();
- child;
- child = child->GetNextSibling()) {
- if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
- nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
- CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
- }
- else if (child->IsElement()) {
- // Only honor PIs in the prolog
- break;
- }
- }
- mXSLTProcessor->SetSourceContentModel(mDocument, mDocumentChildren);
- // Since the processor now holds a reference to us we drop our reference
- // to it to avoid owning cycles
- mXSLTProcessor = nullptr;
- }
- else {
- // Kick off layout for non-XSLT transformed documents.
- // Check if we want to prettyprint
- MaybePrettyPrint();
- bool startLayout = true;
- if (mPrettyPrinting) {
- NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
- // We're pretty-printing now. See whether we should wait up on
- // stylesheet loads
- if (mDocument->CSSLoader()->HasPendingLoads() &&
- NS_SUCCEEDED(mDocument->CSSLoader()->AddObserver(this))) {
- // wait for those sheets to load
- startLayout = false;
- }
- }
- if (startLayout) {
- StartLayout(false);
- ScrollToRef();
- }
- mDocument->RemoveObserver(this);
- mIsDocumentObserver = false;
- mDocument->EndLoad();
- }
- DropParserAndPerfHint();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument)
- {
- NS_ENSURE_ARG(aResultDocument);
- nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aResultDocument);
- if (htmlDoc) {
- htmlDoc->SetDocWriteDisabled(true);
- }
- nsCOMPtr<nsIContentViewer> contentViewer;
- mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
- if (contentViewer) {
- return contentViewer->SetDocumentInternal(aResultDocument, true);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXMLContentSink::OnTransformDone(nsresult aResult,
- nsIDocument* aResultDocument)
- {
- MOZ_ASSERT(aResultDocument, "Don't notify about transform end without a document.");
- mDocumentChildren.Clear();
- nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aResultDocument);
- nsCOMPtr<nsIContentViewer> contentViewer;
- mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
- if (NS_FAILED(aResult) && contentViewer) {
- // Transform failed.
- aResultDocument->SetMayStartLayout(false);
- // We have an error document.
- contentViewer->SetDOMDocument(domDoc);
- }
- nsCOMPtr<nsIDocument> originalDocument = mDocument;
- // Transform succeeded, or it failed and we have an error document to display.
- mDocument = aResultDocument;
- nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
- if (htmlDoc) {
- htmlDoc->SetDocWriteDisabled(false);
- }
- // Notify document observers that all the content has been stuck
- // into the document.
- // XXX do we need to notify for things like PIs? Or just the
- // documentElement?
- nsIContent *rootElement = mDocument->GetRootElement();
- if (rootElement) {
- NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
- "rootElement not in doc?");
- mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
- nsNodeUtils::ContentInserted(mDocument, rootElement,
- mDocument->IndexOf(rootElement));
- mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
- }
- // Start the layout process
- StartLayout(false);
- ScrollToRef();
- originalDocument->EndLoad();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXMLContentSink::StyleSheetLoaded(StyleSheet* aSheet,
- bool aWasAlternate,
- nsresult aStatus)
- {
- if (!mPrettyPrinting) {
- return nsContentSink::StyleSheetLoaded(aSheet, aWasAlternate, aStatus);
- }
- if (!mDocument->CSSLoader()->HasPendingLoads()) {
- mDocument->CSSLoader()->RemoveObserver(this);
- StartLayout(false);
- ScrollToRef();
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsXMLContentSink::WillInterrupt(void)
- {
- return WillInterruptImpl();
- }
- NS_IMETHODIMP
- nsXMLContentSink::WillResume(void)
- {
- return WillResumeImpl();
- }
- NS_IMETHODIMP
- nsXMLContentSink::SetParser(nsParserBase* aParser)
- {
- NS_PRECONDITION(aParser, "Should have a parser here!");
- mParser = aParser;
- return NS_OK;
- }
- nsresult
- nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
- mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
- nsIContent** aResult, bool* aAppendContent,
- FromParser aFromParser)
- {
- NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
- *aResult = nullptr;
- *aAppendContent = true;
- nsresult rv = NS_OK;
- RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
- RefPtr<Element> content;
- rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
- NS_ENSURE_SUCCESS(rv, rv);
- if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
- || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
- ) {
- nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
- sele->SetScriptLineNumber(aLineNumber);
- sele->SetCreatorParser(GetParser());
- }
- // XHTML needs some special attention
- if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
- mPrettyPrintHasFactoredElements = true;
- }
- else {
- // If we care, find out if we just used a special factory.
- if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
- mPrettyPrintXML) {
- mPrettyPrintHasFactoredElements =
- nsContentUtils::NameSpaceManager()->
- HasElementCreator(aNodeInfo->NamespaceID());
- }
- if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
- content.forget(aResult);
- return NS_OK;
- }
- }
- if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
- aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
- aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
- nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
- if (ssle) {
- ssle->InitStyleLinkElement(false);
- if (aFromParser) {
- ssle->SetEnableUpdates(false);
- }
- if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
- ssle->SetLineNumber(aFromParser ? aLineNumber : 0);
- }
- }
- }
- content.forget(aResult);
- return NS_OK;
- }
- nsresult
- nsXMLContentSink::CloseElement(nsIContent* aContent)
- {
- NS_ASSERTION(aContent, "missing element to close");
- mozilla::dom::NodeInfo *nodeInfo = aContent->NodeInfo();
- // Some HTML nodes need DoneAddingChildren() called to initialize
- // properly (eg form state restoration).
- if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
- (nodeInfo->NameAtom() == nsGkAtoms::select ||
- nodeInfo->NameAtom() == nsGkAtoms::textarea ||
- nodeInfo->NameAtom() == nsGkAtoms::video ||
- nodeInfo->NameAtom() == nsGkAtoms::audio ||
- nodeInfo->NameAtom() == nsGkAtoms::object ||
- nodeInfo->NameAtom() == nsGkAtoms::applet))
- || nodeInfo->NameAtom() == nsGkAtoms::title
- ) {
- aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
- }
- if (IsMonolithicContainer(nodeInfo)) {
- mInMonolithicContainer--;
- }
- if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
- !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
- return NS_OK;
- }
- if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
- || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
- ) {
- nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
- if (mPreventScriptExecution) {
- sele->PreventExecution();
- return NS_OK;
- }
- // Always check the clock in nsContentSink right after a script
- StopDeflecting();
- // Now tell the script that it's ready to go. This may execute the script
- // or return true, or neither if the script doesn't need executing.
- bool block = sele->AttemptToExecute();
- // If the parser got blocked, make sure to return the appropriate rv.
- // I'm not sure if this is actually needed or not.
- if (mParser && !mParser->IsParserEnabled()) {
- // XXX The HTML sink doesn't call BlockParser here, why do we?
- GetParser()->BlockParser();
- block = true;
- }
- return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
- }
- nsresult rv = NS_OK;
- if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
- // Need to check here to make sure this meta tag does not set
- // mPrettyPrintXML to false when we have a special root!
- (!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
- rv = ProcessMETATag(aContent);
- }
- else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
- nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
- nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
- nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
- if (ssle) {
- ssle->SetEnableUpdates(true);
- bool willNotify;
- bool isAlternate;
- rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
- &willNotify,
- &isAlternate);
- if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
- ++mPendingSheetCount;
- mScriptLoader->AddParserBlockingScriptExecutionBlocker();
- }
- }
- }
- return rv;
- }
- nsresult
- nsXMLContentSink::AddContentAsLeaf(nsIContent *aContent)
- {
- nsresult result = NS_OK;
- if (mState == eXMLContentSinkState_InProlog) {
- NS_ASSERTION(mDocument, "Fragments have no prolog");
- mDocumentChildren.AppendElement(aContent);
- } else if (mState == eXMLContentSinkState_InEpilog) {
- NS_ASSERTION(mDocument, "Fragments have no epilog");
- if (mXSLTProcessor) {
- mDocumentChildren.AppendElement(aContent);
- } else {
- mDocument->AppendChildTo(aContent, false);
- }
- } else {
- nsCOMPtr<nsIContent> parent = GetCurrentContent();
- if (parent) {
- result = parent->AppendChildTo(aContent, false);
- }
- }
- return result;
- }
- // Create an XML parser and an XSL content sink and start parsing
- // the XSL stylesheet located at the given URI.
- nsresult
- nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
- {
- nsCOMPtr<nsIDocumentTransformer> processor =
- do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt");
- if (!processor) {
- // No XSLT processor available, continue normal document loading
- return NS_OK;
- }
- processor->SetTransformObserver(this);
- if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, mDocument))) {
- mXSLTProcessor.swap(processor);
- }
- // Intentionally ignore errors here, we should continue loading the
- // XML document whether we're able to load the XSLT stylesheet or
- // not.
- return NS_OK;
- }
- nsresult
- nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
- const nsSubstring& aHref,
- bool aAlternate,
- const nsSubstring& aTitle,
- const nsSubstring& aType,
- const nsSubstring& aMedia)
- {
- nsresult rv = NS_OK;
- mPrettyPrintXML = false;
- nsAutoCString cmd;
- if (mParser)
- GetParser()->GetCommand(cmd);
- if (cmd.EqualsASCII(kLoadAsData))
- return NS_OK; // Do not load stylesheets when loading as data
- NS_ConvertUTF16toUTF8 type(aType);
- if (type.EqualsIgnoreCase(TEXT_XSL) ||
- type.EqualsIgnoreCase(APPLICATION_XSLT_XML) ||
- type.EqualsIgnoreCase(TEXT_XML) ||
- type.EqualsIgnoreCase(APPLICATION_XML)) {
- if (aAlternate) {
- // don't load alternate XSLT
- return NS_OK;
- }
- // LoadXSLStyleSheet needs a mDocShell.
- if (!mDocShell)
- return NS_OK;
- nsCOMPtr<nsIURI> url;
- rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
- mDocument->GetDocBaseURI());
- NS_ENSURE_SUCCESS(rv, rv);
- // Do security check
- nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
- rv = secMan->
- CheckLoadURIWithPrincipal(mDocument->NodePrincipal(), url,
- nsIScriptSecurityManager::ALLOW_CHROME);
- NS_ENSURE_SUCCESS(rv, NS_OK);
- // Do content policy check
- int16_t decision = nsIContentPolicy::ACCEPT;
- rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XSLT,
- url,
- mDocument->NodePrincipal(),
- aElement,
- type,
- nullptr,
- &decision,
- nsContentUtils::GetContentPolicy(),
- nsContentUtils::GetSecurityManager());
- NS_ENSURE_SUCCESS(rv, rv);
- if (NS_CP_REJECTED(decision)) {
- return NS_OK;
- }
- return LoadXSLStyleSheet(url);
- }
- // Let nsContentSink deal with css.
- rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
- aTitle, aType, aMedia);
- // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
- // pending sheets.
- return rv;
- }
- NS_IMETHODIMP
- nsXMLContentSink::SetDocumentCharset(nsACString& aCharset)
- {
- if (mDocument) {
- mDocument->SetDocumentCharacterSet(aCharset);
- }
- return NS_OK;
- }
- nsISupports *
- nsXMLContentSink::GetTarget()
- {
- return mDocument;
- }
- bool
- nsXMLContentSink::IsScriptExecuting()
- {
- return IsScriptExecutingImpl();
- }
- nsresult
- nsXMLContentSink::FlushText(bool aReleaseTextNode)
- {
- nsresult rv = NS_OK;
- if (mTextLength != 0) {
- if (mLastTextNode) {
- bool notify = HaveNotifiedForCurrentContent();
- // We could probably always increase mInNotification here since
- // if AppendText doesn't notify it shouldn't trigger evil code.
- // But just in case it does, we don't want to mask any notifications.
- if (notify) {
- ++mInNotification;
- }
- rv = mLastTextNode->AppendText(mText, mTextLength, notify);
- if (notify) {
- --mInNotification;
- }
- mTextLength = 0;
- } else {
- RefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager);
- mLastTextNode = textContent;
- // Set the text in the text node
- textContent->SetText(mText, mTextLength, false);
- mTextLength = 0;
- // Add text to its parent
- rv = AddContentAsLeaf(textContent);
- }
- }
- if (aReleaseTextNode) {
- mLastTextNode = nullptr;
- }
- return rv;
- }
- nsIContent*
- nsXMLContentSink::GetCurrentContent()
- {
- if (mContentStack.Length() == 0) {
- return nullptr;
- }
- return GetCurrentStackNode()->mContent;
- }
- StackNode*
- nsXMLContentSink::GetCurrentStackNode()
- {
- int32_t count = mContentStack.Length();
- return count != 0 ? &mContentStack[count-1] : nullptr;
- }
- nsresult
- nsXMLContentSink::PushContent(nsIContent *aContent)
- {
- NS_PRECONDITION(aContent, "Null content being pushed!");
- StackNode *sn = mContentStack.AppendElement();
- NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
- nsIContent* contentToPush = aContent;
- // When an XML parser would append a node to a template element, it
- // must instead append it to the template element's template contents.
- if (contentToPush->IsHTMLElement(nsGkAtoms::_template)) {
- HTMLTemplateElement* templateElement =
- static_cast<HTMLTemplateElement*>(contentToPush);
- contentToPush = templateElement->Content();
- }
- sn->mContent = contentToPush;
- sn->mNumFlushed = 0;
- return NS_OK;
- }
- void
- nsXMLContentSink::PopContent()
- {
- int32_t count = mContentStack.Length();
- if (count == 0) {
- NS_WARNING("Popping empty stack");
- return;
- }
- mContentStack.RemoveElementAt(count - 1);
- }
- bool
- nsXMLContentSink::HaveNotifiedForCurrentContent() const
- {
- uint32_t stackLength = mContentStack.Length();
- if (stackLength) {
- const StackNode& stackNode = mContentStack[stackLength - 1];
- nsIContent* parent = stackNode.mContent;
- return stackNode.mNumFlushed == parent->GetChildCount();
- }
- return true;
- }
- void
- nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
- {
- // XXXbz if aIgnorePendingSheets is true, what should we do when
- // mXSLTProcessor or CanStillPrettyPrint()?
- if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) {
- return;
- }
- StartLayout(aIgnorePendingSheets);
- }
- ////////////////////////////////////////////////////////////////////////
- bool
- nsXMLContentSink::SetDocElement(int32_t aNameSpaceID,
- nsIAtom* aTagName,
- nsIContent *aContent)
- {
- if (mDocElement)
- return false;
- mDocElement = aContent;
- if (mXSLTProcessor) {
- mDocumentChildren.AppendElement(aContent);
- return true;
- }
- if (!mDocumentChildren.IsEmpty()) {
- for (nsIContent* child : mDocumentChildren) {
- mDocument->AppendChildTo(child, false);
- }
- mDocumentChildren.Clear();
- }
- // check for root elements that needs special handling for
- // prettyprinting
- if ((aNameSpaceID == kNameSpaceID_XBL &&
- aTagName == nsGkAtoms::bindings) ||
- (aNameSpaceID == kNameSpaceID_XSLT &&
- (aTagName == nsGkAtoms::stylesheet ||
- aTagName == nsGkAtoms::transform))) {
- mPrettyPrintHasSpecialRoot = true;
- if (mPrettyPrintXML) {
- // In this case, disable script execution, stylesheet
- // loading, and auto XLinks since we plan to prettyprint.
- mDocument->ScriptLoader()->SetEnabled(false);
- if (mCSSLoader) {
- mCSSLoader->SetEnabled(false);
- }
- }
- }
- nsresult rv = mDocument->AppendChildTo(mDocElement, NotifyForDocElement());
- if (NS_FAILED(rv)) {
- // If we return false here, the caller will bail out because it won't
- // find a parent content node to append to, which is fine.
- return false;
- }
- if (aTagName == nsGkAtoms::html &&
- aNameSpaceID == kNameSpaceID_XHTML) {
- ProcessOfflineManifest(aContent);
- }
- return true;
- }
- NS_IMETHODIMP
- nsXMLContentSink::HandleStartElement(const char16_t *aName,
- const char16_t **aAtts,
- uint32_t aAttsCount,
- uint32_t aLineNumber)
- {
- return HandleStartElement(aName, aAtts, aAttsCount, aLineNumber,
- true);
- }
- nsresult
- nsXMLContentSink::HandleStartElement(const char16_t *aName,
- const char16_t **aAtts,
- uint32_t aAttsCount,
- uint32_t aLineNumber,
- bool aInterruptable)
- {
- NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
- // Adjust aAttsCount so it's the actual number of attributes
- aAttsCount /= 2;
- nsresult result = NS_OK;
- bool appendContent = true;
- nsCOMPtr<nsIContent> content;
- // XXX Hopefully the parser will flag this before we get
- // here. If we're in the epilog, there should be no
- // new elements
- MOZ_ASSERT(eXMLContentSinkState_InEpilog != mState);
- FlushText();
- DidAddContent();
- mState = eXMLContentSinkState_InDocumentElement;
- int32_t nameSpaceID;
- nsCOMPtr<nsIAtom> prefix, localName;
- nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
- getter_AddRefs(localName), &nameSpaceID);
- if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName, aLineNumber)) {
- return NS_OK;
- }
- RefPtr<mozilla::dom::NodeInfo> nodeInfo;
- nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
- nsIDOMNode::ELEMENT_NODE);
- result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
- getter_AddRefs(content), &appendContent,
- FROM_PARSER_NETWORK);
- NS_ENSURE_SUCCESS(result, result);
- // Have to do this before we push the new content on the stack... and have to
- // do that before we set attributes, call BindToTree, etc. Ideally we'd push
- // on the stack inside CreateElement (which is effectively what the HTML sink
- // does), but that's hard with all the subclass overrides going on.
- nsCOMPtr<nsIContent> parent = GetCurrentContent();
- result = PushContent(content);
- NS_ENSURE_SUCCESS(result, result);
- // Set the attributes on the new content element
- result = AddAttributes(aAtts, content);
- if (NS_OK == result) {
- // Store the element
- if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
- NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
- parent->AppendChildTo(content, false);
- }
- }
- // Some HTML nodes need DoneCreatingElement() called to initialize
- // properly (eg form state restoration).
- if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML) {
- if (nodeInfo->NameAtom() == nsGkAtoms::input ||
- nodeInfo->NameAtom() == nsGkAtoms::button ||
- nodeInfo->NameAtom() == nsGkAtoms::menuitem ||
- nodeInfo->NameAtom() == nsGkAtoms::audio ||
- nodeInfo->NameAtom() == nsGkAtoms::video) {
- content->DoneCreatingElement();
- } else if (nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) {
- mCurrentHead = content;
- }
- }
- if (IsMonolithicContainer(nodeInfo)) {
- mInMonolithicContainer++;
- }
- if (!mXSLTProcessor) {
- if (content == mDocElement) {
- NotifyDocElementCreated(mDocument);
- } else if (!mCurrentHead) {
- // This isn't the root and we're not inside an XHTML <head>.
- // Might need to start layout
- MaybeStartLayout(false);
- }
- }
- return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
- result;
- }
- NS_IMETHODIMP
- nsXMLContentSink::HandleEndElement(const char16_t *aName)
- {
- return HandleEndElement(aName, true);
- }
- nsresult
- nsXMLContentSink::HandleEndElement(const char16_t *aName,
- bool aInterruptable)
- {
- nsresult result = NS_OK;
- // XXX Hopefully the parser will flag this before we get
- // here. If we're in the prolog or epilog, there should be
- // no close tags for elements.
- MOZ_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
- FlushText();
- StackNode* sn = GetCurrentStackNode();
- if (!sn) {
- return NS_ERROR_UNEXPECTED;
- }
- nsCOMPtr<nsIContent> content;
- sn->mContent.swap(content);
- uint32_t numFlushed = sn->mNumFlushed;
- PopContent();
- NS_ASSERTION(content, "failed to pop content");
- #ifdef DEBUG
- // Check that we're closing the right thing
- nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom;
- int32_t debugNameSpaceID;
- nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
- getter_AddRefs(debugTagAtom),
- &debugNameSpaceID);
- // Check if we are closing a template element because template
- // elements do not get pushed on the stack, the template
- // element content is pushed instead.
- bool isTemplateElement = debugTagAtom == nsGkAtoms::_template &&
- debugNameSpaceID == kNameSpaceID_XHTML;
- NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID) ||
- (debugNameSpaceID == kNameSpaceID_MathML &&
- content->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_MathML &&
- content->NodeInfo()->Equals(debugTagAtom)) ||
- isTemplateElement, "Wrong element being closed");
- #endif
- result = CloseElement(content);
- if (mCurrentHead == content) {
- mCurrentHead = nullptr;
- }
- if (mDocElement == content) {
- // XXXbz for roots that don't want to be appended on open, we
- // probably need to deal here.... (and stop appending them on open).
- mState = eXMLContentSinkState_InEpilog;
- // We might have had no occasion to start layout yet. Do so now.
- MaybeStartLayout(false);
- }
- int32_t stackLen = mContentStack.Length();
- if (mNotifyLevel >= stackLen) {
- if (numFlushed < content->GetChildCount()) {
- NotifyAppend(content, numFlushed);
- }
- mNotifyLevel = stackLen - 1;
- }
- DidAddContent();
- if (content->IsSVGElement(nsGkAtoms::svg)) {
- FlushTags();
- nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content);
- if (NS_FAILED(NS_DispatchToMainThread(event))) {
- NS_WARNING("failed to dispatch svg load dispatcher");
- }
- }
- return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
- result;
- }
- NS_IMETHODIMP
- nsXMLContentSink::HandleComment(const char16_t *aName)
- {
- FlushText();
- RefPtr<Comment> comment = new Comment(mNodeInfoManager);
- comment->SetText(nsDependentString(aName), false);
- nsresult rv = AddContentAsLeaf(comment);
- DidAddContent();
- return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
- }
- NS_IMETHODIMP
- nsXMLContentSink::HandleCDataSection(const char16_t *aData,
- uint32_t aLength)
- {
- // XSLT doesn't differentiate between text and cdata and wants adjacent
- // textnodes merged, so add as text.
- if (mXSLTProcessor) {
- return AddText(aData, aLength);
- }
- FlushText();
- RefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager);
- cdata->SetText(aData, aLength, false);
- nsresult rv = AddContentAsLeaf(cdata);
- DidAddContent();
- return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
- }
- NS_IMETHODIMP
- nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset,
- const nsAString & aName,
- const nsAString & aSystemId,
- const nsAString & aPublicId,
- nsISupports* aCatalogData)
- {
- FlushText();
- nsresult rv = NS_OK;
- NS_ASSERTION(mDocument, "Shouldn't get here from a document fragment");
- nsCOMPtr<nsIAtom> name = NS_Atomize(aName);
- NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
- // Create a new doctype node
- nsCOMPtr<nsIDOMDocumentType> docType;
- rv = NS_NewDOMDocumentType(getter_AddRefs(docType), mNodeInfoManager,
- name, aPublicId, aSystemId, aSubset);
- if (NS_FAILED(rv) || !docType) {
- return rv;
- }
- MOZ_ASSERT(!aCatalogData, "Need to add back support for catalog style "
- "sheets");
- nsCOMPtr<nsIContent> content = do_QueryInterface(docType);
- NS_ASSERTION(content, "doctype isn't content?");
- mDocumentChildren.AppendElement(content);
- DidAddContent();
- return DidProcessATokenImpl();
- }
- NS_IMETHODIMP
- nsXMLContentSink::HandleCharacterData(const char16_t *aData,
- uint32_t aLength)
- {
- return HandleCharacterData(aData, aLength, true);
- }
- nsresult
- nsXMLContentSink::HandleCharacterData(const char16_t *aData, uint32_t aLength,
- bool aInterruptable)
- {
- nsresult rv = NS_OK;
- if (aData && mState != eXMLContentSinkState_InProlog &&
- mState != eXMLContentSinkState_InEpilog) {
- rv = AddText(aData, aLength);
- }
- return aInterruptable && NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
- }
- NS_IMETHODIMP
- nsXMLContentSink::HandleProcessingInstruction(const char16_t *aTarget,
- const char16_t *aData)
- {
- FlushText();
- const nsDependentString target(aTarget);
- const nsDependentString data(aData);
- nsCOMPtr<nsIContent> node =
- NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data);
- nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node));
- if (ssle) {
- ssle->InitStyleLinkElement(false);
- ssle->SetEnableUpdates(false);
- mPrettyPrintXML = false;
- }
- nsresult rv = AddContentAsLeaf(node);
- NS_ENSURE_SUCCESS(rv, rv);
- DidAddContent();
- if (ssle) {
- // This is an xml-stylesheet processing instruction... but it might not be
- // a CSS one if the type is set to something else.
- ssle->SetEnableUpdates(true);
- bool willNotify;
- bool isAlternate;
- rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
- &willNotify,
- &isAlternate);
- NS_ENSURE_SUCCESS(rv, rv);
- if (willNotify) {
- // Successfully started a stylesheet load
- if (!isAlternate && !mRunsToCompletion) {
- ++mPendingSheetCount;
- mScriptLoader->AddParserBlockingScriptExecutionBlocker();
- }
- return NS_OK;
- }
- }
- // If it's not a CSS stylesheet PI...
- nsAutoString type;
- nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
- if (mState != eXMLContentSinkState_InProlog ||
- !target.EqualsLiteral("xml-stylesheet") ||
- type.IsEmpty() ||
- type.LowerCaseEqualsLiteral("text/css")) {
- return DidProcessATokenImpl();
- }
- nsAutoString href, title, media;
- bool isAlternate = false;
- // If there was no href, we can't do anything with this PI
- if (!ParsePIData(data, href, title, media, isAlternate)) {
- return DidProcessATokenImpl();
- }
- rv = ProcessStyleLink(node, href, isAlternate, title, type, media);
- return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
- }
- /* static */
- bool
- nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref,
- nsString &aTitle, nsString &aMedia,
- bool &aIsAlternate)
- {
- // If there was no href, we can't do anything with this PI
- if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) {
- return false;
- }
- nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle);
- nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia);
- nsAutoString alternate;
- nsContentUtils::GetPseudoAttributeValue(aData,
- nsGkAtoms::alternate,
- alternate);
- aIsAlternate = alternate.EqualsLiteral("yes");
- return true;
- }
- NS_IMETHODIMP
- nsXMLContentSink::HandleXMLDeclaration(const char16_t *aVersion,
- const char16_t *aEncoding,
- int32_t aStandalone)
- {
- mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone);
- return DidProcessATokenImpl();
- }
- NS_IMETHODIMP
- nsXMLContentSink::ReportError(const char16_t* aErrorText,
- const char16_t* aSourceText,
- nsIScriptError *aError,
- bool *_retval)
- {
- NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
- nsresult rv = NS_OK;
- // The expat driver should report the error. We're just cleaning up the mess.
- *_retval = true;
- mPrettyPrintXML = false;
- mState = eXMLContentSinkState_InProlog;
- // XXX need to stop scripts here -- hsivonen
- // stop observing in order to avoid crashing when removing content
- mDocument->RemoveObserver(this);
- mIsDocumentObserver = false;
- // Clear the current content
- mDocumentChildren.Clear();
- nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mDocument));
- if (node) {
- for (;;) {
- nsCOMPtr<nsIDOMNode> child, dummy;
- node->GetLastChild(getter_AddRefs(child));
- if (!child)
- break;
- node->RemoveChild(child, getter_AddRefs(dummy));
- }
- }
- mDocElement = nullptr;
- // Clear any buffered-up text we have. It's enough to set the length to 0.
- // The buffer itself is allocated when we're created and deleted in our
- // destructor, so don't mess with it.
- mTextLength = 0;
- if (mXSLTProcessor) {
- // Get rid of the XSLT processor.
- mXSLTProcessor->CancelLoads();
- mXSLTProcessor = nullptr;
- }
- // release the nodes on stack
- mContentStack.Clear();
- mNotifyLevel = 0;
- // return leaving the document empty if we're asked to not add a <parsererror> root node
- if (mDocument->SuppressParserErrorElement()) {
- return NS_OK;
- }
- // prepare to set <parsererror> as the document root
- rv = HandleProcessingInstruction(u"xml-stylesheet",
- u"href=\"chrome://global/locale/intl.css\" type=\"text/css\"");
- NS_ENSURE_SUCCESS(rv, rv);
- const char16_t* noAtts[] = { 0, 0 };
- NS_NAMED_LITERAL_STRING(errorNs,
- "http://www.mozilla.org/newlayout/xml/parsererror.xml");
- nsAutoString parsererror(errorNs);
- parsererror.Append((char16_t)0xFFFF);
- parsererror.AppendLiteral("parsererror");
- rv = HandleStartElement(parsererror.get(), noAtts, 0, (uint32_t)-1,
- false);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false);
- NS_ENSURE_SUCCESS(rv, rv);
- nsAutoString sourcetext(errorNs);
- sourcetext.Append((char16_t)0xFFFF);
- sourcetext.AppendLiteral("sourcetext");
- rv = HandleStartElement(sourcetext.get(), noAtts, 0, (uint32_t)-1,
- false);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText), false);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = HandleEndElement(sourcetext.get(), false);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = HandleEndElement(parsererror.get(), false);
- NS_ENSURE_SUCCESS(rv, rv);
- FlushTags();
- return NS_OK;
- }
- nsresult
- nsXMLContentSink::AddAttributes(const char16_t** aAtts,
- nsIContent* aContent)
- {
- // Add tag attributes to the content attributes
- nsCOMPtr<nsIAtom> prefix, localName;
- while (*aAtts) {
- int32_t nameSpaceID;
- nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
- getter_AddRefs(localName), &nameSpaceID);
- // Add attribute to content
- aContent->SetAttr(nameSpaceID, localName, prefix,
- nsDependentString(aAtts[1]), false);
- aAtts += 2;
- }
- return NS_OK;
- }
- #define NS_ACCUMULATION_BUFFER_SIZE 4096
- nsresult
- nsXMLContentSink::AddText(const char16_t* aText,
- int32_t aLength)
- {
- // Copy data from string into our buffer; flush buffer when it fills up.
- int32_t offset = 0;
- while (0 != aLength) {
- int32_t amount = NS_ACCUMULATION_BUFFER_SIZE - mTextLength;
- if (0 == amount) {
- nsresult rv = FlushText(false);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- MOZ_ASSERT(mTextLength == 0);
- amount = NS_ACCUMULATION_BUFFER_SIZE;
- }
- if (amount > aLength) {
- amount = aLength;
- }
- memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount);
- mTextLength += amount;
- offset += amount;
- aLength -= amount;
- }
- return NS_OK;
- }
- void
- nsXMLContentSink::FlushPendingNotifications(mozFlushType aType)
- {
- // Only flush tags if we're not doing the notification ourselves
- // (since we aren't reentrant)
- if (!mInNotification) {
- if (mIsDocumentObserver) {
- // Only flush if we're still a document observer (so that our child
- // counts should be correct).
- if (aType >= Flush_ContentAndNotify) {
- FlushTags();
- }
- else {
- FlushText(false);
- }
- }
- if (aType >= Flush_InterruptibleLayout) {
- // Make sure that layout has started so that the reflow flush
- // will actually happen.
- MaybeStartLayout(true);
- }
- }
- }
- /**
- * NOTE!! Forked from SinkContext. Please keep in sync.
- *
- * Flush all elements that have been seen so far such that
- * they are visible in the tree. Specifically, make sure
- * that they are all added to their respective parents.
- * Also, do notification at the top for all content that
- * has been newly added so that the frame tree is complete.
- */
- nsresult
- nsXMLContentSink::FlushTags()
- {
- mDeferredFlushTags = false;
- bool oldBeganUpdate = mBeganUpdate;
- uint32_t oldUpdates = mUpdatesInNotification;
- mUpdatesInNotification = 0;
- ++mInNotification;
- {
- // Scope so we call EndUpdate before we decrease mInNotification
- mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, true);
- mBeganUpdate = true;
- // Don't release last text node in case we need to add to it again
- FlushText(false);
- // Start from the base of the stack (growing downward) and do
- // a notification from the node that is closest to the root of
- // tree for any content that has been added.
- int32_t stackPos;
- int32_t stackLen = mContentStack.Length();
- bool flushed = false;
- uint32_t childCount;
- nsIContent* content;
- for (stackPos = 0; stackPos < stackLen; ++stackPos) {
- content = mContentStack[stackPos].mContent;
- childCount = content->GetChildCount();
- if (!flushed && (mContentStack[stackPos].mNumFlushed < childCount)) {
- NotifyAppend(content, mContentStack[stackPos].mNumFlushed);
- flushed = true;
- }
- mContentStack[stackPos].mNumFlushed = childCount;
- }
- mNotifyLevel = stackLen - 1;
- }
- --mInNotification;
- if (mUpdatesInNotification > 1) {
- UpdateChildCounts();
- }
- mUpdatesInNotification = oldUpdates;
- mBeganUpdate = oldBeganUpdate;
- return NS_OK;
- }
- /**
- * NOTE!! Forked from SinkContext. Please keep in sync.
- */
- void
- nsXMLContentSink::UpdateChildCounts()
- {
- // Start from the top of the stack (growing upwards) and see if any
- // new content has been appended. If so, we recognize that reflows
- // have been generated for it and we should make sure that no
- // further reflows occur. Note that we have to include stackPos == 0
- // to properly notify on kids of <html>.
- int32_t stackLen = mContentStack.Length();
- int32_t stackPos = stackLen - 1;
- while (stackPos >= 0) {
- StackNode & node = mContentStack[stackPos];
- node.mNumFlushed = node.mContent->GetChildCount();
- stackPos--;
- }
- mNotifyLevel = stackLen - 1;
- }
- bool
- nsXMLContentSink::IsMonolithicContainer(mozilla::dom::NodeInfo* aNodeInfo)
- {
- return ((aNodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
- (aNodeInfo->NameAtom() == nsGkAtoms::tr ||
- aNodeInfo->NameAtom() == nsGkAtoms::select ||
- aNodeInfo->NameAtom() == nsGkAtoms::object ||
- aNodeInfo->NameAtom() == nsGkAtoms::applet)) ||
- (aNodeInfo->NamespaceID() == kNameSpaceID_MathML &&
- (aNodeInfo->NameAtom() == nsGkAtoms::math))
- );
- }
- void
- nsXMLContentSink::ContinueInterruptedParsingIfEnabled()
- {
- if (mParser && mParser->IsParserEnabled()) {
- GetParser()->ContinueInterruptedParsing();
- }
- }
- void
- nsXMLContentSink::ContinueInterruptedParsingAsync()
- {
- nsCOMPtr<nsIRunnable> ev = NewRunnableMethod(this,
- &nsXMLContentSink::ContinueInterruptedParsingIfEnabled);
- NS_DispatchToCurrentThread(ev);
- }
- nsIParser*
- nsXMLContentSink::GetParser()
- {
- return static_cast<nsIParser*>(mParser.get());
- }
|