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