nsXMLContentSink.cpp 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsCOMPtr.h"
  6. #include "nsXMLContentSink.h"
  7. #include "nsIParser.h"
  8. #include "nsIDocument.h"
  9. #include "nsIDOMDocument.h"
  10. #include "nsIDOMDocumentType.h"
  11. #include "nsIContent.h"
  12. #include "nsIURI.h"
  13. #include "nsNetUtil.h"
  14. #include "nsIDocShell.h"
  15. #include "nsIStyleSheetLinkingElement.h"
  16. #include "nsIDOMComment.h"
  17. #include "nsIDOMCDATASection.h"
  18. #include "DocumentType.h"
  19. #include "nsHTMLParts.h"
  20. #include "nsCRT.h"
  21. #include "mozilla/StyleSheetInlines.h"
  22. #include "mozilla/css/Loader.h"
  23. #include "nsGkAtoms.h"
  24. #include "nsContentUtils.h"
  25. #include "nsIScriptContext.h"
  26. #include "nsNameSpaceManager.h"
  27. #include "nsIServiceManager.h"
  28. #include "nsIScriptSecurityManager.h"
  29. #include "nsIContentViewer.h"
  30. #include "prtime.h"
  31. #include "mozilla/Logging.h"
  32. #include "prmem.h"
  33. #include "nsRect.h"
  34. #include "nsIWebNavigation.h"
  35. #include "nsIScriptElement.h"
  36. #include "nsStyleLinkElement.h"
  37. #include "nsReadableUtils.h"
  38. #include "nsUnicharUtils.h"
  39. #include "nsICookieService.h"
  40. #include "nsIPrompt.h"
  41. #include "nsIChannel.h"
  42. #include "nsIPrincipal.h"
  43. #include "nsXMLPrettyPrinter.h"
  44. #include "nsNodeInfoManager.h"
  45. #include "nsContentCreatorFunctions.h"
  46. #include "nsIContentPolicy.h"
  47. #include "nsContentPolicyUtils.h"
  48. #include "nsError.h"
  49. #include "nsIDOMProcessingInstruction.h"
  50. #include "nsNodeUtils.h"
  51. #include "nsIScriptGlobalObject.h"
  52. #include "nsIHTMLDocument.h"
  53. #include "mozAutoDocUpdate.h"
  54. #include "nsMimeTypes.h"
  55. #include "nsHtml5SVGLoadDispatcher.h"
  56. #include "nsTextNode.h"
  57. #include "mozilla/dom/CDATASection.h"
  58. #include "mozilla/dom/Comment.h"
  59. #include "mozilla/dom/Element.h"
  60. #include "mozilla/dom/HTMLTemplateElement.h"
  61. #include "mozilla/dom/ProcessingInstruction.h"
  62. #include "mozilla/dom/ScriptLoader.h"
  63. using namespace mozilla;
  64. using namespace mozilla::dom;
  65. // XXX Open Issues:
  66. // 1) what's not allowed - We need to figure out which HTML tags
  67. // (prefixed with a HTML namespace qualifier) are explicitly not
  68. // allowed (if any).
  69. // 2) factoring code with nsHTMLContentSink - There's some amount of
  70. // common code between this and the HTML content sink. This will
  71. // increase as we support more and more HTML elements. How can code
  72. // from the code be factored?
  73. nsresult
  74. NS_NewXMLContentSink(nsIXMLContentSink** aResult,
  75. nsIDocument* aDoc,
  76. nsIURI* aURI,
  77. nsISupports* aContainer,
  78. nsIChannel* aChannel)
  79. {
  80. NS_PRECONDITION(nullptr != aResult, "null ptr");
  81. if (nullptr == aResult) {
  82. return NS_ERROR_NULL_POINTER;
  83. }
  84. RefPtr<nsXMLContentSink> it = new nsXMLContentSink();
  85. nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
  86. NS_ENSURE_SUCCESS(rv, rv);
  87. it.forget(aResult);
  88. return NS_OK;
  89. }
  90. nsXMLContentSink::nsXMLContentSink()
  91. : mTextLength(0)
  92. , mNotifyLevel(0)
  93. , mPrettyPrintXML(true)
  94. , mPrettyPrintHasSpecialRoot(0)
  95. , mPrettyPrintHasFactoredElements(0)
  96. , mPrettyPrinting(0)
  97. , mPreventScriptExecution(0)
  98. {
  99. PodArrayZero(mText);
  100. }
  101. nsXMLContentSink::~nsXMLContentSink()
  102. {
  103. }
  104. nsresult
  105. nsXMLContentSink::Init(nsIDocument* aDoc,
  106. nsIURI* aURI,
  107. nsISupports* aContainer,
  108. nsIChannel* aChannel)
  109. {
  110. nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
  111. NS_ENSURE_SUCCESS(rv, rv);
  112. aDoc->AddObserver(this);
  113. mIsDocumentObserver = true;
  114. if (!mDocShell) {
  115. mPrettyPrintXML = false;
  116. }
  117. mState = eXMLContentSinkState_InProlog;
  118. mDocElement = nullptr;
  119. return NS_OK;
  120. }
  121. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink)
  122. NS_INTERFACE_MAP_ENTRY(nsIContentSink)
  123. NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
  124. NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
  125. NS_INTERFACE_MAP_ENTRY(nsITransformObserver)
  126. NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
  127. NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink)
  128. NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink)
  129. NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink)
  130. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink,
  131. nsContentSink)
  132. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentHead)
  133. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocElement)
  134. for (uint32_t i = 0, count = tmp->mContentStack.Length(); i < count; i++) {
  135. const StackNode& node = tmp->mContentStack.ElementAt(i);
  136. cb.NoteXPCOMChild(node.mContent);
  137. }
  138. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentChildren)
  139. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  140. // nsIContentSink
  141. NS_IMETHODIMP
  142. nsXMLContentSink::WillParse(void)
  143. {
  144. return WillParseImpl();
  145. }
  146. NS_IMETHODIMP
  147. nsXMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
  148. {
  149. WillBuildModelImpl();
  150. // Notify document that the load is beginning
  151. mDocument->BeginLoad();
  152. // Check for correct load-command for maybe prettyprinting
  153. if (mPrettyPrintXML) {
  154. nsAutoCString command;
  155. GetParser()->GetCommand(command);
  156. if (!command.EqualsLiteral("view")) {
  157. mPrettyPrintXML = false;
  158. }
  159. }
  160. return NS_OK;
  161. }
  162. bool
  163. nsXMLContentSink::CanStillPrettyPrint()
  164. {
  165. return mPrettyPrintXML &&
  166. (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot);
  167. }
  168. nsresult
  169. nsXMLContentSink::MaybePrettyPrint()
  170. {
  171. if (!CanStillPrettyPrint()) {
  172. mPrettyPrintXML = false;
  173. return NS_OK;
  174. }
  175. // stop observing in order to avoid crashing when replacing content
  176. mDocument->RemoveObserver(this);
  177. mIsDocumentObserver = false;
  178. // Reenable the CSSLoader so that the prettyprinting stylesheets can load
  179. if (mCSSLoader) {
  180. mCSSLoader->SetEnabled(true);
  181. }
  182. RefPtr<nsXMLPrettyPrinter> printer;
  183. nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer));
  184. NS_ENSURE_SUCCESS(rv, rv);
  185. bool isPrettyPrinting;
  186. rv = printer->PrettyPrint(mDocument, &isPrettyPrinting);
  187. NS_ENSURE_SUCCESS(rv, rv);
  188. mPrettyPrinting = isPrettyPrinting;
  189. return NS_OK;
  190. }
  191. static void
  192. CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
  193. nsIDocumentTransformer* aProcessor,
  194. nsIDocument* aDocument)
  195. {
  196. nsAutoString target, data;
  197. aPi->GetTarget(target);
  198. // Check for namespace declarations
  199. if (target.EqualsLiteral("xslt-param-namespace")) {
  200. aPi->GetData(data);
  201. nsAutoString prefix, namespaceAttr;
  202. nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix,
  203. prefix);
  204. if (!prefix.IsEmpty() &&
  205. nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
  206. namespaceAttr)) {
  207. aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
  208. }
  209. }
  210. // Check for actual parameters
  211. else if (target.EqualsLiteral("xslt-param")) {
  212. aPi->GetData(data);
  213. nsAutoString name, namespaceAttr, select, value;
  214. nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name,
  215. name);
  216. nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
  217. namespaceAttr);
  218. if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) {
  219. select.SetIsVoid(true);
  220. }
  221. if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) {
  222. value.SetIsVoid(true);
  223. }
  224. if (!name.IsEmpty()) {
  225. nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
  226. aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc);
  227. }
  228. }
  229. }
  230. NS_IMETHODIMP
  231. nsXMLContentSink::DidBuildModel(bool aTerminated)
  232. {
  233. if (!mParser) {
  234. // If mParser is null, this parse has already been terminated and must
  235. // not been terminated again. However, nsDocument may still think that
  236. // the parse has not been terminated and call back into here in the case
  237. // where the XML parser has finished but the XSLT transform associated
  238. // with the document has not.
  239. return NS_OK;
  240. }
  241. DidBuildModelImpl(aTerminated);
  242. if (mXSLTProcessor) {
  243. // stop observing in order to avoid crashing when replacing content
  244. mDocument->RemoveObserver(this);
  245. mIsDocumentObserver = false;
  246. // Check for xslt-param and xslt-param-namespace PIs
  247. for (nsIContent* child = mDocument->GetFirstChild();
  248. child;
  249. child = child->GetNextSibling()) {
  250. if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
  251. nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
  252. CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
  253. }
  254. else if (child->IsElement()) {
  255. // Only honor PIs in the prolog
  256. break;
  257. }
  258. }
  259. mXSLTProcessor->SetSourceContentModel(mDocument, mDocumentChildren);
  260. // Since the processor now holds a reference to us we drop our reference
  261. // to it to avoid owning cycles
  262. mXSLTProcessor = nullptr;
  263. }
  264. else {
  265. // Kick off layout for non-XSLT transformed documents.
  266. // Check if we want to prettyprint
  267. MaybePrettyPrint();
  268. bool startLayout = true;
  269. if (mPrettyPrinting) {
  270. NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
  271. // We're pretty-printing now. See whether we should wait up on
  272. // stylesheet loads
  273. if (mDocument->CSSLoader()->HasPendingLoads() &&
  274. NS_SUCCEEDED(mDocument->CSSLoader()->AddObserver(this))) {
  275. // wait for those sheets to load
  276. startLayout = false;
  277. }
  278. }
  279. if (startLayout) {
  280. StartLayout(false);
  281. ScrollToRef();
  282. }
  283. mDocument->RemoveObserver(this);
  284. mIsDocumentObserver = false;
  285. mDocument->EndLoad();
  286. }
  287. DropParserAndPerfHint();
  288. return NS_OK;
  289. }
  290. NS_IMETHODIMP
  291. nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument)
  292. {
  293. NS_ENSURE_ARG(aResultDocument);
  294. nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aResultDocument);
  295. if (htmlDoc) {
  296. htmlDoc->SetDocWriteDisabled(true);
  297. }
  298. nsCOMPtr<nsIContentViewer> contentViewer;
  299. mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
  300. if (contentViewer) {
  301. return contentViewer->SetDocumentInternal(aResultDocument, true);
  302. }
  303. return NS_OK;
  304. }
  305. NS_IMETHODIMP
  306. nsXMLContentSink::OnTransformDone(nsresult aResult,
  307. nsIDocument* aResultDocument)
  308. {
  309. MOZ_ASSERT(aResultDocument, "Don't notify about transform end without a document.");
  310. mDocumentChildren.Clear();
  311. nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aResultDocument);
  312. nsCOMPtr<nsIContentViewer> contentViewer;
  313. mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
  314. if (NS_FAILED(aResult) && contentViewer) {
  315. // Transform failed.
  316. aResultDocument->SetMayStartLayout(false);
  317. // We have an error document.
  318. contentViewer->SetDOMDocument(domDoc);
  319. }
  320. nsCOMPtr<nsIDocument> originalDocument = mDocument;
  321. // Transform succeeded, or it failed and we have an error document to display.
  322. mDocument = aResultDocument;
  323. nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
  324. if (htmlDoc) {
  325. htmlDoc->SetDocWriteDisabled(false);
  326. }
  327. // Notify document observers that all the content has been stuck
  328. // into the document.
  329. // XXX do we need to notify for things like PIs? Or just the
  330. // documentElement?
  331. nsIContent *rootElement = mDocument->GetRootElement();
  332. if (rootElement) {
  333. NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
  334. "rootElement not in doc?");
  335. mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
  336. nsNodeUtils::ContentInserted(mDocument, rootElement,
  337. mDocument->IndexOf(rootElement));
  338. mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
  339. }
  340. // Start the layout process
  341. StartLayout(false);
  342. ScrollToRef();
  343. originalDocument->EndLoad();
  344. return NS_OK;
  345. }
  346. NS_IMETHODIMP
  347. nsXMLContentSink::StyleSheetLoaded(StyleSheet* aSheet,
  348. bool aWasAlternate,
  349. nsresult aStatus)
  350. {
  351. if (!mPrettyPrinting) {
  352. return nsContentSink::StyleSheetLoaded(aSheet, aWasAlternate, aStatus);
  353. }
  354. if (!mDocument->CSSLoader()->HasPendingLoads()) {
  355. mDocument->CSSLoader()->RemoveObserver(this);
  356. StartLayout(false);
  357. ScrollToRef();
  358. }
  359. return NS_OK;
  360. }
  361. NS_IMETHODIMP
  362. nsXMLContentSink::WillInterrupt(void)
  363. {
  364. return WillInterruptImpl();
  365. }
  366. NS_IMETHODIMP
  367. nsXMLContentSink::WillResume(void)
  368. {
  369. return WillResumeImpl();
  370. }
  371. NS_IMETHODIMP
  372. nsXMLContentSink::SetParser(nsParserBase* aParser)
  373. {
  374. NS_PRECONDITION(aParser, "Should have a parser here!");
  375. mParser = aParser;
  376. return NS_OK;
  377. }
  378. nsresult
  379. nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
  380. mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
  381. nsIContent** aResult, bool* aAppendContent,
  382. FromParser aFromParser)
  383. {
  384. NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
  385. *aResult = nullptr;
  386. *aAppendContent = true;
  387. nsresult rv = NS_OK;
  388. RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
  389. RefPtr<Element> content;
  390. rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
  391. NS_ENSURE_SUCCESS(rv, rv);
  392. if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
  393. || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
  394. ) {
  395. nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
  396. sele->SetScriptLineNumber(aLineNumber);
  397. sele->SetCreatorParser(GetParser());
  398. }
  399. // XHTML needs some special attention
  400. if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
  401. mPrettyPrintHasFactoredElements = true;
  402. }
  403. else {
  404. // If we care, find out if we just used a special factory.
  405. if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
  406. mPrettyPrintXML) {
  407. mPrettyPrintHasFactoredElements =
  408. nsContentUtils::NameSpaceManager()->
  409. HasElementCreator(aNodeInfo->NamespaceID());
  410. }
  411. if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
  412. content.forget(aResult);
  413. return NS_OK;
  414. }
  415. }
  416. if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
  417. aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
  418. aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
  419. nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
  420. if (ssle) {
  421. ssle->InitStyleLinkElement(false);
  422. if (aFromParser) {
  423. ssle->SetEnableUpdates(false);
  424. }
  425. if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
  426. ssle->SetLineNumber(aFromParser ? aLineNumber : 0);
  427. }
  428. }
  429. }
  430. content.forget(aResult);
  431. return NS_OK;
  432. }
  433. nsresult
  434. nsXMLContentSink::CloseElement(nsIContent* aContent)
  435. {
  436. NS_ASSERTION(aContent, "missing element to close");
  437. mozilla::dom::NodeInfo *nodeInfo = aContent->NodeInfo();
  438. // Some HTML nodes need DoneAddingChildren() called to initialize
  439. // properly (eg form state restoration).
  440. if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
  441. (nodeInfo->NameAtom() == nsGkAtoms::select ||
  442. nodeInfo->NameAtom() == nsGkAtoms::textarea ||
  443. nodeInfo->NameAtom() == nsGkAtoms::video ||
  444. nodeInfo->NameAtom() == nsGkAtoms::audio ||
  445. nodeInfo->NameAtom() == nsGkAtoms::object ||
  446. nodeInfo->NameAtom() == nsGkAtoms::applet))
  447. || nodeInfo->NameAtom() == nsGkAtoms::title
  448. ) {
  449. aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
  450. }
  451. if (IsMonolithicContainer(nodeInfo)) {
  452. mInMonolithicContainer--;
  453. }
  454. if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
  455. !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
  456. return NS_OK;
  457. }
  458. if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
  459. || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
  460. ) {
  461. nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
  462. if (mPreventScriptExecution) {
  463. sele->PreventExecution();
  464. return NS_OK;
  465. }
  466. // Always check the clock in nsContentSink right after a script
  467. StopDeflecting();
  468. // Now tell the script that it's ready to go. This may execute the script
  469. // or return true, or neither if the script doesn't need executing.
  470. bool block = sele->AttemptToExecute();
  471. // If the parser got blocked, make sure to return the appropriate rv.
  472. // I'm not sure if this is actually needed or not.
  473. if (mParser && !mParser->IsParserEnabled()) {
  474. // XXX The HTML sink doesn't call BlockParser here, why do we?
  475. GetParser()->BlockParser();
  476. block = true;
  477. }
  478. return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
  479. }
  480. nsresult rv = NS_OK;
  481. if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
  482. // Need to check here to make sure this meta tag does not set
  483. // mPrettyPrintXML to false when we have a special root!
  484. (!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
  485. rv = ProcessMETATag(aContent);
  486. }
  487. else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
  488. nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
  489. nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
  490. nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
  491. if (ssle) {
  492. ssle->SetEnableUpdates(true);
  493. bool willNotify;
  494. bool isAlternate;
  495. rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
  496. &willNotify,
  497. &isAlternate);
  498. if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
  499. ++mPendingSheetCount;
  500. mScriptLoader->AddParserBlockingScriptExecutionBlocker();
  501. }
  502. }
  503. }
  504. return rv;
  505. }
  506. nsresult
  507. nsXMLContentSink::AddContentAsLeaf(nsIContent *aContent)
  508. {
  509. nsresult result = NS_OK;
  510. if (mState == eXMLContentSinkState_InProlog) {
  511. NS_ASSERTION(mDocument, "Fragments have no prolog");
  512. mDocumentChildren.AppendElement(aContent);
  513. } else if (mState == eXMLContentSinkState_InEpilog) {
  514. NS_ASSERTION(mDocument, "Fragments have no epilog");
  515. if (mXSLTProcessor) {
  516. mDocumentChildren.AppendElement(aContent);
  517. } else {
  518. mDocument->AppendChildTo(aContent, false);
  519. }
  520. } else {
  521. nsCOMPtr<nsIContent> parent = GetCurrentContent();
  522. if (parent) {
  523. result = parent->AppendChildTo(aContent, false);
  524. }
  525. }
  526. return result;
  527. }
  528. // Create an XML parser and an XSL content sink and start parsing
  529. // the XSL stylesheet located at the given URI.
  530. nsresult
  531. nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
  532. {
  533. nsCOMPtr<nsIDocumentTransformer> processor =
  534. do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt");
  535. if (!processor) {
  536. // No XSLT processor available, continue normal document loading
  537. return NS_OK;
  538. }
  539. processor->SetTransformObserver(this);
  540. if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, mDocument))) {
  541. mXSLTProcessor.swap(processor);
  542. }
  543. // Intentionally ignore errors here, we should continue loading the
  544. // XML document whether we're able to load the XSLT stylesheet or
  545. // not.
  546. return NS_OK;
  547. }
  548. nsresult
  549. nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
  550. const nsSubstring& aHref,
  551. bool aAlternate,
  552. const nsSubstring& aTitle,
  553. const nsSubstring& aType,
  554. const nsSubstring& aMedia)
  555. {
  556. nsresult rv = NS_OK;
  557. mPrettyPrintXML = false;
  558. nsAutoCString cmd;
  559. if (mParser)
  560. GetParser()->GetCommand(cmd);
  561. if (cmd.EqualsASCII(kLoadAsData))
  562. return NS_OK; // Do not load stylesheets when loading as data
  563. NS_ConvertUTF16toUTF8 type(aType);
  564. if (type.EqualsIgnoreCase(TEXT_XSL) ||
  565. type.EqualsIgnoreCase(APPLICATION_XSLT_XML) ||
  566. type.EqualsIgnoreCase(TEXT_XML) ||
  567. type.EqualsIgnoreCase(APPLICATION_XML)) {
  568. if (aAlternate) {
  569. // don't load alternate XSLT
  570. return NS_OK;
  571. }
  572. // LoadXSLStyleSheet needs a mDocShell.
  573. if (!mDocShell)
  574. return NS_OK;
  575. nsCOMPtr<nsIURI> url;
  576. rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
  577. mDocument->GetDocBaseURI());
  578. NS_ENSURE_SUCCESS(rv, rv);
  579. // Do security check
  580. nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
  581. rv = secMan->
  582. CheckLoadURIWithPrincipal(mDocument->NodePrincipal(), url,
  583. nsIScriptSecurityManager::ALLOW_CHROME);
  584. NS_ENSURE_SUCCESS(rv, NS_OK);
  585. // Do content policy check
  586. int16_t decision = nsIContentPolicy::ACCEPT;
  587. rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XSLT,
  588. url,
  589. mDocument->NodePrincipal(),
  590. aElement,
  591. type,
  592. nullptr,
  593. &decision,
  594. nsContentUtils::GetContentPolicy(),
  595. nsContentUtils::GetSecurityManager());
  596. NS_ENSURE_SUCCESS(rv, rv);
  597. if (NS_CP_REJECTED(decision)) {
  598. return NS_OK;
  599. }
  600. return LoadXSLStyleSheet(url);
  601. }
  602. // Let nsContentSink deal with css.
  603. rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
  604. aTitle, aType, aMedia);
  605. // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
  606. // pending sheets.
  607. return rv;
  608. }
  609. NS_IMETHODIMP
  610. nsXMLContentSink::SetDocumentCharset(nsACString& aCharset)
  611. {
  612. if (mDocument) {
  613. mDocument->SetDocumentCharacterSet(aCharset);
  614. }
  615. return NS_OK;
  616. }
  617. nsISupports *
  618. nsXMLContentSink::GetTarget()
  619. {
  620. return mDocument;
  621. }
  622. bool
  623. nsXMLContentSink::IsScriptExecuting()
  624. {
  625. return IsScriptExecutingImpl();
  626. }
  627. nsresult
  628. nsXMLContentSink::FlushText(bool aReleaseTextNode)
  629. {
  630. nsresult rv = NS_OK;
  631. if (mTextLength != 0) {
  632. if (mLastTextNode) {
  633. bool notify = HaveNotifiedForCurrentContent();
  634. // We could probably always increase mInNotification here since
  635. // if AppendText doesn't notify it shouldn't trigger evil code.
  636. // But just in case it does, we don't want to mask any notifications.
  637. if (notify) {
  638. ++mInNotification;
  639. }
  640. rv = mLastTextNode->AppendText(mText, mTextLength, notify);
  641. if (notify) {
  642. --mInNotification;
  643. }
  644. mTextLength = 0;
  645. } else {
  646. RefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager);
  647. mLastTextNode = textContent;
  648. // Set the text in the text node
  649. textContent->SetText(mText, mTextLength, false);
  650. mTextLength = 0;
  651. // Add text to its parent
  652. rv = AddContentAsLeaf(textContent);
  653. }
  654. }
  655. if (aReleaseTextNode) {
  656. mLastTextNode = nullptr;
  657. }
  658. return rv;
  659. }
  660. nsIContent*
  661. nsXMLContentSink::GetCurrentContent()
  662. {
  663. if (mContentStack.Length() == 0) {
  664. return nullptr;
  665. }
  666. return GetCurrentStackNode()->mContent;
  667. }
  668. StackNode*
  669. nsXMLContentSink::GetCurrentStackNode()
  670. {
  671. int32_t count = mContentStack.Length();
  672. return count != 0 ? &mContentStack[count-1] : nullptr;
  673. }
  674. nsresult
  675. nsXMLContentSink::PushContent(nsIContent *aContent)
  676. {
  677. NS_PRECONDITION(aContent, "Null content being pushed!");
  678. StackNode *sn = mContentStack.AppendElement();
  679. NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
  680. nsIContent* contentToPush = aContent;
  681. // When an XML parser would append a node to a template element, it
  682. // must instead append it to the template element's template contents.
  683. if (contentToPush->IsHTMLElement(nsGkAtoms::_template)) {
  684. HTMLTemplateElement* templateElement =
  685. static_cast<HTMLTemplateElement*>(contentToPush);
  686. contentToPush = templateElement->Content();
  687. }
  688. sn->mContent = contentToPush;
  689. sn->mNumFlushed = 0;
  690. return NS_OK;
  691. }
  692. void
  693. nsXMLContentSink::PopContent()
  694. {
  695. int32_t count = mContentStack.Length();
  696. if (count == 0) {
  697. NS_WARNING("Popping empty stack");
  698. return;
  699. }
  700. mContentStack.RemoveElementAt(count - 1);
  701. }
  702. bool
  703. nsXMLContentSink::HaveNotifiedForCurrentContent() const
  704. {
  705. uint32_t stackLength = mContentStack.Length();
  706. if (stackLength) {
  707. const StackNode& stackNode = mContentStack[stackLength - 1];
  708. nsIContent* parent = stackNode.mContent;
  709. return stackNode.mNumFlushed == parent->GetChildCount();
  710. }
  711. return true;
  712. }
  713. void
  714. nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
  715. {
  716. // XXXbz if aIgnorePendingSheets is true, what should we do when
  717. // mXSLTProcessor or CanStillPrettyPrint()?
  718. if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) {
  719. return;
  720. }
  721. StartLayout(aIgnorePendingSheets);
  722. }
  723. ////////////////////////////////////////////////////////////////////////
  724. bool
  725. nsXMLContentSink::SetDocElement(int32_t aNameSpaceID,
  726. nsIAtom* aTagName,
  727. nsIContent *aContent)
  728. {
  729. if (mDocElement)
  730. return false;
  731. mDocElement = aContent;
  732. if (mXSLTProcessor) {
  733. mDocumentChildren.AppendElement(aContent);
  734. return true;
  735. }
  736. if (!mDocumentChildren.IsEmpty()) {
  737. for (nsIContent* child : mDocumentChildren) {
  738. mDocument->AppendChildTo(child, false);
  739. }
  740. mDocumentChildren.Clear();
  741. }
  742. // check for root elements that needs special handling for
  743. // prettyprinting
  744. if ((aNameSpaceID == kNameSpaceID_XBL &&
  745. aTagName == nsGkAtoms::bindings) ||
  746. (aNameSpaceID == kNameSpaceID_XSLT &&
  747. (aTagName == nsGkAtoms::stylesheet ||
  748. aTagName == nsGkAtoms::transform))) {
  749. mPrettyPrintHasSpecialRoot = true;
  750. if (mPrettyPrintXML) {
  751. // In this case, disable script execution, stylesheet
  752. // loading, and auto XLinks since we plan to prettyprint.
  753. mDocument->ScriptLoader()->SetEnabled(false);
  754. if (mCSSLoader) {
  755. mCSSLoader->SetEnabled(false);
  756. }
  757. }
  758. }
  759. nsresult rv = mDocument->AppendChildTo(mDocElement, NotifyForDocElement());
  760. if (NS_FAILED(rv)) {
  761. // If we return false here, the caller will bail out because it won't
  762. // find a parent content node to append to, which is fine.
  763. return false;
  764. }
  765. if (aTagName == nsGkAtoms::html &&
  766. aNameSpaceID == kNameSpaceID_XHTML) {
  767. ProcessOfflineManifest(aContent);
  768. }
  769. return true;
  770. }
  771. NS_IMETHODIMP
  772. nsXMLContentSink::HandleStartElement(const char16_t *aName,
  773. const char16_t **aAtts,
  774. uint32_t aAttsCount,
  775. uint32_t aLineNumber)
  776. {
  777. return HandleStartElement(aName, aAtts, aAttsCount, aLineNumber,
  778. true);
  779. }
  780. nsresult
  781. nsXMLContentSink::HandleStartElement(const char16_t *aName,
  782. const char16_t **aAtts,
  783. uint32_t aAttsCount,
  784. uint32_t aLineNumber,
  785. bool aInterruptable)
  786. {
  787. NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
  788. // Adjust aAttsCount so it's the actual number of attributes
  789. aAttsCount /= 2;
  790. nsresult result = NS_OK;
  791. bool appendContent = true;
  792. nsCOMPtr<nsIContent> content;
  793. // XXX Hopefully the parser will flag this before we get
  794. // here. If we're in the epilog, there should be no
  795. // new elements
  796. MOZ_ASSERT(eXMLContentSinkState_InEpilog != mState);
  797. FlushText();
  798. DidAddContent();
  799. mState = eXMLContentSinkState_InDocumentElement;
  800. int32_t nameSpaceID;
  801. nsCOMPtr<nsIAtom> prefix, localName;
  802. nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
  803. getter_AddRefs(localName), &nameSpaceID);
  804. if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName, aLineNumber)) {
  805. return NS_OK;
  806. }
  807. RefPtr<mozilla::dom::NodeInfo> nodeInfo;
  808. nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
  809. nsIDOMNode::ELEMENT_NODE);
  810. result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
  811. getter_AddRefs(content), &appendContent,
  812. FROM_PARSER_NETWORK);
  813. NS_ENSURE_SUCCESS(result, result);
  814. // Have to do this before we push the new content on the stack... and have to
  815. // do that before we set attributes, call BindToTree, etc. Ideally we'd push
  816. // on the stack inside CreateElement (which is effectively what the HTML sink
  817. // does), but that's hard with all the subclass overrides going on.
  818. nsCOMPtr<nsIContent> parent = GetCurrentContent();
  819. result = PushContent(content);
  820. NS_ENSURE_SUCCESS(result, result);
  821. // Set the attributes on the new content element
  822. result = AddAttributes(aAtts, content);
  823. if (NS_OK == result) {
  824. // Store the element
  825. if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
  826. NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
  827. parent->AppendChildTo(content, false);
  828. }
  829. }
  830. // Some HTML nodes need DoneCreatingElement() called to initialize
  831. // properly (eg form state restoration).
  832. if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML) {
  833. if (nodeInfo->NameAtom() == nsGkAtoms::input ||
  834. nodeInfo->NameAtom() == nsGkAtoms::button ||
  835. nodeInfo->NameAtom() == nsGkAtoms::menuitem ||
  836. nodeInfo->NameAtom() == nsGkAtoms::audio ||
  837. nodeInfo->NameAtom() == nsGkAtoms::video) {
  838. content->DoneCreatingElement();
  839. } else if (nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) {
  840. mCurrentHead = content;
  841. }
  842. }
  843. if (IsMonolithicContainer(nodeInfo)) {
  844. mInMonolithicContainer++;
  845. }
  846. if (!mXSLTProcessor) {
  847. if (content == mDocElement) {
  848. NotifyDocElementCreated(mDocument);
  849. } else if (!mCurrentHead) {
  850. // This isn't the root and we're not inside an XHTML <head>.
  851. // Might need to start layout
  852. MaybeStartLayout(false);
  853. }
  854. }
  855. return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
  856. result;
  857. }
  858. NS_IMETHODIMP
  859. nsXMLContentSink::HandleEndElement(const char16_t *aName)
  860. {
  861. return HandleEndElement(aName, true);
  862. }
  863. nsresult
  864. nsXMLContentSink::HandleEndElement(const char16_t *aName,
  865. bool aInterruptable)
  866. {
  867. nsresult result = NS_OK;
  868. // XXX Hopefully the parser will flag this before we get
  869. // here. If we're in the prolog or epilog, there should be
  870. // no close tags for elements.
  871. MOZ_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
  872. FlushText();
  873. StackNode* sn = GetCurrentStackNode();
  874. if (!sn) {
  875. return NS_ERROR_UNEXPECTED;
  876. }
  877. nsCOMPtr<nsIContent> content;
  878. sn->mContent.swap(content);
  879. uint32_t numFlushed = sn->mNumFlushed;
  880. PopContent();
  881. NS_ASSERTION(content, "failed to pop content");
  882. #ifdef DEBUG
  883. // Check that we're closing the right thing
  884. nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom;
  885. int32_t debugNameSpaceID;
  886. nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
  887. getter_AddRefs(debugTagAtom),
  888. &debugNameSpaceID);
  889. // Check if we are closing a template element because template
  890. // elements do not get pushed on the stack, the template
  891. // element content is pushed instead.
  892. bool isTemplateElement = debugTagAtom == nsGkAtoms::_template &&
  893. debugNameSpaceID == kNameSpaceID_XHTML;
  894. NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID) ||
  895. (debugNameSpaceID == kNameSpaceID_MathML &&
  896. content->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_MathML &&
  897. content->NodeInfo()->Equals(debugTagAtom)) ||
  898. isTemplateElement, "Wrong element being closed");
  899. #endif
  900. result = CloseElement(content);
  901. if (mCurrentHead == content) {
  902. mCurrentHead = nullptr;
  903. }
  904. if (mDocElement == content) {
  905. // XXXbz for roots that don't want to be appended on open, we
  906. // probably need to deal here.... (and stop appending them on open).
  907. mState = eXMLContentSinkState_InEpilog;
  908. // We might have had no occasion to start layout yet. Do so now.
  909. MaybeStartLayout(false);
  910. }
  911. int32_t stackLen = mContentStack.Length();
  912. if (mNotifyLevel >= stackLen) {
  913. if (numFlushed < content->GetChildCount()) {
  914. NotifyAppend(content, numFlushed);
  915. }
  916. mNotifyLevel = stackLen - 1;
  917. }
  918. DidAddContent();
  919. if (content->IsSVGElement(nsGkAtoms::svg)) {
  920. FlushTags();
  921. nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content);
  922. if (NS_FAILED(NS_DispatchToMainThread(event))) {
  923. NS_WARNING("failed to dispatch svg load dispatcher");
  924. }
  925. }
  926. return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
  927. result;
  928. }
  929. NS_IMETHODIMP
  930. nsXMLContentSink::HandleComment(const char16_t *aName)
  931. {
  932. FlushText();
  933. RefPtr<Comment> comment = new Comment(mNodeInfoManager);
  934. comment->SetText(nsDependentString(aName), false);
  935. nsresult rv = AddContentAsLeaf(comment);
  936. DidAddContent();
  937. return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  938. }
  939. NS_IMETHODIMP
  940. nsXMLContentSink::HandleCDataSection(const char16_t *aData,
  941. uint32_t aLength)
  942. {
  943. // XSLT doesn't differentiate between text and cdata and wants adjacent
  944. // textnodes merged, so add as text.
  945. if (mXSLTProcessor) {
  946. return AddText(aData, aLength);
  947. }
  948. FlushText();
  949. RefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager);
  950. cdata->SetText(aData, aLength, false);
  951. nsresult rv = AddContentAsLeaf(cdata);
  952. DidAddContent();
  953. return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  954. }
  955. NS_IMETHODIMP
  956. nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset,
  957. const nsAString & aName,
  958. const nsAString & aSystemId,
  959. const nsAString & aPublicId,
  960. nsISupports* aCatalogData)
  961. {
  962. FlushText();
  963. nsresult rv = NS_OK;
  964. NS_ASSERTION(mDocument, "Shouldn't get here from a document fragment");
  965. nsCOMPtr<nsIAtom> name = NS_Atomize(aName);
  966. NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
  967. // Create a new doctype node
  968. nsCOMPtr<nsIDOMDocumentType> docType;
  969. rv = NS_NewDOMDocumentType(getter_AddRefs(docType), mNodeInfoManager,
  970. name, aPublicId, aSystemId, aSubset);
  971. if (NS_FAILED(rv) || !docType) {
  972. return rv;
  973. }
  974. MOZ_ASSERT(!aCatalogData, "Need to add back support for catalog style "
  975. "sheets");
  976. nsCOMPtr<nsIContent> content = do_QueryInterface(docType);
  977. NS_ASSERTION(content, "doctype isn't content?");
  978. mDocumentChildren.AppendElement(content);
  979. DidAddContent();
  980. return DidProcessATokenImpl();
  981. }
  982. NS_IMETHODIMP
  983. nsXMLContentSink::HandleCharacterData(const char16_t *aData,
  984. uint32_t aLength)
  985. {
  986. return HandleCharacterData(aData, aLength, true);
  987. }
  988. nsresult
  989. nsXMLContentSink::HandleCharacterData(const char16_t *aData, uint32_t aLength,
  990. bool aInterruptable)
  991. {
  992. nsresult rv = NS_OK;
  993. if (aData && mState != eXMLContentSinkState_InProlog &&
  994. mState != eXMLContentSinkState_InEpilog) {
  995. rv = AddText(aData, aLength);
  996. }
  997. return aInterruptable && NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  998. }
  999. NS_IMETHODIMP
  1000. nsXMLContentSink::HandleProcessingInstruction(const char16_t *aTarget,
  1001. const char16_t *aData)
  1002. {
  1003. FlushText();
  1004. const nsDependentString target(aTarget);
  1005. const nsDependentString data(aData);
  1006. nsCOMPtr<nsIContent> node =
  1007. NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data);
  1008. nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node));
  1009. if (ssle) {
  1010. ssle->InitStyleLinkElement(false);
  1011. ssle->SetEnableUpdates(false);
  1012. mPrettyPrintXML = false;
  1013. }
  1014. nsresult rv = AddContentAsLeaf(node);
  1015. NS_ENSURE_SUCCESS(rv, rv);
  1016. DidAddContent();
  1017. if (ssle) {
  1018. // This is an xml-stylesheet processing instruction... but it might not be
  1019. // a CSS one if the type is set to something else.
  1020. ssle->SetEnableUpdates(true);
  1021. bool willNotify;
  1022. bool isAlternate;
  1023. rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
  1024. &willNotify,
  1025. &isAlternate);
  1026. NS_ENSURE_SUCCESS(rv, rv);
  1027. if (willNotify) {
  1028. // Successfully started a stylesheet load
  1029. if (!isAlternate && !mRunsToCompletion) {
  1030. ++mPendingSheetCount;
  1031. mScriptLoader->AddParserBlockingScriptExecutionBlocker();
  1032. }
  1033. return NS_OK;
  1034. }
  1035. }
  1036. // If it's not a CSS stylesheet PI...
  1037. nsAutoString type;
  1038. nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
  1039. if (mState != eXMLContentSinkState_InProlog ||
  1040. !target.EqualsLiteral("xml-stylesheet") ||
  1041. type.IsEmpty() ||
  1042. type.LowerCaseEqualsLiteral("text/css")) {
  1043. return DidProcessATokenImpl();
  1044. }
  1045. nsAutoString href, title, media;
  1046. bool isAlternate = false;
  1047. // If there was no href, we can't do anything with this PI
  1048. if (!ParsePIData(data, href, title, media, isAlternate)) {
  1049. return DidProcessATokenImpl();
  1050. }
  1051. rv = ProcessStyleLink(node, href, isAlternate, title, type, media);
  1052. return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
  1053. }
  1054. /* static */
  1055. bool
  1056. nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref,
  1057. nsString &aTitle, nsString &aMedia,
  1058. bool &aIsAlternate)
  1059. {
  1060. // If there was no href, we can't do anything with this PI
  1061. if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) {
  1062. return false;
  1063. }
  1064. nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle);
  1065. nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia);
  1066. nsAutoString alternate;
  1067. nsContentUtils::GetPseudoAttributeValue(aData,
  1068. nsGkAtoms::alternate,
  1069. alternate);
  1070. aIsAlternate = alternate.EqualsLiteral("yes");
  1071. return true;
  1072. }
  1073. NS_IMETHODIMP
  1074. nsXMLContentSink::HandleXMLDeclaration(const char16_t *aVersion,
  1075. const char16_t *aEncoding,
  1076. int32_t aStandalone)
  1077. {
  1078. mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone);
  1079. return DidProcessATokenImpl();
  1080. }
  1081. NS_IMETHODIMP
  1082. nsXMLContentSink::ReportError(const char16_t* aErrorText,
  1083. const char16_t* aSourceText,
  1084. nsIScriptError *aError,
  1085. bool *_retval)
  1086. {
  1087. NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
  1088. nsresult rv = NS_OK;
  1089. // The expat driver should report the error. We're just cleaning up the mess.
  1090. *_retval = true;
  1091. mPrettyPrintXML = false;
  1092. mState = eXMLContentSinkState_InProlog;
  1093. // XXX need to stop scripts here -- hsivonen
  1094. // stop observing in order to avoid crashing when removing content
  1095. mDocument->RemoveObserver(this);
  1096. mIsDocumentObserver = false;
  1097. // Clear the current content
  1098. mDocumentChildren.Clear();
  1099. nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mDocument));
  1100. if (node) {
  1101. for (;;) {
  1102. nsCOMPtr<nsIDOMNode> child, dummy;
  1103. node->GetLastChild(getter_AddRefs(child));
  1104. if (!child)
  1105. break;
  1106. node->RemoveChild(child, getter_AddRefs(dummy));
  1107. }
  1108. }
  1109. mDocElement = nullptr;
  1110. // Clear any buffered-up text we have. It's enough to set the length to 0.
  1111. // The buffer itself is allocated when we're created and deleted in our
  1112. // destructor, so don't mess with it.
  1113. mTextLength = 0;
  1114. if (mXSLTProcessor) {
  1115. // Get rid of the XSLT processor.
  1116. mXSLTProcessor->CancelLoads();
  1117. mXSLTProcessor = nullptr;
  1118. }
  1119. // release the nodes on stack
  1120. mContentStack.Clear();
  1121. mNotifyLevel = 0;
  1122. // return leaving the document empty if we're asked to not add a <parsererror> root node
  1123. if (mDocument->SuppressParserErrorElement()) {
  1124. return NS_OK;
  1125. }
  1126. // prepare to set <parsererror> as the document root
  1127. rv = HandleProcessingInstruction(u"xml-stylesheet",
  1128. u"href=\"chrome://global/locale/intl.css\" type=\"text/css\"");
  1129. NS_ENSURE_SUCCESS(rv, rv);
  1130. const char16_t* noAtts[] = { 0, 0 };
  1131. NS_NAMED_LITERAL_STRING(errorNs,
  1132. "http://www.mozilla.org/newlayout/xml/parsererror.xml");
  1133. nsAutoString parsererror(errorNs);
  1134. parsererror.Append((char16_t)0xFFFF);
  1135. parsererror.AppendLiteral("parsererror");
  1136. rv = HandleStartElement(parsererror.get(), noAtts, 0, (uint32_t)-1,
  1137. false);
  1138. NS_ENSURE_SUCCESS(rv, rv);
  1139. rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false);
  1140. NS_ENSURE_SUCCESS(rv, rv);
  1141. nsAutoString sourcetext(errorNs);
  1142. sourcetext.Append((char16_t)0xFFFF);
  1143. sourcetext.AppendLiteral("sourcetext");
  1144. rv = HandleStartElement(sourcetext.get(), noAtts, 0, (uint32_t)-1,
  1145. false);
  1146. NS_ENSURE_SUCCESS(rv, rv);
  1147. rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText), false);
  1148. NS_ENSURE_SUCCESS(rv, rv);
  1149. rv = HandleEndElement(sourcetext.get(), false);
  1150. NS_ENSURE_SUCCESS(rv, rv);
  1151. rv = HandleEndElement(parsererror.get(), false);
  1152. NS_ENSURE_SUCCESS(rv, rv);
  1153. FlushTags();
  1154. return NS_OK;
  1155. }
  1156. nsresult
  1157. nsXMLContentSink::AddAttributes(const char16_t** aAtts,
  1158. nsIContent* aContent)
  1159. {
  1160. // Add tag attributes to the content attributes
  1161. nsCOMPtr<nsIAtom> prefix, localName;
  1162. while (*aAtts) {
  1163. int32_t nameSpaceID;
  1164. nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
  1165. getter_AddRefs(localName), &nameSpaceID);
  1166. // Add attribute to content
  1167. aContent->SetAttr(nameSpaceID, localName, prefix,
  1168. nsDependentString(aAtts[1]), false);
  1169. aAtts += 2;
  1170. }
  1171. return NS_OK;
  1172. }
  1173. #define NS_ACCUMULATION_BUFFER_SIZE 4096
  1174. nsresult
  1175. nsXMLContentSink::AddText(const char16_t* aText,
  1176. int32_t aLength)
  1177. {
  1178. // Copy data from string into our buffer; flush buffer when it fills up.
  1179. int32_t offset = 0;
  1180. while (0 != aLength) {
  1181. int32_t amount = NS_ACCUMULATION_BUFFER_SIZE - mTextLength;
  1182. if (0 == amount) {
  1183. nsresult rv = FlushText(false);
  1184. if (NS_WARN_IF(NS_FAILED(rv))) {
  1185. return rv;
  1186. }
  1187. MOZ_ASSERT(mTextLength == 0);
  1188. amount = NS_ACCUMULATION_BUFFER_SIZE;
  1189. }
  1190. if (amount > aLength) {
  1191. amount = aLength;
  1192. }
  1193. memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount);
  1194. mTextLength += amount;
  1195. offset += amount;
  1196. aLength -= amount;
  1197. }
  1198. return NS_OK;
  1199. }
  1200. void
  1201. nsXMLContentSink::FlushPendingNotifications(mozFlushType aType)
  1202. {
  1203. // Only flush tags if we're not doing the notification ourselves
  1204. // (since we aren't reentrant)
  1205. if (!mInNotification) {
  1206. if (mIsDocumentObserver) {
  1207. // Only flush if we're still a document observer (so that our child
  1208. // counts should be correct).
  1209. if (aType >= Flush_ContentAndNotify) {
  1210. FlushTags();
  1211. }
  1212. else {
  1213. FlushText(false);
  1214. }
  1215. }
  1216. if (aType >= Flush_InterruptibleLayout) {
  1217. // Make sure that layout has started so that the reflow flush
  1218. // will actually happen.
  1219. MaybeStartLayout(true);
  1220. }
  1221. }
  1222. }
  1223. /**
  1224. * NOTE!! Forked from SinkContext. Please keep in sync.
  1225. *
  1226. * Flush all elements that have been seen so far such that
  1227. * they are visible in the tree. Specifically, make sure
  1228. * that they are all added to their respective parents.
  1229. * Also, do notification at the top for all content that
  1230. * has been newly added so that the frame tree is complete.
  1231. */
  1232. nsresult
  1233. nsXMLContentSink::FlushTags()
  1234. {
  1235. mDeferredFlushTags = false;
  1236. bool oldBeganUpdate = mBeganUpdate;
  1237. uint32_t oldUpdates = mUpdatesInNotification;
  1238. mUpdatesInNotification = 0;
  1239. ++mInNotification;
  1240. {
  1241. // Scope so we call EndUpdate before we decrease mInNotification
  1242. mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, true);
  1243. mBeganUpdate = true;
  1244. // Don't release last text node in case we need to add to it again
  1245. FlushText(false);
  1246. // Start from the base of the stack (growing downward) and do
  1247. // a notification from the node that is closest to the root of
  1248. // tree for any content that has been added.
  1249. int32_t stackPos;
  1250. int32_t stackLen = mContentStack.Length();
  1251. bool flushed = false;
  1252. uint32_t childCount;
  1253. nsIContent* content;
  1254. for (stackPos = 0; stackPos < stackLen; ++stackPos) {
  1255. content = mContentStack[stackPos].mContent;
  1256. childCount = content->GetChildCount();
  1257. if (!flushed && (mContentStack[stackPos].mNumFlushed < childCount)) {
  1258. NotifyAppend(content, mContentStack[stackPos].mNumFlushed);
  1259. flushed = true;
  1260. }
  1261. mContentStack[stackPos].mNumFlushed = childCount;
  1262. }
  1263. mNotifyLevel = stackLen - 1;
  1264. }
  1265. --mInNotification;
  1266. if (mUpdatesInNotification > 1) {
  1267. UpdateChildCounts();
  1268. }
  1269. mUpdatesInNotification = oldUpdates;
  1270. mBeganUpdate = oldBeganUpdate;
  1271. return NS_OK;
  1272. }
  1273. /**
  1274. * NOTE!! Forked from SinkContext. Please keep in sync.
  1275. */
  1276. void
  1277. nsXMLContentSink::UpdateChildCounts()
  1278. {
  1279. // Start from the top of the stack (growing upwards) and see if any
  1280. // new content has been appended. If so, we recognize that reflows
  1281. // have been generated for it and we should make sure that no
  1282. // further reflows occur. Note that we have to include stackPos == 0
  1283. // to properly notify on kids of <html>.
  1284. int32_t stackLen = mContentStack.Length();
  1285. int32_t stackPos = stackLen - 1;
  1286. while (stackPos >= 0) {
  1287. StackNode & node = mContentStack[stackPos];
  1288. node.mNumFlushed = node.mContent->GetChildCount();
  1289. stackPos--;
  1290. }
  1291. mNotifyLevel = stackLen - 1;
  1292. }
  1293. bool
  1294. nsXMLContentSink::IsMonolithicContainer(mozilla::dom::NodeInfo* aNodeInfo)
  1295. {
  1296. return ((aNodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
  1297. (aNodeInfo->NameAtom() == nsGkAtoms::tr ||
  1298. aNodeInfo->NameAtom() == nsGkAtoms::select ||
  1299. aNodeInfo->NameAtom() == nsGkAtoms::object ||
  1300. aNodeInfo->NameAtom() == nsGkAtoms::applet)) ||
  1301. (aNodeInfo->NamespaceID() == kNameSpaceID_MathML &&
  1302. (aNodeInfo->NameAtom() == nsGkAtoms::math))
  1303. );
  1304. }
  1305. void
  1306. nsXMLContentSink::ContinueInterruptedParsingIfEnabled()
  1307. {
  1308. if (mParser && mParser->IsParserEnabled()) {
  1309. GetParser()->ContinueInterruptedParsing();
  1310. }
  1311. }
  1312. void
  1313. nsXMLContentSink::ContinueInterruptedParsingAsync()
  1314. {
  1315. nsCOMPtr<nsIRunnable> ev = NewRunnableMethod(this,
  1316. &nsXMLContentSink::ContinueInterruptedParsingIfEnabled);
  1317. NS_DispatchToCurrentThread(ev);
  1318. }
  1319. nsIParser*
  1320. nsXMLContentSink::GetParser()
  1321. {
  1322. return static_cast<nsIParser*>(mParser.get());
  1323. }