1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "txMozillaTextOutput.h"
7 #include "nsContentCID.h"
8 #include "nsIContent.h"
9 #include "nsIDocument.h"
10 #include "nsIDOMDocument.h"
11 #include "nsIDOMDocumentFragment.h"
12 #include "nsIDocumentTransformer.h"
13 #include "nsCharsetSource.h"
14 #include "nsIPrincipal.h"
15 #include "txURIUtils.h"
16 #include "nsContentCreatorFunctions.h"
17 #include "nsContentUtils.h"
18 #include "nsGkAtoms.h"
19 #include "mozilla/Encoding.h"
20 #include "nsTextNode.h"
21 #include "nsNameSpaceManager.h"
22
23 using namespace mozilla;
24 using namespace mozilla::dom;
25
txMozillaTextOutput(nsITransformObserver * aObserver)26 txMozillaTextOutput::txMozillaTextOutput(nsITransformObserver* aObserver) {
27 MOZ_COUNT_CTOR(txMozillaTextOutput);
28 mObserver = do_GetWeakReference(aObserver);
29 }
30
txMozillaTextOutput(nsIDOMDocumentFragment * aDest)31 txMozillaTextOutput::txMozillaTextOutput(nsIDOMDocumentFragment* aDest) {
32 MOZ_COUNT_CTOR(txMozillaTextOutput);
33 mTextParent = do_QueryInterface(aDest);
34 mDocument = mTextParent->OwnerDoc();
35 }
36
~txMozillaTextOutput()37 txMozillaTextOutput::~txMozillaTextOutput() {
38 MOZ_COUNT_DTOR(txMozillaTextOutput);
39 }
40
attribute(nsAtom * aPrefix,nsAtom * aLocalName,nsAtom * aLowercaseLocalName,int32_t aNsID,const nsString & aValue)41 nsresult txMozillaTextOutput::attribute(nsAtom* aPrefix, nsAtom* aLocalName,
42 nsAtom* aLowercaseLocalName,
43 int32_t aNsID, const nsString& aValue) {
44 return NS_OK;
45 }
46
attribute(nsAtom * aPrefix,const nsAString & aName,const int32_t aNsID,const nsString & aValue)47 nsresult txMozillaTextOutput::attribute(nsAtom* aPrefix, const nsAString& aName,
48 const int32_t aNsID,
49 const nsString& aValue) {
50 return NS_OK;
51 }
52
characters(const nsAString & aData,bool aDOE)53 nsresult txMozillaTextOutput::characters(const nsAString& aData, bool aDOE) {
54 mText.Append(aData);
55
56 return NS_OK;
57 }
58
comment(const nsString & aData)59 nsresult txMozillaTextOutput::comment(const nsString& aData) { return NS_OK; }
60
endDocument(nsresult aResult)61 nsresult txMozillaTextOutput::endDocument(nsresult aResult) {
62 NS_ENSURE_TRUE(mDocument && mTextParent, NS_ERROR_FAILURE);
63
64 RefPtr<nsTextNode> text = new nsTextNode(mDocument->NodeInfoManager());
65
66 text->SetText(mText, false);
67 nsresult rv = mTextParent->AppendChildTo(text, true);
68 NS_ENSURE_SUCCESS(rv, rv);
69
70 // This should really be handled by nsIDocument::EndLoad
71 if (mObserver) {
72 MOZ_ASSERT(
73 mDocument->GetReadyStateEnum() == nsIDocument::READYSTATE_LOADING,
74 "Bad readyState");
75 } else {
76 MOZ_ASSERT(
77 mDocument->GetReadyStateEnum() == nsIDocument::READYSTATE_INTERACTIVE,
78 "Bad readyState");
79 }
80 mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_INTERACTIVE);
81
82 if (NS_SUCCEEDED(aResult)) {
83 nsCOMPtr<nsITransformObserver> observer = do_QueryReferent(mObserver);
84 if (observer) {
85 observer->OnTransformDone(aResult, mDocument);
86 }
87 }
88
89 return NS_OK;
90 }
91
endElement()92 nsresult txMozillaTextOutput::endElement() { return NS_OK; }
93
processingInstruction(const nsString & aTarget,const nsString & aData)94 nsresult txMozillaTextOutput::processingInstruction(const nsString& aTarget,
95 const nsString& aData) {
96 return NS_OK;
97 }
98
startDocument()99 nsresult txMozillaTextOutput::startDocument() { return NS_OK; }
100
createResultDocument(nsIDocument * aSourceDocument,bool aLoadedAsData)101 nsresult txMozillaTextOutput::createResultDocument(nsIDocument* aSourceDocument,
102 bool aLoadedAsData) {
103 /*
104 * Create an XHTML document to hold the text.
105 *
106 * <html>
107 * <head />
108 * <body>
109 * <pre id="transformiixResult"> * The text comes here * </pre>
110 * <body>
111 * </html>
112 *
113 * Except if we are transforming into a non-displayed document we create
114 * the following DOM
115 *
116 * <transformiix:result> * The text comes here * </transformiix:result>
117 */
118
119 // Create the document
120 nsresult rv = NS_NewXMLDocument(getter_AddRefs(mDocument), aLoadedAsData);
121 NS_ENSURE_SUCCESS(rv, rv);
122 // This should really be handled by nsIDocument::BeginLoad
123 MOZ_ASSERT(
124 mDocument->GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED,
125 "Bad readyState");
126 mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_LOADING);
127 bool hasHadScriptObject = false;
128 nsIScriptGlobalObject* sgo =
129 aSourceDocument->GetScriptHandlingObject(hasHadScriptObject);
130 NS_ENSURE_STATE(sgo || !hasHadScriptObject);
131
132 NS_ASSERTION(mDocument, "Need document");
133
134 // Reset and set up document
135 URIUtils::ResetWithSource(mDocument, aSourceDocument);
136 // Only do this after resetting the document to ensure we have the
137 // correct principal.
138 mDocument->SetScriptHandlingObject(sgo);
139
140 // Set the charset
141 if (!mOutputFormat.mEncoding.IsEmpty()) {
142 const Encoding* encoding = Encoding::ForLabel(mOutputFormat.mEncoding);
143 if (encoding) {
144 mDocument->SetDocumentCharacterSetSource(kCharsetFromOtherComponent);
145 mDocument->SetDocumentCharacterSet(WrapNotNull(encoding));
146 }
147 }
148
149 // Notify the contentsink that the document is created
150 nsCOMPtr<nsITransformObserver> observer = do_QueryReferent(mObserver);
151 if (observer) {
152 rv = observer->OnDocumentCreated(mDocument);
153 NS_ENSURE_SUCCESS(rv, rv);
154 }
155
156 // Create the content
157
158 // When transforming into a non-displayed document (i.e. when there is no
159 // observer) we only create a transformiix:result root element.
160 if (!observer) {
161 int32_t namespaceID;
162 rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
163 NS_LITERAL_STRING(kTXNameSpaceURI), namespaceID);
164 NS_ENSURE_SUCCESS(rv, rv);
165
166 mTextParent =
167 mDocument->CreateElem(nsDependentAtomString(nsGkAtoms::result),
168 nsGkAtoms::transformiix, namespaceID);
169
170 rv = mDocument->AppendChildTo(mTextParent, true);
171 NS_ENSURE_SUCCESS(rv, rv);
172 } else {
173 RefPtr<Element> html, head, body;
174 rv = createXHTMLElement(nsGkAtoms::html, getter_AddRefs(html));
175 NS_ENSURE_SUCCESS(rv, rv);
176
177 rv = createXHTMLElement(nsGkAtoms::head, getter_AddRefs(head));
178 NS_ENSURE_SUCCESS(rv, rv);
179
180 rv = html->AppendChildTo(head, false);
181 NS_ENSURE_SUCCESS(rv, rv);
182
183 rv = createXHTMLElement(nsGkAtoms::body, getter_AddRefs(body));
184 NS_ENSURE_SUCCESS(rv, rv);
185
186 rv = html->AppendChildTo(body, false);
187 NS_ENSURE_SUCCESS(rv, rv);
188
189 {
190 RefPtr<Element> textParent;
191 rv = createXHTMLElement(nsGkAtoms::pre, getter_AddRefs(textParent));
192 NS_ENSURE_SUCCESS(rv, rv);
193 mTextParent = textParent.forget();
194 }
195
196 rv = mTextParent->AsElement()->SetAttr(
197 kNameSpaceID_None, nsGkAtoms::id,
198 NS_LITERAL_STRING("transformiixResult"), false);
199 NS_ENSURE_SUCCESS(rv, rv);
200
201 rv = body->AppendChildTo(mTextParent, false);
202 NS_ENSURE_SUCCESS(rv, rv);
203
204 rv = mDocument->AppendChildTo(html, true);
205 NS_ENSURE_SUCCESS(rv, rv);
206 }
207
208 return NS_OK;
209 }
210
startElement(nsAtom * aPrefix,nsAtom * aLocalName,nsAtom * aLowercaseLocalName,int32_t aNsID)211 nsresult txMozillaTextOutput::startElement(nsAtom* aPrefix, nsAtom* aLocalName,
212 nsAtom* aLowercaseLocalName,
213 int32_t aNsID) {
214 return NS_OK;
215 }
216
startElement(nsAtom * aPrefix,const nsAString & aName,const int32_t aNsID)217 nsresult txMozillaTextOutput::startElement(nsAtom* aPrefix,
218 const nsAString& aName,
219 const int32_t aNsID) {
220 return NS_OK;
221 }
222
getOutputDocument(nsIDOMDocument ** aDocument)223 void txMozillaTextOutput::getOutputDocument(nsIDOMDocument** aDocument) {
224 CallQueryInterface(mDocument, aDocument);
225 }
226
createXHTMLElement(nsAtom * aName,Element ** aResult)227 nsresult txMozillaTextOutput::createXHTMLElement(nsAtom* aName,
228 Element** aResult) {
229 nsCOMPtr<Element> element = mDocument->CreateHTMLElement(aName);
230 element.forget(aResult);
231 return NS_OK;
232 }
233