<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[209628] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/209628">209628</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2016-12-09 14:06:29 -0800 (Fri, 09 Dec 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>document.webkitFullscreenElement leaks elements inside a shadow tree
https://bugs.webkit.org/show_bug.cgi?id=158471

Reviewed by Chris Dumez.

Source/WebCore:

Fixed the bug by calling the newly added ancestorElementInThisScope in webkitCurrentFullScreenElementForBindings
and webkitFullscreenElementForBinding.

The specification (https://fullscreen.spec.whatwg.org/#dom-document-fullscreenelement) uses &quot;the result of
retargeting fullscreen element&quot; and returns null if the result is not in the same tree as the context object.

This is equivalent to the algorithm implemented by ancestorElementInThisScope. Observe that the retargeting
algorithm (https://dom.spec.whatwg.org/#retarget) finds the lowest common tree scope of the retargetee and
the context object. There are two cases to consider.

1. The context object's tree scope is the lowest common tree scope: In this case, an ancestor shadow host or
the retargetee itself is in this tree scope. It's sufficient traverse every shadow host to find the one that
resides in the same tree scope as the context object. This is precisely what ancestorElementInThisScope does.

2. The context object's tree scope is not the lowest common tree scope: In this case, the context object is
inside a shadow tree whose ancestor shadow host is in the lowest common tree scope. In this case, retargeting
algorithm finds a node which is not in the same tree as the context object. Thus, the result is null.
ancestorElementInThisScope traveres ancestor shadow hosts and returns null if no shadow host's tree scope
matches that of the context object's tree scope. Thus, it would return null in this case as desired.

Also renamed TreeScope::focusedElement to focusedElementInScope for clarity since Document which inherits
from TreeScope also has a distinct member function named focusedElement called by TreeScope::focusedElement,
and used ancestorElementInThisScope since it uses the same algorithm.

Tests: fast/shadow-dom/activeElement-for-focused-element-in-another-shadow.html
       fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content.html
       fast/shadow-dom/fullscreen-in-shadow-fullscreenElement.html
       fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement.html
       fast/shadow-dom/fullscreen-in-slot-fullscreenElement.html
       fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement.html

* dom/Document.cpp:
(WebCore::Document::removeFocusedNodeOfSubtree):
(WebCore::Document::activeElement):
* dom/Document.h:
(WebCore::Document::webkitCurrentFullScreenElementForBindings): Added.
(WebCore::Document::webkitFullscreenElementForBindings): Added.
* dom/Document.idl:
* dom/Element.cpp:
(WebCore::Element::blur):
* dom/ShadowRoot.h:
(WebCore::ShadowRoot::activeElement):
* dom/TreeScope.cpp:
(WebCore::TreeScope::ancestorNodeInThisScope): Renamed from ancestorInThisScope for clarity.
(WebCore::TreeScope::ancestorElementInThisScope):
(WebCore::TreeScope::focusedElementInScope): Renamed from focusedElement to disambiguate it from Document's
focusedElement.
* dom/TreeScope.h:
* editing/VisibleSelection.cpp:
(WebCore::adjustPositionForEnd):
(WebCore::adjustPositionForStart):
* editing/htmlediting.cpp:
(WebCore::comparePositions):
(WebCore::firstEditablePositionAfterPositionInRoot):
(WebCore::lastEditablePositionBeforePositionInRoot):
* page/DOMSelection.cpp:
(WebCore::selectionShadowAncestor):
(WebCore::DOMSelection::shadowAdjustedNode):
(WebCore::DOMSelection::shadowAdjustedOffset):
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::addNodeToRectBasedTestResult): Added a FIXME here since this is clearly wrong for
shadow trees created by author scripts.

Source/WebKit/mac:

Use the API for bindings to avoid exposing nodes inside a shadow tree.

* DOM/DOMDocument.mm:
(-[DOMDocument webkitCurrentFullScreenElement]):
(-[DOMDocument webkitFullscreenElement]):

LayoutTests:

Added tests for calling webkitFullscreenElement and webkitCurrentFullScreenElement on a fullscreened element
to make sure they return the shadow host instead.

Also added two unrelated test cases for temporal regressions I introduced while working on this patch.

Skip the fullscreen tests on iOS WK2 since eventSender doesn't work there.

* fast/shadow-dom/activeElement-for-focused-element-in-another-shadow-expected.txt: Added.
* fast/shadow-dom/activeElement-for-focused-element-in-another-shadow.html: Added.
* fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content-expected.txt: Added.
* fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content.html: Added.
* fast/shadow-dom/fullscreen-in-shadow-fullscreenElement-expected.txt: Added.
* fast/shadow-dom/fullscreen-in-shadow-fullscreenElement.html: Added.
* fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement-expected.txt: Added.
* fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement.html: Added.
* fast/shadow-dom/fullscreen-in-slot-fullscreenElement-expected.txt: Added.
* fast/shadow-dom/fullscreen-in-slot-fullscreenElement.html: Added.
* fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement-expected.txt: Added.
* fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement.html: Added.
* platform/ios-simulator-wk2/TestExpectations:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformiossimulatorwk2TestExpectations">trunk/LayoutTests/platform/ios-simulator-wk2/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomDocumentcpp">trunk/Source/WebCore/dom/Document.cpp</a></li>
<li><a href="#trunkSourceWebCoredomDocumenth">trunk/Source/WebCore/dom/Document.h</a></li>
<li><a href="#trunkSourceWebCoredomDocumentidl">trunk/Source/WebCore/dom/Document.idl</a></li>
<li><a href="#trunkSourceWebCoredomElementcpp">trunk/Source/WebCore/dom/Element.cpp</a></li>
<li><a href="#trunkSourceWebCoredomShadowRooth">trunk/Source/WebCore/dom/ShadowRoot.h</a></li>
<li><a href="#trunkSourceWebCoredomTreeScopecpp">trunk/Source/WebCore/dom/TreeScope.cpp</a></li>
<li><a href="#trunkSourceWebCoredomTreeScopeh">trunk/Source/WebCore/dom/TreeScope.h</a></li>
<li><a href="#trunkSourceWebCoreeditingVisibleSelectioncpp">trunk/Source/WebCore/editing/VisibleSelection.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditinghtmleditingcpp">trunk/Source/WebCore/editing/htmlediting.cpp</a></li>
<li><a href="#trunkSourceWebCorepageDOMSelectioncpp">trunk/Source/WebCore/page/DOMSelection.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingHitTestResultcpp">trunk/Source/WebCore/rendering/HitTestResult.cpp</a></li>
<li><a href="#trunkSourceWebKitmacChangeLog">trunk/Source/WebKit/mac/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitmacDOMDOMDocumentmm">trunk/Source/WebKit/mac/DOM/DOMDocument.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastshadowdomactiveElementforfocusedelementinanothershadowexpectedtxt">trunk/LayoutTests/fast/shadow-dom/activeElement-for-focused-element-in-another-shadow-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomactiveElementforfocusedelementinanothershadowhtml">trunk/LayoutTests/fast/shadow-dom/activeElement-for-focused-element-in-another-shadow.html</a></li>
<li><a href="#trunkLayoutTestsfastshadowdombluronshadowhostwithfocusedshadowcontentexpectedtxt">trunk/LayoutTests/fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastshadowdombluronshadowhostwithfocusedshadowcontenthtml">trunk/LayoutTests/fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content.html</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomfullscreeninshadowfullscreenElementexpectedtxt">trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-fullscreenElement-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomfullscreeninshadowfullscreenElementhtml">trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-fullscreenElement.html</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomfullscreeninshadowwebkitCurrentFullScreenElementexpectedtxt">trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomfullscreeninshadowwebkitCurrentFullScreenElementhtml">trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement.html</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomfullscreeninslotfullscreenElementexpectedtxt">trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-fullscreenElement-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomfullscreeninslotfullscreenElementhtml">trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-fullscreenElement.html</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomfullscreeninslotwebkitCurrentFullScreenElementexpectedtxt">trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomfullscreeninslotwebkitCurrentFullScreenElementhtml">trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/LayoutTests/ChangeLog        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2016-12-09  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        document.webkitFullscreenElement leaks elements inside a shadow tree
+        https://bugs.webkit.org/show_bug.cgi?id=158471
+
+        Reviewed by Chris Dumez.
+
+        Added tests for calling webkitFullscreenElement and webkitCurrentFullScreenElement on a fullscreened element
+        to make sure they return the shadow host instead.
+
+        Also added two unrelated test cases for temporal regressions I introduced while working on this patch.
+
+        Skip the fullscreen tests on iOS WK2 since eventSender doesn't work there.
+
+        * fast/shadow-dom/activeElement-for-focused-element-in-another-shadow-expected.txt: Added.
+        * fast/shadow-dom/activeElement-for-focused-element-in-another-shadow.html: Added.
+        * fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content-expected.txt: Added.
+        * fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content.html: Added.
+        * fast/shadow-dom/fullscreen-in-shadow-fullscreenElement-expected.txt: Added.
+        * fast/shadow-dom/fullscreen-in-shadow-fullscreenElement.html: Added.
+        * fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement-expected.txt: Added.
+        * fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement.html: Added.
+        * fast/shadow-dom/fullscreen-in-slot-fullscreenElement-expected.txt: Added.
+        * fast/shadow-dom/fullscreen-in-slot-fullscreenElement.html: Added.
+        * fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement-expected.txt: Added.
+        * fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement.html: Added.
+        * platform/ios-simulator-wk2/TestExpectations:
+
</ins><span class="cx"> 2016-12-09  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Cocoa] Validation message for required checkbox doesn’t conform the the Apple Style Guide
</span></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomactiveElementforfocusedelementinanothershadowexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/activeElement-for-focused-element-in-another-shadow-expected.txt (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/activeElement-for-focused-element-in-another-shadow-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/activeElement-for-focused-element-in-another-shadow-expected.txt        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+
+PASS ShadowRoot.activeElement must return null the focused element is in another shadow tree when both shadow roots are open. 
+PASS ShadowRoot.activeElement must return null the focused element is in another shadow tree when both shadow roots are closed. 
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomactiveElementforfocusedelementinanothershadowhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/activeElement-for-focused-element-in-another-shadow.html (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/activeElement-for-focused-element-in-another-shadow.html                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/activeElement-for-focused-element-in-another-shadow.html        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,50 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;meta name=&quot;author&quot; title=&quot;Ryosuke Niwa&quot; href=&quot;mailto:rniwa@webkit.org&quot;&gt;
+&lt;meta name=&quot;assert&quot; content=&quot;ShadowRoot's &quot;&gt;
+&lt;link rel=&quot;help&quot; href=&quot;http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event-interface&quot;&gt;
+&lt;script src=&quot;../../resources/testharness.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/testharnessreport.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;resources/event-path-test-helpers.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div id=&quot;log&quot;&gt;&lt;/div&gt;
+&lt;script&gt;
+
+function testActiveElementWithFocusedElementInAnotherShadow(mode) {
+    test(function () {
+        const host = document.createElement('div');
+        document.body.appendChild(host);
+        const shadowRoot = host.attachShadow({'mode': mode});
+        const input = document.createElement('input');
+        shadowRoot.appendChild(input);
+        assert_equals(shadowRoot.activeElement, null);
+        input.focus();
+        assert_equals(shadowRoot.activeElement, input);
+        assert_equals(document.activeElement, host);
+
+        const anotherHost = document.createElement('div');
+        document.body.appendChild(anotherHost);
+        const anotherShadowRoot = anotherHost.attachShadow({'mode': mode});
+        const anotherInput = document.createElement('input');
+        anotherShadowRoot.appendChild(anotherInput);
+
+        assert_equals(anotherShadowRoot.activeElement, null);
+        assert_equals(shadowRoot.activeElement, input);
+        assert_equals(document.activeElement, host);
+
+        anotherInput.focus();
+        assert_equals(anotherShadowRoot.activeElement, anotherInput);
+        assert_equals(shadowRoot.activeElement, null);
+        assert_equals(document.activeElement, anotherHost);
+
+    }, 'ShadowRoot.activeElement must return null the focused element is in another shadow tree when both shadow roots are ' + mode + '.');
+}
+
+testActiveElementWithFocusedElementInAnotherShadow('open');
+testActiveElementWithFocusedElementInAnotherShadow('closed');
+
+&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdombluronshadowhostwithfocusedshadowcontentexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content-expected.txt (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content-expected.txt        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+Test that calling blur() on a shadow host of a focused element clears the focus.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS input = shadowRoot.querySelector(&quot;input&quot;); input.focus(); shadowRoot.activeElement is input
+PASS document.activeElement is shadowHost
+PASS shadowHost.blur(); shadowRoot.activeElement is null
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdombluronshadowhostwithfocusedshadowcontenthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content.html (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content.html                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content.html        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;div id=&quot;host&quot;&gt;&lt;/div&gt;
+&lt;script src=&quot;../../resources/js-test.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+description('Test that calling blur() on a shadow host of a focused element clears the focus.');
+
+let shadowHost = document.getElementById('host');
+let shadowRoot = shadowHost.attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = `&lt;input&gt;`;
+
+shouldBe('input = shadowRoot.querySelector(&quot;input&quot;); input.focus(); shadowRoot.activeElement', 'input');
+shouldBe('document.activeElement', 'shadowHost');
+shouldBe('shadowHost.blur(); shadowRoot.activeElement', 'null');
+
+var successfullyParsed = true;
+
+&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomfullscreeninshadowfullscreenElementexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-fullscreenElement-expected.txt (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-fullscreenElement-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-fullscreenElement-expected.txt        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+Test that webkitFullscreenElement retargets the fullscreen element inside a shadow tree.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.webkitFullscreenElement is shadowHost
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Enter fullscreen
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomfullscreeninshadowfullscreenElementhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-fullscreenElement.html (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-fullscreenElement.html                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-fullscreenElement.html        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;div id=&quot;host&quot;&gt;&lt;/div&gt;
+&lt;button&gt;Enter fullscreen&lt;/button&gt;
+&lt;script src=&quot;../../resources/js-test.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+description('Test that webkitFullscreenElement retargets the fullscreen element inside a shadow tree.');
+
+let shadowHost = document.getElementById('host');
+let shadowRoot = shadowHost.attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = '&lt;span&gt;full screen content&lt;/span&gt;';
+
+function goFullscreen() {
+    shadowRoot.querySelector('span').webkitRequestFullscreen();
+    setTimeout(function () {
+        if (done)
+            return;
+
+        testFailed('webkitfullscreenchange was not fired');
+        finishJSTest();
+    }, 2000);
+}
+
+let done = false;
+function finalizeTest() {
+    if (done)
+        return;
+    done = true;
+
+    shouldBe('document.webkitFullscreenElement', 'shadowHost');
+    finishJSTest();
+}
+
+shadowRoot.addEventListener('webkitfullscreenchange', finalizeTest);
+document.addEventListener('fullscreenchange', finalizeTest); // Standard fullscreenchange only fires at document level.
+
+let button = document.querySelector('button');
+button.onclick = goFullscreen;
+
+if (window.eventSender) {
+    jsTestIsAsync = true;
+    eventSender.mouseMoveTo(button.offsetLeft + 5, button.offsetTop + 5);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
+&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomfullscreeninshadowwebkitCurrentFullScreenElementexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement-expected.txt (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement-expected.txt        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+Test that webkitCurrentFullScreenElement retargets the fullscreen element inside a shadow tree.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.webkitCurrentFullScreenElement is shadowHost
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Enter fullscreen
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomfullscreeninshadowwebkitCurrentFullScreenElementhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement.html (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement.html                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement.html        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;div id=&quot;host&quot;&gt;&lt;/div&gt;
+&lt;button&gt;Enter fullscreen&lt;/button&gt;
+&lt;script src=&quot;../../resources/js-test.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+description('Test that webkitCurrentFullScreenElement retargets the fullscreen element inside a shadow tree.');
+
+let shadowHost = document.getElementById('host');
+let shadowRoot = shadowHost.attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = '&lt;span&gt;full screen content&lt;/span&gt;';
+
+function goFullscreen() {
+    shadowRoot.querySelector('span').webkitRequestFullScreen();
+    setTimeout(function () {
+        if (done)
+            return;
+
+        testFailed('webkitfullscreenchange was not fired');
+        finishJSTest();
+    }, 2000);
+}
+
+let done = false;
+function finalizeTest() {
+    if (done)
+        return;
+    done = true;
+
+    shouldBe('document.webkitCurrentFullScreenElement', 'shadowHost');
+    finishJSTest();
+}
+
+shadowRoot.addEventListener('webkitfullscreenchange', finalizeTest);
+document.addEventListener('fullscreenchange', finalizeTest); // Standard fullscreenchange only fires at document level.
+
+let button = document.querySelector('button');
+button.onclick = goFullscreen;
+
+if (window.eventSender) {
+    jsTestIsAsync = true;
+    eventSender.mouseMoveTo(button.offsetLeft + 5, button.offsetTop + 5);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
+&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomfullscreeninslotfullscreenElementexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-fullscreenElement-expected.txt (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-fullscreenElement-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-fullscreenElement-expected.txt        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+Test that webkitFullscreenElement retargets the fullscreen element assigned to a slot.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.webkitFullscreenElement is document.querySelector(&quot;section&quot;)
+PASS successfullyParsed is true
+
+TEST COMPLETE
+full screen content
+Enter fullscreen
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomfullscreeninslotfullscreenElementhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-fullscreenElement.html (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-fullscreenElement.html                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-fullscreenElement.html        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;div id=&quot;host&quot;&gt;&lt;section&gt;full screen content&lt;/section&gt;&lt;/div&gt;
+&lt;button&gt;Enter fullscreen&lt;/button&gt;
+&lt;script src=&quot;../../resources/js-test.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+description('Test that webkitFullscreenElement retargets the fullscreen element assigned to a slot.');
+
+let shadowHost = document.getElementById('host');
+let shadowRoot = shadowHost.attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = '&lt;span&gt;&lt;slot&gt;&lt;/slot&gt;&lt;/span&gt;';
+
+function goFullscreen() {
+    document.querySelector('section').webkitRequestFullscreen();
+    setTimeout(function () {
+        if (done)
+            return;
+
+        testFailed('webkitfullscreenchange was not fired');
+        finishJSTest();
+    }, 2000);
+}
+
+let done = false;
+function finalizeTest() {
+    if (done)
+        return;
+    done = true;
+
+    shouldBe('document.webkitFullscreenElement', 'document.querySelector(&quot;section&quot;)');
+    finishJSTest();
+}
+
+shadowRoot.addEventListener('webkitfullscreenchange', finalizeTest);
+document.addEventListener('fullscreenchange', finalizeTest); // Standard fullscreenchange only fires at document level.
+
+let button = document.querySelector('button');
+button.onclick = goFullscreen;
+
+if (window.eventSender) {
+    jsTestIsAsync = true;
+    eventSender.mouseMoveTo(button.offsetLeft + 5, button.offsetTop + 5);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
+&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomfullscreeninslotwebkitCurrentFullScreenElementexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement-expected.txt (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement-expected.txt        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+Test that webkitCurrentFullScreenElement retargets the fullscreen element assigned to a slot.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.webkitCurrentFullScreenElement is document.querySelector(&quot;section&quot;)
+PASS successfullyParsed is true
+
+TEST COMPLETE
+full screen content
+Enter fullscreen
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomfullscreeninslotwebkitCurrentFullScreenElementhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement.html (0 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement.html                                (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement.html        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;div id=&quot;host&quot;&gt;&lt;section&gt;full screen content&lt;/section&gt;&lt;/div&gt;
+&lt;button&gt;Enter fullscreen&lt;/button&gt;
+&lt;script src=&quot;../../resources/js-test.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+description('Test that webkitCurrentFullScreenElement retargets the fullscreen element assigned to a slot.');
+
+let shadowHost = document.getElementById('host');
+let shadowRoot = shadowHost.attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = '&lt;span&gt;&lt;slot&gt;&lt;/slot&gt;&lt;/span&gt;';
+
+function goFullscreen() {
+    document.querySelector('section').webkitRequestFullScreen();
+    setTimeout(function () {
+        if (done)
+            return;
+
+        testFailed('webkitfullscreenchange was not fired');
+        finishJSTest();
+    }, 2000);
+}
+
+let done = false;
+function finalizeTest() {
+    if (done)
+        return;
+    done = true;
+
+    shouldBe('document.webkitCurrentFullScreenElement', 'document.querySelector(&quot;section&quot;)');
+    finishJSTest();
+}
+
+shadowRoot.addEventListener('webkitfullscreenchange', finalizeTest);
+document.addEventListener('fullscreenchange', finalizeTest); // Standard fullscreenchange only fires at document level.
+
+let button = document.querySelector('button');
+button.onclick = goFullscreen;
+
+if (window.eventSender) {
+    jsTestIsAsync = true;
+    eventSender.mouseMoveTo(button.offsetLeft + 5, button.offsetTop + 5);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
+&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatorwk2TestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/ios-simulator-wk2/TestExpectations (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator-wk2/TestExpectations        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/LayoutTests/platform/ios-simulator-wk2/TestExpectations        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -1778,6 +1778,10 @@
</span><span class="cx"> imported/blink/editing/selection/selectstart-event-crash.html [ Skip ]
</span><span class="cx"> fast/dom/Window/post-message-user-action.html [ Skip ]
</span><span class="cx"> fast/shadow-dom/click-text-inside-linked-slot.html [ Skip ]
</span><ins>+fast/shadow-dom/fullscreen-in-shadow-fullscreenElement.html
+fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement.html
+fast/shadow-dom/fullscreen-in-slot-fullscreenElement.html
+fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement.html
</ins><span class="cx"> 
</span><span class="cx"> # No touch events
</span><span class="cx"> http/tests/contentdispositionattachmentsandbox/referer-header-stripped-with-meta-referer-always.html [ Skip ]
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/ChangeLog        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -1,3 +1,73 @@
</span><ins>+2016-12-09  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        document.webkitFullscreenElement leaks elements inside a shadow tree
+        https://bugs.webkit.org/show_bug.cgi?id=158471
+
+        Reviewed by Chris Dumez.
+
+        Fixed the bug by calling the newly added ancestorElementInThisScope in webkitCurrentFullScreenElementForBindings
+        and webkitFullscreenElementForBinding.
+
+        The specification (https://fullscreen.spec.whatwg.org/#dom-document-fullscreenelement) uses &quot;the result of
+        retargeting fullscreen element&quot; and returns null if the result is not in the same tree as the context object.
+
+        This is equivalent to the algorithm implemented by ancestorElementInThisScope. Observe that the retargeting
+        algorithm (https://dom.spec.whatwg.org/#retarget) finds the lowest common tree scope of the retargetee and
+        the context object. There are two cases to consider.
+
+        1. The context object's tree scope is the lowest common tree scope: In this case, an ancestor shadow host or
+        the retargetee itself is in this tree scope. It's sufficient traverse every shadow host to find the one that
+        resides in the same tree scope as the context object. This is precisely what ancestorElementInThisScope does.
+
+        2. The context object's tree scope is not the lowest common tree scope: In this case, the context object is
+        inside a shadow tree whose ancestor shadow host is in the lowest common tree scope. In this case, retargeting
+        algorithm finds a node which is not in the same tree as the context object. Thus, the result is null.
+        ancestorElementInThisScope traveres ancestor shadow hosts and returns null if no shadow host's tree scope
+        matches that of the context object's tree scope. Thus, it would return null in this case as desired.
+
+        Also renamed TreeScope::focusedElement to focusedElementInScope for clarity since Document which inherits
+        from TreeScope also has a distinct member function named focusedElement called by TreeScope::focusedElement,
+        and used ancestorElementInThisScope since it uses the same algorithm.
+
+        Tests: fast/shadow-dom/activeElement-for-focused-element-in-another-shadow.html
+               fast/shadow-dom/blur-on-shadow-host-with-focused-shadow-content.html
+               fast/shadow-dom/fullscreen-in-shadow-fullscreenElement.html
+               fast/shadow-dom/fullscreen-in-shadow-webkitCurrentFullScreenElement.html
+               fast/shadow-dom/fullscreen-in-slot-fullscreenElement.html
+               fast/shadow-dom/fullscreen-in-slot-webkitCurrentFullScreenElement.html
+
+        * dom/Document.cpp:
+        (WebCore::Document::removeFocusedNodeOfSubtree):
+        (WebCore::Document::activeElement):
+        * dom/Document.h:
+        (WebCore::Document::webkitCurrentFullScreenElementForBindings): Added.
+        (WebCore::Document::webkitFullscreenElementForBindings): Added.
+        * dom/Document.idl:
+        * dom/Element.cpp:
+        (WebCore::Element::blur):
+        * dom/ShadowRoot.h:
+        (WebCore::ShadowRoot::activeElement):
+        * dom/TreeScope.cpp:
+        (WebCore::TreeScope::ancestorNodeInThisScope): Renamed from ancestorInThisScope for clarity.
+        (WebCore::TreeScope::ancestorElementInThisScope):
+        (WebCore::TreeScope::focusedElementInScope): Renamed from focusedElement to disambiguate it from Document's
+        focusedElement.
+        * dom/TreeScope.h:
+        * editing/VisibleSelection.cpp:
+        (WebCore::adjustPositionForEnd):
+        (WebCore::adjustPositionForStart):
+        * editing/htmlediting.cpp:
+        (WebCore::comparePositions):
+        (WebCore::firstEditablePositionAfterPositionInRoot):
+        (WebCore::lastEditablePositionBeforePositionInRoot):
+        * page/DOMSelection.cpp:
+        (WebCore::selectionShadowAncestor):
+        (WebCore::DOMSelection::shadowAdjustedNode):
+        (WebCore::DOMSelection::shadowAdjustedOffset):
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::addNodeToRectBasedTestResult): Added a FIXME here since this is clearly wrong for
+        shadow trees created by author scripts.
+
</ins><span class="cx"> 2016-12-09  Geoffrey Garen  &lt;ggaren@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         TextPosition and OrdinalNumber should be more like idiomatic numbers
</span></span></pre></div>
<a id="trunkSourceWebCoredomDocumentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Document.cpp (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Document.cpp        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/dom/Document.cpp        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -3540,7 +3540,7 @@
</span><span class="cx">     if (!m_focusedElement || pageCacheState() != NotInPageCache) // If the document is in the page cache, then we don't need to clear out the focused node.
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    Element* focusedElement = node.treeScope().focusedElement();
</del><ins>+    Element* focusedElement = node.treeScope().focusedElementInScope();
</ins><span class="cx">     if (!focusedElement)
</span><span class="cx">         return;
</span><span class="cx">     
</span><span class="lines">@@ -6771,7 +6771,7 @@
</span><span class="cx"> 
</span><span class="cx"> Element* Document::activeElement()
</span><span class="cx"> {
</span><del>-    if (Element* element = treeScope().focusedElement())
</del><ins>+    if (Element* element = treeScope().focusedElementInScope())
</ins><span class="cx">         return element;
</span><span class="cx">     return bodyOrFrameset();
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoredomDocumenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Document.h (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Document.h        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/dom/Document.h        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -1088,7 +1088,8 @@
</span><span class="cx">     bool webkitIsFullScreen() const { return m_fullScreenElement.get(); }
</span><span class="cx">     bool webkitFullScreenKeyboardInputAllowed() const { return m_fullScreenElement.get() &amp;&amp; m_areKeysEnabledInFullScreen; }
</span><span class="cx">     Element* webkitCurrentFullScreenElement() const { return m_fullScreenElement.get(); }
</span><del>-    
</del><ins>+    Element* webkitCurrentFullScreenElementForBindings() const { return ancestorElementInThisScope(webkitCurrentFullScreenElement()); }
+
</ins><span class="cx">     enum FullScreenCheckType {
</span><span class="cx">         EnforceIFrameAllowFullScreenRequirement,
</span><span class="cx">         ExemptIFrameAllowFullScreenRequirement,
</span><span class="lines">@@ -1115,6 +1116,7 @@
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT bool webkitFullscreenEnabled() const;
</span><span class="cx">     Element* webkitFullscreenElement() const { return !m_fullScreenElementStack.isEmpty() ? m_fullScreenElementStack.last().get() : nullptr; }
</span><ins>+    Element* webkitFullscreenElementForBindings() const { return ancestorElementInThisScope(webkitFullscreenElement()); }
</ins><span class="cx">     WEBCORE_EXPORT void webkitExitFullscreen();
</span><span class="cx"> #endif
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoredomDocumentidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Document.idl (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Document.idl        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/dom/Document.idl        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -143,12 +143,12 @@
</span><span class="cx">     // Mozilla version
</span><span class="cx">     readonly attribute boolean webkitIsFullScreen;
</span><span class="cx">     readonly attribute boolean webkitFullScreenKeyboardInputAllowed;
</span><del>-    readonly attribute Element webkitCurrentFullScreenElement;
</del><ins>+    [ImplementedAs=webkitCurrentFullScreenElementForBindings] readonly attribute Element webkitCurrentFullScreenElement;
</ins><span class="cx">     void webkitCancelFullScreen();
</span><span class="cx"> 
</span><span class="cx">     // W3C version
</span><span class="cx">     readonly attribute boolean webkitFullscreenEnabled;
</span><del>-    readonly attribute Element? webkitFullscreenElement;
</del><ins>+    [ImplementedAs=webkitFullscreenElementForBindings] readonly attribute Element? webkitFullscreenElement;
</ins><span class="cx">     void webkitExitFullscreen();
</span><span class="cx"> #endif
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Element.cpp (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Element.cpp        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/dom/Element.cpp        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -2438,7 +2438,7 @@
</span><span class="cx"> void Element::blur()
</span><span class="cx"> {
</span><span class="cx">     cancelFocusAppearanceUpdate();
</span><del>-    if (treeScope().focusedElement() == this) {
</del><ins>+    if (treeScope().focusedElementInScope() == this) {
</ins><span class="cx">         if (Frame* frame = document().frame())
</span><span class="cx">             frame-&gt;page()-&gt;focusController().setFocusedElement(0, frame);
</span><span class="cx">         else
</span></span></pre></div>
<a id="trunkSourceWebCoredomShadowRooth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ShadowRoot.h (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ShadowRoot.h        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/dom/ShadowRoot.h        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -110,7 +110,7 @@
</span><span class="cx"> 
</span><span class="cx"> inline Element* ShadowRoot::activeElement() const
</span><span class="cx"> {
</span><del>-    return treeScope().focusedElement();
</del><ins>+    return treeScope().focusedElementInScope();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline ShadowRoot* Node::shadowRoot() const
</span></span></pre></div>
<a id="trunkSourceWebCoredomTreeScopecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/TreeScope.cpp (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/TreeScope.cpp        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/dom/TreeScope.cpp        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -195,7 +195,7 @@
</span><span class="cx">     return *shadowRootInLowestCommonTreeScope.host();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Node* TreeScope::ancestorInThisScope(Node* node) const
</del><ins>+Node* TreeScope::ancestorNodeInThisScope(Node* node) const
</ins><span class="cx"> {
</span><span class="cx">     for (; node; node = node-&gt;shadowHost()) {
</span><span class="cx">         if (&amp;node-&gt;treeScope() == this)
</span><span class="lines">@@ -206,6 +206,17 @@
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Element* TreeScope::ancestorElementInThisScope(Element* element) const
+{
+    for (; element; element = element-&gt;shadowHost()) {
+        if (&amp;element-&gt;treeScope() == this)
+            return element;
+        if (!element-&gt;isInShadowTree())
+            return nullptr;
+    }
+    return nullptr;
+}
+
</ins><span class="cx"> void TreeScope::addImageMap(HTMLMapElement&amp; imageMap)
</span><span class="cx"> {
</span><span class="cx">     AtomicStringImpl* name = imageMap.getName().impl();
</span><span class="lines">@@ -364,7 +375,7 @@
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Element* TreeScope::focusedElement()
</del><ins>+Element* TreeScope::focusedElementInScope()
</ins><span class="cx"> {
</span><span class="cx">     Document&amp; document = m_rootNode.document();
</span><span class="cx">     Element* element = document.focusedElement();
</span><span class="lines">@@ -371,21 +382,8 @@
</span><span class="cx"> 
</span><span class="cx">     if (!element &amp;&amp; document.page())
</span><span class="cx">         element = focusedFrameOwnerElement(document.page()-&gt;focusController().focusedFrame(), document.frame());
</span><del>-    if (!element)
-        return nullptr;
-    TreeScope* treeScope = &amp;element-&gt;treeScope();
-    RELEASE_ASSERT(&amp;document == &amp;treeScope-&gt;documentScope());
-    while (treeScope != this &amp;&amp; treeScope != &amp;document) {
-        auto&amp; rootNode = treeScope-&gt;rootNode();
-        if (is&lt;ShadowRoot&gt;(rootNode))
-            element = downcast&lt;ShadowRoot&gt;(rootNode).host();
-        else
-            return nullptr;
-        treeScope = &amp;element-&gt;treeScope();
-    }
-    if (this != treeScope)
-        return nullptr;
-    return element;
</del><ins>+
+    return ancestorElementInThisScope(element);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void listTreeScopes(Node* node, Vector&lt;TreeScope*, 5&gt;&amp; treeScopes)
</span></span></pre></div>
<a id="trunkSourceWebCoredomTreeScopeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/TreeScope.h (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/TreeScope.h        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/dom/TreeScope.h        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -51,7 +51,7 @@
</span><span class="cx">     TreeScope* parentTreeScope() const { return m_parentTreeScope; }
</span><span class="cx">     void setParentTreeScope(TreeScope&amp;);
</span><span class="cx"> 
</span><del>-    Element* focusedElement();
</del><ins>+    Element* focusedElementInScope();
</ins><span class="cx">     WEBCORE_EXPORT Element* getElementById(const AtomicString&amp;) const;
</span><span class="cx">     WEBCORE_EXPORT Element* getElementById(const String&amp;) const;
</span><span class="cx">     const Vector&lt;Element*&gt;* getAllElementsById(const AtomicString&amp;) const;
</span><span class="lines">@@ -72,7 +72,8 @@
</span><span class="cx">     // https://dom.spec.whatwg.org/#retarget
</span><span class="cx">     Node&amp; retargetToScope(Node&amp;) const;
</span><span class="cx"> 
</span><del>-    Node* ancestorInThisScope(Node*) const;
</del><ins>+    Node* ancestorNodeInThisScope(Node*) const;
+    WEBCORE_EXPORT Element* ancestorElementInThisScope(Element*) const;
</ins><span class="cx"> 
</span><span class="cx">     void addImageMap(HTMLMapElement&amp;);
</span><span class="cx">     void removeImageMap(HTMLMapElement&amp;);
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingVisibleSelectioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/VisibleSelection.cpp (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/VisibleSelection.cpp        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/editing/VisibleSelection.cpp        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -473,7 +473,7 @@
</span><span class="cx"> 
</span><span class="cx">     ASSERT(&amp;currentPosition.containerNode()-&gt;treeScope() != &amp;treeScope);
</span><span class="cx"> 
</span><del>-    if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.containerNode())) {
</del><ins>+    if (Node* ancestor = treeScope.ancestorNodeInThisScope(currentPosition.containerNode())) {
</ins><span class="cx">         if (ancestor-&gt;contains(startContainerNode))
</span><span class="cx">             return positionAfterNode(ancestor);
</span><span class="cx">         return positionBeforeNode(ancestor);
</span><span class="lines">@@ -491,7 +491,7 @@
</span><span class="cx"> 
</span><span class="cx">     ASSERT(&amp;currentPosition.containerNode()-&gt;treeScope() != &amp;treeScope);
</span><span class="cx">     
</span><del>-    if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.containerNode())) {
</del><ins>+    if (Node* ancestor = treeScope.ancestorNodeInThisScope(currentPosition.containerNode())) {
</ins><span class="cx">         if (ancestor-&gt;contains(endContainerNode))
</span><span class="cx">             return positionBeforeNode(ancestor);
</span><span class="cx">         return positionAfterNode(ancestor);
</span></span></pre></div>
<a id="trunkSourceWebCoreeditinghtmleditingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/htmlediting.cpp (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/htmlediting.cpp        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/editing/htmlediting.cpp        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -83,12 +83,12 @@
</span><span class="cx">     if (!commonScope)
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><del>-    Node* nodeA = commonScope-&gt;ancestorInThisScope(a.containerNode());
</del><ins>+    Node* nodeA = commonScope-&gt;ancestorNodeInThisScope(a.containerNode());
</ins><span class="cx">     ASSERT(nodeA);
</span><span class="cx">     bool hasDescendentA = nodeA != a.containerNode();
</span><span class="cx">     int offsetA = hasDescendentA ? 0 : a.computeOffsetInContainerNode();
</span><span class="cx"> 
</span><del>-    Node* nodeB = commonScope-&gt;ancestorInThisScope(b.containerNode());
</del><ins>+    Node* nodeB = commonScope-&gt;ancestorNodeInThisScope(b.containerNode());
</ins><span class="cx">     ASSERT(nodeB);
</span><span class="cx">     bool hasDescendentB = nodeB != b.containerNode();
</span><span class="cx">     int offsetB = hasDescendentB ? 0 : b.computeOffsetInContainerNode();
</span><span class="lines">@@ -292,7 +292,7 @@
</span><span class="cx">     Position candidate = position;
</span><span class="cx"> 
</span><span class="cx">     if (&amp;position.deprecatedNode()-&gt;treeScope() != &amp;highestRoot-&gt;treeScope()) {
</span><del>-        auto* shadowAncestor = highestRoot-&gt;treeScope().ancestorInThisScope(position.deprecatedNode());
</del><ins>+        auto* shadowAncestor = highestRoot-&gt;treeScope().ancestorNodeInThisScope(position.deprecatedNode());
</ins><span class="cx">         if (!shadowAncestor)
</span><span class="cx">             return { };
</span><span class="cx"> 
</span><span class="lines">@@ -320,7 +320,7 @@
</span><span class="cx">     Position candidate = position;
</span><span class="cx"> 
</span><span class="cx">     if (&amp;position.deprecatedNode()-&gt;treeScope() != &amp;highestRoot-&gt;treeScope()) {
</span><del>-        auto* shadowAncestor = highestRoot-&gt;treeScope().ancestorInThisScope(position.deprecatedNode());
</del><ins>+        auto* shadowAncestor = highestRoot-&gt;treeScope().ancestorNodeInThisScope(position.deprecatedNode());
</ins><span class="cx">         if (!shadowAncestor)
</span><span class="cx">             return { };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorepageDOMSelectioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/DOMSelection.cpp (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/DOMSelection.cpp        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/page/DOMSelection.cpp        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -49,7 +49,7 @@
</span><span class="cx">     if (!node-&gt;isInShadowTree())
</span><span class="cx">         return nullptr;
</span><span class="cx">     // FIXME: Unclear on why this needs to be the possibly null frame.document() instead of the never null node-&gt;document().
</span><del>-    return frame.document()-&gt;ancestorInThisScope(node);
</del><ins>+    return frame.document()-&gt;ancestorNodeInThisScope(node);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> DOMSelection::DOMSelection(Frame&amp; frame)
</span><span class="lines">@@ -436,7 +436,7 @@
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><span class="cx">     auto* containerNode = position.containerNode();
</span><del>-    auto* adjustedNode = m_frame-&gt;document()-&gt;ancestorInThisScope(containerNode);
</del><ins>+    auto* adjustedNode = m_frame-&gt;document()-&gt;ancestorNodeInThisScope(containerNode);
</ins><span class="cx">     if (!adjustedNode)
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><span class="lines">@@ -452,7 +452,7 @@
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><span class="cx">     auto* containerNode = position.containerNode();
</span><del>-    auto* adjustedNode = m_frame-&gt;document()-&gt;ancestorInThisScope(containerNode);
</del><ins>+    auto* adjustedNode = m_frame-&gt;document()-&gt;ancestorNodeInThisScope(containerNode);
</ins><span class="cx">     if (!adjustedNode)
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingHitTestResultcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/HitTestResult.cpp (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/HitTestResult.cpp        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebCore/rendering/HitTestResult.cpp        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -668,8 +668,9 @@
</span><span class="cx">     if (!node)
</span><span class="cx">         return true;
</span><span class="cx"> 
</span><ins>+    // FIXME: This moves out of a author shadow tree.
</ins><span class="cx">     if (request.disallowsUserAgentShadowContent())
</span><del>-        node = node-&gt;document().ancestorInThisScope(node);
</del><ins>+        node = node-&gt;document().ancestorNodeInThisScope(node);
</ins><span class="cx"> 
</span><span class="cx">     mutableRectBasedTestResult().add(node);
</span><span class="cx"> 
</span><span class="lines">@@ -688,8 +689,9 @@
</span><span class="cx">     if (!node)
</span><span class="cx">         return true;
</span><span class="cx"> 
</span><ins>+    // FIXME: This moves out of a author shadow tree.
</ins><span class="cx">     if (request.disallowsUserAgentShadowContent())
</span><del>-        node = node-&gt;document().ancestorInThisScope(node);
</del><ins>+        node = node-&gt;document().ancestorNodeInThisScope(node);
</ins><span class="cx"> 
</span><span class="cx">     mutableRectBasedTestResult().add(node);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitmacChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/ChangeLog (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/ChangeLog        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebKit/mac/ChangeLog        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2016-12-09  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        document.webkitFullscreenElement leaks elements inside a shadow tree
+        https://bugs.webkit.org/show_bug.cgi?id=158471
+
+        Reviewed by Chris Dumez.
+
+        Use the API for bindings to avoid exposing nodes inside a shadow tree.
+
+        * DOM/DOMDocument.mm:
+        (-[DOMDocument webkitCurrentFullScreenElement]):
+        (-[DOMDocument webkitFullscreenElement]):
+
</ins><span class="cx"> 2016-12-09  Beth Dakin  &lt;bdakin@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Password fields should not show the emoji button in TouchBar
</span></span></pre></div>
<a id="trunkSourceWebKitmacDOMDOMDocumentmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/DOM/DOMDocument.mm (209627 => 209628)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/DOM/DOMDocument.mm        2016-12-09 22:04:14 UTC (rev 209627)
+++ trunk/Source/WebKit/mac/DOM/DOMDocument.mm        2016-12-09 22:06:29 UTC (rev 209628)
</span><span class="lines">@@ -361,7 +361,7 @@
</span><span class="cx"> - (DOMElement *)webkitCurrentFullScreenElement
</span><span class="cx"> {
</span><span class="cx">     WebCore::JSMainThreadNullState state;
</span><del>-    return kit(WTF::getPtr(IMPL-&gt;webkitCurrentFullScreenElement()));
</del><ins>+    return kit(WTF::getPtr(IMPL-&gt;webkitCurrentFullScreenElementForBindings()));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (BOOL)webkitFullscreenEnabled
</span><span class="lines">@@ -373,7 +373,7 @@
</span><span class="cx"> - (DOMElement *)webkitFullscreenElement
</span><span class="cx"> {
</span><span class="cx">     WebCore::JSMainThreadNullState state;
</span><del>-    return kit(WTF::getPtr(IMPL-&gt;webkitFullscreenElement()));
</del><ins>+    return kit(WTF::getPtr(IMPL-&gt;webkitFullscreenElementForBindings()));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #endif
</span></span></pre>
</div>
</div>

</body>
</html>