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