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/. */
7 #include "nsHtml5TreeOperation.h"
8 #include "nsContentUtils.h"
9 #include "nsDocElementCreatedNotificationRunner.h"
10 #include "nsNodeUtils.h"
11 #include "nsAttrName.h"
12 #include "nsHtml5TreeBuilder.h"
13 #include "nsIDOMMutationEvent.h"
14 #include "mozAutoDocUpdate.h"
15 #include "nsBindingManager.h"
16 #include "nsXBLBinding.h"
17 #include "nsHtml5DocumentMode.h"
18 #include "nsHtml5HtmlAttributes.h"
19 #include "nsContentCreatorFunctions.h"
20 #include "nsIScriptElement.h"
22 #include "nsISupportsImpl.h"
23 #include "nsIDOMHTMLFormElement.h"
24 #include "nsIFormControl.h"
25 #include "nsIStyleSheetLinkingElement.h"
26 #include "nsIDOMDocumentType.h"
27 #include "nsIObserverService.h"
28 #include "mozilla/Services.h"
29 #include "nsIMutationObserver.h"
30 #include "nsIFormProcessor.h"
31 #include "nsIServiceManager.h"
33 #include "mozilla/dom/Comment.h"
34 #include "mozilla/dom/Element.h"
35 #include "mozilla/dom/HTMLImageElement.h"
36 #include "mozilla/dom/HTMLTemplateElement.h"
37 #include "nsHtml5SVGLoadDispatcher.h"
39 #include "nsIProtocolHandler.h"
40 #include "nsNetUtil.h"
41 #include "nsIHTMLDocument.h"
42 #include "mozilla/Likely.h"
43 #include "nsTextNode.h"
45 using namespace mozilla
;
47 static NS_DEFINE_CID(kFormProcessorCID
, NS_FORMPROCESSOR_CID
);
50 * Helper class that opens a notification batch if the current doc
51 * is different from the executor doc.
53 class MOZ_STACK_CLASS nsHtml5OtherDocUpdate
{
55 nsHtml5OtherDocUpdate(nsIDocument
* aCurrentDoc
, nsIDocument
* aExecutorDoc
)
57 NS_PRECONDITION(aCurrentDoc
, "Node has no doc?");
58 NS_PRECONDITION(aExecutorDoc
, "Executor has no doc?");
59 if (MOZ_LIKELY(aCurrentDoc
== aExecutorDoc
)) {
62 mDocument
= aCurrentDoc
;
63 aCurrentDoc
->BeginUpdate(UPDATE_CONTENT_MODEL
);
67 ~nsHtml5OtherDocUpdate()
69 if (MOZ_UNLIKELY(mDocument
)) {
70 mDocument
->EndUpdate(UPDATE_CONTENT_MODEL
);
74 nsCOMPtr
<nsIDocument
> mDocument
;
77 nsHtml5TreeOperation::nsHtml5TreeOperation()
78 : mOpCode(eTreeOpUninitialized
)
80 MOZ_COUNT_CTOR(nsHtml5TreeOperation
);
83 nsHtml5TreeOperation::~nsHtml5TreeOperation()
85 MOZ_COUNT_DTOR(nsHtml5TreeOperation
);
86 NS_ASSERTION(mOpCode
!= eTreeOpUninitialized
, "Uninitialized tree op.");
88 case eTreeOpAddAttributes
:
89 delete mTwo
.attributes
;
91 case eTreeOpCreateElementNetwork
:
92 case eTreeOpCreateElementNotNetwork
:
93 delete mThree
.attributes
;
95 case eTreeOpAppendDoctypeToDocument
:
96 delete mTwo
.stringPair
;
98 case eTreeOpFosterParentText
:
99 case eTreeOpAppendText
:
100 case eTreeOpAppendComment
:
101 case eTreeOpAppendCommentToDocument
:
102 case eTreeOpAddViewSourceHref
:
103 case eTreeOpAddViewSourceBase
:
104 delete[] mTwo
.unicharPtr
;
106 case eTreeOpSetDocumentCharset
:
107 case eTreeOpNeedsCharsetSwitchTo
:
108 delete[] mOne
.charPtr
;
110 case eTreeOpProcessOfflineManifest
:
111 free(mOne
.unicharPtr
);
113 default: // keep the compiler happy
119 nsHtml5TreeOperation::AppendTextToTextNode(const char16_t
* aBuffer
,
121 nsIContent
* aTextNode
,
122 nsHtml5DocumentBuilder
* aBuilder
)
124 NS_PRECONDITION(aTextNode
, "Got null text node.");
125 MOZ_ASSERT(aBuilder
);
126 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
127 uint32_t oldLength
= aTextNode
->TextLength();
128 CharacterDataChangeInfo info
= {
134 nsNodeUtils::CharacterDataWillChange(aTextNode
, &info
);
136 nsresult rv
= aTextNode
->AppendText(aBuffer
, aLength
, false);
137 NS_ENSURE_SUCCESS(rv
, rv
);
139 nsNodeUtils::CharacterDataChanged(aTextNode
, &info
);
145 nsHtml5TreeOperation::AppendText(const char16_t
* aBuffer
,
148 nsHtml5DocumentBuilder
* aBuilder
)
151 nsIContent
* lastChild
= aParent
->GetLastChild();
152 if (lastChild
&& lastChild
->IsNodeOfType(nsINode::eTEXT
)) {
153 nsHtml5OtherDocUpdate
update(aParent
->OwnerDoc(),
154 aBuilder
->GetDocument());
155 return AppendTextToTextNode(aBuffer
,
161 nsNodeInfoManager
* nodeInfoManager
= aParent
->OwnerDoc()->NodeInfoManager();
162 RefPtr
<nsTextNode
> text
= new nsTextNode(nodeInfoManager
);
163 NS_ASSERTION(text
, "Infallible malloc failed?");
164 rv
= text
->SetText(aBuffer
, aLength
, false);
165 NS_ENSURE_SUCCESS(rv
, rv
);
167 return Append(text
, aParent
, aBuilder
);
171 nsHtml5TreeOperation::Append(nsIContent
* aNode
,
173 nsHtml5DocumentBuilder
* aBuilder
)
175 MOZ_ASSERT(aBuilder
);
176 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
178 nsHtml5OtherDocUpdate
update(aParent
->OwnerDoc(),
179 aBuilder
->GetDocument());
180 uint32_t childCount
= aParent
->GetChildCount();
181 rv
= aParent
->AppendChildTo(aNode
, false);
182 if (NS_SUCCEEDED(rv
)) {
183 aNode
->SetParserHasNotified();
184 nsNodeUtils::ContentAppended(aParent
, aNode
, childCount
);
190 nsHtml5TreeOperation::AppendToDocument(nsIContent
* aNode
,
191 nsHtml5DocumentBuilder
* aBuilder
)
193 MOZ_ASSERT(aBuilder
);
194 MOZ_ASSERT(aBuilder
->GetDocument() == aNode
->OwnerDoc());
195 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
198 nsIDocument
* doc
= aBuilder
->GetDocument();
199 uint32_t childCount
= doc
->GetChildCount();
200 rv
= doc
->AppendChildTo(aNode
, false);
201 if (rv
== NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
) {
202 aNode
->SetParserHasNotified();
205 NS_ENSURE_SUCCESS(rv
, rv
);
206 aNode
->SetParserHasNotified();
207 nsNodeUtils::ContentInserted(doc
, aNode
, childCount
);
209 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
210 "Someone forgot to block scripts");
211 if (aNode
->IsElement()) {
212 nsContentUtils::AddScriptRunner(
213 new nsDocElementCreatedNotificationRunner(doc
));
219 IsElementOrTemplateContent(nsINode
* aNode
) {
221 if (aNode
->IsElement()) {
223 } else if (aNode
->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE
) {
224 // Check if the node is a template content.
225 mozilla::dom::DocumentFragment
* frag
=
226 static_cast<mozilla::dom::DocumentFragment
*>(aNode
);
227 nsIContent
* fragHost
= frag
->GetHost();
228 if (fragHost
&& nsNodeUtils::IsTemplateElement(fragHost
)) {
237 nsHtml5TreeOperation::Detach(nsIContent
* aNode
, nsHtml5DocumentBuilder
* aBuilder
)
239 MOZ_ASSERT(aBuilder
);
240 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
241 nsCOMPtr
<nsINode
> parent
= aNode
->GetParentNode();
243 nsHtml5OtherDocUpdate
update(parent
->OwnerDoc(),
244 aBuilder
->GetDocument());
245 int32_t pos
= parent
->IndexOf(aNode
);
246 NS_ASSERTION((pos
>= 0), "Element not found as child of its parent");
247 parent
->RemoveChildAt(pos
, true);
252 nsHtml5TreeOperation::AppendChildrenToNewParent(nsIContent
* aNode
,
254 nsHtml5DocumentBuilder
* aBuilder
)
256 MOZ_ASSERT(aBuilder
);
257 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
258 nsHtml5OtherDocUpdate
update(aParent
->OwnerDoc(),
259 aBuilder
->GetDocument());
261 uint32_t childCount
= aParent
->GetChildCount();
262 bool didAppend
= false;
263 while (aNode
->HasChildren()) {
264 nsCOMPtr
<nsIContent
> child
= aNode
->GetFirstChild();
265 aNode
->RemoveChildAt(0, true);
266 nsresult rv
= aParent
->AppendChildTo(child
, false);
267 NS_ENSURE_SUCCESS(rv
, rv
);
271 nsNodeUtils::ContentAppended(aParent
, aParent
->GetChildAt(childCount
),
278 nsHtml5TreeOperation::FosterParent(nsIContent
* aNode
,
281 nsHtml5DocumentBuilder
* aBuilder
)
283 MOZ_ASSERT(aBuilder
);
284 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
285 nsIContent
* foster
= aTable
->GetParent();
287 if (IsElementOrTemplateContent(foster
)) {
289 nsHtml5OtherDocUpdate
update(foster
->OwnerDoc(),
290 aBuilder
->GetDocument());
292 uint32_t pos
= foster
->IndexOf(aTable
);
293 nsresult rv
= foster
->InsertChildAt(aNode
, pos
, false);
294 NS_ENSURE_SUCCESS(rv
, rv
);
295 nsNodeUtils::ContentInserted(foster
, aNode
, pos
);
299 return Append(aNode
, aParent
, aBuilder
);
303 nsHtml5TreeOperation::AddAttributes(nsIContent
* aNode
,
304 nsHtml5HtmlAttributes
* aAttributes
,
305 nsHtml5DocumentBuilder
* aBuilder
)
307 dom::Element
* node
= aNode
->AsElement();
308 nsHtml5OtherDocUpdate
update(node
->OwnerDoc(),
309 aBuilder
->GetDocument());
311 int32_t len
= aAttributes
->getLength();
312 for (int32_t i
= len
; i
> 0;) {
314 // prefix doesn't need regetting. it is always null or a static atom
315 // local name is never null
316 nsCOMPtr
<nsIAtom
> localName
=
317 Reget(aAttributes
->getLocalNameNoBoundsCheck(i
));
318 int32_t nsuri
= aAttributes
->getURINoBoundsCheck(i
);
319 if (!node
->HasAttr(nsuri
, localName
)) {
320 // prefix doesn't need regetting. it is always null or a static atom
321 // local name is never null
324 aAttributes
->getPrefixNoBoundsCheck(i
),
325 *(aAttributes
->getValueNoBoundsCheck(i
)),
327 // XXX what to do with nsresult?
335 nsHtml5TreeOperation::CreateElement(int32_t aNs
,
337 nsHtml5HtmlAttributes
* aAttributes
,
338 mozilla::dom::FromParser aFromParser
,
339 nsNodeInfoManager
* aNodeInfoManager
,
340 nsHtml5DocumentBuilder
* aBuilder
)
342 bool isKeygen
= (aName
== nsHtml5Atoms::keygen
&& aNs
== kNameSpaceID_XHTML
);
343 if (MOZ_UNLIKELY(isKeygen
)) {
344 aName
= nsHtml5Atoms::select
;
347 nsCOMPtr
<dom::Element
> newElement
;
348 RefPtr
<dom::NodeInfo
> nodeInfo
= aNodeInfoManager
->
349 GetNodeInfo(aName
, nullptr, aNs
, nsIDOMNode::ELEMENT_NODE
);
350 NS_ASSERTION(nodeInfo
, "Got null nodeinfo.");
351 NS_NewElement(getter_AddRefs(newElement
),
354 NS_ASSERTION(newElement
, "Element creation created null pointer.");
356 dom::Element
* newContent
= newElement
;
357 aBuilder
->HoldElement(newElement
.forget());
359 if (MOZ_UNLIKELY(aName
== nsHtml5Atoms::style
|| aName
== nsHtml5Atoms::link
)) {
360 nsCOMPtr
<nsIStyleSheetLinkingElement
> ssle(do_QueryInterface(newContent
));
362 ssle
->InitStyleLinkElement(false);
363 ssle
->SetEnableUpdates(false);
365 } else if (MOZ_UNLIKELY(isKeygen
)) {
366 // Adapted from CNavDTD
368 nsCOMPtr
<nsIFormProcessor
> theFormProcessor
=
369 do_GetService(kFormProcessorCID
, &rv
);
374 nsTArray
<nsString
> theContent
;
375 nsAutoString theAttribute
;
377 (void) theFormProcessor
->ProvideContent(NS_LITERAL_STRING("select"),
381 newContent
->SetAttr(kNameSpaceID_None
,
387 RefPtr
<dom::NodeInfo
> optionNodeInfo
=
388 aNodeInfoManager
->GetNodeInfo(nsHtml5Atoms::option
,
391 nsIDOMNode::ELEMENT_NODE
);
393 for (uint32_t i
= 0; i
< theContent
.Length(); ++i
) {
394 nsCOMPtr
<dom::Element
> optionElt
;
395 RefPtr
<dom::NodeInfo
> ni
= optionNodeInfo
;
396 NS_NewElement(getter_AddRefs(optionElt
),
399 RefPtr
<nsTextNode
> optionText
= new nsTextNode(aNodeInfoManager
);
400 (void) optionText
->SetText(theContent
[i
], false);
401 optionElt
->AppendChildTo(optionText
, false);
402 newContent
->AppendChildTo(optionElt
, false);
403 // XXXsmaug Shouldn't we call this after adding all the child nodes.
404 newContent
->DoneAddingChildren(false);
412 int32_t len
= aAttributes
->getLength();
413 for (int32_t i
= len
; i
> 0;) {
415 // prefix doesn't need regetting. it is always null or a static atom
416 // local name is never null
417 nsCOMPtr
<nsIAtom
> localName
=
418 Reget(aAttributes
->getLocalNameNoBoundsCheck(i
));
419 nsCOMPtr
<nsIAtom
> prefix
= aAttributes
->getPrefixNoBoundsCheck(i
);
420 int32_t nsuri
= aAttributes
->getURINoBoundsCheck(i
);
422 if (aNs
== kNameSpaceID_XHTML
&&
423 nsHtml5Atoms::a
== aName
&&
424 nsHtml5Atoms::name
== localName
) {
425 // This is an HTML5-incompliant Geckoism.
426 // Remove when fixing bug 582361
427 NS_ConvertUTF16toUTF8
cname(*(aAttributes
->getValueNoBoundsCheck(i
)));
428 NS_ConvertUTF8toUTF16
uv(nsUnescape(cname
.BeginWriting()));
429 newContent
->SetAttr(nsuri
,
435 nsString
& value
= *(aAttributes
->getValueNoBoundsCheck(i
));
436 newContent
->SetAttr(nsuri
,
442 // Custom element setup may be needed if there is an "is" attribute.
443 if (kNameSpaceID_None
== nsuri
&& !prefix
&& nsGkAtoms::is
== localName
) {
444 newContent
->OwnerDoc()->SetupCustomElement(newContent
,
445 newContent
->GetNameSpaceID(),
454 nsHtml5TreeOperation::SetFormElement(nsIContent
* aNode
, nsIContent
* aParent
)
456 nsCOMPtr
<nsIFormControl
> formControl(do_QueryInterface(aNode
));
457 nsCOMPtr
<nsIDOMHTMLImageElement
> domImageElement
= do_QueryInterface(aNode
);
458 // NS_ASSERTION(formControl, "Form-associated element did not implement nsIFormControl.");
459 // TODO: uncomment the above line when <keygen> (bug 101019) is supported by Gecko
460 nsCOMPtr
<nsIDOMHTMLFormElement
> formElement(do_QueryInterface(aParent
));
461 NS_ASSERTION(formElement
, "The form element doesn't implement nsIDOMHTMLFormElement.");
462 // avoid crashing on <keygen>
464 !aNode
->HasAttr(kNameSpaceID_None
, nsGkAtoms::form
)) {
465 formControl
->SetForm(formElement
);
466 } else if (domImageElement
) {
467 RefPtr
<dom::HTMLImageElement
> imageElement
=
468 static_cast<dom::HTMLImageElement
*>(domImageElement
.get());
469 MOZ_ASSERT(imageElement
);
470 imageElement
->SetForm(formElement
);
475 nsHtml5TreeOperation::AppendIsindexPrompt(nsIContent
* parent
, nsHtml5DocumentBuilder
* aBuilder
)
477 nsXPIDLString prompt
;
479 nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES
,
480 "IsIndexPromptWithSpace", prompt
);
481 uint32_t len
= prompt
.Length();
486 // Don't bother appending a zero-length text node.
489 return AppendText(prompt
.BeginReading(), len
, parent
, aBuilder
);
493 nsHtml5TreeOperation::FosterParentText(nsIContent
* aStackParent
,
497 nsHtml5DocumentBuilder
* aBuilder
)
499 MOZ_ASSERT(aBuilder
);
500 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
502 nsIContent
* foster
= aTable
->GetParent();
504 if (IsElementOrTemplateContent(foster
)) {
505 nsHtml5OtherDocUpdate
update(foster
->OwnerDoc(),
506 aBuilder
->GetDocument());
508 uint32_t pos
= foster
->IndexOf(aTable
);
510 nsIContent
* previousSibling
= aTable
->GetPreviousSibling();
511 if (previousSibling
&& previousSibling
->IsNodeOfType(nsINode::eTEXT
)) {
512 return AppendTextToTextNode(aBuffer
,
518 nsNodeInfoManager
* nodeInfoManager
= aStackParent
->OwnerDoc()->NodeInfoManager();
519 RefPtr
<nsTextNode
> text
= new nsTextNode(nodeInfoManager
);
520 NS_ASSERTION(text
, "Infallible malloc failed?");
521 rv
= text
->SetText(aBuffer
, aLength
, false);
522 NS_ENSURE_SUCCESS(rv
, rv
);
524 rv
= foster
->InsertChildAt(text
, pos
, false);
525 NS_ENSURE_SUCCESS(rv
, rv
);
526 nsNodeUtils::ContentInserted(foster
, text
, pos
);
530 return AppendText(aBuffer
, aLength
, aStackParent
, aBuilder
);
534 nsHtml5TreeOperation::AppendComment(nsIContent
* aParent
,
537 nsHtml5DocumentBuilder
* aBuilder
)
539 nsNodeInfoManager
* nodeInfoManager
= aParent
->OwnerDoc()->NodeInfoManager();
540 RefPtr
<dom::Comment
> comment
= new dom::Comment(nodeInfoManager
);
541 NS_ASSERTION(comment
, "Infallible malloc failed?");
542 nsresult rv
= comment
->SetText(aBuffer
, aLength
, false);
543 NS_ENSURE_SUCCESS(rv
, rv
);
545 return Append(comment
, aParent
, aBuilder
);
549 nsHtml5TreeOperation::AppendCommentToDocument(char16_t
* aBuffer
,
551 nsHtml5DocumentBuilder
* aBuilder
)
553 RefPtr
<dom::Comment
> comment
=
554 new dom::Comment(aBuilder
->GetNodeInfoManager());
555 NS_ASSERTION(comment
, "Infallible malloc failed?");
556 nsresult rv
= comment
->SetText(aBuffer
, aLength
, false);
557 NS_ENSURE_SUCCESS(rv
, rv
);
559 return AppendToDocument(comment
, aBuilder
);
563 nsHtml5TreeOperation::AppendDoctypeToDocument(nsIAtom
* aName
,
564 const nsAString
& aPublicId
,
565 const nsAString
& aSystemId
,
566 nsHtml5DocumentBuilder
* aBuilder
)
568 // Adapted from nsXMLContentSink
569 // Create a new doctype node
570 nsCOMPtr
<nsIDOMDocumentType
> docType
;
571 nsAutoString voidString
;
572 voidString
.SetIsVoid(true);
573 NS_NewDOMDocumentType(getter_AddRefs(docType
),
574 aBuilder
->GetNodeInfoManager(),
579 NS_ASSERTION(docType
, "Doctype creation failed.");
580 nsCOMPtr
<nsIContent
> asContent
= do_QueryInterface(docType
);
581 return AppendToDocument(asContent
, aBuilder
);
585 nsHtml5TreeOperation::GetDocumentFragmentForTemplate(nsIContent
* aNode
)
587 dom::HTMLTemplateElement
* tempElem
=
588 static_cast<dom::HTMLTemplateElement
*>(aNode
);
589 RefPtr
<dom::DocumentFragment
> frag
= tempElem
->Content();
594 nsHtml5TreeOperation::GetFosterParent(nsIContent
* aTable
, nsIContent
* aStackParent
)
596 nsIContent
* tableParent
= aTable
->GetParent();
597 return IsElementOrTemplateContent(tableParent
) ? tableParent
: aStackParent
;
601 nsHtml5TreeOperation::PreventScriptExecution(nsIContent
* aNode
)
603 nsCOMPtr
<nsIScriptElement
> sele
= do_QueryInterface(aNode
);
605 sele
->PreventExecution();
609 nsHtml5TreeOperation::DoneAddingChildren(nsIContent
* aNode
)
611 aNode
->DoneAddingChildren(aNode
->HasParserNotified());
615 nsHtml5TreeOperation::DoneCreatingElement(nsIContent
* aNode
)
617 aNode
->DoneCreatingElement();
621 nsHtml5TreeOperation::SvgLoad(nsIContent
* aNode
)
623 nsCOMPtr
<nsIRunnable
> event
= new nsHtml5SVGLoadDispatcher(aNode
);
624 if (NS_FAILED(NS_DispatchToMainThread(event
))) {
625 NS_WARNING("failed to dispatch svg load dispatcher");
630 nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent
* aNode
)
632 nsCOMPtr
<nsIScriptElement
> sele
= do_QueryInterface(aNode
);
634 // Make sure to serialize this script correctly, for nice round tripping.
635 sele
->SetIsMalformed();
640 nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor
* aBuilder
,
641 nsIContent
** aScriptElement
)
644 case eTreeOpAppend
: {
645 nsIContent
* node
= *(mOne
.node
);
646 nsIContent
* parent
= *(mTwo
.node
);
647 return Append(node
, parent
, aBuilder
);
649 case eTreeOpDetach
: {
650 nsIContent
* node
= *(mOne
.node
);
651 Detach(node
, aBuilder
);
654 case eTreeOpAppendChildrenToNewParent
: {
655 nsCOMPtr
<nsIContent
> node
= *(mOne
.node
);
656 nsIContent
* parent
= *(mTwo
.node
);
657 return AppendChildrenToNewParent(node
, parent
, aBuilder
);
659 case eTreeOpFosterParent
: {
660 nsIContent
* node
= *(mOne
.node
);
661 nsIContent
* parent
= *(mTwo
.node
);
662 nsIContent
* table
= *(mThree
.node
);
663 return FosterParent(node
, parent
, table
, aBuilder
);
665 case eTreeOpAppendToDocument
: {
666 nsIContent
* node
= *(mOne
.node
);
667 return AppendToDocument(node
, aBuilder
);
669 case eTreeOpAddAttributes
: {
670 nsIContent
* node
= *(mOne
.node
);
671 nsHtml5HtmlAttributes
* attributes
= mTwo
.attributes
;
672 return AddAttributes(node
, attributes
, aBuilder
);
674 case eTreeOpCreateElementNetwork
:
675 case eTreeOpCreateElementNotNetwork
: {
676 nsIContent
** target
= mOne
.node
;
677 int32_t ns
= mFour
.integer
;
678 nsCOMPtr
<nsIAtom
> name
= Reget(mTwo
.atom
);
679 nsHtml5HtmlAttributes
* attributes
= mThree
.attributes
;
680 nsIContent
* intendedParent
= mFive
.node
? *(mFive
.node
) : nullptr;
682 // intendedParent == nullptr is a special case where the
683 // intended parent is the document.
684 nsNodeInfoManager
* nodeInfoManager
= intendedParent
?
685 intendedParent
->OwnerDoc()->NodeInfoManager() :
686 aBuilder
->GetNodeInfoManager();
688 *target
= CreateElement(ns
,
691 mOpCode
== eTreeOpCreateElementNetwork
?
692 dom::FROM_PARSER_NETWORK
:
693 dom::FROM_PARSER_DOCUMENT_WRITE
,
698 case eTreeOpSetFormElement
: {
699 nsIContent
* node
= *(mOne
.node
);
700 nsIContent
* parent
= *(mTwo
.node
);
701 SetFormElement(node
, parent
);
704 case eTreeOpAppendText
: {
705 nsIContent
* parent
= *mOne
.node
;
706 char16_t
* buffer
= mTwo
.unicharPtr
;
707 uint32_t length
= mFour
.integer
;
708 return AppendText(buffer
, length
, parent
, aBuilder
);
710 case eTreeOpAppendIsindexPrompt
: {
711 nsIContent
* parent
= *mOne
.node
;
712 return AppendIsindexPrompt(parent
, aBuilder
);
714 case eTreeOpFosterParentText
: {
715 nsIContent
* stackParent
= *mOne
.node
;
716 char16_t
* buffer
= mTwo
.unicharPtr
;
717 uint32_t length
= mFour
.integer
;
718 nsIContent
* table
= *mThree
.node
;
719 return FosterParentText(stackParent
, buffer
, length
, table
, aBuilder
);
721 case eTreeOpAppendComment
: {
722 nsIContent
* parent
= *mOne
.node
;
723 char16_t
* buffer
= mTwo
.unicharPtr
;
724 int32_t length
= mFour
.integer
;
725 return AppendComment(parent
, buffer
, length
, aBuilder
);
727 case eTreeOpAppendCommentToDocument
: {
728 char16_t
* buffer
= mTwo
.unicharPtr
;
729 int32_t length
= mFour
.integer
;
730 return AppendCommentToDocument(buffer
, length
, aBuilder
);
732 case eTreeOpAppendDoctypeToDocument
: {
733 nsCOMPtr
<nsIAtom
> name
= Reget(mOne
.atom
);
734 nsHtml5TreeOperationStringPair
* pair
= mTwo
.stringPair
;
737 pair
->Get(publicId
, systemId
);
738 return AppendDoctypeToDocument(name
, publicId
, systemId
, aBuilder
);
740 case eTreeOpGetDocumentFragmentForTemplate
: {
741 nsIContent
* node
= *(mOne
.node
);
742 *mTwo
.node
= GetDocumentFragmentForTemplate(node
);
745 case eTreeOpGetFosterParent
: {
746 nsIContent
* table
= *(mOne
.node
);
747 nsIContent
* stackParent
= *(mTwo
.node
);
748 nsIContent
* fosterParent
= GetFosterParent(table
, stackParent
);
749 *mThree
.node
= fosterParent
;
752 case eTreeOpMarkAsBroken
: {
755 case eTreeOpRunScript
: {
756 nsIContent
* node
= *(mOne
.node
);
757 nsAHtml5TreeBuilderState
* snapshot
= mTwo
.state
;
759 aBuilder
->InitializeDocWriteParserState(snapshot
, mFour
.integer
);
761 *aScriptElement
= node
;
764 case eTreeOpRunScriptAsyncDefer
: {
765 nsIContent
* node
= *(mOne
.node
);
766 aBuilder
->RunScript(node
);
769 case eTreeOpPreventScriptExecution
: {
770 nsIContent
* node
= *(mOne
.node
);
771 PreventScriptExecution(node
);
774 case eTreeOpDoneAddingChildren
: {
775 nsIContent
* node
= *(mOne
.node
);
776 node
->DoneAddingChildren(node
->HasParserNotified());
779 case eTreeOpDoneCreatingElement
: {
780 nsIContent
* node
= *(mOne
.node
);
781 DoneCreatingElement(node
);
784 case eTreeOpSetDocumentCharset
: {
785 char* str
= mOne
.charPtr
;
786 int32_t charsetSource
= mFour
.integer
;
787 nsDependentCString
dependentString(str
);
788 aBuilder
->SetDocumentCharsetAndSource(dependentString
, charsetSource
);
791 case eTreeOpNeedsCharsetSwitchTo
: {
792 char* str
= mOne
.charPtr
;
793 int32_t charsetSource
= mFour
.integer
;
794 int32_t lineNumber
= mTwo
.integer
;
795 aBuilder
->NeedsCharsetSwitchTo(str
, charsetSource
, (uint32_t)lineNumber
);
798 case eTreeOpUpdateStyleSheet
: {
799 nsIContent
* node
= *(mOne
.node
);
800 aBuilder
->UpdateStyleSheet(node
);
803 case eTreeOpProcessMeta
: {
804 nsIContent
* node
= *(mOne
.node
);
805 return aBuilder
->ProcessMETATag(node
);
807 case eTreeOpProcessOfflineManifest
: {
808 char16_t
* str
= mOne
.unicharPtr
;
809 nsDependentString
dependentString(str
);
810 aBuilder
->ProcessOfflineManifest(dependentString
);
813 case eTreeOpMarkMalformedIfScript
: {
814 nsIContent
* node
= *(mOne
.node
);
815 MarkMalformedIfScript(node
);
818 case eTreeOpStreamEnded
: {
819 aBuilder
->DidBuildModel(false); // this causes a notifications flush anyway
822 case eTreeOpStartLayout
: {
823 aBuilder
->StartLayout(); // this causes a notification flush anyway
826 case eTreeOpDocumentMode
: {
827 aBuilder
->SetDocumentMode(mOne
.mode
);
830 case eTreeOpSetStyleLineNumber
: {
831 nsIContent
* node
= *(mOne
.node
);
832 nsCOMPtr
<nsIStyleSheetLinkingElement
> ssle
= do_QueryInterface(node
);
833 NS_ASSERTION(ssle
, "Node didn't QI to style.");
834 ssle
->SetLineNumber(mFour
.integer
);
837 case eTreeOpSetScriptLineNumberAndFreeze
: {
838 nsIContent
* node
= *(mOne
.node
);
839 nsCOMPtr
<nsIScriptElement
> sele
= do_QueryInterface(node
);
840 NS_ASSERTION(sele
, "Node didn't QI to script.");
841 sele
->SetScriptLineNumber(mFour
.integer
);
842 sele
->FreezeUriAsyncDefer();
845 case eTreeOpSvgLoad
: {
846 nsIContent
* node
= *(mOne
.node
);
850 case eTreeOpMaybeComplainAboutCharset
: {
851 char* msgId
= mOne
.charPtr
;
852 bool error
= mTwo
.integer
;
853 int32_t lineNumber
= mThree
.integer
;
854 aBuilder
->MaybeComplainAboutCharset(msgId
, error
, (uint32_t)lineNumber
);
857 case eTreeOpAddClass
: {
858 nsIContent
* node
= *(mOne
.node
);
859 char16_t
* str
= mTwo
.unicharPtr
;
860 nsDependentString
depStr(str
);
861 // See viewsource.css for the possible classes
863 node
->GetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, klass
);
864 if (!klass
.IsEmpty()) {
866 klass
.Append(depStr
);
867 node
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, klass
, true);
869 node
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, depStr
, true);
873 case eTreeOpAddLineNumberId
: {
874 nsIContent
* node
= *(mOne
.node
);
875 int32_t lineNumber
= mFour
.integer
;
876 nsAutoString
val(NS_LITERAL_STRING("line"));
877 val
.AppendInt(lineNumber
);
878 node
->SetAttr(kNameSpaceID_None
, nsGkAtoms::id
, val
, true);
881 case eTreeOpAddViewSourceHref
: {
882 nsIContent
* node
= *mOne
.node
;
883 char16_t
* buffer
= mTwo
.unicharPtr
;
884 int32_t length
= mFour
.integer
;
886 nsDependentString
relative(buffer
, length
);
888 nsIDocument
* doc
= aBuilder
->GetDocument();
890 const nsCString
& charset
= doc
->GetDocumentCharacterSet();
891 nsCOMPtr
<nsIURI
> uri
;
892 nsresult rv
= NS_NewURI(getter_AddRefs(uri
),
895 aBuilder
->GetViewSourceBaseURI());
896 NS_ENSURE_SUCCESS(rv
, NS_OK
);
898 // Reuse the fix for bug 467852
899 // URLs that execute script (e.g. "javascript:" URLs) should just be
900 // ignored. There's nothing reasonable we can do with them, and allowing
901 // them to execute in the context of the view-source window presents a
902 // security risk. Just return the empty string in this case.
903 bool openingExecutesScript
= false;
904 rv
= NS_URIChainHasFlags(uri
,
905 nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT
,
906 &openingExecutesScript
);
907 if (NS_FAILED(rv
) || openingExecutesScript
) {
911 nsAutoCString viewSourceUrl
;
913 // URLs that return data (e.g. "http:" URLs) should be prefixed with
914 // "view-source:". URLs that don't return data should just be returned
916 bool doesNotReturnData
= false;
917 rv
= NS_URIChainHasFlags(uri
,
918 nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA
,
920 NS_ENSURE_SUCCESS(rv
, NS_OK
);
921 if (!doesNotReturnData
) {
922 viewSourceUrl
.AssignLiteral("view-source:");
928 viewSourceUrl
.Append(spec
);
931 CopyUTF8toUTF16(viewSourceUrl
, utf16
);
933 node
->SetAttr(kNameSpaceID_None
, nsGkAtoms::href
, utf16
, true);
936 case eTreeOpAddError
: {
937 nsIContent
* node
= *(mOne
.node
);
938 char* msgId
= mTwo
.charPtr
;
939 nsCOMPtr
<nsIAtom
> atom
= Reget(mThree
.atom
);
940 nsCOMPtr
<nsIAtom
> otherAtom
= Reget(mFour
.atom
);
941 // See viewsource.css for the possible classes in addition to "error".
943 node
->GetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, klass
);
944 if (!klass
.IsEmpty()) {
945 klass
.AppendLiteral(" error");
946 node
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, klass
, true);
948 node
->SetAttr(kNameSpaceID_None
,
950 NS_LITERAL_STRING("error"),
955 nsXPIDLString message
;
957 const char16_t
* params
[] = { atom
->GetUTF16String(),
958 otherAtom
->GetUTF16String() };
959 rv
= nsContentUtils::FormatLocalizedString(
960 nsContentUtils::eHTMLPARSER_PROPERTIES
, msgId
, params
, message
);
961 NS_ENSURE_SUCCESS(rv
, NS_OK
);
963 const char16_t
* params
[] = { atom
->GetUTF16String() };
964 rv
= nsContentUtils::FormatLocalizedString(
965 nsContentUtils::eHTMLPARSER_PROPERTIES
, msgId
, params
, message
);
966 NS_ENSURE_SUCCESS(rv
, NS_OK
);
968 rv
= nsContentUtils::GetLocalizedString(
969 nsContentUtils::eHTMLPARSER_PROPERTIES
, msgId
, message
);
970 NS_ENSURE_SUCCESS(rv
, NS_OK
);
974 node
->GetAttr(kNameSpaceID_None
, nsGkAtoms::title
, title
);
975 if (!title
.IsEmpty()) {
977 title
.Append(message
);
978 node
->SetAttr(kNameSpaceID_None
, nsGkAtoms::title
, title
, true);
980 node
->SetAttr(kNameSpaceID_None
, nsGkAtoms::title
, message
, true);
984 case eTreeOpAddViewSourceBase
: {
985 char16_t
* buffer
= mTwo
.unicharPtr
;
986 int32_t length
= mFour
.integer
;
987 nsDependentString
baseUrl(buffer
, length
);
988 aBuilder
->AddBase(baseUrl
);
992 MOZ_CRASH("Bogus tree op");
995 return NS_OK
; // keep compiler happy