Diff
Modified: trunk/LayoutTests/ChangeLog (201470 => 201471)
--- trunk/LayoutTests/ChangeLog 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/LayoutTests/ChangeLog 2016-05-27 22:31:43 UTC (rev 201471)
@@ -1,3 +1,29 @@
+2016-05-26 Ryosuke Niwa <[email protected]>
+
+ Crash in TreeScope::focusedElement
+ https://bugs.webkit.org/show_bug.cgi?id=158108
+
+ Reviewed by Enrica Casucci.
+
+ 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.
+
2016-05-27 Brent Fulgham <[email protected]>
CSP: Fire 'load' events even when blocking loads via 'frame-src'.
Modified: trunk/LayoutTests/fast/dom/Range/range-created-during-remove-children-expected.txt (201470 => 201471)
--- trunk/LayoutTests/fast/dom/Range/range-created-during-remove-children-expected.txt 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/LayoutTests/fast/dom/Range/range-created-during-remove-children-expected.txt 2016-05-27 22:31:43 UTC (rev 201471)
@@ -1,7 +1,7 @@
-PASS ranges["blur"].startContainer is sample
-PASS ranges["blur"].endContainer is sample
-PASS ranges["blur"].startOffset is 0
-PASS ranges["blur"].endOffset is 0
+PASS ranges["unload"].startContainer is sample
+PASS ranges["unload"].endContainer is sample
+PASS ranges["unload"].startOffset is 0
+PASS ranges["unload"].endOffset is 0
PASS ranges["DOMNodeRemovedFromDocument"].startContainer is sample
PASS ranges["DOMNodeRemovedFromDocument"].endContainer is sample
PASS ranges["DOMNodeRemovedFromDocument"].startOffset is 0
Modified: trunk/LayoutTests/fast/dom/Range/range-created-during-remove-children.html (201470 => 201471)
--- trunk/LayoutTests/fast/dom/Range/range-created-during-remove-children.html 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/LayoutTests/fast/dom/Range/range-created-during-remove-children.html 2016-05-27 22:31:43 UTC (rev 201471)
@@ -1,6 +1,6 @@
<div id="container">
<p id="description"></p>
-<div id="sample"><span contenteditable="true">foobar</span></div>
+<div id="sample"><span contenteditable="true">foobar<iframe id="target"></iframe></span></div>
</div>
<div id="console"></div>
<script src=""
@@ -16,16 +16,16 @@
ranges[event.type].selectNodeContents(sample.firstChild.firstChild);
}
-document.addEventListener('blur', eventHandler, true);
+document.querySelector('iframe').contentWindow.addEventListener('unload', eventHandler, true);
document.addEventListener('DOMNodeRemovedFromDocument', eventHandler, true);
sample.firstChild.focus();
sample.innerHTML = '';
-shouldBe('ranges["blur"].startContainer', 'sample');
-shouldBe('ranges["blur"].endContainer', 'sample');
-shouldBe('ranges["blur"].startOffset', '0');
-shouldBe('ranges["blur"].endOffset', '0');
+shouldBe('ranges["unload"].startContainer', 'sample');
+shouldBe('ranges["unload"].endContainer', 'sample');
+shouldBe('ranges["unload"].startOffset', '0');
+shouldBe('ranges["unload"].endOffset', '0');
shouldBe('ranges["DOMNodeRemovedFromDocument"].startContainer', 'sample');
shouldBe('ranges["DOMNodeRemovedFromDocument"].endContainer', 'sample');
shouldBe('ranges["DOMNodeRemovedFromDocument"].startOffset', '0');
Modified: trunk/LayoutTests/fast/dom/adopt-node-prevented-expected.txt (201470 => 201471)
--- trunk/LayoutTests/fast/dom/adopt-node-prevented-expected.txt 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/LayoutTests/fast/dom/adopt-node-prevented-expected.txt 2016-05-27 22:31:43 UTC (rev 201471)
@@ -8,3 +8,4 @@
TEST COMPLETE
PASS target.ownerDocument.location is document.location
+
Modified: trunk/LayoutTests/fast/dom/adopt-node-prevented.html (201470 => 201471)
--- trunk/LayoutTests/fast/dom/adopt-node-prevented.html 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/LayoutTests/fast/dom/adopt-node-prevented.html 2016-05-27 22:31:43 UTC (rev 201471)
@@ -5,14 +5,14 @@
</head>
<body>
<div id="newParent"></div>
- <a href="" id="target"></a>
+ <iframe href="" id="target"></iframe>
<script>
description("Test that adoptNode fails safely if prevented by a DOM mutation.");
function run() {
newParent = document.getElementById("newParent");
target = document.getElementById("target");
- target.addEventListener("blur", function () { newParent.appendChild(target); }, false);
+ target.contentWindow.addEventListener("unload", function () { newParent.appendChild(target); }, false);
target.focus();
var anotherDocument = document.implementation.createDocument("", "", null);
Modified: trunk/LayoutTests/fast/dom/remove-body-during-body-replacement2.html (201470 => 201471)
--- trunk/LayoutTests/fast/dom/remove-body-during-body-replacement2.html 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/LayoutTests/fast/dom/remove-body-during-body-replacement2.html 2016-05-27 22:31:43 UTC (rev 201471)
@@ -17,7 +17,7 @@
}
setTimeout(function () {
- document.addEventListener('DOMFocusOut', function () { crash(); }, true);
+ document.addEventListener('DOMNodeRemoved', function () { crash(); }, true);
document.addEventListener('DOMSubtreeModified', function () { /* noop */ }, false);
document.designMode = "on";
document.execCommand("SelectAll");
Modified: trunk/LayoutTests/fast/events/nested-event-remove-node-crash.html (201470 => 201471)
--- trunk/LayoutTests/fast/events/nested-event-remove-node-crash.html 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/LayoutTests/fast/events/nested-event-remove-node-crash.html 2016-05-27 22:31:43 UTC (rev 201471)
@@ -34,7 +34,9 @@
3. the focused node's onblur will fire
4. the onblur event handler will send off an XHR who's handler will remove the node
*/
- document.getElementById("theSelect").focus();
+ var select = document.getElementById("theSelect");
+ select.addEventListener('DOMNodeRemovedFromDocument', function () { sendXHR();GC(); });
+ select.focus();
sendXHR();
if (window.testRunner) {
Modified: trunk/LayoutTests/fast/events/onblur-remove-expected.txt (201470 => 201471)
--- trunk/LayoutTests/fast/events/onblur-remove-expected.txt 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/LayoutTests/fast/events/onblur-remove-expected.txt 2016-05-27 22:31:43 UTC (rev 201471)
@@ -1,10 +1,9 @@
-This tests that elements shouldn't emit any onblur events when they are being removed from the document.
-Note, this test is expected to fail as of 04/25/2011. See bug #59379.
+This tests that elements shouldn't emit any onblur events when they are being removed from the document.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-FAIL Onblur handler called.
+PASS blurEventCount is 0
TEST COMPLETE
Modified: trunk/LayoutTests/fast/events/onblur-remove.html (201470 => 201471)
--- trunk/LayoutTests/fast/events/onblur-remove.html 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/LayoutTests/fast/events/onblur-remove.html 2016-05-27 22:31:43 UTC (rev 201471)
@@ -5,7 +5,7 @@
if (window.testRunner)
testRunner.waitUntilDone();
- var numBlurs = 0;
+ var blurEventCount = 0;
window._onload_ = function() { document.getElementById("input").focus(); }
@@ -14,10 +14,7 @@
f.innerHTML = '';
- if (numBlurs)
- testFailed('Onblur handler called.');
- else
- testPassed('Onblur handler not called.');
+ shouldBe("blurEventCount", "0");
debug('<br /><span class="pass">TEST COMPLETE</span>');
if (window.testRunner)
@@ -28,12 +25,11 @@
<body>
<p id="description"></p>
<form id='f'>
- <input id="input" _onblur_="numBlurs++" _onfocus_="setTimeout('finish()', 0)">
+ <input id="input" _onblur_="blurEventCount++" _onfocus_="setTimeout('finish()', 0)">
</form>
<div id="console"></div>
<script>
- description("This tests that elements shouldn't emit any onblur events when they are being removed from the document. <br>" +
- "Note, this test is expected to fail as of 04/25/2011. See bug #59379.");
+ description("This tests that elements shouldn't emit any onblur events when they are being removed from the document.");
</script>
</body>
</html>
Added: trunk/LayoutTests/fast/shadow-dom/shadow-root-active-element-crash-expected.txt (0 => 201471)
--- trunk/LayoutTests/fast/shadow-dom/shadow-root-active-element-crash-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/shadow-root-active-element-crash-expected.txt 2016-05-27 22:31:43 UTC (rev 201471)
@@ -0,0 +1,4 @@
+This tests removing a focused element from a document and calling activeElement on a shadow tree in the same document.
+WebKit should clear the focused element even if the removed element was focused during removal and should not crash or hit an assertion.
+
+PASS - did not crash
Added: trunk/LayoutTests/fast/shadow-dom/shadow-root-active-element-crash.html (0 => 201471)
--- trunk/LayoutTests/fast/shadow-dom/shadow-root-active-element-crash.html (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/shadow-root-active-element-crash.html 2016-05-27 22:31:43 UTC (rev 201471)
@@ -0,0 +1,66 @@
+<!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>
Modified: trunk/Source/WebCore/ChangeLog (201470 => 201471)
--- trunk/Source/WebCore/ChangeLog 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/Source/WebCore/ChangeLog 2016-05-27 22:31:43 UTC (rev 201471)
@@ -1,3 +1,45 @@
+2016-05-26 Ryosuke Niwa <[email protected]>
+
+ Crash in TreeScope::focusedElement
+ https://bugs.webkit.org/show_bug.cgi?id=158108
+
+ Reviewed by Enrica Casucci.
+
+ 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.
+
2016-05-27 Brent Fulgham <[email protected]>
CSP: Fire 'load' events even when blocking loads via 'frame-src'.
Modified: trunk/Source/WebCore/dom/ContainerNode.cpp (201470 => 201471)
--- trunk/Source/WebCore/dom/ContainerNode.cpp 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/Source/WebCore/dom/ContainerNode.cpp 2016-05-27 22:31:43 UTC (rev 201471)
@@ -456,7 +456,7 @@
return true;
}
-void ContainerNode::willRemoveChild(Node& child)
+static void willRemoveChild(ContainerNode& container, Node& child)
{
ASSERT(child.parentNode());
@@ -464,12 +464,16 @@
child.notifyMutationObserversNodeWillDetach();
dispatchChildRemovalEvents(child);
- if (child.parentNode() != this)
+ if (child.parentNode() != &container)
return;
- child.document().nodeWillBeRemoved(child); // e.g. mutation event listener can create a new range.
if (is<ContainerNode>(child))
disconnectSubframesIfNeeded(downcast<ContainerNode>(child), RootAndDescendants);
+
+ if (child.parentNode() != &container)
+ return;
+
+ child.document().nodeWillBeRemoved(child); // e.g. mutation event listener can create a new range.
}
static void willRemoveChildren(ContainerNode& container)
@@ -486,9 +490,10 @@
dispatchChildRemovalEvents(child.get());
}
+ disconnectSubframesIfNeeded(container, DescendantsOnly);
+
container.document().nodeChildrenWillBeRemoved(container);
- disconnectSubframesIfNeeded(container, DescendantsOnly);
}
void ContainerNode::disconnectDescendantFrames()
@@ -514,12 +519,6 @@
Ref<Node> child(oldChild);
- document().removeFocusedNodeOfSubtree(child.ptr());
-
-#if ENABLE(FULLSCREEN_API)
- document().removeFullScreenElementOfSubtree(&child.get());
-#endif
-
// Events fired when blurring currently focused node might have moved this
// child into a different parent.
if (child->parentNode() != this) {
@@ -527,7 +526,7 @@
return false;
}
- willRemoveChild(child);
+ willRemoveChild(*this, child);
// Mutation events might have moved this child into a different parent.
if (child->parentNode() != this) {
@@ -611,13 +610,6 @@
// The container node can be removed from event handlers.
Ref<ContainerNode> protectedThis(*this);
- // exclude this node when looking for removed focusedNode since only children will be removed
- document().removeFocusedNodeOfSubtree(this, true);
-
-#if ENABLE(FULLSCREEN_API)
- document().removeFullScreenElementOfSubtree(this, true);
-#endif
-
// Do any prep work needed before actually starting to detach
// and remove... e.g. stop loading frames, fire unload events.
willRemoveChildren(*this);
Modified: trunk/Source/WebCore/dom/ContainerNode.h (201470 => 201471)
--- trunk/Source/WebCore/dom/ContainerNode.h 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/Source/WebCore/dom/ContainerNode.h 2016-05-27 22:31:43 UTC (rev 201471)
@@ -130,8 +130,6 @@
bool isContainerNode() const = delete;
- void willRemoveChild(Node& child);
-
Node* m_firstChild { nullptr };
Node* m_lastChild { nullptr };
};
Modified: trunk/Source/WebCore/dom/Document.cpp (201470 => 201471)
--- trunk/Source/WebCore/dom/Document.cpp 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/Source/WebCore/dom/Document.cpp 2016-05-27 22:31:43 UTC (rev 201471)
@@ -3700,7 +3700,7 @@
nodeInSubtree = (focusedElement == node) || focusedElement->isDescendantOf(node);
if (nodeInSubtree)
- setFocusedElement(nullptr);
+ setFocusedElement(nullptr, FocusDirectionNone, FocusRemovalEventsMode::DoNotDispatch);
}
void Document::hoveredElementDidDetach(Element* element)
@@ -3738,7 +3738,7 @@
}
#endif
-bool Document::setFocusedElement(Element* element, FocusDirection direction)
+bool Document::setFocusedElement(Element* element, FocusDirection direction, FocusRemovalEventsMode eventsMode)
{
RefPtr<Element> newFocusedElement = element;
// Make sure newFocusedElement is actually in this document
@@ -3761,33 +3761,36 @@
oldFocusedElement->setFocus(false);
- // Dispatch a change event for form control elements that have been edited.
- if (is<HTMLFormControlElement>(*oldFocusedElement)) {
- HTMLFormControlElement& formControlElement = downcast<HTMLFormControlElement>(*oldFocusedElement);
- if (formControlElement.wasChangedSinceLastFormControlChangeEvent())
- formControlElement.dispatchFormControlChangeEvent();
- }
+ if (eventsMode == FocusRemovalEventsMode::Dispatch) {
+ // Dispatch a change event for form control elements that have been edited.
+ if (is<HTMLFormControlElement>(*oldFocusedElement)) {
+ HTMLFormControlElement& formControlElement = downcast<HTMLFormControlElement>(*oldFocusedElement);
+ if (formControlElement.wasChangedSinceLastFormControlChangeEvent())
+ formControlElement.dispatchFormControlChangeEvent();
+ }
- // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
- oldFocusedElement->dispatchBlurEvent(newFocusedElement.copyRef());
+ // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
+ oldFocusedElement->dispatchBlurEvent(newFocusedElement.copyRef());
- if (m_focusedElement) {
- // handler shifted focus
- focusChangeBlocked = true;
- newFocusedElement = nullptr;
- }
-
- oldFocusedElement->dispatchFocusOutEvent(eventNames().focusoutEvent, newFocusedElement.copyRef()); // DOM level 3 name for the bubbling blur event.
- // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends
- // on it, probably when <rdar://problem/8503958> is resolved.
- oldFocusedElement->dispatchFocusOutEvent(eventNames().DOMFocusOutEvent, newFocusedElement.copyRef()); // DOM level 2 name for compatibility.
+ if (m_focusedElement) {
+ // handler shifted focus
+ focusChangeBlocked = true;
+ newFocusedElement = nullptr;
+ }
- if (m_focusedElement) {
- // handler shifted focus
- focusChangeBlocked = true;
- newFocusedElement = nullptr;
- }
-
+ oldFocusedElement->dispatchFocusOutEvent(eventNames().focusoutEvent, newFocusedElement.copyRef()); // DOM level 3 name for the bubbling blur event.
+ // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends
+ // on it, probably when <rdar://problem/8503958> is resolved.
+ oldFocusedElement->dispatchFocusOutEvent(eventNames().DOMFocusOutEvent, newFocusedElement.copyRef()); // DOM level 2 name for compatibility.
+
+ if (m_focusedElement) {
+ // handler shifted focus
+ focusChangeBlocked = true;
+ newFocusedElement = nullptr;
+ }
+ } else
+ ASSERT(!m_focusedElement);
+
if (oldFocusedElement->isRootEditableElement())
frame()->editor().didEndEditing();
@@ -3967,6 +3970,14 @@
void Document::nodeChildrenWillBeRemoved(ContainerNode& container)
{
+ NoEventDispatchAssertion assertNoEventDispatch;
+
+ removeFocusedNodeOfSubtree(&container, true /* amongChildrenOnly */);
+
+#if ENABLE(FULLSCREEN_API)
+ removeFullScreenElementOfSubtree(&container, true /* amongChildrenOnly */);
+#endif
+
for (auto* range : m_ranges)
range->nodeChildrenWillBeRemoved(container);
@@ -3991,6 +4002,14 @@
void Document::nodeWillBeRemoved(Node& n)
{
+ NoEventDispatchAssertion assertNoEventDispatch;
+
+ removeFocusedNodeOfSubtree(&n);
+
+#if ENABLE(FULLSCREEN_API)
+ removeFullScreenElementOfSubtree(&n);
+#endif
+
for (auto* it : m_nodeIterators)
it->nodeWillBeRemoved(n);
Modified: trunk/Source/WebCore/dom/Document.h (201470 => 201471)
--- trunk/Source/WebCore/dom/Document.h 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/Source/WebCore/dom/Document.h 2016-05-27 22:31:43 UTC (rev 201471)
@@ -722,7 +722,9 @@
String selectedStylesheetSet() const;
void setSelectedStylesheetSet(const String&);
- WEBCORE_EXPORT bool setFocusedElement(Element*, FocusDirection = FocusDirectionNone);
+ enum class FocusRemovalEventsMode { Dispatch, DoNotDispatch };
+ WEBCORE_EXPORT bool setFocusedElement(Element*, FocusDirection = FocusDirectionNone,
+ FocusRemovalEventsMode = FocusRemovalEventsMode::Dispatch);
Element* focusedElement() const { return m_focusedElement.get(); }
UserActionElementSet& userActionElements() { return m_userActionElements; }
const UserActionElementSet& userActionElements() const { return m_userActionElements; }
Modified: trunk/Source/WebCore/dom/TreeScope.cpp (201470 => 201471)
--- trunk/Source/WebCore/dom/TreeScope.cpp 2016-05-27 22:29:02 UTC (rev 201470)
+++ trunk/Source/WebCore/dom/TreeScope.cpp 2016-05-27 22:31:43 UTC (rev 201471)
@@ -311,8 +311,13 @@
if (!element)
return nullptr;
TreeScope* treeScope = &element->treeScope();
+ RELEASE_ASSERT(&document == &treeScope->documentScope());
while (treeScope != this && treeScope != &document) {
- element = downcast<ShadowRoot>(treeScope->rootNode()).host();
+ auto& rootNode = treeScope->rootNode();
+ if (is<ShadowRoot>(rootNode))
+ element = downcast<ShadowRoot>(rootNode).host();
+ else
+ return nullptr;
treeScope = &element->treeScope();
}
if (this != treeScope)