nsHtml5TreeOperation.cpp (46672B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 sw=2 et tw=78: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "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 "nsIFormControl.h" 36 #include "nsIMutationObserver.h" 37 #include "nsINode.h" 38 #include "nsIProtocolHandler.h" 39 #include "nsIScriptElement.h" 40 #include "nsISupportsImpl.h" 41 #include "nsIURI.h" 42 #include "nsNetUtil.h" 43 #include "nsTextNode.h" 44 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin 45 46 using namespace mozilla; 47 using namespace mozilla::dom; 48 49 // If you are adding fields to a tree op and this static assert fails, 50 // please consider reordering the fields to avoid excess padding or, 51 // if that doesn't help, splitting a rare operation into multiple 52 // tree ops before allowing the size of all operations to get larger. 53 static_assert(sizeof(nsHtml5TreeOperation) <= 56); 54 55 /** 56 * Helper class that opens a notification batch if the current doc 57 * is different from the executor doc. 58 */ 59 class MOZ_STACK_CLASS nsHtml5OtherDocUpdate { 60 public: 61 nsHtml5OtherDocUpdate(Document* aCurrentDoc, Document* aExecutorDoc) { 62 MOZ_ASSERT(aCurrentDoc, "Node has no doc?"); 63 MOZ_ASSERT(aExecutorDoc, "Executor has no doc?"); 64 if (MOZ_LIKELY(aCurrentDoc == aExecutorDoc)) { 65 mDocument = nullptr; 66 } else { 67 mDocument = aCurrentDoc; 68 aCurrentDoc->BeginUpdate(); 69 } 70 } 71 72 ~nsHtml5OtherDocUpdate() { 73 if (MOZ_UNLIKELY(mDocument)) { 74 mDocument->EndUpdate(); 75 } 76 } 77 78 private: 79 RefPtr<Document> mDocument; 80 }; 81 82 nsHtml5TreeOperation::nsHtml5TreeOperation() : mOperation(uninitialized()) { 83 MOZ_COUNT_CTOR(nsHtml5TreeOperation); 84 } 85 86 nsHtml5TreeOperation::~nsHtml5TreeOperation() { 87 MOZ_COUNT_DTOR(nsHtml5TreeOperation); 88 89 struct TreeOperationMatcher { 90 void operator()(const opAppend& aOperation) {} 91 92 void operator()(const opDetach& aOperation) {} 93 94 void operator()(const opAppendChildrenToNewParent& aOperation) {} 95 96 void operator()(const opFosterParent& aOperation) {} 97 98 void operator()(const opAppendToDocument& aOperation) {} 99 100 void operator()(const opAddAttributes& aOperation) { 101 delete aOperation.mAttributes; 102 } 103 104 void operator()(const nsHtml5DocumentMode& aMode) {} 105 106 void operator()(const opCreateHTMLElement& aOperation) { 107 aOperation.mName->Release(); 108 delete aOperation.mAttributes; 109 } 110 111 void operator()(const opCreateSVGElement& aOperation) { 112 aOperation.mName->Release(); 113 delete aOperation.mAttributes; 114 } 115 116 void operator()(const opCreateMathMLElement& aOperation) { 117 aOperation.mName->Release(); 118 delete aOperation.mAttributes; 119 } 120 121 void operator()(const opSetFormElement& aOperation) {} 122 123 void operator()(const opAppendText& aOperation) { 124 delete[] aOperation.mBuffer; 125 } 126 127 void operator()(const opFosterParentText& aOperation) { 128 delete[] aOperation.mBuffer; 129 } 130 131 void operator()(const opAppendComment& aOperation) { 132 delete[] aOperation.mBuffer; 133 } 134 135 void operator()(const opAppendCommentToDocument& aOperation) { 136 delete[] aOperation.mBuffer; 137 } 138 139 void operator()(const opAppendDoctypeToDocument& aOperation) { 140 aOperation.mName->Release(); 141 delete aOperation.mStringPair; 142 } 143 144 void operator()(const opGetDocumentFragmentForTemplate& aOperation) {} 145 146 void operator()(const opSetDocumentFragmentForTemplate& aOperation) {} 147 148 void operator()(const opGetShadowRootFromHost& aOperation) {} 149 150 void operator()(const opGetFosterParent& aOperation) {} 151 152 void operator()(const opMarkAsBroken& aOperation) {} 153 154 void operator()(const opRunScriptThatMayDocumentWriteOrBlock& aOperation) {} 155 156 void operator()( 157 const opRunScriptThatCannotDocumentWriteOrBlock& aOperation) {} 158 159 void operator()(const opPreventScriptExecution& aOperation) {} 160 161 void operator()(const opDoneAddingChildren& aOperation) {} 162 163 void operator()(const opDoneCreatingElement& aOperation) {} 164 165 void operator()(const opUpdateCharsetSource& aOperation) {} 166 167 void operator()(const opCharsetSwitchTo& aOperation) {} 168 169 void operator()(const opUpdateStyleSheet& aOperation) {} 170 171 void operator()(const opProcessOfflineManifest& aOperation) { 172 free(aOperation.mUrl); 173 } 174 175 void operator()(const opMarkMalformedIfScript& aOperation) {} 176 177 void operator()(const opStreamEnded& aOperation) {} 178 179 void operator()(const opSetStyleLineNumber& aOperation) {} 180 181 void operator()(const opSetScriptLineAndColumnNumberAndFreeze& aOperation) { 182 } 183 184 void operator()(const opSvgLoad& aOperation) {} 185 186 void operator()(const opMaybeComplainAboutCharset& aOperation) {} 187 188 void operator()(const opMaybeComplainAboutDeepTree& aOperation) {} 189 190 void operator()(const opAddClass& aOperation) {} 191 192 void operator()(const opAddViewSourceHref& aOperation) { 193 delete[] aOperation.mBuffer; 194 } 195 196 void operator()(const opAddViewSourceBase& aOperation) { 197 delete[] aOperation.mBuffer; 198 } 199 200 void operator()(const opAddErrorType& aOperation) { 201 if (aOperation.mName) { 202 aOperation.mName->Release(); 203 } 204 if (aOperation.mOther) { 205 aOperation.mOther->Release(); 206 } 207 } 208 209 void operator()(const opAddLineNumberId& aOperation) {} 210 211 void operator()(const opShallowCloneInto& aOperation) {} 212 213 void operator()(const opStartLayout& aOperation) {} 214 215 void operator()(const opEnableEncodingMenu& aOperation) {} 216 217 void operator()(const opMicrotaskCheckpoint& aOperation) {} 218 219 void operator()(const uninitialized& aOperation) { 220 NS_WARNING("Uninitialized tree op."); 221 } 222 }; 223 224 mOperation.match(TreeOperationMatcher()); 225 } 226 227 nsresult nsHtml5TreeOperation::AppendTextToTextNode( 228 const char16_t* aBuffer, uint32_t aLength, Text* aTextNode, 229 nsHtml5DocumentBuilder* aBuilder) { 230 MOZ_ASSERT(aTextNode, "Got null text node."); 231 MOZ_ASSERT(aBuilder); 232 MOZ_ASSERT(aBuilder->IsInDocUpdate()); 233 uint32_t oldLength = aTextNode->TextLength(); 234 CharacterDataChangeInfo info = {true, oldLength, oldLength, aLength, 235 MutationEffectOnScript::KeepTrustWorthiness}; 236 MutationObservers::NotifyCharacterDataWillChange(aTextNode, info); 237 238 nsresult rv = aTextNode->AppendText(aBuffer, aLength, false); 239 NS_ENSURE_SUCCESS(rv, rv); 240 241 MutationObservers::NotifyCharacterDataChanged(aTextNode, info); 242 return rv; 243 } 244 245 nsresult nsHtml5TreeOperation::AppendText(const char16_t* aBuffer, 246 uint32_t aLength, nsIContent* aParent, 247 nsHtml5DocumentBuilder* aBuilder) { 248 nsresult rv = NS_OK; 249 nsIContent* lastChild = aParent->GetLastChild(); 250 if (lastChild && lastChild->IsText()) { 251 nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), aBuilder->GetDocument()); 252 return AppendTextToTextNode(aBuffer, aLength, lastChild->GetAsText(), 253 aBuilder); 254 } 255 256 nsNodeInfoManager* nodeInfoManager = aParent->OwnerDoc()->NodeInfoManager(); 257 RefPtr<nsTextNode> text = new (nodeInfoManager) nsTextNode(nodeInfoManager); 258 NS_ASSERTION(text, "Infallible malloc failed?"); 259 rv = text->SetText(aBuffer, aLength, false); 260 NS_ENSURE_SUCCESS(rv, rv); 261 262 return Append(text, aParent, aBuilder); 263 } 264 265 nsresult nsHtml5TreeOperation::Append(nsIContent* aNode, nsIContent* aParent, 266 nsHtml5DocumentBuilder* aBuilder) { 267 MOZ_ASSERT(aBuilder); 268 MOZ_ASSERT(aBuilder->IsInDocUpdate()); 269 ErrorResult rv; 270 Document* ownerDoc = aParent->OwnerDoc(); 271 nsHtml5OtherDocUpdate update(ownerDoc, aBuilder->GetDocument()); 272 aParent->AppendChildTo(aNode, false, rv); 273 if (!rv.Failed() && !ownerDoc->DOMNotificationsSuspended()) { 274 aNode->SetParserHasNotified(); 275 MutationObservers::NotifyContentAppended( 276 aParent, aNode, {MutationEffectOnScript::KeepTrustWorthiness}); 277 } 278 return rv.StealNSResult(); 279 } 280 281 nsresult nsHtml5TreeOperation::Append(nsIContent* aNode, nsIContent* aParent, 282 FromParser aFromParser, 283 nsHtml5DocumentBuilder* aBuilder) { 284 Maybe<nsHtml5AutoPauseUpdate> autoPause; 285 Maybe<AutoCEReaction> autoCEReaction; 286 DocGroup* docGroup = aParent->OwnerDoc()->GetDocGroup(); 287 if (docGroup && aFromParser != FROM_PARSER_FRAGMENT) { 288 autoCEReaction.emplace(docGroup->CustomElementReactionsStack(), nullptr); 289 } 290 nsresult rv = Append(aNode, aParent, aBuilder); 291 // Pause the parser only when there are reactions to be invoked to avoid 292 // pausing parsing too aggressive. 293 if (autoCEReaction.isSome() && docGroup && 294 docGroup->CustomElementReactionsStack() 295 ->IsElementQueuePushedForCurrentRecursionDepth()) { 296 autoPause.emplace(aBuilder); 297 } 298 return rv; 299 } 300 301 nsresult nsHtml5TreeOperation::AppendToDocument( 302 nsIContent* aNode, nsHtml5DocumentBuilder* aBuilder) { 303 MOZ_ASSERT(aBuilder); 304 MOZ_ASSERT(aBuilder->GetDocument() == aNode->OwnerDoc()); 305 MOZ_ASSERT(aBuilder->IsInDocUpdate()); 306 307 ErrorResult rv; 308 Document* doc = aBuilder->GetDocument(); 309 doc->AppendChildTo(aNode, false, rv); 310 if (rv.ErrorCodeIs(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR)) { 311 aNode->SetParserHasNotified(); 312 return NS_OK; 313 } 314 if (rv.Failed()) { 315 return rv.StealNSResult(); 316 } 317 318 if (!doc->DOMNotificationsSuspended()) { 319 aNode->SetParserHasNotified(); 320 MutationObservers::NotifyContentInserted( 321 doc, aNode, {MutationEffectOnScript::KeepTrustWorthiness}); 322 } 323 324 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), 325 "Someone forgot to block scripts"); 326 if (aNode->IsElement()) { 327 nsContentUtils::AddScriptRunner( 328 new nsDocElementCreatedNotificationRunner(doc)); 329 } 330 return NS_OK; 331 } 332 333 static bool IsElementOrTemplateContent(nsINode* aNode) { 334 if (aNode) { 335 if (aNode->IsElement()) { 336 return true; 337 } 338 if (aNode->IsDocumentFragment()) { 339 // Check if the node is a template content. 340 nsIContent* fragHost = aNode->AsDocumentFragment()->GetHost(); 341 if (fragHost && fragHost->IsTemplateElement()) { 342 return true; 343 } 344 } 345 } 346 return false; 347 } 348 349 void nsHtml5TreeOperation::Detach(nsIContent* aNode, 350 nsHtml5DocumentBuilder* aBuilder) { 351 MOZ_ASSERT(aBuilder); 352 MOZ_ASSERT(aBuilder->IsInDocUpdate()); 353 nsCOMPtr<nsINode> parent = aNode->GetParentNode(); 354 if (parent) { 355 nsHtml5OtherDocUpdate update(parent->OwnerDoc(), aBuilder->GetDocument()); 356 parent->RemoveChildNode(aNode, true, nullptr, nullptr, 357 MutationEffectOnScript::KeepTrustWorthiness); 358 } 359 } 360 361 nsresult nsHtml5TreeOperation::AppendChildrenToNewParent( 362 nsIContent* aNode, nsIContent* aParent, nsHtml5DocumentBuilder* aBuilder) { 363 MOZ_ASSERT(aBuilder); 364 MOZ_ASSERT(aBuilder->IsInDocUpdate()); 365 nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), aBuilder->GetDocument()); 366 367 bool didAppend = false; 368 while (aNode->HasChildren()) { 369 nsCOMPtr<nsIContent> child = aNode->GetFirstChild(); 370 aNode->RemoveChildNode(child, true, nullptr, nullptr, 371 MutationEffectOnScript::KeepTrustWorthiness); 372 373 ErrorResult rv; 374 aParent->AppendChildTo(child, false, rv); 375 if (rv.Failed()) { 376 return rv.StealNSResult(); 377 } 378 didAppend = true; 379 } 380 if (didAppend) { 381 MutationObservers::NotifyContentAppended( 382 aParent, aParent->GetLastChild(), 383 {MutationEffectOnScript::KeepTrustWorthiness}); 384 } 385 return NS_OK; 386 } 387 388 nsresult nsHtml5TreeOperation::FosterParent(nsIContent* aNode, 389 nsIContent* aParent, 390 nsIContent* aTable, 391 nsHtml5DocumentBuilder* aBuilder) { 392 MOZ_ASSERT(aBuilder); 393 MOZ_ASSERT(aBuilder->IsInDocUpdate()); 394 nsIContent* foster = aTable->GetParent(); 395 396 if (IsElementOrTemplateContent(foster)) { 397 nsHtml5OtherDocUpdate update(foster->OwnerDoc(), aBuilder->GetDocument()); 398 399 ErrorResult rv; 400 foster->InsertChildBefore(aNode, aTable, false, rv); 401 if (rv.Failed()) { 402 return rv.StealNSResult(); 403 } 404 405 MutationObservers::NotifyContentInserted( 406 foster, aNode, {MutationEffectOnScript::KeepTrustWorthiness}); 407 return NS_OK; 408 } 409 410 return Append(aNode, aParent, aBuilder); 411 } 412 413 nsresult nsHtml5TreeOperation::AddAttributes(nsIContent* aNode, 414 nsHtml5HtmlAttributes* aAttributes, 415 nsHtml5DocumentBuilder* aBuilder) { 416 MOZ_ASSERT(aNode->IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::html)); 417 418 Element* node = aNode->AsElement(); 419 nsHtml5OtherDocUpdate update(node->OwnerDoc(), aBuilder->GetDocument()); 420 421 int32_t len = aAttributes->getLength(); 422 for (int32_t i = len; i > 0;) { 423 --i; 424 nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i); 425 int32_t nsuri = aAttributes->getURINoBoundsCheck(i); 426 if (!node->HasAttr(nsuri, localName) && 427 !(nsuri == kNameSpaceID_None && localName == nsGkAtoms::nonce)) { 428 nsHtml5String val = aAttributes->getValueNoBoundsCheck(i); 429 nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i); 430 431 // If value is already an atom, use it directly to avoid string 432 // allocation. 433 nsAtom* valAtom = val.MaybeAsAtom(); 434 if (valAtom) { 435 node->SetAttr(nsuri, localName, prefix, valAtom, nullptr, true); 436 } else { 437 nsString value; // Not Auto, because using it to hold nsStringBuffer* 438 val.ToString(value); 439 node->SetAttr(nsuri, localName, prefix, value, true); 440 } 441 // XXX what to do with nsresult? 442 } 443 } 444 return NS_OK; 445 } 446 447 void nsHtml5TreeOperation::SetHTMLElementAttributes( 448 Element* aElement, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes) { 449 int32_t len = aAttributes->getLength(); 450 aElement->TryReserveAttributeCount((uint32_t)len); 451 if (aAttributes->getDuplicateAttributeError()) { 452 aElement->SetParserHadDuplicateAttributeError(); 453 } 454 for (int32_t i = 0; i < len; i++) { 455 nsHtml5String val = aAttributes->getValueNoBoundsCheck(i); 456 nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i); 457 if (localName == nsGkAtoms::_class) { 458 nsAtom* klass = val.MaybeAsAtom(); 459 if (klass) { 460 aElement->SetClassAttrFromParser(klass); 461 continue; 462 } 463 } 464 465 nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i); 466 int32_t nsuri = aAttributes->getURINoBoundsCheck(i); 467 468 // If value is already an atom, use it directly to avoid string allocation. 469 nsAtom* valAtom = val.MaybeAsAtom(); 470 if (valAtom) { 471 aElement->SetAttr(nsuri, localName, prefix, valAtom, nullptr, false); 472 } else { 473 nsString value; // Not Auto, because using it to hold nsStringBuffer* 474 val.ToString(value); 475 aElement->SetAttr(nsuri, localName, prefix, value, false); 476 } 477 } 478 } 479 480 nsIContent* nsHtml5TreeOperation::CreateHTMLElement( 481 nsAtom* aName, nsHtml5HtmlAttributes* aAttributes, FromParser aFromParser, 482 nsNodeInfoManager* aNodeInfoManager, nsHtml5DocumentBuilder* aBuilder, 483 HTMLContentCreatorFunction aCreator) { 484 RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo( 485 aName, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE); 486 NS_ASSERTION(nodeInfo, "Got null nodeinfo."); 487 488 Document* document = nodeInfo->GetDocument(); 489 RefPtr<nsAtom> isAtom; 490 if (aAttributes) { 491 nsHtml5String is = aAttributes->getValue(nsHtml5AttributeName::ATTR_IS); 492 if (is) { 493 nsAutoString isValue; 494 is.ToString(isValue); 495 isAtom = NS_Atomize(isValue); 496 } 497 } 498 499 const bool isCustomElement = aCreator == NS_NewCustomElement || isAtom; 500 CustomElementDefinition* customElementDefinition = nullptr; 501 if (isCustomElement && aFromParser != FROM_PARSER_FRAGMENT) { 502 RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom(); 503 RefPtr<nsAtom> typeAtom = 504 aCreator == NS_NewCustomElement ? tagAtom : isAtom; 505 506 MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())); 507 customElementDefinition = nsContentUtils::LookupCustomElementDefinition( 508 document, nodeInfo->NameAtom(), nodeInfo->NamespaceID(), typeAtom); 509 } 510 511 auto DoCreateElement = [&](HTMLContentCreatorFunction aCreator) -> Element* { 512 nsCOMPtr<Element> newElement; 513 if (aCreator) { 514 newElement = aCreator(nodeInfo.forget(), aFromParser); 515 } else { 516 NS_NewHTMLElement(getter_AddRefs(newElement), nodeInfo.forget(), 517 aFromParser, isAtom, customElementDefinition); 518 } 519 520 MOZ_ASSERT(newElement, "Element creation created null pointer."); 521 Element* element = newElement.get(); 522 aBuilder->HoldElement(newElement.forget()); 523 524 if (auto* linkStyle = LinkStyle::FromNode(*element)) { 525 linkStyle->DisableUpdates(); 526 } 527 528 if (!aAttributes) { 529 return element; 530 } 531 532 SetHTMLElementAttributes(element, aName, aAttributes); 533 return element; 534 }; 535 536 if (customElementDefinition) { 537 // This will cause custom element constructors to run. 538 AutoSetThrowOnDynamicMarkupInsertionCounter 539 throwOnDynamicMarkupInsertionCounter(document); 540 nsHtml5AutoPauseUpdate autoPauseContentUpdate(aBuilder); 541 { 542 nsAutoMicroTask mt; 543 } 544 AutoCEReaction autoCEReaction( 545 document->GetDocGroup()->CustomElementReactionsStack(), nullptr); 546 return DoCreateElement(nullptr); 547 } 548 return DoCreateElement(isCustomElement ? nullptr : aCreator); 549 } 550 551 nsIContent* nsHtml5TreeOperation::CreateSVGElement( 552 nsAtom* aName, nsHtml5HtmlAttributes* aAttributes, FromParser aFromParser, 553 nsNodeInfoManager* aNodeInfoManager, nsHtml5DocumentBuilder* aBuilder, 554 SVGContentCreatorFunction aCreator) { 555 nsCOMPtr<nsIContent> newElement; 556 if (MOZ_LIKELY(aNodeInfoManager->SVGEnabled())) { 557 RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo( 558 aName, nullptr, kNameSpaceID_SVG, nsINode::ELEMENT_NODE); 559 MOZ_ASSERT(nodeInfo, "Got null nodeinfo."); 560 561 DebugOnly<nsresult> rv = 562 aCreator(getter_AddRefs(newElement), nodeInfo.forget(), aFromParser); 563 MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement); 564 } else { 565 RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo( 566 aName, nullptr, kNameSpaceID_disabled_SVG, nsINode::ELEMENT_NODE); 567 MOZ_ASSERT(nodeInfo, "Got null nodeinfo."); 568 569 // The mismatch between NS_NewXMLElement and SVGContentCreatorFunction 570 // argument types is annoying. 571 nsCOMPtr<Element> xmlElement; 572 DebugOnly<nsresult> rv = 573 NS_NewXMLElement(getter_AddRefs(xmlElement), nodeInfo.forget()); 574 MOZ_ASSERT(NS_SUCCEEDED(rv) && xmlElement); 575 newElement = xmlElement; 576 } 577 578 Element* newContent = newElement->AsElement(); 579 aBuilder->HoldElement(newElement.forget()); 580 581 if (MOZ_UNLIKELY(aName == nsGkAtoms::style)) { 582 if (auto* linkStyle = LinkStyle::FromNode(*newContent)) { 583 linkStyle->DisableUpdates(); 584 } 585 } 586 587 if (!aAttributes) { 588 return newContent; 589 } 590 591 if (aAttributes->getDuplicateAttributeError()) { 592 newContent->SetParserHadDuplicateAttributeError(); 593 } 594 595 int32_t len = aAttributes->getLength(); 596 for (int32_t i = 0; i < len; i++) { 597 nsHtml5String val = aAttributes->getValueNoBoundsCheck(i); 598 nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i); 599 if (localName == nsGkAtoms::_class) { 600 nsAtom* klass = val.MaybeAsAtom(); 601 if (klass) { 602 newContent->SetClassAttrFromParser(klass); 603 continue; 604 } 605 } 606 607 nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i); 608 int32_t nsuri = aAttributes->getURINoBoundsCheck(i); 609 610 // If value is already an atom, use it directly to avoid string allocation. 611 nsAtom* valAtom = val.MaybeAsAtom(); 612 if (valAtom) { 613 newContent->SetAttr(nsuri, localName, prefix, valAtom, nullptr, false); 614 } else { 615 nsString value; // Not Auto, because using it to hold nsStringBuffer* 616 val.ToString(value); 617 newContent->SetAttr(nsuri, localName, prefix, value, false); 618 } 619 } 620 return newContent; 621 } 622 623 nsIContent* nsHtml5TreeOperation::CreateMathMLElement( 624 nsAtom* aName, nsHtml5HtmlAttributes* aAttributes, 625 nsNodeInfoManager* aNodeInfoManager, nsHtml5DocumentBuilder* aBuilder) { 626 nsCOMPtr<Element> newElement; 627 if (MOZ_LIKELY(aNodeInfoManager->MathMLEnabled())) { 628 RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo( 629 aName, nullptr, kNameSpaceID_MathML, nsINode::ELEMENT_NODE); 630 NS_ASSERTION(nodeInfo, "Got null nodeinfo."); 631 632 DebugOnly<nsresult> rv = 633 NS_NewMathMLElement(getter_AddRefs(newElement), nodeInfo.forget()); 634 MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement); 635 } else { 636 RefPtr<NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo( 637 aName, nullptr, kNameSpaceID_disabled_MathML, nsINode::ELEMENT_NODE); 638 NS_ASSERTION(nodeInfo, "Got null nodeinfo."); 639 640 DebugOnly<nsresult> rv = 641 NS_NewXMLElement(getter_AddRefs(newElement), nodeInfo.forget()); 642 MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement); 643 } 644 645 Element* newContent = newElement; 646 aBuilder->HoldElement(newElement.forget()); 647 648 if (!aAttributes) { 649 return newContent; 650 } 651 652 if (aAttributes->getDuplicateAttributeError()) { 653 newContent->SetParserHadDuplicateAttributeError(); 654 } 655 656 int32_t len = aAttributes->getLength(); 657 for (int32_t i = 0; i < len; i++) { 658 nsHtml5String val = aAttributes->getValueNoBoundsCheck(i); 659 nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i); 660 if (localName == nsGkAtoms::_class) { 661 nsAtom* klass = val.MaybeAsAtom(); 662 if (klass) { 663 newContent->SetClassAttrFromParser(klass); 664 continue; 665 } 666 } 667 668 nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i); 669 int32_t nsuri = aAttributes->getURINoBoundsCheck(i); 670 671 // If value is already an atom, use it directly to avoid string allocation. 672 nsAtom* valAtom = val.MaybeAsAtom(); 673 if (valAtom) { 674 newContent->SetAttr(nsuri, localName, prefix, valAtom, nullptr, false); 675 } else { 676 nsString value; // Not Auto, because using it to hold nsStringBuffer* 677 val.ToString(value); 678 newContent->SetAttr(nsuri, localName, prefix, value, false); 679 } 680 } 681 return newContent; 682 } 683 684 void nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aForm, 685 nsIContent* aParent) { 686 RefPtr formElement = HTMLFormElement::FromNodeOrNull(aForm); 687 NS_ASSERTION(formElement, 688 "The form element doesn't implement HTMLFormElement."); 689 nsCOMPtr<nsIFormControl> formControl = nsIFormControl::FromNodeOrNull(aNode); 690 if (formControl && 691 formControl->ControlType() != 692 FormControlType::FormAssociatedCustomElement && 693 !aNode->AsElement()->HasAttr(nsGkAtoms::form) && 694 aForm->SubtreeRoot() == aParent->SubtreeRoot()) { 695 formControl->SetForm(formElement); 696 } else if (auto* image = HTMLImageElement::FromNodeOrNull(aNode)) { 697 image->SetForm(formElement); 698 } 699 } 700 701 nsresult nsHtml5TreeOperation::FosterParentText( 702 nsIContent* aStackParent, char16_t* aBuffer, uint32_t aLength, 703 nsIContent* aTable, nsHtml5DocumentBuilder* aBuilder) { 704 MOZ_ASSERT(aBuilder); 705 MOZ_ASSERT(aBuilder->IsInDocUpdate()); 706 nsresult rv = NS_OK; 707 nsIContent* foster = aTable->GetParent(); 708 709 if (IsElementOrTemplateContent(foster)) { 710 nsHtml5OtherDocUpdate update(foster->OwnerDoc(), aBuilder->GetDocument()); 711 712 nsIContent* previousSibling = aTable->GetPreviousSibling(); 713 if (previousSibling && previousSibling->IsText()) { 714 return AppendTextToTextNode(aBuffer, aLength, 715 previousSibling->GetAsText(), aBuilder); 716 } 717 718 nsNodeInfoManager* nodeInfoManager = 719 aStackParent->OwnerDoc()->NodeInfoManager(); 720 RefPtr<nsTextNode> text = new (nodeInfoManager) nsTextNode(nodeInfoManager); 721 NS_ASSERTION(text, "Infallible malloc failed?"); 722 rv = text->SetText(aBuffer, aLength, false); 723 NS_ENSURE_SUCCESS(rv, rv); 724 725 ErrorResult error; 726 foster->InsertChildBefore(text, aTable, false, error); 727 if (error.Failed()) { 728 return error.StealNSResult(); 729 } 730 731 MutationObservers::NotifyContentInserted( 732 foster, text, {MutationEffectOnScript::KeepTrustWorthiness}); 733 return rv; 734 } 735 736 return AppendText(aBuffer, aLength, aStackParent, aBuilder); 737 } 738 739 nsresult nsHtml5TreeOperation::AppendComment(nsIContent* aParent, 740 char16_t* aBuffer, int32_t aLength, 741 nsHtml5DocumentBuilder* aBuilder) { 742 nsNodeInfoManager* nodeInfoManager = aParent->OwnerDoc()->NodeInfoManager(); 743 RefPtr<Comment> comment = new (nodeInfoManager) Comment(nodeInfoManager); 744 NS_ASSERTION(comment, "Infallible malloc failed?"); 745 nsresult rv = comment->SetText(aBuffer, aLength, false); 746 NS_ENSURE_SUCCESS(rv, rv); 747 748 return Append(comment, aParent, aBuilder); 749 } 750 751 nsresult nsHtml5TreeOperation::AppendCommentToDocument( 752 char16_t* aBuffer, int32_t aLength, nsHtml5DocumentBuilder* aBuilder) { 753 RefPtr<Comment> comment = new (aBuilder->GetNodeInfoManager()) 754 Comment(aBuilder->GetNodeInfoManager()); 755 NS_ASSERTION(comment, "Infallible malloc failed?"); 756 nsresult rv = comment->SetText(aBuffer, aLength, false); 757 NS_ENSURE_SUCCESS(rv, rv); 758 759 return AppendToDocument(comment, aBuilder); 760 } 761 762 nsresult nsHtml5TreeOperation::AppendDoctypeToDocument( 763 nsAtom* aName, const nsAString& aPublicId, const nsAString& aSystemId, 764 nsHtml5DocumentBuilder* aBuilder) { 765 // Adapted from nsXMLContentSink 766 // Create a new doctype node 767 RefPtr<DocumentType> docType = 768 NS_NewDOMDocumentType(aBuilder->GetNodeInfoManager(), aName, aPublicId, 769 aSystemId, VoidString()); 770 return AppendToDocument(docType, aBuilder); 771 } 772 773 nsIContent* nsHtml5TreeOperation::GetDocumentFragmentForTemplate( 774 nsIContent* aNode) { 775 auto* tempElem = static_cast<HTMLTemplateElement*>(aNode); 776 return tempElem->Content(); 777 } 778 779 void nsHtml5TreeOperation::SetDocumentFragmentForTemplate( 780 nsIContent* aNode, nsIContent* aDocumentFragment) { 781 auto* tempElem = static_cast<HTMLTemplateElement*>(aNode); 782 tempElem->SetContent(static_cast<DocumentFragment*>(aDocumentFragment)); 783 } 784 785 nsIContent* nsHtml5TreeOperation::GetFosterParent(nsIContent* aTable, 786 nsIContent* aStackParent) { 787 nsIContent* tableParent = aTable->GetParent(); 788 return IsElementOrTemplateContent(tableParent) ? tableParent : aStackParent; 789 } 790 791 void nsHtml5TreeOperation::PreventScriptExecution(nsIContent* aNode) { 792 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode); 793 if (sele) { 794 sele->PreventExecution(); 795 } else { 796 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, 797 "Node didn't QI to script, but SVG wasn't disabled."); 798 } 799 } 800 801 void nsHtml5TreeOperation::DoneAddingChildren(nsIContent* aNode) { 802 aNode->DoneAddingChildren(aNode->HasParserNotified()); 803 } 804 805 void nsHtml5TreeOperation::DoneCreatingElement(nsIContent* aNode) { 806 aNode->DoneCreatingElement(); 807 } 808 809 void nsHtml5TreeOperation::SvgLoad(nsIContent* aNode) { 810 nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(aNode); 811 if (NS_FAILED(aNode->OwnerDoc()->Dispatch(event.forget()))) { 812 NS_WARNING("failed to dispatch svg load dispatcher"); 813 } 814 } 815 816 void nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode) { 817 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode); 818 if (sele) { 819 // Make sure to serialize this script correctly, for nice round tripping. 820 sele->SetIsMalformed(); 821 } 822 } 823 824 nsresult nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, 825 nsIContent** aScriptElement, 826 bool* aInterrupted, bool* aStreamEnded) { 827 struct TreeOperationMatcher { 828 TreeOperationMatcher(nsHtml5TreeOpExecutor* aBuilder, 829 nsIContent** aScriptElement, bool* aInterrupted, 830 bool* aStreamEnded) 831 : mBuilder(aBuilder), 832 mScriptElement(aScriptElement), 833 mInterrupted(aInterrupted), 834 mStreamEnded(aStreamEnded) {} 835 836 nsHtml5TreeOpExecutor* mBuilder; 837 nsIContent** mScriptElement; 838 bool* mInterrupted; 839 bool* mStreamEnded; 840 841 nsresult operator()(const opAppend& aOperation) { 842 return Append(*(aOperation.mChild), *(aOperation.mParent), 843 aOperation.mFromNetwork, mBuilder); 844 } 845 846 nsresult operator()(const opDetach& aOperation) { 847 Detach(*(aOperation.mElement), mBuilder); 848 return NS_OK; 849 } 850 851 nsresult operator()(const opAppendChildrenToNewParent& aOperation) { 852 nsCOMPtr<nsIContent> node = *(aOperation.mOldParent); 853 nsIContent* parent = *(aOperation.mNewParent); 854 return AppendChildrenToNewParent(node, parent, mBuilder); 855 } 856 857 nsresult operator()(const opFosterParent& aOperation) { 858 nsIContent* node = *(aOperation.mChild); 859 nsIContent* parent = *(aOperation.mStackParent); 860 nsIContent* table = *(aOperation.mTable); 861 return FosterParent(node, parent, table, mBuilder); 862 } 863 864 nsresult operator()(const opAppendToDocument& aOperation) { 865 nsresult rv = AppendToDocument(*(aOperation.mContent), mBuilder); 866 mBuilder->PauseDocUpdate(mInterrupted); 867 return rv; 868 } 869 870 nsresult operator()(const opAddAttributes& aOperation) { 871 nsIContent* node = *(aOperation.mElement); 872 nsHtml5HtmlAttributes* attributes = aOperation.mAttributes; 873 return AddAttributes(node, attributes, mBuilder); 874 } 875 876 nsresult operator()(const nsHtml5DocumentMode& aMode) { 877 mBuilder->SetDocumentMode(aMode); 878 return NS_OK; 879 } 880 881 nsresult operator()(const opCreateHTMLElement& aOperation) { 882 nsIContent** target = aOperation.mContent; 883 HTMLContentCreatorFunction creator = aOperation.mCreator; 884 nsAtom* name = aOperation.mName; 885 nsHtml5HtmlAttributes* attributes = aOperation.mAttributes; 886 nsIContent* intendedParent = 887 aOperation.mIntendedParent ? *(aOperation.mIntendedParent) : nullptr; 888 889 // intendedParent == nullptr is a special case where the 890 // intended parent is the document. 891 nsNodeInfoManager* nodeInfoManager = 892 intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager() 893 : mBuilder->GetNodeInfoManager(); 894 895 *target = CreateHTMLElement(name, attributes, aOperation.mFromNetwork, 896 nodeInfoManager, mBuilder, creator); 897 return NS_OK; 898 } 899 900 nsresult operator()(const opCreateSVGElement& aOperation) { 901 nsIContent** target = aOperation.mContent; 902 SVGContentCreatorFunction creator = aOperation.mCreator; 903 nsAtom* name = aOperation.mName; 904 nsHtml5HtmlAttributes* attributes = aOperation.mAttributes; 905 nsIContent* intendedParent = 906 aOperation.mIntendedParent ? *(aOperation.mIntendedParent) : nullptr; 907 908 // intendedParent == nullptr is a special case where the 909 // intended parent is the document. 910 nsNodeInfoManager* nodeInfoManager = 911 intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager() 912 : mBuilder->GetNodeInfoManager(); 913 914 *target = CreateSVGElement(name, attributes, aOperation.mFromNetwork, 915 nodeInfoManager, mBuilder, creator); 916 return NS_OK; 917 } 918 919 nsresult operator()(const opCreateMathMLElement& aOperation) { 920 nsIContent** target = aOperation.mContent; 921 nsAtom* name = aOperation.mName; 922 nsHtml5HtmlAttributes* attributes = aOperation.mAttributes; 923 nsIContent* intendedParent = 924 aOperation.mIntendedParent ? *(aOperation.mIntendedParent) : nullptr; 925 926 // intendedParent == nullptr is a special case where the 927 // intended parent is the document. 928 nsNodeInfoManager* nodeInfoManager = 929 intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager() 930 : mBuilder->GetNodeInfoManager(); 931 932 *target = 933 CreateMathMLElement(name, attributes, nodeInfoManager, mBuilder); 934 return NS_OK; 935 } 936 937 nsresult operator()(const opSetFormElement& aOperation) { 938 SetFormElement(*(aOperation.mContent), *(aOperation.mFormElement), 939 *(aOperation.mIntendedParent)); 940 return NS_OK; 941 } 942 943 nsresult operator()(const opAppendText& aOperation) { 944 nsIContent* parent = *aOperation.mParent; 945 char16_t* buffer = aOperation.mBuffer; 946 uint32_t length = aOperation.mLength; 947 return AppendText(buffer, length, parent, mBuilder); 948 } 949 950 nsresult operator()(const opFosterParentText& aOperation) { 951 nsIContent* stackParent = *aOperation.mStackParent; 952 char16_t* buffer = aOperation.mBuffer; 953 uint32_t length = aOperation.mLength; 954 nsIContent* table = *aOperation.mTable; 955 return FosterParentText(stackParent, buffer, length, table, mBuilder); 956 } 957 958 nsresult operator()(const opAppendComment& aOperation) { 959 nsIContent* parent = *aOperation.mParent; 960 char16_t* buffer = aOperation.mBuffer; 961 uint32_t length = aOperation.mLength; 962 return AppendComment(parent, buffer, length, mBuilder); 963 } 964 965 nsresult operator()(const opAppendCommentToDocument& aOperation) { 966 char16_t* buffer = aOperation.mBuffer; 967 int32_t length = aOperation.mLength; 968 return AppendCommentToDocument(buffer, length, mBuilder); 969 } 970 971 nsresult operator()(const opAppendDoctypeToDocument& aOperation) { 972 nsAtom* name = aOperation.mName; 973 nsHtml5TreeOperationStringPair* pair = aOperation.mStringPair; 974 nsString publicId; 975 nsString systemId; 976 pair->Get(publicId, systemId); 977 return AppendDoctypeToDocument(name, publicId, systemId, mBuilder); 978 } 979 980 nsresult operator()(const opGetDocumentFragmentForTemplate& aOperation) { 981 nsIContent* node = *(aOperation.mTemplate); 982 *(aOperation.mFragHandle) = GetDocumentFragmentForTemplate(node); 983 return NS_OK; 984 } 985 986 nsresult operator()(const opSetDocumentFragmentForTemplate& aOperation) { 987 SetDocumentFragmentForTemplate(*aOperation.mTemplate, 988 *aOperation.mFragment); 989 return NS_OK; 990 } 991 992 nsresult operator()(const opGetShadowRootFromHost& aOperation) { 993 nsIContent* root = nsContentUtils::AttachDeclarativeShadowRoot( 994 *aOperation.mHost, aOperation.mShadowRootMode, 995 aOperation.mShadowRootIsClonable, 996 aOperation.mShadowRootIsSerializable, 997 aOperation.mShadowRootDelegatesFocus, 998 aOperation.mShadowRootReferenceTarget); 999 if (root) { 1000 *aOperation.mFragHandle = root; 1001 return NS_OK; 1002 } 1003 1004 // We failed to attach a new shadow root, so instead attach a template 1005 // element and return its content. 1006 nsHtml5TreeOperation::Append(*aOperation.mTemplateNode, *aOperation.mHost, 1007 mBuilder); 1008 *aOperation.mFragHandle = 1009 static_cast<HTMLTemplateElement*>(*aOperation.mTemplateNode) 1010 ->Content(); 1011 nsContentUtils::LogSimpleConsoleError( 1012 u"Failed to attach Declarative Shadow DOM."_ns, "DOM"_ns, 1013 mBuilder->GetDocument()->IsInPrivateBrowsing(), 1014 mBuilder->GetDocument()->IsInChromeDocShell()); 1015 return NS_OK; 1016 } 1017 1018 nsresult operator()(const opGetFosterParent& aOperation) { 1019 nsIContent* table = *(aOperation.mTable); 1020 nsIContent* stackParent = *(aOperation.mStackParent); 1021 nsIContent* fosterParent = GetFosterParent(table, stackParent); 1022 *aOperation.mParentHandle = fosterParent; 1023 return NS_OK; 1024 } 1025 1026 nsresult operator()(const opMarkAsBroken& aOperation) { 1027 return aOperation.mResult; 1028 } 1029 1030 nsresult operator()( 1031 const opRunScriptThatMayDocumentWriteOrBlock& aOperation) { 1032 nsIContent* node = *(aOperation.mElement); 1033 nsAHtml5TreeBuilderState* snapshot = aOperation.mBuilderState; 1034 if (snapshot) { 1035 mBuilder->InitializeDocWriteParserState(snapshot, 1036 aOperation.mLineNumber); 1037 } 1038 *mScriptElement = node; 1039 return NS_OK; 1040 } 1041 1042 nsresult operator()( 1043 const opRunScriptThatCannotDocumentWriteOrBlock& aOperation) { 1044 mBuilder->RunScript(*(aOperation.mElement), false); 1045 return NS_OK; 1046 } 1047 1048 nsresult operator()(const opPreventScriptExecution& aOperation) { 1049 PreventScriptExecution(*(aOperation.mElement)); 1050 return NS_OK; 1051 } 1052 1053 nsresult operator()(const opDoneAddingChildren& aOperation) { 1054 nsIContent* node = *(aOperation.mElement); 1055 node->DoneAddingChildren(node->HasParserNotified()); 1056 return NS_OK; 1057 } 1058 1059 nsresult operator()(const opDoneCreatingElement& aOperation) { 1060 DoneCreatingElement(*(aOperation.mElement)); 1061 return NS_OK; 1062 } 1063 1064 nsresult operator()(const opUpdateCharsetSource& aOperation) { 1065 mBuilder->UpdateCharsetSource(aOperation.mCharsetSource); 1066 return NS_OK; 1067 } 1068 1069 nsresult operator()(const opCharsetSwitchTo& aOperation) { 1070 auto encoding = WrapNotNull(aOperation.mEncoding); 1071 mBuilder->NeedsCharsetSwitchTo(encoding, aOperation.mCharsetSource, 1072 (uint32_t)aOperation.mLineNumber); 1073 return NS_OK; 1074 } 1075 1076 nsresult operator()(const opUpdateStyleSheet& aOperation) { 1077 mBuilder->UpdateStyleSheet(*(aOperation.mElement)); 1078 return NS_OK; 1079 } 1080 1081 nsresult operator()(const opProcessOfflineManifest& aOperation) { 1082 // TODO: remove this 1083 return NS_OK; 1084 } 1085 1086 nsresult operator()(const opMarkMalformedIfScript& aOperation) { 1087 MarkMalformedIfScript(*(aOperation.mElement)); 1088 return NS_OK; 1089 } 1090 1091 nsresult operator()(const opStreamEnded& aOperation) { 1092 *mStreamEnded = true; 1093 return NS_OK; 1094 } 1095 1096 nsresult operator()(const opSetStyleLineNumber& aOperation) { 1097 nsIContent* node = *(aOperation.mContent); 1098 if (auto* linkStyle = LinkStyle::FromNode(*node)) { 1099 linkStyle->SetLineNumber(aOperation.mLineNumber); 1100 } else { 1101 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, 1102 "Node didn't QI to style, but SVG wasn't disabled."); 1103 } 1104 return NS_OK; 1105 } 1106 1107 nsresult operator()( 1108 const opSetScriptLineAndColumnNumberAndFreeze& aOperation) { 1109 nsIContent* node = *(aOperation.mContent); 1110 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node); 1111 if (sele) { 1112 sele->SetScriptLineNumber(aOperation.mLineNumber); 1113 sele->SetScriptColumnNumber( 1114 JS::ColumnNumberOneOrigin(aOperation.mColumnNumber)); 1115 sele->FreezeExecutionAttrs(node->OwnerDoc()); 1116 } else { 1117 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, 1118 "Node didn't QI to script, but SVG wasn't disabled."); 1119 } 1120 return NS_OK; 1121 } 1122 1123 nsresult operator()(const opSvgLoad& aOperation) { 1124 SvgLoad(*(aOperation.mElement)); 1125 return NS_OK; 1126 } 1127 1128 nsresult operator()(const opMaybeComplainAboutCharset& aOperation) { 1129 char* msgId = aOperation.mMsgId; 1130 bool error = aOperation.mError; 1131 int32_t lineNumber = aOperation.mLineNumber; 1132 mBuilder->MaybeComplainAboutCharset(msgId, error, (uint32_t)lineNumber); 1133 return NS_OK; 1134 } 1135 1136 nsresult operator()(const opMaybeComplainAboutDeepTree& aOperation) { 1137 mBuilder->MaybeComplainAboutDeepTree((uint32_t)aOperation.mLineNumber); 1138 return NS_OK; 1139 } 1140 1141 nsresult operator()(const opAddClass& aOperation) { 1142 Element* element = (*(aOperation.mElement))->AsElement(); 1143 char16_t* str = aOperation.mClass; 1144 nsDependentString depStr(str); 1145 // See viewsource.css for the possible classes 1146 nsAutoString klass; 1147 element->GetAttr(nsGkAtoms::_class, klass); 1148 if (!klass.IsEmpty()) { 1149 klass.Append(' '); 1150 klass.Append(depStr); 1151 element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true); 1152 } else { 1153 element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, depStr, true); 1154 } 1155 return NS_OK; 1156 } 1157 1158 nsresult operator()(const opAddViewSourceHref& aOperation) { 1159 Element* element = (*aOperation.mElement)->AsElement(); 1160 char16_t* buffer = aOperation.mBuffer; 1161 int32_t length = aOperation.mLength; 1162 nsDependentString relative(buffer, length); 1163 1164 Document* doc = mBuilder->GetDocument(); 1165 1166 auto encoding = doc->GetDocumentCharacterSet(); 1167 nsCOMPtr<nsIURI> uri; 1168 nsresult rv = NS_NewURI(getter_AddRefs(uri), relative, encoding, 1169 mBuilder->GetViewSourceBaseURI()); 1170 NS_ENSURE_SUCCESS(rv, NS_OK); 1171 1172 // Reuse the fix for bug 467852 1173 // URLs that execute script (e.g. "javascript:" URLs) should just be 1174 // ignored. There's nothing reasonable we can do with them, and allowing 1175 // them to execute in the context of the view-source window presents a 1176 // security risk. Just return the empty string in this case. 1177 bool openingExecutesScript = false; 1178 rv = NS_URIChainHasFlags(uri, 1179 nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, 1180 &openingExecutesScript); 1181 if (NS_FAILED(rv) || openingExecutesScript) { 1182 return NS_OK; 1183 } 1184 1185 nsAutoCString viewSourceUrl; 1186 1187 // URLs that return data (e.g. "http:" URLs) should be prefixed with 1188 // "view-source:". URLs that don't return data should just be returned 1189 // undecorated. 1190 if (!nsContentUtils::IsExternalProtocol(uri)) { 1191 viewSourceUrl.AssignLiteral("view-source:"); 1192 } 1193 1194 nsAutoCString spec; 1195 rv = uri->GetSpec(spec); 1196 NS_ENSURE_SUCCESS(rv, rv); 1197 1198 viewSourceUrl.Append(spec); 1199 1200 nsAutoString utf16; 1201 CopyUTF8toUTF16(viewSourceUrl, utf16); 1202 1203 element->SetAttr(kNameSpaceID_None, nsGkAtoms::href, utf16, true); 1204 return NS_OK; 1205 } 1206 1207 nsresult operator()(const opAddViewSourceBase& aOperation) { 1208 nsDependentString baseUrl(aOperation.mBuffer, aOperation.mLength); 1209 mBuilder->AddBase(baseUrl); 1210 return NS_OK; 1211 } 1212 1213 nsresult operator()(const opAddErrorType& aOperation) { 1214 Element* element = (*(aOperation.mElement))->AsElement(); 1215 char* msgId = aOperation.mMsgId; 1216 nsAtom* atom = aOperation.mName; 1217 nsAtom* otherAtom = aOperation.mOther; 1218 // See viewsource.css for the possible classes in addition to "error". 1219 nsAutoString klass; 1220 element->GetAttr(nsGkAtoms::_class, klass); 1221 if (!klass.IsEmpty()) { 1222 klass.AppendLiteral(" error"); 1223 element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true); 1224 } else { 1225 element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, u"error"_ns, 1226 true); 1227 } 1228 1229 nsresult rv; 1230 nsAutoString message; 1231 if (otherAtom) { 1232 rv = nsContentUtils::FormatLocalizedString( 1233 message, nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, 1234 nsDependentAtomString(atom), nsDependentAtomString(otherAtom)); 1235 NS_ENSURE_SUCCESS(rv, NS_OK); 1236 } else if (atom) { 1237 rv = nsContentUtils::FormatLocalizedString( 1238 message, nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, 1239 nsDependentAtomString(atom)); 1240 NS_ENSURE_SUCCESS(rv, NS_OK); 1241 } else { 1242 rv = nsContentUtils::GetLocalizedString( 1243 nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, message); 1244 NS_ENSURE_SUCCESS(rv, NS_OK); 1245 } 1246 1247 nsAutoString title; 1248 element->GetAttr(nsGkAtoms::title, title); 1249 if (!title.IsEmpty()) { 1250 title.Append('\n'); 1251 title.Append(message); 1252 element->SetAttr(kNameSpaceID_None, nsGkAtoms::title, title, true); 1253 } else { 1254 element->SetAttr(kNameSpaceID_None, nsGkAtoms::title, message, true); 1255 } 1256 return rv; 1257 } 1258 1259 nsresult operator()(const opAddLineNumberId& aOperation) { 1260 Element* element = (*(aOperation.mElement))->AsElement(); 1261 int32_t lineNumber = aOperation.mLineNumber; 1262 nsAutoString val(u"line"_ns); 1263 val.AppendInt(lineNumber); 1264 element->SetAttr(kNameSpaceID_None, nsGkAtoms::id, val, true); 1265 return NS_OK; 1266 } 1267 1268 nsresult operator()(const opShallowCloneInto& aOperation) { 1269 nsIContent* src = *aOperation.mSrc; 1270 ErrorResult rv; 1271 RefPtr<nsINode> clone = src->CloneNode(false, rv); 1272 if (NS_WARN_IF(rv.Failed())) { 1273 return rv.StealNSResult(); 1274 } 1275 *aOperation.mDst = clone->AsContent(); 1276 mBuilder->HoldElement(clone.forget().downcast<nsIContent>()); 1277 return Append(*aOperation.mDst, *aOperation.mIntendedParent, 1278 aOperation.mFromParser, mBuilder); 1279 } 1280 1281 nsresult operator()(const opStartLayout& aOperation) { 1282 mBuilder->StartLayout( 1283 mInterrupted); // this causes a notification flush anyway 1284 return NS_OK; 1285 } 1286 1287 nsresult operator()(const opEnableEncodingMenu& aOperation) { 1288 Document* doc = mBuilder->GetDocument(); 1289 doc->EnableEncodingMenu(); 1290 return NS_OK; 1291 } 1292 1293 nsresult operator()(const opMicrotaskCheckpoint& aOperation) { 1294 nsHtml5AutoPauseUpdate autoPauseContentUpdate(mBuilder); 1295 nsAutoMicroTask mt; 1296 return NS_OK; 1297 } 1298 1299 nsresult operator()(const uninitialized& aOperation) { 1300 MOZ_CRASH("uninitialized"); 1301 return NS_OK; 1302 } 1303 }; 1304 1305 return mOperation.match(TreeOperationMatcher(aBuilder, aScriptElement, 1306 aInterrupted, aStreamEnded)); 1307 }