Diff
Modified: trunk/LayoutTests/ChangeLog (210431 => 210432)
--- trunk/LayoutTests/ChangeLog 2017-01-06 03:30:50 UTC (rev 210431)
+++ trunk/LayoutTests/ChangeLog 2017-01-06 03:45:16 UTC (rev 210432)
@@ -1,3 +1,29 @@
+2017-01-05 Ryosuke Niwa <rn...@webkit.org>
+
+ 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:
+
2017-01-05 Filip Pizlo <fpi...@apple.com>
Unreviewed, teach run-_javascript_core-tests that this is a slow test.
Modified: trunk/LayoutTests/editing/text-iterator/count-mark-lineboxes-expected.txt (210431 => 210432)
--- 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)
@@ -1,8 +1,8 @@
-PASS internals.countMatchesForText('Catilina', 23, 'mark') is 3
+PASS internals.countMatchesForText('Catilina', findOptions, 'mark') is 3
PASS internals.markerCountForNode(text, 'all') is 3
-PASS internals.countMatchesForText('Roma', 23, 'mark') is 3
+PASS internals.countMatchesForText('Roma', findOptions, 'mark') is 3
PASS internals.markerCountForNode(text, 'all') is 6
-PASS internals.countMatchesForText('uid', 23, 'mark') is 2
+PASS internals.countMatchesForText('uid', findOptions, 'mark') is 2
PASS internals.markerCountForNode(text, 'all') is 8
PASS successfullyParsed is true
Modified: trunk/LayoutTests/editing/text-iterator/count-mark-lineboxes.html (210431 => 210432)
--- 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)
@@ -49,11 +49,12 @@
</p>
<script>
var text = document.getElementById('test').firstChild;
-shouldBe("internals.countMatchesForText('Catilina', 23, 'mark')", "3");
+var findOptions = ['CaseInsensitive', 'AtWordStarts', 'TreatMedialCapitalAsWordStart', 'WrapAround'];
+shouldBe("internals.countMatchesForText('Catilina', findOptions, 'mark')", "3");
shouldBe("internals.markerCountForNode(text, 'all')", "3");
-shouldBe("internals.countMatchesForText('Roma', 23, 'mark')", "3");
+shouldBe("internals.countMatchesForText('Roma', findOptions, 'mark')", "3");
shouldBe("internals.markerCountForNode(text, 'all')", "6");
-shouldBe("internals.countMatchesForText('uid', 23, 'mark')", "2");
+shouldBe("internals.countMatchesForText('uid', findOptions, 'mark')", "2");
shouldBe("internals.markerCountForNode(text, 'all')", "8");
</script>
<script src=""
Modified: trunk/LayoutTests/editing/text-iterator/count-mark-simple-lines-expected.txt (210431 => 210432)
--- 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)
@@ -1,8 +1,8 @@
-PASS internals.countMatchesForText('Catilina', 23, 'mark') is 3
+PASS internals.countMatchesForText('Catilina', findOptions, 'mark') is 3
PASS internals.markerCountForNode(text, 'all') is 3
-PASS internals.countMatchesForText('Roma', 23, 'mark') is 3
+PASS internals.countMatchesForText('Roma', findOptions, 'mark') is 3
PASS internals.markerCountForNode(text, 'all') is 6
-PASS internals.countMatchesForText('uid', 23, 'mark') is 2
+PASS internals.countMatchesForText('uid', findOptions, 'mark') is 2
PASS internals.markerCountForNode(text, 'all') is 8
PASS successfullyParsed is true
Modified: trunk/LayoutTests/editing/text-iterator/count-mark-simple-lines.html (210431 => 210432)
--- 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)
@@ -46,11 +46,12 @@
</p>
<script>
var text = document.getElementById('test').firstChild;
-shouldBe("internals.countMatchesForText('Catilina', 23, 'mark')", "3");
+var findOptions = ['CaseInsensitive', 'AtWordStarts', 'TreatMedialCapitalAsWordStart', 'WrapAround'];
+shouldBe("internals.countMatchesForText('Catilina', findOptions, 'mark')", "3");
shouldBe("internals.markerCountForNode(text, 'all')", "3");
-shouldBe("internals.countMatchesForText('Roma', 23, 'mark')", "3");
+shouldBe("internals.countMatchesForText('Roma', findOptions, 'mark')", "3");
shouldBe("internals.markerCountForNode(text, 'all')", "6");
-shouldBe("internals.countMatchesForText('uid', 23, 'mark')", "2");
+shouldBe("internals.countMatchesForText('uid', findOptions, 'mark')", "2");
shouldBe("internals.markerCountForNode(text, 'all')", "8");
</script>
<script src=""
Modified: trunk/LayoutTests/editing/text-iterator/count-matches-in-form-expected.txt (210431 => 210432)
--- 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)
@@ -1,4 +1,4 @@
-PASS internals.countMatchesForText('rule', 23, '') is 1
+PASS internals.countMatchesForText('rule', ['CaseInsensitive', 'AtWordStarts', 'TreatMedialCapitalAsWordStart', 'WrapAround'], '') is 1
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/editing/text-iterator/count-matches-in-form.html (210431 => 210432)
--- 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)
@@ -3,6 +3,6 @@
<body>
<fieldset><input value="rule"></fieldset>
<script>
-shouldBe("internals.countMatchesForText('rule', 23, '')", "1");
+shouldBe("internals.countMatchesForText('rule', ['CaseInsensitive', 'AtWordStarts', 'TreatMedialCapitalAsWordStart', 'WrapAround'], '')", "1");
</script>
<script src=""
Modified: trunk/LayoutTests/editing/text-iterator/count-matches-in-frames.html (210431 => 210432)
--- 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)
@@ -25,7 +25,7 @@
frame.contentDocument.body.innerHTML = findString;
- assert_equals(internals.countFindMatches(findString, 0, ''), shouldFindInFrame ? 2 : 1);
+ assert_equals(internals.countFindMatches(findString, [], ''), shouldFindInFrame ? 2 : 1);
}
test(function () {
Added: trunk/LayoutTests/editing/text-iterator/find-string-on-flat-tree-expected.txt (0 => 210432)
--- 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)
@@ -0,0 +1,83 @@
+This tests finding across shadow boundaries using the flat tree.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+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
Added: trunk/LayoutTests/editing/text-iterator/find-string-on-flat-tree.html (0 => 210432)
--- 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)
@@ -0,0 +1,169 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="test-content">in-document <span id="host">unslotted <b id="slotted-element" slot="named-slot">slotted</b> unslotted</span> in-document<span id="user-agent-host"></span></div>
+<script src=""
+<script>
+
+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 <slot name="named-slot">in-slot</slot> 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("clearSelection(); document.execCommand('FindString', null, 'in-document'); selectedText()", "'(#test-content, 0) 0 to 11'");
+ shouldBe("clearSelection(); window.find('in-document'); selectedText()", "'(#test-content, 0) 0 to 11'");
+ shouldBe("rangeText(internals.rangeOfString('in-document', null, ['DoNotTraverseFlatTree']))", "'(#test-content, 0) 0 to 11'");
+ shouldBe("rangeText(internals.rangeOfString('in-document', null, []))", "'(#test-content, 0) 0 to 11'");
+
+ shouldBe("clearSelection(); document.execCommand('FindString', null, 'in-shadow'); selectedText()", "null");
+ shouldBe("clearSelection(); window.find('in-shadow'); selectedText()", "null");
+ shouldBe("rangeText(internals.rangeOfString('in-shadow', null, ['DoNotTraverseFlatTree']))", "null");
+ shouldBe("rangeText(internals.rangeOfString('in-shadow', null, []))", "'(#shadow-root, 0) 0 to 9'");
+
+ shouldBe("clearSelection(); document.execCommand('FindString', null, 'unslotted'); selectedText()", "null");
+ shouldBe("clearSelection(); window.find('unslotted'); selectedText()", "null");
+ shouldBe("rangeText(internals.rangeOfString('unslotted', null, ['DoNotTraverseFlatTree']))", "null");
+ shouldBe("rangeText(internals.rangeOfString('unslotted', null, []))", "null");
+
+ shouldBe("clearSelection(); document.execCommand('FindString', null, 'slotted'); selectedText()", "'(#slotted-element, 0) 0 to 7'");
+ shouldBe("clearSelection(); window.find('slotted'); selectedText()", "'(#slotted-element, 0) 0 to 7'");
+ shouldBe("rangeText(internals.rangeOfString('slotted', null, ['DoNotTraverseFlatTree']))", "'(#slotted-element, 0) 0 to 7'");
+ shouldBe("rangeText(internals.rangeOfString('slotted', null, []))", "'(#slotted-element, 0) 0 to 7'");
+
+ shouldBe("clearSelection(); document.execCommand('FindString', null, 'slotted in-document'); selectedText()", "'((#slotted-element, 0), 0) to ((#test-content, 2), 12)'");
+ shouldBe("clearSelection(); window.find('slotted in-document'); selectedText()", "'((#slotted-element, 0), 0) to ((#test-content, 2), 12)'");
+ shouldBe("rangeText(internals.rangeOfString('slotted in-document', null, ['DoNotTraverseFlatTree']))", "'((#slotted-element, 0), 0) to ((#test-content, 2), 12)'");
+ shouldBe("rangeText(internals.rangeOfString('slotted in-document', null, []))", "null");
+
+ shouldBe("clearSelection(); document.execCommand('FindString', null, 'in-shadow in-document'); selectedText()", "null");
+ shouldBe("clearSelection(); window.find('in-shadow in-document'); selectedText()", "null");
+ shouldBe("rangeText(internals.rangeOfString('in-shadow in-document', null, ['DoNotTraverseFlatTree']))", "null");
+ shouldBe("rangeText(internals.rangeOfString('in-shadow in-document', null, []))", "null /* Can't return a range across shadow boundary */");
+
+ shouldBe("setSelection(testContent, 1); document.execCommand('FindString', null, 'in-document'); selectedText()", "'(#test-content, 2) 1 to 12'");
+ shouldBe("setSelection(testContent, 1); window.find('in-document'); selectedText()", "'(#test-content, 2) 1 to 12'");
+ shouldBe("rangeText(internals.rangeOfString('in-document', range(testContent, 1), ['DoNotTraverseFlatTree']))", "'(#test-content, 2) 1 to 12'");
+ shouldBe("rangeText(internals.rangeOfString('in-document', range(testContent, 1), []))", "'(#test-content, 2) 1 to 12'");
+
+ shouldBe("setSelection(shadowRoot, 0); document.execCommand('FindString', null, 'in-document'); selectedText()", "'(#test-content, 2) 1 to 12'");
+ shouldBe("setSelection(shadowRoot, 0); window.find('in-document'); selectedText()", "'(#test-content, 2) 1 to 12'");
+ shouldBe("rangeText(internals.rangeOfString('in-document', range(shadowRoot, 0), ['DoNotTraverseFlatTree']))", "'(#test-content, 2) 1 to 12'");
+ shouldBe("rangeText(internals.rangeOfString('in-document', range(shadowRoot, 0), []))", "'(#test-content, 2) 1 to 12'");
+
+ shouldBe("setSelection(shadowRoot, 0); document.execCommand('FindString', null, 'in-shadow'); selectedText()", "'#test-content 1 to 1'");
+ shouldBe("setSelection(shadowRoot, 0); window.find('in-shadow'); selectedText()", "'#test-content 1 to 1'");
+ shouldBe("rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 0), ['DoNotTraverseFlatTree']))", "'(#shadow-root, 0) 0 to 9'");
+ shouldBe("rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 0), []))", "'(#shadow-root, 0) 0 to 9'");
+
+ shouldBe("setSelection(shadowRoot, 0); document.execCommand('FindString', null, 'slotted'); selectedText()", "'(#slotted-element, 0) 0 to 7' /* Wrapped around */");
+ shouldBe("setSelection(shadowRoot, 0); window.find('slotted'); selectedText()", "'#test-content 1 to 1'");
+ shouldBe("setSelection(shadowRoot, 0); window.find('slotted', /* caseSensitive */ true, /* backwards */ false, /* wrap */ true); selectedText()", "'(#slotted-element, 0) 0 to 7'");
+ shouldBe("rangeText(internals.rangeOfString('slotted', range(shadowRoot, 0), ['DoNotTraverseFlatTree']))", "null");
+ shouldBe("rangeText(internals.rangeOfString('slotted', range(shadowRoot, 0), []))", "'(#slotted-element, 0) 0 to 7'");
+
+ shouldBe("setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'slotted'); selectedText()", "'(#slotted-element, 0) 0 to 7' /* Wrapped around */");
+ shouldBe("setSelection(shadowRoot, 1); window.find('slotted'); selectedText()", "'#test-content 1 to 1'");
+ shouldBe("setSelection(shadowRoot, 1); window.find('slotted', /* caseSensitive */ true, /* backwards */ false, /* wrap */ true); selectedText()", "'(#slotted-element, 0) 0 to 7'");
+ shouldBe("rangeText(internals.rangeOfString('slotted', range(shadowRoot, 1), ['DoNotTraverseFlatTree']))", "null");
+ shouldBe("rangeText(internals.rangeOfString('slotted', range(shadowRoot, 1), []))", "'(#slotted-element, 0) 0 to 7'");
+
+ shouldBe("setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'in-shadow'); selectedText()", "'#test-content 1 to 1'");
+ shouldBe("setSelection(shadowRoot, 1); window.find('in-shadow'); selectedText()", "'#test-content 1 to 1'");
+ shouldBe("rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 1), ['DoNotTraverseFlatTree']))", "'(#shadow-root, 2) 1 to 10'");
+ shouldBe("rangeText(internals.rangeOfString('in-shadow', range(shadowRoot, 1), []))", "'(#shadow-root, 2) 1 to 10'");
+
+ shouldBe("setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'in-document'); selectedText()", "'(#test-content, 2) 1 to 12'");
+ shouldBe("setSelection(shadowRoot, 1); window.find('in-document'); selectedText()", "'(#test-content, 2) 1 to 12'");
+ shouldBe("rangeText(internals.rangeOfString('in-document', range(shadowRoot, 1), ['DoNotTraverseFlatTree']))", "'(#test-content, 2) 1 to 12'");
+ shouldBe("rangeText(internals.rangeOfString('in-document', range(shadowRoot, 1), []))", "'(#test-content, 2) 1 to 12'");
+
+ shouldBe("setSelection(shadowRoot, 1); document.execCommand('FindString', null, 'in-slot'); selectedText()", "'#test-content 1 to 1'");
+ shouldBe("setSelection(shadowRoot, 1); window.find('in-slot'); selectedText()", "'#test-content 1 to 1'");
+ shouldBe("rangeText(internals.rangeOfString('in-slot', range(shadowRoot, 1), ['DoNotTraverseFlatTree']))", "null");
+ shouldBe("rangeText(internals.rangeOfString('in-slot', range(shadowRoot, 1), []))", "null");
+
+ shouldBe("clearSelection(); document.execCommand('FindString', null, 'in-user-agent-shadow'); selectedText()", "null");
+ shouldBe("clearSelection(); window.find('in-user-agent-shadow'); selectedText()", "null");
+ shouldBe("rangeText(internals.rangeOfString('in-user-agent-shadow', null, ['DoNotTraverseFlatTree']))", "null");
+ shouldBe("rangeText(internals.rangeOfString('in-user-agent-shadow', null, []))", "null");
+
+ shouldBe("setSelection(userAgentShadowRoot, 0); document.execCommand('FindString', null, 'in-user-agent-shadow'); selectedText()", "'#test-content 3 to 3'");
+ shouldBe("setSelection(userAgentShadowRoot, 0); window.find('in-user-agent-shadow'); selectedText()", "'#test-content 3 to 3'");
+ shouldBe("rangeText(internals.rangeOfString('in-user-agent-shadow', range(userAgentShadowRoot, 0), ['DoNotTraverseFlatTree']))", "'(#user-agent-shadow-root, 0) 0 to 20'");
+ shouldBe("rangeText(internals.rangeOfString('in-user-agent-shadow', range(userAgentShadowRoot, 0), []))", "'(#user-agent-shadow-root, 0) 0 to 20'");
+
+ shouldBe("clearSelection(); internals.countFindMatches('in-document', ['DoNotTraverseFlatTree'])", "2");
+ shouldBe("internals.countFindMatches('in-document', [])", "2");
+
+ shouldBe("internals.countFindMatches('in-shadow', ['DoNotTraverseFlatTree'])", "0");
+ shouldBe("internals.countFindMatches('in-shadow', [])", "2");
+
+ shouldBe("internals.countFindMatches('in-', ['DoNotTraverseFlatTree'])", "2");
+ shouldBe("internals.countFindMatches('in-', [])", "4");
+
+ shouldBe("internals.countFindMatches('in-shadow in-document', ['DoNotTraverseFlatTree'])", "0");
+ shouldBe("internals.countFindMatches('in-shadow in-document', [])", "0");
+
+ document.getElementById('console').style.display = null;
+}
+
+</script>
+</body>
+</html>
Modified: trunk/LayoutTests/fast/text/mark-matches-broken-line-rendering.html (210431 => 210432)
--- 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)
@@ -11,6 +11,6 @@
<script>
if (window.internals) {
internals.setMarkedTextMatchesAreHighlighted(true);
- internals.countMatchesForText("Quo usque tandem abutere, Catilina, patientia nostra?", 0, "mark");
+ internals.countMatchesForText("Quo usque tandem abutere, Catilina, patientia nostra?", [], "mark");
}
</script>
Modified: trunk/LayoutTests/fast/text/mark-matches-overflow-clip.html (210431 => 210432)
--- 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)
@@ -17,7 +17,7 @@
}
testRunner.dumpAsText();
- internals.countMatchesForText("tandem", 0, "mark");
+ internals.countMatchesForText("tandem", [], "mark");
var markedNode = document.getElementsByTagName("span")[0].firstChild;
document.write(internals.dumpMarkerRects("TextMatch"));
Modified: trunk/LayoutTests/fast/text/mark-matches-rendering-simple-lines-expected.html (210431 => 210432)
--- 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)
@@ -8,6 +8,6 @@
<script>
if (window.internals) {
internals.setMarkedTextMatchesAreHighlighted(true);
- internals.countMatchesForText("ti", 0, "mark");
+ internals.countMatchesForText("ti", [], "mark");
}
</script>
Modified: trunk/LayoutTests/fast/text/mark-matches-rendering-simple-lines.html (210431 => 210432)
--- 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)
@@ -4,6 +4,6 @@
<script>
if (window.internals) {
internals.setMarkedTextMatchesAreHighlighted(true);
- internals.countMatchesForText("ti", 0, "mark");
+ internals.countMatchesForText("ti", [], "mark");
}
</script>
Modified: trunk/LayoutTests/fast/text/mark-matches-rendering.html (210431 => 210432)
--- 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)
@@ -4,6 +4,6 @@
<script>
if (window.internals) {
internals.setMarkedTextMatchesAreHighlighted(true);
- internals.countMatchesForText("Quo usque tandem abutere, Catilina, patientia nostra?", 0, "mark");
+ internals.countMatchesForText("Quo usque tandem abutere, Catilina, patientia nostra?", [], "mark");
}
</script>
Modified: trunk/Source/WebCore/ChangeLog (210431 => 210432)
--- 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)
@@ -1,3 +1,54 @@
+2017-01-05 Ryosuke Niwa <rn...@webkit.org>
+
+ 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.
+
2017-01-05 Chris Dumez <cdu...@apple.com>
[Form Validation] lengthy validation messages should be truncated with an ellipsis
Modified: trunk/Source/WebCore/editing/Editor.cpp (210431 => 210432)
--- 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)
@@ -3132,7 +3132,7 @@
searchRange->setEnd(startInReferenceRange ? referenceRange->endPosition() : referenceRange->startPosition());
}
- RefPtr<Node> shadowTreeRoot = referenceRange ? referenceRange->startContainer().nonBoundaryShadowTreeRootNode() : nullptr;
+ RefPtr<ShadowRoot> shadowTreeRoot = referenceRange ? referenceRange->startContainer().containingShadowRoot() : nullptr;
if (shadowTreeRoot) {
if (forward)
searchRange->setEnd(*shadowTreeRoot, shadowTreeRoot->countChildNodes());
Modified: trunk/Source/WebCore/editing/Editor.h (210431 => 210432)
--- 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)
@@ -378,7 +378,7 @@
String selectedTextForDataTransfer() const;
WEBCORE_EXPORT bool findString(const String&, FindOptions);
- RefPtr<Range> rangeOfString(const String&, Range*, FindOptions);
+ WEBCORE_EXPORT RefPtr<Range> rangeOfString(const String&, Range*, FindOptions);
const VisibleSelection& mark() const; // Mark, to be used as emacs uses it.
void setMark(const VisibleSelection&);
Modified: trunk/Source/WebCore/editing/EditorCommand.cpp (210431 => 210432)
--- 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)
@@ -377,7 +377,7 @@
static bool executeFindString(Frame& frame, Event*, EditorCommandSource, const String& value)
{
- return frame.editor().findString(value, CaseInsensitive | WrapAround);
+ return frame.editor().findString(value, CaseInsensitive | WrapAround | DoNotTraverseFlatTree);
}
static bool executeFontName(Frame& frame, Event*, EditorCommandSource source, const String& value)
Modified: trunk/Source/WebCore/editing/FindOptions.h (210431 => 210432)
--- 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)
@@ -37,9 +37,10 @@
WrapAround = 1 << 4,
StartInSelection = 1 << 5,
DoNotRevealSelection = 1 << 6,
- AtWordEnds = 1 << 7
+ AtWordEnds = 1 << 7,
+ DoNotTraverseFlatTree = 1 << 8,
};
-typedef unsigned char FindOptions;
+typedef unsigned short FindOptions;
} // namespace WebCore
Modified: trunk/Source/WebCore/editing/TextIterator.cpp (210431 => 210432)
--- 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)
@@ -381,6 +381,69 @@
{
}
+static HTMLSlotElement* assignedAuthorSlot(Node& node)
+{
+ auto* slot = node.assignedSlot();
+ if (!slot || slot->containingShadowRoot()->mode() == ShadowRootMode::UserAgent)
+ return nullptr;
+ return slot;
+}
+
+static ShadowRoot* authorShadowRoot(Node& node)
+{
+ auto* shadowRoot = node.shadowRoot();
+ if (!shadowRoot || shadowRoot->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& node)
+{
+ if (auto* shadowRoot = authorShadowRoot(node))
+ return shadowRoot->firstChild();
+ if (is<HTMLSlotElement>(node)) {
+ if (auto* assignedNodes = downcast<HTMLSlotElement>(node).assignedNodes())
+ return assignedNodes->at(0);
+ }
+ return node.firstChild();
+}
+
+static inline Node* nextSiblingInFlatTreeIgnoringUserAgentShadow(Node& node)
+{
+ if (auto* slot = assignedAuthorSlot(node)) {
+ auto* assignedNodes = slot->assignedNodes();
+ ASSERT(assignedNodes);
+ auto nodeIndex = assignedNodes->find(&node);
+ ASSERT(nodeIndex != notFound);
+ if (assignedNodes->size() > nodeIndex + 1)
+ return assignedNodes->at(nodeIndex + 1);
+ return nullptr;
+ }
+ return node.nextSibling();
+}
+
+static inline Node* firstChild(TextIteratorBehavior options, Node& node)
+{
+ if (UNLIKELY(options & TextIteratorTraversesFlatTree))
+ return firstChildInFlatTreeIgnoringUserAgentShadow(node);
+ return node.firstChild();
+}
+
+static inline Node* nextSibling(TextIteratorBehavior options, Node& node)
+{
+ if (UNLIKELY(options & TextIteratorTraversesFlatTree))
+ return nextSiblingInFlatTreeIgnoringUserAgentShadow(node);
+ return node.nextSibling();
+}
+
+static inline Node* parentNodeOrShadowHost(TextIteratorBehavior options, Node& node)
+{
+ if (UNLIKELY(options & TextIteratorTraversesFlatTree))
+ return node.parentInComposedTree();
+ return node.parentOrShadowHostNode();
+}
+
void TextIterator::advance()
{
ASSERT(!atEnd());
@@ -430,7 +493,7 @@
auto* renderer = m_node->renderer();
if (!renderer) {
m_handledNode = true;
- m_handledChildren = true;
+ m_handledChildren = !((m_behavior & TextIteratorTraversesFlatTree) && is<Element>(*m_node) && downcast<Element>(*m_node).hasDisplayContents());
} else {
// handle current node according to its type
if (!m_handledNode) {
@@ -447,13 +510,13 @@
// find a new current node to handle in depth-first manner,
// calling exitNode() as we come back thru a parent node
- Node* next = m_handledChildren ? nullptr : m_node->firstChild();
+ Node* next = m_handledChildren ? nullptr : firstChild(m_behavior, *m_node);
m_offset = 0;
if (!next) {
- next = m_node->nextSibling();
+ next = nextSibling(m_behavior, *m_node);
if (!next) {
bool pastEnd = NodeTraversal::next(*m_node) == m_pastEndNode;
- Node* parentNode = m_node->parentOrShadowHostNode();
+ Node* parentNode = parentNodeOrShadowHost(m_behavior, *m_node);
while (!next && parentNode) {
if ((pastEnd && parentNode == m_endContainer) || m_endContainer->isDescendantOf(*parentNode))
return;
@@ -461,7 +524,7 @@
Node* exitedNode = m_node;
m_node = parentNode;
m_fullyClippedStack.pop();
- parentNode = m_node->parentOrShadowHostNode();
+ parentNode = parentNodeOrShadowHost(m_behavior, *m_node);
if (haveRenderer)
exitNode(exitedNode);
if (m_positionNode) {
@@ -469,7 +532,7 @@
m_handledChildren = true;
return;
}
- next = m_node->nextSibling();
+ next = nextSibling(m_behavior, *m_node);
}
}
m_fullyClippedStack.pop();
@@ -2640,6 +2703,8 @@
bool searchForward = !(options & Backwards);
TextIteratorBehavior iteratorOptions = TextIteratorEntersTextControls | TextIteratorClipsToFrameAncestors;
+ if (!(options & DoNotTraverseFlatTree))
+ iteratorOptions |= TextIteratorTraversesFlatTree;
CharacterIterator findIterator(range, iteratorOptions);
auto result = findPlainTextOffset(buffer, findIterator, searchForward);
Modified: trunk/Source/WebCore/editing/TextIteratorBehavior.h (210431 => 210432)
--- 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)
@@ -57,6 +57,8 @@
// Makes visiblity test take into account the visibility of the frame.
// FIXME: This should probably be always on unless TextIteratorIgnoresStyleVisibility is set.
TextIteratorClipsToFrameAncestors = 1 << 8,
+
+ TextIteratorTraversesFlatTree = 1 << 9,
};
typedef unsigned short TextIteratorBehavior;
Modified: trunk/Source/WebCore/page/DOMWindow.cpp (210431 => 210432)
--- 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)
@@ -1207,7 +1207,7 @@
// FIXME (13016): Support wholeWord, searchInFrames and showDialog.
FindOptions options = (backwards ? Backwards : 0) | (caseSensitive ? 0 : CaseInsensitive) | (wrap ? WrapAround : 0);
- return m_frame->editor().findString(string, options);
+ return m_frame->editor().findString(string, options | DoNotTraverseFlatTree);
}
bool DOMWindow::offscreenBuffering() const
Modified: trunk/Source/WebCore/testing/Internals.cpp (210431 => 210432)
--- 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)
@@ -1822,23 +1822,76 @@
document->frame()->editor().toggleOverwriteModeEnabled();
}
-unsigned Internals::countMatchesForText(const String& text, unsigned findOptions, const String& markMatches)
+static ExceptionOr<FindOptions> parseFindOptions(const Vector<String>& optionList)
{
+ const struct {
+ const char* name;
+ FindOptionFlag value;
+ } flagList[] = {
+ {"CaseInsensitive", CaseInsensitive},
+ {"AtWordStarts", AtWordStarts},
+ {"TreatMedialCapitalAsWordStart", TreatMedialCapitalAsWordStart},
+ {"Backwards", Backwards},
+ {"WrapAround", WrapAround},
+ {"StartInSelection", StartInSelection},
+ {"DoNotRevealSelection", DoNotRevealSelection},
+ {"AtWordEnds", AtWordEnds},
+ {"DoNotTraverseFlatTree", DoNotTraverseFlatTree},
+ };
+ FindOptions result = 0;
+ for (auto& option : optionList) {
+ bool found = false;
+ for (auto& flag : flagList) {
+ if (flag.name == option) {
+ result |= flag.value;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return Exception { SYNTAX_ERR };
+ }
+ return result;
+}
+
+ExceptionOr<RefPtr<Range>> Internals::rangeOfString(const String& text, RefPtr<Range>&& referenceRange, const Vector<String>& findOptions)
+{
Document* document = contextDocument();
if (!document || !document->frame())
- return 0;
+ return Exception { INVALID_ACCESS_ERR };
+ auto parsedOptions = parseFindOptions(findOptions);
+ if (parsedOptions.hasException())
+ return parsedOptions.releaseException();
+
+ return document->frame()->editor().rangeOfString(text, referenceRange.get(), parsedOptions.releaseReturnValue());
+}
+
+ExceptionOr<unsigned> Internals::countMatchesForText(const String& text, const Vector<String>& findOptions, const String& markMatches)
+{
+ Document* document = contextDocument();
+ if (!document || !document->frame())
+ return Exception { INVALID_ACCESS_ERR };
+
+ auto parsedOptions = parseFindOptions(findOptions);
+ if (parsedOptions.hasException())
+ return parsedOptions.releaseException();
+
bool mark = markMatches == "mark";
- return document->frame()->editor().countMatchesForText(text, nullptr, findOptions, 1000, mark, nullptr);
+ return document->frame()->editor().countMatchesForText(text, nullptr, parsedOptions.releaseReturnValue(), 1000, mark, nullptr);
}
-unsigned Internals::countFindMatches(const String& text, unsigned findOptions)
+ExceptionOr<unsigned> Internals::countFindMatches(const String& text, const Vector<String>& findOptions)
{
Document* document = contextDocument();
if (!document || !document->page())
- return 0;
+ return Exception { INVALID_ACCESS_ERR };
- return document->page()->countFindMatches(text, findOptions, 1000);
+ auto parsedOptions = parseFindOptions(findOptions);
+ if (parsedOptions.hasException())
+ return parsedOptions.releaseException();
+
+ return document->page()->countFindMatches(text, parsedOptions.releaseReturnValue(), 1000);
}
unsigned Internals::numberOfLiveNodes() const
Modified: trunk/Source/WebCore/testing/Internals.h (210431 => 210432)
--- 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)
@@ -237,8 +237,9 @@
bool isOverwriteModeEnabled();
void toggleOverwriteModeEnabled();
- unsigned countMatchesForText(const String&, unsigned findOptions, const String& markMatches);
- unsigned countFindMatches(const String&, unsigned findOptions);
+ ExceptionOr<RefPtr<Range>> rangeOfString(const String&, RefPtr<Range>&&, const Vector<String>& findOptions);
+ ExceptionOr<unsigned> countMatchesForText(const String&, const Vector<String>& findOptions, const String& markMatches);
+ ExceptionOr<unsigned> countFindMatches(const String&, const Vector<String>& findOptions);
unsigned numberOfScrollableAreas();
Modified: trunk/Source/WebCore/testing/Internals.idl (210431 => 210432)
--- 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)
@@ -178,9 +178,11 @@
void setEditingValue(HTMLInputElement inputElement, DOMString value);
void setAutofilled(HTMLInputElement inputElement, boolean enabled);
void setShowAutoFillButton(HTMLInputElement inputElement, AutoFillButtonType autoFillButtonType);
- unsigned long countMatchesForText(DOMString text, unsigned long findOptions, DOMString markMatches);
- unsigned long countFindMatches(DOMString text, unsigned long findOptions);
+ [MayThrowException] Range? rangeOfString(DOMString text, Range? referenceRange, sequence<DOMString> findOptions);
+ [MayThrowException] unsigned long countMatchesForText(DOMString text, sequence<DOMString> findOptions, DOMString markMatches);
+ [MayThrowException] unsigned long countFindMatches(DOMString text, sequence<DOMString> findOptions);
+
[MayThrowException] DOMString autofillFieldName(Element formControlElement);
[MayThrowException] void paintControlTints();