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