<!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>[210432] 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/210432">210432</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2017-01-05 19:45:16 -0800 (Thu, 05 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Finding text doesn't work across shadow boundary
https://bugs.webkit.org/show_bug.cgi?id=158503

Reviewed by Antti Koivisto.

Source/WebCore:

Added a new TextIterator behavior flag, TextIteratorTraversesFlatTree, which makes TextIterator traverse
the flat tree instead of the DOM tree, and made this behavior default in findPlainText.

Also added a new find options flag, DoNotTraverseFlatTree, to suppress this behavior in window.find(~)
and execCommand('FindString', false, ~) as they should not be able to peek information inside shadow trees.
Unfortunately these APIs have been deprecated in the standards so there is no specification to follow.

For now, we don't support finding a word or a keyword across a shadow boundary as this would require
making rangeOfString and other related functions return a Range-like object that can cross shadow boundaries.

Also added internals.rangeOfString to test Editor::rangeOfString, and replaced the bit-flag arguments
to internals.countMatchesForText and internals.countFindMatches by an array of strings for better portability.

Test: editing/text-iterator/find-string-on-flat-tree.html

* editing/Editor.cpp:
(WebCore::Editor::rangeOfString): Use the modern containingShadowRoot instead of nonBoundaryShadowTreeRootNode
since the start container can be a shadow root, which nonBoundaryShadowTreeRootNode asserts not be the case.
* editing/Editor.h:
* editing/EditorCommand.cpp:
(WebCore::executeFindString): Don't traverse across shadow boundaries.
* editing/FindOptions.h: Added DoNotTraverseFlatTree.
* editing/TextIterator.cpp:
(WebCore::assignedAuthorSlot): Added.
(WebCore::authorShadowRoot): Added.
(WebCore::firstChildInFlatTreeIgnoringUserAgentShadow): Added.
(WebCore::nextSiblingInFlatTreeIgnoringUserAgentShadow): Added.
(WebCore::firstChild): Added. Traverses the flat tree when TextIteratorTraversesFlatTree is set.
(WebCore::nextSibling): Ditto.
(WebCore::parentNodeOrShadowHost): Ditto.
(WebCore::TextIterator::advance): Don't set m_handledChildren to true when the current node has display: contents.
(WebCore::findPlainText): Use TextIteratorTraversesFlatTree unless DoNotTraverseFlatTree is set.
* editing/TextIteratorBehavior.h: Added TextIteratorTraversesFlatTree.
* page/DOMWindow.cpp:
(WebCore::DOMWindow::find): Don't traverse across shadow boundaries.
* testing/Internals.cpp:
(WebCore::parseFindOptions): Added.
(WebCore::Internals::rangeOfString): Added.
(WebCore::Internals::countMatchesForText): Replaced the find options by an array of strings instead of a bit mask.
(WebCore::Internals::countFindMatches): Ditto.
* testing/Internals.h:
* testing/Internals.idl: Added rangeOfString, and replaced find options bit-flag in countMatchesForText and
countFindMatches by an array of strings so that the tests themselves don't rely on a specific value of each bit flag.

LayoutTests:

Updated the existing tests per changes to use an array of find options instead of raw bit mask,
and added a regression test for finding text by traversing flat tree along with testing
window.find and execCommand('FindString', false, ~) not walking across shadow boundaries.

