/src/mozilla-central/dom/xml/nsXMLFragmentContentSink.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "nsCOMPtr.h" |
8 | | #include "nsXMLContentSink.h" |
9 | | #include "nsIFragmentContentSink.h" |
10 | | #include "nsIXMLContentSink.h" |
11 | | #include "nsContentSink.h" |
12 | | #include "nsIExpatSink.h" |
13 | | #include "nsIDTD.h" |
14 | | #include "nsIDocument.h" |
15 | | #include "nsIContent.h" |
16 | | #include "nsGkAtoms.h" |
17 | | #include "mozilla/dom/NodeInfo.h" |
18 | | #include "nsContentCreatorFunctions.h" |
19 | | #include "nsError.h" |
20 | | #include "nsIConsoleService.h" |
21 | | #include "nsIScriptError.h" |
22 | | #include "nsTHashtable.h" |
23 | | #include "nsHashKeys.h" |
24 | | #include "nsTArray.h" |
25 | | #include "nsCycleCollectionParticipant.h" |
26 | | #include "nsIDocShell.h" |
27 | | #include "mozilla/css/Loader.h" |
28 | | #include "mozilla/dom/DocumentFragment.h" |
29 | | #include "mozilla/dom/ProcessingInstruction.h" |
30 | | #include "mozilla/dom/ScriptLoader.h" |
31 | | |
32 | | using namespace mozilla::dom; |
33 | | |
34 | | class nsXMLFragmentContentSink : public nsXMLContentSink, |
35 | | public nsIFragmentContentSink |
36 | | { |
37 | | public: |
38 | | nsXMLFragmentContentSink(); |
39 | | |
40 | | // nsISupports |
41 | | NS_DECL_ISUPPORTS_INHERITED |
42 | | NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsXMLFragmentContentSink, |
43 | | nsXMLContentSink) |
44 | | |
45 | | // nsIExpatSink |
46 | | NS_IMETHOD HandleDoctypeDecl(const nsAString& aSubset, |
47 | | const nsAString& aName, |
48 | | const nsAString& aSystemId, |
49 | | const nsAString& aPublicId, |
50 | | nsISupports* aCatalogData) override; |
51 | | NS_IMETHOD HandleProcessingInstruction(const char16_t* aTarget, |
52 | | const char16_t* aData) override; |
53 | | NS_IMETHOD HandleXMLDeclaration(const char16_t* aVersion, |
54 | | const char16_t* aEncoding, |
55 | | int32_t aStandalone) override; |
56 | | NS_IMETHOD ReportError(const char16_t* aErrorText, |
57 | | const char16_t* aSourceText, |
58 | | nsIScriptError* aError, |
59 | | bool* aRetval) override; |
60 | | |
61 | | // nsIContentSink |
62 | | NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode) override; |
63 | | NS_IMETHOD DidBuildModel(bool aTerminated) override; |
64 | | virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override; |
65 | | virtual nsISupports* GetTarget() override; |
66 | | NS_IMETHOD DidProcessATokenImpl(); |
67 | | |
68 | | // nsIXMLContentSink |
69 | | |
70 | | // nsIFragmentContentSink |
71 | | NS_IMETHOD FinishFragmentParsing(DocumentFragment** aFragment) override; |
72 | | NS_IMETHOD SetTargetDocument(nsIDocument* aDocument) override; |
73 | | NS_IMETHOD WillBuildContent() override; |
74 | | NS_IMETHOD DidBuildContent() override; |
75 | | NS_IMETHOD IgnoreFirstContainer() override; |
76 | | NS_IMETHOD SetPreventScriptExecution(bool aPreventScriptExecution) override; |
77 | | |
78 | | protected: |
79 | | virtual ~nsXMLFragmentContentSink(); |
80 | | |
81 | | virtual bool SetDocElement(int32_t aNameSpaceID, |
82 | | nsAtom* aTagName, |
83 | | nsIContent* aContent) override; |
84 | | virtual nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount, |
85 | | mozilla::dom::NodeInfo* aNodeInfo, |
86 | | uint32_t aLineNumber, uint32_t aColumnNumber, |
87 | | nsIContent** aResult, bool* aAppendContent, |
88 | | mozilla::dom::FromParser aFromParser) override; |
89 | | virtual nsresult CloseElement(nsIContent* aContent) override; |
90 | | |
91 | | virtual void MaybeStartLayout(bool aIgnorePendingSheets) override; |
92 | | |
93 | | // nsContentSink overrides |
94 | | virtual nsresult ProcessStyleLinkFromHeader( |
95 | | const nsAString& aHref, |
96 | | bool aAlternate, |
97 | | const nsAString& aTitle, |
98 | | const nsAString& aType, |
99 | | const nsAString& aMedia, |
100 | | const nsAString& aReferrerPolicy) override; |
101 | | |
102 | | // nsXMLContentSink overrides |
103 | | virtual nsresult MaybeProcessXSLTLink( |
104 | | ProcessingInstruction* aProcessingInstruction, |
105 | | const nsAString& aHref, |
106 | | bool aAlternate, |
107 | | const nsAString& aTitle, |
108 | | const nsAString& aType, |
109 | | const nsAString& aMedia, |
110 | | const nsAString& aReferrerPolicy, |
111 | | bool* aWasXSLT = nullptr) override; |
112 | | |
113 | | nsCOMPtr<nsIDocument> mTargetDocument; |
114 | | // the fragment |
115 | | RefPtr<DocumentFragment> mRoot; |
116 | | bool mParseError; |
117 | | }; |
118 | | |
119 | | static nsresult |
120 | | NewXMLFragmentContentSinkHelper(nsIFragmentContentSink** aResult) |
121 | 0 | { |
122 | 0 | nsXMLFragmentContentSink* it = new nsXMLFragmentContentSink(); |
123 | 0 |
|
124 | 0 | NS_ADDREF(*aResult = it); |
125 | 0 |
|
126 | 0 | return NS_OK; |
127 | 0 | } |
128 | | |
129 | | nsresult |
130 | | NS_NewXMLFragmentContentSink(nsIFragmentContentSink** aResult) |
131 | 0 | { |
132 | 0 | return NewXMLFragmentContentSinkHelper(aResult); |
133 | 0 | } |
134 | | |
135 | | nsXMLFragmentContentSink::nsXMLFragmentContentSink() |
136 | | : mParseError(false) |
137 | 0 | { |
138 | 0 | mRunsToCompletion = true; |
139 | 0 | } |
140 | | |
141 | | nsXMLFragmentContentSink::~nsXMLFragmentContentSink() |
142 | 0 | { |
143 | 0 | } |
144 | | |
145 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLFragmentContentSink) |
146 | 0 | NS_INTERFACE_MAP_ENTRY(nsIFragmentContentSink) |
147 | 0 | NS_INTERFACE_MAP_END_INHERITING(nsXMLContentSink) |
148 | | |
149 | | NS_IMPL_ADDREF_INHERITED(nsXMLFragmentContentSink, nsXMLContentSink) |
150 | | NS_IMPL_RELEASE_INHERITED(nsXMLFragmentContentSink, nsXMLContentSink) |
151 | | |
152 | | NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLFragmentContentSink) |
153 | | |
154 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLFragmentContentSink, |
155 | 0 | nsXMLContentSink) |
156 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTargetDocument) |
157 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) |
158 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
159 | | |
160 | | NS_IMETHODIMP |
161 | | nsXMLFragmentContentSink::WillBuildModel(nsDTDMode aDTDMode) |
162 | 0 | { |
163 | 0 | if (mRoot) { |
164 | 0 | return NS_OK; |
165 | 0 | } |
166 | 0 | |
167 | 0 | mState = eXMLContentSinkState_InDocumentElement; |
168 | 0 |
|
169 | 0 | NS_ASSERTION(mTargetDocument, "Need a document!"); |
170 | 0 |
|
171 | 0 | mRoot = new DocumentFragment(mNodeInfoManager); |
172 | 0 |
|
173 | 0 | return NS_OK; |
174 | 0 | } |
175 | | |
176 | | NS_IMETHODIMP |
177 | | nsXMLFragmentContentSink::DidBuildModel(bool aTerminated) |
178 | 0 | { |
179 | 0 | // Drop our reference to the parser to get rid of a circular |
180 | 0 | // reference. |
181 | 0 | mParser = nullptr; |
182 | 0 |
|
183 | 0 | return NS_OK; |
184 | 0 | } |
185 | | |
186 | | void |
187 | | nsXMLFragmentContentSink::SetDocumentCharset( |
188 | | NotNull<const Encoding*> aEncoding) |
189 | 0 | { |
190 | 0 | MOZ_ASSERT_UNREACHABLE("fragments shouldn't set charset"); |
191 | 0 | } |
192 | | |
193 | | nsISupports * |
194 | | nsXMLFragmentContentSink::GetTarget() |
195 | 0 | { |
196 | 0 | return mTargetDocument; |
197 | 0 | } |
198 | | |
199 | | //////////////////////////////////////////////////////////////////////// |
200 | | |
201 | | bool |
202 | | nsXMLFragmentContentSink::SetDocElement(int32_t aNameSpaceID, |
203 | | nsAtom* aTagName, |
204 | | nsIContent *aContent) |
205 | 0 | { |
206 | 0 | // this is a fragment, not a document |
207 | 0 | return false; |
208 | 0 | } |
209 | | |
210 | | nsresult |
211 | | nsXMLFragmentContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount, |
212 | | mozilla::dom::NodeInfo* aNodeInfo, |
213 | | uint32_t aLineNumber, uint32_t aColumnNumber, |
214 | | nsIContent** aResult, bool* aAppendContent, |
215 | | FromParser /*aFromParser*/) |
216 | 0 | { |
217 | 0 | // Claim to not be coming from parser, since we don't do any of the |
218 | 0 | // fancy CloseElement stuff. |
219 | 0 | nsresult rv = nsXMLContentSink::CreateElement(aAtts, aAttsCount, |
220 | 0 | aNodeInfo, aLineNumber, |
221 | 0 | aColumnNumber, |
222 | 0 | aResult, aAppendContent, |
223 | 0 | NOT_FROM_PARSER); |
224 | 0 |
|
225 | 0 | // When we aren't grabbing all of the content we, never open a doc |
226 | 0 | // element, we run into trouble on the first element, so we don't append, |
227 | 0 | // and simply push this onto the content stack. |
228 | 0 | if (mContentStack.Length() == 0) { |
229 | 0 | *aAppendContent = false; |
230 | 0 | } |
231 | 0 |
|
232 | 0 | return rv; |
233 | 0 | } |
234 | | |
235 | | nsresult |
236 | | nsXMLFragmentContentSink::CloseElement(nsIContent* aContent) |
237 | 0 | { |
238 | 0 | // don't do fancy stuff in nsXMLContentSink |
239 | 0 | if (mPreventScriptExecution && |
240 | 0 | (aContent->IsHTMLElement(nsGkAtoms::script) || |
241 | 0 | aContent->IsSVGElement(nsGkAtoms::script))) { |
242 | 0 | nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent); |
243 | 0 | if (sele) { |
244 | 0 | sele->PreventExecution(); |
245 | 0 | } else { |
246 | 0 | NS_ASSERTION(nsNameSpaceManager::GetInstance()->mSVGDisabled, "Script did QI correctly, but wasn't a disabled SVG!"); |
247 | 0 | } |
248 | 0 | } |
249 | 0 | return NS_OK; |
250 | 0 | } |
251 | | |
252 | | void |
253 | | nsXMLFragmentContentSink::MaybeStartLayout(bool aIgnorePendingSheets) |
254 | 0 | { |
255 | 0 | } |
256 | | |
257 | | //////////////////////////////////////////////////////////////////////// |
258 | | |
259 | | NS_IMETHODIMP |
260 | | nsXMLFragmentContentSink::HandleDoctypeDecl(const nsAString & aSubset, |
261 | | const nsAString & aName, |
262 | | const nsAString & aSystemId, |
263 | | const nsAString & aPublicId, |
264 | | nsISupports* aCatalogData) |
265 | 0 | { |
266 | 0 | MOZ_ASSERT_UNREACHABLE("fragments shouldn't have doctype declarations"); |
267 | 0 |
|
268 | 0 | return NS_OK; |
269 | 0 | } |
270 | | |
271 | | NS_IMETHODIMP |
272 | | nsXMLFragmentContentSink::HandleProcessingInstruction(const char16_t *aTarget, |
273 | | const char16_t *aData) |
274 | 0 | { |
275 | 0 | FlushText(); |
276 | 0 |
|
277 | 0 | const nsDependentString target(aTarget); |
278 | 0 | const nsDependentString data(aData); |
279 | 0 |
|
280 | 0 | RefPtr<ProcessingInstruction> node = |
281 | 0 | NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data); |
282 | 0 |
|
283 | 0 | // no special processing here. that should happen when the fragment moves into the document |
284 | 0 | return AddContentAsLeaf(node); |
285 | 0 | } |
286 | | |
287 | | NS_IMETHODIMP |
288 | | nsXMLFragmentContentSink::HandleXMLDeclaration(const char16_t *aVersion, |
289 | | const char16_t *aEncoding, |
290 | | int32_t aStandalone) |
291 | 0 | { |
292 | 0 | MOZ_ASSERT_UNREACHABLE("fragments shouldn't have XML declarations"); |
293 | 0 | return NS_OK; |
294 | 0 | } |
295 | | |
296 | | NS_IMETHODIMP |
297 | | nsXMLFragmentContentSink::ReportError(const char16_t* aErrorText, |
298 | | const char16_t* aSourceText, |
299 | | nsIScriptError *aError, |
300 | | bool *_retval) |
301 | 0 | { |
302 | 0 | MOZ_ASSERT(aError && aSourceText && aErrorText, "Check arguments!!!"); |
303 | 0 |
|
304 | 0 | // The expat driver should report the error. |
305 | 0 | *_retval = true; |
306 | 0 |
|
307 | 0 | mParseError = true; |
308 | 0 |
|
309 | | #ifdef DEBUG |
310 | | // Report the error to stderr. |
311 | | fprintf(stderr, |
312 | | "\n%s\n%s\n\n", |
313 | | NS_LossyConvertUTF16toASCII(aErrorText).get(), |
314 | | NS_LossyConvertUTF16toASCII(aSourceText).get()); |
315 | | #endif |
316 | |
|
317 | 0 | // The following code is similar to the cleanup in nsXMLContentSink::ReportError() |
318 | 0 | mState = eXMLContentSinkState_InProlog; |
319 | 0 |
|
320 | 0 | // Clear the current content |
321 | 0 | while (mRoot->GetLastChild()) { |
322 | 0 | mRoot->GetLastChild()->Remove(); |
323 | 0 | } |
324 | 0 |
|
325 | 0 | // Clear any buffered-up text we have. It's enough to set the length to 0. |
326 | 0 | // The buffer itself is allocated when we're created and deleted in our |
327 | 0 | // destructor, so don't mess with it. |
328 | 0 | mTextLength = 0; |
329 | 0 |
|
330 | 0 | return NS_OK; |
331 | 0 | } |
332 | | |
333 | | nsresult |
334 | | nsXMLFragmentContentSink::ProcessStyleLinkFromHeader( |
335 | | const nsAString& aHref, |
336 | | bool aAlternate, |
337 | | const nsAString& aTitle, |
338 | | const nsAString& aType, |
339 | | const nsAString& aMedia, |
340 | | const nsAString& aReferrerPolicy) |
341 | | |
342 | 0 | { |
343 | 0 | MOZ_ASSERT_UNREACHABLE("Shouldn't have headers for a fragment sink"); |
344 | 0 | return NS_OK; |
345 | 0 | } |
346 | | |
347 | | nsresult |
348 | | nsXMLFragmentContentSink::MaybeProcessXSLTLink( |
349 | | ProcessingInstruction* aProcessingInstruction, |
350 | | const nsAString& aHref, |
351 | | bool aAlternate, |
352 | | const nsAString& aTitle, |
353 | | const nsAString& aType, |
354 | | const nsAString& aMedia, |
355 | | const nsAString& aReferrerPolicy, |
356 | | bool* aWasXSLT) |
357 | 0 | { |
358 | 0 | MOZ_ASSERT(!aWasXSLT, "Our one caller doesn't care about whether we're XSLT"); |
359 | 0 | return NS_OK; |
360 | 0 | } |
361 | | |
362 | | //////////////////////////////////////////////////////////////////////// |
363 | | |
364 | | NS_IMETHODIMP |
365 | | nsXMLFragmentContentSink::FinishFragmentParsing(DocumentFragment** aFragment) |
366 | 0 | { |
367 | 0 | mTargetDocument = nullptr; |
368 | 0 | mNodeInfoManager = nullptr; |
369 | 0 | mScriptLoader = nullptr; |
370 | 0 | mCSSLoader = nullptr; |
371 | 0 | mContentStack.Clear(); |
372 | 0 | mDocumentURI = nullptr; |
373 | 0 | mDocShell = nullptr; |
374 | 0 | mDocElement = nullptr; |
375 | 0 | mCurrentHead = nullptr; |
376 | 0 | if (mParseError) { |
377 | 0 | //XXX PARSE_ERR from DOM3 Load and Save would be more appropriate |
378 | 0 | mRoot = nullptr; |
379 | 0 | mParseError = false; |
380 | 0 | *aFragment = nullptr; |
381 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
382 | 0 | } |
383 | 0 | |
384 | 0 | mRoot.forget(aFragment); |
385 | 0 | return NS_OK; |
386 | 0 | } |
387 | | |
388 | | NS_IMETHODIMP |
389 | | nsXMLFragmentContentSink::SetTargetDocument(nsIDocument* aTargetDocument) |
390 | 0 | { |
391 | 0 | NS_ENSURE_ARG_POINTER(aTargetDocument); |
392 | 0 |
|
393 | 0 | mTargetDocument = aTargetDocument; |
394 | 0 | mNodeInfoManager = aTargetDocument->NodeInfoManager(); |
395 | 0 |
|
396 | 0 | return NS_OK; |
397 | 0 | } |
398 | | |
399 | | NS_IMETHODIMP |
400 | | nsXMLFragmentContentSink::WillBuildContent() |
401 | 0 | { |
402 | 0 | PushContent(mRoot); |
403 | 0 |
|
404 | 0 | return NS_OK; |
405 | 0 | } |
406 | | |
407 | | NS_IMETHODIMP |
408 | | nsXMLFragmentContentSink::DidBuildContent() |
409 | 0 | { |
410 | 0 | // Note: we need to FlushText() here because if we don't, we might not get |
411 | 0 | // an end element to do it for us, so make sure. |
412 | 0 | if (!mParseError) { |
413 | 0 | FlushText(); |
414 | 0 | } |
415 | 0 | PopContent(); |
416 | 0 |
|
417 | 0 | return NS_OK; |
418 | 0 | } |
419 | | |
420 | | NS_IMETHODIMP |
421 | | nsXMLFragmentContentSink::DidProcessATokenImpl() |
422 | 0 | { |
423 | 0 | return NS_OK; |
424 | 0 | } |
425 | | |
426 | | NS_IMETHODIMP |
427 | | nsXMLFragmentContentSink::IgnoreFirstContainer() |
428 | 0 | { |
429 | 0 | MOZ_ASSERT_UNREACHABLE("XML isn't as broken as HTML"); |
430 | 0 | return NS_ERROR_FAILURE; |
431 | 0 | } |
432 | | |
433 | | NS_IMETHODIMP |
434 | | nsXMLFragmentContentSink::SetPreventScriptExecution(bool aPrevent) |
435 | 0 | { |
436 | 0 | mPreventScriptExecution = aPrevent; |
437 | 0 | return NS_OK; |
438 | 0 | } |