Repository navigation
Conversation
…nt they replace The inner loop of the adoption agency algorithm created each clone with commonAncestor as the intended parent. That gave the clone commonAncestor's node document and custom element registry, even when the element it replaces lives in the inert template contents document because commonAncestor is a template element, or because the parser sanitizer configuration removed an element between commonAncestor and it in the stack of open elements. Use the replaced element as the intended parent instead, so that the clone inherits the document and registry of the element it replaces. Part of #13093.
…renting furthestBlock The adoption agency algorithm inserted lastNode, the subtree rooted at furthestBlock, at commonAncestor's insertion location before determining the sanitizer action for the new formatting element. When that action is Remove, furthestBlock's children were briefly connected before being moved into the never-inserted new element, running their insertion steps and custom element reactions along the way. Create the new element and compute its sanitizer action first, and move furthestBlock's children into it before lastNode is inserted. The children, which were created in an inert document because the removed formatting element was, now never become connected. As a result, the new element's constructor (for customized built-in elements) now runs before lastNode is inserted rather than after. Part of #13093.
… of their new parent When the adoption agency algorithm moves furthestBlock out of a formatting element that the sanitizer removed, furthestBlock and its descendants were created in an inert document with a null custom element registry. Adopting them into the target's node document only assigns that document's registry, so a scoped registry that applies to the target was lost, and elements parsed later into the subtree could not look one up. Before inserting lastNode, set the null registries in its subtree to the registry looked up from the target when it is an element or a shadow root, as creating an element for a token does. When the target is a document fragment, such as template contents, the registries stay null. Part of #13093.
Inclusive descendants of a node are not an Infra list, and the other places in the spec that iterate descendants in tree order use a plain For each.
furthestBlock's intended parent is the current node at the time, which can be an element between formattingElement and furthestBlock that is not a clone (e.g., a span), and furthestBlock's descendants have furthestBlock or its descendants as intended parents. What matters for the note is only that the subtree was created below formattingElement.
|
Review-and-fix pass over the current head (242a597), together with web-platform-tests/wpt#64909. Questions / follow-ups
FindingsAll three commits trace correctly through the six tests in the companion WPT (each expected result follows from the algorithm as written),
|
The rationale for the intended-parent change, for moving furthestBlock's children before inserting lastNode, and for propagating the registry is in the pull request and commit messages; the algorithm steps stand on their own.
Move furthestBlock's children into newElement before inserting lastNode whenever sanitizerAction is not "Replace with children", instead of doing it before lastNode insertion for "Remove" and inside the final insertion block for "Keep". When sanitizerAction is "Keep", newElement is not yet connected while lastNode is being inserted, so moving the children there only removes them from furthestBlock earlier and shrinks the "Keep" insertion block to the pre-insert validity assert and the insert.
Findings and fixesSpec (
|
AI feedbackReviewed at 9d6f088, only for how it interacts with #13215; not a full review. Suggestions
|
|
Restored |
AI feedbackReviewed at 2f98c06. Suggestions
|
Applied PR description suggestion and WPT. Also finished the checkboxes apart from "multiple implementers interested". @keithamus @annevk |
Adoption agency: fix element creation and reparenting with a sanitizer
The adoption agency algorithm reparents and recreates elements, and the parser sanitizer configuration and scoped custom element registries made the context in which it does so observable. With a formatting element that the sanitizer removes,
furthestBlockand its descendants are created in an inert document with a null custom element registry, and three things go wrong when the algorithm moves them back into the live tree:commonAncestoras the intended parent, giving itcommonAncestor's document and registry rather than those of the element it replaces; also wrong whencommonAncestoris atemplateelement (Adoption agency algorithm issues (sanitizer and intended parent) #13093 items 3 and 4).lastNodewas inserted before the new formatting element's sanitizer action was known, so when that action is Remove,furthestBlock's children were briefly connected before being moved into the never-inserted new element, running insertion steps and custom element reactions (Adoption agency algorithm issues (sanitizer and intended parent) #13093 item 2).furthestBlockinto the target only gives it the document's global registry, so a scoped registry applying to the target was lost for it and for everything parsed into it afterwards (Adoption agency algorithm issues (sanitizer and intended parent) #13093 item 1).This PR:
Creates inner-loop clones with the element they replace as the intended parent.
Creates the new formatting element and determines its sanitizer action before inserting
lastNode. If the action is Remove, movesfurthestBlock's children into the new element first so they are never connected whenlastNodeis inserted; otherwise preserves the existing order (insertlastNode, movefurthestBlock's children into the new element unless Replace with children, then insert the new element intofurthestBlock). Note that a customized built-in new element's constructor now runs beforelastNodeis inserted rather than after.Before inserting
lastNode, sets the null registries in its subtree to the registry looked up fromtargetif it is anElementor aShadowRoot, or frominsertionLocation's target parent otherwise, matching "create an element for a token".Neither Chrome Canary nor Firefox Nightly propagates the scoped registry (tests 2, 3, and 4). In
streamHTMLUnsafe(), Chrome Canary also connects and disconnectsfurthestBlock's children before moving them into the removed new formatting element (test 6), and drops the inner-loop clone of a formatting element whose token has anisattribute, with or without a sanitizer (test 8).Tests: web-platform-tests/wpt#64909.
Fixes #13093.
(See WHATWG Working Mode: Changes for more details.)
/parsing.html ( diff )