|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 sw=2 et tw=78: */ |
|
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 "nsIParser.h" |
|
10 #include "nsIDocument.h" |
|
11 #include "nsIDOMDocument.h" |
|
12 #include "nsIDOMDocumentType.h" |
|
13 #include "nsIContent.h" |
|
14 #include "nsIURI.h" |
|
15 #include "nsNetUtil.h" |
|
16 #include "nsIDocShell.h" |
|
17 #include "nsIStyleSheetLinkingElement.h" |
|
18 #include "nsIDOMComment.h" |
|
19 #include "nsIDOMCDATASection.h" |
|
20 #include "DocumentType.h" |
|
21 #include "nsHTMLParts.h" |
|
22 #include "nsCRT.h" |
|
23 #include "nsCSSStyleSheet.h" |
|
24 #include "mozilla/css/Loader.h" |
|
25 #include "nsGkAtoms.h" |
|
26 #include "nsContentUtils.h" |
|
27 #include "nsIScriptContext.h" |
|
28 #include "nsNameSpaceManager.h" |
|
29 #include "nsIServiceManager.h" |
|
30 #include "nsIScriptSecurityManager.h" |
|
31 #include "nsIContentViewer.h" |
|
32 #include "prtime.h" |
|
33 #include "prlog.h" |
|
34 #include "prmem.h" |
|
35 #include "nsRect.h" |
|
36 #include "nsIWebNavigation.h" |
|
37 #include "nsIScriptElement.h" |
|
38 #include "nsScriptLoader.h" |
|
39 #include "nsStyleLinkElement.h" |
|
40 #include "nsReadableUtils.h" |
|
41 #include "nsUnicharUtils.h" |
|
42 #include "nsICookieService.h" |
|
43 #include "nsIPrompt.h" |
|
44 #include "nsIChannel.h" |
|
45 #include "nsIPrincipal.h" |
|
46 #include "nsXMLPrettyPrinter.h" |
|
47 #include "nsNodeInfoManager.h" |
|
48 #include "nsContentCreatorFunctions.h" |
|
49 #include "nsIContentPolicy.h" |
|
50 #include "nsContentPolicyUtils.h" |
|
51 #include "nsError.h" |
|
52 #include "nsIDOMProcessingInstruction.h" |
|
53 #include "nsNodeUtils.h" |
|
54 #include "nsIScriptGlobalObject.h" |
|
55 #include "nsIHTMLDocument.h" |
|
56 #include "mozAutoDocUpdate.h" |
|
57 #include "nsMimeTypes.h" |
|
58 #include "nsHtml5SVGLoadDispatcher.h" |
|
59 #include "nsTextNode.h" |
|
60 #include "mozilla/dom/CDATASection.h" |
|
61 #include "mozilla/dom/Comment.h" |
|
62 #include "mozilla/dom/Element.h" |
|
63 #include "mozilla/dom/ProcessingInstruction.h" |
|
64 |
|
65 using namespace mozilla::dom; |
|
66 |
|
67 // XXX Open Issues: |
|
68 // 1) what's not allowed - We need to figure out which HTML tags |
|
69 // (prefixed with a HTML namespace qualifier) are explicitly not |
|
70 // allowed (if any). |
|
71 // 2) factoring code with nsHTMLContentSink - There's some amount of |
|
72 // common code between this and the HTML content sink. This will |
|
73 // increase as we support more and more HTML elements. How can code |
|
74 // from the code be factored? |
|
75 |
|
76 nsresult |
|
77 NS_NewXMLContentSink(nsIXMLContentSink** aResult, |
|
78 nsIDocument* aDoc, |
|
79 nsIURI* aURI, |
|
80 nsISupports* aContainer, |
|
81 nsIChannel* aChannel) |
|
82 { |
|
83 NS_PRECONDITION(nullptr != aResult, "null ptr"); |
|
84 if (nullptr == aResult) { |
|
85 return NS_ERROR_NULL_POINTER; |
|
86 } |
|
87 nsXMLContentSink* it = new nsXMLContentSink(); |
|
88 |
|
89 nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it; |
|
90 nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel); |
|
91 NS_ENSURE_SUCCESS(rv, rv); |
|
92 |
|
93 return CallQueryInterface(it, aResult); |
|
94 } |
|
95 |
|
96 nsXMLContentSink::nsXMLContentSink() |
|
97 : mConstrainSize(true), |
|
98 mPrettyPrintXML(true) |
|
99 { |
|
100 } |
|
101 |
|
102 nsXMLContentSink::~nsXMLContentSink() |
|
103 { |
|
104 if (mText) { |
|
105 PR_Free(mText); // Doesn't null out, unlike PR_FREEIF |
|
106 } |
|
107 } |
|
108 |
|
109 nsresult |
|
110 nsXMLContentSink::Init(nsIDocument* aDoc, |
|
111 nsIURI* aURI, |
|
112 nsISupports* aContainer, |
|
113 nsIChannel* aChannel) |
|
114 { |
|
115 nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel); |
|
116 NS_ENSURE_SUCCESS(rv, rv); |
|
117 |
|
118 aDoc->AddObserver(this); |
|
119 mIsDocumentObserver = true; |
|
120 |
|
121 if (!mDocShell) { |
|
122 mPrettyPrintXML = false; |
|
123 } |
|
124 |
|
125 mState = eXMLContentSinkState_InProlog; |
|
126 mDocElement = nullptr; |
|
127 |
|
128 return NS_OK; |
|
129 } |
|
130 |
|
131 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink) |
|
132 NS_INTERFACE_MAP_ENTRY(nsIContentSink) |
|
133 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink) |
|
134 NS_INTERFACE_MAP_ENTRY(nsIExpatSink) |
|
135 NS_INTERFACE_MAP_ENTRY(nsITransformObserver) |
|
136 NS_INTERFACE_MAP_END_INHERITING(nsContentSink) |
|
137 |
|
138 NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink) |
|
139 NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink) |
|
140 |
|
141 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink) |
|
142 |
|
143 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink, |
|
144 nsContentSink) |
|
145 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentHead) |
|
146 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocElement) |
|
147 for (uint32_t i = 0, count = tmp->mContentStack.Length(); i < count; i++) { |
|
148 const StackNode& node = tmp->mContentStack.ElementAt(i); |
|
149 cb.NoteXPCOMChild(node.mContent); |
|
150 } |
|
151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
|
152 |
|
153 // nsIContentSink |
|
154 NS_IMETHODIMP |
|
155 nsXMLContentSink::WillParse(void) |
|
156 { |
|
157 return WillParseImpl(); |
|
158 } |
|
159 |
|
160 NS_IMETHODIMP |
|
161 nsXMLContentSink::WillBuildModel(nsDTDMode aDTDMode) |
|
162 { |
|
163 WillBuildModelImpl(); |
|
164 |
|
165 // Notify document that the load is beginning |
|
166 mDocument->BeginLoad(); |
|
167 |
|
168 // Check for correct load-command for maybe prettyprinting |
|
169 if (mPrettyPrintXML) { |
|
170 nsAutoCString command; |
|
171 GetParser()->GetCommand(command); |
|
172 if (!command.EqualsLiteral("view")) { |
|
173 mPrettyPrintXML = false; |
|
174 } |
|
175 } |
|
176 |
|
177 return NS_OK; |
|
178 } |
|
179 |
|
180 bool |
|
181 nsXMLContentSink::CanStillPrettyPrint() |
|
182 { |
|
183 return mPrettyPrintXML && |
|
184 (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot); |
|
185 } |
|
186 |
|
187 nsresult |
|
188 nsXMLContentSink::MaybePrettyPrint() |
|
189 { |
|
190 if (!CanStillPrettyPrint()) { |
|
191 mPrettyPrintXML = false; |
|
192 |
|
193 return NS_OK; |
|
194 } |
|
195 |
|
196 // stop observing in order to avoid crashing when replacing content |
|
197 mDocument->RemoveObserver(this); |
|
198 mIsDocumentObserver = false; |
|
199 |
|
200 // Reenable the CSSLoader so that the prettyprinting stylesheets can load |
|
201 if (mCSSLoader) { |
|
202 mCSSLoader->SetEnabled(true); |
|
203 } |
|
204 |
|
205 nsRefPtr<nsXMLPrettyPrinter> printer; |
|
206 nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer)); |
|
207 NS_ENSURE_SUCCESS(rv, rv); |
|
208 |
|
209 bool isPrettyPrinting; |
|
210 rv = printer->PrettyPrint(mDocument, &isPrettyPrinting); |
|
211 NS_ENSURE_SUCCESS(rv, rv); |
|
212 |
|
213 mPrettyPrinting = isPrettyPrinting; |
|
214 return NS_OK; |
|
215 } |
|
216 |
|
217 static void |
|
218 CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi, |
|
219 nsIDocumentTransformer* aProcessor, |
|
220 nsIDocument* aDocument) |
|
221 { |
|
222 nsAutoString target, data; |
|
223 aPi->GetTarget(target); |
|
224 |
|
225 // Check for namespace declarations |
|
226 if (target.EqualsLiteral("xslt-param-namespace")) { |
|
227 aPi->GetData(data); |
|
228 nsAutoString prefix, namespaceAttr; |
|
229 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix, |
|
230 prefix); |
|
231 if (!prefix.IsEmpty() && |
|
232 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace, |
|
233 namespaceAttr)) { |
|
234 aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr); |
|
235 } |
|
236 } |
|
237 |
|
238 // Check for actual parameters |
|
239 else if (target.EqualsLiteral("xslt-param")) { |
|
240 aPi->GetData(data); |
|
241 nsAutoString name, namespaceAttr, select, value; |
|
242 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name, |
|
243 name); |
|
244 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace, |
|
245 namespaceAttr); |
|
246 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) { |
|
247 select.SetIsVoid(true); |
|
248 } |
|
249 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) { |
|
250 value.SetIsVoid(true); |
|
251 } |
|
252 if (!name.IsEmpty()) { |
|
253 nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument); |
|
254 aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc); |
|
255 } |
|
256 } |
|
257 } |
|
258 |
|
259 NS_IMETHODIMP |
|
260 nsXMLContentSink::DidBuildModel(bool aTerminated) |
|
261 { |
|
262 if (!mParser) { |
|
263 // If mParser is null, this parse has already been terminated and must |
|
264 // not been terminated again. However, nsDocument may still think that |
|
265 // the parse has not been terminated and call back into here in the case |
|
266 // where the XML parser has finished but the XSLT transform associated |
|
267 // with the document has not. |
|
268 return NS_OK; |
|
269 } |
|
270 |
|
271 DidBuildModelImpl(aTerminated); |
|
272 |
|
273 if (mXSLTProcessor) { |
|
274 // stop observing in order to avoid crashing when replacing content |
|
275 mDocument->RemoveObserver(this); |
|
276 mIsDocumentObserver = false; |
|
277 |
|
278 // Check for xslt-param and xslt-param-namespace PIs |
|
279 for (nsIContent* child = mDocument->GetFirstChild(); |
|
280 child; |
|
281 child = child->GetNextSibling()) { |
|
282 if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) { |
|
283 nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child); |
|
284 CheckXSLTParamPI(pi, mXSLTProcessor, mDocument); |
|
285 } |
|
286 else if (child->IsElement()) { |
|
287 // Only honor PIs in the prolog |
|
288 break; |
|
289 } |
|
290 } |
|
291 |
|
292 nsCOMPtr<nsIDOMDocument> currentDOMDoc(do_QueryInterface(mDocument)); |
|
293 mXSLTProcessor->SetSourceContentModel(currentDOMDoc); |
|
294 // Since the processor now holds a reference to us we drop our reference |
|
295 // to it to avoid owning cycles |
|
296 mXSLTProcessor = nullptr; |
|
297 } |
|
298 else { |
|
299 // Kick off layout for non-XSLT transformed documents. |
|
300 |
|
301 // Check if we want to prettyprint |
|
302 MaybePrettyPrint(); |
|
303 |
|
304 bool startLayout = true; |
|
305 |
|
306 if (mPrettyPrinting) { |
|
307 NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!"); |
|
308 |
|
309 // We're pretty-printing now. See whether we should wait up on |
|
310 // stylesheet loads |
|
311 if (mDocument->CSSLoader()->HasPendingLoads() && |
|
312 NS_SUCCEEDED(mDocument->CSSLoader()->AddObserver(this))) { |
|
313 // wait for those sheets to load |
|
314 startLayout = false; |
|
315 } |
|
316 } |
|
317 |
|
318 if (startLayout) { |
|
319 StartLayout(false); |
|
320 |
|
321 ScrollToRef(); |
|
322 } |
|
323 |
|
324 mDocument->RemoveObserver(this); |
|
325 mIsDocumentObserver = false; |
|
326 |
|
327 mDocument->EndLoad(); |
|
328 } |
|
329 |
|
330 DropParserAndPerfHint(); |
|
331 |
|
332 return NS_OK; |
|
333 } |
|
334 |
|
335 NS_IMETHODIMP |
|
336 nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument) |
|
337 { |
|
338 NS_ENSURE_ARG(aResultDocument); |
|
339 |
|
340 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aResultDocument); |
|
341 if (htmlDoc) { |
|
342 htmlDoc->SetDocWriteDisabled(true); |
|
343 } |
|
344 |
|
345 nsCOMPtr<nsIContentViewer> contentViewer; |
|
346 mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); |
|
347 if (contentViewer) { |
|
348 return contentViewer->SetDocumentInternal(aResultDocument, true); |
|
349 } |
|
350 return NS_OK; |
|
351 } |
|
352 |
|
353 NS_IMETHODIMP |
|
354 nsXMLContentSink::OnTransformDone(nsresult aResult, |
|
355 nsIDocument* aResultDocument) |
|
356 { |
|
357 NS_ASSERTION(NS_FAILED(aResult) || aResultDocument, |
|
358 "Don't notify about transform success without a document."); |
|
359 |
|
360 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aResultDocument); |
|
361 |
|
362 nsCOMPtr<nsIContentViewer> contentViewer; |
|
363 mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); |
|
364 |
|
365 if (NS_FAILED(aResult) && contentViewer) { |
|
366 // Transform failed. |
|
367 if (domDoc) { |
|
368 aResultDocument->SetMayStartLayout(false); |
|
369 // We have an error document. |
|
370 contentViewer->SetDOMDocument(domDoc); |
|
371 } |
|
372 else { |
|
373 // We don't have an error document, display the |
|
374 // untransformed source document. |
|
375 nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument); |
|
376 contentViewer->SetDOMDocument(document); |
|
377 } |
|
378 } |
|
379 |
|
380 nsCOMPtr<nsIDocument> originalDocument = mDocument; |
|
381 if (NS_SUCCEEDED(aResult) || aResultDocument) { |
|
382 // Transform succeeded or it failed and we have an error |
|
383 // document to display. |
|
384 mDocument = aResultDocument; |
|
385 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument); |
|
386 if (htmlDoc) { |
|
387 htmlDoc->SetDocWriteDisabled(false); |
|
388 } |
|
389 } |
|
390 |
|
391 // Notify document observers that all the content has been stuck |
|
392 // into the document. |
|
393 // XXX do we need to notify for things like PIs? Or just the |
|
394 // documentElement? |
|
395 nsIContent *rootElement = mDocument->GetRootElement(); |
|
396 if (rootElement) { |
|
397 NS_ASSERTION(mDocument->IndexOf(rootElement) != -1, |
|
398 "rootElement not in doc?"); |
|
399 mDocument->BeginUpdate(UPDATE_CONTENT_MODEL); |
|
400 nsNodeUtils::ContentInserted(mDocument, rootElement, |
|
401 mDocument->IndexOf(rootElement)); |
|
402 mDocument->EndUpdate(UPDATE_CONTENT_MODEL); |
|
403 } |
|
404 |
|
405 // Start the layout process |
|
406 StartLayout(false); |
|
407 |
|
408 ScrollToRef(); |
|
409 |
|
410 originalDocument->EndLoad(); |
|
411 |
|
412 return NS_OK; |
|
413 } |
|
414 |
|
415 NS_IMETHODIMP |
|
416 nsXMLContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet, |
|
417 bool aWasAlternate, |
|
418 nsresult aStatus) |
|
419 { |
|
420 if (!mPrettyPrinting) { |
|
421 return nsContentSink::StyleSheetLoaded(aSheet, aWasAlternate, aStatus); |
|
422 } |
|
423 |
|
424 if (!mDocument->CSSLoader()->HasPendingLoads()) { |
|
425 mDocument->CSSLoader()->RemoveObserver(this); |
|
426 StartLayout(false); |
|
427 ScrollToRef(); |
|
428 } |
|
429 |
|
430 return NS_OK; |
|
431 } |
|
432 |
|
433 NS_IMETHODIMP |
|
434 nsXMLContentSink::WillInterrupt(void) |
|
435 { |
|
436 return WillInterruptImpl(); |
|
437 } |
|
438 |
|
439 NS_IMETHODIMP |
|
440 nsXMLContentSink::WillResume(void) |
|
441 { |
|
442 return WillResumeImpl(); |
|
443 } |
|
444 |
|
445 NS_IMETHODIMP |
|
446 nsXMLContentSink::SetParser(nsParserBase* aParser) |
|
447 { |
|
448 NS_PRECONDITION(aParser, "Should have a parser here!"); |
|
449 mParser = aParser; |
|
450 return NS_OK; |
|
451 } |
|
452 |
|
453 nsresult |
|
454 nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount, |
|
455 nsINodeInfo* aNodeInfo, uint32_t aLineNumber, |
|
456 nsIContent** aResult, bool* aAppendContent, |
|
457 FromParser aFromParser) |
|
458 { |
|
459 NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo"); |
|
460 |
|
461 *aResult = nullptr; |
|
462 *aAppendContent = true; |
|
463 nsresult rv = NS_OK; |
|
464 |
|
465 nsCOMPtr<nsINodeInfo> ni = aNodeInfo; |
|
466 nsCOMPtr<Element> content; |
|
467 rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser); |
|
468 NS_ENSURE_SUCCESS(rv, rv); |
|
469 |
|
470 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) |
|
471 || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG) |
|
472 ) { |
|
473 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content); |
|
474 sele->SetScriptLineNumber(aLineNumber); |
|
475 sele->SetCreatorParser(GetParser()); |
|
476 mConstrainSize = false; |
|
477 } |
|
478 |
|
479 // XHTML needs some special attention |
|
480 if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) { |
|
481 mPrettyPrintHasFactoredElements = true; |
|
482 } |
|
483 else { |
|
484 // If we care, find out if we just used a special factory. |
|
485 if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot && |
|
486 mPrettyPrintXML) { |
|
487 mPrettyPrintHasFactoredElements = |
|
488 nsContentUtils::NameSpaceManager()-> |
|
489 HasElementCreator(aNodeInfo->NamespaceID()); |
|
490 } |
|
491 |
|
492 if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) { |
|
493 content.forget(aResult); |
|
494 |
|
495 return NS_OK; |
|
496 } |
|
497 } |
|
498 |
|
499 if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) || |
|
500 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) || |
|
501 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) { |
|
502 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content)); |
|
503 if (ssle) { |
|
504 ssle->InitStyleLinkElement(false); |
|
505 if (aFromParser) { |
|
506 ssle->SetEnableUpdates(false); |
|
507 } |
|
508 if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) { |
|
509 ssle->SetLineNumber(aFromParser ? aLineNumber : 0); |
|
510 } |
|
511 } |
|
512 } |
|
513 |
|
514 content.forget(aResult); |
|
515 |
|
516 return NS_OK; |
|
517 } |
|
518 |
|
519 |
|
520 nsresult |
|
521 nsXMLContentSink::CloseElement(nsIContent* aContent) |
|
522 { |
|
523 NS_ASSERTION(aContent, "missing element to close"); |
|
524 |
|
525 nsINodeInfo *nodeInfo = aContent->NodeInfo(); |
|
526 |
|
527 // Some HTML nodes need DoneAddingChildren() called to initialize |
|
528 // properly (eg form state restoration). |
|
529 if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML && |
|
530 (nodeInfo->NameAtom() == nsGkAtoms::select || |
|
531 nodeInfo->NameAtom() == nsGkAtoms::textarea || |
|
532 nodeInfo->NameAtom() == nsGkAtoms::video || |
|
533 nodeInfo->NameAtom() == nsGkAtoms::audio || |
|
534 nodeInfo->NameAtom() == nsGkAtoms::object || |
|
535 nodeInfo->NameAtom() == nsGkAtoms::applet)) |
|
536 || nodeInfo->NameAtom() == nsGkAtoms::title |
|
537 ) { |
|
538 aContent->DoneAddingChildren(HaveNotifiedForCurrentContent()); |
|
539 } |
|
540 |
|
541 if (IsMonolithicContainer(nodeInfo)) { |
|
542 mInMonolithicContainer--; |
|
543 } |
|
544 |
|
545 if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) && |
|
546 !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) { |
|
547 return NS_OK; |
|
548 } |
|
549 |
|
550 if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) |
|
551 || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG) |
|
552 ) { |
|
553 mConstrainSize = true; |
|
554 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent); |
|
555 |
|
556 if (mPreventScriptExecution) { |
|
557 sele->PreventExecution(); |
|
558 return NS_OK; |
|
559 } |
|
560 |
|
561 // Always check the clock in nsContentSink right after a script |
|
562 StopDeflecting(); |
|
563 |
|
564 // Now tell the script that it's ready to go. This may execute the script |
|
565 // or return true, or neither if the script doesn't need executing. |
|
566 bool block = sele->AttemptToExecute(); |
|
567 |
|
568 // If the parser got blocked, make sure to return the appropriate rv. |
|
569 // I'm not sure if this is actually needed or not. |
|
570 if (mParser && !mParser->IsParserEnabled()) { |
|
571 // XXX The HTML sink doesn't call BlockParser here, why do we? |
|
572 GetParser()->BlockParser(); |
|
573 block = true; |
|
574 } |
|
575 |
|
576 return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK; |
|
577 } |
|
578 |
|
579 nsresult rv = NS_OK; |
|
580 if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) && |
|
581 // Need to check here to make sure this meta tag does not set |
|
582 // mPrettyPrintXML to false when we have a special root! |
|
583 (!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) { |
|
584 rv = ProcessMETATag(aContent); |
|
585 } |
|
586 else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) || |
|
587 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) || |
|
588 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) { |
|
589 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent)); |
|
590 if (ssle) { |
|
591 ssle->SetEnableUpdates(true); |
|
592 bool willNotify; |
|
593 bool isAlternate; |
|
594 rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this, |
|
595 &willNotify, |
|
596 &isAlternate); |
|
597 if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) { |
|
598 ++mPendingSheetCount; |
|
599 mScriptLoader->AddExecuteBlocker(); |
|
600 } |
|
601 } |
|
602 // Look for <link rel="dns-prefetch" href="hostname"> |
|
603 // and look for <link rel="next" href="hostname"> like in HTML sink |
|
604 if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) { |
|
605 nsAutoString relVal; |
|
606 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal); |
|
607 if (!relVal.IsEmpty()) { |
|
608 uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal); |
|
609 bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH; |
|
610 if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) { |
|
611 nsAutoString hrefVal; |
|
612 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal); |
|
613 if (!hrefVal.IsEmpty()) { |
|
614 PrefetchHref(hrefVal, aContent, hasPrefetch); |
|
615 } |
|
616 } |
|
617 if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) { |
|
618 nsAutoString hrefVal; |
|
619 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal); |
|
620 if (!hrefVal.IsEmpty()) { |
|
621 PrefetchDNS(hrefVal); |
|
622 } |
|
623 } |
|
624 } |
|
625 } |
|
626 } |
|
627 |
|
628 return rv; |
|
629 } |
|
630 |
|
631 nsresult |
|
632 nsXMLContentSink::AddContentAsLeaf(nsIContent *aContent) |
|
633 { |
|
634 nsresult result = NS_OK; |
|
635 |
|
636 if ((eXMLContentSinkState_InProlog == mState) || |
|
637 (eXMLContentSinkState_InEpilog == mState)) { |
|
638 NS_ASSERTION(mDocument, "Fragments have no prolog or epilog"); |
|
639 mDocument->AppendChildTo(aContent, false); |
|
640 } |
|
641 else { |
|
642 nsCOMPtr<nsIContent> parent = GetCurrentContent(); |
|
643 |
|
644 if (parent) { |
|
645 result = parent->AppendChildTo(aContent, false); |
|
646 } |
|
647 } |
|
648 return result; |
|
649 } |
|
650 |
|
651 // Create an XML parser and an XSL content sink and start parsing |
|
652 // the XSL stylesheet located at the given URI. |
|
653 nsresult |
|
654 nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl) |
|
655 { |
|
656 nsCOMPtr<nsIDocumentTransformer> processor = |
|
657 do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt"); |
|
658 if (!processor) { |
|
659 // No XSLT processor available, continue normal document loading |
|
660 return NS_OK; |
|
661 } |
|
662 |
|
663 processor->Init(mDocument->NodePrincipal()); |
|
664 processor->SetTransformObserver(this); |
|
665 |
|
666 nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup(); |
|
667 if (!loadGroup) { |
|
668 return NS_ERROR_FAILURE; |
|
669 } |
|
670 |
|
671 if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, loadGroup))) { |
|
672 mXSLTProcessor.swap(processor); |
|
673 } |
|
674 |
|
675 // Intentionally ignore errors here, we should continue loading the |
|
676 // XML document whether we're able to load the XSLT stylesheet or |
|
677 // not. |
|
678 |
|
679 return NS_OK; |
|
680 } |
|
681 |
|
682 nsresult |
|
683 nsXMLContentSink::ProcessStyleLink(nsIContent* aElement, |
|
684 const nsSubstring& aHref, |
|
685 bool aAlternate, |
|
686 const nsSubstring& aTitle, |
|
687 const nsSubstring& aType, |
|
688 const nsSubstring& aMedia) |
|
689 { |
|
690 nsresult rv = NS_OK; |
|
691 mPrettyPrintXML = false; |
|
692 |
|
693 nsAutoCString cmd; |
|
694 if (mParser) |
|
695 GetParser()->GetCommand(cmd); |
|
696 if (cmd.EqualsASCII(kLoadAsData)) |
|
697 return NS_OK; // Do not load stylesheets when loading as data |
|
698 |
|
699 NS_ConvertUTF16toUTF8 type(aType); |
|
700 if (type.EqualsIgnoreCase(TEXT_XSL) || |
|
701 type.EqualsIgnoreCase(APPLICATION_XSLT_XML) || |
|
702 type.EqualsIgnoreCase(TEXT_XML) || |
|
703 type.EqualsIgnoreCase(APPLICATION_XML)) { |
|
704 if (aAlternate) { |
|
705 // don't load alternate XSLT |
|
706 return NS_OK; |
|
707 } |
|
708 // LoadXSLStyleSheet needs a mDocShell. |
|
709 if (!mDocShell) |
|
710 return NS_OK; |
|
711 |
|
712 nsCOMPtr<nsIURI> url; |
|
713 rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr, |
|
714 mDocument->GetDocBaseURI()); |
|
715 NS_ENSURE_SUCCESS(rv, rv); |
|
716 |
|
717 // Do security check |
|
718 nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager(); |
|
719 rv = secMan-> |
|
720 CheckLoadURIWithPrincipal(mDocument->NodePrincipal(), url, |
|
721 nsIScriptSecurityManager::ALLOW_CHROME); |
|
722 NS_ENSURE_SUCCESS(rv, NS_OK); |
|
723 |
|
724 // Do content policy check |
|
725 int16_t decision = nsIContentPolicy::ACCEPT; |
|
726 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XSLT, |
|
727 url, |
|
728 mDocument->NodePrincipal(), |
|
729 aElement, |
|
730 type, |
|
731 nullptr, |
|
732 &decision, |
|
733 nsContentUtils::GetContentPolicy(), |
|
734 nsContentUtils::GetSecurityManager()); |
|
735 |
|
736 NS_ENSURE_SUCCESS(rv, rv); |
|
737 |
|
738 if (NS_CP_REJECTED(decision)) { |
|
739 return NS_OK; |
|
740 } |
|
741 |
|
742 return LoadXSLStyleSheet(url); |
|
743 } |
|
744 |
|
745 // Let nsContentSink deal with css. |
|
746 rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate, |
|
747 aTitle, aType, aMedia); |
|
748 |
|
749 // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt |
|
750 // pending sheets. |
|
751 |
|
752 return rv; |
|
753 } |
|
754 |
|
755 NS_IMETHODIMP |
|
756 nsXMLContentSink::SetDocumentCharset(nsACString& aCharset) |
|
757 { |
|
758 if (mDocument) { |
|
759 mDocument->SetDocumentCharacterSet(aCharset); |
|
760 } |
|
761 |
|
762 return NS_OK; |
|
763 } |
|
764 |
|
765 nsISupports * |
|
766 nsXMLContentSink::GetTarget() |
|
767 { |
|
768 return mDocument; |
|
769 } |
|
770 |
|
771 bool |
|
772 nsXMLContentSink::IsScriptExecuting() |
|
773 { |
|
774 return IsScriptExecutingImpl(); |
|
775 } |
|
776 |
|
777 nsresult |
|
778 nsXMLContentSink::FlushText(bool aReleaseTextNode) |
|
779 { |
|
780 nsresult rv = NS_OK; |
|
781 |
|
782 if (mTextLength != 0) { |
|
783 if (mLastTextNode) { |
|
784 if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) { |
|
785 mLastTextNodeSize = 0; |
|
786 mLastTextNode = nullptr; |
|
787 FlushText(aReleaseTextNode); |
|
788 } else { |
|
789 bool notify = HaveNotifiedForCurrentContent(); |
|
790 // We could probably always increase mInNotification here since |
|
791 // if AppendText doesn't notify it shouldn't trigger evil code. |
|
792 // But just in case it does, we don't want to mask any notifications. |
|
793 if (notify) { |
|
794 ++mInNotification; |
|
795 } |
|
796 rv = mLastTextNode->AppendText(mText, mTextLength, notify); |
|
797 if (notify) { |
|
798 --mInNotification; |
|
799 } |
|
800 |
|
801 mLastTextNodeSize += mTextLength; |
|
802 mTextLength = 0; |
|
803 } |
|
804 } else { |
|
805 nsRefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager); |
|
806 |
|
807 mLastTextNode = textContent; |
|
808 |
|
809 // Set the text in the text node |
|
810 textContent->SetText(mText, mTextLength, false); |
|
811 mLastTextNodeSize += mTextLength; |
|
812 mTextLength = 0; |
|
813 |
|
814 // Add text to its parent |
|
815 rv = AddContentAsLeaf(textContent); |
|
816 } |
|
817 } |
|
818 |
|
819 if (aReleaseTextNode) { |
|
820 mLastTextNodeSize = 0; |
|
821 mLastTextNode = nullptr; |
|
822 } |
|
823 |
|
824 return rv; |
|
825 } |
|
826 |
|
827 nsIContent* |
|
828 nsXMLContentSink::GetCurrentContent() |
|
829 { |
|
830 if (mContentStack.Length() == 0) { |
|
831 return nullptr; |
|
832 } |
|
833 return GetCurrentStackNode()->mContent; |
|
834 } |
|
835 |
|
836 StackNode* |
|
837 nsXMLContentSink::GetCurrentStackNode() |
|
838 { |
|
839 int32_t count = mContentStack.Length(); |
|
840 return count != 0 ? &mContentStack[count-1] : nullptr; |
|
841 } |
|
842 |
|
843 |
|
844 nsresult |
|
845 nsXMLContentSink::PushContent(nsIContent *aContent) |
|
846 { |
|
847 NS_PRECONDITION(aContent, "Null content being pushed!"); |
|
848 StackNode *sn = mContentStack.AppendElement(); |
|
849 NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY); |
|
850 |
|
851 sn->mContent = aContent; |
|
852 sn->mNumFlushed = 0; |
|
853 return NS_OK; |
|
854 } |
|
855 |
|
856 void |
|
857 nsXMLContentSink::PopContent() |
|
858 { |
|
859 int32_t count = mContentStack.Length(); |
|
860 |
|
861 if (count == 0) { |
|
862 NS_WARNING("Popping empty stack"); |
|
863 return; |
|
864 } |
|
865 |
|
866 mContentStack.RemoveElementAt(count - 1); |
|
867 } |
|
868 |
|
869 bool |
|
870 nsXMLContentSink::HaveNotifiedForCurrentContent() const |
|
871 { |
|
872 uint32_t stackLength = mContentStack.Length(); |
|
873 if (stackLength) { |
|
874 const StackNode& stackNode = mContentStack[stackLength - 1]; |
|
875 nsIContent* parent = stackNode.mContent; |
|
876 return stackNode.mNumFlushed == parent->GetChildCount(); |
|
877 } |
|
878 return true; |
|
879 } |
|
880 |
|
881 void |
|
882 nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets) |
|
883 { |
|
884 // XXXbz if aIgnorePendingSheets is true, what should we do when |
|
885 // mXSLTProcessor or CanStillPrettyPrint()? |
|
886 if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) { |
|
887 return; |
|
888 } |
|
889 StartLayout(aIgnorePendingSheets); |
|
890 } |
|
891 |
|
892 //////////////////////////////////////////////////////////////////////// |
|
893 |
|
894 bool |
|
895 nsXMLContentSink::SetDocElement(int32_t aNameSpaceID, |
|
896 nsIAtom* aTagName, |
|
897 nsIContent *aContent) |
|
898 { |
|
899 if (mDocElement) |
|
900 return false; |
|
901 |
|
902 // check for root elements that needs special handling for |
|
903 // prettyprinting |
|
904 if ((aNameSpaceID == kNameSpaceID_XBL && |
|
905 aTagName == nsGkAtoms::bindings) || |
|
906 (aNameSpaceID == kNameSpaceID_XSLT && |
|
907 (aTagName == nsGkAtoms::stylesheet || |
|
908 aTagName == nsGkAtoms::transform))) { |
|
909 mPrettyPrintHasSpecialRoot = true; |
|
910 if (mPrettyPrintXML) { |
|
911 // In this case, disable script execution, stylesheet |
|
912 // loading, and auto XLinks since we plan to prettyprint. |
|
913 mDocument->ScriptLoader()->SetEnabled(false); |
|
914 if (mCSSLoader) { |
|
915 mCSSLoader->SetEnabled(false); |
|
916 } |
|
917 } |
|
918 } |
|
919 |
|
920 mDocElement = aContent; |
|
921 nsresult rv = mDocument->AppendChildTo(mDocElement, NotifyForDocElement()); |
|
922 if (NS_FAILED(rv)) { |
|
923 // If we return false here, the caller will bail out because it won't |
|
924 // find a parent content node to append to, which is fine. |
|
925 return false; |
|
926 } |
|
927 |
|
928 if (aTagName == nsGkAtoms::html && |
|
929 aNameSpaceID == kNameSpaceID_XHTML) { |
|
930 ProcessOfflineManifest(aContent); |
|
931 } |
|
932 |
|
933 return true; |
|
934 } |
|
935 |
|
936 NS_IMETHODIMP |
|
937 nsXMLContentSink::HandleStartElement(const char16_t *aName, |
|
938 const char16_t **aAtts, |
|
939 uint32_t aAttsCount, |
|
940 int32_t aIndex, |
|
941 uint32_t aLineNumber) |
|
942 { |
|
943 return HandleStartElement(aName, aAtts, aAttsCount, aIndex, aLineNumber, |
|
944 true); |
|
945 } |
|
946 |
|
947 nsresult |
|
948 nsXMLContentSink::HandleStartElement(const char16_t *aName, |
|
949 const char16_t **aAtts, |
|
950 uint32_t aAttsCount, |
|
951 int32_t aIndex, |
|
952 uint32_t aLineNumber, |
|
953 bool aInterruptable) |
|
954 { |
|
955 NS_PRECONDITION(aIndex >= -1, "Bogus aIndex"); |
|
956 NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount"); |
|
957 // Adjust aAttsCount so it's the actual number of attributes |
|
958 aAttsCount /= 2; |
|
959 |
|
960 nsresult result = NS_OK; |
|
961 bool appendContent = true; |
|
962 nsCOMPtr<nsIContent> content; |
|
963 |
|
964 // XXX Hopefully the parser will flag this before we get |
|
965 // here. If we're in the epilog, there should be no |
|
966 // new elements |
|
967 PR_ASSERT(eXMLContentSinkState_InEpilog != mState); |
|
968 |
|
969 FlushText(); |
|
970 DidAddContent(); |
|
971 |
|
972 mState = eXMLContentSinkState_InDocumentElement; |
|
973 |
|
974 int32_t nameSpaceID; |
|
975 nsCOMPtr<nsIAtom> prefix, localName; |
|
976 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix), |
|
977 getter_AddRefs(localName), &nameSpaceID); |
|
978 |
|
979 if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName, aLineNumber)) { |
|
980 return NS_OK; |
|
981 } |
|
982 |
|
983 nsCOMPtr<nsINodeInfo> nodeInfo; |
|
984 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID, |
|
985 nsIDOMNode::ELEMENT_NODE); |
|
986 |
|
987 result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber, |
|
988 getter_AddRefs(content), &appendContent, |
|
989 FROM_PARSER_NETWORK); |
|
990 NS_ENSURE_SUCCESS(result, result); |
|
991 |
|
992 // Have to do this before we push the new content on the stack... and have to |
|
993 // do that before we set attributes, call BindToTree, etc. Ideally we'd push |
|
994 // on the stack inside CreateElement (which is effectively what the HTML sink |
|
995 // does), but that's hard with all the subclass overrides going on. |
|
996 nsCOMPtr<nsIContent> parent = GetCurrentContent(); |
|
997 |
|
998 result = PushContent(content); |
|
999 NS_ENSURE_SUCCESS(result, result); |
|
1000 |
|
1001 // Set the ID attribute atom on the node info object for this node |
|
1002 // This must occur before the attributes are added so the name |
|
1003 // of the id attribute is known. |
|
1004 if (aIndex != -1 && NS_SUCCEEDED(result)) { |
|
1005 nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]); |
|
1006 |
|
1007 if (IDAttr) { |
|
1008 nodeInfo->SetIDAttributeAtom(IDAttr); |
|
1009 } |
|
1010 } |
|
1011 |
|
1012 // Set the attributes on the new content element |
|
1013 result = AddAttributes(aAtts, content); |
|
1014 |
|
1015 if (NS_OK == result) { |
|
1016 // Store the element |
|
1017 if (!SetDocElement(nameSpaceID, localName, content) && appendContent) { |
|
1018 NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED); |
|
1019 |
|
1020 parent->AppendChildTo(content, false); |
|
1021 } |
|
1022 } |
|
1023 |
|
1024 // Some HTML nodes need DoneCreatingElement() called to initialize |
|
1025 // properly (eg form state restoration). |
|
1026 if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML) { |
|
1027 if (nodeInfo->NameAtom() == nsGkAtoms::input || |
|
1028 nodeInfo->NameAtom() == nsGkAtoms::button || |
|
1029 nodeInfo->NameAtom() == nsGkAtoms::menuitem || |
|
1030 nodeInfo->NameAtom() == nsGkAtoms::audio || |
|
1031 nodeInfo->NameAtom() == nsGkAtoms::video) { |
|
1032 content->DoneCreatingElement(); |
|
1033 } else if (nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) { |
|
1034 mCurrentHead = content; |
|
1035 } |
|
1036 } |
|
1037 |
|
1038 if (IsMonolithicContainer(nodeInfo)) { |
|
1039 mInMonolithicContainer++; |
|
1040 } |
|
1041 |
|
1042 if (content != mDocElement && !mCurrentHead) { |
|
1043 // This isn't the root and we're not inside an XHTML <head>. |
|
1044 // Might need to start layout |
|
1045 MaybeStartLayout(false); |
|
1046 } |
|
1047 |
|
1048 if (content == mDocElement) { |
|
1049 NotifyDocElementCreated(mDocument); |
|
1050 } |
|
1051 |
|
1052 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() : |
|
1053 result; |
|
1054 } |
|
1055 |
|
1056 NS_IMETHODIMP |
|
1057 nsXMLContentSink::HandleEndElement(const char16_t *aName) |
|
1058 { |
|
1059 return HandleEndElement(aName, true); |
|
1060 } |
|
1061 |
|
1062 nsresult |
|
1063 nsXMLContentSink::HandleEndElement(const char16_t *aName, |
|
1064 bool aInterruptable) |
|
1065 { |
|
1066 nsresult result = NS_OK; |
|
1067 |
|
1068 // XXX Hopefully the parser will flag this before we get |
|
1069 // here. If we're in the prolog or epilog, there should be |
|
1070 // no close tags for elements. |
|
1071 PR_ASSERT(eXMLContentSinkState_InDocumentElement == mState); |
|
1072 |
|
1073 FlushText(); |
|
1074 |
|
1075 StackNode* sn = GetCurrentStackNode(); |
|
1076 if (!sn) { |
|
1077 return NS_ERROR_UNEXPECTED; |
|
1078 } |
|
1079 |
|
1080 nsCOMPtr<nsIContent> content; |
|
1081 sn->mContent.swap(content); |
|
1082 uint32_t numFlushed = sn->mNumFlushed; |
|
1083 |
|
1084 PopContent(); |
|
1085 NS_ASSERTION(content, "failed to pop content"); |
|
1086 #ifdef DEBUG |
|
1087 // Check that we're closing the right thing |
|
1088 nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom; |
|
1089 int32_t debugNameSpaceID; |
|
1090 nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix), |
|
1091 getter_AddRefs(debugTagAtom), |
|
1092 &debugNameSpaceID); |
|
1093 NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID), |
|
1094 "Wrong element being closed"); |
|
1095 #endif |
|
1096 |
|
1097 result = CloseElement(content); |
|
1098 |
|
1099 if (mCurrentHead == content) { |
|
1100 mCurrentHead = nullptr; |
|
1101 } |
|
1102 |
|
1103 if (mDocElement == content) { |
|
1104 // XXXbz for roots that don't want to be appended on open, we |
|
1105 // probably need to deal here.... (and stop appending them on open). |
|
1106 mState = eXMLContentSinkState_InEpilog; |
|
1107 |
|
1108 // We might have had no occasion to start layout yet. Do so now. |
|
1109 MaybeStartLayout(false); |
|
1110 } |
|
1111 |
|
1112 int32_t stackLen = mContentStack.Length(); |
|
1113 if (mNotifyLevel >= stackLen) { |
|
1114 if (numFlushed < content->GetChildCount()) { |
|
1115 NotifyAppend(content, numFlushed); |
|
1116 } |
|
1117 mNotifyLevel = stackLen - 1; |
|
1118 } |
|
1119 DidAddContent(); |
|
1120 |
|
1121 if (content->IsSVG(nsGkAtoms::svg)) { |
|
1122 FlushTags(); |
|
1123 nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content); |
|
1124 if (NS_FAILED(NS_DispatchToMainThread(event))) { |
|
1125 NS_WARNING("failed to dispatch svg load dispatcher"); |
|
1126 } |
|
1127 } |
|
1128 |
|
1129 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() : |
|
1130 result; |
|
1131 } |
|
1132 |
|
1133 NS_IMETHODIMP |
|
1134 nsXMLContentSink::HandleComment(const char16_t *aName) |
|
1135 { |
|
1136 FlushText(); |
|
1137 |
|
1138 nsRefPtr<Comment> comment = new Comment(mNodeInfoManager); |
|
1139 comment->SetText(nsDependentString(aName), false); |
|
1140 nsresult rv = AddContentAsLeaf(comment); |
|
1141 DidAddContent(); |
|
1142 |
|
1143 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv; |
|
1144 } |
|
1145 |
|
1146 NS_IMETHODIMP |
|
1147 nsXMLContentSink::HandleCDataSection(const char16_t *aData, |
|
1148 uint32_t aLength) |
|
1149 { |
|
1150 // XSLT doesn't differentiate between text and cdata and wants adjacent |
|
1151 // textnodes merged, so add as text. |
|
1152 if (mXSLTProcessor) { |
|
1153 return AddText(aData, aLength); |
|
1154 } |
|
1155 |
|
1156 FlushText(); |
|
1157 |
|
1158 nsRefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager); |
|
1159 cdata->SetText(aData, aLength, false); |
|
1160 nsresult rv = AddContentAsLeaf(cdata); |
|
1161 DidAddContent(); |
|
1162 |
|
1163 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv; |
|
1164 } |
|
1165 |
|
1166 NS_IMETHODIMP |
|
1167 nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset, |
|
1168 const nsAString & aName, |
|
1169 const nsAString & aSystemId, |
|
1170 const nsAString & aPublicId, |
|
1171 nsISupports* aCatalogData) |
|
1172 { |
|
1173 FlushText(); |
|
1174 |
|
1175 nsresult rv = NS_OK; |
|
1176 |
|
1177 NS_ASSERTION(mDocument, "Shouldn't get here from a document fragment"); |
|
1178 |
|
1179 nsCOMPtr<nsIAtom> name = do_GetAtom(aName); |
|
1180 NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY); |
|
1181 |
|
1182 // Create a new doctype node |
|
1183 nsCOMPtr<nsIDOMDocumentType> docType; |
|
1184 rv = NS_NewDOMDocumentType(getter_AddRefs(docType), mNodeInfoManager, |
|
1185 name, aPublicId, aSystemId, aSubset); |
|
1186 if (NS_FAILED(rv) || !docType) { |
|
1187 return rv; |
|
1188 } |
|
1189 |
|
1190 if (aCatalogData && mCSSLoader && mDocument) { |
|
1191 // bug 124570 - we only expect additional agent sheets for now -- ignore |
|
1192 // exit codes, error are not fatal here, just that the stylesheet won't apply |
|
1193 nsCOMPtr<nsIURI> uri(do_QueryInterface(aCatalogData)); |
|
1194 if (uri) { |
|
1195 nsRefPtr<nsCSSStyleSheet> sheet; |
|
1196 mCSSLoader->LoadSheetSync(uri, true, true, getter_AddRefs(sheet)); |
|
1197 |
|
1198 #ifdef DEBUG |
|
1199 nsAutoCString uriStr; |
|
1200 uri->GetSpec(uriStr); |
|
1201 printf("Loading catalog stylesheet: %s ... %s\n", uriStr.get(), sheet.get() ? "Done" : "Failed"); |
|
1202 #endif |
|
1203 if (sheet) { |
|
1204 mDocument->BeginUpdate(UPDATE_STYLE); |
|
1205 mDocument->AddCatalogStyleSheet(sheet); |
|
1206 mDocument->EndUpdate(UPDATE_STYLE); |
|
1207 } |
|
1208 } |
|
1209 } |
|
1210 |
|
1211 nsCOMPtr<nsIContent> content = do_QueryInterface(docType); |
|
1212 NS_ASSERTION(content, "doctype isn't content?"); |
|
1213 |
|
1214 rv = mDocument->AppendChildTo(content, false); |
|
1215 DidAddContent(); |
|
1216 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv; |
|
1217 } |
|
1218 |
|
1219 NS_IMETHODIMP |
|
1220 nsXMLContentSink::HandleCharacterData(const char16_t *aData, |
|
1221 uint32_t aLength) |
|
1222 { |
|
1223 return HandleCharacterData(aData, aLength, true); |
|
1224 } |
|
1225 |
|
1226 nsresult |
|
1227 nsXMLContentSink::HandleCharacterData(const char16_t *aData, uint32_t aLength, |
|
1228 bool aInterruptable) |
|
1229 { |
|
1230 nsresult rv = NS_OK; |
|
1231 if (aData && mState != eXMLContentSinkState_InProlog && |
|
1232 mState != eXMLContentSinkState_InEpilog) { |
|
1233 rv = AddText(aData, aLength); |
|
1234 } |
|
1235 return aInterruptable && NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv; |
|
1236 } |
|
1237 |
|
1238 NS_IMETHODIMP |
|
1239 nsXMLContentSink::HandleProcessingInstruction(const char16_t *aTarget, |
|
1240 const char16_t *aData) |
|
1241 { |
|
1242 FlushText(); |
|
1243 |
|
1244 const nsDependentString target(aTarget); |
|
1245 const nsDependentString data(aData); |
|
1246 |
|
1247 nsCOMPtr<nsIContent> node = |
|
1248 NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data); |
|
1249 |
|
1250 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node)); |
|
1251 if (ssle) { |
|
1252 ssle->InitStyleLinkElement(false); |
|
1253 ssle->SetEnableUpdates(false); |
|
1254 mPrettyPrintXML = false; |
|
1255 } |
|
1256 |
|
1257 nsresult rv = AddContentAsLeaf(node); |
|
1258 NS_ENSURE_SUCCESS(rv, rv); |
|
1259 DidAddContent(); |
|
1260 |
|
1261 if (ssle) { |
|
1262 // This is an xml-stylesheet processing instruction... but it might not be |
|
1263 // a CSS one if the type is set to something else. |
|
1264 ssle->SetEnableUpdates(true); |
|
1265 bool willNotify; |
|
1266 bool isAlternate; |
|
1267 rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this, |
|
1268 &willNotify, |
|
1269 &isAlternate); |
|
1270 NS_ENSURE_SUCCESS(rv, rv); |
|
1271 |
|
1272 if (willNotify) { |
|
1273 // Successfully started a stylesheet load |
|
1274 if (!isAlternate && !mRunsToCompletion) { |
|
1275 ++mPendingSheetCount; |
|
1276 mScriptLoader->AddExecuteBlocker(); |
|
1277 } |
|
1278 |
|
1279 return NS_OK; |
|
1280 } |
|
1281 } |
|
1282 |
|
1283 // If it's not a CSS stylesheet PI... |
|
1284 nsAutoString type; |
|
1285 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type); |
|
1286 |
|
1287 if (mState != eXMLContentSinkState_InProlog || |
|
1288 !target.EqualsLiteral("xml-stylesheet") || |
|
1289 type.IsEmpty() || |
|
1290 type.LowerCaseEqualsLiteral("text/css")) { |
|
1291 return DidProcessATokenImpl(); |
|
1292 } |
|
1293 |
|
1294 nsAutoString href, title, media; |
|
1295 bool isAlternate = false; |
|
1296 |
|
1297 // If there was no href, we can't do anything with this PI |
|
1298 if (!ParsePIData(data, href, title, media, isAlternate)) { |
|
1299 return DidProcessATokenImpl(); |
|
1300 } |
|
1301 |
|
1302 rv = ProcessStyleLink(node, href, isAlternate, title, type, media); |
|
1303 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv; |
|
1304 } |
|
1305 |
|
1306 /* static */ |
|
1307 bool |
|
1308 nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref, |
|
1309 nsString &aTitle, nsString &aMedia, |
|
1310 bool &aIsAlternate) |
|
1311 { |
|
1312 // If there was no href, we can't do anything with this PI |
|
1313 if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) { |
|
1314 return false; |
|
1315 } |
|
1316 |
|
1317 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle); |
|
1318 |
|
1319 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia); |
|
1320 |
|
1321 nsAutoString alternate; |
|
1322 nsContentUtils::GetPseudoAttributeValue(aData, |
|
1323 nsGkAtoms::alternate, |
|
1324 alternate); |
|
1325 |
|
1326 aIsAlternate = alternate.EqualsLiteral("yes"); |
|
1327 |
|
1328 return true; |
|
1329 } |
|
1330 |
|
1331 NS_IMETHODIMP |
|
1332 nsXMLContentSink::HandleXMLDeclaration(const char16_t *aVersion, |
|
1333 const char16_t *aEncoding, |
|
1334 int32_t aStandalone) |
|
1335 { |
|
1336 mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone); |
|
1337 |
|
1338 return DidProcessATokenImpl(); |
|
1339 } |
|
1340 |
|
1341 NS_IMETHODIMP |
|
1342 nsXMLContentSink::ReportError(const char16_t* aErrorText, |
|
1343 const char16_t* aSourceText, |
|
1344 nsIScriptError *aError, |
|
1345 bool *_retval) |
|
1346 { |
|
1347 NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!"); |
|
1348 nsresult rv = NS_OK; |
|
1349 |
|
1350 // The expat driver should report the error. We're just cleaning up the mess. |
|
1351 *_retval = true; |
|
1352 |
|
1353 mPrettyPrintXML = false; |
|
1354 |
|
1355 mState = eXMLContentSinkState_InProlog; |
|
1356 |
|
1357 // XXX need to stop scripts here -- hsivonen |
|
1358 |
|
1359 // stop observing in order to avoid crashing when removing content |
|
1360 mDocument->RemoveObserver(this); |
|
1361 mIsDocumentObserver = false; |
|
1362 |
|
1363 // Clear the current content and |
|
1364 // prepare to set <parsererror> as the document root |
|
1365 nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mDocument)); |
|
1366 if (node) { |
|
1367 for (;;) { |
|
1368 nsCOMPtr<nsIDOMNode> child, dummy; |
|
1369 node->GetLastChild(getter_AddRefs(child)); |
|
1370 if (!child) |
|
1371 break; |
|
1372 node->RemoveChild(child, getter_AddRefs(dummy)); |
|
1373 } |
|
1374 } |
|
1375 mDocElement = nullptr; |
|
1376 |
|
1377 // Clear any buffered-up text we have. It's enough to set the length to 0. |
|
1378 // The buffer itself is allocated when we're created and deleted in our |
|
1379 // destructor, so don't mess with it. |
|
1380 mTextLength = 0; |
|
1381 |
|
1382 if (mXSLTProcessor) { |
|
1383 // Get rid of the XSLT processor. |
|
1384 mXSLTProcessor->CancelLoads(); |
|
1385 mXSLTProcessor = nullptr; |
|
1386 } |
|
1387 |
|
1388 // release the nodes on stack |
|
1389 mContentStack.Clear(); |
|
1390 mNotifyLevel = 0; |
|
1391 |
|
1392 rv = HandleProcessingInstruction(MOZ_UTF16("xml-stylesheet"), |
|
1393 MOZ_UTF16("href=\"chrome://global/locale/intl.css\" type=\"text/css\"")); |
|
1394 NS_ENSURE_SUCCESS(rv, rv); |
|
1395 |
|
1396 const char16_t* noAtts[] = { 0, 0 }; |
|
1397 |
|
1398 NS_NAMED_LITERAL_STRING(errorNs, |
|
1399 "http://www.mozilla.org/newlayout/xml/parsererror.xml"); |
|
1400 |
|
1401 nsAutoString parsererror(errorNs); |
|
1402 parsererror.Append((char16_t)0xFFFF); |
|
1403 parsererror.AppendLiteral("parsererror"); |
|
1404 |
|
1405 rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, (uint32_t)-1, |
|
1406 false); |
|
1407 NS_ENSURE_SUCCESS(rv, rv); |
|
1408 |
|
1409 rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false); |
|
1410 NS_ENSURE_SUCCESS(rv, rv); |
|
1411 |
|
1412 nsAutoString sourcetext(errorNs); |
|
1413 sourcetext.Append((char16_t)0xFFFF); |
|
1414 sourcetext.AppendLiteral("sourcetext"); |
|
1415 |
|
1416 rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, (uint32_t)-1, |
|
1417 false); |
|
1418 NS_ENSURE_SUCCESS(rv, rv); |
|
1419 |
|
1420 rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText), false); |
|
1421 NS_ENSURE_SUCCESS(rv, rv); |
|
1422 |
|
1423 rv = HandleEndElement(sourcetext.get(), false); |
|
1424 NS_ENSURE_SUCCESS(rv, rv); |
|
1425 |
|
1426 rv = HandleEndElement(parsererror.get(), false); |
|
1427 NS_ENSURE_SUCCESS(rv, rv); |
|
1428 |
|
1429 FlushTags(); |
|
1430 |
|
1431 return NS_OK; |
|
1432 } |
|
1433 |
|
1434 nsresult |
|
1435 nsXMLContentSink::AddAttributes(const char16_t** aAtts, |
|
1436 nsIContent* aContent) |
|
1437 { |
|
1438 // Add tag attributes to the content attributes |
|
1439 nsCOMPtr<nsIAtom> prefix, localName; |
|
1440 while (*aAtts) { |
|
1441 int32_t nameSpaceID; |
|
1442 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), |
|
1443 getter_AddRefs(localName), &nameSpaceID); |
|
1444 |
|
1445 // Add attribute to content |
|
1446 aContent->SetAttr(nameSpaceID, localName, prefix, |
|
1447 nsDependentString(aAtts[1]), false); |
|
1448 aAtts += 2; |
|
1449 } |
|
1450 |
|
1451 return NS_OK; |
|
1452 } |
|
1453 |
|
1454 #define NS_ACCUMULATION_BUFFER_SIZE 4096 |
|
1455 |
|
1456 nsresult |
|
1457 nsXMLContentSink::AddText(const char16_t* aText, |
|
1458 int32_t aLength) |
|
1459 { |
|
1460 // Create buffer when we first need it |
|
1461 if (0 == mTextSize) { |
|
1462 mText = (char16_t *) PR_MALLOC(sizeof(char16_t) * NS_ACCUMULATION_BUFFER_SIZE); |
|
1463 if (nullptr == mText) { |
|
1464 return NS_ERROR_OUT_OF_MEMORY; |
|
1465 } |
|
1466 mTextSize = NS_ACCUMULATION_BUFFER_SIZE; |
|
1467 } |
|
1468 |
|
1469 // Copy data from string into our buffer; flush buffer when it fills up |
|
1470 int32_t offset = 0; |
|
1471 while (0 != aLength) { |
|
1472 int32_t amount = mTextSize - mTextLength; |
|
1473 if (0 == amount) { |
|
1474 // XSLT wants adjacent textnodes merged. |
|
1475 if (mConstrainSize && !mXSLTProcessor) { |
|
1476 nsresult rv = FlushText(); |
|
1477 if (NS_OK != rv) { |
|
1478 return rv; |
|
1479 } |
|
1480 |
|
1481 amount = mTextSize - mTextLength; |
|
1482 } |
|
1483 else { |
|
1484 mTextSize += aLength; |
|
1485 mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize); |
|
1486 if (nullptr == mText) { |
|
1487 mTextSize = 0; |
|
1488 |
|
1489 return NS_ERROR_OUT_OF_MEMORY; |
|
1490 } |
|
1491 |
|
1492 amount = aLength; |
|
1493 } |
|
1494 } |
|
1495 if (amount > aLength) { |
|
1496 amount = aLength; |
|
1497 } |
|
1498 memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount); |
|
1499 mTextLength += amount; |
|
1500 offset += amount; |
|
1501 aLength -= amount; |
|
1502 } |
|
1503 |
|
1504 return NS_OK; |
|
1505 } |
|
1506 |
|
1507 void |
|
1508 nsXMLContentSink::FlushPendingNotifications(mozFlushType aType) |
|
1509 { |
|
1510 // Only flush tags if we're not doing the notification ourselves |
|
1511 // (since we aren't reentrant) |
|
1512 if (!mInNotification) { |
|
1513 if (mIsDocumentObserver) { |
|
1514 // Only flush if we're still a document observer (so that our child |
|
1515 // counts should be correct). |
|
1516 if (aType >= Flush_ContentAndNotify) { |
|
1517 FlushTags(); |
|
1518 } |
|
1519 else { |
|
1520 FlushText(false); |
|
1521 } |
|
1522 } |
|
1523 if (aType >= Flush_InterruptibleLayout) { |
|
1524 // Make sure that layout has started so that the reflow flush |
|
1525 // will actually happen. |
|
1526 MaybeStartLayout(true); |
|
1527 } |
|
1528 } |
|
1529 } |
|
1530 |
|
1531 /** |
|
1532 * NOTE!! Forked from SinkContext. Please keep in sync. |
|
1533 * |
|
1534 * Flush all elements that have been seen so far such that |
|
1535 * they are visible in the tree. Specifically, make sure |
|
1536 * that they are all added to their respective parents. |
|
1537 * Also, do notification at the top for all content that |
|
1538 * has been newly added so that the frame tree is complete. |
|
1539 */ |
|
1540 nsresult |
|
1541 nsXMLContentSink::FlushTags() |
|
1542 { |
|
1543 mDeferredFlushTags = false; |
|
1544 bool oldBeganUpdate = mBeganUpdate; |
|
1545 uint32_t oldUpdates = mUpdatesInNotification; |
|
1546 |
|
1547 mUpdatesInNotification = 0; |
|
1548 ++mInNotification; |
|
1549 { |
|
1550 // Scope so we call EndUpdate before we decrease mInNotification |
|
1551 mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, true); |
|
1552 mBeganUpdate = true; |
|
1553 |
|
1554 // Don't release last text node in case we need to add to it again |
|
1555 FlushText(false); |
|
1556 |
|
1557 // Start from the base of the stack (growing downward) and do |
|
1558 // a notification from the node that is closest to the root of |
|
1559 // tree for any content that has been added. |
|
1560 |
|
1561 int32_t stackPos; |
|
1562 int32_t stackLen = mContentStack.Length(); |
|
1563 bool flushed = false; |
|
1564 uint32_t childCount; |
|
1565 nsIContent* content; |
|
1566 |
|
1567 for (stackPos = 0; stackPos < stackLen; ++stackPos) { |
|
1568 content = mContentStack[stackPos].mContent; |
|
1569 childCount = content->GetChildCount(); |
|
1570 |
|
1571 if (!flushed && (mContentStack[stackPos].mNumFlushed < childCount)) { |
|
1572 NotifyAppend(content, mContentStack[stackPos].mNumFlushed); |
|
1573 flushed = true; |
|
1574 } |
|
1575 |
|
1576 mContentStack[stackPos].mNumFlushed = childCount; |
|
1577 } |
|
1578 mNotifyLevel = stackLen - 1; |
|
1579 } |
|
1580 --mInNotification; |
|
1581 |
|
1582 if (mUpdatesInNotification > 1) { |
|
1583 UpdateChildCounts(); |
|
1584 } |
|
1585 |
|
1586 mUpdatesInNotification = oldUpdates; |
|
1587 mBeganUpdate = oldBeganUpdate; |
|
1588 |
|
1589 return NS_OK; |
|
1590 } |
|
1591 |
|
1592 /** |
|
1593 * NOTE!! Forked from SinkContext. Please keep in sync. |
|
1594 */ |
|
1595 void |
|
1596 nsXMLContentSink::UpdateChildCounts() |
|
1597 { |
|
1598 // Start from the top of the stack (growing upwards) and see if any |
|
1599 // new content has been appended. If so, we recognize that reflows |
|
1600 // have been generated for it and we should make sure that no |
|
1601 // further reflows occur. Note that we have to include stackPos == 0 |
|
1602 // to properly notify on kids of <html>. |
|
1603 int32_t stackLen = mContentStack.Length(); |
|
1604 int32_t stackPos = stackLen - 1; |
|
1605 while (stackPos >= 0) { |
|
1606 StackNode & node = mContentStack[stackPos]; |
|
1607 node.mNumFlushed = node.mContent->GetChildCount(); |
|
1608 |
|
1609 stackPos--; |
|
1610 } |
|
1611 mNotifyLevel = stackLen - 1; |
|
1612 } |
|
1613 |
|
1614 bool |
|
1615 nsXMLContentSink::IsMonolithicContainer(nsINodeInfo* aNodeInfo) |
|
1616 { |
|
1617 return ((aNodeInfo->NamespaceID() == kNameSpaceID_XHTML && |
|
1618 (aNodeInfo->NameAtom() == nsGkAtoms::tr || |
|
1619 aNodeInfo->NameAtom() == nsGkAtoms::select || |
|
1620 aNodeInfo->NameAtom() == nsGkAtoms::object || |
|
1621 aNodeInfo->NameAtom() == nsGkAtoms::applet)) || |
|
1622 (aNodeInfo->NamespaceID() == kNameSpaceID_MathML && |
|
1623 (aNodeInfo->NameAtom() == nsGkAtoms::math)) |
|
1624 ); |
|
1625 } |
|
1626 |
|
1627 void |
|
1628 nsXMLContentSink::ContinueInterruptedParsingIfEnabled() |
|
1629 { |
|
1630 if (mParser && mParser->IsParserEnabled()) { |
|
1631 GetParser()->ContinueInterruptedParsing(); |
|
1632 } |
|
1633 } |
|
1634 |
|
1635 void |
|
1636 nsXMLContentSink::ContinueInterruptedParsingAsync() |
|
1637 { |
|
1638 nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this, |
|
1639 &nsXMLContentSink::ContinueInterruptedParsingIfEnabled); |
|
1640 |
|
1641 NS_DispatchToCurrentThread(ev); |
|
1642 } |
|
1643 |
|
1644 nsIParser* |
|
1645 nsXMLContentSink::GetParser() |
|
1646 { |
|
1647 return static_cast<nsIParser*>(mParser.get()); |
|
1648 } |