Diff
Modified: trunk/LayoutTests/ChangeLog (236784 => 236785)
--- trunk/LayoutTests/ChangeLog 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/LayoutTests/ChangeLog 2018-10-03 06:28:07 UTC (rev 236785)
@@ -1,3 +1,27 @@
+2018-10-02 Ryosuke Niwa <rn...@webkit.org>
+
+ Copying content with shadow DOM doesn't copy any contents
+ https://bugs.webkit.org/show_bug.cgi?id=157443
+
+ Reviewed by Wenson Hsieh.
+
+ Added tests for copying and pasting across shadow boundaries with HTML and plain text.
+
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-1-expected.txt: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-1.html: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-2-expected.txt: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-2.html: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-3-expected.txt: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-3.html: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-4-expected.txt: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-4.html: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1-expected.txt: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1.html: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-2-expected.txt: Added.
+ * editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-2.html: Added.
+ * editing/pasteboard/copy-paste-with-shadow-content-expected.txt: Added.
+ * editing/pasteboard/copy-paste-with-shadow-content.html: Added.
+
2018-10-01 Ryosuke Niwa <rn...@webkit.org>
GC can collect JS wrappers of nodes in the mutation records waiting to be delivered
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-1-expected.txt (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-1-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-1-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,14 @@
+This tests copying and pasting content across shadow boundaries.
+To test manually, copy text blow starting from "hello" ending with "Web", and paste into the green box below. All the text shoul be copied & pasted.
+
+pasted html:
+| "hello "
+| <span>
+| id="host"
+| <span>
+| style="display: contents;"
+| "world"
+| " Web<#selection-caret>"
+
+text/plain:
+| "hello world Web"
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-1.html (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-1.html (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-1.html 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,39 @@
+<!DOCTYPE html><!-- webkit-test-runner [ internal:selectionAcrossShadowBoundariesEnabled=true ] -->
+<html>
+<body>
+<p id="description">This tests copying and pasting content across shadow boundaries.<br>
+To test manually, copy text blow starting from "hello" ending with "Web", and paste into the green box below. All the text shoul be copied & pasted.</p>
+<style> .box { border: solid 1px; padding: 0.2rem; margin-bottom: 1rem; } </style>
+<div id="source" class="box" style="border-color: blue">hello <span id="host">world</span> rocks</div>
+<div id="destination" class="box" style="border-color: blue" contenteditable></div>
+<pre id="htmlResult"></pre>
+<pre id="textResult"></pre>
+<script src=""
+<script>
+
+Markup.description(description.textContent);
+Markup.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'open'});
+shadowRoot.innerHTML = '<slot></slot> WebKit';
+
+destination.addEventListener('paste', (event) => {
+ htmlResult.textContent = event.clipboardData.getData('text/html');
+ textResult.textContent = event.clipboardData.getData('text/plain');
+ setTimeout(() => {
+ Markup.dump(destination, 'pasted html');
+ Markup.dump(textResult, 'text/plain');
+ Markup.notifyDone();
+ }, 0);
+});
+
+if (window.testRunner) {
+ internals.setSelectionWithoutValidation(source, 0, shadowRoot.lastChild, shadowRoot.lastChild.data.indexOf('Kit'));
+ document.execCommand('copy');
+ destination.focus();
+ document.execCommand('paste');
+}
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-2-expected.txt (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-2-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-2-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,15 @@
+This tests copying and pasting content across shadow boundaries.
+To test manually, copy text blow starting from "world" ending with "rocks", and paste into the green box below. All the text shoul be copied & pasted.
+
+pasted html:
+| <span>
+| id="host"
+| <span>
+| style="display: contents;"
+| "world"
+| " "
+| "WebKit"
+| " rocks<#selection-caret>"
+
+text/plain:
+| "world WebKit rocks"
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-2.html (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-2.html (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-2.html 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,39 @@
+<!DOCTYPE html><!-- webkit-test-runner [ internal:selectionAcrossShadowBoundariesEnabled=true ] -->
+<html>
+<body>
+<p id="description">This tests copying and pasting content across shadow boundaries.<br>
+To test manually, copy text blow starting from "world" ending with "rocks", and paste into the green box below. All the text shoul be copied & pasted.</p>
+<style> .box { border: solid 1px; padding: 0.2rem; margin-bottom: 1rem; } </style>
+<div id="source" class="box" style="border-color: blue">hello <span id="host">world</span> rocks</div>
+<div id="destination" class="box" style="border-color: blue" contenteditable></div>
+<pre id="htmlResult"></pre>
+<pre id="textResult"></pre>
+<script src=""
+<script>
+
+Markup.description(description.textContent);
+Markup.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'open'});
+shadowRoot.innerHTML = '<slot></slot> WebKit';
+
+destination.addEventListener('paste', (event) => {
+ htmlResult.textContent = event.clipboardData.getData('text/html');
+ textResult.textContent = event.clipboardData.getData('text/plain');
+ setTimeout(() => {
+ Markup.dump(destination, 'pasted html');
+ Markup.dump(textResult, 'text/plain');
+ Markup.notifyDone();
+ }, 0);
+});
+
+if (window.testRunner) {
+ internals.setSelectionWithoutValidation(host.firstChild, 0, source.lastChild, source.lastChild.data.length);
+ document.execCommand('copy');
+ destination.focus();
+ document.execCommand('paste');
+}
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-3-expected.txt (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-3-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-3-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,13 @@
+This tests copying and pasting content across shadow boundaries.
+To test manually, copy text blow starting from "WebKit" ending with "rocks", and paste into the green box below. All the text shoul be copied & pasted.
+
+pasted html:
+| <span>
+| id="host"
+| <span>
+| style="display: contents;"
+| "world WebKit"
+| " rocks<#selection-caret>"
+
+text/plain:
+| "world WebKit rocks"
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-3.html (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-3.html (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-3.html 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,39 @@
+<!DOCTYPE html><!-- webkit-test-runner [ internal:selectionAcrossShadowBoundariesEnabled=true ] -->
+<html>
+<body>
+<p id="description">This tests copying and pasting content across shadow boundaries.<br>
+To test manually, copy text blow starting from "WebKit" ending with "rocks", and paste into the green box below. All the text shoul be copied & pasted.</p>
+<style> .box { border: solid 1px; padding: 0.2rem; margin-bottom: 1rem; } </style>
+<div id="source" class="box" style="border-color: blue"><span id="host">world WebKit</span> rocks</div>
+<div id="destination" class="box" style="border-color: blue" contenteditable></div>
+<pre id="htmlResult"></pre>
+<pre id="textResult"></pre>
+<script src=""
+<script>
+
+Markup.description(description.textContent);
+Markup.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'open'});
+shadowRoot.innerHTML = 'hello <slot></slot>';
+
+destination.addEventListener('paste', (event) => {
+ htmlResult.textContent = event.clipboardData.getData('text/html');
+ textResult.textContent = event.clipboardData.getData('text/plain');
+ setTimeout(() => {
+ Markup.dump(destination, 'pasted html');
+ Markup.dump(textResult, 'text/plain');
+ Markup.notifyDone();
+ }, 0);
+});
+
+if (window.testRunner) {
+ internals.setSelectionWithoutValidation(host.firstChild, 0, source.lastChild, source.lastChild.data.length);
+ document.execCommand('copy');
+ destination.focus();
+ document.execCommand('paste');
+}
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-4-expected.txt (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-4-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-4-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,11 @@
+This tests copying and pasting content across shadow boundaries.
+To test manually, copy text blow starting from "hello" ending with "Web", and paste into the green box below. All the text shoul be copied & pasted.
+
+pasted html:
+| "hello "
+| <span>
+| style="display: contents;"
+| "world Web<#selection-caret>"
+
+text/plain:
+| "hello world Web"
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-4.html (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-4.html (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-4.html 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,39 @@
+<!DOCTYPE html><!-- webkit-test-runner [ internal:selectionAcrossShadowBoundariesEnabled=true ] -->
+<html>
+<body>
+<p id="description">This tests copying and pasting content across shadow boundaries.<br>
+To test manually, copy text blow starting from "hello" ending with "Web", and paste into the green box below. All the text shoul be copied & pasted.</p>
+<style> .box { border: solid 1px; padding: 0.2rem; margin-bottom: 1rem; } </style>
+<div id="source" class="box" style="border-color: blue"><span id="host">world WebKit</span> rocks</div>
+<div id="destination" class="box" style="border-color: blue" contenteditable></div>
+<pre id="htmlResult"></pre>
+<pre id="textResult"></pre>
+<script src=""
+<script>
+
+Markup.description(description.textContent);
+Markup.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'open'});
+shadowRoot.innerHTML = 'hello <slot></slot>';
+
+destination.addEventListener('paste', (event) => {
+ htmlResult.textContent = event.clipboardData.getData('text/html');
+ textResult.textContent = event.clipboardData.getData('text/plain');
+ setTimeout(() => {
+ Markup.dump(destination, 'pasted html');
+ Markup.dump(textResult, 'text/plain');
+ Markup.notifyDone();
+ }, 0);
+});
+
+if (window.testRunner) {
+ internals.setSelectionWithoutValidation(shadowRoot, 0, host.firstChild, host.firstChild.data.indexOf('Kit'));
+ document.execCommand('copy');
+ destination.focus();
+ document.execCommand('paste');
+}
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1-expected.txt (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,17 @@
+This tests copying and pasting content across shadow boundaries.
+To test manually, copy text blow starting from "hello" ending with "Web", and paste into the green box below. All the text shoul be copied & pasted.
+
+pasted html:
+| <b>
+| <span>
+| id="host"
+| "hello "
+| <span>
+| id="host"
+| <span>
+| style="display: contents; color: blue;"
+| "world"
+| " Web<#selection-caret>"
+
+text/plain:
+| "hello world Web"
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1.html (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1.html (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1.html 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,39 @@
+<!DOCTYPE html><!-- webkit-test-runner [ internal:selectionAcrossShadowBoundariesEnabled=true ] -->
+<html>
+<body>
+<p id="description">This tests copying and pasting content across shadow boundaries.<br>
+To test manually, copy text blow starting from "hello" ending with "Web", and paste into the green box below. All the text shoul be copied & pasted.</p>
+<style> .box { border: solid 1px; padding: 0.2rem; margin-bottom: 1rem; } </style>
+<div id="source" class="box" style="border-color: blue"><b>hello <span id="host">world</span></b> rocks</div>
+<div id="destination" class="box" style="border-color: blue" contenteditable></div>
+<pre id="htmlResult"></pre>
+<pre id="textResult"></pre>
+<script src=""
+<script>
+
+Markup.description(description.textContent);
+Markup.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'open'});
+shadowRoot.innerHTML = '<slot style="color: blue;"></slot> WebKit';
+
+destination.addEventListener('paste', (event) => {
+ htmlResult.textContent = event.clipboardData.getData('text/html');
+ textResult.textContent = event.clipboardData.getData('text/plain');
+ setTimeout(() => {
+ Markup.dump(destination, 'pasted html');
+ Markup.dump(textResult, 'text/plain');
+ Markup.notifyDone();
+ }, 0);
+});
+
+if (window.testRunner) {
+ internals.setSelectionWithoutValidation(source, 0, shadowRoot.lastChild, shadowRoot.lastChild.data.indexOf('Kit'));
+ document.execCommand('copy');
+ destination.focus();
+ document.execCommand('paste');
+}
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-2-expected.txt (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-2-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-2-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,21 @@
+This tests copying and pasting content across shadow boundaries.
+To test manually, copy text blow starting from "hello" ending with "WebKit", and paste into the green box below. All the text shoul be copied & pasted.
+
+pasted html:
+| <div>
+| id="host1"
+| style="font-style: italic;"
+| <span>
+| style="display: contents; color: blue;"
+| <b>
+| "hello"
+| " "
+| "world"
+| <div>
+| id="host2"
+| <u>
+| "WebKit <#selection-caret>"
+
+text/plain:
+| "hello world
+WebKit "
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-2.html (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-2.html (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-2.html 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,42 @@
+<!DOCTYPE html><!-- webkit-test-runner [ internal:selectionAcrossShadowBoundariesEnabled=true ] -->
+<html>
+<body>
+<p id="description">This tests copying and pasting content across shadow boundaries.<br>
+To test manually, copy text blow starting from "hello" ending with "WebKit", and paste into the green box below. All the text shoul be copied & pasted.</p>
+<style> .box { border: solid 1px; padding: 0.2rem; margin-bottom: 1rem; } </style>
+<div id="source" class="box" style="border-color: blue"><div style="font-style: italic" id="host1"><b>hello</b></div><div id="host2">rocks</div></div>
+<div id="destination" class="box" style="border-color: blue" contenteditable></div>
+<pre id="htmlResult"></pre>
+<pre id="textResult"></pre>
+<script src=""
+<script>
+
+Markup.description(description.textContent);
+Markup.waitUntilDone();
+
+const shadowRoot1 = host1.attachShadow({mode: 'open'});
+shadowRoot1.innerHTML = '<slot style="color: blue;"></slot> world';
+
+const shadowRoot2 = host2.attachShadow({mode: 'open'});
+shadowRoot2.innerHTML = '<u>WebKit <slot></slot></u>';
+
+destination.addEventListener('paste', (event) => {
+ htmlResult.textContent = event.clipboardData.getData('text/html');
+ textResult.textContent = event.clipboardData.getData('text/plain');
+ setTimeout(() => {
+ Markup.dump(destination, 'pasted html');
+ Markup.dump(textResult, 'text/plain');
+ Markup.notifyDone();
+ }, 0);
+});
+
+if (window.testRunner) {
+ internals.setSelectionWithoutValidation(source, 0, shadowRoot2.querySelector('u'), 1);
+ document.execCommand('copy');
+ destination.focus();
+ document.execCommand('paste');
+}
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-with-shadow-content-expected.txt (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-with-shadow-content-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-with-shadow-content-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,31 @@
+This tests copying and pasting content with a shadow tree.
+To test manually, copy paste the content in the blue box to the green box below. All the text shoul be copied & pasted
+
+pasted:
+| <span>
+| id="host"
+| "hello "
+| <span>
+| id="host"
+| <span>
+| style="display: contents;"
+| "world"
+| " "
+| "WebKit"
+| " rocks<#selection-caret>"
+
+text/html:
+| <span>
+| id="host"
+| "hello "
+| <span>
+| id="host"
+| <span>
+| style="display: contents;"
+| "world"
+| " "
+| "WebKit"
+| " rocks<#selection-caret>"
+
+text/plain:
+| "hello world WebKit rocks"
Added: trunk/LayoutTests/editing/pasteboard/copy-paste-with-shadow-content.html (0 => 236785)
--- trunk/LayoutTests/editing/pasteboard/copy-paste-with-shadow-content.html (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/copy-paste-with-shadow-content.html 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,40 @@
+<!DOCTYPE html><!-- webkit-test-runner [ internal:selectionAcrossShadowBoundariesEnabled=true ] -->
+<html>
+<body>
+<p id="description">This tests copying and pasting content with a shadow tree.<br>
+To test manually, copy paste the content in the blue box to the green box below. All the text shoul be copied & pasted</p>
+<style> .box { border: solid 1px; padding: 0.2rem; margin-bottom: 1rem; } </style>
+<div id="source" class="box" style="border-color: blue">hello <span id="host">world</span> rocks</div>
+<div id="destination" class="box" style="border-color: blue" contenteditable></div>
+<pre id="htmlResult"></pre>
+<pre id="textResult"></pre>
+<script src=""
+<script>
+
+Markup.description(description.textContent);
+Markup.waitUntilDone();
+
+const shadowRoot = host.attachShadow({mode: 'open'});
+shadowRoot.innerHTML = '<slot></slot> WebKit';
+getSelection().selectAllChildren(source);
+
+destination.addEventListener('paste', (event) => {
+ htmlResult.textContent = event.clipboardData.getData('text/html');
+ textResult.textContent = event.clipboardData.getData('text/plain');
+ setTimeout(() => {
+ Markup.dump(destination, 'pasted');
+ Markup.dump(destination, 'text/html');
+ Markup.dump(textResult, 'text/plain');
+ Markup.notifyDone();
+ }, 0);
+});
+
+if (window.testRunner) {
+ document.execCommand('copy');
+ destination.focus();
+ document.execCommand('paste');
+}
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-2-expected.txt (0 => 236785)
--- trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-2-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-2-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,18 @@
+This tests copying and pasting content across shadow boundaries.
+To test manually, copy text blow starting from "world" ending with "rocks", and paste into the green box below. All the text shoul be copied & pasted.
+
+pasted html:
+| <span>
+| id="host"
+| style="-webkit-text-size-adjust: auto;"
+| <span>
+| style="display: contents;"
+| "world"
+| " "
+| "WebKit"
+| <span>
+| style="-webkit-text-size-adjust: auto;"
+| " rocks<#selection-caret>"
+
+text/plain:
+| "world WebKit rocks"
Added: trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-3-expected.txt (0 => 236785)
--- trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-3-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-3-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,16 @@
+This tests copying and pasting content across shadow boundaries.
+To test manually, copy text blow starting from "WebKit" ending with "rocks", and paste into the green box below. All the text shoul be copied & pasted.
+
+pasted html:
+| <span>
+| id="host"
+| style="-webkit-text-size-adjust: auto;"
+| <span>
+| style="display: contents;"
+| "world WebKit"
+| <span>
+| style="-webkit-text-size-adjust: auto;"
+| " rocks<#selection-caret>"
+
+text/plain:
+| "world WebKit rocks"
Added: trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-4-expected.txt (0 => 236785)
--- trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-4-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-4-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,13 @@
+This tests copying and pasting content across shadow boundaries.
+To test manually, copy text blow starting from "hello" ending with "Web", and paste into the green box below. All the text shoul be copied & pasted.
+
+pasted html:
+| <span>
+| style="-webkit-text-size-adjust: auto;"
+| "hello "
+| <span>
+| style="-webkit-text-size-adjust: auto; display: contents;"
+| "world Web<#selection-caret>"
+
+text/plain:
+| "hello world Web"
Added: trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1-expected.txt (0 => 236785)
--- trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,18 @@
+This tests copying and pasting content across shadow boundaries.
+To test manually, copy text blow starting from "hello" ending with "Web", and paste into the green box below. All the text shoul be copied & pasted.
+
+pasted html:
+| <b>
+| style="-webkit-text-size-adjust: auto;"
+| <span>
+| id="host"
+| "hello "
+| <span>
+| id="host"
+| <span>
+| style="display: contents; color: blue;"
+| "world"
+| " Web<#selection-caret>"
+
+text/plain:
+| "hello world Web"
Added: trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-with-shadow-content-expected.txt (0 => 236785)
--- trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-with-shadow-content-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/ios/editing/pasteboard/copy-paste-with-shadow-content-expected.txt 2018-10-03 06:28:07 UTC (rev 236785)
@@ -0,0 +1,33 @@
+This tests copying and pasting content with a shadow tree.
+To test manually, copy paste the content in the blue box to the green box below. All the text shoul be copied & pasted
+
+pasted:
+| <span>
+| id="host"
+| style="-webkit-text-size-adjust: auto;"
+| "hello "
+| <span>
+| id="host"
+| <span>
+| style="display: contents;"
+| "world"
+| " "
+| "WebKit"
+| " rocks<#selection-caret>"
+
+text/html:
+| <span>
+| id="host"
+| style="-webkit-text-size-adjust: auto;"
+| "hello "
+| <span>
+| id="host"
+| <span>
+| style="display: contents;"
+| "world"
+| " "
+| "WebKit"
+| " rocks<#selection-caret>"
+
+text/plain:
+| "hello world WebKit rocks"
Modified: trunk/Source/WebCore/ChangeLog (236784 => 236785)
--- trunk/Source/WebCore/ChangeLog 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/ChangeLog 2018-10-03 06:28:07 UTC (rev 236785)
@@ -1,3 +1,86 @@
+2018-10-02 Ryosuke Niwa <rn...@webkit.org>
+
+ Copying content with shadow DOM doesn't copy any contents
+ https://bugs.webkit.org/show_bug.cgi?id=157443
+
+ Reviewed by Wenson Hsieh.
+
+ This patch adds the support for copying and pasting content across shadow boundaries in HTML and plain text,
+ which is enabled whenever selection across shadow boundaries is enabled.
+
+ To do this, TextIterator now has a constructor which takes two Positions, and the node traversal code in
+ StyledMarkupAccumulator has been abstracted via helper functions as done for TextIterator.
+
+ When serializing a HTMl slot element, serialize it as a span with "display: contents" to make sure when
+ the content is pasted into a shadow tree, it wouldn't affect the slot assignment of the shadow tree.
+
+ Tests: editing/pasteboard/copy-paste-across-shadow-boundaries-1.html
+ editing/pasteboard/copy-paste-across-shadow-boundaries-2.html
+ editing/pasteboard/copy-paste-across-shadow-boundaries-3.html
+ editing/pasteboard/copy-paste-across-shadow-boundaries-4.html
+ editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-1.html
+ editing/pasteboard/copy-paste-across-shadow-boundaries-with-style-2.html
+ editing/pasteboard/copy-paste-with-shadow-content.html
+
+ * dom/ComposedTreeIterator.h:
+ (WebCore::assignedSlotIgnoringUserAgentShadow): Moved from TextIterator.cpp.
+ (WebCore::shadowRootIgnoringUserAgentShadow): Ditto.
+ (WebCore::firstChildInComposedTreeIgnoringUserAgentShadow): Ditto.
+ (WebCore::nextSiblingInComposedTreeIgnoringUserAgentShadow): Ditto.
+ * dom/Position.h:
+ (WebCore::Position::treeScope const): Added.
+ * editing/EditingStyle.cpp:
+ (WebCore::EditingStyle::addDisplayContents): Added.
+ * editing/EditingStyle.h:
+ * editing/Editor.cpp:
+ (WebCore::Editor::selectedText const): Use the new behavior when selectionAcrossShadowBoundariesEnabled is set.
+ (WebCore::Editor::selectedTextForDataTransfer const): Ditto.
+ * editing/MarkupAccumulator.cpp:
+ (WebCore::MarkupAccumulator::appendEndElement): Renamed from appendEndTag. Now takes StringBuilder.
+ * editing/MarkupAccumulator.h:
+ (WebCore::MarkupAccumulator::appendEndTag):
+ * editing/TextIterator.cpp:
+ (WebCore::TextIterator::TextIterator): Added a new variant which takes two positions.
+ (WebCore::TextIterator::init):
+ (WebCore::firstChild):
+ (WebCore::nextSibling):
+ (WebCore::plainText): Ditto.
+ * editing/TextIterator.h:
+ * editing/cocoa/EditorCocoa.mm:
+ (WebCore::Editor::selectionInHTMLFormat): Use the new behavior if selectionAcrossShadowBoundariesEnabled is set.
+ * editing/gtk/EditorGtk.cpp:
+ (WebCore::Editor::writeSelectionToPasteboard): Ditto.
+ * editing/markup.cpp:
+ (WebCore::StyledMarkupAccumulator::parentNode): Added.
+ (WebCore::StyledMarkupAccumulator::firstChild): Added.
+ (WebCore::StyledMarkupAccumulator::nextSibling): Added.
+ (WebCore::StyledMarkupAccumulator::nextSkippingChildren): Added.
+ (WebCore::StyledMarkupAccumulator::hasChildNodes): Added.
+ (WebCore::StyledMarkupAccumulator::isDescendantOf): Added.
+ (WebCore::StyledMarkupAccumulator::StyledMarkupAccumulator):
+ (WebCore::StyledMarkupAccumulator::appendElement): Serialize a slot element as a span with display: contents.
+ (WebCore::StyledMarkupAccumulator::appendEndElement): Added. Ditto.
+ (WebCore::StyledMarkupAccumulator::serializeNodes):
+ (WebCore::StyledMarkupAccumulator::traverseNodesForSerialization): Use the newly added helper functions to
+ traverse the composed tree when m_useComposedTree is set.
+ (WebCore::commonShadowIncludingAncestor): Added.
+ (WebCore::serializePreservingVisualAppearanceInternal): Added SerializeComposedTree as an argument. Also use
+ StyledMarkupAccumulator::parentNode to serialize special common ancestors; e.g. to preserve b, i, etc...
+ (WebCore::serializePreservingVisualAppearance): Ditto to the variant which takes VisibleSelection.
+ (WebCore::sanitizedMarkupForFragmentInDocument):
+ * editing/markup.h:
+ * editing/wpe/EditorWPE.cpp:
+ (WebCore::Editor::writeSelectionToPasteboard):
+ * loader/archive/cf/LegacyWebArchive.cpp:
+ (WebCore::LegacyWebArchive::createFromSelection):
+ * page/PageSerializer.cpp:
+ (WebCore::PageSerializer::SerializerMarkupAccumulator::appendEndElement):
+ * testing/Internals.cpp:
+ (WebCore::Internals::setSelectionWithoutValidation): Added. A helper function to create a selection across
+ shadow boundaries for testing purposes.
+ * testing/Internals.h:
+ * testing/Internals.idl:
+
2018-10-02 Chris Dumez <cdu...@apple.com>
MessageEvent.ports should return the same object
Modified: trunk/Source/WebCore/dom/ComposedTreeIterator.h (236784 => 236785)
--- trunk/Source/WebCore/dom/ComposedTreeIterator.h 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/dom/ComposedTreeIterator.h 2018-10-03 06:28:07 UTC (rev 236785)
@@ -26,6 +26,7 @@
#pragma once
#include "ElementAndTextDescendantIterator.h"
+#include "HTMLSlotElement.h"
#include "ShadowRoot.h"
namespace WebCore {
@@ -199,4 +200,49 @@
enum class ComposedTreeAsTextMode { Normal, WithPointers };
WEBCORE_EXPORT String composedTreeAsText(ContainerNode& root, ComposedTreeAsTextMode = ComposedTreeAsTextMode::Normal);
+
+// Helper functions for walking the composed tree.
+// FIXME: Use ComposedTreeIterator instead. These functions are more expensive because they might do O(n) work.
+
+inline HTMLSlotElement* assignedSlotIgnoringUserAgentShadow(Node& node)
+{
+ auto* slot = node.assignedSlot();
+ if (!slot || slot->containingShadowRoot()->mode() == ShadowRootMode::UserAgent)
+ return nullptr;
+ return slot;
+}
+
+inline ShadowRoot* shadowRootIgnoringUserAgentShadow(Node& node)
+{
+ auto* shadowRoot = node.shadowRoot();
+ if (!shadowRoot || shadowRoot->mode() == ShadowRootMode::UserAgent)
+ return nullptr;
+ return shadowRoot;
+}
+
+inline Node* firstChildInComposedTreeIgnoringUserAgentShadow(Node& node)
+{
+ if (auto* shadowRoot = shadowRootIgnoringUserAgentShadow(node))
+ return shadowRoot->firstChild();
+ if (is<HTMLSlotElement>(node)) {
+ if (auto* assignedNodes = downcast<HTMLSlotElement>(node).assignedNodes())
+ return assignedNodes->at(0);
+ }
+ return node.firstChild();
+}
+
+inline Node* nextSiblingInComposedTreeIgnoringUserAgentShadow(Node& node)
+{
+ if (auto* slot = assignedSlotIgnoringUserAgentShadow(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();
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/dom/Position.h (236784 => 236785)
--- trunk/Source/WebCore/dom/Position.h 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/dom/Position.h 2018-10-03 06:28:07 UTC (rev 236785)
@@ -117,6 +117,7 @@
Node* deprecatedNode() const { return m_anchorNode.get(); }
Document* document() const { return m_anchorNode ? &m_anchorNode->document() : nullptr; }
+ TreeScope* treeScope() const { return m_anchorNode ? &m_anchorNode->treeScope() : nullptr; }
Element* rootEditableElement() const
{
Node* container = containerNode();
Modified: trunk/Source/WebCore/editing/EditingStyle.cpp (236784 => 236785)
--- trunk/Source/WebCore/editing/EditingStyle.cpp 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/EditingStyle.cpp 2018-10-03 06:28:07 UTC (rev 236785)
@@ -1369,6 +1369,13 @@
m_mutableStyle->setProperty(CSSPropertyDisplay, CSSValueInline, propertyIsImportant);
}
+void EditingStyle::addDisplayContents()
+{
+ if (!m_mutableStyle)
+ m_mutableStyle = MutableStyleProperties::create();
+ m_mutableStyle->setProperty(CSSPropertyDisplay, CSSValueContents);
+}
+
bool EditingStyle::convertPositionStyle()
{
if (!m_mutableStyle)
Modified: trunk/Source/WebCore/editing/EditingStyle.h (236784 => 236785)
--- trunk/Source/WebCore/editing/EditingStyle.h 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/EditingStyle.h 2018-10-03 06:28:07 UTC (rev 236785)
@@ -149,6 +149,7 @@
void removeStyleFromRulesAndContext(StyledElement&, Node* context);
void removePropertiesInElementDefaultStyle(Element&);
void forceInline();
+ void addDisplayContents();
bool convertPositionStyle();
bool isFloating();
int legacyFontSize(Document&) const;
Modified: trunk/Source/WebCore/editing/Editor.cpp (236784 => 236785)
--- trunk/Source/WebCore/editing/Editor.cpp 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/Editor.cpp 2018-10-03 06:28:07 UTC (rev 236785)
@@ -3182,18 +3182,25 @@
String Editor::selectedText() const
{
- return selectedText(TextIteratorDefaultBehavior);
+ TextIteratorBehavior behavior = TextIteratorDefaultBehavior;
+ if (m_frame.settings().selectionAcrossShadowBoundariesEnabled())
+ behavior |= TextIteratorTraversesFlatTree;
+ return selectedText(behavior);
}
String Editor::selectedTextForDataTransfer() const
{
- return selectedText(TextIteratorEmitsImageAltText);
+ TextIteratorBehavior behavior = TextIteratorEmitsImageAltText;
+ if (m_frame.settings().selectionAcrossShadowBoundariesEnabled())
+ behavior |= TextIteratorTraversesFlatTree;
+ return selectedText(behavior);
}
String Editor::selectedText(TextIteratorBehavior behavior) const
{
// We remove '\0' characters because they are not visibly rendered to the user.
- return plainText(m_frame.selection().toNormalizedRange().get(), behavior).replaceWithLiteral('\0', "");
+ auto& selection = m_frame.selection().selection();
+ return plainText(selection.start(), selection.end(), behavior).replaceWithLiteral('\0', "");
}
static inline void collapseCaretWidth(IntRect& rect)
Modified: trunk/Source/WebCore/editing/MarkupAccumulator.cpp (236784 => 236785)
--- trunk/Source/WebCore/editing/MarkupAccumulator.cpp 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/MarkupAccumulator.cpp 2018-10-03 06:28:07 UTC (rev 236785)
@@ -192,9 +192,9 @@
m_nodes->append(const_cast<Node*>(&node));
}
-void MarkupAccumulator::appendEndTag(const Element& element)
+void MarkupAccumulator::appendEndElement(StringBuilder& out, const Element& element)
{
- appendEndMarkup(m_markup, element);
+ appendEndMarkup(out, element);
}
void MarkupAccumulator::appendTextSubstring(const Text& text, unsigned start, unsigned length)
Modified: trunk/Source/WebCore/editing/MarkupAccumulator.h (236784 => 236785)
--- trunk/Source/WebCore/editing/MarkupAccumulator.h 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/MarkupAccumulator.h 2018-10-03 06:28:07 UTC (rev 236785)
@@ -76,10 +76,10 @@
void appendEndTag(const Node& node)
{
if (is<Element>(node))
- appendEndTag(downcast<Element>(node));
+ appendEndElement(m_markup, downcast<Element>(node));
}
- virtual void appendEndTag(const Element&);
+ virtual void appendEndElement(StringBuilder&, const Element&);
virtual void appendCustomAttributes(StringBuilder&, const Element&, Namespaces*);
virtual void appendText(StringBuilder&, const Text&);
virtual void appendElement(StringBuilder&, const Element&, Namespaces*);
Modified: trunk/Source/WebCore/editing/TextIterator.cpp (236784 => 236785)
--- trunk/Source/WebCore/editing/TextIterator.cpp 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/TextIterator.cpp 2018-10-03 06:28:07 UTC (rev 236785)
@@ -27,6 +27,7 @@
#include "config.h"
#include "TextIterator.h"
+#include "ComposedTreeIterator.h"
#include "Document.h"
#include "Editing.h"
#include "FontCascade.h"
@@ -339,10 +340,35 @@
// --------
+
+TextIterator::TextIterator(Position start, Position end, TextIteratorBehavior behavior)
+ : m_behavior(behavior)
+{
+ if (start.isNull() || end.isNull())
+ return;
+ ASSERT(comparePositions(start, end) <= 0);
+
+ RELEASE_ASSERT(behavior & TextIteratorTraversesFlatTree || start.treeScope() == end.treeScope());
+
+ start.document()->updateLayoutIgnorePendingStylesheets();
+
+ // FIXME: Use Position / PositionIterator instead to avoid offset computation.
+ m_startContainer = start.containerNode();
+ m_startOffset = start.computeOffsetInContainerNode();
+
+ m_endContainer = end.containerNode();
+ m_endOffset = end.computeOffsetInContainerNode();
+
+ m_node = start.firstNode().get();
+ if (!m_node)
+ return;
+
+ init();
+}
+
TextIterator::TextIterator(const Range* range, TextIteratorBehavior behavior)
: m_behavior(behavior)
{
- // FIXME: Only m_positionNode above needs to be initialized if range is null.
if (!range)
return;
@@ -358,11 +384,15 @@
m_endContainer = &range->endContainer();
m_endOffset = range->endOffset();
- // Set up the current node for processing.
m_node = range->firstNode();
if (!m_node)
return;
+ init();
+}
+
+void TextIterator::init()
+{
if (isClippedByFrameAncestor(m_node->document(), m_behavior))
return;
@@ -379,52 +409,11 @@
TextIterator::~TextIterator() = default;
-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 firstChildInComposedTreeIgnoringUserAgentShadow(node);
return node.firstChild();
}
@@ -431,7 +420,7 @@
static inline Node* nextSibling(TextIteratorBehavior options, Node& node)
{
if (UNLIKELY(options & TextIteratorTraversesFlatTree))
- return nextSiblingInFlatTreeIgnoringUserAgentShadow(node);
+ return nextSiblingInComposedTreeIgnoringUserAgentShadow(node);
return node.nextSibling();
}
@@ -2654,11 +2643,15 @@
return false;
}
-String plainText(const Range* r, TextIteratorBehavior defaultBehavior, bool isDisplayString)
+String plainText(Position start, Position end, TextIteratorBehavior defaultBehavior, bool isDisplayString)
{
// The initial buffer size can be critical for performance: https://bugs.webkit.org/show_bug.cgi?id=81192
static const unsigned initialCapacity = 1 << 15;
+ if (!start.document())
+ return { };
+ auto document = makeRef(*start.document());
+
unsigned bufferLength = 0;
StringBuilder builder;
builder.reserveCapacity(initialCapacity);
@@ -2665,8 +2658,8 @@
TextIteratorBehavior behavior = defaultBehavior;
if (!isDisplayString)
behavior = static_cast<TextIteratorBehavior>(behavior | TextIteratorEmitsTextsWithoutTranscoding);
-
- for (TextIterator it(r, behavior); !it.atEnd(); it.advance()) {
+
+ for (TextIterator it(start, end, behavior); !it.atEnd(); it.advance()) {
it.appendTextToStringBuilder(builder);
bufferLength += it.text().length();
}
@@ -2677,11 +2670,18 @@
String result = builder.toString();
if (isDisplayString)
- r->ownerDocument().displayStringModifiedByEncoding(result);
+ document->displayStringModifiedByEncoding(result);
return result;
}
+String plainText(const Range* range, TextIteratorBehavior defaultBehavior, bool isDisplayString)
+{
+ if (!range)
+ return emptyString();
+ return plainText(range->startPosition(), range->endPosition(), defaultBehavior, isDisplayString);
+}
+
String plainTextReplacingNoBreakSpace(const Range* range, TextIteratorBehavior defaultBehavior, bool isDisplayString)
{
return plainText(range, defaultBehavior, isDisplayString).replace(noBreakSpace, ' ');
Modified: trunk/Source/WebCore/editing/TextIterator.h (236784 => 236785)
--- trunk/Source/WebCore/editing/TextIterator.h 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/TextIterator.h 2018-10-03 06:28:07 UTC (rev 236785)
@@ -43,6 +43,8 @@
class RunResolver;
}
+WEBCORE_EXPORT String plainText(Position start, Position end, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
+
WEBCORE_EXPORT String plainText(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
WEBCORE_EXPORT String plainTextReplacingNoBreakSpace(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
Ref<Range> findPlainText(const Range&, const String&, FindOptions);
@@ -99,6 +101,7 @@
class TextIterator {
public:
+ explicit TextIterator(Position start, Position end, TextIteratorBehavior = TextIteratorDefaultBehavior);
WEBCORE_EXPORT explicit TextIterator(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior);
WEBCORE_EXPORT ~TextIterator();
@@ -118,6 +121,7 @@
WEBCORE_EXPORT static Ref<Range> subrange(Range& entireRange, int characterOffset, int characterCount);
private:
+ void init();
void exitNode(Node*);
bool shouldRepresentNodeOffsetZero();
bool shouldEmitSpaceBeforeAndAfterNode(Node&);
Modified: trunk/Source/WebCore/editing/cocoa/EditorCocoa.mm (236784 => 236785)
--- trunk/Source/WebCore/editing/cocoa/EditorCocoa.mm 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/cocoa/EditorCocoa.mm 2018-10-03 06:28:07 UTC (rev 236785)
@@ -49,6 +49,7 @@
#import "Pasteboard.h"
#import "RenderElement.h"
#import "RenderStyle.h"
+#import "Settings.h"
#import "Text.h"
#import "WebContentReader.h"
#import "WebCoreNSURLExtras.h"
@@ -75,7 +76,8 @@
String Editor::selectionInHTMLFormat()
{
- return serializePreservingVisualAppearance(m_frame.selection().selection(), ResolveURLs::YesExcludingLocalFileURLsForPrivacy);
+ return serializePreservingVisualAppearance(m_frame.selection().selection(), ResolveURLs::YesExcludingLocalFileURLsForPrivacy,
+ m_frame.settings().selectionAcrossShadowBoundariesEnabled() ? SerializeComposedTree::Yes : SerializeComposedTree::No);
}
#if ENABLE(ATTACHMENT_ELEMENT)
Modified: trunk/Source/WebCore/editing/gtk/EditorGtk.cpp (236784 => 236785)
--- trunk/Source/WebCore/editing/gtk/EditorGtk.cpp 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/gtk/EditorGtk.cpp 2018-10-03 06:28:07 UTC (rev 236785)
@@ -43,6 +43,7 @@
#include "SVGElement.h"
#include "SVGImageElement.h"
#include "SelectionData.h"
+#include "Settings.h"
#include "XLinkNames.h"
#include "markup.h"
#include <cairo.h>
@@ -146,7 +147,8 @@
PasteboardWebContent pasteboardContent;
pasteboardContent.canSmartCopyOrDelete = canSmartCopyOrDelete();
pasteboardContent.text = selectedTextForDataTransfer();
- pasteboardContent.markup = serializePreservingVisualAppearance(m_frame.selection().selection(), ResolveURLs::YesExcludingLocalFileURLsForPrivacy);
+ pasteboardContent.markup = serializePreservingVisualAppearance(m_frame.selection().selection(), ResolveURLs::YesExcludingLocalFileURLsForPrivacy,
+ m_frame.settings().selectionAcrossShadowBoundariesEnabled() ? SerializeComposedTree::Yes : SerializeComposedTree::No);
pasteboard.write(pasteboardContent);
}
Modified: trunk/Source/WebCore/editing/markup.cpp (236784 => 236785)
--- trunk/Source/WebCore/editing/markup.cpp 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/markup.cpp 2018-10-03 06:28:07 UTC (rev 236785)
@@ -37,6 +37,7 @@
#include "CacheStorageProvider.h"
#include "ChildListMutationScope.h"
#include "Comment.h"
+#include "ComposedTreeIterator.h"
#include "DocumentFragment.h"
#include "DocumentLoader.h"
#include "DocumentType.h"
@@ -219,8 +220,8 @@
public:
enum RangeFullySelectsNode { DoesFullySelectNode, DoesNotFullySelectNode };
- StyledMarkupAccumulator(const Position& start, const Position& end, Vector<Node*>* nodes,
- ResolveURLs, AnnotateForInterchange, MSOListMode, bool needsPositionStyleConversion, Node* highestNodeToBeSerialized = nullptr);
+ StyledMarkupAccumulator(const Position& start, const Position& end, Vector<Node*>* nodes, ResolveURLs, SerializeComposedTree,
+ AnnotateForInterchange, MSOListMode, bool needsPositionStyleConversion, Node* highestNodeToBeSerialized = nullptr);
Node* serializeNodes(const Position& start, const Position& end);
void wrapWithNode(Node&, bool convertBlocksToInlines = false, RangeFullySelectsNode = DoesFullySelectNode);
@@ -232,6 +233,13 @@
using MarkupAccumulator::appendString;
+ ContainerNode* parentNode(Node& node)
+ {
+ if (UNLIKELY(m_useComposedTree))
+ return node.parentInComposedTree();
+ return node.parentOrShadowHostNode();
+ }
+
private:
void appendStyleNodeOpenTag(StringBuilder&, StyleProperties*, Document&, bool isBlock = false);
const String& styleNodeCloseTag(bool isBlock = false);
@@ -242,6 +250,7 @@
bool shouldPreserveMSOListStyleForElement(const Element&);
void appendElement(StringBuilder& out, const Element&, bool addDisplayInline, RangeFullySelectsNode);
+ void appendEndElement(StringBuilder& out, const Element&) override;
void appendCustomAttributes(StringBuilder&, const Element&, Namespaces*) override;
void appendText(StringBuilder& out, const Text&) override;
@@ -250,6 +259,48 @@
appendElement(out, element, false, DoesFullySelectNode);
}
+ Node* firstChild(Node& node)
+ {
+ if (UNLIKELY(m_useComposedTree))
+ return firstChildInComposedTreeIgnoringUserAgentShadow(node);
+ return node.firstChild();
+ }
+
+ Node* nextSibling(Node& node)
+ {
+ if (UNLIKELY(m_useComposedTree))
+ return nextSiblingInComposedTreeIgnoringUserAgentShadow(node);
+ return node.nextSibling();
+ }
+
+ Node* nextSkippingChildren(Node& node)
+ {
+ if (UNLIKELY(m_useComposedTree)) {
+ if (auto* sibling = nextSiblingInComposedTreeIgnoringUserAgentShadow(node))
+ return sibling;
+ for (auto* ancestor = node.parentInComposedTree(); ancestor; ancestor = ancestor->parentInComposedTree()) {
+ if (auto* sibling = nextSiblingInComposedTreeIgnoringUserAgentShadow(*ancestor))
+ return sibling;
+ }
+ return nullptr;
+ }
+ return NodeTraversal::nextSkippingChildren(node);
+ }
+
+ bool hasChildNodes(Node& node)
+ {
+ if (UNLIKELY(m_useComposedTree))
+ return firstChildInComposedTreeIgnoringUserAgentShadow(node);
+ return node.hasChildNodes();
+ }
+
+ bool isDescendantOf(Node& node, Node& possibleAncestor)
+ {
+ if (UNLIKELY(m_useComposedTree))
+ return node.isDescendantOrShadowDescendantOf(&possibleAncestor);
+ return node.isDescendantOf(&possibleAncestor);
+ }
+
enum class NodeTraversalMode { EmitString, DoNotEmitString };
Node* traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode);
@@ -271,6 +322,7 @@
const AnnotateForInterchange m_annotate;
RefPtr<Node> m_highestNodeToBeSerialized;
RefPtr<EditingStyle> m_wrappingStyle;
+ bool m_useComposedTree;
bool m_needsPositionStyleConversion;
bool m_needRelativeStyleWrapper { false };
bool m_needClearingDiv { false };
@@ -278,13 +330,14 @@
bool m_inMSOList { false };
};
-inline StyledMarkupAccumulator::StyledMarkupAccumulator(const Position& start, const Position& end, Vector<Node*>* nodes,
- ResolveURLs urlsToResolve, AnnotateForInterchange annotate, MSOListMode msoListMode, bool needsPositionStyleConversion, Node* highestNodeToBeSerialized)
+inline StyledMarkupAccumulator::StyledMarkupAccumulator(const Position& start, const Position& end, Vector<Node*>* nodes, ResolveURLs urlsToResolve, SerializeComposedTree serializeComposedTree,
+ AnnotateForInterchange annotate, MSOListMode msoListMode, bool needsPositionStyleConversion, Node* highestNodeToBeSerialized)
: MarkupAccumulator(nodes, urlsToResolve)
, m_start(start)
, m_end(end)
, m_annotate(annotate)
, m_highestNodeToBeSerialized(highestNodeToBeSerialized)
+ , m_useComposedTree(serializeComposedTree == SerializeComposedTree::Yes)
, m_needsPositionStyleConversion(needsPositionStyleConversion)
, m_shouldPreserveMSOList(msoListMode == MSOListMode::Preserve)
{
@@ -445,12 +498,16 @@
void StyledMarkupAccumulator::appendElement(StringBuilder& out, const Element& element, bool addDisplayInline, RangeFullySelectsNode rangeFullySelectsNode)
{
const bool documentIsHTML = element.document().isHTMLDocument();
- appendOpenTag(out, element, 0);
+ const bool isSlotElement = is<HTMLSlotElement>(element);
+ if (UNLIKELY(isSlotElement))
+ out.append("<span");
+ else
+ appendOpenTag(out, element, nullptr);
appendCustomAttributes(out, element, nullptr);
const bool shouldAnnotateOrForceInline = element.isHTMLElement() && (shouldAnnotate() || addDisplayInline);
- bool shouldOverrideStyleAttr = (shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element)) && !shouldPreserveMSOListStyleForElement(element);
+ bool shouldOverrideStyleAttr = (shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element) || isSlotElement) && !shouldPreserveMSOListStyleForElement(element);
if (element.hasAttributes()) {
for (const Attribute& attribute : element.attributesIterator()) {
// We'll handle the style attribute separately, below.
@@ -472,6 +529,9 @@
} else
newInlineStyle = EditingStyle::create();
+ if (isSlotElement)
+ newInlineStyle->addDisplayContents();
+
if (is<StyledElement>(element) && downcast<StyledElement>(element).inlineStyle())
newInlineStyle->overrideWithStyle(*downcast<StyledElement>(element).inlineStyle());
@@ -503,13 +563,21 @@
appendCloseTag(out, element);
}
+void StyledMarkupAccumulator::appendEndElement(StringBuilder& out, const Element& element)
+{
+ if (UNLIKELY(is<HTMLSlotElement>(element)))
+ out.append("</span>");
+ else
+ MarkupAccumulator::appendEndElement(out, element);
+}
+
Node* StyledMarkupAccumulator::serializeNodes(const Position& start, const Position& end)
{
ASSERT(comparePositions(start, end) <= 0);
auto startNode = start.firstNode();
Node* pastEnd = end.computeNodeAfterPosition();
- if (!pastEnd)
- pastEnd = NodeTraversal::nextSkippingChildren(*end.containerNode());
+ if (!pastEnd && end.containerNode())
+ pastEnd = nextSkippingChildren(*end.containerNode());
if (!m_highestNodeToBeSerialized) {
Node* lastClosed = traverseNodesForSerialization(startNode.get(), pastEnd, NodeTraversalMode::DoNotEmitString);
@@ -535,7 +603,8 @@
return false;
}
- if (!node.renderer() && !enclosingElementWithTag(firstPositionInOrBeforeNode(&node), selectTag))
+ bool isDisplayContents = is<Element>(node) && downcast<Element>(node).hasDisplayContents();
+ if (!node.renderer() && !isDisplayContents && !enclosingElementWithTag(firstPositionInOrBeforeNode(&node), selectTag))
return false;
++depth;
@@ -561,20 +630,19 @@
Node* lastNode = nullptr;
Node* next = nullptr;
- for (Node* n = startNode; n != pastEnd; n = next) {
- lastNode = n;
+ for (auto* n = startNode; n != pastEnd; lastNode = n, n = next) {
Vector<Node*, 8> exitedAncestors;
next = nullptr;
- if (auto* firstChild = n->firstChild())
- next = firstChild;
- else if (auto* nextSibling = n->nextSibling())
- next = nextSibling;
+ if (auto* child = firstChild(*n))
+ next = child;
+ else if (auto* sibling = nextSibling(*n))
+ next = sibling;
else {
- for (auto* ancestor = n->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
+ for (auto* ancestor = parentNode(*n); ancestor; ancestor = parentNode(*ancestor)) {
exitedAncestors.append(ancestor);
- if (auto* nextSibling = ancestor->nextSibling()) {
- next = nextSibling;
+ if (auto* sibling = nextSibling(*ancestor)) {
+ next = sibling;
break;
}
}
@@ -588,10 +656,10 @@
if (!enterNode(*n)) {
next = NodeTraversal::nextSkippingChildren(*n);
// Don't skip over pastEnd.
- if (pastEnd && pastEnd->isDescendantOf(*n))
+ if (pastEnd && isDescendantOf(*pastEnd, *n))
next = pastEnd;
} else {
- if (!n->hasChildNodes())
+ if (!hasChildNodes(*n))
exitNode(*n);
}
@@ -601,10 +669,13 @@
exitNode(*ancestor);
}
}
+
+ ASSERT(lastNode || !depth);
+ if (depth) {
+ for (auto* ancestor = parentNode(pastEnd ? *pastEnd : *lastNode); ancestor && depth; ancestor = parentNode(*ancestor))
+ exitNode(*ancestor);
+ }
- for (auto* ancestor = (pastEnd ? pastEnd : lastNode)->parentNode(); ancestor && depth; ancestor = ancestor->parentNode())
- exitNode(*ancestor);
-
return lastClosed;
}
@@ -754,15 +825,27 @@
return specialCommonAncestor;
}
-static String serializePreservingVisualAppearanceInternal(const Position& start, const Position& end, Vector<Node*>* nodes,
- AnnotateForInterchange annotate, ConvertBlocksToInlines convertBlocksToInlines, ResolveURLs urlsToResolve, MSOListMode msoListMode)
+static RefPtr<Node> commonShadowIncludingAncestor(const Position& a, const Position& b)
{
+ TreeScope* commonScope = commonTreeScope(a.containerNode(), b.containerNode());
+ if (!commonScope)
+ return nullptr;
+ auto* nodeA = commonScope->ancestorNodeInThisScope(a.containerNode());
+ ASSERT(nodeA);
+ auto* nodeB = commonScope->ancestorNodeInThisScope(b.containerNode());
+ ASSERT(nodeB);
+ return Range::commonAncestorContainer(nodeA, nodeB);
+}
+
+static String serializePreservingVisualAppearanceInternal(const Position& start, const Position& end, Vector<Node*>* nodes, ResolveURLs urlsToResolve, SerializeComposedTree serializeComposedTree,
+ AnnotateForInterchange annotate, ConvertBlocksToInlines convertBlocksToInlines, MSOListMode msoListMode)
+{
static NeverDestroyed<const String> interchangeNewlineString(MAKE_STATIC_STRING_IMPL("<br class=\"" AppleInterchangeNewline "\">"));
if (!comparePositions(start, end))
return emptyString();
- RefPtr<Node> commonAncestor = Range::commonAncestorContainer(start.containerNode(), end.containerNode());
+ RefPtr<Node> commonAncestor = commonShadowIncludingAncestor(start, end);
if (!commonAncestor)
return emptyString();
@@ -781,7 +864,7 @@
Node* specialCommonAncestor = highestAncestorToWrapMarkup(start, end, *commonAncestor, annotate);
- StyledMarkupAccumulator accumulator(start, end, nodes, urlsToResolve, annotate, msoListMode, needsPositionStyleConversion, specialCommonAncestor);
+ StyledMarkupAccumulator accumulator(start, end, nodes, urlsToResolve, serializeComposedTree, annotate, msoListMode, needsPositionStyleConversion, specialCommonAncestor);
Position startAdjustedForInterchangeNewline = start;
if (annotate == AnnotateForInterchange::Yes && needInterchangeNewlineAfter(visibleStart)) {
@@ -799,7 +882,7 @@
if (specialCommonAncestor && lastClosed) {
// Also include all of the ancestors of lastClosed up to this special ancestor.
- for (ContainerNode* ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
+ for (ContainerNode* ancestor = accumulator.parentNode(*lastClosed); ancestor; ancestor = accumulator.parentNode(*ancestor)) {
if (ancestor == fullySelectedRoot && convertBlocksToInlines == ConvertBlocksToInlines::No) {
RefPtr<EditingStyle> fullySelectedRootStyle = styleFromMatchedRulesAndInlineDecl(*fullySelectedRoot);
@@ -849,13 +932,14 @@
String serializePreservingVisualAppearance(const Range& range, Vector<Node*>* nodes, AnnotateForInterchange annotate, ConvertBlocksToInlines convertBlocksToInlines, ResolveURLs urlsToReslve)
{
- return serializePreservingVisualAppearanceInternal(range.startPosition(), range.endPosition(), nodes, annotate, convertBlocksToInlines, urlsToReslve, MSOListMode::DoNotPreserve);
+ return serializePreservingVisualAppearanceInternal(range.startPosition(), range.endPosition(), nodes, urlsToReslve, SerializeComposedTree::No,
+ annotate, convertBlocksToInlines, MSOListMode::DoNotPreserve);
}
-String serializePreservingVisualAppearance(const VisibleSelection& selection, ResolveURLs resolveURLs, Vector<Node*>* nodes)
+String serializePreservingVisualAppearance(const VisibleSelection& selection, ResolveURLs resolveURLs, SerializeComposedTree serializeComposedTree, Vector<Node*>* nodes)
{
- return serializePreservingVisualAppearanceInternal(selection.start(), selection.end(), nodes,
- AnnotateForInterchange::Yes, ConvertBlocksToInlines::No, resolveURLs, MSOListMode::DoNotPreserve);
+ return serializePreservingVisualAppearanceInternal(selection.start(), selection.end(), nodes, resolveURLs, serializeComposedTree,
+ AnnotateForInterchange::Yes, ConvertBlocksToInlines::No, MSOListMode::DoNotPreserve);
}
@@ -880,8 +964,9 @@
ASSERT(bodyElement);
bodyElement->appendChild(fragment.get());
+ // SerializeComposedTree::No because there can't be a shadow tree in the pasted fragment.
auto result = serializePreservingVisualAppearanceInternal(firstPositionInNode(bodyElement.get()), lastPositionInNode(bodyElement.get()), nullptr,
- AnnotateForInterchange::Yes, ConvertBlocksToInlines::No, ResolveURLs::YesExcludingLocalFileURLsForPrivacy, msoListMode);
+ ResolveURLs::YesExcludingLocalFileURLsForPrivacy, SerializeComposedTree::No, AnnotateForInterchange::Yes, ConvertBlocksToInlines::No, msoListMode);
if (msoListMode == MSOListMode::Preserve) {
StringBuilder builder;
Modified: trunk/Source/WebCore/editing/markup.h (236784 => 236785)
--- trunk/Source/WebCore/editing/markup.h 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/markup.h 2018-10-03 06:28:07 UTC (rev 236785)
@@ -70,8 +70,9 @@
enum class ResolveURLs : uint8_t { No, Yes, YesExcludingLocalFileURLsForPrivacy };
enum class ConvertBlocksToInlines : uint8_t { No, Yes };
+enum class SerializeComposedTree : uint8_t { No, Yes };
WEBCORE_EXPORT String serializePreservingVisualAppearance(const Range&, Vector<Node*>* = nullptr, AnnotateForInterchange = AnnotateForInterchange::No, ConvertBlocksToInlines = ConvertBlocksToInlines::No, ResolveURLs = ResolveURLs::No);
-String serializePreservingVisualAppearance(const VisibleSelection&, ResolveURLs = ResolveURLs::No, Vector<Node*>* = nullptr);
+String serializePreservingVisualAppearance(const VisibleSelection&, ResolveURLs = ResolveURLs::No, SerializeComposedTree = SerializeComposedTree::No, Vector<Node*>* = nullptr);
enum class SerializedNodes : uint8_t { SubtreeIncludingNode, SubtreesOfChildren };
enum class SerializationSyntax : uint8_t { HTML, XML };
Modified: trunk/Source/WebCore/editing/wpe/EditorWPE.cpp (236784 => 236785)
--- trunk/Source/WebCore/editing/wpe/EditorWPE.cpp 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/editing/wpe/EditorWPE.cpp 2018-10-03 06:28:07 UTC (rev 236785)
@@ -64,7 +64,8 @@
{
PasteboardWebContent pasteboardContent;
pasteboardContent.text = selectedTextForDataTransfer();
- pasteboardContent.markup = serializePreservingVisualAppearance(m_frame.selection().selection(), ResolveURLs::YesExcludingLocalFileURLsForPrivacy);
+ pasteboardContent.markup = serializePreservingVisualAppearance(m_frame.selection().selection(), ResolveURLs::YesExcludingLocalFileURLsForPrivacy,
+ m_frame.settings().selectionAcrossShadowBoundariesEnabled() ? SerializeComposedTree::Yes : SerializeComposedTree::No);
pasteboard.write(pasteboardContent);
}
Modified: trunk/Source/WebCore/loader/archive/cf/LegacyWebArchive.cpp (236784 => 236785)
--- trunk/Source/WebCore/loader/archive/cf/LegacyWebArchive.cpp 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/loader/archive/cf/LegacyWebArchive.cpp 2018-10-03 06:28:07 UTC (rev 236785)
@@ -554,7 +554,8 @@
builder.append(documentTypeString(*document));
Vector<Node*> nodeList;
- builder.append(serializePreservingVisualAppearance(frame->selection().selection(), ResolveURLs::No, &nodeList));
+ auto serializeComposedTree = frame->settings().selectionAcrossShadowBoundariesEnabled() ? SerializeComposedTree::Yes : SerializeComposedTree::No;
+ builder.append(serializePreservingVisualAppearance(frame->selection().selection(), ResolveURLs::No, serializeComposedTree, &nodeList));
auto archive = create(builder.toString(), *frame, nodeList, nullptr);
Modified: trunk/Source/WebCore/page/PageSerializer.cpp (236784 => 236785)
--- trunk/Source/WebCore/page/PageSerializer.cpp 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/page/PageSerializer.cpp 2018-10-03 06:28:07 UTC (rev 236785)
@@ -105,7 +105,7 @@
void appendText(StringBuilder&, const Text&) override;
void appendElement(StringBuilder&, const Element&, Namespaces*) override;
void appendCustomAttributes(StringBuilder&, const Element&, Namespaces*) override;
- void appendEndTag(const Element&) override;
+ void appendEndElement(StringBuilder&, const Element&) override;
};
PageSerializer::SerializerMarkupAccumulator::SerializerMarkupAccumulator(PageSerializer& serializer, Document& document, Vector<Node*>* nodes)
@@ -158,10 +158,10 @@
appendAttribute(out, element, Attribute(frameOwnerURLAttributeName(frameOwner), url.string()), namespaces);
}
-void PageSerializer::SerializerMarkupAccumulator::appendEndTag(const Element& element)
+void PageSerializer::SerializerMarkupAccumulator::appendEndElement(StringBuilder& out, const Element& element)
{
if (!shouldIgnoreElement(element))
- MarkupAccumulator::appendEndTag(element);
+ MarkupAccumulator::appendEndElement(out, element);
}
PageSerializer::PageSerializer(Vector<PageSerializer::Resource>& resources)
Modified: trunk/Source/WebCore/testing/Internals.cpp (236784 => 236785)
--- trunk/Source/WebCore/testing/Internals.cpp 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/testing/Internals.cpp 2018-10-03 06:28:07 UTC (rev 236785)
@@ -3449,6 +3449,13 @@
return DOMRect::create(document->frame()->selection().selectionBounds());
}
+void Internals::setSelectionWithoutValidation(Ref<Node> baseNode, unsigned baseOffset, RefPtr<Node> extentNode, unsigned extentOffset)
+{
+ contextDocument()->frame()->selection().moveTo(
+ VisiblePosition { createLegacyEditingPosition(baseNode.ptr(), baseOffset) },
+ VisiblePosition { createLegacyEditingPosition(extentNode.get(), extentOffset) });
+}
+
ExceptionOr<bool> Internals::isPluginUnavailabilityIndicatorObscured(Element& element)
{
if (!is<HTMLPlugInElement>(element))
Modified: trunk/Source/WebCore/testing/Internals.h (236784 => 236785)
--- trunk/Source/WebCore/testing/Internals.h 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/testing/Internals.h 2018-10-03 06:28:07 UTC (rev 236785)
@@ -534,6 +534,7 @@
#endif
ExceptionOr<Ref<DOMRect>> selectionBounds();
+ void setSelectionWithoutValidation(Ref<Node> baseNode, unsigned baseOffset, RefPtr<Node> extentNode, unsigned extentOffset);
ExceptionOr<bool> isPluginUnavailabilityIndicatorObscured(Element&);
ExceptionOr<String> unavailablePluginReplacementText(Element&);
Modified: trunk/Source/WebCore/testing/Internals.idl (236784 => 236785)
--- trunk/Source/WebCore/testing/Internals.idl 2018-10-03 01:59:04 UTC (rev 236784)
+++ trunk/Source/WebCore/testing/Internals.idl 2018-10-03 06:28:07 UTC (rev 236785)
@@ -541,6 +541,7 @@
boolean isPluginSnapshotted(Element element);
[MayThrowException] DOMRect selectionBounds();
+ void setSelectionWithoutValidation(Node baseNode, unsigned long baseOffset, Node? extentNode, unsigned long extentOffset);
[Conditional=MEDIA_SOURCE] void initializeMockMediaSource();
[Conditional=MEDIA_SOURCE] sequence<DOMString> bufferedSamplesForTrackID(SourceBuffer buffer, DOMString trackID);