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 "mozAutoDocUpdate.h"
9 #include "mozilla/CycleCollectedJSContext.h"
10 #include "mozilla/Likely.h"
11 #include "mozilla/dom/Comment.h"
12 #include "mozilla/dom/CustomElementRegistry.h"
13 #include "mozilla/dom/DocumentType.h"
14 #include "mozilla/dom/Element.h"
15 #include "mozilla/dom/LinkStyle.h"
16 #include "mozilla/dom/HTMLFormElement.h"
17 #include "mozilla/dom/HTMLImageElement.h"
18 #include "mozilla/dom/HTMLTemplateElement.h"
19 #include "mozilla/dom/MutationObservers.h"
20 #include "mozilla/dom/Text.h"
21 #include "nsAttrName.h"
22 #include "nsContentCreatorFunctions.h"
23 #include "nsContentUtils.h"
24 #include "nsDocElementCreatedNotificationRunner.h"
26 #include "nsHtml5AutoPauseUpdate.h"
27 #include "nsHtml5DocumentMode.h"
28 #include "nsHtml5HtmlAttributes.h"
29 #include "nsHtml5SVGLoadDispatcher.h"
30 #include "nsHtml5TreeBuilder.h"
32 #include "nsIFormControl.h"
33 #include "nsIMutationObserver.h"
35 #include "nsIProtocolHandler.h"
36 #include "nsIScriptElement.h"
37 #include "nsISupportsImpl.h"
39 #include "nsNetUtil.h"
40 #include "nsTextNode.h"
42 using namespace mozilla
;
43 using namespace mozilla::dom
;
44 using mozilla::dom::Document
;
47 * Helper class that opens a notification batch if the current doc
48 * is different from the executor doc.
50 class MOZ_STACK_CLASS nsHtml5OtherDocUpdate
{
52 nsHtml5OtherDocUpdate(Document
* aCurrentDoc
, Document
* aExecutorDoc
) {
53 MOZ_ASSERT(aCurrentDoc
, "Node has no doc?");
54 MOZ_ASSERT(aExecutorDoc
, "Executor has no doc?");
55 if (MOZ_LIKELY(aCurrentDoc
== aExecutorDoc
)) {
58 mDocument
= aCurrentDoc
;
59 aCurrentDoc
->BeginUpdate();
63 ~nsHtml5OtherDocUpdate() {
64 if (MOZ_UNLIKELY(mDocument
)) {
65 mDocument
->EndUpdate();
70 RefPtr
<Document
> mDocument
;
73 nsHtml5TreeOperation::nsHtml5TreeOperation() : mOperation(uninitialized()) {
74 MOZ_COUNT_CTOR(nsHtml5TreeOperation
);
77 nsHtml5TreeOperation::~nsHtml5TreeOperation() {
78 MOZ_COUNT_DTOR(nsHtml5TreeOperation
);
80 struct TreeOperationMatcher
{
81 void operator()(const opAppend
& aOperation
) {}
83 void operator()(const opDetach
& aOperation
) {}
85 void operator()(const opAppendChildrenToNewParent
& aOperation
) {}
87 void operator()(const opFosterParent
& aOperation
) {}
89 void operator()(const opAppendToDocument
& aOperation
) {}
91 void operator()(const opAddAttributes
& aOperation
) {
92 delete aOperation
.mAttributes
;
95 void operator()(const nsHtml5DocumentMode
& aMode
) {}
97 void operator()(const opCreateHTMLElement
& aOperation
) {
98 aOperation
.mName
->Release();
99 delete aOperation
.mAttributes
;
102 void operator()(const opCreateSVGElement
& aOperation
) {
103 aOperation
.mName
->Release();
104 delete aOperation
.mAttributes
;
107 void operator()(const opCreateMathMLElement
& aOperation
) {
108 aOperation
.mName
->Release();
109 delete aOperation
.mAttributes
;
112 void operator()(const opSetFormElement
& aOperation
) {}
114 void operator()(const opAppendText
& aOperation
) {
115 delete[] aOperation
.mBuffer
;
118 void operator()(const opFosterParentText
& aOperation
) {
119 delete[] aOperation
.mBuffer
;
122 void operator()(const opAppendComment
& aOperation
) {
123 delete[] aOperation
.mBuffer
;
126 void operator()(const opAppendCommentToDocument
& aOperation
) {
127 delete[] aOperation
.mBuffer
;
130 void operator()(const opAppendDoctypeToDocument
& aOperation
) {
131 aOperation
.mName
->Release();
132 delete aOperation
.mStringPair
;
135 void operator()(const opGetDocumentFragmentForTemplate
& aOperation
) {}
137 void operator()(const opGetFosterParent
& aOperation
) {}
139 void operator()(const opMarkAsBroken
& aOperation
) {}
141 void operator()(const opRunScript
& aOperation
) {}
143 void operator()(const opRunScriptAsyncDefer
& aOperation
) {}
145 void operator()(const opPreventScriptExecution
& aOperation
) {}
147 void operator()(const opDoneAddingChildren
& aOperation
) {}
149 void operator()(const opDoneCreatingElement
& aOperation
) {}
151 void operator()(const opSetDocumentCharset
& aOperation
) {}
153 void operator()(const opCharsetSwitchTo
& aOperation
) {}
155 void operator()(const opUpdateStyleSheet
& aOperation
) {}
157 void operator()(const opProcessOfflineManifest
& aOperation
) {
158 free(aOperation
.mUrl
);
161 void operator()(const opMarkMalformedIfScript
& aOperation
) {}
163 void operator()(const opStreamEnded
& aOperation
) {}
165 void operator()(const opSetStyleLineNumber
& aOperation
) {}
167 void operator()(const opSetScriptLineNumberAndFreeze
& aOperation
) {}
169 void operator()(const opSvgLoad
& aOperation
) {}
171 void operator()(const opMaybeComplainAboutCharset
& aOperation
) {}
173 void operator()(const opMaybeComplainAboutDeepTree
& aOperation
) {}
175 void operator()(const opAddClass
& aOperation
) {}
177 void operator()(const opAddViewSourceHref
& aOperation
) {
178 delete[] aOperation
.mBuffer
;
181 void operator()(const opAddViewSourceBase
& aOperation
) {
182 delete[] aOperation
.mBuffer
;
185 void operator()(const opAddErrorType
& aOperation
) {
186 if (aOperation
.mName
) {
187 aOperation
.mName
->Release();
189 if (aOperation
.mOther
) {
190 aOperation
.mOther
->Release();
194 void operator()(const opAddLineNumberId
& aOperation
) {}
196 void operator()(const opStartLayout
& aOperation
) {}
198 void operator()(const opEnableEncodingMenu
& aOperation
) {}
200 void operator()(const uninitialized
& aOperation
) {
201 NS_WARNING("Uninitialized tree op.");
205 mOperation
.match(TreeOperationMatcher());
208 nsresult
nsHtml5TreeOperation::AppendTextToTextNode(
209 const char16_t
* aBuffer
, uint32_t aLength
, dom::Text
* aTextNode
,
210 nsHtml5DocumentBuilder
* aBuilder
) {
211 MOZ_ASSERT(aTextNode
, "Got null text node.");
212 MOZ_ASSERT(aBuilder
);
213 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
214 uint32_t oldLength
= aTextNode
->TextLength();
215 CharacterDataChangeInfo info
= {true, oldLength
, oldLength
, aLength
};
216 MutationObservers::NotifyCharacterDataWillChange(aTextNode
, info
);
218 nsresult rv
= aTextNode
->AppendText(aBuffer
, aLength
, false);
219 NS_ENSURE_SUCCESS(rv
, rv
);
221 MutationObservers::NotifyCharacterDataChanged(aTextNode
, info
);
225 nsresult
nsHtml5TreeOperation::AppendText(const char16_t
* aBuffer
,
226 uint32_t aLength
, nsIContent
* aParent
,
227 nsHtml5DocumentBuilder
* aBuilder
) {
229 nsIContent
* lastChild
= aParent
->GetLastChild();
230 if (lastChild
&& lastChild
->IsText()) {
231 nsHtml5OtherDocUpdate
update(aParent
->OwnerDoc(), aBuilder
->GetDocument());
232 return AppendTextToTextNode(aBuffer
, aLength
, lastChild
->GetAsText(),
236 nsNodeInfoManager
* nodeInfoManager
= aParent
->OwnerDoc()->NodeInfoManager();
237 RefPtr
<nsTextNode
> text
= new (nodeInfoManager
) nsTextNode(nodeInfoManager
);
238 NS_ASSERTION(text
, "Infallible malloc failed?");
239 rv
= text
->SetText(aBuffer
, aLength
, false);
240 NS_ENSURE_SUCCESS(rv
, rv
);
242 return Append(text
, aParent
, aBuilder
);
245 nsresult
nsHtml5TreeOperation::Append(nsIContent
* aNode
, nsIContent
* aParent
,
246 nsHtml5DocumentBuilder
* aBuilder
) {
247 MOZ_ASSERT(aBuilder
);
248 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
250 nsHtml5OtherDocUpdate
update(aParent
->OwnerDoc(), aBuilder
->GetDocument());
251 rv
= aParent
->AppendChildTo(aNode
, false);
252 if (NS_SUCCEEDED(rv
)) {
253 aNode
->SetParserHasNotified();
254 MutationObservers::NotifyContentAppended(aParent
, aNode
);
259 nsresult
nsHtml5TreeOperation::Append(nsIContent
* aNode
, nsIContent
* aParent
,
260 mozilla::dom::FromParser aFromParser
,
261 nsHtml5DocumentBuilder
* aBuilder
) {
262 Maybe
<nsHtml5AutoPauseUpdate
> autoPause
;
263 Maybe
<dom::AutoCEReaction
> autoCEReaction
;
264 dom::DocGroup
* docGroup
= aParent
->OwnerDoc()->GetDocGroup();
265 if (docGroup
&& aFromParser
!= mozilla::dom::FROM_PARSER_FRAGMENT
) {
266 autoCEReaction
.emplace(docGroup
->CustomElementReactionsStack(), nullptr);
268 nsresult rv
= Append(aNode
, aParent
, aBuilder
);
269 // Pause the parser only when there are reactions to be invoked to avoid
270 // pausing parsing too aggressive.
271 if (autoCEReaction
.isSome() && docGroup
&&
272 docGroup
->CustomElementReactionsStack()
273 ->IsElementQueuePushedForCurrentRecursionDepth()) {
274 autoPause
.emplace(aBuilder
);
279 nsresult
nsHtml5TreeOperation::AppendToDocument(
280 nsIContent
* aNode
, nsHtml5DocumentBuilder
* aBuilder
) {
281 MOZ_ASSERT(aBuilder
);
282 MOZ_ASSERT(aBuilder
->GetDocument() == aNode
->OwnerDoc());
283 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
286 Document
* doc
= aBuilder
->GetDocument();
287 rv
= doc
->AppendChildTo(aNode
, false);
288 if (rv
== NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
) {
289 aNode
->SetParserHasNotified();
292 NS_ENSURE_SUCCESS(rv
, rv
);
293 aNode
->SetParserHasNotified();
294 MutationObservers::NotifyContentInserted(doc
, aNode
);
296 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
297 "Someone forgot to block scripts");
298 if (aNode
->IsElement()) {
299 nsContentUtils::AddScriptRunner(
300 new nsDocElementCreatedNotificationRunner(doc
));
305 static bool IsElementOrTemplateContent(nsINode
* aNode
) {
307 if (aNode
->IsElement()) {
310 if (aNode
->IsDocumentFragment()) {
311 // Check if the node is a template content.
312 nsIContent
* fragHost
= aNode
->AsDocumentFragment()->GetHost();
313 if (fragHost
&& fragHost
->IsTemplateElement()) {
321 void nsHtml5TreeOperation::Detach(nsIContent
* aNode
,
322 nsHtml5DocumentBuilder
* aBuilder
) {
323 MOZ_ASSERT(aBuilder
);
324 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
325 nsCOMPtr
<nsINode
> parent
= aNode
->GetParentNode();
327 nsHtml5OtherDocUpdate
update(parent
->OwnerDoc(), aBuilder
->GetDocument());
328 parent
->RemoveChildNode(aNode
, true);
332 nsresult
nsHtml5TreeOperation::AppendChildrenToNewParent(
333 nsIContent
* aNode
, nsIContent
* aParent
, nsHtml5DocumentBuilder
* aBuilder
) {
334 MOZ_ASSERT(aBuilder
);
335 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
336 nsHtml5OtherDocUpdate
update(aParent
->OwnerDoc(), aBuilder
->GetDocument());
338 bool didAppend
= false;
339 while (aNode
->HasChildren()) {
340 nsCOMPtr
<nsIContent
> child
= aNode
->GetFirstChild();
341 aNode
->RemoveChildNode(child
, true);
342 nsresult rv
= aParent
->AppendChildTo(child
, false);
343 NS_ENSURE_SUCCESS(rv
, rv
);
347 MutationObservers::NotifyContentAppended(aParent
, aParent
->GetLastChild());
352 nsresult
nsHtml5TreeOperation::FosterParent(nsIContent
* aNode
,
355 nsHtml5DocumentBuilder
* aBuilder
) {
356 MOZ_ASSERT(aBuilder
);
357 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
358 nsIContent
* foster
= aTable
->GetParent();
360 if (IsElementOrTemplateContent(foster
)) {
361 nsHtml5OtherDocUpdate
update(foster
->OwnerDoc(), aBuilder
->GetDocument());
363 nsresult rv
= foster
->InsertChildBefore(aNode
, aTable
, false);
364 NS_ENSURE_SUCCESS(rv
, rv
);
365 MutationObservers::NotifyContentInserted(foster
, aNode
);
369 return Append(aNode
, aParent
, aBuilder
);
372 nsresult
nsHtml5TreeOperation::AddAttributes(nsIContent
* aNode
,
373 nsHtml5HtmlAttributes
* aAttributes
,
374 nsHtml5DocumentBuilder
* aBuilder
) {
375 dom::Element
* node
= aNode
->AsElement();
376 nsHtml5OtherDocUpdate
update(node
->OwnerDoc(), aBuilder
->GetDocument());
378 int32_t len
= aAttributes
->getLength();
379 for (int32_t i
= len
; i
> 0;) {
381 nsAtom
* localName
= aAttributes
->getLocalNameNoBoundsCheck(i
);
382 int32_t nsuri
= aAttributes
->getURINoBoundsCheck(i
);
383 if (!node
->HasAttr(nsuri
, localName
)) {
384 nsString value
; // Not Auto, because using it to hold nsStringBuffer*
385 aAttributes
->getValueNoBoundsCheck(i
).ToString(value
);
386 node
->SetAttr(nsuri
, localName
, aAttributes
->getPrefixNoBoundsCheck(i
),
388 // XXX what to do with nsresult?
394 void nsHtml5TreeOperation::SetHTMLElementAttributes(
395 dom::Element
* aElement
, nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
) {
396 int32_t len
= aAttributes
->getLength();
397 for (int32_t i
= 0; i
< len
; i
++) {
398 nsHtml5String val
= aAttributes
->getValueNoBoundsCheck(i
);
399 nsAtom
* klass
= val
.MaybeAsAtom();
401 aElement
->SetSingleClassFromParser(klass
);
403 nsAtom
* localName
= aAttributes
->getLocalNameNoBoundsCheck(i
);
404 nsAtom
* prefix
= aAttributes
->getPrefixNoBoundsCheck(i
);
405 int32_t nsuri
= aAttributes
->getURINoBoundsCheck(i
);
407 nsString value
; // Not Auto, because using it to hold nsStringBuffer*
409 if (nsGkAtoms::a
== aName
&& nsGkAtoms::name
== localName
) {
410 // This is an HTML5-incompliant Geckoism.
411 // Remove when fixing bug 582361
412 NS_ConvertUTF16toUTF8
cname(value
);
413 NS_ConvertUTF8toUTF16
uv(nsUnescape(cname
.BeginWriting()));
414 aElement
->SetAttr(nsuri
, localName
, prefix
, uv
, false);
416 aElement
->SetAttr(nsuri
, localName
, prefix
, value
, false);
422 nsIContent
* nsHtml5TreeOperation::CreateHTMLElement(
423 nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
424 mozilla::dom::FromParser aFromParser
, nsNodeInfoManager
* aNodeInfoManager
,
425 nsHtml5DocumentBuilder
* aBuilder
,
426 mozilla::dom::HTMLContentCreatorFunction aCreator
) {
427 RefPtr
<dom::NodeInfo
> nodeInfo
= aNodeInfoManager
->GetNodeInfo(
428 aName
, nullptr, kNameSpaceID_XHTML
, nsINode::ELEMENT_NODE
);
429 NS_ASSERTION(nodeInfo
, "Got null nodeinfo.");
431 dom::Element
* newContent
= nullptr;
432 Document
* document
= nodeInfo
->GetDocument();
433 bool willExecuteScript
= false;
434 bool isCustomElement
= false;
435 RefPtr
<nsAtom
> isAtom
;
436 dom::CustomElementDefinition
* definition
= nullptr;
439 nsHtml5String is
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_IS
);
441 nsAutoString isValue
;
442 is
.ToString(isValue
);
443 isAtom
= NS_Atomize(isValue
);
447 isCustomElement
= (aCreator
== NS_NewCustomElement
|| isAtom
);
448 if (isCustomElement
&& aFromParser
!= dom::FROM_PARSER_FRAGMENT
) {
449 RefPtr
<nsAtom
> tagAtom
= nodeInfo
->NameAtom();
450 RefPtr
<nsAtom
> typeAtom
=
451 (aCreator
== NS_NewCustomElement
) ? tagAtom
: isAtom
;
453 MOZ_ASSERT(nodeInfo
->NameAtom()->Equals(nodeInfo
->LocalName()));
454 definition
= nsContentUtils::LookupCustomElementDefinition(
455 document
, nodeInfo
->NameAtom(), nodeInfo
->NamespaceID(), typeAtom
);
458 willExecuteScript
= true;
462 if (willExecuteScript
) { // This will cause custom element constructors to
464 mozilla::dom::AutoSetThrowOnDynamicMarkupInsertionCounter
465 throwOnDynamicMarkupInsertionCounter(document
);
466 nsHtml5AutoPauseUpdate
autoPauseContentUpdate(aBuilder
);
467 { nsAutoMicroTask mt
; }
468 dom::AutoCEReaction
autoCEReaction(
469 document
->GetDocGroup()->CustomElementReactionsStack(), nullptr);
471 nsCOMPtr
<dom::Element
> newElement
;
472 NS_NewHTMLElement(getter_AddRefs(newElement
), nodeInfo
.forget(),
473 aFromParser
, isAtom
, definition
);
475 MOZ_ASSERT(newElement
, "Element creation created null pointer.");
476 newContent
= newElement
;
477 aBuilder
->HoldElement(newElement
.forget());
479 if (MOZ_UNLIKELY(aName
== nsGkAtoms::style
|| aName
== nsGkAtoms::link
)) {
480 if (auto* linkStyle
= dom::LinkStyle::FromNode(*newContent
)) {
481 linkStyle
->SetEnableUpdates(false);
489 SetHTMLElementAttributes(newContent
, aName
, aAttributes
);
491 nsCOMPtr
<dom::Element
> newElement
;
493 if (isCustomElement
) {
494 NS_NewHTMLElement(getter_AddRefs(newElement
), nodeInfo
.forget(),
495 aFromParser
, isAtom
, definition
);
497 newElement
= aCreator(nodeInfo
.forget(), aFromParser
);
500 MOZ_ASSERT(newElement
, "Element creation created null pointer.");
502 newContent
= newElement
;
503 aBuilder
->HoldElement(newElement
.forget());
505 if (MOZ_UNLIKELY(aName
== nsGkAtoms::style
|| aName
== nsGkAtoms::link
)) {
506 if (auto* linkStyle
= dom::LinkStyle::FromNode(*newContent
)) {
507 linkStyle
->SetEnableUpdates(false);
515 SetHTMLElementAttributes(newContent
, aName
, aAttributes
);
521 nsIContent
* nsHtml5TreeOperation::CreateSVGElement(
522 nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
523 mozilla::dom::FromParser aFromParser
, nsNodeInfoManager
* aNodeInfoManager
,
524 nsHtml5DocumentBuilder
* aBuilder
,
525 mozilla::dom::SVGContentCreatorFunction aCreator
) {
526 nsCOMPtr
<nsIContent
> newElement
;
527 if (MOZ_LIKELY(aNodeInfoManager
->SVGEnabled())) {
528 RefPtr
<dom::NodeInfo
> nodeInfo
= aNodeInfoManager
->GetNodeInfo(
529 aName
, nullptr, kNameSpaceID_SVG
, nsINode::ELEMENT_NODE
);
530 MOZ_ASSERT(nodeInfo
, "Got null nodeinfo.");
532 mozilla::DebugOnly
<nsresult
> rv
=
533 aCreator(getter_AddRefs(newElement
), nodeInfo
.forget(), aFromParser
);
534 MOZ_ASSERT(NS_SUCCEEDED(rv
) && newElement
);
536 RefPtr
<dom::NodeInfo
> nodeInfo
= aNodeInfoManager
->GetNodeInfo(
537 aName
, nullptr, kNameSpaceID_disabled_SVG
, nsINode::ELEMENT_NODE
);
538 MOZ_ASSERT(nodeInfo
, "Got null nodeinfo.");
540 // The mismatch between NS_NewXMLElement and SVGContentCreatorFunction
541 // argument types is annoying.
542 nsCOMPtr
<dom::Element
> xmlElement
;
543 mozilla::DebugOnly
<nsresult
> rv
=
544 NS_NewXMLElement(getter_AddRefs(xmlElement
), nodeInfo
.forget());
545 MOZ_ASSERT(NS_SUCCEEDED(rv
) && xmlElement
);
546 newElement
= xmlElement
;
549 dom::Element
* newContent
= newElement
->AsElement();
550 aBuilder
->HoldElement(newElement
.forget());
552 if (MOZ_UNLIKELY(aName
== nsGkAtoms::style
)) {
553 if (auto* linkStyle
= dom::LinkStyle::FromNode(*newContent
)) {
554 linkStyle
->SetEnableUpdates(false);
562 int32_t len
= aAttributes
->getLength();
563 for (int32_t i
= 0; i
< len
; i
++) {
564 nsHtml5String val
= aAttributes
->getValueNoBoundsCheck(i
);
565 nsAtom
* klass
= val
.MaybeAsAtom();
567 newContent
->SetSingleClassFromParser(klass
);
569 nsAtom
* localName
= aAttributes
->getLocalNameNoBoundsCheck(i
);
570 nsAtom
* prefix
= aAttributes
->getPrefixNoBoundsCheck(i
);
571 int32_t nsuri
= aAttributes
->getURINoBoundsCheck(i
);
573 nsString value
; // Not Auto, because using it to hold nsStringBuffer*
575 newContent
->SetAttr(nsuri
, localName
, prefix
, value
, false);
581 nsIContent
* nsHtml5TreeOperation::CreateMathMLElement(
582 nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
583 nsNodeInfoManager
* aNodeInfoManager
, nsHtml5DocumentBuilder
* aBuilder
) {
584 nsCOMPtr
<dom::Element
> newElement
;
585 if (MOZ_LIKELY(aNodeInfoManager
->MathMLEnabled())) {
586 RefPtr
<dom::NodeInfo
> nodeInfo
= aNodeInfoManager
->GetNodeInfo(
587 aName
, nullptr, kNameSpaceID_MathML
, nsINode::ELEMENT_NODE
);
588 NS_ASSERTION(nodeInfo
, "Got null nodeinfo.");
590 mozilla::DebugOnly
<nsresult
> rv
=
591 NS_NewMathMLElement(getter_AddRefs(newElement
), nodeInfo
.forget());
592 MOZ_ASSERT(NS_SUCCEEDED(rv
) && newElement
);
594 RefPtr
<dom::NodeInfo
> nodeInfo
= aNodeInfoManager
->GetNodeInfo(
595 aName
, nullptr, kNameSpaceID_disabled_MathML
, nsINode::ELEMENT_NODE
);
596 NS_ASSERTION(nodeInfo
, "Got null nodeinfo.");
598 mozilla::DebugOnly
<nsresult
> rv
=
599 NS_NewXMLElement(getter_AddRefs(newElement
), nodeInfo
.forget());
600 MOZ_ASSERT(NS_SUCCEEDED(rv
) && newElement
);
603 dom::Element
* newContent
= newElement
;
604 aBuilder
->HoldElement(newElement
.forget());
610 int32_t len
= aAttributes
->getLength();
611 for (int32_t i
= 0; i
< len
; i
++) {
612 nsHtml5String val
= aAttributes
->getValueNoBoundsCheck(i
);
613 nsAtom
* klass
= val
.MaybeAsAtom();
615 newContent
->SetSingleClassFromParser(klass
);
617 nsAtom
* localName
= aAttributes
->getLocalNameNoBoundsCheck(i
);
618 nsAtom
* prefix
= aAttributes
->getPrefixNoBoundsCheck(i
);
619 int32_t nsuri
= aAttributes
->getURINoBoundsCheck(i
);
621 nsString value
; // Not Auto, because using it to hold nsStringBuffer*
623 newContent
->SetAttr(nsuri
, localName
, prefix
, value
, false);
629 void nsHtml5TreeOperation::SetFormElement(nsIContent
* aNode
,
630 nsIContent
* aParent
) {
631 nsCOMPtr
<nsIFormControl
> formControl(do_QueryInterface(aNode
));
632 RefPtr
<dom::HTMLImageElement
> domImageElement
=
633 dom::HTMLImageElement::FromNodeOrNull(aNode
);
634 // NS_ASSERTION(formControl, "Form-associated element did not implement
635 // nsIFormControl.");
636 // TODO: uncomment the above line when img doesn't cause an issue (bug
638 RefPtr
<dom::HTMLFormElement
> formElement
=
639 dom::HTMLFormElement::FromNodeOrNull(aParent
);
640 NS_ASSERTION(formElement
,
641 "The form element doesn't implement HTMLFormElement.");
642 // Avoid crashing on <img>
644 !aNode
->AsElement()->HasAttr(kNameSpaceID_None
, nsGkAtoms::form
)) {
645 formControl
->SetForm(formElement
);
646 } else if (domImageElement
) {
647 domImageElement
->SetForm(formElement
);
651 nsresult
nsHtml5TreeOperation::FosterParentText(
652 nsIContent
* aStackParent
, char16_t
* aBuffer
, uint32_t aLength
,
653 nsIContent
* aTable
, nsHtml5DocumentBuilder
* aBuilder
) {
654 MOZ_ASSERT(aBuilder
);
655 MOZ_ASSERT(aBuilder
->IsInDocUpdate());
657 nsIContent
* foster
= aTable
->GetParent();
659 if (IsElementOrTemplateContent(foster
)) {
660 nsHtml5OtherDocUpdate
update(foster
->OwnerDoc(), aBuilder
->GetDocument());
662 nsIContent
* previousSibling
= aTable
->GetPreviousSibling();
663 if (previousSibling
&& previousSibling
->IsText()) {
664 return AppendTextToTextNode(aBuffer
, aLength
,
665 previousSibling
->GetAsText(), aBuilder
);
668 nsNodeInfoManager
* nodeInfoManager
=
669 aStackParent
->OwnerDoc()->NodeInfoManager();
670 RefPtr
<nsTextNode
> text
= new (nodeInfoManager
) nsTextNode(nodeInfoManager
);
671 NS_ASSERTION(text
, "Infallible malloc failed?");
672 rv
= text
->SetText(aBuffer
, aLength
, false);
673 NS_ENSURE_SUCCESS(rv
, rv
);
675 rv
= foster
->InsertChildBefore(text
, aTable
, false);
676 NS_ENSURE_SUCCESS(rv
, rv
);
677 MutationObservers::NotifyContentInserted(foster
, text
);
681 return AppendText(aBuffer
, aLength
, aStackParent
, aBuilder
);
684 nsresult
nsHtml5TreeOperation::AppendComment(nsIContent
* aParent
,
685 char16_t
* aBuffer
, int32_t aLength
,
686 nsHtml5DocumentBuilder
* aBuilder
) {
687 nsNodeInfoManager
* nodeInfoManager
= aParent
->OwnerDoc()->NodeInfoManager();
688 RefPtr
<dom::Comment
> comment
=
689 new (nodeInfoManager
) dom::Comment(nodeInfoManager
);
690 NS_ASSERTION(comment
, "Infallible malloc failed?");
691 nsresult rv
= comment
->SetText(aBuffer
, aLength
, false);
692 NS_ENSURE_SUCCESS(rv
, rv
);
694 return Append(comment
, aParent
, aBuilder
);
697 nsresult
nsHtml5TreeOperation::AppendCommentToDocument(
698 char16_t
* aBuffer
, int32_t aLength
, nsHtml5DocumentBuilder
* aBuilder
) {
699 RefPtr
<dom::Comment
> comment
= new (aBuilder
->GetNodeInfoManager())
700 dom::Comment(aBuilder
->GetNodeInfoManager());
701 NS_ASSERTION(comment
, "Infallible malloc failed?");
702 nsresult rv
= comment
->SetText(aBuffer
, aLength
, false);
703 NS_ENSURE_SUCCESS(rv
, rv
);
705 return AppendToDocument(comment
, aBuilder
);
708 nsresult
nsHtml5TreeOperation::AppendDoctypeToDocument(
709 nsAtom
* aName
, const nsAString
& aPublicId
, const nsAString
& aSystemId
,
710 nsHtml5DocumentBuilder
* aBuilder
) {
711 // Adapted from nsXMLContentSink
712 // Create a new doctype node
713 RefPtr
<dom::DocumentType
> docType
=
714 NS_NewDOMDocumentType(aBuilder
->GetNodeInfoManager(), aName
, aPublicId
,
715 aSystemId
, VoidString());
716 return AppendToDocument(docType
, aBuilder
);
719 nsIContent
* nsHtml5TreeOperation::GetDocumentFragmentForTemplate(
721 dom::HTMLTemplateElement
* tempElem
=
722 static_cast<dom::HTMLTemplateElement
*>(aNode
);
723 RefPtr
<dom::DocumentFragment
> frag
= tempElem
->Content();
727 nsIContent
* nsHtml5TreeOperation::GetFosterParent(nsIContent
* aTable
,
728 nsIContent
* aStackParent
) {
729 nsIContent
* tableParent
= aTable
->GetParent();
730 return IsElementOrTemplateContent(tableParent
) ? tableParent
: aStackParent
;
733 void nsHtml5TreeOperation::PreventScriptExecution(nsIContent
* aNode
) {
734 nsCOMPtr
<nsIScriptElement
> sele
= do_QueryInterface(aNode
);
736 sele
->PreventExecution();
738 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled
,
739 "Node didn't QI to script, but SVG wasn't disabled.");
743 void nsHtml5TreeOperation::DoneAddingChildren(nsIContent
* aNode
) {
744 aNode
->DoneAddingChildren(aNode
->HasParserNotified());
747 void nsHtml5TreeOperation::DoneCreatingElement(nsIContent
* aNode
) {
748 aNode
->DoneCreatingElement();
751 void nsHtml5TreeOperation::SvgLoad(nsIContent
* aNode
) {
752 nsCOMPtr
<nsIRunnable
> event
= new nsHtml5SVGLoadDispatcher(aNode
);
754 aNode
->OwnerDoc()->Dispatch(TaskCategory::Network
, event
.forget()))) {
755 NS_WARNING("failed to dispatch svg load dispatcher");
759 void nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent
* aNode
) {
760 nsCOMPtr
<nsIScriptElement
> sele
= do_QueryInterface(aNode
);
762 // Make sure to serialize this script correctly, for nice round tripping.
763 sele
->SetIsMalformed();
767 nsresult
nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor
* aBuilder
,
768 nsIContent
** aScriptElement
,
769 bool* aInterrupted
, bool* aStreamEnded
) {
770 struct TreeOperationMatcher
{
771 TreeOperationMatcher(nsHtml5TreeOpExecutor
* aBuilder
,
772 nsIContent
** aScriptElement
, bool* aInterrupted
,
774 : mBuilder(aBuilder
),
775 mScriptElement(aScriptElement
),
776 mInterrupted(aInterrupted
),
777 mStreamEnded(aStreamEnded
) {}
779 nsHtml5TreeOpExecutor
* mBuilder
;
780 nsIContent
** mScriptElement
;
784 nsresult
operator()(const opAppend
& aOperation
) {
785 return Append(*(aOperation
.mChild
), *(aOperation
.mParent
),
786 aOperation
.mFromNetwork
, mBuilder
);
789 nsresult
operator()(const opDetach
& aOperation
) {
790 Detach(*(aOperation
.mElement
), mBuilder
);
794 nsresult
operator()(const opAppendChildrenToNewParent
& aOperation
) {
795 nsCOMPtr
<nsIContent
> node
= *(aOperation
.mOldParent
);
796 nsIContent
* parent
= *(aOperation
.mNewParent
);
797 return AppendChildrenToNewParent(node
, parent
, mBuilder
);
800 nsresult
operator()(const opFosterParent
& aOperation
) {
801 nsIContent
* node
= *(aOperation
.mChild
);
802 nsIContent
* parent
= *(aOperation
.mStackParent
);
803 nsIContent
* table
= *(aOperation
.mTable
);
804 return FosterParent(node
, parent
, table
, mBuilder
);
807 nsresult
operator()(const opAppendToDocument
& aOperation
) {
808 nsresult rv
= AppendToDocument(*(aOperation
.mContent
), mBuilder
);
809 mBuilder
->PauseDocUpdate(mInterrupted
);
813 nsresult
operator()(const opAddAttributes
& aOperation
) {
814 nsIContent
* node
= *(aOperation
.mElement
);
815 nsHtml5HtmlAttributes
* attributes
= aOperation
.mAttributes
;
816 return AddAttributes(node
, attributes
, mBuilder
);
819 nsresult
operator()(const nsHtml5DocumentMode
& aMode
) {
820 mBuilder
->SetDocumentMode(aMode
);
824 nsresult
operator()(const opCreateHTMLElement
& aOperation
) {
825 nsIContent
** target
= aOperation
.mContent
;
826 mozilla::dom::HTMLContentCreatorFunction creator
= aOperation
.mCreator
;
827 nsAtom
* name
= aOperation
.mName
;
828 nsHtml5HtmlAttributes
* attributes
= aOperation
.mAttributes
;
829 nsIContent
* intendedParent
=
830 aOperation
.mIntendedParent
? *(aOperation
.mIntendedParent
) : nullptr;
832 // intendedParent == nullptr is a special case where the
833 // intended parent is the document.
834 nsNodeInfoManager
* nodeInfoManager
=
835 intendedParent
? intendedParent
->OwnerDoc()->NodeInfoManager()
836 : mBuilder
->GetNodeInfoManager();
838 *target
= CreateHTMLElement(name
, attributes
, aOperation
.mFromNetwork
,
839 nodeInfoManager
, mBuilder
, creator
);
843 nsresult
operator()(const opCreateSVGElement
& aOperation
) {
844 nsIContent
** target
= aOperation
.mContent
;
845 mozilla::dom::SVGContentCreatorFunction creator
= aOperation
.mCreator
;
846 nsAtom
* name
= aOperation
.mName
;
847 nsHtml5HtmlAttributes
* attributes
= aOperation
.mAttributes
;
848 nsIContent
* intendedParent
=
849 aOperation
.mIntendedParent
? *(aOperation
.mIntendedParent
) : nullptr;
851 // intendedParent == nullptr is a special case where the
852 // intended parent is the document.
853 nsNodeInfoManager
* nodeInfoManager
=
854 intendedParent
? intendedParent
->OwnerDoc()->NodeInfoManager()
855 : mBuilder
->GetNodeInfoManager();
857 *target
= CreateSVGElement(name
, attributes
, aOperation
.mFromNetwork
,
858 nodeInfoManager
, mBuilder
, creator
);
862 nsresult
operator()(const opCreateMathMLElement
& aOperation
) {
863 nsIContent
** target
= aOperation
.mContent
;
864 nsAtom
* name
= aOperation
.mName
;
865 nsHtml5HtmlAttributes
* attributes
= aOperation
.mAttributes
;
866 nsIContent
* intendedParent
=
867 aOperation
.mIntendedParent
? *(aOperation
.mIntendedParent
) : nullptr;
869 // intendedParent == nullptr is a special case where the
870 // intended parent is the document.
871 nsNodeInfoManager
* nodeInfoManager
=
872 intendedParent
? intendedParent
->OwnerDoc()->NodeInfoManager()
873 : mBuilder
->GetNodeInfoManager();
876 CreateMathMLElement(name
, attributes
, nodeInfoManager
, mBuilder
);
880 nsresult
operator()(const opSetFormElement
& aOperation
) {
881 SetFormElement(*(aOperation
.mContent
), *(aOperation
.mFormElement
));
885 nsresult
operator()(const opAppendText
& aOperation
) {
886 nsIContent
* parent
= *aOperation
.mParent
;
887 char16_t
* buffer
= aOperation
.mBuffer
;
888 uint32_t length
= aOperation
.mLength
;
889 return AppendText(buffer
, length
, parent
, mBuilder
);
892 nsresult
operator()(const opFosterParentText
& aOperation
) {
893 nsIContent
* stackParent
= *aOperation
.mStackParent
;
894 char16_t
* buffer
= aOperation
.mBuffer
;
895 uint32_t length
= aOperation
.mLength
;
896 nsIContent
* table
= *aOperation
.mTable
;
897 return FosterParentText(stackParent
, buffer
, length
, table
, mBuilder
);
900 nsresult
operator()(const opAppendComment
& aOperation
) {
901 nsIContent
* parent
= *aOperation
.mParent
;
902 char16_t
* buffer
= aOperation
.mBuffer
;
903 uint32_t length
= aOperation
.mLength
;
904 return AppendComment(parent
, buffer
, length
, mBuilder
);
907 nsresult
operator()(const opAppendCommentToDocument
& aOperation
) {
908 char16_t
* buffer
= aOperation
.mBuffer
;
909 int32_t length
= aOperation
.mLength
;
910 return AppendCommentToDocument(buffer
, length
, mBuilder
);
913 nsresult
operator()(const opAppendDoctypeToDocument
& aOperation
) {
914 nsAtom
* name
= aOperation
.mName
;
915 nsHtml5TreeOperationStringPair
* pair
= aOperation
.mStringPair
;
918 pair
->Get(publicId
, systemId
);
919 return AppendDoctypeToDocument(name
, publicId
, systemId
, mBuilder
);
922 nsresult
operator()(const opGetDocumentFragmentForTemplate
& aOperation
) {
923 nsIContent
* node
= *(aOperation
.mTemplate
);
924 *(aOperation
.mFragHandle
) = GetDocumentFragmentForTemplate(node
);
928 nsresult
operator()(const opGetFosterParent
& aOperation
) {
929 nsIContent
* table
= *(aOperation
.mTable
);
930 nsIContent
* stackParent
= *(aOperation
.mStackParent
);
931 nsIContent
* fosterParent
= GetFosterParent(table
, stackParent
);
932 *aOperation
.mParentHandle
= fosterParent
;
936 nsresult
operator()(const opMarkAsBroken
& aOperation
) {
937 return aOperation
.mResult
;
940 nsresult
operator()(const opRunScript
& aOperation
) {
941 nsIContent
* node
= *(aOperation
.mElement
);
942 nsAHtml5TreeBuilderState
* snapshot
= aOperation
.mBuilderState
;
944 mBuilder
->InitializeDocWriteParserState(snapshot
,
945 aOperation
.mLineNumber
);
947 *mScriptElement
= node
;
951 nsresult
operator()(const opRunScriptAsyncDefer
& aOperation
) {
952 mBuilder
->RunScript(*(aOperation
.mElement
));
956 nsresult
operator()(const opPreventScriptExecution
& aOperation
) {
957 PreventScriptExecution(*(aOperation
.mElement
));
961 nsresult
operator()(const opDoneAddingChildren
& aOperation
) {
962 nsIContent
* node
= *(aOperation
.mElement
);
963 node
->DoneAddingChildren(node
->HasParserNotified());
967 nsresult
operator()(const opDoneCreatingElement
& aOperation
) {
968 DoneCreatingElement(*(aOperation
.mElement
));
972 nsresult
operator()(const opSetDocumentCharset
& aOperation
) {
973 auto encoding
= WrapNotNull(aOperation
.mEncoding
);
974 mBuilder
->SetDocumentCharsetAndSource(encoding
,
975 aOperation
.mCharsetSource
);
979 nsresult
operator()(const opCharsetSwitchTo
& aOperation
) {
980 auto encoding
= WrapNotNull(aOperation
.mEncoding
);
981 mBuilder
->NeedsCharsetSwitchTo(encoding
, aOperation
.mCharsetSource
,
982 (uint32_t)aOperation
.mLineNumber
);
986 nsresult
operator()(const opUpdateStyleSheet
& aOperation
) {
987 mBuilder
->UpdateStyleSheet(*(aOperation
.mElement
));
991 nsresult
operator()(const opProcessOfflineManifest
& aOperation
) {
992 nsDependentString
dependentString(aOperation
.mUrl
);
993 mBuilder
->ProcessOfflineManifest(dependentString
);
997 nsresult
operator()(const opMarkMalformedIfScript
& aOperation
) {
998 MarkMalformedIfScript(*(aOperation
.mElement
));
1002 nsresult
operator()(const opStreamEnded
& aOperation
) {
1003 *mStreamEnded
= true;
1007 nsresult
operator()(const opSetStyleLineNumber
& aOperation
) {
1008 nsIContent
* node
= *(aOperation
.mContent
);
1009 if (auto* linkStyle
= dom::LinkStyle::FromNode(*node
)) {
1010 linkStyle
->SetLineNumber(aOperation
.mLineNumber
);
1012 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled
,
1013 "Node didn't QI to style, but SVG wasn't disabled.");
1018 nsresult
operator()(const opSetScriptLineNumberAndFreeze
& aOperation
) {
1019 nsIContent
* node
= *(aOperation
.mContent
);
1020 nsCOMPtr
<nsIScriptElement
> sele
= do_QueryInterface(node
);
1022 sele
->SetScriptLineNumber(aOperation
.mLineNumber
);
1023 sele
->FreezeExecutionAttrs(node
->OwnerDoc());
1025 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled
,
1026 "Node didn't QI to script, but SVG wasn't disabled.");
1031 nsresult
operator()(const opSvgLoad
& aOperation
) {
1032 SvgLoad(*(aOperation
.mElement
));
1036 nsresult
operator()(const opMaybeComplainAboutCharset
& aOperation
) {
1037 char* msgId
= aOperation
.mMsgId
;
1038 bool error
= aOperation
.mError
;
1039 int32_t lineNumber
= aOperation
.mLineNumber
;
1040 mBuilder
->MaybeComplainAboutCharset(msgId
, error
, (uint32_t)lineNumber
);
1044 nsresult
operator()(const opMaybeComplainAboutDeepTree
& aOperation
) {
1045 mBuilder
->MaybeComplainAboutDeepTree((uint32_t)aOperation
.mLineNumber
);
1049 nsresult
operator()(const opAddClass
& aOperation
) {
1050 Element
* element
= (*(aOperation
.mElement
))->AsElement();
1051 char16_t
* str
= aOperation
.mClass
;
1052 nsDependentString
depStr(str
);
1053 // See viewsource.css for the possible classes
1055 element
->GetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, klass
);
1056 if (!klass
.IsEmpty()) {
1058 klass
.Append(depStr
);
1059 element
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, klass
, true);
1061 element
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, depStr
, true);
1066 nsresult
operator()(const opAddViewSourceHref
& aOperation
) {
1067 Element
* element
= (*aOperation
.mElement
)->AsElement();
1068 char16_t
* buffer
= aOperation
.mBuffer
;
1069 int32_t length
= aOperation
.mLength
;
1070 nsDependentString
relative(buffer
, length
);
1072 Document
* doc
= mBuilder
->GetDocument();
1074 auto encoding
= doc
->GetDocumentCharacterSet();
1075 nsCOMPtr
<nsIURI
> uri
;
1076 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), relative
, encoding
,
1077 mBuilder
->GetViewSourceBaseURI());
1078 NS_ENSURE_SUCCESS(rv
, NS_OK
);
1080 // Reuse the fix for bug 467852
1081 // URLs that execute script (e.g. "javascript:" URLs) should just be
1082 // ignored. There's nothing reasonable we can do with them, and allowing
1083 // them to execute in the context of the view-source window presents a
1084 // security risk. Just return the empty string in this case.
1085 bool openingExecutesScript
= false;
1086 rv
= NS_URIChainHasFlags(uri
,
1087 nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT
,
1088 &openingExecutesScript
);
1089 if (NS_FAILED(rv
) || openingExecutesScript
) {
1093 nsAutoCString viewSourceUrl
;
1095 // URLs that return data (e.g. "http:" URLs) should be prefixed with
1096 // "view-source:". URLs that don't return data should just be returned
1098 bool doesNotReturnData
= false;
1100 NS_URIChainHasFlags(uri
, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA
,
1101 &doesNotReturnData
);
1102 NS_ENSURE_SUCCESS(rv
, NS_OK
);
1103 if (!doesNotReturnData
) {
1104 viewSourceUrl
.AssignLiteral("view-source:");
1108 rv
= uri
->GetSpec(spec
);
1109 NS_ENSURE_SUCCESS(rv
, rv
);
1111 viewSourceUrl
.Append(spec
);
1114 CopyUTF8toUTF16(viewSourceUrl
, utf16
);
1116 element
->SetAttr(kNameSpaceID_None
, nsGkAtoms::href
, utf16
, true);
1120 nsresult
operator()(const opAddViewSourceBase
& aOperation
) {
1121 nsDependentString
baseUrl(aOperation
.mBuffer
, aOperation
.mLength
);
1122 mBuilder
->AddBase(baseUrl
);
1126 nsresult
operator()(const opAddErrorType
& aOperation
) {
1127 Element
* element
= (*(aOperation
.mElement
))->AsElement();
1128 char* msgId
= aOperation
.mMsgId
;
1129 nsAtom
* atom
= aOperation
.mName
;
1130 nsAtom
* otherAtom
= aOperation
.mOther
;
1131 // See viewsource.css for the possible classes in addition to "error".
1133 element
->GetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, klass
);
1134 if (!klass
.IsEmpty()) {
1135 klass
.AppendLiteral(" error");
1136 element
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, klass
, true);
1138 element
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, u
"error"_ns
,
1143 nsAutoString message
;
1145 rv
= nsContentUtils::FormatLocalizedString(
1146 message
, nsContentUtils::eHTMLPARSER_PROPERTIES
, msgId
,
1147 nsDependentAtomString(atom
), nsDependentAtomString(otherAtom
));
1148 NS_ENSURE_SUCCESS(rv
, NS_OK
);
1150 rv
= nsContentUtils::FormatLocalizedString(
1151 message
, nsContentUtils::eHTMLPARSER_PROPERTIES
, msgId
,
1152 nsDependentAtomString(atom
));
1153 NS_ENSURE_SUCCESS(rv
, NS_OK
);
1155 rv
= nsContentUtils::GetLocalizedString(
1156 nsContentUtils::eHTMLPARSER_PROPERTIES
, msgId
, message
);
1157 NS_ENSURE_SUCCESS(rv
, NS_OK
);
1161 element
->GetAttr(kNameSpaceID_None
, nsGkAtoms::title
, title
);
1162 if (!title
.IsEmpty()) {
1164 title
.Append(message
);
1165 element
->SetAttr(kNameSpaceID_None
, nsGkAtoms::title
, title
, true);
1167 element
->SetAttr(kNameSpaceID_None
, nsGkAtoms::title
, message
, true);
1172 nsresult
operator()(const opAddLineNumberId
& aOperation
) {
1173 Element
* element
= (*(aOperation
.mElement
))->AsElement();
1174 int32_t lineNumber
= aOperation
.mLineNumber
;
1175 nsAutoString
val(u
"line"_ns
);
1176 val
.AppendInt(lineNumber
);
1177 element
->SetAttr(kNameSpaceID_None
, nsGkAtoms::id
, val
, true);
1181 nsresult
operator()(const opStartLayout
& aOperation
) {
1182 mBuilder
->StartLayout(
1183 mInterrupted
); // this causes a notification flush anyway
1187 nsresult
operator()(const opEnableEncodingMenu
& aOperation
) {
1188 Document
* doc
= mBuilder
->GetDocument();
1189 doc
->EnableEncodingMenu();
1193 nsresult
operator()(const uninitialized
& aOperation
) {
1194 MOZ_CRASH("uninitialized");
1199 return mOperation
.match(TreeOperationMatcher(aBuilder
, aScriptElement
,
1200 aInterrupted
, aStreamEnded
));