* editing/text-iterator/count-mark-lineboxes-expected.txt:
* editing/text-iterator/count-mark-lineboxes.html:
* editing/text-iterator/count-mark-simple-lines-expected.txt:
* editing/text-iterator/count-mark-simple-lines.html:
* editing/text-iterator/count-matches-in-form-expected.txt:
* editing/text-iterator/count-matches-in-form.html:
* editing/text-iterator/count-matches-in-frames.html:
* editing/text-iterator/find-string-on-flat-tree-expected.txt: Added.
* editing/text-iterator/find-string-on-flat-tree.html: Added.
* fast/text/mark-matches-broken-line-rendering.html:
* fast/text/mark-matches-overflow-clip.html:
* fast/text/mark-matches-rendering-simple-lines-expected.html:
* fast/text/mark-matches-rendering-simple-lines.html:
* fast/text/mark-matches-rendering.html:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestseditingtextiteratorcountmarklineboxesexpectedtxt">trunk/LayoutTests/editing/text-iterator/count-mark-lineboxes-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingtextiteratorcountmarklineboxeshtml">trunk/LayoutTests/editing/text-iterator/count-mark-lineboxes.html</a></li>
<li><a href="#trunkLayoutTestseditingtextiteratorcountmarksimplelinesexpectedtxt">trunk/LayoutTests/editing/text-iterator/count-mark-simple-lines-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingtextiteratorcountmarksimplelineshtml">trunk/LayoutTests/editing/text-iterator/count-mark-simple-lines.html</a></li>
<li><a href="#trunkLayoutTestseditingtextiteratorcountmatchesinformexpectedtxt">trunk/LayoutTests/editing/text-iterator/count-matches-in-form-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingtextiteratorcountmatchesinformhtml">trunk/LayoutTests/editing/text-iterator/count-matches-in-form.html</a></li>
<li><a href="#trunkLayoutTestseditingtextiteratorcountmatchesinframeshtml">trunk/LayoutTests/editing/text-iterator/count-matches-in-frames.html</a></li>
<li><a href="#trunkLayoutTestsfasttextmarkmatchesbrokenlinerenderinghtml">trunk/LayoutTests/fast/text/mark-matches-broken-line-rendering.html</a></li>
<li><a href="#trunkLayoutTestsfasttextmarkmatchesoverflowcliphtml">trunk/LayoutTests/fast/text/mark-matches-overflow-clip.html</a></li>
<li><a href="#trunkLayoutTestsfasttextmarkmatchesrenderingsimplelinesexpectedhtml">trunk/LayoutTests/fast/text/mark-matches-rendering-simple-lines-expected.html</a></li>
<li><a href="#trunkLayoutTestsfasttextmarkmatchesrenderingsimplelineshtml">trunk/LayoutTests/fast/text/mark-matches-rendering-simple-lines.html</a></li>
<li><a href="#trunkLayoutTestsfasttextmarkmatchesrenderinghtml">trunk/LayoutTests/fast/text/mark-matches-rendering.html</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreeditingEditorcpp">trunk/Source/WebCore/editing/Editor.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingEditorh">trunk/Source/WebCore/editing/Editor.h</a></li>
<li><a href="#trunkSourceWebCoreeditingEditorCommandcpp">trunk/Source/WebCore/editing/EditorCommand.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingFindOptionsh">trunk/Source/WebCore/editing/FindOptions.h</a></li>
<li><a href="#trunkSourceWebCoreeditingTextIteratorcpp">trunk/Source/WebCore/editing/TextIterator.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingTextIteratorBehaviorh">trunk/Source/WebCore/editing/TextIteratorBehavior.h</a></li>
<li><a href="#trunkSourceWebCorepageDOMWindowcpp">trunk/Source/WebCore/page/DOMWindow.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingInternalscpp">trunk/Source/WebCore/testing/Internals.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingInternalsh">trunk/Source/WebCore/testing/Internals.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalsidl">trunk/Source/WebCore/testing/Internals.idl</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestseditingtextiteratorfindstringonflattreeexpectedtxt">trunk/LayoutTests/editing/text-iterator/find-string-on-flat-tree-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingtextiteratorfindstringonflattreehtml">trunk/LayoutTests/editing/text-iterator/find-string-on-flat-tree.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/ChangeLog        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2017-01-05  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        Finding text doesn't work across shadow boundary
+        https://bugs.webkit.org/show_bug.cgi?id=158503
+
+        Reviewed by Antti Koivisto.
+
+        Updated the existing tests per changes to use an array of find options instead of raw bit mask,
+        and added a regression test for finding text by traversing flat tree along with testing
+        window.find and execCommand('FindString', false, ~) not walking across shadow boundaries.
+
+        * editing/text-iterator/count-mark-lineboxes-expected.txt:
+        * editing/text-iterator/count-mark-lineboxes.html:
+        * editing/text-iterator/count-mark-simple-lines-expected.txt:
+        * editing/text-iterator/count-mark-simple-lines.html:
+        * editing/text-iterator/count-matches-in-form-expected.txt:
+        * editing/text-iterator/count-matches-in-form.html:
+        * editing/text-iterator/count-matches-in-frames.html:
+        * editing/text-iterator/find-string-on-flat-tree-expected.txt: Added.
+        * editing/text-iterator/find-string-on-flat-tree.html: Added.
+        * fast/text/mark-matches-broken-line-rendering.html:
+        * fast/text/mark-matches-overflow-clip.html:
+        * fast/text/mark-matches-rendering-simple-lines-expected.html:
+        * fast/text/mark-matches-rendering-simple-lines.html:
+        * fast/text/mark-matches-rendering.html:
+
</ins><span class="cx"> 2017-01-05  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, teach run-javascriptcore-tests that this is a slow test.
</span></span></pre></div>
<a id="trunkLayoutTestseditingtextiteratorcountmarklineboxesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/text-iterator/count-mark-lineboxes-expected.txt (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/text-iterator/count-mark-lineboxes-expected.txt        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/editing/text-iterator/count-mark-lineboxes-expected.txt        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -1,8 +1,8 @@
</span><del>-PASS internals.countMatchesForText('Catilina', 23, 'mark') is 3
</del><ins>+PASS internals.countMatchesForText('Catilina', findOptions, 'mark') is 3
</ins><span class="cx"> PASS internals.markerCountForNode(text, 'all') is 3
</span><del>-PASS internals.countMatchesForText('Roma', 23, 'mark') is 3
</del><ins>+PASS internals.countMatchesForText('Roma', findOptions, 'mark') is 3
</ins><span class="cx"> PASS internals.markerCountForNode(text, 'all') is 6
</span><del>-PASS internals.countMatchesForText('uid', 23, 'mark') is 2
</del><ins>+PASS internals.countMatchesForText('uid', findOptions, 'mark') is 2
</ins><span class="cx"> PASS internals.markerCountForNode(text, 'all') is 8
</span><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestseditingtextiteratorcountmarklineboxeshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/text-iterator/count-mark-lineboxes.html (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/text-iterator/count-mark-lineboxes.html        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/editing/text-iterator/count-mark-lineboxes.html        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -49,11 +49,12 @@
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> &lt;script&gt;
</span><span class="cx"> var text = document.getElementById('test').firstChild;
</span><del>-shouldBe(&quot;internals.countMatchesForText('Catilina', 23, 'mark')&quot;, &quot;3&quot;);
</del><ins>+var findOptions = ['CaseInsensitive', 'AtWordStarts', 'TreatMedialCapitalAsWordStart', 'WrapAround'];
+shouldBe(&quot;internals.countMatchesForText('Catilina', findOptions, 'mark')&quot;, &quot;3&quot;);
</ins><span class="cx"> shouldBe(&quot;internals.markerCountForNode(text, 'all')&quot;, &quot;3&quot;);
</span><del>-shouldBe(&quot;internals.countMatchesForText('Roma', 23, 'mark')&quot;, &quot;3&quot;);
</del><ins>+shouldBe(&quot;internals.countMatchesForText('Roma', findOptions, 'mark')&quot;, &quot;3&quot;);
</ins><span class="cx"> shouldBe(&quot;internals.markerCountForNode(text, 'all')&quot;, &quot;6&quot;);
</span><del>-shouldBe(&quot;internals.countMatchesForText('uid', 23, 'mark')&quot;, &quot;2&quot;);
</del><ins>+shouldBe(&quot;internals.countMatchesForText('uid', findOptions, 'mark')&quot;, &quot;2&quot;);
</ins><span class="cx"> shouldBe(&quot;internals.markerCountForNode(text, 'all')&quot;, &quot;8&quot;);
</span><span class="cx"> &lt;/script&gt;
</span><span class="cx"> &lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</span></span></pre></div>
<a id="trunkLayoutTestseditingtextiteratorcountmarksimplelinesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/text-iterator/count-mark-simple-lines-expected.txt (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/text-iterator/count-mark-simple-lines-expected.txt        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/editing/text-iterator/count-mark-simple-lines-expected.txt        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -1,8 +1,8 @@
</span><del>-PASS internals.countMatchesForText('Catilina', 23, 'mark') is 3
</del><ins>+PASS internals.countMatchesForText('Catilina', findOptions, 'mark') is 3
</ins><span class="cx"> PASS internals.markerCountForNode(text, 'all') is 3
</span><del>-PASS internals.countMatchesForText('Roma', 23, 'mark') is 3
</del><ins>+PASS internals.countMatchesForText('Roma', findOptions, 'mark') is 3
</ins><span class="cx"> PASS internals.markerCountForNode(text, 'all') is 6
</span><del>-PASS internals.countMatchesForText('uid', 23, 'mark') is 2
</del><ins>+PASS internals.countMatchesForText('uid', findOptions, 'mark') is 2
</ins><span class="cx"> PASS internals.markerCountForNode(text, 'all') is 8
</span><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestseditingtextiteratorcountmarksimplelineshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/text-iterator/count-mark-simple-lines.html (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/text-iterator/count-mark-simple-lines.html        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/editing/text-iterator/count-mark-simple-lines.html        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -46,11 +46,12 @@
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> &lt;script&gt;
</span><span class="cx"> var text = document.getElementById('test').firstChild;
</span><del>-shouldBe(&quot;internals.countMatchesForText('Catilina', 23, 'mark')&quot;, &quot;3&quot;);
</del><ins>+var findOptions = ['CaseInsensitive', 'AtWordStarts', 'TreatMedialCapitalAsWordStart', 'WrapAround'];
+shouldBe(&quot;internals.countMatchesForText('Catilina', findOptions, 'mark')&quot;, &quot;3&quot;);
</ins><span class="cx"> shouldBe(&quot;internals.markerCountForNode(text, 'all')&quot;, &quot;3&quot;);
</span><del>-shouldBe(&quot;internals.countMatchesForText('Roma', 23, 'mark')&quot;, &quot;3&quot;);
</del><ins>+shouldBe(&quot;internals.countMatchesForText('Roma', findOptions, 'mark')&quot;, &quot;3&quot;);
</ins><span class="cx"> shouldBe(&quot;internals.markerCountForNode(text, 'all')&quot;, &quot;6&quot;);
</span><del>-shouldBe(&quot;internals.countMatchesForText('uid', 23, 'mark')&quot;, &quot;2&quot;);
</del><ins>+shouldBe(&quot;internals.countMatchesForText('uid', findOptions, 'mark')&quot;, &quot;2&quot;);
</ins><span class="cx"> shouldBe(&quot;internals.markerCountForNode(text, 'all')&quot;, &quot;8&quot;);
</span><span class="cx"> &lt;/script&gt;
</span><span class="cx"> &lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</span></span></pre></div>
<a id="trunkLayoutTestseditingtextiteratorcountmatchesinformexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/text-iterator/count-matches-in-form-expected.txt (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/text-iterator/count-matches-in-form-expected.txt        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/editing/text-iterator/count-matches-in-form-expected.txt        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-PASS internals.countMatchesForText('rule', 23, '') is 1
</del><ins>+PASS internals.countMatchesForText('rule', ['CaseInsensitive', 'AtWordStarts', 'TreatMedialCapitalAsWordStart', 'WrapAround'], '') is 1
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestseditingtextiteratorcountmatchesinformhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/text-iterator/count-matches-in-form.html (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/text-iterator/count-matches-in-form.html        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/editing/text-iterator/count-matches-in-form.html        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -3,6 +3,6 @@
</span><span class="cx"> &lt;body&gt;
</span><span class="cx"> &lt;fieldset&gt;&lt;input value=&quot;rule&quot;&gt;&lt;/fieldset&gt;
</span><span class="cx"> &lt;script&gt;
</span><del>-shouldBe(&quot;internals.countMatchesForText('rule', 23, '')&quot;, &quot;1&quot;);
</del><ins>+shouldBe(&quot;internals.countMatchesForText('rule', ['CaseInsensitive', 'AtWordStarts', 'TreatMedialCapitalAsWordStart', 'WrapAround'], '')&quot;, &quot;1&quot;);
</ins><span class="cx"> &lt;/script&gt;
</span><span class="cx"> &lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</span></span></pre></div>
<a id="trunkLayoutTestseditingtextiteratorcountmatchesinframeshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/text-iterator/count-matches-in-frames.html (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/text-iterator/count-matches-in-frames.html        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/editing/text-iterator/count-matches-in-frames.html        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -25,7 +25,7 @@
</span><span class="cx"> 
</span><span class="cx">     frame.contentDocument.body.innerHTML = findString;
</span><span class="cx"> 
</span><del>-    assert_equals(internals.countFindMatches(findString, 0, ''), shouldFindInFrame ? 2 : 1);
</del><ins>+    assert_equals(internals.countFindMatches(findString, [], ''), shouldFindInFrame ? 2 : 1);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> test(function () {
</span></span></pre></div>
<a id="trunkLayoutTestseditingtextiteratorfindstringonflattreeexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/text-iterator/find-string-on-flat-tree-expected.txt (0 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/text-iterator/find-string-on-flat-tree-expected.txt                                (rev 0)
+++ trunk/LayoutTests/editing/text-iterator/find-string-on-flat-tree-expected.txt        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -0,0 +1,83 @@
</span><ins>+This tests finding across shadow boundaries using the flat tree.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS clearSelection(); document.execCommand('FindString', null, 'in-document'); selectedText() is '(#test-content, 0) 0 to 11'
+PASS clearSelection(); window.find('in-document'); selectedText() is '(#test-content, 0) 0 to 11'
+PASS rangeText(internals.rangeOfString('in-document', null, ['DoNotTraverseFlatTree'])) is '(#test-content, 0) 0 to 11'
+PASS rangeText(internals.rangeOfString('in-document', null, [])) is '(#test-content, 0) 0 to 11'
+PASS clearSelection(); document.execCommand('FindString', null, 'in-shadow'); selectedText() is null
+PASS clearSelection(); window.find('in-shadow'); selectedText() is null
+PASS rangeText(internals.rangeOfString('in-shadow', null, ['DoNotTraverseFlatTree'])) is null
+PASS rangeText(internals.rangeOfString('in-shadow', null, [])) is '(#shadow-root, 0) 0 to 9'
+PASS clearSelection(); document.execCommand('FindString', null, 'unslotted'); selectedText() is null
+PASS clearSelection(); window.find('unslotted'); selectedText() is null
+PASS rangeText(internals.rangeOfString('unslotted', null, ['DoNotTraverseFlatTree'])) is null
+PASS rangeText(internals.rangeOfString('unslotted', null, [])) is null
+PASS clearSelection(); document.execCommand('FindString', null, 'slotted'); selectedText() is '(#slotted-element, 0) 0 to 7'
+PASS clearSelection(); window.find('slotted'); selectedText() is '(#slotted-element, 0) 0 to 7'
+PASS rangeText(internals.rangeOfString('slotted', null, ['DoNotTraverseFlatTree'])) is '(#slotted-element, 0) 0 to 7'
+PASS rangeText(internals.rangeOfString('slotted', null, [])) is '(#slotted-element, 0) 0 to 7'
+PASS clearSelection(); document.execCommand('FindString', null, 'slotted in-document'); selectedText() is '((#slotted-element, 0), 0) to ((#test-content, 2), 12)'
+PASS clearSelection(); window.find('slotted in-document'); selectedText() is '((#slotted-element, 0), 0) to ((#test-content, 2), 12)'
+PASS rangeText(internals.rangeOfString('slotted in-document', null, ['DoNotTraverseFlatTree'])) is '((#slotted-element, 0), 0) to ((#test-content, 2), 12)'
+PASS rangeText(internals.rangeOfString('slotted in-document', null, [])) is null
+PASS clearSelection(); document.execCommand('FindString', null, 'in-shadow in-document'); selectedText() is null
+PASS clearSelection(); window.find('in-shadow in-document'); selectedText() is null
+PASS rangeText(internals.rangeOfString('in-shadow in-document', null, ['DoNotTraverseFlatTree'])) is null
+PASS rangeText(internals.rangeOfString('in-shadow in-document', null, [])) is null /* Can't return a range across shadow boundary */
+PASS setSelection(testContent, 1); document.execCommand('FindString', null, 'in-document'); selectedText() is '(#test-content, 2) 1 to 12'
+PASS setSelection(testContent, 1); window.find('in-document'); selectedText() is '(#test-content, 2) 1 to 12'
+PASS rangeText(internals.rangeOfString('in-document', range(testContent, 1), ['DoNotTraverseFlatTree'])) is '(#test-content, 2) 1 to 12'
+PASS rangeText(internals.rangeOfString('in-document', range(testContent, 1), [])) is '(#test-content, 2) 1 to 12'
+PASS setSelection(shadowRoot, 0); document.execCommand('FindString', null, 'in-document'); selectedText() is '(#test-content, 2) 1 to 12'
+PASS setSelection(shadowRoot, 0); window.find('in-document'); selectedText() is '(#test-content, 2) 1 to 12'
+PASS rangeText(internals.rangeOfString('in-document', range(shadowRoot, 0), ['DoNotTraverseFlatTree'])) is '(#test-content, 2) 1 to 12'
+PASS rangeText(internals.rangeOfString('in-document', range(shadowRoot, 0), [])) is '(#test-content, 2) 1 to 12'
+PASS setSelection(shadowRoot, 0); document.execCommand('FindString', null, 'in-shadow'); selectedText() is '#test-content 1 to 1'
+PASS setSelection(shadowRoot, 0); window.find('in-shadow'); selectedText() is '#test-content 1 to 1'
+PASS rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 0), ['DoNotTraverseFlatTree'])) is '(#shadow-root, 0) 0 to 9'
+PASS rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 0), [])) is '(#shadow-root, 0) 0 to 9'
+PASS setSelection(shadowRoot, 0); document.execCommand('FindString', null, 'slotted'); selectedText() is '(#slotted-element, 0) 0 to 7' /* Wrapped around */
+PASS setSelection(shadowRoot, 0); window.find('slotted'); selectedText() is '#test-content 1 to 1'
+PASS setSelection(shadowRoot, 0); window.find('slotted', /* caseSensitive */ true, /* backwards */ false, /* wrap */ true); selectedText() is '(#slotted-element, 0) 0 to 7'
+PASS rangeText(internals.rangeOfString('slotted', range(shadowRoot, 0), ['DoNotTraverseFlatTree'])) is null
+PASS rangeText(internals.rangeOfString('slotted', range(shadowRoot, 0), [])) is '(#slotted-element, 0) 0 to 7'
+PASS setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'slotted'); selectedText() is '(#slotted-element, 0) 0 to 7' /* Wrapped around */
+PASS setSelection(shadowRoot, 1); window.find('slotted'); selectedText() is '#test-content 1 to 1'
+PASS setSelection(shadowRoot, 1); window.find('slotted', /* caseSensitive */ true, /* backwards */ false, /* wrap */ true); selectedText() is '(#slotted-element, 0) 0 to 7'
+PASS rangeText(internals.rangeOfString('slotted', range(shadowRoot, 1), ['DoNotTraverseFlatTree'])) is null
+PASS rangeText(internals.rangeOfString('slotted', range(shadowRoot, 1), [])) is '(#slotted-element, 0) 0 to 7'
+PASS setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'in-shadow'); selectedText() is '#test-content 1 to 1'
+PASS setSelection(shadowRoot, 1); window.find('in-shadow'); selectedText() is '#test-content 1 to 1'
+PASS rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 1), ['DoNotTraverseFlatTree'])) is '(#shadow-root, 2) 1 to 10'
+PASS rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 1), [])) is '(#shadow-root, 2) 1 to 10'
+PASS setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'in-document'); selectedText() is '(#test-content, 2) 1 to 12'
+PASS setSelection(shadowRoot, 1); window.find('in-document'); selectedText() is '(#test-content, 2) 1 to 12'
+PASS rangeText(internals.rangeOfString('in-document', range(shadowRoot, 1), ['DoNotTraverseFlatTree'])) is '(#test-content, 2) 1 to 12'
+PASS rangeText(internals.rangeOfString('in-document', range(shadowRoot, 1), [])) is '(#test-content, 2) 1 to 12'
+PASS setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'in-slot'); selectedText() is '#test-content 1 to 1'
+PASS setSelection(shadowRoot, 1); window.find('in-slot'); selectedText() is '#test-content 1 to 1'
+PASS rangeText(internals.rangeOfString('in-slot', range(shadowRoot, 1), ['DoNotTraverseFlatTree'])) is null
+PASS rangeText(internals.rangeOfString('in-slot', range(shadowRoot, 1), [])) is null
+PASS clearSelection(); document.execCommand('FindString', null, 'in-user-agent-shadow'); selectedText() is null
+PASS clearSelection(); window.find('in-user-agent-shadow'); selectedText() is null
+PASS rangeText(internals.rangeOfString('in-user-agent-shadow', null, ['DoNotTraverseFlatTree'])) is null
+PASS rangeText(internals.rangeOfString('in-user-agent-shadow', null, [])) is null
+PASS setSelection(userAgentShadowRoot, 0); document.execCommand('FindString', null, 'in-user-agent-shadow'); selectedText() is '#test-content 3 to 3'
+PASS setSelection(userAgentShadowRoot, 0); window.find('in-user-agent-shadow'); selectedText() is '#test-content 3 to 3'
+PASS rangeText(internals.rangeOfString('in-user-agent-shadow', range(userAgentShadowRoot, 0), ['DoNotTraverseFlatTree'])) is '(#user-agent-shadow-root, 0) 0 to 20'
+PASS rangeText(internals.rangeOfString('in-user-agent-shadow', range(userAgentShadowRoot, 0), [])) is '(#user-agent-shadow-root, 0) 0 to 20'
+PASS clearSelection(); internals.countFindMatches('in-document', ['DoNotTraverseFlatTree']) is 2
+PASS internals.countFindMatches('in-document', []) is 2
+PASS internals.countFindMatches('in-shadow', ['DoNotTraverseFlatTree']) is 0
+PASS internals.countFindMatches('in-shadow', []) is 2
+PASS internals.countFindMatches('in-', ['DoNotTraverseFlatTree']) is 2
+PASS internals.countFindMatches('in-', []) is 4
+PASS internals.countFindMatches('in-shadow in-document', ['DoNotTraverseFlatTree']) is 0
+PASS internals.countFindMatches('in-shadow in-document', []) is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+in-document slotted in-document
</ins></span></pre></div>
<a id="trunkLayoutTestseditingtextiteratorfindstringonflattreehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/text-iterator/find-string-on-flat-tree.html (0 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/text-iterator/find-string-on-flat-tree.html                                (rev 0)
+++ trunk/LayoutTests/editing/text-iterator/find-string-on-flat-tree.html        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -0,0 +1,169 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;div id=&quot;test-content&quot;&gt;in-document &lt;span id=&quot;host&quot;&gt;unslotted &lt;b id=&quot;slotted-element&quot; slot=&quot;named-slot&quot;&gt;slotted&lt;/b&gt; unslotted&lt;/span&gt; in-document&lt;span id=&quot;user-agent-host&quot;&gt;&lt;/span&gt;&lt;/div&gt;
+&lt;script src=&quot;../../resources/js-test.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+description('This tests finding across shadow boundaries using the flat tree.');
+
+var testContent = document.getElementById('test-content');
+var shadowHost = document.getElementById('host');
+var shadowRoot = shadowHost.attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = 'in-shadow &lt;slot name=&quot;named-slot&quot;&gt;in-slot&lt;/slot&gt; in-shadow';
+shadowRoot.id = 'shadow-root';
+
+if (!window.internals)
+    testFailed('This test requires internals');
+else {
+    var userAgentShadowHost = document.getElementById('user-agent-host');
+    var userAgentShadowRoot = internals.ensureUserAgentShadowRoot(userAgentShadowHost);
+    userAgentShadowRoot.innerHTML = 'in-user-agent-shadow';
+    userAgentShadowRoot.id = 'user-agent-shadow-root';
+
+    // Hide console so that we don't end up finding text in the log itself.
+    document.getElementById('console').style.display = 'none';
+
+    function nodeLabel(node)
+    {
+        if (node.nodeType != Node.TEXT_NODE)
+            return '#' + node.id;
+        let offset = 0;
+        for (let child = node.previousSibling; child; child = child.previousSibling)
+            offset++;
+        return `(#${node.parentNode.id}, ${offset})`;
+    }
+
+    function rangeText(range)
+    {
+        if (!range)
+            return null;
+        if (range.startContainer == range.endContainer)
+            return `${nodeLabel(range.startContainer)} ${range.startOffset} to ${range.endOffset}`;
+        return `(${nodeLabel(range.startContainer)}, ${range.startOffset}) to (${nodeLabel(range.endContainer)}, ${range.endOffset})`;
+    }
+
+    function clearSelection()
+    {
+        getSelection().removeAllRanges();
+    }
+
+    function selectedText(range)
+    {
+        if (!getSelection().rangeCount)
+            return null;
+        return rangeText(getSelection().getRangeAt(0));
+    }
+
+    function setSelection(node, offset)
+    {
+        getSelection().setPosition(node, offset);
+    }
+
+    function range(node, offset)
+    {
+        let range = new Range;
+        range.setStart(node, offset);
+        return range;
+    }
+
+    shouldBe(&quot;clearSelection(); document.execCommand('FindString', null, 'in-document'); selectedText()&quot;, &quot;'(#test-content, 0) 0 to 11'&quot;);
+    shouldBe(&quot;clearSelection(); window.find('in-document'); selectedText()&quot;, &quot;'(#test-content, 0) 0 to 11'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-document', null, ['DoNotTraverseFlatTree']))&quot;, &quot;'(#test-content, 0) 0 to 11'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-document', null, []))&quot;, &quot;'(#test-content, 0) 0 to 11'&quot;);
+
+    shouldBe(&quot;clearSelection(); document.execCommand('FindString', null, 'in-shadow'); selectedText()&quot;, &quot;null&quot;);
+    shouldBe(&quot;clearSelection(); window.find('in-shadow'); selectedText()&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-shadow', null, ['DoNotTraverseFlatTree']))&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-shadow', null, []))&quot;, &quot;'(#shadow-root, 0) 0 to 9'&quot;);
+
+    shouldBe(&quot;clearSelection(); document.execCommand('FindString', null, 'unslotted'); selectedText()&quot;, &quot;null&quot;);
+    shouldBe(&quot;clearSelection(); window.find('unslotted'); selectedText()&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('unslotted', null, ['DoNotTraverseFlatTree']))&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('unslotted', null, []))&quot;, &quot;null&quot;);
+
+    shouldBe(&quot;clearSelection(); document.execCommand('FindString', null, 'slotted'); selectedText()&quot;, &quot;'(#slotted-element, 0) 0 to 7'&quot;);
+    shouldBe(&quot;clearSelection(); window.find('slotted'); selectedText()&quot;, &quot;'(#slotted-element, 0) 0 to 7'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('slotted', null, ['DoNotTraverseFlatTree']))&quot;, &quot;'(#slotted-element, 0) 0 to 7'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('slotted', null, []))&quot;, &quot;'(#slotted-element, 0) 0 to 7'&quot;);
+
+    shouldBe(&quot;clearSelection(); document.execCommand('FindString', null, 'slotted in-document'); selectedText()&quot;, &quot;'((#slotted-element, 0), 0) to ((#test-content, 2), 12)'&quot;);
+    shouldBe(&quot;clearSelection(); window.find('slotted in-document'); selectedText()&quot;, &quot;'((#slotted-element, 0), 0) to ((#test-content, 2), 12)'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('slotted in-document', null, ['DoNotTraverseFlatTree']))&quot;, &quot;'((#slotted-element, 0), 0) to ((#test-content, 2), 12)'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('slotted in-document', null, []))&quot;, &quot;null&quot;);
+
+    shouldBe(&quot;clearSelection(); document.execCommand('FindString', null, 'in-shadow in-document'); selectedText()&quot;, &quot;null&quot;);
+    shouldBe(&quot;clearSelection(); window.find('in-shadow in-document'); selectedText()&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-shadow in-document', null, ['DoNotTraverseFlatTree']))&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-shadow in-document', null, []))&quot;, &quot;null /* Can't return a range across shadow boundary */&quot;);
+
+    shouldBe(&quot;setSelection(testContent, 1); document.execCommand('FindString', null, 'in-document'); selectedText()&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+    shouldBe(&quot;setSelection(testContent, 1); window.find('in-document'); selectedText()&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-document', range(testContent, 1), ['DoNotTraverseFlatTree']))&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-document', range(testContent, 1), []))&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+
+    shouldBe(&quot;setSelection(shadowRoot, 0); document.execCommand('FindString', null, 'in-document'); selectedText()&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+    shouldBe(&quot;setSelection(shadowRoot, 0); window.find('in-document'); selectedText()&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-document', range(shadowRoot, 0), ['DoNotTraverseFlatTree']))&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-document', range(shadowRoot, 0), []))&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+
+    shouldBe(&quot;setSelection(shadowRoot, 0); document.execCommand('FindString', null, 'in-shadow'); selectedText()&quot;, &quot;'#test-content 1 to 1'&quot;);
+    shouldBe(&quot;setSelection(shadowRoot, 0); window.find('in-shadow'); selectedText()&quot;, &quot;'#test-content 1 to 1'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 0), ['DoNotTraverseFlatTree']))&quot;, &quot;'(#shadow-root, 0) 0 to 9'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 0), []))&quot;, &quot;'(#shadow-root, 0) 0 to 9'&quot;);
+
+    shouldBe(&quot;setSelection(shadowRoot, 0); document.execCommand('FindString', null, 'slotted'); selectedText()&quot;, &quot;'(#slotted-element, 0) 0 to 7' /* Wrapped around */&quot;);
+    shouldBe(&quot;setSelection(shadowRoot, 0); window.find('slotted'); selectedText()&quot;, &quot;'#test-content 1 to 1'&quot;);
+    shouldBe(&quot;setSelection(shadowRoot, 0); window.find('slotted', /* caseSensitive */ true, /* backwards */ false, /* wrap */ true); selectedText()&quot;, &quot;'(#slotted-element, 0) 0 to 7'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('slotted', range(shadowRoot, 0), ['DoNotTraverseFlatTree']))&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('slotted', range(shadowRoot, 0), []))&quot;, &quot;'(#slotted-element, 0) 0 to 7'&quot;);
+
+    shouldBe(&quot;setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'slotted'); selectedText()&quot;, &quot;'(#slotted-element, 0) 0 to 7' /* Wrapped around */&quot;);
+    shouldBe(&quot;setSelection(shadowRoot, 1); window.find('slotted'); selectedText()&quot;, &quot;'#test-content 1 to 1'&quot;);
+    shouldBe(&quot;setSelection(shadowRoot, 1); window.find('slotted', /* caseSensitive */ true, /* backwards */ false, /* wrap */ true); selectedText()&quot;, &quot;'(#slotted-element, 0) 0 to 7'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('slotted', range(shadowRoot, 1), ['DoNotTraverseFlatTree']))&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('slotted', range(shadowRoot, 1), []))&quot;, &quot;'(#slotted-element, 0) 0 to 7'&quot;);
+
+    shouldBe(&quot;setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'in-shadow'); selectedText()&quot;, &quot;'#test-content 1 to 1'&quot;);
+    shouldBe(&quot;setSelection(shadowRoot, 1); window.find('in-shadow'); selectedText()&quot;, &quot;'#test-content 1 to 1'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 1), ['DoNotTraverseFlatTree']))&quot;, &quot;'(#shadow-root, 2) 1 to 10'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 1), []))&quot;, &quot;'(#shadow-root, 2) 1 to 10'&quot;);
+
+    shouldBe(&quot;setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'in-document'); selectedText()&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+    shouldBe(&quot;setSelection(shadowRoot, 1); window.find('in-document'); selectedText()&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-document', range(shadowRoot, 1), ['DoNotTraverseFlatTree']))&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-document', range(shadowRoot, 1), []))&quot;, &quot;'(#test-content, 2) 1 to 12'&quot;);
+
+    shouldBe(&quot;setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'in-slot'); selectedText()&quot;, &quot;'#test-content 1 to 1'&quot;);
+    shouldBe(&quot;setSelection(shadowRoot, 1); window.find('in-slot'); selectedText()&quot;, &quot;'#test-content 1 to 1'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-slot', range(shadowRoot, 1), ['DoNotTraverseFlatTree']))&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-slot', range(shadowRoot, 1), []))&quot;, &quot;null&quot;);
+
+    shouldBe(&quot;clearSelection(); document.execCommand('FindString', null, 'in-user-agent-shadow'); selectedText()&quot;, &quot;null&quot;);
+    shouldBe(&quot;clearSelection(); window.find('in-user-agent-shadow'); selectedText()&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-user-agent-shadow', null, ['DoNotTraverseFlatTree']))&quot;, &quot;null&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-user-agent-shadow', null, []))&quot;, &quot;null&quot;);
+
+    shouldBe(&quot;setSelection(userAgentShadowRoot, 0); document.execCommand('FindString', null, 'in-user-agent-shadow'); selectedText()&quot;, &quot;'#test-content 3 to 3'&quot;);
+    shouldBe(&quot;setSelection(userAgentShadowRoot, 0); window.find('in-user-agent-shadow'); selectedText()&quot;, &quot;'#test-content 3 to 3'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-user-agent-shadow', range(userAgentShadowRoot, 0), ['DoNotTraverseFlatTree']))&quot;, &quot;'(#user-agent-shadow-root, 0) 0 to 20'&quot;);
+    shouldBe(&quot;rangeText(internals.rangeOfString('in-user-agent-shadow', range(userAgentShadowRoot, 0), []))&quot;, &quot;'(#user-agent-shadow-root, 0) 0 to 20'&quot;);
+
+    shouldBe(&quot;clearSelection(); internals.countFindMatches('in-document', ['DoNotTraverseFlatTree'])&quot;, &quot;2&quot;);
+    shouldBe(&quot;internals.countFindMatches('in-document', [])&quot;, &quot;2&quot;);
+
+    shouldBe(&quot;internals.countFindMatches('in-shadow', ['DoNotTraverseFlatTree'])&quot;, &quot;0&quot;);
+    shouldBe(&quot;internals.countFindMatches('in-shadow', [])&quot;, &quot;2&quot;);
+
+    shouldBe(&quot;internals.countFindMatches('in-', ['DoNotTraverseFlatTree'])&quot;, &quot;2&quot;);
+    shouldBe(&quot;internals.countFindMatches('in-', [])&quot;, &quot;4&quot;);
+
+    shouldBe(&quot;internals.countFindMatches('in-shadow in-document', ['DoNotTraverseFlatTree'])&quot;, &quot;0&quot;);
+    shouldBe(&quot;internals.countFindMatches('in-shadow in-document', [])&quot;, &quot;0&quot;);
+
+    document.getElementById('console').style.display = null;
+}
+
+&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfasttextmarkmatchesbrokenlinerenderinghtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/text/mark-matches-broken-line-rendering.html (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/mark-matches-broken-line-rendering.html        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/fast/text/mark-matches-broken-line-rendering.html        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -11,6 +11,6 @@
</span><span class="cx"> &lt;script&gt;
</span><span class="cx"> if (window.internals) {
</span><span class="cx">     internals.setMarkedTextMatchesAreHighlighted(true);
</span><del>-    internals.countMatchesForText(&quot;Quo usque tandem abutere, Catilina, patientia nostra?&quot;, 0, &quot;mark&quot;);
</del><ins>+    internals.countMatchesForText(&quot;Quo usque tandem abutere, Catilina, patientia nostra?&quot;, [], &quot;mark&quot;);
</ins><span class="cx"> }
</span><span class="cx"> &lt;/script&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsfasttextmarkmatchesoverflowcliphtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/text/mark-matches-overflow-clip.html (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/mark-matches-overflow-clip.html        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/fast/text/mark-matches-overflow-clip.html        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -17,7 +17,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     testRunner.dumpAsText();
</span><del>-    internals.countMatchesForText(&quot;tandem&quot;, 0, &quot;mark&quot;);
</del><ins>+    internals.countMatchesForText(&quot;tandem&quot;, [], &quot;mark&quot;);
</ins><span class="cx">     
</span><span class="cx">     var markedNode = document.getElementsByTagName(&quot;span&quot;)[0].firstChild;
</span><span class="cx">     document.write(internals.dumpMarkerRects(&quot;TextMatch&quot;));
</span></span></pre></div>
<a id="trunkLayoutTestsfasttextmarkmatchesrenderingsimplelinesexpectedhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/text/mark-matches-rendering-simple-lines-expected.html (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/mark-matches-rendering-simple-lines-expected.html        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/fast/text/mark-matches-rendering-simple-lines-expected.html        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -8,6 +8,6 @@
</span><span class="cx"> &lt;script&gt;
</span><span class="cx"> if (window.internals) {
</span><span class="cx">     internals.setMarkedTextMatchesAreHighlighted(true);
</span><del>-    internals.countMatchesForText(&quot;ti&quot;, 0, &quot;mark&quot;);
</del><ins>+    internals.countMatchesForText(&quot;ti&quot;, [], &quot;mark&quot;);
</ins><span class="cx"> }
</span><span class="cx"> &lt;/script&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsfasttextmarkmatchesrenderingsimplelineshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/text/mark-matches-rendering-simple-lines.html (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/mark-matches-rendering-simple-lines.html        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/fast/text/mark-matches-rendering-simple-lines.html        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -4,6 +4,6 @@
</span><span class="cx"> &lt;script&gt;
</span><span class="cx"> if (window.internals) {
</span><span class="cx">     internals.setMarkedTextMatchesAreHighlighted(true);
</span><del>-    internals.countMatchesForText(&quot;ti&quot;, 0, &quot;mark&quot;);
</del><ins>+    internals.countMatchesForText(&quot;ti&quot;, [], &quot;mark&quot;);
</ins><span class="cx"> }
</span><span class="cx"> &lt;/script&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsfasttextmarkmatchesrenderinghtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/text/mark-matches-rendering.html (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/mark-matches-rendering.html        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/fast/text/mark-matches-rendering.html        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -4,6 +4,6 @@
</span><span class="cx"> &lt;script&gt;
</span><span class="cx"> if (window.internals) {
</span><span class="cx">     internals.setMarkedTextMatchesAreHighlighted(true);
</span><del>-    internals.countMatchesForText(&quot;Quo usque tandem abutere, Catilina, patientia nostra?&quot;, 0, &quot;mark&quot;);
</del><ins>+    internals.countMatchesForText(&quot;Quo usque tandem abutere, Catilina, patientia nostra?&quot;, [], &quot;mark&quot;);
</ins><span class="cx"> }
</span><span class="cx"> &lt;/script&gt;
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/ChangeLog        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -1,3 +1,54 @@
</span><ins>+2017-01-05  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        Finding text doesn't work across shadow boundary
+        https://bugs.webkit.org/show_bug.cgi?id=158503
+
+        Reviewed by Antti Koivisto.
+
+        Added a new TextIterator behavior flag, TextIteratorTraversesFlatTree, which makes TextIterator traverse
+        the flat tree instead of the DOM tree, and made this behavior default in findPlainText.
+
+        Also added a new find options flag, DoNotTraverseFlatTree, to suppress this behavior in window.find(~)
+        and execCommand('FindString', false, ~) as they should not be able to peek information inside shadow trees.
+        Unfortunately these APIs have been deprecated in the standards so there is no specification to follow.
+
+        For now, we don't support finding a word or a keyword across a shadow boundary as this would require
+        making rangeOfString and other related functions return a Range-like object that can cross shadow boundaries.
+
+        Also added internals.rangeOfString to test Editor::rangeOfString, and replaced the bit-flag arguments
+        to internals.countMatchesForText and internals.countFindMatches by an array of strings for better portability.
+
+        Test: editing/text-iterator/find-string-on-flat-tree.html
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::rangeOfString): Use the modern containingShadowRoot instead of nonBoundaryShadowTreeRootNode
+        since the start container can be a shadow root, which nonBoundaryShadowTreeRootNode asserts not be the case.
+        * editing/Editor.h:
+        * editing/EditorCommand.cpp:
+        (WebCore::executeFindString): Don't traverse across shadow boundaries.
+        * editing/FindOptions.h: Added DoNotTraverseFlatTree.
+        * editing/TextIterator.cpp:
+        (WebCore::assignedAuthorSlot): Added.
+        (WebCore::authorShadowRoot): Added.
+        (WebCore::firstChildInFlatTreeIgnoringUserAgentShadow): Added.
+        (WebCore::nextSiblingInFlatTreeIgnoringUserAgentShadow): Added.
+        (WebCore::firstChild): Added. Traverses the flat tree when TextIteratorTraversesFlatTree is set.
+        (WebCore::nextSibling): Ditto.
+        (WebCore::parentNodeOrShadowHost): Ditto.
+        (WebCore::TextIterator::advance): Don't set m_handledChildren to true when the current node has display: contents.
+        (WebCore::findPlainText): Use TextIteratorTraversesFlatTree unless DoNotTraverseFlatTree is set.
+        * editing/TextIteratorBehavior.h: Added TextIteratorTraversesFlatTree.
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::find): Don't traverse across shadow boundaries.
+        * testing/Internals.cpp:
+        (WebCore::parseFindOptions): Added.
+        (WebCore::Internals::rangeOfString): Added.
+        (WebCore::Internals::countMatchesForText): Replaced the find options by an array of strings instead of a bit mask.
+        (WebCore::Internals::countFindMatches): Ditto.
+        * testing/Internals.h:
+        * testing/Internals.idl: Added rangeOfString, and replaced find options bit-flag in countMatchesForText and
+        countFindMatches by an array of strings so that the tests themselves don't rely on a specific value of each bit flag.
+
</ins><span class="cx"> 2017-01-05  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Form Validation] lengthy validation messages should be truncated with an ellipsis
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingEditorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/Editor.cpp (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/Editor.cpp        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/editing/Editor.cpp        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -3132,7 +3132,7 @@
</span><span class="cx">             searchRange-&gt;setEnd(startInReferenceRange ? referenceRange-&gt;endPosition() : referenceRange-&gt;startPosition());
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    RefPtr&lt;Node&gt; shadowTreeRoot = referenceRange ? referenceRange-&gt;startContainer().nonBoundaryShadowTreeRootNode() : nullptr;
</del><ins>+    RefPtr&lt;ShadowRoot&gt; shadowTreeRoot = referenceRange ? referenceRange-&gt;startContainer().containingShadowRoot() : nullptr;
</ins><span class="cx">     if (shadowTreeRoot) {
</span><span class="cx">         if (forward)
</span><span class="cx">             searchRange-&gt;setEnd(*shadowTreeRoot, shadowTreeRoot-&gt;countChildNodes());
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingEditorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/Editor.h (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/Editor.h        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/editing/Editor.h        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -378,7 +378,7 @@
</span><span class="cx">     String selectedTextForDataTransfer() const;
</span><span class="cx">     WEBCORE_EXPORT bool findString(const String&amp;, FindOptions);
</span><span class="cx"> 
</span><del>-    RefPtr&lt;Range&gt; rangeOfString(const String&amp;, Range*, FindOptions);
</del><ins>+    WEBCORE_EXPORT RefPtr&lt;Range&gt; rangeOfString(const String&amp;, Range*, FindOptions);
</ins><span class="cx"> 
</span><span class="cx">     const VisibleSelection&amp; mark() const; // Mark, to be used as emacs uses it.
</span><span class="cx">     void setMark(const VisibleSelection&amp;);
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingEditorCommandcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/EditorCommand.cpp (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/EditorCommand.cpp        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/editing/EditorCommand.cpp        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -377,7 +377,7 @@
</span><span class="cx"> 
</span><span class="cx"> static bool executeFindString(Frame&amp; frame, Event*, EditorCommandSource, const String&amp; value)
</span><span class="cx"> {
</span><del>-    return frame.editor().findString(value, CaseInsensitive | WrapAround);
</del><ins>+    return frame.editor().findString(value, CaseInsensitive | WrapAround | DoNotTraverseFlatTree);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static bool executeFontName(Frame&amp; frame, Event*, EditorCommandSource source, const String&amp; value)
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingFindOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/FindOptions.h (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/FindOptions.h        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/editing/FindOptions.h        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -37,9 +37,10 @@
</span><span class="cx">     WrapAround = 1 &lt;&lt; 4,
</span><span class="cx">     StartInSelection = 1 &lt;&lt; 5,
</span><span class="cx">     DoNotRevealSelection = 1 &lt;&lt; 6,
</span><del>-    AtWordEnds = 1 &lt;&lt; 7
</del><ins>+    AtWordEnds = 1 &lt;&lt; 7,
+    DoNotTraverseFlatTree = 1 &lt;&lt; 8,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-typedef unsigned char FindOptions;
</del><ins>+typedef unsigned short FindOptions;
</ins><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingTextIteratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/TextIterator.cpp (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/TextIterator.cpp        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/editing/TextIterator.cpp        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -381,6 +381,69 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static HTMLSlotElement* assignedAuthorSlot(Node&amp; node)
+{
+    auto* slot = node.assignedSlot();
+    if (!slot || slot-&gt;containingShadowRoot()-&gt;mode() == ShadowRootMode::UserAgent)
+        return nullptr;
+    return slot;
+}
+
+static ShadowRoot* authorShadowRoot(Node&amp; node)
+{
+    auto* shadowRoot = node.shadowRoot();
+    if (!shadowRoot || shadowRoot-&gt;mode() == ShadowRootMode::UserAgent)
+        return nullptr;
+    return shadowRoot;
+}
+
+// FIXME: Use ComposedTreeIterator instead. These functions are more expensive because they might do O(n) work.
+static inline Node* firstChildInFlatTreeIgnoringUserAgentShadow(Node&amp; node)
+{
+    if (auto* shadowRoot = authorShadowRoot(node))
+        return shadowRoot-&gt;firstChild();
+    if (is&lt;HTMLSlotElement&gt;(node)) {
+        if (auto* assignedNodes = downcast&lt;HTMLSlotElement&gt;(node).assignedNodes())
+            return assignedNodes-&gt;at(0);
+    }
+    return node.firstChild();
+}
+
+static inline Node* nextSiblingInFlatTreeIgnoringUserAgentShadow(Node&amp; node)
+{
+    if (auto* slot = assignedAuthorSlot(node)) {
+        auto* assignedNodes = slot-&gt;assignedNodes();
+        ASSERT(assignedNodes);
+        auto nodeIndex = assignedNodes-&gt;find(&amp;node);
+        ASSERT(nodeIndex != notFound);
+        if (assignedNodes-&gt;size() &gt; nodeIndex + 1)
+            return assignedNodes-&gt;at(nodeIndex + 1);
+        return nullptr;
+    }
+    return node.nextSibling();
+}
+
+static inline Node* firstChild(TextIteratorBehavior options, Node&amp; node)
+{
+    if (UNLIKELY(options &amp; TextIteratorTraversesFlatTree))
+        return firstChildInFlatTreeIgnoringUserAgentShadow(node);
+    return node.firstChild();
+}
+
+static inline Node* nextSibling(TextIteratorBehavior options, Node&amp; node)
+{
+    if (UNLIKELY(options &amp; TextIteratorTraversesFlatTree))
+        return nextSiblingInFlatTreeIgnoringUserAgentShadow(node);
+    return node.nextSibling();
+}
+
+static inline Node* parentNodeOrShadowHost(TextIteratorBehavior options, Node&amp; node)
+{
+    if (UNLIKELY(options &amp; TextIteratorTraversesFlatTree))
+        return node.parentInComposedTree();
+    return node.parentOrShadowHostNode();
+}
+
</ins><span class="cx"> void TextIterator::advance()
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!atEnd());
</span><span class="lines">@@ -430,7 +493,7 @@
</span><span class="cx">         auto* renderer = m_node-&gt;renderer();
</span><span class="cx">         if (!renderer) {
</span><span class="cx">             m_handledNode = true;
</span><del>-            m_handledChildren = true;
</del><ins>+            m_handledChildren = !((m_behavior &amp; TextIteratorTraversesFlatTree) &amp;&amp; is&lt;Element&gt;(*m_node) &amp;&amp; downcast&lt;Element&gt;(*m_node).hasDisplayContents());
</ins><span class="cx">         } else {
</span><span class="cx">             // handle current node according to its type
</span><span class="cx">             if (!m_handledNode) {
</span><span class="lines">@@ -447,13 +510,13 @@
</span><span class="cx"> 
</span><span class="cx">         // find a new current node to handle in depth-first manner,
</span><span class="cx">         // calling exitNode() as we come back thru a parent node
</span><del>-        Node* next = m_handledChildren ? nullptr : m_node-&gt;firstChild();
</del><ins>+        Node* next = m_handledChildren ? nullptr : firstChild(m_behavior, *m_node);
</ins><span class="cx">         m_offset = 0;
</span><span class="cx">         if (!next) {
</span><del>-            next = m_node-&gt;nextSibling();
</del><ins>+            next = nextSibling(m_behavior, *m_node);
</ins><span class="cx">             if (!next) {
</span><span class="cx">                 bool pastEnd = NodeTraversal::next(*m_node) == m_pastEndNode;
</span><del>-                Node* parentNode = m_node-&gt;parentOrShadowHostNode();
</del><ins>+                Node* parentNode = parentNodeOrShadowHost(m_behavior, *m_node);
</ins><span class="cx">                 while (!next &amp;&amp; parentNode) {
</span><span class="cx">                     if ((pastEnd &amp;&amp; parentNode == m_endContainer) || m_endContainer-&gt;isDescendantOf(*parentNode))
</span><span class="cx">                         return;
</span><span class="lines">@@ -461,7 +524,7 @@
</span><span class="cx">                     Node* exitedNode = m_node;
</span><span class="cx">                     m_node = parentNode;
</span><span class="cx">                     m_fullyClippedStack.pop();
</span><del>-                    parentNode = m_node-&gt;parentOrShadowHostNode();
</del><ins>+                    parentNode = parentNodeOrShadowHost(m_behavior, *m_node);
</ins><span class="cx">                     if (haveRenderer)
</span><span class="cx">                         exitNode(exitedNode);
</span><span class="cx">                     if (m_positionNode) {
</span><span class="lines">@@ -469,7 +532,7 @@
</span><span class="cx">                         m_handledChildren = true;
</span><span class="cx">                         return;
</span><span class="cx">                     }
</span><del>-                    next = m_node-&gt;nextSibling();
</del><ins>+                    next = nextSibling(m_behavior, *m_node);
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">             m_fullyClippedStack.pop();            
</span><span class="lines">@@ -2640,6 +2703,8 @@
</span><span class="cx"> 
</span><span class="cx">     bool searchForward = !(options &amp; Backwards);
</span><span class="cx">     TextIteratorBehavior iteratorOptions = TextIteratorEntersTextControls | TextIteratorClipsToFrameAncestors;
</span><ins>+    if (!(options &amp; DoNotTraverseFlatTree))
+        iteratorOptions |= TextIteratorTraversesFlatTree;
</ins><span class="cx"> 
</span><span class="cx">     CharacterIterator findIterator(range, iteratorOptions);
</span><span class="cx">     auto result = findPlainTextOffset(buffer, findIterator, searchForward);
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingTextIteratorBehaviorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/TextIteratorBehavior.h (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/TextIteratorBehavior.h        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/editing/TextIteratorBehavior.h        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -57,6 +57,8 @@
</span><span class="cx">     // Makes visiblity test take into account the visibility of the frame.
</span><span class="cx">     // FIXME: This should probably be always on unless TextIteratorIgnoresStyleVisibility is set.
</span><span class="cx">     TextIteratorClipsToFrameAncestors = 1 &lt;&lt; 8,
</span><ins>+
+    TextIteratorTraversesFlatTree = 1 &lt;&lt; 9,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> typedef unsigned short TextIteratorBehavior;
</span></span></pre></div>
<a id="trunkSourceWebCorepageDOMWindowcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/DOMWindow.cpp (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/DOMWindow.cpp        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/page/DOMWindow.cpp        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -1207,7 +1207,7 @@
</span><span class="cx"> 
</span><span class="cx">     // FIXME (13016): Support wholeWord, searchInFrames and showDialog.    
</span><span class="cx">     FindOptions options = (backwards ? Backwards : 0) | (caseSensitive ? 0 : CaseInsensitive) | (wrap ? WrapAround : 0);
</span><del>-    return m_frame-&gt;editor().findString(string, options);
</del><ins>+    return m_frame-&gt;editor().findString(string, options | DoNotTraverseFlatTree);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool DOMWindow::offscreenBuffering() const
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.cpp (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.cpp        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/testing/Internals.cpp        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -1822,23 +1822,76 @@
</span><span class="cx">     document-&gt;frame()-&gt;editor().toggleOverwriteModeEnabled();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-unsigned Internals::countMatchesForText(const String&amp; text, unsigned findOptions, const String&amp; markMatches)
</del><ins>+static ExceptionOr&lt;FindOptions&gt; parseFindOptions(const Vector&lt;String&gt;&amp; optionList)
</ins><span class="cx"> {
</span><ins>+    const struct {
+        const char* name;
+        FindOptionFlag value;
+    } flagList[] = {
+        {&quot;CaseInsensitive&quot;, CaseInsensitive},
+        {&quot;AtWordStarts&quot;, AtWordStarts},
+        {&quot;TreatMedialCapitalAsWordStart&quot;, TreatMedialCapitalAsWordStart},
+        {&quot;Backwards&quot;, Backwards},
+        {&quot;WrapAround&quot;, WrapAround},
+        {&quot;StartInSelection&quot;, StartInSelection},
+        {&quot;DoNotRevealSelection&quot;, DoNotRevealSelection},
+        {&quot;AtWordEnds&quot;, AtWordEnds},
+        {&quot;DoNotTraverseFlatTree&quot;, DoNotTraverseFlatTree},
+    };
+    FindOptions result = 0;
+    for (auto&amp; option : optionList) {
+        bool found = false;
+        for (auto&amp; flag : flagList) {
+            if (flag.name == option) {
+                result |= flag.value;
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            return Exception { SYNTAX_ERR };
+    }
+    return result;
+}
+
+ExceptionOr&lt;RefPtr&lt;Range&gt;&gt; Internals::rangeOfString(const String&amp; text, RefPtr&lt;Range&gt;&amp;&amp; referenceRange, const Vector&lt;String&gt;&amp; findOptions)
+{
</ins><span class="cx">     Document* document = contextDocument();
</span><span class="cx">     if (!document || !document-&gt;frame())
</span><del>-        return 0;
</del><ins>+        return Exception { INVALID_ACCESS_ERR };
</ins><span class="cx"> 
</span><ins>+    auto parsedOptions = parseFindOptions(findOptions);
+    if (parsedOptions.hasException())
+        return parsedOptions.releaseException();
+
+    return document-&gt;frame()-&gt;editor().rangeOfString(text, referenceRange.get(), parsedOptions.releaseReturnValue());
+}
+
+ExceptionOr&lt;unsigned&gt; Internals::countMatchesForText(const String&amp; text, const Vector&lt;String&gt;&amp; findOptions, const String&amp; markMatches)
+{
+    Document* document = contextDocument();
+    if (!document || !document-&gt;frame())
+        return Exception { INVALID_ACCESS_ERR };
+
+    auto parsedOptions = parseFindOptions(findOptions);
+    if (parsedOptions.hasException())
+        return parsedOptions.releaseException();
+
</ins><span class="cx">     bool mark = markMatches == &quot;mark&quot;;
</span><del>-    return document-&gt;frame()-&gt;editor().countMatchesForText(text, nullptr, findOptions, 1000, mark, nullptr);
</del><ins>+    return document-&gt;frame()-&gt;editor().countMatchesForText(text, nullptr, parsedOptions.releaseReturnValue(), 1000, mark, nullptr);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-unsigned Internals::countFindMatches(const String&amp; text, unsigned findOptions)
</del><ins>+ExceptionOr&lt;unsigned&gt; Internals::countFindMatches(const String&amp; text, const Vector&lt;String&gt;&amp; findOptions)
</ins><span class="cx"> {
</span><span class="cx">     Document* document = contextDocument();
</span><span class="cx">     if (!document || !document-&gt;page())
</span><del>-        return 0;
</del><ins>+        return Exception { INVALID_ACCESS_ERR };
</ins><span class="cx"> 
</span><del>-    return document-&gt;page()-&gt;countFindMatches(text, findOptions, 1000);
</del><ins>+    auto parsedOptions = parseFindOptions(findOptions);
+    if (parsedOptions.hasException())
+        return parsedOptions.releaseException();
+
+    return document-&gt;page()-&gt;countFindMatches(text, parsedOptions.releaseReturnValue(), 1000);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> unsigned Internals::numberOfLiveNodes() const
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.h (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.h        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/testing/Internals.h        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -237,8 +237,9 @@
</span><span class="cx">     bool isOverwriteModeEnabled();
</span><span class="cx">     void toggleOverwriteModeEnabled();
</span><span class="cx"> 
</span><del>-    unsigned countMatchesForText(const String&amp;, unsigned findOptions, const String&amp; markMatches);
-    unsigned countFindMatches(const String&amp;, unsigned findOptions);
</del><ins>+    ExceptionOr&lt;RefPtr&lt;Range&gt;&gt; rangeOfString(const String&amp;, RefPtr&lt;Range&gt;&amp;&amp;, const Vector&lt;String&gt;&amp; findOptions);
+    ExceptionOr&lt;unsigned&gt; countMatchesForText(const String&amp;, const Vector&lt;String&gt;&amp; findOptions, const String&amp; markMatches);
+    ExceptionOr&lt;unsigned&gt; countFindMatches(const String&amp;, const Vector&lt;String&gt;&amp; findOptions);
</ins><span class="cx"> 
</span><span class="cx">     unsigned numberOfScrollableAreas();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalsidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.idl (210431 => 210432)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.idl        2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/Source/WebCore/testing/Internals.idl        2017-01-06 03:45:16 UTC (rev 210432)
</span><span class="lines">@@ -178,9 +178,11 @@
</span><span class="cx">     void setEditingValue(HTMLInputElement inputElement, DOMString value);
</span><span class="cx">     void setAutofilled(HTMLInputElement inputElement, boolean enabled);
</span><span class="cx">     void setShowAutoFillButton(HTMLInputElement inputElement, AutoFillButtonType autoFillButtonType);
</span><del>-    unsigned long countMatchesForText(DOMString text, unsigned long findOptions, DOMString markMatches);
-    unsigned long countFindMatches(DOMString text, unsigned long findOptions);
</del><span class="cx"> 
</span><ins>+    [MayThrowException] Range? rangeOfString(DOMString text, Range? referenceRange, sequence&lt;DOMString&gt; findOptions);
+    [MayThrowException] unsigned long countMatchesForText(DOMString text, sequence&lt;DOMString&gt; findOptions, DOMString markMatches);
+    [MayThrowException] unsigned long countFindMatches(DOMString text, sequence&lt;DOMString&gt; findOptions);
+
</ins><span class="cx">     [MayThrowException] DOMString autofillFieldName(Element formControlElement);
</span><span class="cx"> 
</span><span class="cx">     [MayThrowException] void paintControlTints();
</span></span></pre>
</div>
</div>

</body>
</html>