Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / content / xml / document / src / nsXMLContentSink.cpp
blobd2508a075dfc6134b6e928c0950d880d351089b8
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
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/
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.
16 * The Original Code is Mozilla Communicator client code.
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.
23 * Contributor(s):
24 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Henri Sivonen <hsivonen@iki.fi>
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.
39 * ***** END LICENSE BLOCK ***** */
40 #include "nsCOMPtr.h"
41 #include "nsXMLContentSink.h"
42 #include "nsIParser.h"
43 #include "nsIUnicharInputStream.h"
44 #include "nsIDocument.h"
45 #include "nsIDOMDocument.h"
46 #include "nsIDOMDocumentType.h"
47 #include "nsIDOMDOMImplementation.h"
48 #include "nsIDOMNSDocument.h"
49 #include "nsIContent.h"
50 #include "nsIURI.h"
51 #include "nsNetUtil.h"
52 #include "nsIDocShell.h"
53 #include "nsIDocShellTreeItem.h"
54 #include "nsIStyleSheetLinkingElement.h"
55 #include "nsPresContext.h"
56 #include "nsIPresShell.h"
57 #include "nsIDOMComment.h"
58 #include "nsIDOMCDATASection.h"
59 #include "nsDOMDocumentType.h"
60 #include "nsHTMLParts.h"
61 #include "nsVoidArray.h"
62 #include "nsCRT.h"
63 #include "nsICSSLoader.h"
64 #include "nsICSSStyleSheet.h"
65 #include "nsGkAtoms.h"
66 #include "nsContentUtils.h"
67 #include "nsIScriptContext.h"
68 #include "nsINameSpaceManager.h"
69 #include "nsIServiceManager.h"
70 #include "nsIScriptSecurityManager.h"
71 #include "nsIContentViewer.h"
72 #include "prtime.h"
73 #include "prlog.h"
74 #include "prmem.h"
75 #include "nsParserUtils.h"
76 #include "nsRect.h"
77 #include "nsGenericElement.h"
78 #include "nsIWebNavigation.h"
79 #include "nsIScriptElement.h"
80 #include "nsScriptLoader.h"
81 #include "nsStyleLinkElement.h"
82 #include "nsIImageLoadingContent.h"
83 #include "nsReadableUtils.h"
84 #include "nsUnicharUtils.h"
85 #include "nsICookieService.h"
86 #include "nsIPrompt.h"
87 #include "nsIDOMWindowInternal.h"
88 #include "nsIChannel.h"
89 #include "nsIPrincipal.h"
90 #include "nsXMLPrettyPrinter.h"
91 #include "nsNodeInfoManager.h"
92 #include "nsContentCreatorFunctions.h"
93 #include "nsIContentPolicy.h"
94 #include "nsContentPolicyUtils.h"
95 #include "nsContentErrors.h"
96 #include "nsIDOMProcessingInstruction.h"
97 #include "nsNodeUtils.h"
98 #include "nsIScriptGlobalObject.h"
99 #include "nsEventDispatcher.h"
100 #include "mozAutoDocUpdate.h"
102 #ifdef MOZ_SVG
103 #include "nsGUIEvent.h"
104 #endif
106 #define kXSLType "text/xsl"
108 // XXX Open Issues:
109 // 1) what's not allowed - We need to figure out which HTML tags
110 // (prefixed with a HTML namespace qualifier) are explicitly not
111 // allowed (if any).
112 // 2) factoring code with nsHTMLContentSink - There's some amount of
113 // common code between this and the HTML content sink. This will
114 // increase as we support more and more HTML elements. How can code
115 // from the code be factored?
117 nsresult
118 NS_NewXMLContentSink(nsIXMLContentSink** aResult,
119 nsIDocument* aDoc,
120 nsIURI* aURI,
121 nsISupports* aContainer,
122 nsIChannel* aChannel)
124 NS_PRECONDITION(nsnull != aResult, "null ptr");
125 if (nsnull == aResult) {
126 return NS_ERROR_NULL_POINTER;
128 nsXMLContentSink* it;
129 NS_NEWXPCOM(it, nsXMLContentSink);
130 if (nsnull == it) {
131 return NS_ERROR_OUT_OF_MEMORY;
134 nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
135 nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
136 NS_ENSURE_SUCCESS(rv, rv);
138 return CallQueryInterface(it, aResult);
141 nsXMLContentSink::nsXMLContentSink()
142 : mConstrainSize(PR_TRUE),
143 mPrettyPrintXML(PR_TRUE),
144 mAllowAutoXLinks(PR_TRUE)
148 nsXMLContentSink::~nsXMLContentSink()
150 NS_IF_RELEASE(mDocElement);
151 if (mText) {
152 PR_Free(mText); // Doesn't null out, unlike PR_FREEIF
156 nsresult
157 nsXMLContentSink::Init(nsIDocument* aDoc,
158 nsIURI* aURI,
159 nsISupports* aContainer,
160 nsIChannel* aChannel)
162 MOZ_TIMER_DEBUGLOG(("Reset and start: nsXMLContentSink::Init(), this=%p\n",
163 this));
164 MOZ_TIMER_RESET(mWatch);
165 MOZ_TIMER_START(mWatch);
167 nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
168 NS_ENSURE_SUCCESS(rv, rv);
170 aDoc->AddObserver(this);
172 if (!mDocShell) {
173 mPrettyPrintXML = PR_FALSE;
176 mState = eXMLContentSinkState_InProlog;
177 mDocElement = nsnull;
179 MOZ_TIMER_DEBUGLOG(("Stop: nsXMLContentSink::Init()\n"));
180 MOZ_TIMER_STOP(mWatch);
181 return NS_OK;
184 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink)
185 NS_INTERFACE_MAP_ENTRY(nsIContentSink)
186 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
187 NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
188 NS_INTERFACE_MAP_ENTRY(nsITransformObserver)
189 NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
191 NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink)
192 NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink)
194 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink)
196 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink,
197 nsContentSink)
198 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCurrentHead)
199 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDocElement)
200 for (PRUint32 i = 0, count = tmp->mContentStack.Length(); i < count; i++) {
201 const StackNode& node = tmp->mContentStack.ElementAt(i);
202 cb.NoteXPCOMChild(node.mContent);
204 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
206 // nsIContentSink
207 NS_IMETHODIMP
208 nsXMLContentSink::WillParse(void)
210 return WillParseImpl();
213 NS_IMETHODIMP
214 nsXMLContentSink::WillBuildModel(void)
216 WillBuildModelImpl();
218 // Notify document that the load is beginning
219 mDocument->BeginLoad();
221 // Check for correct load-command for maybe prettyprinting
222 if (mPrettyPrintXML) {
223 nsCAutoString command;
224 mParser->GetCommand(command);
225 if (!command.EqualsLiteral("view")) {
226 mPrettyPrintXML = PR_FALSE;
230 return NS_OK;
233 PRBool
234 nsXMLContentSink::CanStillPrettyPrint()
236 return mPrettyPrintXML &&
237 (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot);
240 nsresult
241 nsXMLContentSink::MaybePrettyPrint()
243 if (!CanStillPrettyPrint()) {
244 mPrettyPrintXML = PR_FALSE;
246 return NS_OK;
249 // stop observing in order to avoid crashing when replacing content
250 mDocument->RemoveObserver(this);
252 // Reenable the CSSLoader so that the prettyprinting stylesheets can load
253 if (mCSSLoader) {
254 mCSSLoader->SetEnabled(PR_TRUE);
257 nsCOMPtr<nsXMLPrettyPrinter> printer;
258 nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer));
259 NS_ENSURE_SUCCESS(rv, rv);
261 PRBool isPrettyPrinting;
262 rv = printer->PrettyPrint(mDocument, &isPrettyPrinting);
263 NS_ENSURE_SUCCESS(rv, rv);
265 mPrettyPrinting = isPrettyPrinting;
266 return NS_OK;
269 static void
270 CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
271 nsIDocumentTransformer* aProcessor,
272 nsIDocument* aDocument)
274 nsAutoString target, data;
275 aPi->GetTarget(target);
277 // Check for namespace declarations
278 if (target.EqualsLiteral("xslt-param-namespace")) {
279 aPi->GetData(data);
280 nsAutoString prefix, namespaceAttr;
281 nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::prefix,
282 prefix);
283 if (!prefix.IsEmpty() &&
284 nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::_namespace,
285 namespaceAttr)) {
286 aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
290 // Check for actual parameters
291 else if (target.EqualsLiteral("xslt-param")) {
292 aPi->GetData(data);
293 nsAutoString name, namespaceAttr, select, value;
294 nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::name,
295 name);
296 nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::_namespace,
297 namespaceAttr);
298 if (!nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::select, select)) {
299 select.SetIsVoid(PR_TRUE);
301 if (!nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::value, value)) {
302 value.SetIsVoid(PR_TRUE);
304 if (!name.IsEmpty()) {
305 nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
306 aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc);
311 NS_IMETHODIMP
312 nsXMLContentSink::DidBuildModel()
314 DidBuildModelImpl();
316 if (mXSLTProcessor) {
317 // stop observing in order to avoid crashing when replacing content
318 mDocument->RemoveObserver(this);
320 // Check for xslt-param and xslt-param-namespace PIs
321 PRUint32 i;
322 nsIContent* child;
323 for (i = 0; (child = mDocument->GetChildAt(i)); ++i) {
324 if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
325 nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
326 CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
328 else if (child->IsNodeOfType(nsINode::eELEMENT)) {
329 // Only honor PIs in the prolog
330 break;
334 nsCOMPtr<nsIDOMDocument> currentDOMDoc(do_QueryInterface(mDocument));
335 mXSLTProcessor->SetSourceContentModel(currentDOMDoc);
336 // Since the processor now holds a reference to us we drop our reference
337 // to it to avoid owning cycles
338 mXSLTProcessor = nsnull;
340 else {
341 // Kick off layout for non-XSLT transformed documents.
342 mDocument->ScriptLoader()->RemoveObserver(this);
344 if (mDocElement) {
345 // Notify document observers that all the content has been stuck
346 // into the document.
347 // XXX do we need to notify for things like PIs? Or just the
348 // documentElement?
349 NS_ASSERTION(mDocument->IndexOf(mDocElement) != -1,
350 "mDocElement not in doc?");
353 // Check if we want to prettyprint
354 MaybePrettyPrint();
356 PRBool startLayout = PR_TRUE;
358 if (mPrettyPrinting) {
359 NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
361 // We're pretty-printing now. See whether we should wait up on
362 // stylesheet loads
363 if (mDocument->CSSLoader()->HasPendingLoads() &&
364 NS_SUCCEEDED(mDocument->CSSLoader()->AddObserver(this))) {
365 // wait for those sheets to load
366 startLayout = PR_FALSE;
370 if (startLayout) {
371 StartLayout(PR_FALSE);
373 ScrollToRef();
376 mDocument->RemoveObserver(this);
378 mDocument->EndLoad();
381 DropParserAndPerfHint();
383 return NS_OK;
386 NS_IMETHODIMP
387 nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument)
389 NS_ENSURE_ARG(aResultDocument);
391 nsCOMPtr<nsIContentViewer> contentViewer;
392 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
393 if (contentViewer) {
394 nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aResultDocument);
395 return contentViewer->SetDOMDocument(doc);
397 return NS_OK;
400 NS_IMETHODIMP
401 nsXMLContentSink::OnTransformDone(nsresult aResult,
402 nsIDocument* aResultDocument)
404 NS_ASSERTION(NS_FAILED(aResult) || aResultDocument,
405 "Don't notify about transform success without a document.");
407 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aResultDocument);
409 nsCOMPtr<nsIContentViewer> contentViewer;
410 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
412 if (NS_FAILED(aResult) && contentViewer) {
413 // Transform failed.
414 if (domDoc) {
415 aResultDocument->SetMayStartLayout(PR_FALSE);
416 // We have an error document.
417 contentViewer->SetDOMDocument(domDoc);
419 else {
420 // We don't have an error document, display the
421 // untransformed source document.
422 nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument);
423 contentViewer->SetDOMDocument(document);
427 nsCOMPtr<nsIDocument> originalDocument = mDocument;
428 if (NS_SUCCEEDED(aResult) || aResultDocument) {
429 // Transform succeeded or it failed and we have an error
430 // document to display.
431 mDocument = aResultDocument;
434 originalDocument->ScriptLoader()->RemoveObserver(this);
436 // Notify document observers that all the content has been stuck
437 // into the document.
438 // XXX do we need to notify for things like PIs? Or just the
439 // documentElement?
440 nsIContent *rootContent = mDocument->GetRootContent();
441 if (rootContent) {
442 NS_ASSERTION(mDocument->IndexOf(rootContent) != -1,
443 "rootContent not in doc?");
444 mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
445 nsNodeUtils::ContentInserted(mDocument, rootContent,
446 mDocument->IndexOf(rootContent));
447 mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
450 // Start the layout process
451 StartLayout(PR_FALSE);
453 ScrollToRef();
455 originalDocument->EndLoad();
457 return NS_OK;
460 NS_IMETHODIMP
461 nsXMLContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet,
462 PRBool aWasAlternate,
463 nsresult aStatus)
465 if (!mPrettyPrinting) {
466 return nsContentSink::StyleSheetLoaded(aSheet, aWasAlternate, aStatus);
469 if (!mDocument->CSSLoader()->HasPendingLoads()) {
470 mDocument->CSSLoader()->RemoveObserver(this);
471 StartLayout(PR_FALSE);
472 ScrollToRef();
475 return NS_OK;
478 NS_IMETHODIMP
479 nsXMLContentSink::WillInterrupt(void)
481 return WillInterruptImpl();
484 NS_IMETHODIMP
485 nsXMLContentSink::WillResume(void)
487 return WillResumeImpl();
490 NS_IMETHODIMP
491 nsXMLContentSink::SetParser(nsIParser* aParser)
493 NS_PRECONDITION(aParser, "Should have a parser here!");
494 mParser = aParser;
495 return NS_OK;
498 nsresult
499 nsXMLContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
500 nsINodeInfo* aNodeInfo, PRUint32 aLineNumber,
501 nsIContent** aResult, PRBool* aAppendContent,
502 PRBool aFromParser)
504 NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
506 *aResult = nsnull;
507 *aAppendContent = PR_TRUE;
508 nsresult rv = NS_OK;
510 nsCOMPtr<nsIContent> content;
511 rv = NS_NewElement(getter_AddRefs(content), aNodeInfo->NamespaceID(),
512 aNodeInfo, aFromParser);
513 NS_ENSURE_SUCCESS(rv, rv);
515 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
516 #ifdef MOZ_SVG
517 || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
518 #endif
520 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
521 sele->SetScriptLineNumber(aLineNumber);
522 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)) {
523 sele->WillCallDoneAddingChildren();
525 mConstrainSize = PR_FALSE;
528 // XHTML needs some special attention
529 if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
530 mPrettyPrintHasFactoredElements = PR_TRUE;
532 else {
533 // If we care, find out if we just used a special factory.
534 if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
535 mPrettyPrintXML) {
536 mPrettyPrintHasFactoredElements =
537 nsContentUtils::NameSpaceManager()->
538 HasElementCreator(aNodeInfo->NamespaceID());
541 if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
542 content.swap(*aResult);
544 return NS_OK;
548 if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
549 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
550 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
551 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
552 if (ssle) {
553 ssle->InitStyleLinkElement(PR_FALSE);
554 ssle->SetEnableUpdates(PR_FALSE);
555 if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
556 ssle->SetLineNumber(aLineNumber);
561 content.swap(*aResult);
563 return NS_OK;
567 nsresult
568 nsXMLContentSink::CloseElement(nsIContent* aContent)
570 NS_ASSERTION(aContent, "missing element to close");
572 nsINodeInfo *nodeInfo = aContent->NodeInfo();
574 // Some HTML nodes need DoneAddingChildren() called to initialize
575 // properly (eg form state restoration).
576 if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
577 (nodeInfo->NameAtom() == nsGkAtoms::select ||
578 nodeInfo->NameAtom() == nsGkAtoms::textarea ||
579 #ifdef MOZ_MEDIA
580 nodeInfo->NameAtom() == nsGkAtoms::video ||
581 nodeInfo->NameAtom() == nsGkAtoms::audio ||
582 #endif
583 nodeInfo->NameAtom() == nsGkAtoms::object ||
584 nodeInfo->NameAtom() == nsGkAtoms::applet))
585 #ifdef MOZ_XTF
586 || nodeInfo->NamespaceID() > kNameSpaceID_LastBuiltin
587 #endif
588 || nodeInfo->NameAtom() == nsGkAtoms::title
590 aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
593 if (IsMonolithicContainer(nodeInfo)) {
594 mInMonolithicContainer--;
597 if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
598 !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
599 return NS_OK;
602 nsresult rv = NS_OK;
604 if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
605 #ifdef MOZ_SVG
606 || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
607 #endif
609 mConstrainSize = PR_TRUE;
611 // Now tell the script that it's ready to go. This may execute the script
612 // or return NS_ERROR_HTMLPARSER_BLOCK. Or neither if the script doesn't
613 // need executing.
614 rv = aContent->DoneAddingChildren(PR_TRUE);
616 // If the act of insertion evaluated the script, we're fine.
617 // Else, block the parser till the script has loaded.
618 if (rv == NS_ERROR_HTMLPARSER_BLOCK) {
619 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
620 mScriptElements.AppendObject(sele);
623 // If the parser got blocked, make sure to return the appropriate rv.
624 // I'm not sure if this is actually needed or not.
625 if (mParser && !mParser->IsParserEnabled()) {
626 // XXX The HTML sink doesn't call BlockParser here, why do we?
627 mParser->BlockParser();
628 rv = NS_ERROR_HTMLPARSER_BLOCK;
631 return rv;
634 if (nodeInfo->Equals(nsGkAtoms::base, kNameSpaceID_XHTML) &&
635 !mHasProcessedBase) {
636 // The first base wins
637 ProcessBASETag(aContent);
638 mHasProcessedBase = PR_TRUE;
640 else if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
641 // Need to check here to make sure this meta tag does not set
642 // mPrettyPrintXML to false when we have a special root!
643 (!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
644 rv = ProcessMETATag(aContent);
646 else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
647 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
648 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
649 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
650 if (ssle) {
651 ssle->SetEnableUpdates(PR_TRUE);
652 PRBool willNotify;
653 PRBool isAlternate;
654 rv = ssle->UpdateStyleSheet(this, &willNotify, &isAlternate);
655 if (NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
656 ++mPendingSheetCount;
657 mScriptLoader->AddExecuteBlocker();
660 // Look for <link rel="dns-prefetch" href="hostname">
661 if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
662 nsAutoString relVal;
663 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
664 if (relVal.EqualsLiteral("dns-prefetch")) {
665 nsAutoString hrefVal;
666 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
667 if (!hrefVal.IsEmpty()) {
668 PrefetchDNS(hrefVal);
674 return rv;
677 nsresult
678 nsXMLContentSink::AddContentAsLeaf(nsIContent *aContent)
680 nsresult result = NS_OK;
682 if ((eXMLContentSinkState_InProlog == mState) ||
683 (eXMLContentSinkState_InEpilog == mState)) {
684 NS_ASSERTION(mDocument, "Fragments have no prolog or epilog");
685 mDocument->AppendChildTo(aContent, PR_FALSE);
687 else {
688 nsCOMPtr<nsIContent> parent = GetCurrentContent();
690 if (parent) {
691 result = parent->AppendChildTo(aContent, PR_FALSE);
694 return result;
697 // Create an XML parser and an XSL content sink and start parsing
698 // the XSL stylesheet located at the given URI.
699 nsresult
700 nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
702 nsCOMPtr<nsIDocumentTransformer> processor =
703 do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt");
704 if (!processor) {
705 // No XSLT processor available, continue normal document loading
706 return NS_OK;
709 processor->Init(mDocument->NodePrincipal());
710 processor->SetTransformObserver(this);
712 nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
713 if (!loadGroup) {
714 return NS_ERROR_FAILURE;
717 if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, loadGroup))) {
718 mXSLTProcessor.swap(processor);
721 // Intentionally ignore errors here, we should continue loading the
722 // XML document whether we're able to load the XSLT stylesheet or
723 // not.
725 return NS_OK;
728 nsresult
729 nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
730 const nsSubstring& aHref,
731 PRBool aAlternate,
732 const nsSubstring& aTitle,
733 const nsSubstring& aType,
734 const nsSubstring& aMedia)
736 nsresult rv = NS_OK;
737 mPrettyPrintXML = PR_FALSE;
739 nsCAutoString cmd;
740 if (mParser)
741 mParser->GetCommand(cmd);
742 if (cmd.EqualsASCII(kLoadAsData))
743 return NS_OK; // Do not load stylesheets when loading as data
745 NS_ConvertUTF16toUTF8 type(aType);
746 if (type.EqualsIgnoreCase(kXSLType) ||
747 type.EqualsIgnoreCase(kXMLTextContentType) ||
748 type.EqualsIgnoreCase(kXMLApplicationContentType)) {
749 if (aAlternate) {
750 // don't load alternate XSLT
751 return NS_OK;
753 // LoadXSLStyleSheet needs a mDocShell.
754 if (!mDocShell)
755 return NS_OK;
757 nsCOMPtr<nsIURI> url;
758 rv = NS_NewURI(getter_AddRefs(url), aHref, nsnull, mDocumentBaseURI);
759 NS_ENSURE_SUCCESS(rv, rv);
761 // Do security check
762 nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
763 rv = secMan->
764 CheckLoadURIWithPrincipal(mDocument->NodePrincipal(), url,
765 nsIScriptSecurityManager::ALLOW_CHROME);
766 NS_ENSURE_SUCCESS(rv, NS_OK);
768 // Do content policy check
769 PRInt16 decision = nsIContentPolicy::ACCEPT;
770 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET,
771 url,
772 mDocument->NodePrincipal(),
773 aElement,
774 type,
775 nsnull,
776 &decision,
777 nsContentUtils::GetContentPolicy(),
778 nsContentUtils::GetSecurityManager());
780 NS_ENSURE_SUCCESS(rv, rv);
782 if (NS_CP_REJECTED(decision)) {
783 return NS_OK;
786 return LoadXSLStyleSheet(url);
789 // Let nsContentSink deal with css.
790 rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
791 aTitle, aType, aMedia);
793 // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
794 // pending sheets.
796 return rv;
799 void
800 nsXMLContentSink::ProcessBASETag(nsIContent* aContent)
802 NS_ASSERTION(aContent, "missing base-element");
804 if (mDocument) {
805 nsAutoString value;
807 if (aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::target, value)) {
808 mDocument->SetBaseTarget(value);
811 if (aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, value)) {
812 nsCOMPtr<nsIURI> baseURI;
813 nsresult rv = NS_NewURI(getter_AddRefs(baseURI), value);
814 if (NS_SUCCEEDED(rv)) {
815 rv = mDocument->SetBaseURI(baseURI); // The document checks if it is legal to set this base
816 if (NS_SUCCEEDED(rv)) {
817 mDocumentBaseURI = mDocument->GetBaseURI();
825 NS_IMETHODIMP
826 nsXMLContentSink::SetDocumentCharset(nsACString& aCharset)
828 if (mDocument) {
829 mDocument->SetDocumentCharacterSet(aCharset);
832 return NS_OK;
835 nsISupports *
836 nsXMLContentSink::GetTarget()
838 return mDocument;
841 nsresult
842 nsXMLContentSink::FlushText(PRBool aReleaseTextNode)
844 nsresult rv = NS_OK;
846 if (mTextLength != 0) {
847 if (mLastTextNode) {
848 if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) {
849 mLastTextNodeSize = 0;
850 mLastTextNode = nsnull;
851 FlushText(aReleaseTextNode);
852 } else {
853 PRBool notify = HaveNotifiedForCurrentContent();
854 // We could probably always increase mInNotification here since
855 // if AppendText doesn't notify it shouldn't trigger evil code.
856 // But just in case it does, we don't want to mask any notifications.
857 if (notify) {
858 ++mInNotification;
860 rv = mLastTextNode->AppendText(mText, mTextLength, notify);
861 if (notify) {
862 --mInNotification;
865 mLastTextNodeSize += mTextLength;
866 mTextLength = 0;
868 } else {
869 nsCOMPtr<nsIContent> textContent;
870 rv = NS_NewTextNode(getter_AddRefs(textContent),
871 mNodeInfoManager);
872 NS_ENSURE_SUCCESS(rv, rv);
874 mLastTextNode = textContent;
876 // Set the text in the text node
877 textContent->SetText(mText, mTextLength, PR_FALSE);
878 mLastTextNodeSize += mTextLength;
879 mTextLength = 0;
881 // Add text to its parent
882 rv = AddContentAsLeaf(textContent);
886 if (aReleaseTextNode) {
887 mLastTextNodeSize = 0;
888 mLastTextNode = nsnull;
891 return rv;
894 nsIContent*
895 nsXMLContentSink::GetCurrentContent()
897 if (mContentStack.Length() == 0) {
898 return nsnull;
900 return GetCurrentStackNode().mContent;
903 StackNode &
904 nsXMLContentSink::GetCurrentStackNode()
906 PRInt32 count = mContentStack.Length();
907 NS_ASSERTION(count > 0, "Bogus Length()");
908 return mContentStack[count-1];
912 nsresult
913 nsXMLContentSink::PushContent(nsIContent *aContent)
915 NS_PRECONDITION(aContent, "Null content being pushed!");
916 StackNode *sn = mContentStack.AppendElement();
917 NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
919 sn->mContent = aContent;
920 sn->mNumFlushed = 0;
921 return NS_OK;
924 void
925 nsXMLContentSink::PopContent()
927 PRInt32 count = mContentStack.Length();
929 if (count == 0) {
930 NS_WARNING("Popping empty stack");
931 return;
934 mContentStack.RemoveElementAt(count - 1);
937 PRBool
938 nsXMLContentSink::HaveNotifiedForCurrentContent() const
940 PRUint32 stackLength = mContentStack.Length();
941 if (stackLength) {
942 const StackNode& stackNode = mContentStack[stackLength - 1];
943 nsIContent* parent = stackNode.mContent;
944 return stackNode.mNumFlushed == parent->GetChildCount();
946 return PR_TRUE;
949 void
950 nsXMLContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets)
952 // XXXbz if aIgnorePendingSheets is true, what should we do when
953 // mXSLTProcessor or CanStillPrettyPrint()?
954 if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) {
955 return;
957 StartLayout(aIgnorePendingSheets);
960 ////////////////////////////////////////////////////////////////////////
962 PRBool
963 nsXMLContentSink::SetDocElement(PRInt32 aNameSpaceID,
964 nsIAtom* aTagName,
965 nsIContent *aContent)
967 if (mDocElement)
968 return PR_FALSE;
970 // check for root elements that needs special handling for
971 // prettyprinting
972 if ((aNameSpaceID == kNameSpaceID_XBL &&
973 aTagName == nsGkAtoms::bindings) ||
974 (aNameSpaceID == kNameSpaceID_XSLT &&
975 (aTagName == nsGkAtoms::stylesheet ||
976 aTagName == nsGkAtoms::transform))) {
977 mPrettyPrintHasSpecialRoot = PR_TRUE;
978 if (mPrettyPrintXML) {
979 // In this case, disable script execution, stylesheet
980 // loading, and auto XLinks since we plan to prettyprint.
981 mAllowAutoXLinks = PR_FALSE;
982 mDocument->ScriptLoader()->SetEnabled(PR_FALSE);
983 if (mCSSLoader) {
984 mCSSLoader->SetEnabled(PR_FALSE);
989 mDocElement = aContent;
990 NS_ADDREF(mDocElement);
991 nsresult rv = mDocument->AppendChildTo(mDocElement, PR_TRUE);
992 if (NS_FAILED(rv)) {
993 // If we return PR_FALSE here, the caller will bail out because it won't
994 // find a parent content node to append to, which is fine.
995 return PR_FALSE;
997 return PR_TRUE;
1000 NS_IMETHODIMP
1001 nsXMLContentSink::HandleStartElement(const PRUnichar *aName,
1002 const PRUnichar **aAtts,
1003 PRUint32 aAttsCount,
1004 PRInt32 aIndex,
1005 PRUint32 aLineNumber)
1007 return HandleStartElement(aName, aAtts, aAttsCount, aIndex, aLineNumber,
1008 PR_TRUE);
1011 nsresult
1012 nsXMLContentSink::HandleStartElement(const PRUnichar *aName,
1013 const PRUnichar **aAtts,
1014 PRUint32 aAttsCount,
1015 PRInt32 aIndex,
1016 PRUint32 aLineNumber,
1017 PRBool aInterruptable)
1019 NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
1020 NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
1021 // Adjust aAttsCount so it's the actual number of attributes
1022 aAttsCount /= 2;
1024 nsresult result = NS_OK;
1025 PRBool appendContent = PR_TRUE;
1026 nsCOMPtr<nsIContent> content;
1028 // XXX Hopefully the parser will flag this before we get
1029 // here. If we're in the epilog, there should be no
1030 // new elements
1031 PR_ASSERT(eXMLContentSinkState_InEpilog != mState);
1033 FlushText();
1034 DidAddContent();
1036 mState = eXMLContentSinkState_InDocumentElement;
1038 PRInt32 nameSpaceID;
1039 nsCOMPtr<nsIAtom> prefix, localName;
1040 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
1041 getter_AddRefs(localName), &nameSpaceID);
1043 if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName, aLineNumber)) {
1044 return NS_OK;
1047 nsCOMPtr<nsINodeInfo> nodeInfo;
1048 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID);
1049 NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
1051 result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
1052 getter_AddRefs(content), &appendContent, PR_TRUE);
1053 NS_ENSURE_SUCCESS(result, result);
1055 // Have to do this before we push the new content on the stack... and have to
1056 // do that before we set attributes, call BindToTree, etc. Ideally we'd push
1057 // on the stack inside CreateElement (which is effectively what the HTML sink
1058 // does), but that's hard with all the subclass overrides going on.
1059 nsCOMPtr<nsIContent> parent = GetCurrentContent();
1061 result = PushContent(content);
1062 NS_ENSURE_SUCCESS(result, result);
1064 // Set the ID attribute atom on the node info object for this node
1065 // This must occur before the attributes are added so the name
1066 // of the id attribute is known.
1067 if (aIndex != -1 && NS_SUCCEEDED(result)) {
1068 nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
1070 if (IDAttr) {
1071 nodeInfo->SetIDAttributeAtom(IDAttr);
1075 #ifdef MOZ_XTF
1076 if (nameSpaceID > kNameSpaceID_LastBuiltin)
1077 content->BeginAddingChildren();
1078 #endif
1080 // Set the attributes on the new content element
1081 result = AddAttributes(aAtts, content);
1083 if (NS_OK == result) {
1084 // Store the element
1085 if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
1086 NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
1088 parent->AppendChildTo(content, PR_FALSE);
1092 // Some HTML nodes need DoneCreatingElement() called to initialize
1093 // properly (eg form state restoration).
1094 if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML) {
1095 if (nodeInfo->NameAtom() == nsGkAtoms::input ||
1096 nodeInfo->NameAtom() == nsGkAtoms::button) {
1097 content->DoneCreatingElement();
1098 } else if (nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) {
1099 mCurrentHead = content;
1103 if (IsMonolithicContainer(nodeInfo)) {
1104 mInMonolithicContainer++;
1107 if (content != mDocElement && !mCurrentHead) {
1108 // This isn't the root and we're not inside an XHTML <head>.
1109 // Might need to start layout
1110 MaybeStartLayout(PR_FALSE);
1113 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
1114 result;
1117 NS_IMETHODIMP
1118 nsXMLContentSink::HandleEndElement(const PRUnichar *aName)
1120 return HandleEndElement(aName, PR_TRUE);
1123 nsresult
1124 nsXMLContentSink::HandleEndElement(const PRUnichar *aName,
1125 PRBool aInterruptable)
1127 nsresult result = NS_OK;
1129 // XXX Hopefully the parser will flag this before we get
1130 // here. If we're in the prolog or epilog, there should be
1131 // no close tags for elements.
1132 PR_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
1134 FlushText();
1136 StackNode & sn = GetCurrentStackNode();
1138 nsCOMPtr<nsIContent> content;
1139 sn.mContent.swap(content);
1140 PRUint32 numFlushed = sn.mNumFlushed;
1142 PopContent();
1143 NS_ASSERTION(content, "failed to pop content");
1144 #ifdef DEBUG
1145 // Check that we're closing the right thing
1146 nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom;
1147 PRInt32 debugNameSpaceID;
1148 nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
1149 getter_AddRefs(debugTagAtom),
1150 &debugNameSpaceID);
1151 NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID),
1152 "Wrong element being closed");
1153 #endif
1155 result = CloseElement(content);
1157 if (mCurrentHead == content) {
1158 mCurrentHead = nsnull;
1161 if (mDocElement == content) {
1162 // XXXbz for roots that don't want to be appended on open, we
1163 // probably need to deal here.... (and stop appending them on open).
1164 mState = eXMLContentSinkState_InEpilog;
1166 // We might have had no occasion to start layout yet. Do so now.
1167 MaybeStartLayout(PR_FALSE);
1170 PRInt32 stackLen = mContentStack.Length();
1171 if (mNotifyLevel >= stackLen) {
1172 if (numFlushed < content->GetChildCount()) {
1173 NotifyAppend(content, numFlushed);
1175 mNotifyLevel = stackLen - 1;
1177 DidAddContent();
1179 #ifdef MOZ_SVG
1180 if (mDocument &&
1181 content->GetNameSpaceID() == kNameSpaceID_SVG &&
1182 content->HasAttr(kNameSpaceID_None, nsGkAtoms::onload)) {
1183 FlushTags();
1185 nsEvent event(PR_TRUE, NS_SVG_LOAD);
1186 event.eventStructType = NS_SVG_EVENT;
1187 event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
1189 // Do we care about forcing presshell creation if it hasn't happened yet?
1190 // That is, should this code flush or something? Does it really matter?
1191 // For that matter, do we really want to try getting the prescontext? Does
1192 // this event ever want one?
1193 nsRefPtr<nsPresContext> ctx;
1194 nsCOMPtr<nsIPresShell> shell = mDocument->GetPrimaryShell();
1195 if (shell) {
1196 ctx = shell->GetPresContext();
1198 nsEventDispatcher::Dispatch(content, ctx, &event);
1200 #endif
1202 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
1203 result;
1206 NS_IMETHODIMP
1207 nsXMLContentSink::HandleComment(const PRUnichar *aName)
1209 FlushText();
1211 nsCOMPtr<nsIContent> comment;
1212 nsresult rv = NS_NewCommentNode(getter_AddRefs(comment), mNodeInfoManager);
1213 if (comment) {
1214 comment->SetText(nsDependentString(aName), PR_FALSE);
1215 rv = AddContentAsLeaf(comment);
1216 DidAddContent();
1219 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1222 NS_IMETHODIMP
1223 nsXMLContentSink::HandleCDataSection(const PRUnichar *aData,
1224 PRUint32 aLength)
1226 // XSLT doesn't differentiate between text and cdata and wants adjacent
1227 // textnodes merged, so add as text.
1228 if (mXSLTProcessor) {
1229 return AddText(aData, aLength);
1232 FlushText();
1234 nsCOMPtr<nsIContent> cdata;
1235 nsresult rv = NS_NewXMLCDATASection(getter_AddRefs(cdata), mNodeInfoManager);
1236 if (cdata) {
1237 cdata->SetText(aData, aLength, PR_FALSE);
1238 rv = AddContentAsLeaf(cdata);
1239 DidAddContent();
1242 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1245 NS_IMETHODIMP
1246 nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset,
1247 const nsAString & aName,
1248 const nsAString & aSystemId,
1249 const nsAString & aPublicId,
1250 nsISupports* aCatalogData)
1252 FlushText();
1254 nsresult rv = NS_OK;
1256 NS_ASSERTION(mDocument, "Shouldn't get here from a document fragment");
1258 nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
1259 NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
1261 // Create a new doctype node
1262 nsCOMPtr<nsIDOMDocumentType> docType;
1263 rv = NS_NewDOMDocumentType(getter_AddRefs(docType), mNodeInfoManager, nsnull,
1264 name, nsnull, nsnull, aPublicId, aSystemId,
1265 aSubset);
1266 if (NS_FAILED(rv) || !docType) {
1267 return rv;
1270 if (aCatalogData && mCSSLoader && mDocument) {
1271 // bug 124570 - we only expect additional agent sheets for now -- ignore
1272 // exit codes, error are not fatal here, just that the stylesheet won't apply
1273 nsCOMPtr<nsIURI> uri(do_QueryInterface(aCatalogData));
1274 if (uri) {
1275 nsCOMPtr<nsICSSStyleSheet> sheet;
1276 mCSSLoader->LoadSheetSync(uri, PR_TRUE, getter_AddRefs(sheet));
1278 #ifdef NS_DEBUG
1279 nsCAutoString uriStr;
1280 uri->GetSpec(uriStr);
1281 printf("Loading catalog stylesheet: %s ... %s\n", uriStr.get(), sheet.get() ? "Done" : "Failed");
1282 #endif
1283 if (sheet) {
1284 mDocument->BeginUpdate(UPDATE_STYLE);
1285 mDocument->AddCatalogStyleSheet(sheet);
1286 mDocument->EndUpdate(UPDATE_STYLE);
1291 nsCOMPtr<nsIContent> content = do_QueryInterface(docType);
1292 NS_ASSERTION(content, "doctype isn't content?");
1294 rv = mDocument->AppendChildTo(content, PR_FALSE);
1295 DidAddContent();
1296 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1299 NS_IMETHODIMP
1300 nsXMLContentSink::HandleCharacterData(const PRUnichar *aData,
1301 PRUint32 aLength)
1303 return HandleCharacterData(aData, aLength, PR_TRUE);
1306 nsresult
1307 nsXMLContentSink::HandleCharacterData(const PRUnichar *aData, PRUint32 aLength,
1308 PRBool aInterruptable)
1310 nsresult rv = NS_OK;
1311 if (aData && mState != eXMLContentSinkState_InProlog &&
1312 mState != eXMLContentSinkState_InEpilog) {
1313 rv = AddText(aData, aLength);
1315 return aInterruptable && NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1318 NS_IMETHODIMP
1319 nsXMLContentSink::HandleProcessingInstruction(const PRUnichar *aTarget,
1320 const PRUnichar *aData)
1322 FlushText();
1324 const nsDependentString target(aTarget);
1325 const nsDependentString data(aData);
1327 nsCOMPtr<nsIContent> node;
1329 nsresult rv = NS_NewXMLProcessingInstruction(getter_AddRefs(node),
1330 mNodeInfoManager, target, data);
1331 NS_ENSURE_SUCCESS(rv, rv);
1333 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node));
1334 if (ssle) {
1335 ssle->InitStyleLinkElement(PR_FALSE);
1336 ssle->SetEnableUpdates(PR_FALSE);
1337 mPrettyPrintXML = PR_FALSE;
1340 rv = AddContentAsLeaf(node);
1341 NS_ENSURE_SUCCESS(rv, rv);
1342 DidAddContent();
1344 if (ssle) {
1345 // This is an xml-stylesheet processing instruction... but it might not be
1346 // a CSS one if the type is set to something else.
1347 ssle->SetEnableUpdates(PR_TRUE);
1348 PRBool willNotify;
1349 PRBool isAlternate;
1350 rv = ssle->UpdateStyleSheet(this, &willNotify, &isAlternate);
1351 NS_ENSURE_SUCCESS(rv, rv);
1353 if (willNotify) {
1354 // Successfully started a stylesheet load
1355 if (!isAlternate) {
1356 ++mPendingSheetCount;
1357 mScriptLoader->AddExecuteBlocker();
1360 return NS_OK;
1364 // If it's not a CSS stylesheet PI...
1365 nsAutoString type;
1366 nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::type, type);
1368 if (mState != eXMLContentSinkState_InProlog ||
1369 !target.EqualsLiteral("xml-stylesheet") ||
1370 type.IsEmpty() ||
1371 type.LowerCaseEqualsLiteral("text/css")) {
1372 return DidProcessATokenImpl();
1375 nsAutoString href, title, media;
1376 PRBool isAlternate = PR_FALSE;
1378 // If there was no href, we can't do anything with this PI
1379 if (!ParsePIData(data, href, title, media, isAlternate)) {
1380 return DidProcessATokenImpl();
1383 rv = ProcessStyleLink(node, href, isAlternate, title, type, media);
1384 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1387 /* static */
1388 PRBool
1389 nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref,
1390 nsString &aTitle, nsString &aMedia,
1391 PRBool &aIsAlternate)
1393 // If there was no href, we can't do anything with this PI
1394 if (!nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::href, aHref)) {
1395 return PR_FALSE;
1398 nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::title, aTitle);
1400 nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::media, aMedia);
1402 nsAutoString alternate;
1403 nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::alternate, alternate);
1405 aIsAlternate = alternate.EqualsLiteral("yes");
1407 return PR_TRUE;
1411 * Extends nsContentSink::ProcessMETATag to grab the 'viewport' meta tag. This
1412 * information is ignored by the generic content sink because it only stores
1413 * http-equiv meta tags. We need it in the XMLContentSink for XHTML documents.
1415 * Initially implemented for bug #436083
1417 nsresult
1418 nsXMLContentSink::ProcessMETATag(nsIContent *aContent) {
1420 /* Call the superclass method. */
1421 nsContentSink::ProcessMETATag(aContent);
1423 nsresult rv = NS_OK;
1425 /* Look for the viewport meta tag. If we find it, process it and put the
1426 * data into the document header. */
1427 if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
1428 nsGkAtoms::viewport, eIgnoreCase)) {
1429 nsAutoString value;
1430 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, value);
1431 rv = nsContentUtils::ProcessViewportInfo(mDocument, value);
1434 return rv;
1437 NS_IMETHODIMP
1438 nsXMLContentSink::HandleXMLDeclaration(const PRUnichar *aVersion,
1439 const PRUnichar *aEncoding,
1440 PRInt32 aStandalone)
1442 mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone);
1444 return DidProcessATokenImpl();
1447 NS_IMETHODIMP
1448 nsXMLContentSink::ReportError(const PRUnichar* aErrorText,
1449 const PRUnichar* aSourceText,
1450 nsIScriptError *aError,
1451 PRBool *_retval)
1453 NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
1454 nsresult rv = NS_OK;
1456 // The expat driver should report the error. We're just cleaning up the mess.
1457 *_retval = PR_TRUE;
1459 mPrettyPrintXML = PR_FALSE;
1461 mState = eXMLContentSinkState_InProlog;
1463 // XXX need to stop scripts here -- hsivonen
1465 // stop observing in order to avoid crashing when removing content
1466 mDocument->RemoveObserver(this);
1468 // Clear the current content and
1469 // prepare to set <parsererror> as the document root
1470 nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mDocument));
1471 if (node) {
1472 for (;;) {
1473 nsCOMPtr<nsIDOMNode> child, dummy;
1474 node->GetLastChild(getter_AddRefs(child));
1475 if (!child)
1476 break;
1477 node->RemoveChild(child, getter_AddRefs(dummy));
1480 NS_IF_RELEASE(mDocElement);
1482 // Clear any buffered-up text we have. It's enough to set the length to 0.
1483 // The buffer itself is allocated when we're created and deleted in our
1484 // destructor, so don't mess with it.
1485 mTextLength = 0;
1487 if (mXSLTProcessor) {
1488 // Get rid of the XSLT processor.
1489 mXSLTProcessor->CancelLoads();
1490 mXSLTProcessor = nsnull;
1493 // release the nodes on stack
1494 mContentStack.Clear();
1495 mNotifyLevel = 0;
1497 const PRUnichar* noAtts[] = { 0, 0 };
1499 NS_NAMED_LITERAL_STRING(errorNs,
1500 "http://www.mozilla.org/newlayout/xml/parsererror.xml");
1502 nsAutoString parsererror(errorNs);
1503 parsererror.Append((PRUnichar)0xFFFF);
1504 parsererror.AppendLiteral("parsererror");
1506 rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, (PRUint32)-1,
1507 PR_FALSE);
1508 NS_ENSURE_SUCCESS(rv, rv);
1510 rv = HandleCharacterData(aErrorText, nsCRT::strlen(aErrorText), PR_FALSE);
1511 NS_ENSURE_SUCCESS(rv, rv);
1513 nsAutoString sourcetext(errorNs);
1514 sourcetext.Append((PRUnichar)0xFFFF);
1515 sourcetext.AppendLiteral("sourcetext");
1517 rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, (PRUint32)-1,
1518 PR_FALSE);
1519 NS_ENSURE_SUCCESS(rv, rv);
1521 rv = HandleCharacterData(aSourceText, nsCRT::strlen(aSourceText), PR_FALSE);
1522 NS_ENSURE_SUCCESS(rv, rv);
1524 rv = HandleEndElement(sourcetext.get(), PR_FALSE);
1525 NS_ENSURE_SUCCESS(rv, rv);
1527 rv = HandleEndElement(parsererror.get(), PR_FALSE);
1528 NS_ENSURE_SUCCESS(rv, rv);
1530 FlushTags();
1532 return NS_OK;
1535 nsresult
1536 nsXMLContentSink::AddAttributes(const PRUnichar** aAtts,
1537 nsIContent* aContent)
1539 // Add tag attributes to the content attributes
1540 nsCOMPtr<nsIAtom> prefix, localName;
1541 while (*aAtts) {
1542 PRInt32 nameSpaceID;
1543 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
1544 getter_AddRefs(localName), &nameSpaceID);
1546 // Add attribute to content
1547 aContent->SetAttr(nameSpaceID, localName, prefix,
1548 nsDependentString(aAtts[1]), PR_FALSE);
1549 aAtts += 2;
1552 // Give autoloading links a chance to fire
1553 if (mDocShell && mAllowAutoXLinks) {
1554 nsresult rv = aContent->MaybeTriggerAutoLink(mDocShell);
1555 if (rv == NS_XML_AUTOLINK_REPLACE ||
1556 rv == NS_XML_AUTOLINK_UNDEFINED) {
1557 // If we do not terminate the parse, we just keep generating link trigger
1558 // events. We want to parse only up to the first replace link, and stop.
1559 mParser->Terminate();
1563 return NS_OK;
1566 #define NS_ACCUMULATION_BUFFER_SIZE 4096
1568 nsresult
1569 nsXMLContentSink::AddText(const PRUnichar* aText,
1570 PRInt32 aLength)
1572 // Create buffer when we first need it
1573 if (0 == mTextSize) {
1574 mText = (PRUnichar *) PR_MALLOC(sizeof(PRUnichar) * NS_ACCUMULATION_BUFFER_SIZE);
1575 if (nsnull == mText) {
1576 return NS_ERROR_OUT_OF_MEMORY;
1578 mTextSize = NS_ACCUMULATION_BUFFER_SIZE;
1581 // Copy data from string into our buffer; flush buffer when it fills up
1582 PRInt32 offset = 0;
1583 while (0 != aLength) {
1584 PRInt32 amount = mTextSize - mTextLength;
1585 if (0 == amount) {
1586 // XSLT wants adjacent textnodes merged.
1587 if (mConstrainSize && !mXSLTProcessor) {
1588 nsresult rv = FlushText();
1589 if (NS_OK != rv) {
1590 return rv;
1593 amount = mTextSize - mTextLength;
1595 else {
1596 mTextSize += aLength;
1597 mText = (PRUnichar *) PR_REALLOC(mText, sizeof(PRUnichar) * mTextSize);
1598 if (nsnull == mText) {
1599 mTextSize = 0;
1601 return NS_ERROR_OUT_OF_MEMORY;
1604 amount = aLength;
1607 if (amount > aLength) {
1608 amount = aLength;
1610 memcpy(&mText[mTextLength], &aText[offset], sizeof(PRUnichar) * amount);
1611 mTextLength += amount;
1612 offset += amount;
1613 aLength -= amount;
1616 return NS_OK;
1619 void
1620 nsXMLContentSink::FlushPendingNotifications(mozFlushType aType)
1622 // Only flush tags if we're not doing the notification ourselves
1623 // (since we aren't reentrant)
1624 if (!mInNotification) {
1625 if (aType >= Flush_ContentAndNotify) {
1626 FlushTags();
1628 else {
1629 FlushText(PR_FALSE);
1631 if (aType >= Flush_Layout) {
1632 // Make sure that layout has started so that the reflow flush
1633 // will actually happen.
1634 MaybeStartLayout(PR_TRUE);
1640 * NOTE!! Forked from SinkContext. Please keep in sync.
1642 * Flush all elements that have been seen so far such that
1643 * they are visible in the tree. Specifically, make sure
1644 * that they are all added to their respective parents.
1645 * Also, do notification at the top for all content that
1646 * has been newly added so that the frame tree is complete.
1648 nsresult
1649 nsXMLContentSink::FlushTags()
1651 mDeferredFlushTags = PR_FALSE;
1652 PRBool oldBeganUpdate = mBeganUpdate;
1653 PRUint32 oldUpdates = mUpdatesInNotification;
1655 mUpdatesInNotification = 0;
1656 ++mInNotification;
1658 // Scope so we call EndUpdate before we decrease mInNotification
1659 mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, PR_TRUE);
1660 mBeganUpdate = PR_TRUE;
1662 // Don't release last text node in case we need to add to it again
1663 FlushText(PR_FALSE);
1665 // Start from the base of the stack (growing downward) and do
1666 // a notification from the node that is closest to the root of
1667 // tree for any content that has been added.
1669 PRInt32 stackPos;
1670 PRInt32 stackLen = mContentStack.Length();
1671 PRBool flushed = PR_FALSE;
1672 PRUint32 childCount;
1673 nsIContent* content;
1675 for (stackPos = 0; stackPos < stackLen; ++stackPos) {
1676 content = mContentStack[stackPos].mContent;
1677 childCount = content->GetChildCount();
1679 if (!flushed && (mContentStack[stackPos].mNumFlushed < childCount)) {
1680 NotifyAppend(content, mContentStack[stackPos].mNumFlushed);
1681 flushed = PR_TRUE;
1684 mContentStack[stackPos].mNumFlushed = childCount;
1686 mNotifyLevel = stackLen - 1;
1688 --mInNotification;
1690 if (mUpdatesInNotification > 1) {
1691 UpdateChildCounts();
1694 mUpdatesInNotification = oldUpdates;
1695 mBeganUpdate = oldBeganUpdate;
1697 return NS_OK;
1701 * NOTE!! Forked from SinkContext. Please keep in sync.
1703 void
1704 nsXMLContentSink::UpdateChildCounts()
1706 // Start from the top of the stack (growing upwards) and see if any
1707 // new content has been appended. If so, we recognize that reflows
1708 // have been generated for it and we should make sure that no
1709 // further reflows occur. Note that we have to include stackPos == 0
1710 // to properly notify on kids of <html>.
1711 PRInt32 stackLen = mContentStack.Length();
1712 PRInt32 stackPos = stackLen - 1;
1713 while (stackPos >= 0) {
1714 StackNode & node = mContentStack[stackPos];
1715 node.mNumFlushed = node.mContent->GetChildCount();
1717 stackPos--;
1719 mNotifyLevel = stackLen - 1;
1722 PRBool
1723 nsXMLContentSink::IsMonolithicContainer(nsINodeInfo* aNodeInfo)
1725 return ((aNodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
1726 (aNodeInfo->NameAtom() == nsGkAtoms::tr ||
1727 aNodeInfo->NameAtom() == nsGkAtoms::select ||
1728 aNodeInfo->NameAtom() == nsGkAtoms::object ||
1729 aNodeInfo->NameAtom() == nsGkAtoms::applet))
1730 #ifdef MOZ_MATHML
1731 || (aNodeInfo->NamespaceID() == kNameSpaceID_MathML &&
1732 (aNodeInfo->NameAtom() == nsGkAtoms::math))
1733 #endif