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