haikuwebkit/LayoutTests/fast/shadow-dom/shadow-root-active-element-...

67 lines
1.8 KiB
HTML
Raw Permalink Normal View History

Crash in TreeScope::focusedElement https://bugs.webkit.org/show_bug.cgi?id=158108 Reviewed by Enrica Casucci. Source/WebCore: The bug was caused by a flawed sequence of steps we took to remove an element. When an element is removed, willRemoveChild and willRemoveChildren fire blur events on removed focused element and its ancestors and unload event on any removed iframes. However, it was possible to focus an element on which we had fired blur during an unload event, leaving m_focusedElement point to an element that's not in the document anymore. Changing the order doesn't help because that would make it possible to insert the removed iframes back into the document inside a event listener of the blur event, which was specifically fixed by r127534 four years ago. Instead, fix the bug by not firing blur and change events on removed nodes. New behavior matches Firefox and HTML5 specification: https://html.spec.whatwg.org/multipage/interaction.html#focus-fixup-rule-one Test: fast/shadow-dom/shadow-root-active-element-crash.html * dom/ContainerNode.cpp: (WebCore::willRemoveChild): Made this function static local since it didn't need to have access to any private member variables. Call Document::nodeWillBeRemoved after disconnecting iframes since unload event handler could allocate new Ranges just like mutation events. (WebCore::willRemoveChildren): Ditto. (WebCore::ContainerNode::removeChild): Removed the calls to removeFullScreenElementOfSubtree and removeFocusedNodeOfSubtree as they're now called in Document::nodeWillBeRemoved. (WebCore::ContainerNode::removeChildren): Ditto. * dom/ContainerNode.h: * dom/Document.cpp: (WebCore::Document::removeFocusedNodeOfSubtree): Don't dispatch blur and change events when a node is removed. (WebCore::Document::setFocusedElement): Added FocusRemovalEventsMode as the third argument. Avoid dispatching blur and change events when FocusRemovalEventsMode::Dispatch is set. (WebCore::Document::nodeChildrenWillBeRemoved): Added calls to removeFullScreenElementOfSubtree and removeFocusedNodeOfSubtree. Also assert that no events are fired within this function. If we ever fire an event here, "unloaded" iframes can be inserted back into a document before ContainerNode::removeChild actually removes them. (WebCore::Document::nodeWillBeRemoved): Ditto. * dom/Document.h: * dom/TreeScope.cpp: (WebCore::TreeScope::focusedElement): Added a release assertion to make sure the focused element is in the document of the tree scope, and added an explicit type check just in case. LayoutTests: Added a regression test for accessing shadowRoot.activeElement after re-focusing an element inside DOMNodeRemovedFromDocument event and unload events. This patch also restores the expected result of fast/events/onblur-remove.html to that of when the test was in r15720 and updated in r19014. The expected result was changed in r85495 as it was converted to a eventSender test. * fast/dom/Range/range-created-during-remove-children-expected.txt: * fast/dom/Range/range-created-during-remove-children.html: Update the test to use unload event of an iframe since we no longer fire blur event when removing a focused element. * fast/dom/adopt-node-prevented-expected.txt: * fast/dom/adopt-node-prevented.html: Ditto. * fast/dom/remove-body-during-body-replacement2.html: Ditto. Use DOMNodeRemoved instead. * fast/events/nested-event-remove-node-crash.html: Ditto. Use DOMNodeRemovedFromDocument instead. * fast/events/onblur-remove-expected.txt: * fast/events/onblur-remove.html: See above. * fast/shadow-dom/shadow-root-active-element-crash-expected.txt: Added. * fast/shadow-dom/shadow-root-active-element-crash.html: Added. Canonical link: https://commits.webkit.org/176271@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@201471 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-27 22:31:43 +00:00
<!DOCTYPE html>
<html>
<body>
<p>This tests removing a focused element from a document and calling activeElement on a shadow tree in the same document.<br>
WebKit should clear the focused element even if the removed element was focused during removal and should not crash or hit an assertion.</p>
<script>
if (window.testRunner)
testRunner.dumpAsText();
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
var doc = iframe.contentDocument;
var host = doc.createElement('div');
var shadowRoot = host.attachShadow({mode: 'closed'});
doc.body.appendChild(host);
var input = doc.createElement('input');
doc.body.appendChild(input);
input.focus();
input.addEventListener('DOMNodeRemovedFromDocument', function () {
input.focus();
});
// 1. ContainerNode::removeChild
document.body.appendChild(input);
shadowRoot.activeElement;
// 2. ContainerNode::removeChildren
doc.body.appendChild(input);
input.focus();
doc.body.innerHTML = '';
document.body.appendChild(input);
shadowRoot.activeElement;
// 3. ContainerNode::removeChild for disconnecting frames
var focusableIframe = document.createElement('iframe');
doc.body.appendChild(host);
doc.body.appendChild(focusableIframe);
focusableIframe.focus();
focusableIframe.contentWindow.addEventListener('unload', function () {
focusableIframe.focus();
});
document.body.appendChild(focusableIframe);
shadowRoot.activeElement;
// 4. ContainerNode::removeChildren for disconnecting frames
focusableIframe = document.createElement('iframe');
doc.body.appendChild(host);
doc.body.appendChild(focusableIframe);
focusableIframe.focus();
focusableIframe.contentWindow.addEventListener('unload', function () {
focusableIframe.focus();
});
doc.body.innerHTML = '';
document.body.appendChild(focusableIframe);
shadowRoot.activeElement;
document.write('PASS - did not crash');
</script>
</body>
</html>