Bug 1931425 - Limit how often moz-label's #setStyles runs r=reusable-components-revie...
[gecko.git] / parser / html / nsHtml5TreeOperation.cpp
blob5687d5e651aab9ca2b609fb22cef89e15aa808e2
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/DocGroup.h"
14 #include "mozilla/dom/DocumentFragment.h"
15 #include "mozilla/dom/DocumentType.h"
16 #include "mozilla/dom/Element.h"
17 #include "mozilla/dom/LinkStyle.h"
18 #include "mozilla/dom/HTMLFormElement.h"
19 #include "mozilla/dom/HTMLImageElement.h"
20 #include "mozilla/dom/HTMLTemplateElement.h"
21 #include "mozilla/dom/MutationObservers.h"
22 #include "mozilla/dom/ShadowRoot.h"
23 #include "mozilla/dom/Text.h"
24 #include "nsAttrName.h"
25 #include "nsContentCreatorFunctions.h"
26 #include "nsContentUtils.h"
27 #include "nsDocElementCreatedNotificationRunner.h"
28 #include "nsEscape.h"
29 #include "nsGenericHTMLElement.h"
30 #include "nsHtml5AutoPauseUpdate.h"
31 #include "nsHtml5DocumentMode.h"
32 #include "nsHtml5HtmlAttributes.h"
33 #include "nsHtml5SVGLoadDispatcher.h"
34 #include "nsHtml5TreeBuilder.h"
35 #include "nsIDTD.h"
36 #include "nsIFormControl.h"
37 #include "nsIMutationObserver.h"
38 #include "nsINode.h"
39 #include "nsIProtocolHandler.h"
40 #include "nsIScriptElement.h"
41 #include "nsISupportsImpl.h"
42 #include "nsIURI.h"
43 #include "nsNetUtil.h"
44 #include "nsTextNode.h"
45 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
47 using namespace mozilla;
48 using namespace mozilla::dom;
50 /**
51 * Helper class that opens a notification batch if the current doc
52 * is different from the executor doc.
54 class MOZ_STACK_CLASS nsHtml5OtherDocUpdate {
55 public:
56 nsHtml5OtherDocUpdate(Document* aCurrentDoc, Document* aExecutorDoc) {
57 MOZ_ASSERT(aCurrentDoc, "Node has no doc?");
58 MOZ_ASSERT(aExecutorDoc, "Executor has no doc?");
59 if (MOZ_LIKELY(aCurrentDoc == aExecutorDoc)) {
60 mDocument = nullptr;
61 } else {
62 mDocument = aCurrentDoc;
63 aCurrentDoc->BeginUpdate();
67 ~nsHtml5OtherDocUpdate() {
68 if (MOZ_UNLIKELY(mDocument)) {
69 mDocument->EndUpdate();
73 private:
74 RefPtr<Document> mDocument;
77 nsHtml5TreeOperation::nsHtml5TreeOperation() : mOperation(uninitialized()) {
78 MOZ_COUNT_CTOR(nsHtml5TreeOperation);
81 nsHtml5TreeOperation::~nsHtml5TreeOperation() {
82 MOZ_COUNT_DTOR(nsHtml5TreeOperation);
84 struct TreeOperationMatcher {
85 void operator()(const opAppend& aOperation) {}
87 void operator()(const opDetach& aOperation) {}
89 void operator()(const opAppendChildrenToNewParent& aOperation) {}
91 void operator()(const opFosterParent& aOperation) {}
93 void operator()(const opAppendToDocument& aOperation) {}
95 void operator()(const opAddAttributes& aOperation) {
96 delete aOperation.mAttributes;
99 void operator()(const nsHtml5DocumentMode& aMode) {}
101 void operator()(const opCreateHTMLElement& aOperation) {
102 aOperation.mName->Release();
103 delete aOperation.mAttributes;
106 void operator()(const opCreateSVGElement& aOperation) {
107 aOperation.mName->Release();
108 delete aOperation.mAttributes;
111 void operator()(const opCreateMathMLElement& aOperation) {
112 aOperation.mName->Release();
113 delete aOperation.mAttributes;
116 void operator()(const opSetFormElement& aOperation) {}
118 void operator()(const opAppendText& aOperation) {
119 delete[] aOperation.mBuffer;
122 void operator()(const opFosterParentText& aOperation) {
123 delete[] aOperation.mBuffer;
126 void operator()(const opAppendComment& aOperation) {
127 delete[] aOperation.mBuffer;
130 void operator()(const opAppendCommentToDocument& aOperation) {
131 delete[] aOperation.mBuffer;
134 void operator()(const opAppendDoctypeToDocument& aOperation) {
135 aOperation.mName->Release();
136 delete aOperation.mStringPair;
139 void operator()(const opGetDocumentFragmentForTemplate& aOperation) {}
141 void operator()(const opSetDocumentFragmentForTemplate& aOperation) {}
143 void operator()(const opGetShadowRootFromHost& aOperation) {}
145 void operator()(const opGetFosterParent& aOperation) {}
147 void operator()(const opMarkAsBroken& aOperation) {}
149 void operator()(const opRunScriptThatMayDocumentWriteOrBlock& aOperation) {}
151 void operator()(
152 const opRunScriptThatCannotDocumentWriteOrBlock& aOperation) {}
154 void operator()(const opPreventScriptExecution& aOperation) {}
156 void operator()(const opDoneAddingChildren& aOperation) {}
158 void operator()(const opDoneCreatingElement& aOperation) {}
160 void operator()(const opUpdateCharsetSource& aOperation) {}
162 void operator()(const opCharsetSwitchTo& aOperation) {}
164 void operator()(const opUpdateStyleSheet& aOperation) {}
166 void operator()(const opProcessOfflineManifest& aOperation) {
167 free(aOperation.mUrl);
170 void operator()(const opMarkMalformedIfScript& aOperation) {}
172 void operator()(const opStreamEnded& aOperation) {}
174 void operator()(const opSetStyleLineNumber& aOperation) {}
176 void operator()(const opSetScriptLineAndColumnNumberAndFreeze& aOperation) {
179 void operator()(const opSvgLoad& aOperation) {}
181 void operator()(const opMaybeComplainAboutCharset& aOperation) {}
183 void operator()(const opMaybeComplainAboutDeepTree& aOperation) {}
185 void operator()(const opAddClass& aOperation) {}
187 void operator()(const opAddViewSourceHref& aOperation) {
188 delete[] aOperation.mBuffer;
191 void operator()(const opAddViewSourceBase& aOperation) {
192 delete[] aOperation.mBuffer;
195 void operator()(const opAddErrorType& aOperation) {
196 if (aOperation.mName) {
197 aOperation.mName->Release();
199 if (aOperation.mOther) {
200 aOperation.mOther->Release();
204 void operator()(const opAddLineNumberId& aOperation) {}
206 void operator()(const opShallowCloneInto& aOperation) {}
208 void operator()(const opStartLayout& aOperation) {}
210 void operator()(const opEnableEncodingMenu& aOperation) {}
212 void operator()(const uninitialized& aOperation) {
213 NS_WARNING("Uninitialized tree op.");
217 mOperation.match(TreeOperationMatcher());
220 nsresult nsHtml5TreeOperation::AppendTextToTextNode(
221 const char16_t* aBuffer, uint32_t aLength, Text* aTextNode,
222 nsHtml5DocumentBuilder* aBuilder) {
223 MOZ_ASSERT(aTextNode, "Got null text node.");
224 MOZ_ASSERT(aBuilder);
225 MOZ_ASSERT(aBuilder->IsInDocUpdate());
226 uint32_t oldLength = aTextNode->TextLength();
227 CharacterDataChangeInfo info = {true, oldLength, oldLength, aLength};
228 MutationObservers::NotifyCharacterDataWillChange(aTextNode, info);
230 nsresult rv = aTextNode->AppendText(aBuffer, aLength, false);
231 NS_ENSURE_SUCCESS(rv, rv);
233 MutationObservers::NotifyCharacterDataChanged(aTextNode, info);
234 return rv;
237 nsresult nsHtml5TreeOperation::AppendText(const char16_t* aBuffer,
238 uint32_t aLength, nsIContent* aParent,
239 nsHtml5DocumentBuilder* aBuilder) {
240 nsresult rv = NS_OK;
241 nsIContent* lastChild = aParent->GetLastChild();
242 if (lastChild && lastChild->IsText()) {
243 nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), aBuilder->GetDocument());
244 return AppendTextToTextNode(aBuffer, aLength, lastChild->GetAsText(),
245 aBuilder);
248 nsNodeInfoManager* nodeInfoManager = aParent->OwnerDoc()->NodeInfoManager();
249 RefPtr<nsTextNode> text = new (nodeInfoManager) nsTextNode(nodeInfoManager);
250 NS_ASSERTION(text, "Infallible malloc failed?");
251 rv = text->SetText(aBuffer, aLength, false);
252 NS_ENSURE_SUCCESS(rv, rv);
254 return Append(text, aParent, aBuilder);
257 nsresult nsHtml5TreeOperation::Append(nsIContent* aNode, nsIContent* aParent,
258 nsHtml5DocumentBuilder* aBuilder) {
259 MOZ_ASSERT(aBuilder);
260 MOZ_ASSERT(aBuilder->IsInDocUpdate());
261 ErrorResult rv;
262 Document* ownerDoc = aParent->OwnerDoc();
263 nsHtml5OtherDocUpdate update(ownerDoc, aBuilder->GetDocument());
264 aParent->AppendChildTo(aNode, false, rv);
265 if (!rv.Failed() && !ownerDoc->DOMNotificationsSuspended()) {
266 aNode->SetParserHasNotified();
267 MutationObservers::NotifyContentAppended(aParent, aNode);
269 return rv.StealNSResult();
272 nsresult nsHtml5TreeOperation::Append(nsIContent* aNode, nsIContent* aParent,
273 FromParser aFromParser,
274 nsHtml5DocumentBuilder* aBuilder) {
275 Maybe<nsHtml5AutoPauseUpdate> autoPause;
276 Maybe<AutoCEReaction> autoCEReaction;
277 DocGroup* docGroup = aParent->OwnerDoc()->GetDocGroup();
278 if (docGroup && aFromParser != FROM_PARSER_FRAGMENT) {
279 autoCEReaction.emplace(docGroup->CustomElementReactionsStack(), nullptr);
281 nsresult rv = Append(aNode, aParent, aBuilder);
282 // Pause the parser only when there are reactions to be invoked to avoid
283 // pausing parsing too aggressive.
284 if (autoCEReaction.isSome() && docGroup &&
285 docGroup->CustomElementReactionsStack()
286 ->IsElementQueuePushedForCurrentRecursionDepth()) {
287 autoPause.emplace(aBuilder);
289 return rv;
292 nsresult nsHtml5TreeOperation::AppendToDocument(
293 nsIContent* aNode, nsHtml5DocumentBuilder* aBuilder) {
294 MOZ_ASSERT(aBuilder);
295 MOZ_ASSERT(aBuilder->GetDocument() == aNode->OwnerDoc());
296 MOZ_ASSERT(aBuilder->IsInDocUpdate());
298 ErrorResult rv;
299 Document* doc = aBuilder->GetDocument();
300 doc->AppendChildTo(aNode, false, rv);
301 if (rv.ErrorCodeIs(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR)) {
302 aNode->SetParserHasNotified();
303 return NS_OK;
305 if (rv.Failed()) {
306 return rv.StealNSResult();
309 if (!doc->DOMNotificationsSuspended()) {
310 aNode->SetParserHasNotified();
311 MutationObservers::NotifyContentInserted(doc, aNode);
314 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
315 "Someone forgot to block scripts");
316 if (aNode->IsElement()) {
317 nsContentUtils::AddScriptRunner(
318 new nsDocElementCreatedNotificationRunner(doc));
320 return NS_OK;
323 static bool IsElementOrTemplateContent(nsINode* aNode) {
324 if (aNode) {
325 if (aNode->IsElement()) {
326 return true;
328 if (aNode->IsDocumentFragment()) {
329 // Check if the node is a template content.
330 nsIContent* fragHost = aNode->AsDocumentFragment()->GetHost();
331 if (fragHost && fragHost->IsTemplateElement()) {
332 return true;
336 return false;
339 void nsHtml5TreeOperation::Detach(nsIContent* aNode,
340 nsHtml5DocumentBuilder* aBuilder) {
341 MOZ_ASSERT(aBuilder);
342 MOZ_ASSERT(aBuilder->IsInDocUpdate());
343 nsCOMPtr<nsINode> parent = aNode->GetParentNode();
344 if (parent) {
345 nsHtml5OtherDocUpdate update(parent->OwnerDoc(), aBuilder->GetDocument());
346 parent->RemoveChildNode(aNode, true);
350 nsresult nsHtml5TreeOperation::AppendChildrenToNewParent(
351 nsIContent* aNode, nsIContent* aParent, nsHtml5DocumentBuilder* aBuilder) {
352 MOZ_ASSERT(aBuilder);
353 MOZ_ASSERT(aBuilder->IsInDocUpdate());
354 nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), aBuilder->GetDocument());
356 bool didAppend = false;
357 while (aNode->HasChildren()) {
358 nsCOMPtr<nsIContent> child = aNode->GetFirstChild();
359 aNode->RemoveChildNode(child, true);
361 ErrorResult rv;
362 aParent->AppendChildTo(child, false, rv);
363 if (rv.Failed()) {
364 return rv.StealNSResult();
366 didAppend = true;
368 if (didAppend) {
369 MutationObservers::NotifyContentAppended(aParent, aParent->GetLastChild());
371 return NS_OK;
374 nsresult nsHtml5TreeOperation::FosterParent(nsIContent* aNode,
375 nsIContent* aParent,
376 nsIContent* aTable,
377 nsHtml5DocumentBuilder* aBuilder) {
378 MOZ_ASSERT(aBuilder);
379 MOZ_ASSERT(aBuilder->IsInDocUpdate());
380 nsIContent* foster = aTable->GetParent();
382 if (IsElementOrTemplateContent(foster)) {
383 nsHtml5OtherDocUpdate update(foster->OwnerDoc(), aBuilder->GetDocument());
385 ErrorResult rv;
386 foster->InsertChildBefore(aNode, aTable, false, rv);
387 if (rv.Failed()) {
388 return rv.StealNSResult();
391 MutationObservers::NotifyContentInserted(foster, aNode);
392 return NS_OK;
395 return Append(aNode, aParent, aBuilder);
398 nsresult nsHtml5TreeOperation::AddAttributes(nsIContent* aNode,
399 nsHtml5HtmlAttributes* aAttributes,
400 nsHtml5DocumentBuilder* aBuilder) {
401 MOZ_ASSERT(aNode->IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::html));
403 Element* node = aNode->AsElement();
404 nsHtml5OtherDocUpdate update(node->OwnerDoc(), aBuilder->GetDocument());
406 int32_t len = aAttributes->getLength();
407 for (int32_t i = len; i > 0;) {
408 --i;
409 nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i);
410 int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
411 if (!node->HasAttr(nsuri, localName) &&
412 !(nsuri == kNameSpaceID_None && localName == nsGkAtoms::nonce)) {
413 nsString value; // Not Auto, because using it to hold nsStringBuffer*
414 aAttributes->getValueNoBoundsCheck(i).ToString(value);
415 node->SetAttr(nsuri, localName, aAttributes->getPrefixNoBoundsCheck(i),
416 value, true);
417 // XXX what to do with nsresult?
420 return NS_OK;
423 void nsHtml5TreeOperation::SetHTMLElementAttributes(
424 Element* aElement, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes) {
425 int32_t len = aAttributes->getLength();
426 aElement->TryReserveAttributeCount((uint32_t)len);
427 if (aAttributes->getDuplicateAttributeError()) {
428 aElement->SetParserHadDuplicateAttributeError();
430 for (int32_t i = 0; i < len; i++) {
431 nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
432 nsAtom* klass = val.MaybeAsAtom();
433 if (klass) {
434 aElement->SetClassAttrFromParser(klass);
435 } else {
436 nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i);
437 nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i);
438 int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
439 nsString value; // Not Auto, because using it to hold nsStringBuffer*
440 val.ToString(value);
441 aElement->SetAttr(nsuri, localName, prefix, value, false);
446 nsIContent* nsHtml5TreeOperation::CreateHTMLElement(
447 nsAtom* aName, nsHtml5HtmlAttributes* aAttributes, FromParser aFromParser,
448 nsNodeInfoManager* aNodeInfoManager, nsHtml5DocumentBuilder* aBuilder,
449 HTMLContentCreatorFunction aCreator) {
450 RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
451 aName, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE);
452 NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
454 Document* document = nodeInfo->GetDocument();
455 RefPtr<nsAtom> isAtom;
456 if (aAttributes) {
457 nsHtml5String is = aAttributes->getValue(nsHtml5AttributeName::ATTR_IS);
458 if (is) {
459 nsAutoString isValue;
460 is.ToString(isValue);
461 isAtom = NS_Atomize(isValue);
465 const bool isCustomElement = aCreator == NS_NewCustomElement || isAtom;
466 CustomElementDefinition* customElementDefinition = nullptr;
467 if (isCustomElement && aFromParser != FROM_PARSER_FRAGMENT) {
468 RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
469 RefPtr<nsAtom> typeAtom =
470 aCreator == NS_NewCustomElement ? tagAtom : isAtom;
472 MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName()));
473 customElementDefinition = nsContentUtils::LookupCustomElementDefinition(
474 document, nodeInfo->NameAtom(), nodeInfo->NamespaceID(), typeAtom);
477 auto DoCreateElement = [&](HTMLContentCreatorFunction aCreator) -> Element* {
478 nsCOMPtr<Element> newElement;
479 if (aCreator) {
480 newElement = aCreator(nodeInfo.forget(), aFromParser);
481 } else {
482 NS_NewHTMLElement(getter_AddRefs(newElement), nodeInfo.forget(),
483 aFromParser, isAtom, customElementDefinition);
486 MOZ_ASSERT(newElement, "Element creation created null pointer.");
487 Element* element = newElement.get();
488 aBuilder->HoldElement(newElement.forget());
490 if (auto* linkStyle = LinkStyle::FromNode(*element)) {
491 linkStyle->DisableUpdates();
494 if (!aAttributes) {
495 return element;
498 SetHTMLElementAttributes(element, aName, aAttributes);
499 return element;
502 if (customElementDefinition) {
503 // This will cause custom element constructors to run.
504 AutoSetThrowOnDynamicMarkupInsertionCounter
505 throwOnDynamicMarkupInsertionCounter(document);
506 nsHtml5AutoPauseUpdate autoPauseContentUpdate(aBuilder);
507 { nsAutoMicroTask mt; }
508 AutoCEReaction autoCEReaction(
509 document->GetDocGroup()->CustomElementReactionsStack(), nullptr);
510 return DoCreateElement(nullptr);
512 return DoCreateElement(isCustomElement ? nullptr : aCreator);
515 nsIContent* nsHtml5TreeOperation::CreateSVGElement(
516 nsAtom* aName, nsHtml5HtmlAttributes* aAttributes, FromParser aFromParser,
517 nsNodeInfoManager* aNodeInfoManager, nsHtml5DocumentBuilder* aBuilder,
518 SVGContentCreatorFunction aCreator) {
519 nsCOMPtr<nsIContent> newElement;
520 if (MOZ_LIKELY(aNodeInfoManager->SVGEnabled())) {
521 RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
522 aName, nullptr, kNameSpaceID_SVG, nsINode::ELEMENT_NODE);
523 MOZ_ASSERT(nodeInfo, "Got null nodeinfo.");
525 DebugOnly<nsresult> rv =
526 aCreator(getter_AddRefs(newElement), nodeInfo.forget(), aFromParser);
527 MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
528 } else {
529 RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
530 aName, nullptr, kNameSpaceID_disabled_SVG, nsINode::ELEMENT_NODE);
531 MOZ_ASSERT(nodeInfo, "Got null nodeinfo.");
533 // The mismatch between NS_NewXMLElement and SVGContentCreatorFunction
534 // argument types is annoying.
535 nsCOMPtr<Element> xmlElement;
536 DebugOnly<nsresult> rv =
537 NS_NewXMLElement(getter_AddRefs(xmlElement), nodeInfo.forget());
538 MOZ_ASSERT(NS_SUCCEEDED(rv) && xmlElement);
539 newElement = xmlElement;
542 Element* newContent = newElement->AsElement();
543 aBuilder->HoldElement(newElement.forget());
545 if (MOZ_UNLIKELY(aName == nsGkAtoms::style)) {
546 if (auto* linkStyle = LinkStyle::FromNode(*newContent)) {
547 linkStyle->DisableUpdates();
551 if (!aAttributes) {
552 return newContent;
555 if (aAttributes->getDuplicateAttributeError()) {
556 newContent->SetParserHadDuplicateAttributeError();
559 int32_t len = aAttributes->getLength();
560 for (int32_t i = 0; i < len; i++) {
561 nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
562 nsAtom* klass = val.MaybeAsAtom();
563 if (klass) {
564 newContent->SetClassAttrFromParser(klass);
565 } else {
566 nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i);
567 nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i);
568 int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
570 nsString value; // Not Auto, because using it to hold nsStringBuffer*
571 val.ToString(value);
572 newContent->SetAttr(nsuri, localName, prefix, value, false);
575 return newContent;
578 nsIContent* nsHtml5TreeOperation::CreateMathMLElement(
579 nsAtom* aName, nsHtml5HtmlAttributes* aAttributes,
580 nsNodeInfoManager* aNodeInfoManager, nsHtml5DocumentBuilder* aBuilder) {
581 nsCOMPtr<Element> newElement;
582 if (MOZ_LIKELY(aNodeInfoManager->MathMLEnabled())) {
583 RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
584 aName, nullptr, kNameSpaceID_MathML, nsINode::ELEMENT_NODE);
585 NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
587 DebugOnly<nsresult> rv =
588 NS_NewMathMLElement(getter_AddRefs(newElement), nodeInfo.forget());
589 MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
590 } else {
591 RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
592 aName, nullptr, kNameSpaceID_disabled_MathML, nsINode::ELEMENT_NODE);
593 NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
595 DebugOnly<nsresult> rv =
596 NS_NewXMLElement(getter_AddRefs(newElement), nodeInfo.forget());
597 MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
600 Element* newContent = newElement;
601 aBuilder->HoldElement(newElement.forget());
603 if (!aAttributes) {
604 return newContent;
607 if (aAttributes->getDuplicateAttributeError()) {
608 newContent->SetParserHadDuplicateAttributeError();
611 int32_t len = aAttributes->getLength();
612 for (int32_t i = 0; i < len; i++) {
613 nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
614 nsAtom* klass = val.MaybeAsAtom();
615 if (klass) {
616 newContent->SetClassAttrFromParser(klass);
617 } else {
618 nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i);
619 nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i);
620 int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
622 nsString value; // Not Auto, because using it to hold nsStringBuffer*
623 val.ToString(value);
624 newContent->SetAttr(nsuri, localName, prefix, value, false);
627 return newContent;
630 void nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aForm,
631 nsIContent* aParent) {
632 RefPtr formElement = HTMLFormElement::FromNodeOrNull(aForm);
633 NS_ASSERTION(formElement,
634 "The form element doesn't implement HTMLFormElement.");
635 nsCOMPtr<nsIFormControl> formControl = nsIFormControl::FromNodeOrNull(aNode);
636 if (formControl &&
637 formControl->ControlType() !=
638 FormControlType::FormAssociatedCustomElement &&
639 !aNode->AsElement()->HasAttr(nsGkAtoms::form) &&
640 aForm->SubtreeRoot() == aParent->SubtreeRoot()) {
641 formControl->SetForm(formElement);
642 } else if (auto* image = HTMLImageElement::FromNodeOrNull(aNode)) {
643 image->SetForm(formElement);
647 nsresult nsHtml5TreeOperation::FosterParentText(
648 nsIContent* aStackParent, char16_t* aBuffer, uint32_t aLength,
649 nsIContent* aTable, nsHtml5DocumentBuilder* aBuilder) {
650 MOZ_ASSERT(aBuilder);
651 MOZ_ASSERT(aBuilder->IsInDocUpdate());
652 nsresult rv = NS_OK;
653 nsIContent* foster = aTable->GetParent();
655 if (IsElementOrTemplateContent(foster)) {
656 nsHtml5OtherDocUpdate update(foster->OwnerDoc(), aBuilder->GetDocument());
658 nsIContent* previousSibling = aTable->GetPreviousSibling();
659 if (previousSibling && previousSibling->IsText()) {
660 return AppendTextToTextNode(aBuffer, aLength,
661 previousSibling->GetAsText(), aBuilder);
664 nsNodeInfoManager* nodeInfoManager =
665 aStackParent->OwnerDoc()->NodeInfoManager();
666 RefPtr<nsTextNode> text = new (nodeInfoManager) nsTextNode(nodeInfoManager);
667 NS_ASSERTION(text, "Infallible malloc failed?");
668 rv = text->SetText(aBuffer, aLength, false);
669 NS_ENSURE_SUCCESS(rv, rv);
671 ErrorResult error;
672 foster->InsertChildBefore(text, aTable, false, error);
673 if (error.Failed()) {
674 return error.StealNSResult();
677 MutationObservers::NotifyContentInserted(foster, text);
678 return rv;
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<Comment> comment = new (nodeInfoManager) Comment(nodeInfoManager);
689 NS_ASSERTION(comment, "Infallible malloc failed?");
690 nsresult rv = comment->SetText(aBuffer, aLength, false);
691 NS_ENSURE_SUCCESS(rv, rv);
693 return Append(comment, aParent, aBuilder);
696 nsresult nsHtml5TreeOperation::AppendCommentToDocument(
697 char16_t* aBuffer, int32_t aLength, nsHtml5DocumentBuilder* aBuilder) {
698 RefPtr<Comment> comment = new (aBuilder->GetNodeInfoManager())
699 Comment(aBuilder->GetNodeInfoManager());
700 NS_ASSERTION(comment, "Infallible malloc failed?");
701 nsresult rv = comment->SetText(aBuffer, aLength, false);
702 NS_ENSURE_SUCCESS(rv, rv);
704 return AppendToDocument(comment, aBuilder);
707 nsresult nsHtml5TreeOperation::AppendDoctypeToDocument(
708 nsAtom* aName, const nsAString& aPublicId, const nsAString& aSystemId,
709 nsHtml5DocumentBuilder* aBuilder) {
710 // Adapted from nsXMLContentSink
711 // Create a new doctype node
712 RefPtr<DocumentType> docType =
713 NS_NewDOMDocumentType(aBuilder->GetNodeInfoManager(), aName, aPublicId,
714 aSystemId, VoidString());
715 return AppendToDocument(docType, aBuilder);
718 nsIContent* nsHtml5TreeOperation::GetDocumentFragmentForTemplate(
719 nsIContent* aNode) {
720 auto* tempElem = static_cast<HTMLTemplateElement*>(aNode);
721 return tempElem->Content();
724 void nsHtml5TreeOperation::SetDocumentFragmentForTemplate(
725 nsIContent* aNode, nsIContent* aDocumentFragment) {
726 auto* tempElem = static_cast<HTMLTemplateElement*>(aNode);
727 tempElem->SetContent(static_cast<DocumentFragment*>(aDocumentFragment));
730 nsIContent* nsHtml5TreeOperation::GetFosterParent(nsIContent* aTable,
731 nsIContent* aStackParent) {
732 nsIContent* tableParent = aTable->GetParent();
733 return IsElementOrTemplateContent(tableParent) ? tableParent : aStackParent;
736 void nsHtml5TreeOperation::PreventScriptExecution(nsIContent* aNode) {
737 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
738 if (sele) {
739 sele->PreventExecution();
740 } else {
741 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
742 "Node didn't QI to script, but SVG wasn't disabled.");
746 void nsHtml5TreeOperation::DoneAddingChildren(nsIContent* aNode) {
747 aNode->DoneAddingChildren(aNode->HasParserNotified());
750 void nsHtml5TreeOperation::DoneCreatingElement(nsIContent* aNode) {
751 aNode->DoneCreatingElement();
754 void nsHtml5TreeOperation::SvgLoad(nsIContent* aNode) {
755 nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(aNode);
756 if (NS_FAILED(aNode->OwnerDoc()->Dispatch(event.forget()))) {
757 NS_WARNING("failed to dispatch svg load dispatcher");
761 void nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode) {
762 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
763 if (sele) {
764 // Make sure to serialize this script correctly, for nice round tripping.
765 sele->SetIsMalformed();
769 nsresult nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
770 nsIContent** aScriptElement,
771 bool* aInterrupted, bool* aStreamEnded) {
772 struct TreeOperationMatcher {
773 TreeOperationMatcher(nsHtml5TreeOpExecutor* aBuilder,
774 nsIContent** aScriptElement, bool* aInterrupted,
775 bool* aStreamEnded)
776 : mBuilder(aBuilder),
777 mScriptElement(aScriptElement),
778 mInterrupted(aInterrupted),
779 mStreamEnded(aStreamEnded) {}
781 nsHtml5TreeOpExecutor* mBuilder;
782 nsIContent** mScriptElement;
783 bool* mInterrupted;
784 bool* mStreamEnded;
786 nsresult operator()(const opAppend& aOperation) {
787 return Append(*(aOperation.mChild), *(aOperation.mParent),
788 aOperation.mFromNetwork, mBuilder);
791 nsresult operator()(const opDetach& aOperation) {
792 Detach(*(aOperation.mElement), mBuilder);
793 return NS_OK;
796 nsresult operator()(const opAppendChildrenToNewParent& aOperation) {
797 nsCOMPtr<nsIContent> node = *(aOperation.mOldParent);
798 nsIContent* parent = *(aOperation.mNewParent);
799 return AppendChildrenToNewParent(node, parent, mBuilder);
802 nsresult operator()(const opFosterParent& aOperation) {
803 nsIContent* node = *(aOperation.mChild);
804 nsIContent* parent = *(aOperation.mStackParent);
805 nsIContent* table = *(aOperation.mTable);
806 return FosterParent(node, parent, table, mBuilder);
809 nsresult operator()(const opAppendToDocument& aOperation) {
810 nsresult rv = AppendToDocument(*(aOperation.mContent), mBuilder);
811 mBuilder->PauseDocUpdate(mInterrupted);
812 return rv;
815 nsresult operator()(const opAddAttributes& aOperation) {
816 nsIContent* node = *(aOperation.mElement);
817 nsHtml5HtmlAttributes* attributes = aOperation.mAttributes;
818 return AddAttributes(node, attributes, mBuilder);
821 nsresult operator()(const nsHtml5DocumentMode& aMode) {
822 mBuilder->SetDocumentMode(aMode);
823 return NS_OK;
826 nsresult operator()(const opCreateHTMLElement& aOperation) {
827 nsIContent** target = aOperation.mContent;
828 HTMLContentCreatorFunction creator = aOperation.mCreator;
829 nsAtom* name = aOperation.mName;
830 nsHtml5HtmlAttributes* attributes = aOperation.mAttributes;
831 nsIContent* intendedParent =
832 aOperation.mIntendedParent ? *(aOperation.mIntendedParent) : nullptr;
834 // intendedParent == nullptr is a special case where the
835 // intended parent is the document.
836 nsNodeInfoManager* nodeInfoManager =
837 intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
838 : mBuilder->GetNodeInfoManager();
840 *target = CreateHTMLElement(name, attributes, aOperation.mFromNetwork,
841 nodeInfoManager, mBuilder, creator);
842 return NS_OK;
845 nsresult operator()(const opCreateSVGElement& aOperation) {
846 nsIContent** target = aOperation.mContent;
847 SVGContentCreatorFunction creator = aOperation.mCreator;
848 nsAtom* name = aOperation.mName;
849 nsHtml5HtmlAttributes* attributes = aOperation.mAttributes;
850 nsIContent* intendedParent =
851 aOperation.mIntendedParent ? *(aOperation.mIntendedParent) : nullptr;
853 // intendedParent == nullptr is a special case where the
854 // intended parent is the document.
855 nsNodeInfoManager* nodeInfoManager =
856 intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
857 : mBuilder->GetNodeInfoManager();
859 *target = CreateSVGElement(name, attributes, aOperation.mFromNetwork,
860 nodeInfoManager, mBuilder, creator);
861 return NS_OK;
864 nsresult operator()(const opCreateMathMLElement& aOperation) {
865 nsIContent** target = aOperation.mContent;
866 nsAtom* name = aOperation.mName;
867 nsHtml5HtmlAttributes* attributes = aOperation.mAttributes;
868 nsIContent* intendedParent =
869 aOperation.mIntendedParent ? *(aOperation.mIntendedParent) : nullptr;
871 // intendedParent == nullptr is a special case where the
872 // intended parent is the document.
873 nsNodeInfoManager* nodeInfoManager =
874 intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
875 : mBuilder->GetNodeInfoManager();
877 *target =
878 CreateMathMLElement(name, attributes, nodeInfoManager, mBuilder);
879 return NS_OK;
882 nsresult operator()(const opSetFormElement& aOperation) {
883 SetFormElement(*(aOperation.mContent), *(aOperation.mFormElement),
884 *(aOperation.mIntendedParent));
885 return NS_OK;
888 nsresult operator()(const opAppendText& aOperation) {
889 nsIContent* parent = *aOperation.mParent;
890 char16_t* buffer = aOperation.mBuffer;
891 uint32_t length = aOperation.mLength;
892 return AppendText(buffer, length, parent, mBuilder);
895 nsresult operator()(const opFosterParentText& aOperation) {
896 nsIContent* stackParent = *aOperation.mStackParent;
897 char16_t* buffer = aOperation.mBuffer;
898 uint32_t length = aOperation.mLength;
899 nsIContent* table = *aOperation.mTable;
900 return FosterParentText(stackParent, buffer, length, table, mBuilder);
903 nsresult operator()(const opAppendComment& aOperation) {
904 nsIContent* parent = *aOperation.mParent;
905 char16_t* buffer = aOperation.mBuffer;
906 uint32_t length = aOperation.mLength;
907 return AppendComment(parent, buffer, length, mBuilder);
910 nsresult operator()(const opAppendCommentToDocument& aOperation) {
911 char16_t* buffer = aOperation.mBuffer;
912 int32_t length = aOperation.mLength;
913 return AppendCommentToDocument(buffer, length, mBuilder);
916 nsresult operator()(const opAppendDoctypeToDocument& aOperation) {
917 nsAtom* name = aOperation.mName;
918 nsHtml5TreeOperationStringPair* pair = aOperation.mStringPair;
919 nsString publicId;
920 nsString systemId;
921 pair->Get(publicId, systemId);
922 return AppendDoctypeToDocument(name, publicId, systemId, mBuilder);
925 nsresult operator()(const opGetDocumentFragmentForTemplate& aOperation) {
926 nsIContent* node = *(aOperation.mTemplate);
927 *(aOperation.mFragHandle) = GetDocumentFragmentForTemplate(node);
928 return NS_OK;
931 nsresult operator()(const opSetDocumentFragmentForTemplate& aOperation) {
932 SetDocumentFragmentForTemplate(*aOperation.mTemplate,
933 *aOperation.mFragment);
934 return NS_OK;
937 nsresult operator()(const opGetShadowRootFromHost& aOperation) {
938 nsIContent* root = nsContentUtils::AttachDeclarativeShadowRoot(
939 *aOperation.mHost, aOperation.mShadowRootMode,
940 aOperation.mShadowRootIsClonable,
941 aOperation.mShadowRootIsSerializable,
942 aOperation.mShadowRootDelegatesFocus);
943 if (root) {
944 *aOperation.mFragHandle = root;
945 return NS_OK;
948 // We failed to attach a new shadow root, so instead attach a template
949 // element and return its content.
950 nsHtml5TreeOperation::Append(*aOperation.mTemplateNode, *aOperation.mHost,
951 mBuilder);
952 *aOperation.mFragHandle =
953 static_cast<HTMLTemplateElement*>(*aOperation.mTemplateNode)
954 ->Content();
955 nsContentUtils::LogSimpleConsoleError(
956 u"Failed to attach Declarative Shadow DOM."_ns, "DOM"_ns,
957 mBuilder->GetDocument()->IsInPrivateBrowsing(),
958 mBuilder->GetDocument()->IsInChromeDocShell());
959 return NS_OK;
962 nsresult operator()(const opGetFosterParent& aOperation) {
963 nsIContent* table = *(aOperation.mTable);
964 nsIContent* stackParent = *(aOperation.mStackParent);
965 nsIContent* fosterParent = GetFosterParent(table, stackParent);
966 *aOperation.mParentHandle = fosterParent;
967 return NS_OK;
970 nsresult operator()(const opMarkAsBroken& aOperation) {
971 return aOperation.mResult;
974 nsresult operator()(
975 const opRunScriptThatMayDocumentWriteOrBlock& aOperation) {
976 nsIContent* node = *(aOperation.mElement);
977 nsAHtml5TreeBuilderState* snapshot = aOperation.mBuilderState;
978 if (snapshot) {
979 mBuilder->InitializeDocWriteParserState(snapshot,
980 aOperation.mLineNumber);
982 *mScriptElement = node;
983 return NS_OK;
986 nsresult operator()(
987 const opRunScriptThatCannotDocumentWriteOrBlock& aOperation) {
988 mBuilder->RunScript(*(aOperation.mElement), false);
989 return NS_OK;
992 nsresult operator()(const opPreventScriptExecution& aOperation) {
993 PreventScriptExecution(*(aOperation.mElement));
994 return NS_OK;
997 nsresult operator()(const opDoneAddingChildren& aOperation) {
998 nsIContent* node = *(aOperation.mElement);
999 node->DoneAddingChildren(node->HasParserNotified());
1000 return NS_OK;
1003 nsresult operator()(const opDoneCreatingElement& aOperation) {
1004 DoneCreatingElement(*(aOperation.mElement));
1005 return NS_OK;
1008 nsresult operator()(const opUpdateCharsetSource& aOperation) {
1009 mBuilder->UpdateCharsetSource(aOperation.mCharsetSource);
1010 return NS_OK;
1013 nsresult operator()(const opCharsetSwitchTo& aOperation) {
1014 auto encoding = WrapNotNull(aOperation.mEncoding);
1015 mBuilder->NeedsCharsetSwitchTo(encoding, aOperation.mCharsetSource,
1016 (uint32_t)aOperation.mLineNumber);
1017 return NS_OK;
1020 nsresult operator()(const opUpdateStyleSheet& aOperation) {
1021 mBuilder->UpdateStyleSheet(*(aOperation.mElement));
1022 return NS_OK;
1025 nsresult operator()(const opProcessOfflineManifest& aOperation) {
1026 // TODO: remove this
1027 return NS_OK;
1030 nsresult operator()(const opMarkMalformedIfScript& aOperation) {
1031 MarkMalformedIfScript(*(aOperation.mElement));
1032 return NS_OK;
1035 nsresult operator()(const opStreamEnded& aOperation) {
1036 *mStreamEnded = true;
1037 return NS_OK;
1040 nsresult operator()(const opSetStyleLineNumber& aOperation) {
1041 nsIContent* node = *(aOperation.mContent);
1042 if (auto* linkStyle = LinkStyle::FromNode(*node)) {
1043 linkStyle->SetLineNumber(aOperation.mLineNumber);
1044 } else {
1045 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
1046 "Node didn't QI to style, but SVG wasn't disabled.");
1048 return NS_OK;
1051 nsresult operator()(
1052 const opSetScriptLineAndColumnNumberAndFreeze& aOperation) {
1053 nsIContent* node = *(aOperation.mContent);
1054 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node);
1055 if (sele) {
1056 sele->SetScriptLineNumber(aOperation.mLineNumber);
1057 sele->SetScriptColumnNumber(
1058 JS::ColumnNumberOneOrigin(aOperation.mColumnNumber));
1059 sele->FreezeExecutionAttrs(node->OwnerDoc());
1060 } else {
1061 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
1062 "Node didn't QI to script, but SVG wasn't disabled.");
1064 return NS_OK;
1067 nsresult operator()(const opSvgLoad& aOperation) {
1068 SvgLoad(*(aOperation.mElement));
1069 return NS_OK;
1072 nsresult operator()(const opMaybeComplainAboutCharset& aOperation) {
1073 char* msgId = aOperation.mMsgId;
1074 bool error = aOperation.mError;
1075 int32_t lineNumber = aOperation.mLineNumber;
1076 mBuilder->MaybeComplainAboutCharset(msgId, error, (uint32_t)lineNumber);
1077 return NS_OK;
1080 nsresult operator()(const opMaybeComplainAboutDeepTree& aOperation) {
1081 mBuilder->MaybeComplainAboutDeepTree((uint32_t)aOperation.mLineNumber);
1082 return NS_OK;
1085 nsresult operator()(const opAddClass& aOperation) {
1086 Element* element = (*(aOperation.mElement))->AsElement();
1087 char16_t* str = aOperation.mClass;
1088 nsDependentString depStr(str);
1089 // See viewsource.css for the possible classes
1090 nsAutoString klass;
1091 element->GetAttr(nsGkAtoms::_class, klass);
1092 if (!klass.IsEmpty()) {
1093 klass.Append(' ');
1094 klass.Append(depStr);
1095 element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
1096 } else {
1097 element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, depStr, true);
1099 return NS_OK;
1102 nsresult operator()(const opAddViewSourceHref& aOperation) {
1103 Element* element = (*aOperation.mElement)->AsElement();
1104 char16_t* buffer = aOperation.mBuffer;
1105 int32_t length = aOperation.mLength;
1106 nsDependentString relative(buffer, length);
1108 Document* doc = mBuilder->GetDocument();
1110 auto encoding = doc->GetDocumentCharacterSet();
1111 nsCOMPtr<nsIURI> uri;
1112 nsresult rv = NS_NewURI(getter_AddRefs(uri), relative, encoding,
1113 mBuilder->GetViewSourceBaseURI());
1114 NS_ENSURE_SUCCESS(rv, NS_OK);
1116 // Reuse the fix for bug 467852
1117 // URLs that execute script (e.g. "javascript:" URLs) should just be
1118 // ignored. There's nothing reasonable we can do with them, and allowing
1119 // them to execute in the context of the view-source window presents a
1120 // security risk. Just return the empty string in this case.
1121 bool openingExecutesScript = false;
1122 rv = NS_URIChainHasFlags(uri,
1123 nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT,
1124 &openingExecutesScript);
1125 if (NS_FAILED(rv) || openingExecutesScript) {
1126 return NS_OK;
1129 nsAutoCString viewSourceUrl;
1131 // URLs that return data (e.g. "http:" URLs) should be prefixed with
1132 // "view-source:". URLs that don't return data should just be returned
1133 // undecorated.
1134 if (!nsContentUtils::IsExternalProtocol(uri)) {
1135 viewSourceUrl.AssignLiteral("view-source:");
1138 nsAutoCString spec;
1139 rv = uri->GetSpec(spec);
1140 NS_ENSURE_SUCCESS(rv, rv);
1142 viewSourceUrl.Append(spec);
1144 nsAutoString utf16;
1145 CopyUTF8toUTF16(viewSourceUrl, utf16);
1147 element->SetAttr(kNameSpaceID_None, nsGkAtoms::href, utf16, true);
1148 return NS_OK;
1151 nsresult operator()(const opAddViewSourceBase& aOperation) {
1152 nsDependentString baseUrl(aOperation.mBuffer, aOperation.mLength);
1153 mBuilder->AddBase(baseUrl);
1154 return NS_OK;
1157 nsresult operator()(const opAddErrorType& aOperation) {
1158 Element* element = (*(aOperation.mElement))->AsElement();
1159 char* msgId = aOperation.mMsgId;
1160 nsAtom* atom = aOperation.mName;
1161 nsAtom* otherAtom = aOperation.mOther;
1162 // See viewsource.css for the possible classes in addition to "error".
1163 nsAutoString klass;
1164 element->GetAttr(nsGkAtoms::_class, klass);
1165 if (!klass.IsEmpty()) {
1166 klass.AppendLiteral(" error");
1167 element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
1168 } else {
1169 element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, u"error"_ns,
1170 true);
1173 nsresult rv;
1174 nsAutoString message;
1175 if (otherAtom) {
1176 rv = nsContentUtils::FormatLocalizedString(
1177 message, nsContentUtils::eHTMLPARSER_PROPERTIES, msgId,
1178 nsDependentAtomString(atom), nsDependentAtomString(otherAtom));
1179 NS_ENSURE_SUCCESS(rv, NS_OK);
1180 } else if (atom) {
1181 rv = nsContentUtils::FormatLocalizedString(
1182 message, nsContentUtils::eHTMLPARSER_PROPERTIES, msgId,
1183 nsDependentAtomString(atom));
1184 NS_ENSURE_SUCCESS(rv, NS_OK);
1185 } else {
1186 rv = nsContentUtils::GetLocalizedString(
1187 nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, message);
1188 NS_ENSURE_SUCCESS(rv, NS_OK);
1191 nsAutoString title;
1192 element->GetAttr(nsGkAtoms::title, title);
1193 if (!title.IsEmpty()) {
1194 title.Append('\n');
1195 title.Append(message);
1196 element->SetAttr(kNameSpaceID_None, nsGkAtoms::title, title, true);
1197 } else {
1198 element->SetAttr(kNameSpaceID_None, nsGkAtoms::title, message, true);
1200 return rv;
1203 nsresult operator()(const opAddLineNumberId& aOperation) {
1204 Element* element = (*(aOperation.mElement))->AsElement();
1205 int32_t lineNumber = aOperation.mLineNumber;
1206 nsAutoString val(u"line"_ns);
1207 val.AppendInt(lineNumber);
1208 element->SetAttr(kNameSpaceID_None, nsGkAtoms::id, val, true);
1209 return NS_OK;
1212 nsresult operator()(const opShallowCloneInto& aOperation) {
1213 nsIContent* src = *aOperation.mSrc;
1214 ErrorResult rv;
1215 RefPtr<nsINode> clone = src->CloneNode(false, rv);
1216 if (NS_WARN_IF(rv.Failed())) {
1217 return rv.StealNSResult();
1219 *aOperation.mDst = clone->AsContent();
1220 mBuilder->HoldElement(clone.forget().downcast<nsIContent>());
1221 return Append(*aOperation.mDst, *aOperation.mIntendedParent,
1222 aOperation.mFromParser, mBuilder);
1225 nsresult operator()(const opStartLayout& aOperation) {
1226 mBuilder->StartLayout(
1227 mInterrupted); // this causes a notification flush anyway
1228 return NS_OK;
1231 nsresult operator()(const opEnableEncodingMenu& aOperation) {
1232 Document* doc = mBuilder->GetDocument();
1233 doc->EnableEncodingMenu();
1234 return NS_OK;
1237 nsresult operator()(const uninitialized& aOperation) {
1238 MOZ_CRASH("uninitialized");
1239 return NS_OK;
1243 return mOperation.match(TreeOperationMatcher(aBuilder, aScriptElement,
1244 aInterrupted, aStreamEnded));