indexForVisiblePosition should use the root editable element as the scope
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 May 2016 19:51:14 +0000 (19:51 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 May 2016 19:51:14 +0000 (19:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=157611

Reviewed by Darin Adler.

Source/WebCore:

Use the highest editing host instead of the document node as the scope in indexForVisiblePosition
when it's called inside an editable region. This refactoring is necessary to unblock the work to support
undo/redo in VoiceOver after r199030.

We have to workaround a bug in indexForVisiblePosition that it could return a slightly higher index than
the expected value because TextIterator emits an extra new line after a block element with a large margin
at the bottom. Unfortunately, fixing this requires a lot of code changes since the rest of the editing
code assumes this behavior and/or happens to cancel it out with some other quirks.

* editing/ApplyBlockElementCommand.cpp:
(WebCore::ApplyBlockElementCommand::doApply):
* editing/htmlediting.cpp:
(WebCore::indexForVisiblePosition):

LayoutTests:

Rebaselined tests with progressions.

* editing/execCommand/crash-indenting-list-item-expected.txt: Now preseves the selection at the beginning of
the editable region instead of moving it to the end.
* editing/execCommand/format-block-multiple-paragraphs-in-pre-expected.txt: Now preserves selection in more test
cases. This test is the one that required the workaround in ApplyBlockElementCommand::doApply. One of the test
cases would regress and clear the selection without it.
* editing/execCommand/indent-pre-list-expected.txt: Now preserves the selection instead of clearing it.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200787 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/editing/execCommand/crash-indenting-list-item-expected.txt
LayoutTests/editing/execCommand/format-block-multiple-paragraphs-in-pre-expected.txt
LayoutTests/editing/execCommand/indent-pre-list-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/editing/ApplyBlockElementCommand.cpp
Source/WebCore/editing/htmlediting.cpp

index 14173d4..cefa71f 100644 (file)
@@ -1,3 +1,19 @@
+2016-05-12  Ryosuke Niwa  <rniwa@webkit.org>
+
+        indexForVisiblePosition should use the root editable element as the scope
+        https://bugs.webkit.org/show_bug.cgi?id=157611
+
+        Reviewed by Darin Adler.
+
+        Rebaselined tests with progressions.
+
+        * editing/execCommand/crash-indenting-list-item-expected.txt: Now preseves the selection at the beginning of
+        the editable region instead of moving it to the end.
+        * editing/execCommand/format-block-multiple-paragraphs-in-pre-expected.txt: Now preserves selection in more test
+        cases. This test is the one that required the workaround in ApplyBlockElementCommand::doApply. One of the test
+        cases would regress and clear the selection without it.
+        * editing/execCommand/indent-pre-list-expected.txt: Now preserves the selection instead of clearing it.
+
 2016-05-12  Eric Carlson  <eric.carlson@apple.com>
 
         Adjust "main content" video heuristic
index a54e16c..7d23851 100644 (file)
@@ -7,8 +7,8 @@
 |         <ul>
 |           <li>
 |             id="foo"
+|             <#selection-caret>
 |             "PASSED"
-|         <#selection-caret>
 |     "
 "
 |     <script>
index 990f974..61d441f 100644 (file)
@@ -4,7 +4,7 @@ Formatting all paragraphs by h3 yields:
 | "
 "
 | <h3>
-|   "hello"
+|   "<#selection-anchor>hello"
 |   <br>
 |   "
 "
@@ -12,7 +12,7 @@ Formatting all paragraphs by h3 yields:
 |   <br>
 |   "
 "
-|   "webkit"
+|   "webkit<#selection-focus>"
 | "
 "
 
@@ -65,12 +65,11 @@ Formatting all but the first paragraph by h3 yields:
 |   "hello
 "
 |   <h3>
-|     "
+|     "<#selection-anchor>
 "
 |     "world"
 |     "
 "
-|     "webkit"
-|   <#selection-caret>
+|     "webkit<#selection-focus>"
 | "
 "
index 1e04227..753a9dc 100644 (file)
@@ -69,11 +69,11 @@ yields:
 |     <pre>
 |       <blockquote>
 |         style="margin: 0 0 0 40px; border: none; padding: 0px;"
-|         "hello"
+|         "<#selection-anchor>hello"
 |         <br>
 |         "world"
 |         <br>
-|         "webkit"
+|         "webkit<#selection-focus>"
 | "
 "
 
index b0118a4..e621cf6 100644 (file)
@@ -1,3 +1,24 @@
+2016-05-12  Ryosuke Niwa  <rniwa@webkit.org>
+
+        indexForVisiblePosition should use the root editable element as the scope
+        https://bugs.webkit.org/show_bug.cgi?id=157611
+
+        Reviewed by Darin Adler.
+
+        Use the highest editing host instead of the document node as the scope in indexForVisiblePosition
+        when it's called inside an editable region. This refactoring is necessary to unblock the work to support
+        undo/redo in VoiceOver after r199030.
+
+        We have to workaround a bug in indexForVisiblePosition that it could return a slightly higher index than
+        the expected value because TextIterator emits an extra new line after a block element with a large margin
+        at the bottom. Unfortunately, fixing this requires a lot of code changes since the rest of the editing
+        code assumes this behavior and/or happens to cancel it out with some other quirks.
+
+        * editing/ApplyBlockElementCommand.cpp:
+        (WebCore::ApplyBlockElementCommand::doApply):
+        * editing/htmlediting.cpp:
+        (WebCore::indexForVisiblePosition):
+
 2016-05-12  Zalan Bujtas  <zalan@apple.com>
 
         Cleanup RenderObject::containingBlock.
index 7eda8d3..7c93b07 100644 (file)
@@ -97,6 +97,11 @@ void ApplyBlockElementCommand::doApply()
     if (startScope == endScope && startIndex >= 0 && startIndex <= endIndex) {
         VisiblePosition start(visiblePositionForIndex(startIndex, startScope.get()));
         VisiblePosition end(visiblePositionForIndex(endIndex, endScope.get()));
+        // Work around the fact indexForVisiblePosition can return a larger index due to TextIterator
+        // using an extra newline to represent a large margin.
+        // FIXME: Add a new TextIteratorBehavior to suppress it.
+        if (start.isNotNull() && end.isNull())
+            end = lastPositionInNode(endScope.get());
         if (start.isNotNull() && end.isNotNull())
             setEndingSelection(VisibleSelection(start, end, endingSelection().isDirectional()));
     }
index 6735956..bca51c8 100644 (file)
@@ -1133,17 +1133,21 @@ int indexForVisiblePosition(const VisiblePosition& visiblePosition, RefPtr<Conta
     if (visiblePosition.isNull())
         return 0;
 
-    Position p(visiblePosition.deepEquivalent());
-    Document& document = p.anchorNode()->document();
-    ShadowRoot* shadowRoot = p.anchorNode()->containingShadowRoot();
-
-    if (shadowRoot)
-        scope = shadowRoot;
-    else
-        scope = document.documentElement();
+    Position position = visiblePosition.deepEquivalent();
+    auto& document = *position.document();
+
+    Node* editableRoot = highestEditableRoot(position, AXObjectCache::accessibilityEnabled() ? HasEditableAXRole : ContentIsEditable);
+    if (editableRoot && !document.inDesignMode())
+        scope = downcast<ContainerNode>(editableRoot);
+    else {
+        if (position.containerNode()->isInShadowTree())
+            scope = position.containerNode()->containingShadowRoot();
+        else
+            scope = &document;
+    }
 
-    RefPtr<Range> range = Range::create(document, firstPositionInNode(scope.get()), p.parentAnchoredEquivalent());
-    return TextIterator::rangeLength(range.get(), true);
+    auto range = Range::create(document, firstPositionInNode(scope.get()), position.parentAnchoredEquivalent());
+    return TextIterator::rangeLength(range.ptr(), true);
 }
 
 // FIXME: Merge these two functions.