1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Mozilla Public License Version
6
* 1.1 (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is the TransforMiiX XSLT processor.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 2001
20
* the Initial Developer. All Rights Reserved.
23
* Peter Van der Beken <peterv@netscape.com>
25
* Alternatively, the contents of this file may be used under the terms of
26
* either the GNU General Public License Version 2 or later (the "GPL"), or
27
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
* in which case the provisions of the GPL or the LGPL are applicable instead
29
* of those above. If you wish to allow use of your version of this file only
30
* under the terms of either the GPL or the LGPL, and not to allow others to
31
* use your version of this file under the terms of the MPL, indicate your
32
* decision by deleting the provisions above and replace them with the notice
33
* and other provisions required by the GPL or the LGPL. If you do not delete
34
* the provisions above, a recipient may use your version of this file under
35
* the terms of any one of the MPL, the GPL or the LGPL.
37
* ***** END LICENSE BLOCK ***** */
39
#include "txMozillaXMLOutput.h"
41
#include "nsIDocument.h"
42
#include "nsIDocShell.h"
43
#include "nsIScriptLoader.h"
44
#include "nsIDOMDocument.h"
45
#include "nsIDOMComment.h"
46
#include "nsIDOMDocumentType.h"
47
#include "nsIDOMDOMImplementation.h"
48
#include "nsIDOMNodeList.h"
49
#include "nsIDOMProcessingInstruction.h"
50
#include "nsIDOMText.h"
51
#include "nsIDOMHTMLTableSectionElem.h"
52
#include "nsIDOMHTMLScriptElement.h"
53
#include "nsIDOMNSDocument.h"
54
#include "nsIParser.h"
55
#include "nsIRefreshURI.h"
56
#include "nsIScriptGlobalObject.h"
57
#include "nsITextContent.h"
58
#include "nsIXMLContent.h"
59
#include "nsContentCID.h"
60
#include "nsNetUtil.h"
61
#include "nsUnicharUtils.h"
64
#include "nsIConsoleService.h"
65
#include "nsIDOMDocumentFragment.h"
66
#include "nsINameSpaceManager.h"
67
#include "nsICSSStyleSheet.h"
68
#include "txStringUtils.h"
69
#include "txURIUtils.h"
70
#include "nsIHTMLDocument.h"
71
#include "nsIStyleSheetLinkingElement.h"
72
#include "nsIDocumentTransformer.h"
74
extern nsINameSpaceManager* gTxNameSpaceManager;
76
static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID);
77
static NS_DEFINE_CID(kHTMLDocumentCID, NS_HTMLDOCUMENT_CID);
79
#define kXHTMLNameSpaceURI "http://www.w3.org/1999/xhtml"
81
#define TX_ENSURE_CURRENTNODE \
82
NS_ASSERTION(mCurrentNode, "mCurrentNode is NULL"); \
86
txMozillaXMLOutput::txMozillaXMLOutput(const nsAString& aRootName,
88
txOutputFormat* aFormat,
89
nsIDOMDocument* aSourceDocument,
90
nsIDOMDocument* aResultDocument,
91
nsITransformObserver* aObserver)
94
mDontAddCurrent(PR_FALSE),
95
mHaveTitleElement(PR_FALSE),
96
mHaveBaseElement(PR_FALSE),
97
mCreatingNewDocument(PR_TRUE)
100
mNotifier = new txTransformNotifier();
102
mNotifier->Init(aObserver);
106
mOutputFormat.merge(*aFormat);
107
mOutputFormat.setFromDefaults();
109
createResultDocument(aRootName, aRootNsID, aSourceDocument, aResultDocument);
112
txMozillaXMLOutput::txMozillaXMLOutput(txOutputFormat* aFormat,
113
nsIDOMDocumentFragment* aFragment)
116
mDontAddCurrent(PR_FALSE),
117
mHaveTitleElement(PR_FALSE),
118
mHaveBaseElement(PR_FALSE),
119
mCreatingNewDocument(PR_FALSE)
121
mOutputFormat.merge(*aFormat);
122
mOutputFormat.setFromDefaults();
124
aFragment->GetOwnerDocument(getter_AddRefs(mDocument));
126
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
127
mDocumentIsHTML = doc && !doc->IsCaseSensitive();
129
mCurrentNode = aFragment;
132
txMozillaXMLOutput::~txMozillaXMLOutput()
136
void txMozillaXMLOutput::attribute(const nsAString& aName,
138
const nsAString& aValue)
141
// XXX Signal this? (can't add attributes after element closed)
144
if (mBadChildLevel) {
148
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mCurrentNode);
149
NS_ASSERTION(element, "No element to add the attribute to.");
151
// XXX Signal this? (no element to add attributes to)
154
if ((mOutputFormat.mMethod == eHTMLOutput) && (aNsID == kNameSpaceID_None)) {
155
// Outputting HTML as XHTML, lowercase attribute names
156
nsAutoString lowerName;
157
TX_ToLowerCase(aName, lowerName);
158
element->SetAttributeNS(nsString(), lowerName,
163
gTxNameSpaceManager->GetNameSpaceURI(aNsID, nsURI);
164
element->SetAttributeNS(nsURI, aName, aValue);
168
void txMozillaXMLOutput::characters(const nsAString& aData, PRBool aDOE)
170
closePrevious(eCloseElement);
172
if (mBadChildLevel) {
179
void txMozillaXMLOutput::comment(const nsAString& aData)
181
closePrevious(eCloseElement | eFlushText);
183
if (mBadChildLevel) {
187
TX_ENSURE_CURRENTNODE;
189
nsCOMPtr<nsIDOMComment> comment;
190
nsresult rv = mDocument->CreateComment(aData,
191
getter_AddRefs(comment));
192
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create comment");
193
nsCOMPtr<nsIDOMNode> resultNode;
194
rv = mCurrentNode->AppendChild(comment, getter_AddRefs(resultNode));
195
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't append comment");
198
void txMozillaXMLOutput::endDocument()
200
closePrevious(eCloseElement | eFlushText);
201
// This should really be handled by nsIDocument::Reset
202
if (mCreatingNewDocument && !mHaveTitleElement) {
203
nsCOMPtr<nsIDOMNSDocument> domDoc = do_QueryInterface(mDocument);
205
domDoc->SetTitle(nsString());
209
if (!mRefreshString.IsEmpty()) {
210
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
211
nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
213
nsCOMPtr<nsIRefreshURI> refURI =
214
do_QueryInterface(sgo->GetDocShell());
216
refURI->SetupRefreshURIFromHeader(doc->GetBaseURI(),
223
mNotifier->OnTransformEnd();
227
void txMozillaXMLOutput::endElement(const nsAString& aName, const PRInt32 aNsID)
229
TX_ENSURE_CURRENTNODE;
231
if (mBadChildLevel) {
233
PR_LOG(txLog::xslt, PR_LOG_DEBUG,
234
("endElement, mBadChildLevel = %d\n", mBadChildLevel));
239
if (mTableState != ADDED_TBODY) {
240
nsAutoString nodeName;
241
mCurrentNode->GetNodeName(nodeName);
242
NS_ASSERTION(nodeName.Equals(aName,
243
nsCaseInsensitiveStringComparator()),
244
"Unbalanced startElement and endElement calls!");
247
nsCOMPtr<nsIDOMNode> parent;
248
mCurrentNode->GetParentNode(getter_AddRefs(parent));
249
nsAutoString nodeName;
250
parent->GetNodeName(nodeName);
251
NS_ASSERTION(nodeName.Equals(aName,
252
nsCaseInsensitiveStringComparator()),
253
"Unbalanced startElement and endElement calls!");
257
closePrevious(eCloseElement | eFlushText);
259
// Handle html-elements
260
if ((mOutputFormat.mMethod == eHTMLOutput && aNsID == kNameSpaceID_None) ||
261
aNsID == kNameSpaceID_XHTML) {
262
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mCurrentNode);
263
NS_ASSERTION(element, "endElement'ing non-element");
264
endHTMLElement(element);
267
// Add the element to the tree if it wasn't added before and take one step
269
// we can't use GetParentNode to check if mCurrentNode is the
270
// "non-added node" since that does strange things when we've called
271
// SetDocument manually
272
if (mCurrentNode == mNonAddedNode) {
273
nsCOMPtr<nsIDocument> document = do_QueryInterface(mNonAddedParent);
274
if (document && !mRootContent) {
275
mRootContent = do_QueryInterface(mCurrentNode);
276
mRootContent->SetDocument(document, PR_FALSE, PR_TRUE);
277
document->SetRootContent(mRootContent);
280
nsCOMPtr<nsIDOMNode> resultNode;
281
mNonAddedParent->AppendChild(mCurrentNode,
282
getter_AddRefs(resultNode));
284
mCurrentNode = mNonAddedParent;
285
mNonAddedParent = nsnull;
286
mNonAddedNode = nsnull;
289
nsCOMPtr<nsIDOMNode> parent;
290
mCurrentNode->GetParentNode(getter_AddRefs(parent));
291
mCurrentNode = parent;
295
NS_STATIC_CAST(TableState, NS_PTR_TO_INT32(mTableStateStack.pop()));
298
void txMozillaXMLOutput::getOutputDocument(nsIDOMDocument** aDocument)
300
*aDocument = mDocument;
301
NS_IF_ADDREF(*aDocument);
304
void txMozillaXMLOutput::processingInstruction(const nsAString& aTarget, const nsAString& aData)
306
if (mOutputFormat.mMethod == eHTMLOutput)
309
closePrevious(eCloseElement | eFlushText);
311
TX_ENSURE_CURRENTNODE;
313
nsCOMPtr<nsIDOMProcessingInstruction> pi;
314
nsresult rv = mDocument->CreateProcessingInstruction(aTarget, aData,
316
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create processing instruction");
320
nsCOMPtr<nsIStyleSheetLinkingElement> ssle;
321
if (mCreatingNewDocument) {
322
ssle = do_QueryInterface(pi);
324
ssle->InitStyleLinkElement(nsnull, PR_FALSE);
325
ssle->SetEnableUpdates(PR_FALSE);
329
nsCOMPtr<nsIDOMNode> resultNode;
330
rv = mCurrentNode->AppendChild(pi, getter_AddRefs(resultNode));
331
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't append processing instruction");
336
ssle->SetEnableUpdates(PR_TRUE);
337
rv = ssle->UpdateStyleSheet(nsnull, mNotifier);
338
if (rv == NS_ERROR_HTMLPARSER_BLOCK) {
339
nsCOMPtr<nsIStyleSheet> stylesheet;
340
ssle->GetStyleSheet(*getter_AddRefs(stylesheet));
342
mNotifier->AddStyleSheet(stylesheet);
348
void txMozillaXMLOutput::startDocument()
351
mNotifier->OnTransformStart();
355
void txMozillaXMLOutput::startElement(const nsAString& aName,
358
TX_ENSURE_CURRENTNODE;
360
if (mBadChildLevel) {
362
PR_LOG(txLog::xslt, PR_LOG_DEBUG,
363
("startElement, mBadChildLevel = %d\n", mBadChildLevel));
367
closePrevious(eCloseElement | eFlushText);
369
if (mBadChildLevel) {
370
// eCloseElement couldn't add the parent, we fail as well
372
PR_LOG(txLog::xslt, PR_LOG_DEBUG,
373
("startElement, mBadChildLevel = %d\n", mBadChildLevel));
377
nsresult rv = mTableStateStack.push(NS_INT32_TO_PTR(mTableState));
381
mTableState = NORMAL;
383
nsCOMPtr<nsIDOMElement> element;
384
mDontAddCurrent = PR_FALSE;
386
if ((mOutputFormat.mMethod == eHTMLOutput) && (aNsID == kNameSpaceID_None)) {
387
if (mDocumentIsHTML) {
388
rv = mDocument->CreateElement(aName,
389
getter_AddRefs(element));
393
ToLowerCase(aName, lcname);
394
rv = mDocument->CreateElementNS(NS_LITERAL_STRING(kXHTMLNameSpaceURI),
396
getter_AddRefs(element));
402
startHTMLElement(element, PR_FALSE);
406
gTxNameSpaceManager->GetNameSpaceURI(aNsID, nsURI);
407
rv = mDocument->CreateElementNS(nsURI, aName,
408
getter_AddRefs(element));
409
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create element");
414
if (aNsID == kNameSpaceID_XHTML)
415
startHTMLElement(element, PR_TRUE);
418
if (mCreatingNewDocument) {
419
nsCOMPtr<nsIContent> cont = do_QueryInterface(element);
420
NS_ASSERTION(cont, "element doesn't implement nsIContent");
421
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
422
cont->SetDocument(doc, PR_FALSE, PR_TRUE);
424
mParentNode = mCurrentNode;
425
mCurrentNode = do_QueryInterface(element);
428
void txMozillaXMLOutput::closePrevious(PRInt8 aAction)
430
TX_ENSURE_CURRENTNODE;
433
if ((aAction & eCloseElement) && mParentNode) {
434
nsCOMPtr<nsIDocument> document = do_QueryInterface(mParentNode);
435
nsCOMPtr<nsIDOMElement> currentElement = do_QueryInterface(mCurrentNode);
437
if (document && currentElement && mRootContent) {
438
// We already have a document element, but the XSLT spec allows this.
439
// As a workaround, create a wrapper object and use that as the
441
nsCOMPtr<nsIDOMElement> wrapper;
443
rv = mDocument->CreateElementNS(NS_LITERAL_STRING(kTXNameSpaceURI),
444
NS_LITERAL_STRING(kTXWrapper),
445
getter_AddRefs(wrapper));
446
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create wrapper element");
448
nsCOMPtr<nsIDOMNode> child, resultNode;
449
PRUint32 i, childCount = document->GetChildCount();
450
for (i = 0; i < childCount; ++i) {
451
nsCOMPtr<nsIContent> childContent = document->GetChildAt(0);
452
if (childContent == mRootContent) {
453
document->SetRootContent(nsnull);
455
child = do_QueryInterface(childContent);
456
wrapper->AppendChild(child, getter_AddRefs(resultNode));
459
mParentNode = wrapper;
460
mRootContent = do_QueryInterface(wrapper);
461
mRootContent->SetDocument(document, PR_FALSE, PR_TRUE);
462
document->SetRootContent(mRootContent);
465
if (mDontAddCurrent && !mNonAddedParent) {
466
mNonAddedParent = mParentNode;
467
mNonAddedNode = mCurrentNode;
470
if (document && currentElement && !mRootContent) {
471
mRootContent = do_QueryInterface(mCurrentNode);
472
mRootContent->SetDocument(document, PR_FALSE, PR_TRUE);
473
document->SetRootContent(mRootContent);
476
nsCOMPtr<nsIDOMNode> resultNode;
478
rv = mParentNode->AppendChild(mCurrentNode, getter_AddRefs(resultNode));
481
mCurrentNode = mParentNode;
482
PR_LOG(txLog::xslt, PR_LOG_DEBUG,
483
("closePrevious, mBadChildLevel = %d\n",
485
// warning to the console
486
nsCOMPtr<nsIConsoleService> consoleSvc =
487
do_GetService("@mozilla.org/consoleservice;1", &rv);
489
consoleSvc->LogStringMessage(
490
NS_LITERAL_STRING("failed to create XSLT content").get());
495
mParentNode = nsnull;
497
else if ((aAction & eFlushText) && !mText.IsEmpty()) {
498
nsCOMPtr<nsIDOMText> text;
499
rv = mDocument->CreateTextNode(mText, getter_AddRefs(text));
500
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create text node");
502
nsCOMPtr<nsIDOMNode> resultNode;
503
rv = mCurrentNode->AppendChild(text, getter_AddRefs(resultNode));
504
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't append text node");
510
void txMozillaXMLOutput::startHTMLElement(nsIDOMElement* aElement, PRBool aXHTML)
513
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
514
nsIAtom *atom = content->Tag();
516
mDontAddCurrent = (atom == txHTMLAtoms::script);
518
if ((atom != txHTMLAtoms::tr || aXHTML) &&
519
NS_PTR_TO_INT32(mTableStateStack.peek()) == ADDED_TBODY) {
520
nsCOMPtr<nsIDOMNode> parent;
521
mCurrentNode->GetParentNode(getter_AddRefs(parent));
522
mCurrentNode.swap(parent);
523
mTableStateStack.pop();
526
if (atom == txHTMLAtoms::table && !aXHTML) {
529
else if (atom == txHTMLAtoms::tr && !aXHTML &&
530
NS_PTR_TO_INT32(mTableStateStack.peek()) == TABLE) {
531
nsCOMPtr<nsIDOMElement> elem;
532
rv = createHTMLElement(NS_LITERAL_STRING("tbody"),
533
getter_AddRefs(elem));
537
nsCOMPtr<nsIDOMNode> dummy;
538
rv = mCurrentNode->AppendChild(elem, getter_AddRefs(dummy));
542
rv = mTableStateStack.push(NS_INT32_TO_PTR(ADDED_TBODY));
548
else if (atom == txHTMLAtoms::head &&
549
mOutputFormat.mMethod == eHTMLOutput) {
550
// Insert META tag, according to spec, 16.2, like
551
// <META http-equiv="Content-Type" content="text/html; charset=EUC-JP">
552
nsCOMPtr<nsIDOMElement> meta;
553
rv = createHTMLElement(NS_LITERAL_STRING("meta"),
554
getter_AddRefs(meta));
558
rv = meta->SetAttribute(NS_LITERAL_STRING("http-equiv"),
559
NS_LITERAL_STRING("Content-Type"));
560
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't set http-equiv on meta");
561
nsAutoString metacontent;
562
metacontent.Append(mOutputFormat.mMediaType);
563
metacontent.Append(NS_LITERAL_STRING("; charset="));
564
metacontent.Append(mOutputFormat.mEncoding);
565
rv = meta->SetAttribute(NS_LITERAL_STRING("content"),
567
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't set content on meta");
568
nsCOMPtr<nsIDOMNode> dummy;
569
rv = aElement->AppendChild(meta, getter_AddRefs(dummy));
570
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't append meta");
572
else if (mCreatingNewDocument) {
573
nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
574
do_QueryInterface(aElement);
576
ssle->InitStyleLinkElement(nsnull, PR_FALSE);
577
ssle->SetEnableUpdates(PR_FALSE);
582
void txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement)
585
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
586
NS_ASSERTION(content, "Can't QI to nsIContent");
588
nsIAtom *atom = content->Tag();
590
if (mTableState == ADDED_TBODY) {
591
NS_ASSERTION(atom == txHTMLAtoms::tbody,
592
"Element flagged as added tbody isn't a tbody");
593
nsCOMPtr<nsIDOMNode> parent;
594
mCurrentNode->GetParentNode(getter_AddRefs(parent));
595
mCurrentNode = parent;
596
mTableState = NS_STATIC_CAST(TableState,
597
NS_PTR_TO_INT32(mTableStateStack.pop()));
603
if (mNotifier && atom == txHTMLAtoms::script) {
604
// Add this script element to the array of loading script elements.
605
nsCOMPtr<nsIDOMHTMLScriptElement> scriptElement =
606
do_QueryInterface(mCurrentNode);
607
NS_ASSERTION(scriptElement, "Need script element");
608
mNotifier->AddScriptElement(scriptElement);
610
// Set document title
611
else if (mCreatingNewDocument &&
612
atom == txHTMLAtoms::title && !mHaveTitleElement) {
613
// The first title wins
614
mHaveTitleElement = PR_TRUE;
615
nsCOMPtr<nsIDOMNSDocument> domDoc = do_QueryInterface(mDocument);
616
nsCOMPtr<nsIDOMNode> textNode;
617
aElement->GetFirstChild(getter_AddRefs(textNode));
618
if (domDoc && textNode) {
620
textNode->GetNodeValue(text);
621
text.CompressWhitespace();
622
domDoc->SetTitle(text);
625
else if (mCreatingNewDocument && atom == txHTMLAtoms::base &&
627
// The first base wins
628
mHaveBaseElement = PR_TRUE;
630
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
631
NS_ASSERTION(doc, "document doesn't implement nsIDocument");
633
content->GetAttr(kNameSpaceID_None, txHTMLAtoms::target, value);
634
doc->SetBaseTarget(value);
636
content->GetAttr(kNameSpaceID_None, txHTMLAtoms::href, value);
637
nsCOMPtr<nsIURI> baseURI;
638
rv = NS_NewURI(getter_AddRefs(baseURI), value, nsnull);
641
doc->SetBaseURI(baseURI); // The document checks if it is legal to set this base
643
else if (mCreatingNewDocument && atom == txHTMLAtoms::meta) {
644
// handle HTTP-EQUIV data
645
nsAutoString httpEquiv;
646
content->GetAttr(kNameSpaceID_None, txHTMLAtoms::httpEquiv, httpEquiv);
647
if (httpEquiv.IsEmpty())
651
content->GetAttr(kNameSpaceID_None, txHTMLAtoms::content, value);
655
TX_ToLowerCase(httpEquiv);
656
nsCOMPtr<nsIAtom> header = do_GetAtom(httpEquiv);
657
processHTTPEquiv(header, value);
660
// Handle all sorts of stylesheets
661
if (mCreatingNewDocument) {
662
nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
663
do_QueryInterface(aElement);
665
ssle->SetEnableUpdates(PR_TRUE);
666
rv = ssle->UpdateStyleSheet(nsnull, mNotifier);
667
if (rv == NS_ERROR_HTMLPARSER_BLOCK) {
668
nsCOMPtr<nsIStyleSheet> stylesheet;
669
ssle->GetStyleSheet(*getter_AddRefs(stylesheet));
671
mNotifier->AddStyleSheet(stylesheet);
678
void txMozillaXMLOutput::processHTTPEquiv(nsIAtom* aHeader, const nsAString& aValue)
680
// For now we only handle "refresh". There's a longer list in
681
// HTMLContentSink::ProcessHeaderData
682
if (aHeader == txHTMLAtoms::refresh)
683
CopyUCS2toASCII(aValue, mRefreshString);
687
txMozillaXMLOutput::createResultDocument(const nsAString& aName, PRInt32 aNsID,
688
nsIDOMDocument* aSourceDocument,
689
nsIDOMDocument* aResultDocument)
693
nsCOMPtr<nsIDocument> doc;
694
if (!aResultDocument) {
695
// Create the document
696
if (mOutputFormat.mMethod == eHTMLOutput) {
697
doc = do_CreateInstance(kHTMLDocumentCID, &rv);
698
NS_ENSURE_SUCCESS(rv, rv);
700
mDocumentIsHTML = PR_TRUE;
703
// We should check the root name/namespace here and create the
704
// appropriate document
705
doc = do_CreateInstance(kXMLDocumentCID, &rv);
706
NS_ENSURE_SUCCESS(rv, rv);
708
mDocumentIsHTML = PR_FALSE;
710
mDocument = do_QueryInterface(doc);
713
mDocument = aResultDocument;
714
doc = do_QueryInterface(aResultDocument);
716
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aResultDocument);
717
mDocumentIsHTML = doc && !doc->IsCaseSensitive();
720
mCurrentNode = mDocument;
722
// Reset and set up the document
723
URIUtils::ResetWithSource(doc, aSourceDocument);
726
if (!mOutputFormat.mEncoding.IsEmpty()) {
727
doc->SetDocumentCharacterSet(
728
NS_LossyConvertUTF16toASCII(mOutputFormat.mEncoding));
729
doc->SetDocumentCharacterSetSource(kCharsetFromOtherComponent);
733
if (!mOutputFormat.mMediaType.IsEmpty()) {
734
doc->SetContentType(mOutputFormat.mMediaType);
736
else if (mOutputFormat.mMethod == eHTMLOutput) {
737
doc->SetContentType(NS_LITERAL_STRING("text/html"));
740
doc->SetContentType(NS_LITERAL_STRING("text/xml"));
743
// Set up script loader of the result document.
744
nsIScriptLoader *loader = doc->GetScriptLoader();
747
loader->AddObserver(mNotifier);
750
// Don't load scripts, we can't notify the caller when they're loaded.
751
loader->SetEnabled(PR_FALSE);
756
mNotifier->SetOutputDocument(mDocument);
759
// Do this after calling OnDocumentCreated to ensure that the
760
// PresShell/PresContext has been hooked up and get notified.
761
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
763
htmlDoc->SetCompatibilityMode(eCompatibility_FullStandards);
766
// Add a doc-type if requested
767
if (!mOutputFormat.mSystemId.IsEmpty()) {
768
nsCOMPtr<nsIDOMDOMImplementation> implementation;
769
rv = aSourceDocument->GetImplementation(getter_AddRefs(implementation));
770
NS_ENSURE_SUCCESS(rv, rv);
772
if (mOutputFormat.mMethod == eHTMLOutput) {
773
qName.Assign(NS_LITERAL_STRING("html"));
778
nsCOMPtr<nsIDOMDocumentType> documentType;
779
rv = implementation->CreateDocumentType(qName,
780
mOutputFormat.mPublicId,
781
mOutputFormat.mSystemId,
782
getter_AddRefs(documentType));
783
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't create doctype");
784
nsCOMPtr<nsIDOMNode> tmp;
785
mDocument->AppendChild(documentType, getter_AddRefs(tmp));
792
txMozillaXMLOutput::createHTMLElement(const nsAString& aName,
793
nsIDOMElement** aResult)
795
if (mDocumentIsHTML) {
796
return mDocument->CreateElement(aName, aResult);
799
return mDocument->CreateElementNS(NS_LITERAL_STRING(kXHTMLNameSpaceURI),
803
txTransformNotifier::txTransformNotifier()
804
: mInTransform(PR_FALSE)
809
txTransformNotifier::~txTransformNotifier()
813
NS_IMPL_ISUPPORTS2(txTransformNotifier,
814
nsIScriptLoaderObserver,
815
nsICSSLoaderObserver)
818
txTransformNotifier::ScriptAvailable(nsresult aResult,
819
nsIDOMHTMLScriptElement *aElement,
824
const nsAString& aScript)
826
if (NS_FAILED(aResult)) {
827
mScriptElements.RemoveObject(aElement);
828
SignalTransformEnd();
835
txTransformNotifier::ScriptEvaluated(nsresult aResult,
836
nsIDOMHTMLScriptElement *aElement,
840
mScriptElements.RemoveObject(aElement);
841
SignalTransformEnd();
846
txTransformNotifier::StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aNotify)
848
// Check that the stylesheet was in the mStylesheets array, if not it is an
849
// alternate and we don't want to call SignalTransformEnd since we don't
850
// wait on alternates before calling OnTransformDone and so the load of the
851
// alternate could finish after we called OnTransformDone already.
852
// See http://bugzilla.mozilla.org/show_bug.cgi?id=215465.
853
if (mStylesheets.RemoveObject(aSheet)) {
854
SignalTransformEnd();
861
txTransformNotifier::Init(nsITransformObserver* aObserver)
863
mObserver = aObserver;
867
txTransformNotifier::AddScriptElement(nsIDOMHTMLScriptElement* aElement)
869
mScriptElements.AppendObject(aElement);
873
txTransformNotifier::AddStyleSheet(nsIStyleSheet* aStyleSheet)
875
mStylesheets.AppendObject(aStyleSheet);
879
txTransformNotifier::OnTransformEnd()
881
mInTransform = PR_FALSE;
882
SignalTransformEnd();
886
txTransformNotifier::OnTransformStart()
888
mInTransform = PR_TRUE;
892
txTransformNotifier::SetOutputDocument(nsIDOMDocument* aDocument)
894
mDocument = aDocument;
896
// Notify the contentsink that the document is created
897
mObserver->OnDocumentCreated(mDocument);
901
txTransformNotifier::SignalTransformEnd()
903
if (mInTransform || mScriptElements.Count() > 0 ||
904
mStylesheets.Count() > 0) {
908
// Make sure that we don't get deleted while this function is executed and
909
// we remove ourselfs from the scriptloader
910
nsCOMPtr<nsIScriptLoaderObserver> kungFuDeathGrip(this);
912
// XXX Need a better way to determine transform success/failure
914
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
915
nsIScriptLoader *loader = doc->GetScriptLoader();
917
loader->RemoveObserver(this);
920
mObserver->OnTransformDone(NS_OK, mDocument);
923
// XXX Need better error message and code.
924
mObserver->OnTransformDone(NS_ERROR_FAILURE, nsnull);