Changeset 275543 in webkit
- Timestamp:
- Apr 6, 2021 12:51:49 PM (3 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r275535 r275543 1 2021-04-06 Ryosuke Niwa <rniwa@webkit.org> 2 3 Assert failure in isCloneInShadowTreeOfSVGUseElement 4 https://bugs.webkit.org/show_bug.cgi?id=224174 5 6 Reviewed by Darin Adler and Antti Koivisto. 7 8 Added tests for mutating nodes which is later inserted into a shadow tree during execCommand 9 as well as forcing a SVG use element to update its shadow tree by mutating the corresponding 10 element tree during execCommand. 11 12 * fast/shadow-dom/mutation-event-in-shadow-tree-expected.txt: Added. 13 * fast/shadow-dom/mutation-event-in-shadow-tree.html: Added. 14 * svg/dom/mutate-symbol-subtree-referenced-by-use-during-execCommand-expected.txt: Added. 15 * svg/dom/mutate-symbol-subtree-referenced-by-use-during-execCommand.html: Added. 16 * svg/dom/update-svg-use-shadow-tree-with-execCommand-expected.txt: Added. 17 * svg/dom/update-svg-use-shadow-tree-with-execCommand.html: Added. 18 1 19 2021-04-06 Jiewen Tan <jiewen_tan@apple.com> 2 20 -
trunk/Source/WebCore/ChangeLog
r275538 r275543 1 2021-04-06 Ryosuke Niwa <rniwa@webkit.org> 2 3 Assert failure in isCloneInShadowTreeOfSVGUseElement 4 https://bugs.webkit.org/show_bug.cgi?id=224174 5 6 Reviewed by Darin Adler and Antti Koivisto. 7 8 The bug was caused by two related but distinct issues: 9 1. An element can have an instance that had been removed from a use element's shadow tree 10 but not yet deleted. Because SVGElement clears its correspondingElement in its destructor, 11 when addEventListener is called on such an element, it can try to add an event listener 12 on this instance which is in the process of getting disposed. 13 2. DOM mutation events can be fired on the corresponding element of an instance inside 14 a use element’s shadow tree with EventQueueScope in the stack when the event is schedueld 15 via Node::dispatchScopedEvent, e.g. because use element's shadow tree was updated during 16 a style update at the beginning of document.execComand. Because SVGUseElement::cloneTarget 17 constructs the shadow tree by cloning the original tree while it's disconnected from the 18 document, Node::dispatchSubtreeModifiedEvent sees isInShadowTree() to be false and happily 19 tries to dispach DOMSubtreeModified event using Node::dispatchScopedEvent. This works fine 20 when the event is dispatched synchronously since these elements had never been exposed to 21 any scripts yet and they are still disconnected so no scripts have had an opportunity to 22 attach an event listener. But when EventQueueScope in the stack, Node::dispatchScopedEvent 23 will queue up the event and fire it later when those instance elements had been inserted 24 into use element's shadow tree. 25 26 This patch addresses (1) by severing correspondingElement relationship as soon as an instance 27 is removed from its use element's shadow tree, and (2) by not dispatching a scheduled mutation 28 event if the target is inside a shadow tree. Note that this patch also addresses (2) for 29 a regular shadow tree attached by author scripts. 30 31 Tests: fast/shadow-dom/mutation-event-in-shadow-tree.html 32 svg/dom/mutate-symbol-subtree-referenced-by-use-during-execCommand.html 33 svg/dom/update-svg-use-shadow-tree-with-execCommand.html 34 35 * dom/ScopedEventQueue.cpp: 36 (WebCore::ScopedEventQueue::dispatchEvent const): 37 * svg/SVGElement.cpp: 38 (WebCore::SVGElement::~SVGElement): 39 (WebCore::SVGElement::removedFromAncestor): 40 (WebCore::SVGElement::addEventListener): 41 (WebCore::SVGElement::removeEventListener): 42 1 43 2021-04-06 Eric Carlson <eric.carlson@apple.com> 2 44 -
trunk/Source/WebCore/dom/Node.h
r274818 r275543 217 217 bool isDocumentFragment() const { return hasNodeFlag(NodeFlag::IsDocumentFragment); } 218 218 bool isShadowRoot() const { return hasNodeFlag(NodeFlag::IsShadowRoot); } 219 bool isUserAgentShadowRoot() const; // Defined in ShadowRoot.h 219 220 220 221 bool hasCustomStyleResolveCallbacks() const { return hasNodeFlag(NodeFlag::HasCustomStyleResolveCallbacks); } … … 226 227 WEBCORE_EXPORT Element* shadowHost() const; 227 228 ShadowRoot* containingShadowRoot() const; 228 ShadowRoot* shadowRoot() const; 229 ShadowRoot* shadowRoot() const; // Defined in ShadowRoot.h 229 230 bool isClosedShadowHidden(const Node&) const; 230 231 … … 241 242 242 243 // Node's parent or shadow tree host. 243 ContainerNode* parentOrShadowHostNode() const; 244 ContainerNode* parentOrShadowHostNode() const; // Defined in ShadowRoot.h 244 245 ContainerNode* parentInComposedTree() const; 245 246 Element* parentElementInComposedTree() const; -
trunk/Source/WebCore/dom/ScopedEventQueue.cpp
r262016 r275543 57 57 void ScopedEventQueue::dispatchEvent(const ScopedEvent& event) const 58 58 { 59 if (event.event->eventInterface() == MutationEventInterfaceType && event.target->isInShadowTree()) 60 return; 59 61 event.target->dispatchEvent(event.event); 60 62 } -
trunk/Source/WebCore/dom/ShadowRoot.h
r266212 r275543 154 154 } 155 155 156 inline bool Node::isUserAgentShadowRoot() const 157 { 158 return isShadowRoot() && downcast<ShadowRoot>(*this).mode() == ShadowRootMode::UserAgent; 159 } 160 156 161 inline ContainerNode* Node::parentOrShadowHostNode() const 157 162 { -
trunk/Source/WebCore/svg/SVGElement.cpp
r275410 r275543 172 172 for (SVGElement* instance : m_svgRareData->instances()) 173 173 instance->m_svgRareData->setCorrespondingElement(nullptr); 174 if (auto correspondingElement = makeRefPtr(m_svgRareData->correspondingElement())) 175 correspondingElement->m_svgRareData->instances().remove(this); 176 174 RELEASE_ASSERT(!m_svgRareData->correspondingElement()); 177 175 m_svgRareData = nullptr; 178 176 } … … 254 252 } 255 253 invalidateInstances(); 254 255 if (removalType.treeScopeChanged && oldParentOfRemovedTree.isUserAgentShadowRoot()) 256 setCorrespondingElement(nullptr); 256 257 } 257 258 … … 376 377 for (auto* instance : instances()) { 377 378 ASSERT(instance->correspondingElement() == this); 379 ASSERT(instance->isInUserAgentShadowTree()); 378 380 bool result = instance->Node::addEventListener(eventType, listener.copyRef(), options); 379 381 ASSERT_UNUSED(result, result); … … 403 405 for (auto& instance : instances()) { 404 406 ASSERT(instance->correspondingElement() == this); 407 ASSERT(instance->isInUserAgentShadowTree()); 405 408 406 409 if (instance->Node::removeEventListener(eventType, listener, options))
Note: See TracChangeset
for help on using the changeset viewer.