nsHtml5TreeBuilderCppSupplement.h (82228B)
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 "ErrorList.h" 8 #include "nsError.h" 9 #include "nsHtml5AttributeName.h" 10 #include "nsHtml5HtmlAttributes.h" 11 #include "nsHtml5String.h" 12 #include "nsNetUtil.h" 13 #include "mozilla/dom/FetchPriority.h" 14 #include "mozilla/dom/ShadowRoot.h" 15 #include "mozilla/dom/ShadowRootBinding.h" 16 #include "mozilla/glean/ParserHtmlMetrics.h" 17 #include "mozilla/CheckedInt.h" 18 #include "mozilla/Likely.h" 19 #include "mozilla/StaticPrefs_dom.h" 20 #include "mozilla/StaticPrefs_network.h" 21 #include "mozilla/UniquePtr.h" 22 #include "mozilla/UniquePtrExtensions.h" 23 24 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder) 25 : mode(0), 26 originalMode(0), 27 framesetOk(false), 28 tokenizer(nullptr), 29 scriptingEnabled(false), 30 needToDropLF(false), 31 fragment(false), 32 contextName(nullptr), 33 contextNamespace(kNameSpaceID_None), 34 contextNode(nullptr), 35 templateModePtr(0), 36 stackNodesIdx(0), 37 numStackNodes(0), 38 currentPtr(0), 39 listPtr(0), 40 formPointer(nullptr), 41 headPointer(nullptr), 42 charBufferLen(0), 43 quirks(false), 44 forceNoQuirks(false), 45 allowDeclarativeShadowRoots(false), 46 keepBuffer(false), 47 mBuilder(aBuilder), 48 mViewSource(nullptr), 49 mOpSink(nullptr), 50 mHandles(nullptr), 51 mHandlesUsed(0), 52 mSpeculativeLoadStage(nullptr), 53 mBroken(NS_OK), 54 mCurrentHtmlScriptCannotDocumentWriteOrBlock(false), 55 mPreventScriptExecution(false), 56 mGenerateSpeculativeLoads(false), 57 mHasSeenImportMap(false) 58 #ifdef DEBUG 59 , 60 mActive(false) 61 #endif 62 { 63 MOZ_COUNT_CTOR(nsHtml5TreeBuilder); 64 } 65 66 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink, 67 nsHtml5TreeOpStage* aStage, 68 bool aGenerateSpeculativeLoads) 69 : mode(0), 70 originalMode(0), 71 framesetOk(false), 72 tokenizer(nullptr), 73 scriptingEnabled(false), 74 needToDropLF(false), 75 fragment(false), 76 contextName(nullptr), 77 contextNamespace(kNameSpaceID_None), 78 contextNode(nullptr), 79 templateModePtr(0), 80 stackNodesIdx(0), 81 numStackNodes(0), 82 currentPtr(0), 83 listPtr(0), 84 formPointer(nullptr), 85 headPointer(nullptr), 86 charBufferLen(0), 87 quirks(false), 88 forceNoQuirks(false), 89 allowDeclarativeShadowRoots(false), 90 keepBuffer(false), 91 mBuilder(nullptr), 92 mViewSource(nullptr), 93 mOpSink(aOpSink), 94 mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH]), 95 mHandlesUsed(0), 96 mSpeculativeLoadStage(aStage), 97 mBroken(NS_OK), 98 mCurrentHtmlScriptCannotDocumentWriteOrBlock(false), 99 mPreventScriptExecution(false), 100 mGenerateSpeculativeLoads(aGenerateSpeculativeLoads), 101 mHasSeenImportMap(false) 102 #ifdef DEBUG 103 , 104 mActive(false) 105 #endif 106 { 107 MOZ_ASSERT(!(!aStage && aGenerateSpeculativeLoads), 108 "Must not generate speculative loads without a stage"); 109 MOZ_COUNT_CTOR(nsHtml5TreeBuilder); 110 } 111 112 nsHtml5TreeBuilder::~nsHtml5TreeBuilder() { 113 MOZ_COUNT_DTOR(nsHtml5TreeBuilder); 114 NS_ASSERTION(!mActive, 115 "nsHtml5TreeBuilder deleted without ever calling end() on it!"); 116 mOpQueue.Clear(); 117 } 118 119 static void getTypeString(nsHtml5String& aType, nsAString& aTypeString) { 120 aType.ToString(aTypeString); 121 122 // Since `typeString` after trimming and lowercasing is only checked 123 // for "module" and " importmap", we don't need to remember 124 // pre-trimming emptiness here. 125 126 // ASCII whitespace https://infra.spec.whatwg.org/#ascii-whitespace: 127 // U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE. 128 static const char kASCIIWhitespace[] = "\t\n\f\r "; 129 aTypeString.Trim(kASCIIWhitespace); 130 } 131 132 nsIContentHandle* nsHtml5TreeBuilder::createElement( 133 int32_t aNamespace, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes, 134 nsIContentHandle* aIntendedParent, nsHtml5ContentCreatorFunction aCreator) { 135 MOZ_ASSERT(aAttributes, "Got null attributes."); 136 MOZ_ASSERT(aName, "Got null name."); 137 MOZ_ASSERT(aNamespace == kNameSpaceID_XHTML || 138 aNamespace == kNameSpaceID_SVG || 139 aNamespace == kNameSpaceID_MathML, 140 "Bogus namespace."); 141 142 if (mBuilder) { 143 nsIContent* intendedParent = 144 aIntendedParent ? static_cast<nsIContent*>(aIntendedParent) : nullptr; 145 146 // intendedParent == nullptr is a special case where the 147 // intended parent is the document. 148 nsNodeInfoManager* nodeInfoManager = 149 intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager() 150 : mBuilder->GetNodeInfoManager(); 151 152 nsIContent* elem; 153 if (aNamespace == kNameSpaceID_XHTML) { 154 elem = nsHtml5TreeOperation::CreateHTMLElement( 155 aName, aAttributes, mozilla::dom::FROM_PARSER_FRAGMENT, 156 nodeInfoManager, mBuilder, aCreator.html); 157 } else if (aNamespace == kNameSpaceID_SVG) { 158 elem = nsHtml5TreeOperation::CreateSVGElement( 159 aName, aAttributes, mozilla::dom::FROM_PARSER_FRAGMENT, 160 nodeInfoManager, mBuilder, aCreator.svg); 161 } else { 162 MOZ_ASSERT(aNamespace == kNameSpaceID_MathML); 163 elem = nsHtml5TreeOperation::CreateMathMLElement( 164 aName, aAttributes, nodeInfoManager, mBuilder); 165 } 166 if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() && 167 aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) { 168 delete aAttributes; 169 } 170 return elem; 171 } 172 173 nsIContentHandle* content = AllocateContentHandle(); 174 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 175 if (MOZ_UNLIKELY(!treeOp)) { 176 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 177 return nullptr; 178 } 179 180 if (aNamespace == kNameSpaceID_XHTML) { 181 opCreateHTMLElement opeation( 182 content, aName, aAttributes, aCreator.html, aIntendedParent, 183 (!!mSpeculativeLoadStage) ? mozilla::dom::FROM_PARSER_NETWORK 184 : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE); 185 treeOp->Init(mozilla::AsVariant(opeation)); 186 } else if (aNamespace == kNameSpaceID_SVG) { 187 opCreateSVGElement operation( 188 content, aName, aAttributes, aCreator.svg, aIntendedParent, 189 (!!mSpeculativeLoadStage) ? mozilla::dom::FROM_PARSER_NETWORK 190 : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE); 191 treeOp->Init(mozilla::AsVariant(operation)); 192 } else { 193 // kNameSpaceID_MathML 194 opCreateMathMLElement operation(content, aName, aAttributes, 195 aIntendedParent); 196 treeOp->Init(mozilla::AsVariant(operation)); 197 } 198 199 // mSpeculativeLoadStage is non-null only in the off-the-main-thread 200 // tree builder, which handles the network stream 201 202 // Start wall of code for speculative loading and line numbers 203 204 if (mGenerateSpeculativeLoads && mode != IN_TEMPLATE) { 205 switch (aNamespace) { 206 case kNameSpaceID_XHTML: 207 if (nsGkAtoms::img == aName) { 208 nsHtml5String loading = 209 aAttributes->getValue(nsHtml5AttributeName::ATTR_LOADING); 210 if (!loading.LowerCaseEqualsASCII("lazy")) { 211 nsHtml5String url = 212 aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); 213 nsHtml5String srcset = 214 aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET); 215 nsHtml5String crossOrigin = 216 aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); 217 nsHtml5String referrerPolicy = aAttributes->getValue( 218 nsHtml5AttributeName::ATTR_REFERRERPOLICY); 219 nsHtml5String sizes = 220 aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES); 221 nsHtml5String fetchPriority = 222 aAttributes->getValue(nsHtml5AttributeName::ATTR_FETCHPRIORITY); 223 nsHtml5String type = 224 aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); 225 mSpeculativeLoadQueue.AppendElement()->InitImage( 226 url, crossOrigin, /* aMedia = */ nullptr, referrerPolicy, 227 srcset, sizes, false, fetchPriority, type); 228 } 229 } else if (nsGkAtoms::source == aName) { 230 nsHtml5String srcset = 231 aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET); 232 // Sources without srcset cannot be selected. The source could also be 233 // for a media element, but in that context doesn't use srcset. See 234 // comments in nsHtml5SpeculativeLoad.h about <picture> preloading 235 if (srcset) { 236 nsHtml5String sizes = 237 aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES); 238 nsHtml5String type = 239 aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); 240 nsHtml5String media = 241 aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA); 242 mSpeculativeLoadQueue.AppendElement()->InitPictureSource( 243 srcset, sizes, type, media); 244 } 245 } else if (nsGkAtoms::script == aName) { 246 nsHtml5TreeOperation* treeOp = 247 mOpQueue.AppendElement(mozilla::fallible); 248 if (MOZ_UNLIKELY(!treeOp)) { 249 MarkAsBrokenAndRequestSuspensionWithoutBuilder( 250 NS_ERROR_OUT_OF_MEMORY); 251 return nullptr; 252 } 253 opSetScriptLineAndColumnNumberAndFreeze operation( 254 content, tokenizer->getLineNumber(), 255 // NOTE: tokenizer->getColumnNumber() points '>'. 256 tokenizer->getColumnNumber() + 1); 257 treeOp->Init(mozilla::AsVariant(operation)); 258 259 nsHtml5String type = 260 aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); 261 nsAutoString typeString; 262 getTypeString(type, typeString); 263 264 bool isModule = typeString.LowerCaseEqualsASCII("module"); 265 bool importmap = typeString.LowerCaseEqualsASCII("importmap"); 266 bool async = false; 267 bool defer = false; 268 bool nomodule = 269 aAttributes->contains(nsHtml5AttributeName::ATTR_NOMODULE); 270 271 // For microtask semantics, we need to queue either 272 // `opRunScriptThatMayDocumentWriteOrBlock` or 273 // `opRunScriptThatCannotDocumentWriteOrBlock` for every script 274 // element--even ones that we already know won't run. 275 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` controls which 276 // kind of operation is used for an HTML script, and this is the 277 // place where `mCurrentHtmlScriptCannotDocumentWriteOrBlock` 278 // needs to be set correctly. 279 // 280 // Non-async, non-defer classic scripts that will run MUST use 281 // `opRunScriptThatMayDocumentWriteOrBlock` in order to run 282 // the more complex code that 283 // 1. is able to resume the HTML parse after a parser-blocking 284 // scripts no longer blocks the parser 285 // 2. is able to receive more content to parse on the main thread 286 // via document.write 287 // 3. is able to throw away off-the-main-thread parsing results 288 // if what's document.written on the main thread invalidates 289 // the speculation. 290 // 291 // Async and defer classic scripts as well as module scripts and 292 // importmaps MUST use `opRunScriptThatCannotDocumentWriteOrBlock`. 293 // This is necessary particularly because the relevant main-thread 294 // code assumes it doesn't need to deal with resuming the HTML 295 // parse some time afterwards, so using a tree operation with 296 // mismatching expectations regarding that responsibility may 297 // cause the HTML parse to stall. 298 // 299 // Various scripts that won't actually run work with either type 300 // of tree op in the sense that the HTML parse won't stall. 301 // However, in the case where a script cannot block or insert 302 // data to the HTML parser via document.write, unnecessary use 303 // of `opRunScriptThatMayDocumentWriteOrBlock` instead of 304 // `opRunScriptThatCannotDocumentWriteOrBlock` causes the HTML 305 // parser to enter the speculative mode when doing so isn't 306 // actually required. 307 // 308 // Ideally, we would check for `type`/`language` attribute 309 // combinations that are known to cause non-execution as well as 310 // ScriptLoader::IsScriptEventHandler equivalent. That way, we 311 // wouldn't unnecessarily speculate after scripts that won't 312 // execute. https://bugzilla.mozilla.org/show_bug.cgi?id=1848311 313 314 if (importmap) { 315 // If we see an importmap, we don't want to later start speculative 316 // loads for modulepreloads, since such load might finish before 317 // the importmap is created. This also applies to module scripts so 318 // that any modulepreload integrity checks can be performed before 319 // the modules scripts are loaded. 320 // This state is not part of speculation rollback: If an importmap 321 // is seen speculatively and the speculation is rolled back, the 322 // importmap is still considered seen. 323 // TODO: Sync importmap seenness between the main thread and the 324 // parser thread. 325 // https://bugzilla.mozilla.org/show_bug.cgi?id=1848312 326 mHasSeenImportMap = true; 327 } 328 nsHtml5String url = 329 aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); 330 if (url) { 331 async = aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC); 332 defer = aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER); 333 if ((isModule && !mHasSeenImportMap) || 334 (!isModule && !importmap && !nomodule)) { 335 nsHtml5String charset = 336 aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); 337 nsHtml5String crossOrigin = 338 aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); 339 nsHtml5String nonce = 340 aAttributes->getValue(nsHtml5AttributeName::ATTR_NONCE); 341 nsHtml5String fetchPriority = aAttributes->getValue( 342 nsHtml5AttributeName::ATTR_FETCHPRIORITY); 343 nsHtml5String integrity = 344 aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); 345 nsHtml5String referrerPolicy = aAttributes->getValue( 346 nsHtml5AttributeName::ATTR_REFERRERPOLICY); 347 mSpeculativeLoadQueue.AppendElement()->InitScript( 348 url, charset, type, crossOrigin, /* aMedia = */ nullptr, 349 nonce, fetchPriority, integrity, referrerPolicy, 350 mode == nsHtml5TreeBuilder::IN_HEAD, async, defer, false); 351 } 352 } 353 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` MUST be computed to 354 // match the ScriptLoader-perceived kind of the script regardless of 355 // enqueuing a speculative load. Scripts with the `nomodule` attribute 356 // never block or document.write: Either the attribute prevents a 357 // classic script execution or is ignored on a module script or 358 // importmap. 359 mCurrentHtmlScriptCannotDocumentWriteOrBlock = 360 isModule || importmap || async || defer || nomodule; 361 } else if (nsGkAtoms::link == aName) { 362 nsHtml5String rel = 363 aAttributes->getValue(nsHtml5AttributeName::ATTR_REL); 364 // Not splitting on space here is bogus but the old parser didn't even 365 // do a case-insensitive check. 366 if (rel) { 367 if (rel.LowerCaseEqualsASCII("stylesheet")) { 368 nsHtml5String url = 369 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); 370 if (url && 371 !aAttributes->getValue(nsHtml5AttributeName::ATTR_DISABLED)) { 372 nsHtml5String charset = 373 aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); 374 nsHtml5String crossOrigin = aAttributes->getValue( 375 nsHtml5AttributeName::ATTR_CROSSORIGIN); 376 nsHtml5String nonce = 377 aAttributes->getValue(nsHtml5AttributeName::ATTR_NONCE); 378 nsHtml5String integrity = 379 aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); 380 nsHtml5String referrerPolicy = aAttributes->getValue( 381 nsHtml5AttributeName::ATTR_REFERRERPOLICY); 382 nsHtml5String media = 383 aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA); 384 nsHtml5String fetchPriority = aAttributes->getValue( 385 nsHtml5AttributeName::ATTR_FETCHPRIORITY); 386 mSpeculativeLoadQueue.AppendElement()->InitStyle( 387 url, charset, crossOrigin, media, referrerPolicy, nonce, 388 integrity, false, fetchPriority); 389 } 390 } else if (rel.LowerCaseEqualsASCII("preconnect")) { 391 nsHtml5String url = 392 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); 393 if (url) { 394 nsHtml5String crossOrigin = aAttributes->getValue( 395 nsHtml5AttributeName::ATTR_CROSSORIGIN); 396 mSpeculativeLoadQueue.AppendElement()->InitPreconnect( 397 url, crossOrigin); 398 } 399 } else if (rel.LowerCaseEqualsASCII("preload")) { 400 nsHtml5String url = 401 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); 402 if (url) { 403 nsHtml5String as = 404 aAttributes->getValue(nsHtml5AttributeName::ATTR_AS); 405 nsHtml5String charset = 406 aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); 407 nsHtml5String crossOrigin = aAttributes->getValue( 408 nsHtml5AttributeName::ATTR_CROSSORIGIN); 409 nsHtml5String nonce = 410 aAttributes->getValue(nsHtml5AttributeName::ATTR_NONCE); 411 nsHtml5String integrity = 412 aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); 413 nsHtml5String referrerPolicy = aAttributes->getValue( 414 nsHtml5AttributeName::ATTR_REFERRERPOLICY); 415 nsHtml5String media = 416 aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA); 417 nsHtml5String fetchPriority = aAttributes->getValue( 418 nsHtml5AttributeName::ATTR_FETCHPRIORITY); 419 420 // Note that respective speculative loaders for scripts and 421 // styles check all additional attributes to be equal to use the 422 // speculative load. So, if any of them is specified and the 423 // preload has to take the expected effect, those attributes 424 // must also be specified on the actual tag to use the preload. 425 // Omitting an attribute on both will make the values equal 426 // (empty) and thus use the preload. 427 if (as.LowerCaseEqualsASCII("script")) { 428 nsHtml5String type = 429 aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); 430 mSpeculativeLoadQueue.AppendElement()->InitScript( 431 url, charset, type, crossOrigin, media, nonce, 432 /* aFetchPriority */ fetchPriority, integrity, 433 referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD, 434 false, false, true); 435 } else if (as.LowerCaseEqualsASCII("style")) { 436 mSpeculativeLoadQueue.AppendElement()->InitStyle( 437 url, charset, crossOrigin, media, referrerPolicy, nonce, 438 integrity, true, fetchPriority); 439 } else if (as.LowerCaseEqualsASCII("image")) { 440 nsHtml5String srcset = aAttributes->getValue( 441 nsHtml5AttributeName::ATTR_IMAGESRCSET); 442 nsHtml5String sizes = aAttributes->getValue( 443 nsHtml5AttributeName::ATTR_IMAGESIZES); 444 nsHtml5String type = 445 aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); 446 mSpeculativeLoadQueue.AppendElement()->InitImage( 447 url, crossOrigin, media, referrerPolicy, srcset, sizes, 448 true, fetchPriority, type); 449 } else if (as.LowerCaseEqualsASCII("font")) { 450 mSpeculativeLoadQueue.AppendElement()->InitFont( 451 url, crossOrigin, media, referrerPolicy, fetchPriority); 452 } else if (as.LowerCaseEqualsASCII("fetch")) { 453 mSpeculativeLoadQueue.AppendElement()->InitFetch( 454 url, crossOrigin, media, referrerPolicy, fetchPriority); 455 } 456 // Other "as" values will be supported later. 457 } 458 } else if (mozilla::StaticPrefs::network_modulepreload() && 459 rel.LowerCaseEqualsASCII("modulepreload") && 460 !mHasSeenImportMap) { 461 nsHtml5String url = 462 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); 463 if (url && url.Length() != 0) { 464 nsHtml5String as = 465 aAttributes->getValue(nsHtml5AttributeName::ATTR_AS); 466 nsAutoString asString; 467 as.ToString(asString); 468 if (mozilla::net::IsScriptLikeOrInvalid(asString)) { 469 nsHtml5String charset = 470 aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); 471 RefPtr<nsAtom> moduleType = nsGkAtoms::_module; 472 nsHtml5String type = 473 nsHtml5String::FromAtom(moduleType.forget()); 474 nsHtml5String crossOrigin = aAttributes->getValue( 475 nsHtml5AttributeName::ATTR_CROSSORIGIN); 476 nsHtml5String media = 477 aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA); 478 nsHtml5String nonce = 479 aAttributes->getValue(nsHtml5AttributeName::ATTR_NONCE); 480 nsHtml5String integrity = aAttributes->getValue( 481 nsHtml5AttributeName::ATTR_INTEGRITY); 482 nsHtml5String referrerPolicy = aAttributes->getValue( 483 nsHtml5AttributeName::ATTR_REFERRERPOLICY); 484 nsHtml5String fetchPriority = aAttributes->getValue( 485 nsHtml5AttributeName::ATTR_FETCHPRIORITY); 486 487 mSpeculativeLoadQueue.AppendElement()->InitScript( 488 url, charset, type, crossOrigin, media, nonce, 489 /* aFetchPriority */ fetchPriority, integrity, 490 referrerPolicy, mode == nsHtml5TreeBuilder::IN_HEAD, 491 false, false, true); 492 } 493 } 494 } 495 } 496 } else if (nsGkAtoms::video == aName) { 497 nsHtml5String url = 498 aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER); 499 if (url) { 500 // Fetch priority is not supported for video. Nullptr will map to 501 // the auto state 502 // (https://html.spec.whatwg.org/#fetch-priority-attribute). 503 auto fetchPriority = nullptr; 504 505 mSpeculativeLoadQueue.AppendElement()->InitImage( 506 url, nullptr, nullptr, nullptr, nullptr, nullptr, false, 507 fetchPriority, nullptr); 508 } 509 } else if (nsGkAtoms::style == aName) { 510 mImportScanner.Start(); 511 nsHtml5TreeOperation* treeOp = 512 mOpQueue.AppendElement(mozilla::fallible); 513 if (MOZ_UNLIKELY(!treeOp)) { 514 MarkAsBrokenAndRequestSuspensionWithoutBuilder( 515 NS_ERROR_OUT_OF_MEMORY); 516 return nullptr; 517 } 518 opSetStyleLineNumber operation(content, tokenizer->getLineNumber()); 519 treeOp->Init(mozilla::AsVariant(operation)); 520 } else if (nsGkAtoms::html == aName) { 521 nsHtml5String url = 522 aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); 523 mSpeculativeLoadQueue.AppendElement()->InitManifest(url); 524 } else if (nsGkAtoms::base == aName) { 525 nsHtml5String url = 526 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); 527 if (url) { 528 mSpeculativeLoadQueue.AppendElement()->InitBase(url); 529 } 530 } else if (nsGkAtoms::meta == aName) { 531 if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString( 532 "content-security-policy", 533 aAttributes->getValue( 534 nsHtml5AttributeName::ATTR_HTTP_EQUIV))) { 535 nsHtml5String csp = 536 aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); 537 if (csp) { 538 mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(csp); 539 } 540 } else if (nsHtml5Portability:: 541 lowerCaseLiteralEqualsIgnoreAsciiCaseString( 542 "referrer", 543 aAttributes->getValue( 544 nsHtml5AttributeName::ATTR_NAME))) { 545 nsHtml5String referrerPolicy = 546 aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); 547 if (referrerPolicy) { 548 mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy( 549 referrerPolicy); 550 } 551 } 552 } 553 break; 554 case kNameSpaceID_SVG: 555 if (nsGkAtoms::image == aName || nsGkAtoms::feImage == aName) { 556 nsHtml5String url = 557 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); 558 if (!url) { 559 url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); 560 } 561 if (url) { 562 nsHtml5String crossOrigin = 563 aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); 564 nsHtml5String fetchPriority = 565 aAttributes->getValue(nsHtml5AttributeName::ATTR_FETCHPRIORITY); 566 567 mSpeculativeLoadQueue.AppendElement()->InitImage( 568 url, crossOrigin, /* aMedia = */ nullptr, nullptr, nullptr, 569 nullptr, false, fetchPriority, nullptr); 570 } 571 } else if (nsGkAtoms::script == aName) { 572 nsHtml5TreeOperation* treeOp = 573 mOpQueue.AppendElement(mozilla::fallible); 574 if (MOZ_UNLIKELY(!treeOp)) { 575 MarkAsBrokenAndRequestSuspensionWithoutBuilder( 576 NS_ERROR_OUT_OF_MEMORY); 577 return nullptr; 578 } 579 opSetScriptLineAndColumnNumberAndFreeze operation( 580 content, tokenizer->getLineNumber(), 581 // NOTE: tokenizer->getColumnNumber() points '>'. 582 tokenizer->getColumnNumber() + 1); 583 treeOp->Init(mozilla::AsVariant(operation)); 584 585 nsHtml5String type = 586 aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); 587 nsAutoString typeString; 588 getTypeString(type, typeString); 589 590 bool isModule = typeString.LowerCaseEqualsASCII("module"); 591 bool importmap = typeString.LowerCaseEqualsASCII("importmap"); 592 bool async = false; 593 bool defer = false; 594 595 if (importmap) { 596 // If we see an importmap, we don't want to later start speculative 597 // loads for modulepreloads, since such load might finish before 598 // the importmap is created. This also applies to module scripts so 599 // that any modulepreload integrity checks can be performed before 600 // the modules scripts are loaded. 601 // This state is not part of speculation rollback: If an importmap 602 // is seen speculatively and the speculation is rolled back, the 603 // importmap is still considered seen. 604 // TODO: Sync importmap seenness between the main thread and the 605 // parser thread. 606 // https://bugzilla.mozilla.org/show_bug.cgi?id=1848312 607 mHasSeenImportMap = true; 608 } 609 nsHtml5String url = 610 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); 611 if (!url) { 612 url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); 613 } 614 if (url) { 615 async = aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC); 616 defer = aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER); 617 if ((isModule && !mHasSeenImportMap) || (!isModule && !importmap)) { 618 nsHtml5String type = 619 aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); 620 nsHtml5String crossOrigin = 621 aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); 622 nsHtml5String nonce = 623 aAttributes->getValue(nsHtml5AttributeName::ATTR_NONCE); 624 nsHtml5String integrity = 625 aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); 626 nsHtml5String referrerPolicy = aAttributes->getValue( 627 nsHtml5AttributeName::ATTR_REFERRERPOLICY); 628 nsHtml5String fetchPriority = aAttributes->getValue( 629 nsHtml5AttributeName::ATTR_FETCHPRIORITY); 630 631 mSpeculativeLoadQueue.AppendElement()->InitScript( 632 url, nullptr, type, crossOrigin, /* aMedia = */ nullptr, 633 nonce, fetchPriority, integrity, referrerPolicy, 634 mode == nsHtml5TreeBuilder::IN_HEAD, async, defer, false); 635 } 636 } 637 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` MUST be computed to 638 // match the ScriptLoader-perceived kind of the script regardless of 639 // enqueuing a speculative load. Either the attribute prevents a 640 // classic script execution or is ignored on a module script. 641 mCurrentHtmlScriptCannotDocumentWriteOrBlock = 642 isModule || importmap || async || defer; 643 } else if (nsGkAtoms::style == aName) { 644 mImportScanner.Start(); 645 nsHtml5TreeOperation* treeOp = 646 mOpQueue.AppendElement(mozilla::fallible); 647 if (MOZ_UNLIKELY(!treeOp)) { 648 MarkAsBrokenAndRequestSuspensionWithoutBuilder( 649 NS_ERROR_OUT_OF_MEMORY); 650 return nullptr; 651 } 652 opSetStyleLineNumber operation(content, tokenizer->getLineNumber()); 653 treeOp->Init(mozilla::AsVariant(operation)); 654 } 655 break; 656 } 657 } else if (aNamespace != kNameSpaceID_MathML) { 658 // No speculative loader--just line numbers and defer/async check 659 if (nsGkAtoms::style == aName) { 660 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 661 if (MOZ_UNLIKELY(!treeOp)) { 662 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 663 return nullptr; 664 } 665 opSetStyleLineNumber operation(content, tokenizer->getLineNumber()); 666 treeOp->Init(mozilla::AsVariant(operation)); 667 } else if (nsGkAtoms::script == aName) { 668 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 669 if (MOZ_UNLIKELY(!treeOp)) { 670 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 671 return nullptr; 672 } 673 opSetScriptLineAndColumnNumberAndFreeze operation( 674 content, tokenizer->getLineNumber(), 675 // NOTE: tokenizer->getColumnNumber() points '>'. 676 tokenizer->getColumnNumber() + 1); 677 treeOp->Init(mozilla::AsVariant(operation)); 678 if (aNamespace == kNameSpaceID_XHTML) { 679 // Although we come here in cases where the value of 680 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` doesn't actually 681 // matter, we also come here when parsing document.written content on 682 // the main thread. In that case, IT MATTERS that 683 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` is set correctly, 684 // so let's just always set it correctly even if it a bit of wasted work 685 // in the scenarios where no scripts execute and it doesn't matter. 686 // 687 // See the comments around generating speculative loads for HTML scripts 688 // elements for the details of when 689 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` needs to be set to 690 // `true` and when to `false`. 691 692 nsHtml5String type = 693 aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); 694 nsAutoString typeString; 695 getTypeString(type, typeString); 696 697 mCurrentHtmlScriptCannotDocumentWriteOrBlock = 698 typeString.LowerCaseEqualsASCII("module") || 699 typeString.LowerCaseEqualsASCII("nomodule") || 700 typeString.LowerCaseEqualsASCII("importmap"); 701 702 if (!mCurrentHtmlScriptCannotDocumentWriteOrBlock && 703 aAttributes->contains(nsHtml5AttributeName::ATTR_SRC)) { 704 mCurrentHtmlScriptCannotDocumentWriteOrBlock = 705 (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) || 706 aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER)); 707 } 708 } 709 } else if (aNamespace == kNameSpaceID_XHTML) { 710 if (nsGkAtoms::html == aName) { 711 nsHtml5String url = 712 aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); 713 nsHtml5TreeOperation* treeOp = 714 mOpQueue.AppendElement(mozilla::fallible); 715 if (MOZ_UNLIKELY(!treeOp)) { 716 MarkAsBrokenAndRequestSuspensionWithoutBuilder( 717 NS_ERROR_OUT_OF_MEMORY); 718 return nullptr; 719 } 720 if (url) { 721 nsString 722 urlString; // Not Auto, because using it to hold nsStringBuffer* 723 url.ToString(urlString); 724 opProcessOfflineManifest operation(ToNewUnicode(urlString)); 725 treeOp->Init(mozilla::AsVariant(operation)); 726 } else { 727 opProcessOfflineManifest operation(ToNewUnicode(u""_ns)); 728 treeOp->Init(mozilla::AsVariant(operation)); 729 } 730 } else if (nsGkAtoms::base == aName && mViewSource) { 731 nsHtml5String url = 732 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); 733 if (url) { 734 mViewSource->AddBase(url); 735 } 736 } 737 } 738 } 739 740 // End wall of code for speculative loading 741 742 return content; 743 } 744 745 nsIContentHandle* nsHtml5TreeBuilder::createElement( 746 int32_t aNamespace, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes, 747 nsIContentHandle* aFormElement, nsIContentHandle* aIntendedParent, 748 nsHtml5ContentCreatorFunction aCreator) { 749 nsIContentHandle* content = 750 createElement(aNamespace, aName, aAttributes, aIntendedParent, aCreator); 751 if (aFormElement) { 752 if (mBuilder) { 753 nsHtml5TreeOperation::SetFormElement( 754 static_cast<nsIContent*>(content), 755 static_cast<nsIContent*>(aFormElement), 756 static_cast<nsIContent*>(aIntendedParent)); 757 } else { 758 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 759 if (MOZ_UNLIKELY(!treeOp)) { 760 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 761 return nullptr; 762 } 763 opSetFormElement operation(content, aFormElement, aIntendedParent); 764 treeOp->Init(mozilla::AsVariant(operation)); 765 } 766 } 767 return content; 768 } 769 770 nsIContentHandle* nsHtml5TreeBuilder::createHtmlElementSetAsRoot( 771 nsHtml5HtmlAttributes* aAttributes) { 772 nsHtml5ContentCreatorFunction creator; 773 // <html> uses NS_NewHTMLSharedElement creator 774 creator.html = NS_NewHTMLSharedElement; 775 nsIContentHandle* content = createElement(kNameSpaceID_XHTML, nsGkAtoms::html, 776 aAttributes, nullptr, creator); 777 if (mBuilder) { 778 nsresult rv = nsHtml5TreeOperation::AppendToDocument( 779 static_cast<nsIContent*>(content), mBuilder); 780 if (NS_FAILED(rv)) { 781 MarkAsBrokenAndRequestSuspensionWithBuilder(rv); 782 } 783 } else { 784 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 785 if (MOZ_UNLIKELY(!treeOp)) { 786 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 787 return nullptr; 788 } 789 opAppendToDocument operation(content); 790 treeOp->Init(mozilla::AsVariant(operation)); 791 } 792 return content; 793 } 794 795 nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement( 796 int32_t aNamespace, nsAtom* aName, nsHtml5HtmlAttributes* aAttributes, 797 nsIContentHandle* aFormElement, nsIContentHandle* aTable, 798 nsIContentHandle* aStackParent, nsHtml5ContentCreatorFunction aCreator) { 799 MOZ_ASSERT(aTable, "Null table"); 800 MOZ_ASSERT(aStackParent, "Null stack parent"); 801 802 if (mBuilder) { 803 // Get the foster parent to use as the intended parent when creating 804 // the child element. 805 nsIContent* fosterParent = nsHtml5TreeOperation::GetFosterParent( 806 static_cast<nsIContent*>(aTable), 807 static_cast<nsIContent*>(aStackParent)); 808 809 nsIContentHandle* child = createElement( 810 aNamespace, aName, aAttributes, aFormElement, fosterParent, aCreator); 811 812 insertFosterParentedChild(child, aTable, aStackParent); 813 814 return child; 815 } 816 817 // Tree op to get the foster parent that we use as the intended parent 818 // when creating the child element. 819 nsHtml5TreeOperation* fosterParentTreeOp = mOpQueue.AppendElement(); 820 NS_ASSERTION(fosterParentTreeOp, "Tree op allocation failed."); 821 nsIContentHandle* fosterParentHandle = AllocateContentHandle(); 822 opGetFosterParent operation(aTable, aStackParent, fosterParentHandle); 823 fosterParentTreeOp->Init(mozilla::AsVariant(operation)); 824 825 // Create the element with the correct intended parent. 826 nsIContentHandle* child = 827 createElement(aNamespace, aName, aAttributes, aFormElement, 828 fosterParentHandle, aCreator); 829 830 // Insert the child into the foster parent. 831 insertFosterParentedChild(child, aTable, aStackParent); 832 833 return child; 834 } 835 836 void nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement) { 837 MOZ_ASSERT(aElement, "Null element"); 838 839 if (mBuilder) { 840 nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement), mBuilder); 841 return; 842 } 843 844 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 845 if (MOZ_UNLIKELY(!treeOp)) { 846 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 847 return; 848 } 849 opDetach operation(aElement); 850 treeOp->Init(mozilla::AsVariant(operation)); 851 } 852 853 void nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild, 854 nsIContentHandle* aParent) { 855 MOZ_ASSERT(aChild, "Null child"); 856 MOZ_ASSERT(aParent, "Null parent"); 857 858 if (mBuilder) { 859 nsresult rv = nsHtml5TreeOperation::Append( 860 static_cast<nsIContent*>(aChild), static_cast<nsIContent*>(aParent), 861 mozilla::dom::FROM_PARSER_FRAGMENT, mBuilder); 862 if (NS_FAILED(rv)) { 863 MarkAsBrokenAndRequestSuspensionWithBuilder(rv); 864 } 865 return; 866 } 867 868 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 869 if (MOZ_UNLIKELY(!treeOp)) { 870 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 871 return; 872 } 873 874 opAppend operation(aChild, aParent, 875 (!!mSpeculativeLoadStage) 876 ? mozilla::dom::FROM_PARSER_NETWORK 877 : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE); 878 treeOp->Init(mozilla::AsVariant(operation)); 879 } 880 881 void nsHtml5TreeBuilder::appendChildrenToNewParent( 882 nsIContentHandle* aOldParent, nsIContentHandle* aNewParent) { 883 MOZ_ASSERT(aOldParent, "Null old parent"); 884 MOZ_ASSERT(aNewParent, "Null new parent"); 885 886 if (mBuilder) { 887 nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent( 888 static_cast<nsIContent*>(aOldParent), 889 static_cast<nsIContent*>(aNewParent), mBuilder); 890 if (NS_FAILED(rv)) { 891 MarkAsBrokenAndRequestSuspensionWithBuilder(rv); 892 } 893 return; 894 } 895 896 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 897 if (MOZ_UNLIKELY(!treeOp)) { 898 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 899 return; 900 } 901 opAppendChildrenToNewParent operation(aOldParent, aNewParent); 902 treeOp->Init(mozilla::AsVariant(operation)); 903 } 904 905 void nsHtml5TreeBuilder::insertFosterParentedCharacters( 906 char16_t* aBuffer, int32_t aStart, int32_t aLength, 907 nsIContentHandle* aTable, nsIContentHandle* aStackParent) { 908 MOZ_ASSERT(aBuffer, "Null buffer"); 909 MOZ_ASSERT(aTable, "Null table"); 910 MOZ_ASSERT(aStackParent, "Null stack parent"); 911 MOZ_ASSERT(!aStart, "aStart must always be zero."); 912 913 if (mBuilder) { 914 nsresult rv = nsHtml5TreeOperation::FosterParentText( 915 static_cast<nsIContent*>(aStackParent), 916 aBuffer, // XXX aStart always ignored??? 917 aLength, static_cast<nsIContent*>(aTable), mBuilder); 918 if (NS_FAILED(rv)) { 919 MarkAsBrokenAndRequestSuspensionWithBuilder(rv); 920 } 921 return; 922 } 923 924 auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength); 925 if (!bufferCopy) { 926 // Just assigning mBroken instead of generating tree op. The caller 927 // of tokenizeBuffer() will call MarkAsBroken() as appropriate. 928 mBroken = NS_ERROR_OUT_OF_MEMORY; 929 requestSuspension(); 930 return; 931 } 932 933 memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t)); 934 935 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 936 if (MOZ_UNLIKELY(!treeOp)) { 937 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 938 return; 939 } 940 opFosterParentText operation(aStackParent, bufferCopy.release(), aTable, 941 aLength); 942 treeOp->Init(mozilla::AsVariant(operation)); 943 } 944 945 void nsHtml5TreeBuilder::insertFosterParentedChild( 946 nsIContentHandle* aChild, nsIContentHandle* aTable, 947 nsIContentHandle* aStackParent) { 948 MOZ_ASSERT(aChild, "Null child"); 949 MOZ_ASSERT(aTable, "Null table"); 950 MOZ_ASSERT(aStackParent, "Null stack parent"); 951 952 if (mBuilder) { 953 nsresult rv = nsHtml5TreeOperation::FosterParent( 954 static_cast<nsIContent*>(aChild), 955 static_cast<nsIContent*>(aStackParent), 956 static_cast<nsIContent*>(aTable), mBuilder); 957 if (NS_FAILED(rv)) { 958 MarkAsBrokenAndRequestSuspensionWithBuilder(rv); 959 } 960 return; 961 } 962 963 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 964 if (MOZ_UNLIKELY(!treeOp)) { 965 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 966 return; 967 } 968 opFosterParent operation(aChild, aStackParent, aTable); 969 treeOp->Init(mozilla::AsVariant(operation)); 970 } 971 972 void nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent, 973 char16_t* aBuffer, int32_t aStart, 974 int32_t aLength) { 975 MOZ_ASSERT(aBuffer, "Null buffer"); 976 MOZ_ASSERT(aParent, "Null parent"); 977 MOZ_ASSERT(!aStart, "aStart must always be zero."); 978 979 if (mBuilder) { 980 nsresult rv = nsHtml5TreeOperation::AppendText( 981 aBuffer, // XXX aStart always ignored??? 982 aLength, static_cast<nsIContent*>(aParent), mBuilder); 983 if (NS_FAILED(rv)) { 984 MarkAsBrokenAndRequestSuspensionWithBuilder(rv); 985 } 986 return; 987 } 988 989 auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength); 990 if (!bufferCopy) { 991 // Just assigning mBroken instead of generating tree op. The caller 992 // of tokenizeBuffer() will call MarkAsBroken() as appropriate. 993 mBroken = NS_ERROR_OUT_OF_MEMORY; 994 requestSuspension(); 995 return; 996 } 997 998 memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t)); 999 1000 if (mImportScanner.ShouldScan()) { 1001 nsTArray<nsString> imports = 1002 mImportScanner.Scan(mozilla::Span(aBuffer, aLength)); 1003 for (nsString& url : imports) { 1004 mSpeculativeLoadQueue.AppendElement()->InitImportStyle(std::move(url)); 1005 } 1006 } 1007 1008 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1009 if (MOZ_UNLIKELY(!treeOp)) { 1010 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1011 return; 1012 } 1013 opAppendText operation(aParent, bufferCopy.release(), aLength); 1014 treeOp->Init(mozilla::AsVariant(operation)); 1015 } 1016 1017 void nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent, 1018 char16_t* aBuffer, int32_t aStart, 1019 int32_t aLength) { 1020 MOZ_ASSERT(aBuffer, "Null buffer"); 1021 MOZ_ASSERT(aParent, "Null parent"); 1022 MOZ_ASSERT(!aStart, "aStart must always be zero."); 1023 1024 if (mBuilder) { 1025 nsresult rv = nsHtml5TreeOperation::AppendComment( 1026 static_cast<nsIContent*>(aParent), 1027 aBuffer, // XXX aStart always ignored??? 1028 aLength, mBuilder); 1029 if (NS_FAILED(rv)) { 1030 MarkAsBrokenAndRequestSuspensionWithBuilder(rv); 1031 } 1032 return; 1033 } 1034 1035 auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength); 1036 if (!bufferCopy) { 1037 // Just assigning mBroken instead of generating tree op. The caller 1038 // of tokenizeBuffer() will call MarkAsBroken() as appropriate. 1039 mBroken = NS_ERROR_OUT_OF_MEMORY; 1040 requestSuspension(); 1041 return; 1042 } 1043 1044 memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t)); 1045 1046 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1047 if (MOZ_UNLIKELY(!treeOp)) { 1048 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1049 return; 1050 } 1051 opAppendComment operation(aParent, bufferCopy.release(), aLength); 1052 treeOp->Init(mozilla::AsVariant(operation)); 1053 } 1054 1055 void nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer, 1056 int32_t aStart, 1057 int32_t aLength) { 1058 MOZ_ASSERT(aBuffer, "Null buffer"); 1059 MOZ_ASSERT(!aStart, "aStart must always be zero."); 1060 1061 if (mBuilder) { 1062 nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument( 1063 aBuffer, // XXX aStart always ignored??? 1064 aLength, mBuilder); 1065 if (NS_FAILED(rv)) { 1066 MarkAsBrokenAndRequestSuspensionWithBuilder(rv); 1067 } 1068 return; 1069 } 1070 1071 auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength); 1072 if (!bufferCopy) { 1073 // Just assigning mBroken instead of generating tree op. The caller 1074 // of tokenizeBuffer() will call MarkAsBroken() as appropriate. 1075 mBroken = NS_ERROR_OUT_OF_MEMORY; 1076 requestSuspension(); 1077 return; 1078 } 1079 1080 memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t)); 1081 1082 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1083 if (MOZ_UNLIKELY(!treeOp)) { 1084 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1085 return; 1086 } 1087 opAppendCommentToDocument data(bufferCopy.release(), aLength); 1088 treeOp->Init(mozilla::AsVariant(data)); 1089 } 1090 1091 void nsHtml5TreeBuilder::addAttributesToElement( 1092 nsIContentHandle* aElement, nsHtml5HtmlAttributes* aAttributes) { 1093 MOZ_ASSERT(aElement, "Null element"); 1094 MOZ_ASSERT(aAttributes, "Null attributes"); 1095 1096 if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) { 1097 return; 1098 } 1099 1100 if (mBuilder) { 1101 MOZ_ASSERT( 1102 aAttributes == tokenizer->GetAttributes(), 1103 "Using attribute other than the tokenizer's to add to body or html."); 1104 nsresult rv = nsHtml5TreeOperation::AddAttributes( 1105 static_cast<nsIContent*>(aElement), aAttributes, mBuilder); 1106 if (NS_FAILED(rv)) { 1107 MarkAsBrokenAndRequestSuspensionWithBuilder(rv); 1108 } 1109 return; 1110 } 1111 1112 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1113 if (MOZ_UNLIKELY(!treeOp)) { 1114 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1115 return; 1116 } 1117 opAddAttributes opeation(aElement, aAttributes); 1118 treeOp->Init(mozilla::AsVariant(opeation)); 1119 } 1120 1121 void nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement) { 1122 MOZ_ASSERT(aElement, "Null element"); 1123 1124 if (mBuilder) { 1125 nsHtml5TreeOperation::MarkMalformedIfScript( 1126 static_cast<nsIContent*>(aElement)); 1127 return; 1128 } 1129 1130 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1131 if (MOZ_UNLIKELY(!treeOp)) { 1132 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1133 return; 1134 } 1135 opMarkMalformedIfScript operation(aElement); 1136 treeOp->Init(mozilla::AsVariant(operation)); 1137 } 1138 1139 void nsHtml5TreeBuilder::start(bool fragment) { 1140 mCurrentHtmlScriptCannotDocumentWriteOrBlock = false; 1141 mozilla::glean::parsing::svg_unusual_pcdata.AddToDenominator(1); 1142 1143 #ifdef DEBUG 1144 mActive = true; 1145 #endif 1146 } 1147 1148 void nsHtml5TreeBuilder::end() { 1149 mOpQueue.Clear(); 1150 #ifdef DEBUG 1151 mActive = false; 1152 #endif 1153 } 1154 1155 void nsHtml5TreeBuilder::appendDoctypeToDocument(nsAtom* aName, 1156 nsHtml5String aPublicId, 1157 nsHtml5String aSystemId) { 1158 MOZ_ASSERT(aName, "Null name"); 1159 nsString publicId; // Not Auto, because using it to hold nsStringBuffer* 1160 nsString systemId; // Not Auto, because using it to hold nsStringBuffer* 1161 aPublicId.ToString(publicId); 1162 aSystemId.ToString(systemId); 1163 if (mBuilder) { 1164 nsresult rv = nsHtml5TreeOperation::AppendDoctypeToDocument( 1165 aName, publicId, systemId, mBuilder); 1166 if (NS_FAILED(rv)) { 1167 MarkAsBrokenAndRequestSuspensionWithBuilder(rv); 1168 } 1169 return; 1170 } 1171 1172 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1173 if (MOZ_UNLIKELY(!treeOp)) { 1174 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1175 return; 1176 } 1177 opAppendDoctypeToDocument operation(aName, publicId, systemId); 1178 treeOp->Init(mozilla::AsVariant(operation)); 1179 // nsXMLContentSink can flush here, but what's the point? 1180 // It can also interrupt here, but we can't. 1181 } 1182 1183 void nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsAtom* aName, 1184 nsIContentHandle* aElement) { 1185 NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || 1186 aNamespace == kNameSpaceID_SVG || 1187 aNamespace == kNameSpaceID_MathML, 1188 "Element isn't HTML, SVG or MathML!"); 1189 NS_ASSERTION(aName, "Element doesn't have local name!"); 1190 NS_ASSERTION(aElement, "No element!"); 1191 /* 1192 * The frame constructor uses recursive algorithms, so it can't deal with 1193 * arbitrarily deep trees. This is especially a problem on Windows where 1194 * the permitted depth of the runtime stack is rather small. 1195 * 1196 * The following is a protection against author incompetence--not against 1197 * malice. There are other ways to make the DOM deep anyway. 1198 * 1199 * The basic idea is that when the tree builder stack gets too deep, 1200 * append operations no longer append to the node that the HTML parsing 1201 * algorithm says they should but instead text nodes are append to the last 1202 * element that was seen before a magic tree builder stack threshold was 1203 * reached and element and comment nodes aren't appended to the DOM at all. 1204 * 1205 * However, for security reasons, non-child descendant text nodes inside an 1206 * SVG script or style element should not become children. Also, non-cell 1207 * table elements shouldn't be used as surrogate parents for user experience 1208 * reasons. 1209 */ 1210 1211 if (MOZ_UNLIKELY(isInSVGOddPCData)) { 1212 // We are seeing an element that has children, which could not have child 1213 // elements in HTML, i.e., is parsed as PCDATA in SVG but CDATA in HTML. 1214 mozilla::glean::parsing::svg_unusual_pcdata.AddToNumerator(1); 1215 } 1216 if (MOZ_UNLIKELY(aNamespace == kNameSpaceID_SVG)) { 1217 if ((aName == nsGkAtoms::style) || (aName == nsGkAtoms::xmp) || 1218 (aName == nsGkAtoms::iframe) || (aName == nsGkAtoms::noembed) || 1219 (aName == nsGkAtoms::noframes) || (aName == nsGkAtoms::noscript) || 1220 (aName == nsGkAtoms::script)) { 1221 isInSVGOddPCData++; 1222 } 1223 } 1224 1225 if (aNamespace != kNameSpaceID_XHTML) { 1226 return; 1227 } 1228 if (aName == nsGkAtoms::body || aName == nsGkAtoms::frameset) { 1229 if (mBuilder) { 1230 // InnerHTML and DOMParser shouldn't start layout anyway 1231 return; 1232 } 1233 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1234 if (MOZ_UNLIKELY(!treeOp)) { 1235 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1236 return; 1237 } 1238 treeOp->Init(mozilla::AsVariant(opStartLayout())); 1239 return; 1240 } 1241 if (nsIContent::RequiresDoneCreatingElement(kNameSpaceID_XHTML, aName)) { 1242 if (mBuilder) { 1243 nsHtml5TreeOperation::DoneCreatingElement( 1244 static_cast<nsIContent*>(aElement)); 1245 } else { 1246 opDoneCreatingElement operation(aElement); 1247 mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation)); 1248 } 1249 return; 1250 } 1251 if (mGenerateSpeculativeLoads && aName == nsGkAtoms::picture) { 1252 // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading 1253 mSpeculativeLoadQueue.AppendElement()->InitOpenPicture(); 1254 return; 1255 } 1256 if (aName == nsGkAtoms::_template) { 1257 if (tokenizer->TemplatePushedOrHeadPopped()) { 1258 requestSuspension(); 1259 } 1260 } 1261 } 1262 1263 void nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsAtom* aName, 1264 nsIContentHandle* aElement) { 1265 NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || 1266 aNamespace == kNameSpaceID_SVG || 1267 aNamespace == kNameSpaceID_MathML, 1268 "Element isn't HTML, SVG or MathML!"); 1269 NS_ASSERTION(aName, "Element doesn't have local name!"); 1270 NS_ASSERTION(aElement, "No element!"); 1271 if (aNamespace == kNameSpaceID_MathML) { 1272 return; 1273 } 1274 if (MOZ_UNLIKELY(aNamespace == kNameSpaceID_SVG)) { 1275 if ((aName == nsGkAtoms::style) || (aName == nsGkAtoms::xmp) || 1276 (aName == nsGkAtoms::iframe) || (aName == nsGkAtoms::noembed) || 1277 (aName == nsGkAtoms::noframes) || (aName == nsGkAtoms::noscript) || 1278 (aName == nsGkAtoms::script)) { 1279 isInSVGOddPCData--; 1280 } 1281 } 1282 // we now have only SVG and HTML 1283 if (aName == nsGkAtoms::script) { 1284 if (mPreventScriptExecution) { 1285 if (mBuilder) { 1286 nsHtml5TreeOperation::PreventScriptExecution( 1287 static_cast<nsIContent*>(aElement)); 1288 return; 1289 } 1290 opPreventScriptExecution operation(aElement); 1291 mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation)); 1292 return; 1293 } 1294 if (mBuilder) { 1295 return; 1296 } 1297 1298 // https://html.spec.whatwg.org/#parsing-main-incdata 1299 // An end tag whose tag name is "script" 1300 // - If the active speculative HTML parser is null and the JavaScript 1301 // execution context stack is empty, then perform a microtask checkpoint. 1302 nsHtml5TreeOperation* treeOpMicrotask = 1303 mOpQueue.AppendElement(mozilla::fallible); 1304 if (MOZ_UNLIKELY(!treeOpMicrotask)) { 1305 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1306 return; 1307 } 1308 treeOpMicrotask->Init(mozilla::AsVariant(opMicrotaskCheckpoint())); 1309 1310 if (mCurrentHtmlScriptCannotDocumentWriteOrBlock) { 1311 NS_ASSERTION( 1312 aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG, 1313 "Only HTML and SVG scripts may be async/defer."); 1314 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1315 if (MOZ_UNLIKELY(!treeOp)) { 1316 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1317 return; 1318 } 1319 opRunScriptThatCannotDocumentWriteOrBlock operation(aElement); 1320 treeOp->Init(mozilla::AsVariant(operation)); 1321 mCurrentHtmlScriptCannotDocumentWriteOrBlock = false; 1322 return; 1323 } 1324 requestSuspension(); 1325 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1326 if (MOZ_UNLIKELY(!treeOp)) { 1327 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1328 return; 1329 } 1330 opRunScriptThatMayDocumentWriteOrBlock operation(aElement, nullptr); 1331 treeOp->Init(mozilla::AsVariant(operation)); 1332 return; 1333 } 1334 // Some nodes need DoneAddingChildren() called to initialize 1335 // properly (e.g. form state restoration). 1336 if (nsIContent::RequiresDoneAddingChildren(aNamespace, aName)) { 1337 if (mBuilder) { 1338 nsHtml5TreeOperation::DoneAddingChildren( 1339 static_cast<nsIContent*>(aElement)); 1340 return; 1341 } 1342 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1343 if (MOZ_UNLIKELY(!treeOp)) { 1344 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1345 return; 1346 } 1347 opDoneAddingChildren operation(aElement); 1348 treeOp->Init(mozilla::AsVariant(operation)); 1349 if (aNamespace == kNameSpaceID_XHTML && aName == nsGkAtoms::head) { 1350 if (tokenizer->TemplatePushedOrHeadPopped()) { 1351 requestSuspension(); 1352 } 1353 } 1354 return; 1355 } 1356 if (aName == nsGkAtoms::style || 1357 (aNamespace == kNameSpaceID_XHTML && aName == nsGkAtoms::link)) { 1358 if (mBuilder) { 1359 MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), 1360 "Scripts must be blocked."); 1361 mBuilder->UpdateStyleSheet(static_cast<nsIContent*>(aElement)); 1362 return; 1363 } 1364 1365 if (aName == nsGkAtoms::style) { 1366 nsTArray<nsString> imports = mImportScanner.Stop(); 1367 for (nsString& url : imports) { 1368 mSpeculativeLoadQueue.AppendElement()->InitImportStyle(std::move(url)); 1369 } 1370 } 1371 1372 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1373 if (MOZ_UNLIKELY(!treeOp)) { 1374 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1375 return; 1376 } 1377 opUpdateStyleSheet operation(aElement); 1378 treeOp->Init(mozilla::AsVariant(operation)); 1379 return; 1380 } 1381 if (aNamespace == kNameSpaceID_SVG) { 1382 if (aName == nsGkAtoms::svg) { 1383 if (!scriptingEnabled || mPreventScriptExecution) { 1384 return; 1385 } 1386 if (mBuilder) { 1387 nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement)); 1388 return; 1389 } 1390 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1391 if (MOZ_UNLIKELY(!treeOp)) { 1392 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1393 return; 1394 } 1395 opSvgLoad operation(aElement); 1396 treeOp->Init(mozilla::AsVariant(operation)); 1397 } 1398 return; 1399 } 1400 1401 if (mGenerateSpeculativeLoads && aName == nsGkAtoms::picture) { 1402 // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading 1403 mSpeculativeLoadQueue.AppendElement()->InitEndPicture(); 1404 return; 1405 } 1406 } 1407 1408 void nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, 1409 int32_t aStart, int32_t aLength) { 1410 MOZ_RELEASE_ASSERT(charBufferLen + aLength <= charBuffer.length, 1411 "About to memcpy past the end of the buffer!"); 1412 memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength); 1413 charBufferLen += aLength; 1414 } 1415 1416 // INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits 1417 // is 2^30. Note that this is counting char16_t units. The underlying 1418 // bytes will be twice that, but they fit even in 32-bit size_t even 1419 // if a contiguous chunk of memory of that size is pretty unlikely to 1420 // be available on a 32-bit system. 1421 #define MAX_POWER_OF_TWO_IN_INT32 0x40000000 1422 1423 bool nsHtml5TreeBuilder::EnsureBufferSpace(int32_t aLength) { 1424 // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer 1425 // so that this method becomes unnecessary. 1426 mozilla::CheckedInt<int32_t> worstCase(charBufferLen); 1427 worstCase += aLength; 1428 if (!worstCase.isValid()) { 1429 return false; 1430 } 1431 if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) { 1432 return false; 1433 } 1434 if (!charBuffer) { 1435 if (worstCase.value() < MAX_POWER_OF_TWO_IN_INT32) { 1436 // Add one to round to the next power of two to avoid immediate 1437 // reallocation once there are a few characters in the buffer. 1438 worstCase += 1; 1439 } 1440 charBuffer = jArray<char16_t, int32_t>::newFallibleJArray( 1441 mozilla::RoundUpPow2(worstCase.value())); 1442 if (!charBuffer) { 1443 return false; 1444 } 1445 } else if (worstCase.value() > charBuffer.length) { 1446 jArray<char16_t, int32_t> newBuf = 1447 jArray<char16_t, int32_t>::newFallibleJArray( 1448 mozilla::RoundUpPow2(worstCase.value())); 1449 if (!newBuf) { 1450 return false; 1451 } 1452 memcpy(newBuf, charBuffer, sizeof(char16_t) * size_t(charBufferLen)); 1453 charBuffer = newBuf; 1454 } 1455 return true; 1456 } 1457 1458 nsIContentHandle* nsHtml5TreeBuilder::AllocateContentHandle() { 1459 if (MOZ_UNLIKELY(mBuilder)) { 1460 MOZ_ASSERT_UNREACHABLE("Must never allocate a handle with builder."); 1461 return nullptr; 1462 } 1463 if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) { 1464 mOldHandles.AppendElement(std::move(mHandles)); 1465 mHandles = mozilla::MakeUnique<nsIContent*[]>( 1466 NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH); 1467 mHandlesUsed = 0; 1468 } 1469 #ifdef DEBUG 1470 mHandles[mHandlesUsed] = reinterpret_cast<nsIContent*>(uintptr_t(0xC0DEDBAD)); 1471 #endif 1472 return &mHandles[mHandlesUsed++]; 1473 } 1474 1475 bool nsHtml5TreeBuilder::HasScriptThatMayDocumentWriteOrBlock() { 1476 uint32_t len = mOpQueue.Length(); 1477 if (!len) { 1478 return false; 1479 } 1480 return mOpQueue.ElementAt(len - 1).IsRunScriptThatMayDocumentWriteOrBlock(); 1481 } 1482 1483 mozilla::Result<bool, nsresult> nsHtml5TreeBuilder::Flush(bool aDiscretionary) { 1484 if (MOZ_UNLIKELY(mBuilder)) { 1485 MOZ_ASSERT_UNREACHABLE("Must never flush with builder."); 1486 return false; 1487 } 1488 if (NS_SUCCEEDED(mBroken)) { 1489 if (!aDiscretionary || !(charBufferLen && currentPtr >= 0 && 1490 stack[currentPtr]->isFosterParenting())) { 1491 // Don't flush text on discretionary flushes if the current element on 1492 // the stack is a foster-parenting element and there's pending text, 1493 // because flushing in that case would make the tree shape dependent on 1494 // where the flush points fall. 1495 flushCharacters(); 1496 } 1497 FlushLoads(); 1498 } 1499 if (mOpSink) { 1500 bool hasOps = !mOpQueue.IsEmpty(); 1501 if (hasOps) { 1502 // If the builder is broken and mOpQueue is not empty, there must be 1503 // one op and it must be eTreeOpMarkAsBroken. 1504 if (NS_FAILED(mBroken)) { 1505 MOZ_ASSERT(mOpQueue.Length() == 1, 1506 "Tree builder is broken with a non-empty op queue whose " 1507 "length isn't 1."); 1508 MOZ_ASSERT(mOpQueue[0].IsMarkAsBroken(), 1509 "Tree builder is broken but the op in queue is not marked " 1510 "as broken."); 1511 } 1512 if (!mOpSink->MoveOpsFrom(mOpQueue)) { 1513 return mozilla::Err(NS_ERROR_OUT_OF_MEMORY); 1514 } 1515 } 1516 return hasOps; 1517 } 1518 // no op sink: throw away ops 1519 mOpQueue.Clear(); 1520 return false; 1521 } 1522 1523 void nsHtml5TreeBuilder::FlushLoads() { 1524 if (MOZ_UNLIKELY(mBuilder)) { 1525 MOZ_ASSERT_UNREACHABLE("Must never flush loads with builder."); 1526 return; 1527 } 1528 if (!mSpeculativeLoadQueue.IsEmpty()) { 1529 mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue); 1530 } 1531 } 1532 1533 void nsHtml5TreeBuilder::SetDocumentCharset(NotNull<const Encoding*> aEncoding, 1534 nsCharsetSource aCharsetSource, 1535 bool aCommitEncodingSpeculation) { 1536 MOZ_ASSERT(!mBuilder, "How did we call this with builder?"); 1537 MOZ_ASSERT(mSpeculativeLoadStage, 1538 "How did we call this without a speculative load stage?"); 1539 mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset( 1540 aEncoding, aCharsetSource, aCommitEncodingSpeculation); 1541 } 1542 1543 void nsHtml5TreeBuilder::UpdateCharsetSource(nsCharsetSource aCharsetSource) { 1544 MOZ_ASSERT(!mBuilder, "How did we call this with builder?"); 1545 MOZ_ASSERT(mSpeculativeLoadStage, 1546 "How did we call this without a speculative load stage (even " 1547 "though we don't need it right here)?"); 1548 if (mViewSource) { 1549 mViewSource->UpdateCharsetSource(aCharsetSource); 1550 return; 1551 } 1552 opUpdateCharsetSource operation(aCharsetSource); 1553 mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation)); 1554 } 1555 1556 void nsHtml5TreeBuilder::StreamEnded() { 1557 MOZ_ASSERT(!mBuilder, "Must not call StreamEnded with builder."); 1558 MOZ_ASSERT(!fragment, "Must not parse fragments off the main thread."); 1559 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1560 if (MOZ_UNLIKELY(!treeOp)) { 1561 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1562 return; 1563 } 1564 treeOp->Init(mozilla::AsVariant(opStreamEnded())); 1565 } 1566 1567 void nsHtml5TreeBuilder::NeedsCharsetSwitchTo( 1568 NotNull<const Encoding*> aEncoding, int32_t aCharsetSource, 1569 int32_t aLineNumber) { 1570 if (MOZ_UNLIKELY(mBuilder)) { 1571 MOZ_ASSERT_UNREACHABLE("Must never switch charset with builder."); 1572 return; 1573 } 1574 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1575 if (MOZ_UNLIKELY(!treeOp)) { 1576 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1577 return; 1578 } 1579 opCharsetSwitchTo opeation(aEncoding, aCharsetSource, aLineNumber); 1580 treeOp->Init(mozilla::AsVariant(opeation)); 1581 } 1582 1583 void nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId, 1584 bool aError, 1585 int32_t aLineNumber) { 1586 if (MOZ_UNLIKELY(mBuilder)) { 1587 MOZ_ASSERT_UNREACHABLE("Must never complain about charset with builder."); 1588 return; 1589 } 1590 1591 if (mSpeculativeLoadStage) { 1592 mSpeculativeLoadQueue.AppendElement()->InitMaybeComplainAboutCharset( 1593 aMsgId, aError, aLineNumber); 1594 } else { 1595 opMaybeComplainAboutCharset opeartion(const_cast<char*>(aMsgId), aError, 1596 aLineNumber); 1597 mOpQueue.AppendElement()->Init(mozilla::AsVariant(opeartion)); 1598 } 1599 } 1600 1601 void nsHtml5TreeBuilder::TryToEnableEncodingMenu() { 1602 if (MOZ_UNLIKELY(mBuilder)) { 1603 MOZ_ASSERT_UNREACHABLE("Must never disable encoding menu with builder."); 1604 return; 1605 } 1606 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1607 NS_ASSERTION(treeOp, "Tree op allocation failed."); 1608 treeOp->Init(mozilla::AsVariant(opEnableEncodingMenu())); 1609 } 1610 1611 void nsHtml5TreeBuilder::AddSnapshotToScript( 1612 nsAHtml5TreeBuilderState* aSnapshot, int32_t aLine) { 1613 if (MOZ_UNLIKELY(mBuilder)) { 1614 MOZ_ASSERT_UNREACHABLE("Must never use snapshots with builder."); 1615 return; 1616 } 1617 MOZ_ASSERT(HasScriptThatMayDocumentWriteOrBlock(), 1618 "No script to add a snapshot to!"); 1619 MOZ_ASSERT(aSnapshot, "Got null snapshot."); 1620 mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine); 1621 } 1622 1623 void nsHtml5TreeBuilder::DropHandles() { 1624 MOZ_ASSERT(!mBuilder, "Must not drop handles with builder."); 1625 mOldHandles.Clear(); 1626 mHandlesUsed = 0; 1627 } 1628 1629 void nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv) { 1630 if (MOZ_UNLIKELY(mBuilder)) { 1631 MOZ_ASSERT_UNREACHABLE("Must not call this with builder."); 1632 return; 1633 } 1634 mBroken = aRv; 1635 mOpQueue.Clear(); // Previous ops don't matter anymore 1636 opMarkAsBroken operation(aRv); 1637 mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation)); 1638 } 1639 1640 void nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv) { 1641 if (mBuilder) { 1642 MarkAsBrokenAndRequestSuspensionWithBuilder(aRv); 1643 return; 1644 } 1645 mBroken = aRv; 1646 requestSuspension(); 1647 } 1648 1649 void nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle) { 1650 MOZ_ASSERT(!mBuilder, "Must not view source with builder."); 1651 1652 startTag(nsHtml5ElementName::ELT_META, 1653 nsHtml5ViewSourceUtils::NewMetaViewportAttributes(), false); 1654 1655 startTag(nsHtml5ElementName::ELT_TITLE, 1656 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, false); 1657 1658 // XUL will add the "Source of: " prefix. 1659 uint32_t length = aTitle.Length(); 1660 if (length > INT32_MAX) { 1661 length = INT32_MAX; 1662 } 1663 characters(aTitle.get(), 0, (int32_t)length); 1664 endTag(nsHtml5ElementName::ELT_TITLE); 1665 1666 startTag(nsHtml5ElementName::ELT_LINK, 1667 nsHtml5ViewSourceUtils::NewLinkAttributes(), false); 1668 1669 startTag(nsHtml5ElementName::ELT_BODY, 1670 nsHtml5ViewSourceUtils::NewBodyAttributes(), false); 1671 1672 StartPlainTextBody(); 1673 } 1674 1675 void nsHtml5TreeBuilder::StartPlainText() { 1676 MOZ_ASSERT(!mBuilder, "Must not view source with builder."); 1677 setForceNoQuirks(true); 1678 startTag(nsHtml5ElementName::ELT_LINK, 1679 nsHtml5PlainTextUtils::NewLinkAttributes(), false); 1680 1681 startTag(nsHtml5ElementName::ELT_BODY, 1682 nsHtml5PlainTextUtils::NewBodyAttributes(), false); 1683 1684 StartPlainTextBody(); 1685 } 1686 1687 void nsHtml5TreeBuilder::StartPlainTextBody() { 1688 MOZ_ASSERT(!mBuilder, "Must not view source with builder."); 1689 startTag(nsHtml5ElementName::ELT_PRE, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, 1690 false); 1691 needToDropLF = false; 1692 } 1693 1694 // DocumentModeHandler 1695 void nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m) { 1696 if (mBuilder) { 1697 mBuilder->SetDocumentMode(m); 1698 return; 1699 } 1700 if (mSpeculativeLoadStage) { 1701 mSpeculativeLoadQueue.AppendElement()->InitSetDocumentMode(m); 1702 return; 1703 } 1704 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1705 if (MOZ_UNLIKELY(!treeOp)) { 1706 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1707 return; 1708 } 1709 treeOp->Init(mozilla::AsVariant(m)); 1710 } 1711 1712 nsIContentHandle* nsHtml5TreeBuilder::getDocumentFragmentForTemplate( 1713 nsIContentHandle* aTemplate) { 1714 if (mBuilder) { 1715 return nsHtml5TreeOperation::GetDocumentFragmentForTemplate( 1716 static_cast<nsIContent*>(aTemplate)); 1717 } 1718 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1719 if (MOZ_UNLIKELY(!treeOp)) { 1720 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1721 return nullptr; 1722 } 1723 nsIContentHandle* fragHandle = AllocateContentHandle(); 1724 opGetDocumentFragmentForTemplate operation(aTemplate, fragHandle); 1725 treeOp->Init(mozilla::AsVariant(operation)); 1726 return fragHandle; 1727 } 1728 1729 void nsHtml5TreeBuilder::setDocumentFragmentForTemplate( 1730 nsIContentHandle* aTemplate, nsIContentHandle* aFragment) { 1731 if (mBuilder) { 1732 nsHtml5TreeOperation::SetDocumentFragmentForTemplate( 1733 static_cast<nsIContent*>(aTemplate), 1734 static_cast<nsIContent*>(aFragment)); 1735 return; 1736 } 1737 1738 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1739 if (MOZ_UNLIKELY(!treeOp)) { 1740 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1741 return; 1742 } 1743 opSetDocumentFragmentForTemplate operation(aTemplate, aFragment); 1744 treeOp->Init(mozilla::AsVariant(operation)); 1745 } 1746 1747 nsIContentHandle* nsHtml5TreeBuilder::getShadowRootFromHost( 1748 nsIContentHandle* aHost, nsIContentHandle* aTemplateNode, 1749 nsHtml5String aShadowRootMode, bool aShadowRootIsClonable, 1750 bool aShadowRootIsSerializable, bool aShadowRootDelegatesFocus, 1751 nsHtml5String aShadowRootReferenceTarget) { 1752 mozilla::dom::ShadowRootMode mode; 1753 if (aShadowRootMode.LowerCaseEqualsASCII("open")) { 1754 mode = mozilla::dom::ShadowRootMode::Open; 1755 } else if (aShadowRootMode.LowerCaseEqualsASCII("closed")) { 1756 mode = mozilla::dom::ShadowRootMode::Closed; 1757 } else { 1758 return nullptr; 1759 } 1760 1761 nsString shadowRootReferenceTarget; 1762 aShadowRootReferenceTarget.ToString(shadowRootReferenceTarget); 1763 1764 if (mBuilder) { 1765 nsIContent* root = nsContentUtils::AttachDeclarativeShadowRoot( 1766 static_cast<nsIContent*>(aHost), mode, aShadowRootIsClonable, 1767 aShadowRootIsSerializable, aShadowRootDelegatesFocus, 1768 shadowRootReferenceTarget); 1769 if (!root) { 1770 nsContentUtils::LogSimpleConsoleError( 1771 u"Failed to attach Declarative Shadow DOM."_ns, "DOM"_ns, 1772 mBuilder->GetDocument()->IsInPrivateBrowsing(), 1773 mBuilder->GetDocument()->IsInChromeDocShell()); 1774 } 1775 return root; 1776 } 1777 1778 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); 1779 if (MOZ_UNLIKELY(!treeOp)) { 1780 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); 1781 return nullptr; 1782 } 1783 nsIContentHandle* fragHandle = AllocateContentHandle(); 1784 opGetShadowRootFromHost operation( 1785 aHost, fragHandle, aTemplateNode, mode, aShadowRootIsClonable, 1786 aShadowRootIsSerializable, aShadowRootDelegatesFocus, 1787 shadowRootReferenceTarget); 1788 treeOp->Init(mozilla::AsVariant(operation)); 1789 return fragHandle; 1790 } 1791 1792 nsIContentHandle* nsHtml5TreeBuilder::getFormPointerForContext( 1793 nsIContentHandle* aContext) { 1794 MOZ_ASSERT(mBuilder, "Must have builder."); 1795 if (!aContext) { 1796 return nullptr; 1797 } 1798 1799 MOZ_ASSERT(NS_IsMainThread()); 1800 1801 // aContext must always be an element that already exists 1802 // in the document. 1803 nsIContent* contextNode = static_cast<nsIContent*>(aContext); 1804 nsIContent* currentAncestor = contextNode; 1805 1806 // We traverse the ancestors of the context node to find the nearest 1807 // form pointer. This traversal is why aContext must not be an emtpy handle. 1808 nsIContent* nearestForm = nullptr; 1809 while (currentAncestor) { 1810 if (currentAncestor->IsHTMLElement(nsGkAtoms::form)) { 1811 nearestForm = currentAncestor; 1812 break; 1813 } 1814 currentAncestor = currentAncestor->GetParent(); 1815 } 1816 1817 if (!nearestForm) { 1818 return nullptr; 1819 } 1820 1821 return nearestForm; 1822 } 1823 1824 // Error reporting 1825 1826 void nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter) { 1827 MOZ_ASSERT(!mBuilder, "Must not view source with builder."); 1828 mViewSource = aHighlighter; 1829 } 1830 1831 void nsHtml5TreeBuilder::errDeepTree() { 1832 if (MOZ_UNLIKELY(mViewSource)) { 1833 mViewSource->AddErrorToCurrentRun("errDeepTree"); 1834 } else if (!mBuilder) { 1835 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1836 MOZ_ASSERT(treeOp, "Tree op allocation failed."); 1837 opMaybeComplainAboutDeepTree operation(tokenizer->getLineNumber()); 1838 treeOp->Init(mozilla::AsVariant(operation)); 1839 } 1840 } 1841 1842 void nsHtml5TreeBuilder::errStrayStartTag(nsAtom* aName) { 1843 if (MOZ_UNLIKELY(mViewSource)) { 1844 mViewSource->AddErrorToCurrentRun("errStrayStartTag2", aName); 1845 } 1846 } 1847 1848 void nsHtml5TreeBuilder::errStrayEndTag(nsAtom* aName) { 1849 if (MOZ_UNLIKELY(mViewSource)) { 1850 mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName); 1851 } 1852 } 1853 1854 void nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex, nsAtom* aName) { 1855 if (MOZ_UNLIKELY(mViewSource)) { 1856 mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName); 1857 } 1858 } 1859 1860 void nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex, 1861 nsAtom* aName) { 1862 if (MOZ_UNLIKELY(mViewSource)) { 1863 mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied", aName); 1864 } 1865 } 1866 1867 void nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex) { 1868 if (MOZ_UNLIKELY(mViewSource)) { 1869 mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell"); 1870 } 1871 } 1872 1873 void nsHtml5TreeBuilder::errStrayDoctype() { 1874 if (MOZ_UNLIKELY(mViewSource)) { 1875 mViewSource->AddErrorToCurrentRun("errStrayDoctype"); 1876 } 1877 } 1878 1879 void nsHtml5TreeBuilder::errAlmostStandardsDoctype() { 1880 if (MOZ_UNLIKELY(mViewSource) && !forceNoQuirks) { 1881 mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype"); 1882 } 1883 } 1884 1885 void nsHtml5TreeBuilder::errQuirkyDoctype() { 1886 if (MOZ_UNLIKELY(mViewSource) && !forceNoQuirks) { 1887 mViewSource->AddErrorToCurrentRun("errQuirkyDoctype"); 1888 } 1889 } 1890 1891 void nsHtml5TreeBuilder::errNonSpaceInTrailer() { 1892 if (MOZ_UNLIKELY(mViewSource)) { 1893 mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer"); 1894 } 1895 } 1896 1897 void nsHtml5TreeBuilder::errNonSpaceAfterFrameset() { 1898 if (MOZ_UNLIKELY(mViewSource)) { 1899 mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset"); 1900 } 1901 } 1902 1903 void nsHtml5TreeBuilder::errNonSpaceInFrameset() { 1904 if (MOZ_UNLIKELY(mViewSource)) { 1905 mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset"); 1906 } 1907 } 1908 1909 void nsHtml5TreeBuilder::errNonSpaceAfterBody() { 1910 if (MOZ_UNLIKELY(mViewSource)) { 1911 mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody"); 1912 } 1913 } 1914 1915 void nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment() { 1916 if (MOZ_UNLIKELY(mViewSource)) { 1917 mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment"); 1918 } 1919 } 1920 1921 void nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead() { 1922 if (MOZ_UNLIKELY(mViewSource)) { 1923 mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead"); 1924 } 1925 } 1926 1927 void nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsAtom* aName) { 1928 if (MOZ_UNLIKELY(mViewSource)) { 1929 mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName); 1930 } 1931 } 1932 1933 void nsHtml5TreeBuilder::errStartTagWithoutDoctype() { 1934 if (MOZ_UNLIKELY(mViewSource) && !forceNoQuirks) { 1935 mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype"); 1936 } 1937 } 1938 1939 void nsHtml5TreeBuilder::errNoSelectInTableScope() { 1940 if (MOZ_UNLIKELY(mViewSource)) { 1941 mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope"); 1942 } 1943 } 1944 1945 void nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected() { 1946 if (MOZ_UNLIKELY(mViewSource)) { 1947 mViewSource->AddErrorToCurrentRun("errStartSelectWhereEndSelectExpected"); 1948 } 1949 } 1950 1951 void nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsAtom* aName) { 1952 if (MOZ_UNLIKELY(mViewSource)) { 1953 mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName); 1954 } 1955 } 1956 1957 void nsHtml5TreeBuilder::errBadStartTagInNoscriptInHead(nsAtom* aName) { 1958 if (MOZ_UNLIKELY(mViewSource)) { 1959 mViewSource->AddErrorToCurrentRun("errBadStartTagInNoscriptInHead", aName); 1960 } 1961 } 1962 1963 void nsHtml5TreeBuilder::errImage() { 1964 if (MOZ_UNLIKELY(mViewSource)) { 1965 mViewSource->AddErrorToCurrentRun("errImage"); 1966 } 1967 } 1968 1969 void nsHtml5TreeBuilder::errIsindex() { 1970 if (MOZ_UNLIKELY(mViewSource)) { 1971 mViewSource->AddErrorToCurrentRun("errIsindex"); 1972 } 1973 } 1974 1975 void nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsAtom* aName) { 1976 if (MOZ_UNLIKELY(mViewSource)) { 1977 mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen2", aName); 1978 } 1979 } 1980 1981 void nsHtml5TreeBuilder::errHeadingWhenHeadingOpen() { 1982 if (MOZ_UNLIKELY(mViewSource)) { 1983 mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen"); 1984 } 1985 } 1986 1987 void nsHtml5TreeBuilder::errFramesetStart() { 1988 if (MOZ_UNLIKELY(mViewSource)) { 1989 mViewSource->AddErrorToCurrentRun("errFramesetStart"); 1990 } 1991 } 1992 1993 void nsHtml5TreeBuilder::errNoCellToClose() { 1994 if (MOZ_UNLIKELY(mViewSource)) { 1995 mViewSource->AddErrorToCurrentRun("errNoCellToClose"); 1996 } 1997 } 1998 1999 void nsHtml5TreeBuilder::errStartTagInTable(nsAtom* aName) { 2000 if (MOZ_UNLIKELY(mViewSource)) { 2001 mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName); 2002 } 2003 } 2004 2005 void nsHtml5TreeBuilder::errFormWhenFormOpen() { 2006 if (MOZ_UNLIKELY(mViewSource)) { 2007 mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen"); 2008 } 2009 } 2010 2011 void nsHtml5TreeBuilder::errTableSeenWhileTableOpen() { 2012 if (MOZ_UNLIKELY(mViewSource)) { 2013 mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen"); 2014 } 2015 } 2016 2017 void nsHtml5TreeBuilder::errStartTagInTableBody(nsAtom* aName) { 2018 if (MOZ_UNLIKELY(mViewSource)) { 2019 mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName); 2020 } 2021 } 2022 2023 void nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype() { 2024 if (MOZ_UNLIKELY(mViewSource) && !forceNoQuirks) { 2025 mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype"); 2026 } 2027 } 2028 2029 void nsHtml5TreeBuilder::errEndTagAfterBody() { 2030 if (MOZ_UNLIKELY(mViewSource)) { 2031 mViewSource->AddErrorToCurrentRun("errEndTagAfterBody"); 2032 } 2033 } 2034 2035 void nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsAtom* aName) { 2036 if (MOZ_UNLIKELY(mViewSource)) { 2037 mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen", aName); 2038 } 2039 } 2040 2041 void nsHtml5TreeBuilder::errGarbageInColgroup() { 2042 if (MOZ_UNLIKELY(mViewSource)) { 2043 mViewSource->AddErrorToCurrentRun("errGarbageInColgroup"); 2044 } 2045 } 2046 2047 void nsHtml5TreeBuilder::errEndTagBr() { 2048 if (MOZ_UNLIKELY(mViewSource)) { 2049 mViewSource->AddErrorToCurrentRun("errEndTagBr"); 2050 } 2051 } 2052 2053 void nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsAtom* aName) { 2054 if (MOZ_UNLIKELY(mViewSource)) { 2055 mViewSource->AddErrorToCurrentRun("errNoElementToCloseButEndTagSeen", 2056 aName); 2057 } 2058 } 2059 2060 void nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsAtom* aName) { 2061 if (MOZ_UNLIKELY(mViewSource)) { 2062 mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext", aName); 2063 } 2064 } 2065 2066 void nsHtml5TreeBuilder::errNoTableRowToClose() { 2067 if (MOZ_UNLIKELY(mViewSource)) { 2068 mViewSource->AddErrorToCurrentRun("errNoTableRowToClose"); 2069 } 2070 } 2071 2072 void nsHtml5TreeBuilder::errNonSpaceInTable() { 2073 if (MOZ_UNLIKELY(mViewSource)) { 2074 mViewSource->AddErrorToCurrentRun("errNonSpaceInTable"); 2075 } 2076 } 2077 2078 void nsHtml5TreeBuilder::errUnclosedChildrenInRuby() { 2079 if (MOZ_UNLIKELY(mViewSource)) { 2080 mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby"); 2081 } 2082 } 2083 2084 void nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsAtom* aName) { 2085 if (MOZ_UNLIKELY(mViewSource)) { 2086 mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby", aName); 2087 } 2088 } 2089 2090 void nsHtml5TreeBuilder::errSelfClosing() { 2091 if (MOZ_UNLIKELY(mViewSource)) { 2092 mViewSource->AddErrorToCurrentSlash("errSelfClosing"); 2093 } 2094 } 2095 2096 void nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack() { 2097 if (MOZ_UNLIKELY(mViewSource)) { 2098 mViewSource->AddErrorToCurrentRun("errNoCheckUnclosedElementsOnStack"); 2099 } 2100 } 2101 2102 void nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement( 2103 nsAtom* aName, nsAtom* aOther) { 2104 if (MOZ_UNLIKELY(mViewSource)) { 2105 mViewSource->AddErrorToCurrentRun("errEndTagDidNotMatchCurrentOpenElement", 2106 aName, aOther); 2107 } 2108 } 2109 2110 void nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsAtom* aName) { 2111 if (MOZ_UNLIKELY(mViewSource)) { 2112 mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName); 2113 } 2114 } 2115 2116 void nsHtml5TreeBuilder::errEndWithUnclosedElements(nsAtom* aName) { 2117 if (MOZ_UNLIKELY(mViewSource)) { 2118 mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName); 2119 } 2120 } 2121 2122 void nsHtml5TreeBuilder::errListUnclosedStartTags(int32_t aIgnored) { 2123 if (MOZ_UNLIKELY(mViewSource)) { 2124 mViewSource->AddErrorToCurrentRun("errListUnclosedStartTags"); 2125 } 2126 }