Title: [258871] trunk
Revision
258871
Author
[email protected]
Date
2020-03-23 13:50:15 -0700 (Mon, 23 Mar 2020)

Log Message

Change TextIterator::rangeLength to not require a live range
https://bugs.webkit.org/show_bug.cgi?id=209207

Reviewed by Antti Koivisto.

Source/WebCore:

- Renamed TextIterator::rangeLength to characterCount.

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::rangeMatchesTextNearRange): Use characterCount.
(WebCore::resetNodeAndOffsetForReplacedNode): Ditto.
(WebCore::AXObjectCache::nextCharacterOffset): Ditto.
* accessibility/atk/AXObjectCacheAtk.cpp:
(WebCore::AXObjectCache::nodeTextChangePlatformNotification): Ditto.
* accessibility/atk/WebKitAccessibleHyperlink.cpp:
(rangeLengthForObject): Ditto.
* accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(-[WebAccessibilityObjectWrapper _convertToNSRange:]): Ditto.

* dom/SimpleRange.h: Export another constructor.

* editing/AlternativeTextController.cpp:
(WebCore::AlternativeTextController::applyAlternativeTextToRange):
Use characterCount.
* editing/ApplyStyleCommand.cpp:
(WebCore::ApplyStyleCommand::applyBlockStyle): Ditto.
* editing/CompositeEditCommand.cpp:
(WebCore::CompositeEditCommand::moveParagraphs): Ditto.
* editing/Editing.cpp:
(WebCore::indexForVisiblePosition): Ditto.
* editing/TextCheckingHelper.cpp:
(WebCore::TextCheckingParagraph::rangeLength const): Ditto.
(WebCore::TextCheckingParagraph::offsetTo const): Ditto.
(WebCore::TextCheckingParagraph::checkingStart const): Ditto.
(WebCore::TextCheckingParagraph::checkingEnd const): Ditto.
(WebCore::TextCheckingParagraph::checkingLength const): Ditto.
(WebCore::TextCheckingParagraph::automaticReplacementStart const): Ditto.
(WebCore::TextCheckingParagraph::automaticReplacementLength const): Ditto.
(WebCore::TextCheckingHelper::findFirstMisspellingOrBadGrammar): Ditto.
(WebCore::TextCheckingHelper::isUngrammatical const): Ditto.

* editing/TextIterator.cpp:
(WebCore::TextIterator::rangeLength): Deleted.
(WebCore::characterCount): Like the baove but the argument is SimpleRange
and return is CharacterCount. Even though each individual node is limited
to 32-bit size, ranges covering multiple nodes could have a count of
characters that exceeds 32 bits, so CharacterCount is size_t.
(WebCore::TextIterator::getLocationAndLengthFromRange): Use characterCount.

* editing/TextIterator.h: Added characterCount function,
CharacterCount and CharacterRange types. Removed TextIterator::rangeLength.
Added FIXME comments about the next steps.

* editing/VisiblePosition.cpp:
(WebCore::makeBoundaryPoint): Added.
* editing/VisiblePosition.h: Added makeBoundaryPoint. Also removed
extraneous forward declarations and moved some function bodies out of the
class definition.

* editing/VisibleUnits.cpp:
(WebCore::distanceBetweenPositions): Changed return type to ptrdiff_t.
Use characterCount.
* editing/VisibleUnits.h: Updated for the above.

* editing/cocoa/DataDetection.mm:
(WebCore::detectItemAtPositionWithRange): Use characterCount.
* editing/cocoa/DictionaryLookup.mm:
(WebCore::DictionaryLookup::rangeForSelection): Ditto.
(WebCore::DictionaryLookup::rangeAtHitTestResult): Ditto.
* editing/ios/DictationCommandIOS.cpp:
(WebCore::DictationCommandIOS::doApply): Ditto.
* editing/mac/DictionaryLookupLegacy.mm:
(WebCore::DictionaryLookup::rangeForSelection): Ditto.
(WebCore::DictionaryLookup::rangeAtHitTestResult): Ditto.
* page/EventHandler.cpp:
(WebCore::textDistance): Ditto.

Source/WebKit:

* Shared/EditingRange.cpp:
(WebKit::EditingRange::toRange): Use characterCount.
* WebProcess/WebCoreSupport/WebEditorClient.cpp:
(WebKit::insertionPointFromCurrentSelection): Changed return type to
CharacterCount and use characterCount.
(WebKit::WebEditorClient::supportsGlobalSelection): Tweaked #if.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::targetFrameForEditing): Use characterCount.
* WebProcess/WebPage/glib/WebPageGLib.cpp:
(WebKit::WebPage::platformEditorState const): Ditto.
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::rangeNearPositionMatchesText): Ditto.
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::platformEditorState const): Ditto.

Source/WebKitLegacy/mac:

* WebCoreSupport/WebEditorClient.mm:
(insertionPointFromCurrentSelection): Use characterCount.
(WebEditorClient::requestCandidatesForSelection): Ditto.
* WebView/WebFrame.mm:
(-[WebFrame _convertToDOMRange:rangeIsRelativeTo:]): Ditto.

LayoutTests:

* editing/mac/spelling/autocorrection-contraction-expected.txt: Update these expected
results because of changes to delegate callbacks. The test is still passing and this
change is only in the legacy WebKit case (there is a separate result for modern WebKit).
This seems to be a progression, not evidence of a bug.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (258870 => 258871)


--- trunk/LayoutTests/ChangeLog	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/LayoutTests/ChangeLog	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1,3 +1,15 @@
+2020-03-23  Darin Adler  <[email protected]>
+
+        Change TextIterator::rangeLength to not require a live range
+        https://bugs.webkit.org/show_bug.cgi?id=209207
+
+        Reviewed by Antti Koivisto.
+
+        * editing/mac/spelling/autocorrection-contraction-expected.txt: Update these expected
+        results because of changes to delegate callbacks. The test is still passing and this
+        change is only in the legacy WebKit case (there is a separate result for modern WebKit).
+        This seems to be a progression, not evidence of a bug.
+
 2020-03-23  Rob Buis  <[email protected]>
 
         XMLHttpRequest: getAllResponseHeaders() sorting

Modified: trunk/LayoutTests/editing/mac/spelling/autocorrection-contraction-expected.txt (258870 => 258871)


--- trunk/LayoutTests/editing/mac/spelling/autocorrection-contraction-expected.txt	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/LayoutTests/editing/mac/spelling/autocorrection-contraction-expected.txt	2020-03-23 20:50:15 UTC (rev 258871)
@@ -151,23 +151,10 @@
 EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 6 of #text > DIV > DIV > BODY > HTML > #document to 6 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 7 of #text > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 7 of #text > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > DIV > DIV > BODY > HTML > #document to 6 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
-EDITING DELEGATE: shouldInsertText:would replacingDOMRange:range from 0 of #text > DIV > DIV > BODY > HTML > #document to 6 of #text > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionTyped
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 7 of #text > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > DIV > DIV > BODY > HTML > #document to 6 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 7 of #text > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > DIV > DIV > BODY > HTML > #document to 6 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 6 of #text > DIV > DIV > BODY > HTML > #document to 6 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 8 of #text > DIV > DIV > BODY > HTML > #document to 8 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of DIV > DIV > BODY > HTML > #document to 0 of DIV > DIV > BODY > HTML > #document toDOMRange:range from 5 of #text > DIV > DIV > BODY > HTML > #document to 5 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 5 of #text > DIV > DIV > BODY > HTML > #document to 5 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 7 of #text > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 7 of #text > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 8 of #text > DIV > DIV > BODY > HTML > #document to 8 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 8 of #text > DIV > DIV > BODY > HTML > #document to 8 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 9 of #text > DIV > DIV > BODY > HTML > #document to 9 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
@@ -186,6 +173,19 @@
 EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 13 of #text > DIV > DIV > BODY > HTML > #document to 13 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 14 of #text > DIV > DIV > BODY > HTML > #document to 14 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 14 of #text > DIV > DIV > BODY > HTML > #document to 14 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > DIV > DIV > BODY > HTML > #document to 6 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldInsertText:would replacingDOMRange:range from 0 of #text > DIV > DIV > BODY > HTML > #document to 6 of #text > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionTyped
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 14 of #text > DIV > DIV > BODY > HTML > #document to 14 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > DIV > DIV > BODY > HTML > #document to 6 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 14 of #text > DIV > DIV > BODY > HTML > #document to 14 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > DIV > DIV > BODY > HTML > #document to 6 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of DIV > DIV > BODY > HTML > #document to 0 of DIV > DIV > BODY > HTML > #document toDOMRange:range from 5 of #text > DIV > DIV > BODY > HTML > #document to 5 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 13 of #text > DIV > DIV > BODY > HTML > #document to 13 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 14 of #text > DIV > DIV > BODY > HTML > #document to 14 of #text > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 14 of #text > DIV > DIV > BODY > HTML > #document to 14 of #text > DIV > DIV > BODY > HTML > #document toDOMRange:range from 0 of DIV > DIV > BODY > HTML > #document to 0 of DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification

Modified: trunk/Source/WebCore/ChangeLog (258870 => 258871)


--- trunk/Source/WebCore/ChangeLog	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/ChangeLog	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1,3 +1,81 @@
+2020-03-23  Darin Adler  <[email protected]>
+
+        Change TextIterator::rangeLength to not require a live range
+        https://bugs.webkit.org/show_bug.cgi?id=209207
+
+        Reviewed by Antti Koivisto.
+
+        - Renamed TextIterator::rangeLength to characterCount.
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::rangeMatchesTextNearRange): Use characterCount.
+        (WebCore::resetNodeAndOffsetForReplacedNode): Ditto.
+        (WebCore::AXObjectCache::nextCharacterOffset): Ditto.
+        * accessibility/atk/AXObjectCacheAtk.cpp:
+        (WebCore::AXObjectCache::nodeTextChangePlatformNotification): Ditto.
+        * accessibility/atk/WebKitAccessibleHyperlink.cpp:
+        (rangeLengthForObject): Ditto.
+        * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+        (-[WebAccessibilityObjectWrapper _convertToNSRange:]): Ditto.
+
+        * dom/SimpleRange.h: Export another constructor.
+
+        * editing/AlternativeTextController.cpp:
+        (WebCore::AlternativeTextController::applyAlternativeTextToRange):
+        Use characterCount.
+        * editing/ApplyStyleCommand.cpp:
+        (WebCore::ApplyStyleCommand::applyBlockStyle): Ditto.
+        * editing/CompositeEditCommand.cpp:
+        (WebCore::CompositeEditCommand::moveParagraphs): Ditto.
+        * editing/Editing.cpp:
+        (WebCore::indexForVisiblePosition): Ditto.
+        * editing/TextCheckingHelper.cpp:
+        (WebCore::TextCheckingParagraph::rangeLength const): Ditto.
+        (WebCore::TextCheckingParagraph::offsetTo const): Ditto.
+        (WebCore::TextCheckingParagraph::checkingStart const): Ditto.
+        (WebCore::TextCheckingParagraph::checkingEnd const): Ditto.
+        (WebCore::TextCheckingParagraph::checkingLength const): Ditto.
+        (WebCore::TextCheckingParagraph::automaticReplacementStart const): Ditto.
+        (WebCore::TextCheckingParagraph::automaticReplacementLength const): Ditto.
+        (WebCore::TextCheckingHelper::findFirstMisspellingOrBadGrammar): Ditto.
+        (WebCore::TextCheckingHelper::isUngrammatical const): Ditto.
+
+        * editing/TextIterator.cpp:
+        (WebCore::TextIterator::rangeLength): Deleted.
+        (WebCore::characterCount): Like the baove but the argument is SimpleRange
+        and return is CharacterCount. Even though each individual node is limited
+        to 32-bit size, ranges covering multiple nodes could have a count of
+        characters that exceeds 32 bits, so CharacterCount is size_t.
+        (WebCore::TextIterator::getLocationAndLengthFromRange): Use characterCount.
+
+        * editing/TextIterator.h: Added characterCount function,
+        CharacterCount and CharacterRange types. Removed TextIterator::rangeLength.
+        Added FIXME comments about the next steps.
+
+        * editing/VisiblePosition.cpp:
+        (WebCore::makeBoundaryPoint): Added.
+        * editing/VisiblePosition.h: Added makeBoundaryPoint. Also removed
+        extraneous forward declarations and moved some function bodies out of the
+        class definition.
+
+        * editing/VisibleUnits.cpp:
+        (WebCore::distanceBetweenPositions): Changed return type to ptrdiff_t.
+        Use characterCount.
+        * editing/VisibleUnits.h: Updated for the above.
+
+        * editing/cocoa/DataDetection.mm:
+        (WebCore::detectItemAtPositionWithRange): Use characterCount.
+        * editing/cocoa/DictionaryLookup.mm:
+        (WebCore::DictionaryLookup::rangeForSelection): Ditto.
+        (WebCore::DictionaryLookup::rangeAtHitTestResult): Ditto.
+        * editing/ios/DictationCommandIOS.cpp:
+        (WebCore::DictationCommandIOS::doApply): Ditto.
+        * editing/mac/DictionaryLookupLegacy.mm:
+        (WebCore::DictionaryLookup::rangeForSelection): Ditto.
+        (WebCore::DictionaryLookup::rangeAtHitTestResult): Ditto.
+        * page/EventHandler.cpp:
+        (WebCore::textDistance): Ditto.
+
 2020-03-23  youenn fablet  <[email protected]>
 
         Rename blankURL to aboutBlankURL

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (258870 => 258871)


--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1938,18 +1938,16 @@
     unsigned textLength = matchText.length();
     auto startPosition = visiblePositionForPositionWithOffset(createLegacyEditingPosition(originalRange.start), -textLength);
     auto endPosition = visiblePositionForPositionWithOffset(createLegacyEditingPosition(originalRange.start), 2 * textLength);
-
     if (startPosition.isNull())
         startPosition = firstPositionInOrBeforeNode(originalRange.start.container.ptr());
     if (endPosition.isNull())
         endPosition = lastPositionInOrAfterNode(originalRange.end.container.ptr());
 
-    auto searchRange = Range::create(m_document, startPosition, endPosition);
-    if (searchRange->collapsed())
+    auto searchRange = SimpleRange { *makeBoundaryPoint(startPosition), *makeBoundaryPoint(endPosition) };
+    if (searchRange.collapsed())
         return WTF::nullopt;
 
-    auto range = Range::create(m_document, startPosition, createLegacyEditingPosition(originalRange.start));
-    unsigned targetOffset = TextIterator::rangeLength(range.ptr(), true);
+    auto targetOffset = characterCount({ searchRange.start, originalRange.start }, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
     return findClosestPlainText(searchRange, matchText, { }, targetOffset);
 }
 
@@ -1992,12 +1990,11 @@
 static Node* resetNodeAndOffsetForReplacedNode(Node* replacedNode, int& offset, int characterCount)
 {
     // Use this function to include the replaced node itself in the range we are creating.
-    if (!replacedNode)
+    auto nodeRange = AXObjectCache::rangeForNodeContents(replacedNode);
+    if (!nodeRange)
         return nullptr;
-    
-    RefPtr<Range> nodeRange = AXObjectCache::rangeForNodeContents(replacedNode);
-    int nodeLength = TextIterator::rangeLength(nodeRange.get());
-    offset = characterCount <= nodeLength ? replacedNode->computeNodeIndex() : replacedNode->computeNodeIndex() + 1;
+    bool isInNode = static_cast<unsigned>(characterCount) <= WebCore::characterCount(*nodeRange);
+    offset = replacedNode->computeNodeIndex() + (isInNode ? 0 : 1);
     return replacedNode->parentNode();
 }
 
@@ -2413,14 +2410,16 @@
         return CharacterOffset();
     
     // We don't always move one 'character' at a time since there might be composed characters.
-    int nextOffset = Position::uncheckedNextOffset(characterOffset.node, characterOffset.offset);
+    unsigned nextOffset = Position::uncheckedNextOffset(characterOffset.node, characterOffset.offset);
     CharacterOffset next = characterOffsetForNodeAndOffset(*characterOffset.node, nextOffset);
     
     // To be consistent with VisiblePosition, we should consider the case that current node end to next node start counts 1 offset.
     if (!ignoreNextNodeStart && !next.isNull() && !isReplacedNodeOrBR(next.node) && next.node != characterOffset.node) {
-        int length = TextIterator::rangeLength(rangeForUnorderedCharacterOffsets(characterOffset, next).get());
-        if (length > nextOffset - characterOffset.offset)
-            next = characterOffsetForNodeAndOffset(*next.node, 0, TraverseOptionIncludeStart);
+        if (auto range = rangeForUnorderedCharacterOffsets(characterOffset, next)) {
+            auto length = characterCount(*range);
+            if (length > nextOffset - characterOffset.offset)
+                next = characterOffsetForNodeAndOffset(*next.node, 0, TraverseOptionIncludeStart);
+        }
     }
     
     return next;

Modified: trunk/Source/WebCore/accessibility/atk/AXObjectCacheAtk.cpp (258870 => 258871)


--- trunk/Source/WebCore/accessibility/atk/AXObjectCacheAtk.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/accessibility/atk/AXObjectCacheAtk.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -355,7 +355,7 @@
         // the current accessibility object to ensure we emit the
         // right offset (e.g. multiline text areas).
         auto range = Range::create(document, node->parentNode(), 0, node, 0);
-        offsetToEmit = offset + TextIterator::rangeLength(range.ptr());
+        offsetToEmit = offset + characterCount(range.get());
     }
 
     g_signal_emit_by_name(wrapper, detail.data(), offsetToEmit, textToEmit.length(), textToEmit.utf8().data());

Modified: trunk/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.cpp (258870 => 258871)


--- trunk/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -154,7 +154,7 @@
 static gint rangeLengthForObject(AccessibilityObject& obj, Range* range)
 {
     // This is going to be the actual length in most of the cases
-    int baseLength = TextIterator::rangeLength(range, true);
+    int baseLength = characterCount(*range, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
 
     // Check whether the current hyperlink belongs to a list item.
     // If so, we need to consider the length of the item's marker

Modified: trunk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.cpp (258870 => 258871)


--- trunk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -410,9 +410,9 @@
 
     // Set values for start offsets and calculate initial range length.
     // These values might be adjusted later to cover special cases.
-    startOffset = webCoreOffsetToAtkOffset(coreObject, TextIterator::rangeLength(rangeInParent.ptr(), true));
+    startOffset = webCoreOffsetToAtkOffset(coreObject, characterCount(rangeInParent.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions));
     auto nodeRange = Range::create(node->document(), nodeRangeStart, nodeRangeEnd);
-    int rangeLength = TextIterator::rangeLength(nodeRange.ptr(), true);
+    int rangeLength = characterCount(nodeRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
 
     // Special cases that are only relevant when working with *_END boundaries.
     if (selection.affinity() == UPSTREAM) {

Modified: trunk/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.cpp (258870 => 258871)


--- trunk/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -247,10 +247,10 @@
         offset = 0;
     else if (!isStartOfLine(endPosition)) {
         RefPtr<Range> range = makeRange(startPosition, endPosition.previous());
-        offset = TextIterator::rangeLength(range.get(), true) + 1;
+        offset = (range ? characterCount(*range, TextIteratorEmitsCharactersBetweenAllVisiblePositions) : 0) + 1;
     } else {
         RefPtr<Range> range = makeRange(startPosition, endPosition);
-        offset = TextIterator::rangeLength(range.get(), true);
+        offset = range ? characterCount(*range, TextIteratorEmitsCharactersBetweenAllVisiblePositions) : 0;
     }
 
     return firstUnignoredParent;

Modified: trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm (258870 => 258871)


--- trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm	2020-03-23 20:50:15 UTC (rev 258871)
@@ -2310,30 +2310,30 @@
     return [array autorelease];
 }
 
-- (NSRange)_convertToNSRange:(Range *)range
+- (NSRange)_convertToNSRange:(Range *)liveRange
 {
-    if (!range)
+    if (!liveRange)
         return NSMakeRange(NSNotFound, 0);
 
-    Document* document = self.axBackingObject->document();
-    Element* selectionRoot = document->frame()->selection().selection().rootEditableElement();
-    Element* scope = selectionRoot ? selectionRoot : document->documentElement();
+    auto range = SimpleRange { *liveRange };
 
+    auto& document = range.start.document();
+    auto* frame = document.frame();
+    if (!frame)
+        return NSMakeRange(NSNotFound, 0);
+
+    auto* rootEditableElement = frame->selection().selection().rootEditableElement();
+    auto* scope = rootEditableElement ? rootEditableElement : document.documentElement();
+    if (!scope)
+        return NSMakeRange(NSNotFound, 0);
+
     // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
-    // that is not inside the current editable region.  These checks ensure we don't produce
+    // that is not inside the current editable region. These checks ensure we don't produce
     // potentially invalid data when responding to such requests.
-    if (&range->startContainer() != scope && !range->startContainer().isDescendantOf(scope))
+    if (!scope->contains(range.start.container.ptr()) || !scope->contains(range.end.container.ptr()))
         return NSMakeRange(NSNotFound, 0);
-    if (&range->endContainer() != scope && !range->endContainer().isDescendantOf(scope))
-        return NSMakeRange(NSNotFound, 0);
 
-    auto testRange = Range::create(scope->document(), scope, 0, &range->startContainer(), range->startOffset());
-    ASSERT(&testRange->startContainer() == scope);
-    int startPosition = TextIterator::rangeLength(testRange.ptr());
-    testRange->setEnd(range->endContainer(), range->endOffset());
-    ASSERT(&testRange->startContainer() == scope);
-    int endPosition = TextIterator::rangeLength(testRange.ptr());
-    return NSMakeRange(startPosition, endPosition - startPosition);
+    return NSMakeRange(characterCount({ { *scope, 0 }, range.start }), characterCount(range));
 }
 
 - (RefPtr<Range>)_convertToDOMRange:(NSRange)nsrange

Modified: trunk/Source/WebCore/dom/SimpleRange.h (258870 => 258871)


--- trunk/Source/WebCore/dom/SimpleRange.h	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/dom/SimpleRange.h	2020-03-23 20:50:15 UTC (rev 258871)
@@ -42,7 +42,7 @@
 
     bool collapsed() const { return start == end; }
 
-    SimpleRange(const BoundaryPoint&, const BoundaryPoint&);
+    WEBCORE_EXPORT SimpleRange(const BoundaryPoint&, const BoundaryPoint&);
     WEBCORE_EXPORT SimpleRange(BoundaryPoint&&, BoundaryPoint&&);
 
     // Convenience overloads to help with transition from using a lot of live ranges.

Modified: trunk/Source/WebCore/editing/AlternativeTextController.cpp (258870 => 258871)


--- trunk/Source/WebCore/editing/AlternativeTextController.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/AlternativeTextController.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -580,52 +580,38 @@
 
 void AlternativeTextController::applyAlternativeTextToRange(const Range& range, const String& alternative, AlternativeTextType alternativeType, OptionSet<DocumentMarker::MarkerType> markerTypesToAdd)
 {
-    auto paragraphRangeContainingCorrection = range.cloneRange();
-
-    setStart(paragraphRangeContainingCorrection.ptr(), startOfParagraph(range.startPosition()));
-    setEnd(paragraphRangeContainingCorrection.ptr(), endOfParagraph(range.endPosition()));
-
     // After we replace the word at range rangeWithAlternative, we need to add markers to that range.
-    // However, once the replacement took place, the value of rangeWithAlternative is not valid anymore.
-    // So before we carry out the replacement, we need to store the start position of rangeWithAlternative
-    // relative to the start position of the containing paragraph. We use correctionStartOffsetInParagraph
-    // to store this value. In order to obtain this offset, we need to first create a range
-    // which spans from the start of paragraph to the start position of rangeWithAlternative.
-    auto correctionStartOffsetInParagraphAsRange = Range::create(paragraphRangeContainingCorrection->startContainer().document(), paragraphRangeContainingCorrection->startPosition(), paragraphRangeContainingCorrection->startPosition());
+    // So before we carry out the replacement,store the start position relative to the start position
+    // of the containing paragraph.
 
-    Position startPositionOfRangeWithAlternative = range.startPosition();
-    if (!startPositionOfRangeWithAlternative.containerNode())
+    // Take note of the location of autocorrection so that we can add marker after the replacement took place.
+    auto correctionStartPosition = range.startPosition();
+    auto correctionStart { makeBoundaryPoint(correctionStartPosition) };
+    auto paragraphStart { makeBoundaryPoint(startOfParagraph(correctionStartPosition)) };
+    if (!correctionStart || !paragraphStart)
         return;
-    auto setEndResult = correctionStartOffsetInParagraphAsRange->setEnd(*startPositionOfRangeWithAlternative.containerNode(), startPositionOfRangeWithAlternative.computeOffsetInContainerNode());
-    if (setEndResult.hasException())
-        return;
+    auto treeScopeRoot = makeRef(correctionStart->container->treeScope().rootNode());
+    auto treeScopeStart = BoundaryPoint { treeScopeRoot.get(), 0 };
+    auto correctionOffsetInParagraph = characterCount({ *paragraphStart, *correctionStart });
+    auto paragraphOffsetInTreeScope = characterCount({ treeScopeStart, *paragraphStart });
 
-    // Take note of the location of autocorrection so that we can add marker after the replacement took place.
-    int correctionStartOffsetInParagraph = TextIterator::rangeLength(correctionStartOffsetInParagraphAsRange.ptr());
+    // Clone the range, since the caller of may keep a refernece to the original range and modify it.
+    SpellingCorrectionCommand::create(range.cloneRange(), alternative)->apply();
 
-    // Clone the range, since the caller of this method may want to keep the original range around.
-    auto rangeWithAlternative = range.cloneRange();
-
-    ContainerNode& rootNode = paragraphRangeContainingCorrection->startContainer().treeScope().rootNode();
-    int paragraphStartIndex = TextIterator::rangeLength(Range::create(rootNode.document(), &rootNode, 0, &paragraphRangeContainingCorrection->startContainer(), paragraphRangeContainingCorrection->startOffset()).ptr());
-    SpellingCorrectionCommand::create(rangeWithAlternative, alternative)->apply();
     // Recalculate pragraphRangeContainingCorrection, since SpellingCorrectionCommand modified the DOM, such that the original paragraphRangeContainingCorrection is no longer valid. Radar: 10305315 Bugzilla: 89526
-    auto updatedParagraphRangeContainingCorrection = TextIterator::rangeFromLocationAndLength(&rootNode, paragraphStartIndex, correctionStartOffsetInParagraph + alternative.length());
+    auto updatedParagraphRangeContainingCorrection = TextIterator::rangeFromLocationAndLength(treeScopeRoot.ptr(), paragraphOffsetInTreeScope, correctionOffsetInParagraph + alternative.length());
     if (!updatedParagraphRangeContainingCorrection)
         return;
-
     setEnd(updatedParagraphRangeContainingCorrection.get(), m_frame.selection().selection().start());
-    RefPtr<Range> replacementRange = TextIterator::subrange(*updatedParagraphRangeContainingCorrection, correctionStartOffsetInParagraph, alternative.length());
-    String newText = plainText(replacementRange.get());
+    auto replacementRange = TextIterator::subrange(*updatedParagraphRangeContainingCorrection, correctionOffsetInParagraph, alternative.length());
 
     // Check to see if replacement succeeded.
-    if (newText != alternative)
+    if (plainText(replacementRange.get()) != alternative)
         return;
 
-    DocumentMarkerController& markers = replacementRange->startContainer().document().markers();
-
+    auto& markers = replacementRange->ownerDocument().markers();
     for (auto markerType : markerTypesToAdd)
-        markers.addMarker(*replacementRange, markerType, markerDescriptionForAppliedAlternativeText(alternativeType, markerType));
+        markers.addMarker(replacementRange, markerType, markerDescriptionForAppliedAlternativeText(alternativeType, markerType));
 }
 
 #endif

Modified: trunk/Source/WebCore/editing/ApplyStyleCommand.cpp (258870 => 258871)


--- trunk/Source/WebCore/editing/ApplyStyleCommand.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/ApplyStyleCommand.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -223,19 +223,14 @@
 
 void ApplyStyleCommand::applyBlockStyle(EditingStyle& style)
 {
-    // update document layout once before removing styles
-    // so that we avoid the expense of updating before each and every call
-    // to check a computed style
+    // Update document layout once before removing styles so that we avoid the expense of
+    // updating before each and every call to check a computed style.
     document().updateLayoutIgnorePendingStylesheets();
 
-    // get positions we want to use for applying style
     Position start = startPosition();
     Position end = endPosition();
-    if (comparePositions(end, start) < 0) {
-        Position swap = start;
-        start = end;
-        end = swap;
-    }
+    if (comparePositions(end, start) < 0)
+        std::swap(start, end);
 
     VisiblePosition visibleStart(start);
     VisiblePosition visibleEnd(end);
@@ -246,15 +241,19 @@
     // Save and restore the selection endpoints using their indices in the editable root, since
     // addBlockStyleIfNeeded may moveParagraphs, which can remove these endpoints.
     // Calculate start and end indices from the start of the tree that they're in.
-    auto* scope = highestEditableRoot(visibleStart.deepEquivalent());
+    auto scope = makeRefPtr(highestEditableRoot(visibleStart.deepEquivalent()));
     if (!scope)
         return;
 
-    auto startRange = Range::create(document(), firstPositionInNode(scope), visibleStart.deepEquivalent().parentAnchoredEquivalent());
-    auto endRange = Range::create(document(), firstPositionInNode(scope), visibleEnd.deepEquivalent().parentAnchoredEquivalent());
-    int startIndex = TextIterator::rangeLength(startRange.ptr(), true);
-    int endIndex = TextIterator::rangeLength(endRange.ptr(), true);
+    auto scopeStart = BoundaryPoint { *scope, 0 };
+    auto startBoundaryPoint = makeBoundaryPoint(visibleStart.deepEquivalent().parentAnchoredEquivalent());
+    auto endBoundaryPoint = makeBoundaryPoint(visibleEnd.deepEquivalent().parentAnchoredEquivalent());
+    if (!startBoundaryPoint || !endBoundaryPoint)
+        return;
 
+    auto startIndex = characterCount({ scopeStart, *startBoundaryPoint }, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
+    auto endIndex = characterCount({ scopeStart, *endBoundaryPoint }, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
+
     VisiblePosition paragraphStart(startOfParagraph(visibleStart));
     VisiblePosition nextParagraphStart(endOfParagraph(paragraphStart).next());
     if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd))
@@ -285,8 +284,8 @@
     }
     
     {
-        auto startRange = TextIterator::rangeFromLocationAndLength(scope, startIndex, 0, true);
-        auto endRange = TextIterator::rangeFromLocationAndLength(scope, endIndex, 0, true);
+        auto startRange = TextIterator::rangeFromLocationAndLength(scope.get(), startIndex, 0, true);
+        auto endRange = TextIterator::rangeFromLocationAndLength(scope.get(), endIndex, 0, true);
         if (startRange && endRange)
             updateStartEnd(startRange->startPosition(), endRange->startPosition());
     }

Modified: trunk/Source/WebCore/editing/CompositeEditCommand.cpp (258870 => 258871)


--- trunk/Source/WebCore/editing/CompositeEditCommand.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/CompositeEditCommand.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1417,7 +1417,6 @@
     
     int startIndex = -1;
     int endIndex = -1;
-    int destinationIndex = -1;
     bool originalIsDirectional = endingSelection().isDirectional();
     if (preserveSelection && !endingSelection().isNone()) {
         VisiblePosition visibleStart = endingSelection().visibleStart();
@@ -1432,18 +1431,22 @@
             
             startIndex = 0;
             if (startInParagraph) {
-                auto startRange = Range::create(document(), startOfParagraphToMove.deepEquivalent().parentAnchoredEquivalent(), visibleStart.deepEquivalent().parentAnchoredEquivalent());
-                startIndex = TextIterator::rangeLength(startRange.ptr(), true);
+                auto paragraphStart = makeBoundaryPoint(startOfParagraphToMove.deepEquivalent().parentAnchoredEquivalent());
+                auto selectionStart = makeBoundaryPoint(visibleStart.deepEquivalent().parentAnchoredEquivalent());
+                if (paragraphStart && selectionStart)
+                    startIndex = characterCount({ *paragraphStart, *selectionStart }, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
             }
 
             endIndex = 0;
             if (endInParagraph) {
-                auto endRange = Range::create(document(), startOfParagraphToMove.deepEquivalent().parentAnchoredEquivalent(), visibleEnd.deepEquivalent().parentAnchoredEquivalent());
-                endIndex = TextIterator::rangeLength(endRange.ptr(), true);
+                auto paragraphStart = makeBoundaryPoint(startOfParagraphToMove.deepEquivalent().parentAnchoredEquivalent());
+                auto selectionEnd = makeBoundaryPoint(visibleEnd.deepEquivalent().parentAnchoredEquivalent());
+                if (paragraphStart && selectionEnd)
+                    endIndex = characterCount({ *paragraphStart, *selectionEnd }, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
             }
         }
     }
-    
+
     VisiblePosition beforeParagraph = startOfParagraphToMove.previous(CannotCrossEditingBoundary);
     VisiblePosition afterParagraph(endOfParagraphToMove.next(CannotCrossEditingBoundary));
 
@@ -1478,9 +1481,9 @@
         // The moved paragraph should assume the block style of the destination.
         styleInEmptyParagraph->removeBlockProperties();
     }
-    
+
     // FIXME (5098931): We should add a new insert action "WebViewInsertActionMoved" and call shouldInsertFragment here.
-    
+
     setEndingSelection(VisibleSelection(start, end, DOWNSTREAM));
     frame().editor().clearMisspellingsAndBadGrammar(endingSelection());
     deleteSelection(false, false, false, false);
@@ -1509,8 +1512,7 @@
     if (!editableRoot)
         editableRoot = &document();
 
-    auto startToDestinationRange = Range::create(document(), firstPositionInNode(editableRoot.get()), destination.deepEquivalent().parentAnchoredEquivalent());
-    destinationIndex = TextIterator::rangeLength(startToDestinationRange.ptr(), true);
+    auto destinationIndex = characterCount({ { *editableRoot, 0 }, *makeBoundaryPoint(destination.deepEquivalent().parentAnchoredEquivalent()) }, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
 
     setEndingSelection(VisibleSelection(destination, originalIsDirectional));
     ASSERT(endingSelection().isCaretOrRange());

Modified: trunk/Source/WebCore/editing/Editing.cpp (258870 => 258871)


--- trunk/Source/WebCore/editing/Editing.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/Editing.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1083,15 +1083,23 @@
             scope = &document;
     }
 
-    auto range = Range::create(document, firstPositionInNode(scope.get()), position.parentAnchoredEquivalent());
-    return TextIterator::rangeLength(range.ptr(), true);
+    auto start = makeBoundaryPoint(firstPositionInNode(scope.get()));
+    auto end = makeBoundaryPoint(position.parentAnchoredEquivalent());
+    if (!start || !end)
+        return 0;
+
+    return characterCount({ *start, *end }, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
 }
 
 // FIXME: Merge this function with the one above.
 int indexForVisiblePosition(Node& node, const VisiblePosition& visiblePosition, bool forSelectionPreservation)
 {
-    auto range = Range::create(node.document(), firstPositionInNode(&node), visiblePosition.deepEquivalent().parentAnchoredEquivalent());
-    return TextIterator::rangeLength(range.ptr(), forSelectionPreservation);
+    auto start = makeBoundaryPoint(firstPositionInNode(&node));
+    auto end = makeBoundaryPoint(visiblePosition.deepEquivalent().parentAnchoredEquivalent());
+    if (!start || !end)
+        return 0;
+
+    return characterCount({ *start, *end }, forSelectionPreservation ? TextIteratorEmitsCharactersBetweenAllVisiblePositions : TextIteratorDefaultBehavior);
 }
 
 VisiblePosition visiblePositionForPositionWithOffset(const VisiblePosition& position, int offset)

Modified: trunk/Source/WebCore/editing/TextCheckingHelper.cpp (258870 => 258871)


--- trunk/Source/WebCore/editing/TextCheckingHelper.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/TextCheckingHelper.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -148,7 +148,7 @@
 
 int TextCheckingParagraph::rangeLength() const
 {
-    return TextIterator::rangeLength(&paragraphRange());
+    return characterCount(paragraphRange());
 }
 
 Range& TextCheckingParagraph::paragraphRange() const
@@ -165,14 +165,11 @@
 
 ExceptionOr<int> TextCheckingParagraph::offsetTo(const Position& position) const
 {
-    if (!position.containerNode())
+    auto start = makeBoundaryPoint(paragraphRange().startPosition());
+    auto end = makeBoundaryPoint(position);
+    if (!start || !end)
         return Exception { TypeError };
-
-    auto range = offsetAsRange().cloneRange();
-    auto result = range->setEnd(*position.containerNode(), position.computeOffsetInContainerNode());
-    if (result.hasException())
-        return result.releaseException();
-    return TextIterator::rangeLength(range.ptr());
+    return characterCount({ *start, *end });
 }
 
 bool TextCheckingParagraph::isEmpty() const
@@ -200,7 +197,7 @@
 int TextCheckingParagraph::checkingStart() const
 {
     if (!m_checkingStart)
-        m_checkingStart = TextIterator::rangeLength(&offsetAsRange());
+        m_checkingStart = characterCount(offsetAsRange());
     return *m_checkingStart;
 }
 
@@ -207,7 +204,7 @@
 int TextCheckingParagraph::checkingEnd() const
 {
     if (!m_checkingEnd)
-        m_checkingEnd = checkingStart() + TextIterator::rangeLength(m_checkingRange.ptr());
+        m_checkingEnd = checkingStart() + checkingLength();
     return *m_checkingEnd;
 }
 
@@ -214,7 +211,7 @@
 int TextCheckingParagraph::checkingLength() const
 {
     if (!m_checkingLength)
-        m_checkingLength = TextIterator::rangeLength(m_checkingRange.ptr());
+        m_checkingLength = characterCount(m_checkingRange);
     return *m_checkingLength;
 }
 
@@ -223,8 +220,12 @@
     if (m_automaticReplacementStart)
         return *m_automaticReplacementStart;
 
-    auto startOffsetRange = Range::create(paragraphRange().startContainer().document(), paragraphRange().startPosition(), m_automaticReplacementRange->startPosition());
-    m_automaticReplacementStart = TextIterator::rangeLength(startOffsetRange.ptr());
+    auto start = makeBoundaryPoint(paragraphRange().startPosition());
+    auto end = makeBoundaryPoint(m_automaticReplacementRange->startPosition());
+    if (!start || !end)
+        return 0;
+
+    m_automaticReplacementStart = characterCount({ *start, *end });
     return *m_automaticReplacementStart;
 }
 
@@ -233,8 +234,7 @@
     if (m_automaticReplacementLength)
         return *m_automaticReplacementLength;
 
-    auto endOffsetRange = Range::create(paragraphRange().startContainer().document(), paragraphRange().startPosition(), m_automaticReplacementRange->endPosition());
-    m_automaticReplacementLength = TextIterator::rangeLength(endOffsetRange.ptr()) - automaticReplacementStart();
+    m_automaticReplacementLength = characterCount(m_automaticReplacementRange);
     return *m_automaticReplacementLength;
 }
 
@@ -323,25 +323,23 @@
     // since we will want to ignore results in this area.
     Ref<Range> paragraphRange = m_range->cloneRange();
     setStart(paragraphRange.ptr(), startOfParagraph(m_range->startPosition()));
-    int totalRangeLength = TextIterator::rangeLength(paragraphRange.ptr());
+    auto totalRangeLength = characterCount(paragraphRange);
     setEnd(paragraphRange.ptr(), endOfParagraph(m_range->startPosition()));
     
-    Ref<Range> offsetAsRange = Range::create(paragraphRange->startContainer().document(), paragraphRange->startPosition(), m_range->startPosition());
-    int rangeStartOffset = TextIterator::rangeLength(offsetAsRange.ptr());
-    int totalLengthProcessed = 0;
+    auto rangeStartOffset = characterCount({ *makeBoundaryPoint(paragraphRange->startPosition()), *makeBoundaryPoint(m_range->startPosition()) });
+    CharacterCount totalLengthProcessed = 0;
     
     bool firstIteration = true;
     bool lastIteration = false;
     while (totalLengthProcessed < totalRangeLength) {
         // Iterate through the search range by paragraphs, checking each one for spelling and grammar.
-        int currentLength = TextIterator::rangeLength(paragraphRange.ptr());
+        auto currentLength = characterCount(paragraphRange);
         int currentStartOffset = firstIteration ? rangeStartOffset : 0;
         int currentEndOffset = currentLength;
         if (inSameParagraph(paragraphRange->startPosition(), m_range->endPosition())) {
             // Determine the character offset from the end of the original search range to the end of the paragraph,
             // since we will want to ignore results in this area.
-            auto endOffsetAsRange = Range::create(paragraphRange->startContainer().document(), paragraphRange->startPosition(), m_range->endPosition());
-            currentEndOffset = TextIterator::rangeLength(endOffsetAsRange.ptr());
+            currentEndOffset = characterCount({ *makeBoundaryPoint(paragraphRange->startPosition()), *makeBoundaryPoint(m_range->endPosition()) });
             lastIteration = true;
         }
         if (currentStartOffset < currentEndOffset) {
@@ -399,10 +397,8 @@
 
                 if (!misspelledWord.isEmpty() && (!checkGrammar || badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) {
                     int spellingOffset = spellingLocation - currentStartOffset;
-                    if (!firstIteration) {
-                        auto paragraphOffsetAsRange = Range::create(paragraphRange->startContainer().document(), m_range->startPosition(), paragraphRange->startPosition());
-                        spellingOffset += TextIterator::rangeLength(paragraphOffsetAsRange.ptr());
-                    }
+                    if (!firstIteration)
+                        spellingOffset += characterCount({ *makeBoundaryPoint(m_range->startPosition()), *makeBoundaryPoint(paragraphRange->startPosition()) });
                     outIsSpelling = true;
                     outFirstFoundOffset = spellingOffset;
                     firstFoundItem = misspelledWord;
@@ -410,10 +406,8 @@
                 }
                 if (checkGrammar && !badGrammarPhrase.isEmpty()) {
                     int grammarPhraseOffset = grammarPhraseLocation - currentStartOffset;
-                    if (!firstIteration) {
-                        auto paragraphOffsetAsRange = Range::create(paragraphRange->startContainer().document(), m_range->startPosition(), paragraphRange->startPosition());
-                        grammarPhraseOffset += TextIterator::rangeLength(paragraphOffsetAsRange.ptr());
-                    }
+                    if (!firstIteration)
+                        grammarPhraseOffset += characterCount({ *makeBoundaryPoint(m_range->startPosition()), *makeBoundaryPoint(paragraphRange->startPosition()) });
                     outIsSpelling = false;
                     outFirstFoundOffset = grammarPhraseOffset;
                     firstFoundItem = badGrammarPhrase;
@@ -556,7 +550,7 @@
         return false;
     
     // Bad grammar at start of range, but end of bad grammar is before or after end of range
-    if (grammarDetail.length != TextIterator::rangeLength(m_range.ptr()))
+    if (static_cast<unsigned>(grammarDetail.length) != characterCount(m_range))
         return false;
     
     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).

Modified: trunk/Source/WebCore/editing/TextIterator.cpp (258870 => 258871)


--- trunk/Source/WebCore/editing/TextIterator.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/TextIterator.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -2343,12 +2343,10 @@
 
 // --------
 
-int TextIterator::rangeLength(const Range* range, bool forSelectionPreservation)
+CharacterCount characterCount(const SimpleRange& range, TextIteratorBehavior behavior)
 {
-    if (!range)
-        return 0;
-    unsigned length = 0;
-    for (TextIterator it(*range, forSelectionPreservation ? TextIteratorEmitsCharactersBetweenAllVisiblePositions : TextIteratorDefaultBehavior); !it.atEnd(); it.advance())
+    CharacterCount length = 0;
+    for (TextIterator it(range, behavior); !it.atEnd(); it.advance())
         length += it.text().length();
     return length;
 }
@@ -2456,21 +2454,16 @@
 
     // The critical assumption is that this only gets called with ranges that
     // concentrate on a given area containing the selection root. This is done
-    // because of text fields and textareas. The DOM for those is not
-    // directly in the document DOM, so ensure that the range does not cross a
-    // boundary of one of those.
+    // because of text fields and textareas. The DOM for those is not directly
+    // in the document DOM, so ensure that the range does not cross a boundary
+    // of one of those.
     if (&range->startContainer() != scope && !range->startContainer().isDescendantOf(scope))
         return false;
     if (&range->endContainer() != scope && !range->endContainer().isDescendantOf(scope))
         return false;
 
-    Ref<Range> testRange = Range::create(scope->document(), scope, 0, &range->startContainer(), range->startOffset());
-    ASSERT(&testRange->startContainer() == scope);
-    location = TextIterator::rangeLength(testRange.ptr());
-
-    testRange->setEnd(range->endContainer(), range->endOffset());
-    ASSERT(&testRange->startContainer() == scope);
-    length = TextIterator::rangeLength(testRange.ptr()) - location;
+    location = characterCount({ { *scope, 0 }, { range->startContainer(), range->startOffset() } });
+    length = characterCount({ { *scope, 0 }, { range->endContainer(), range->endOffset() } }) - location;
     return true;
 }
 

Modified: trunk/Source/WebCore/editing/TextIterator.h (258870 => 258871)


--- trunk/Source/WebCore/editing/TextIterator.h	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/TextIterator.h	2020-03-23 20:50:15 UTC (rev 258871)
@@ -36,7 +36,9 @@
 class Range;
 class RenderTextFragment;
 
+// FIXME: Delete this overload after moving all the callers to the SimpleRange version.
 WEBCORE_EXPORT String plainText(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
+
 WEBCORE_EXPORT String plainText(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
 WEBCORE_EXPORT String plainTextReplacingNoBreakSpace(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
 WEBCORE_EXPORT String plainTextUsingBackwardsTextIteratorForTesting(const SimpleRange&);
@@ -100,7 +102,7 @@
     const TextIteratorCopyableText& copyableText() const { ASSERT(!atEnd()); return m_copyableText; }
     void appendTextToStringBuilder(StringBuilder& builder) const { copyableText().appendToStringBuilder(builder); }
 
-    WEBCORE_EXPORT static int rangeLength(const Range*, bool spacesForReplacedElements = false);
+    // FIXME: Move these to SimpleRange, CharacterRange, and CharacterCount and move out of this class to the top level (bottom of this file).
     WEBCORE_EXPORT static RefPtr<Range> rangeFromLocationAndLength(ContainerNode* scope, int rangeLocation, int rangeLength, bool spacesForReplacedElements = false);
     WEBCORE_EXPORT static bool getLocationAndLengthFromRange(Node* scope, const Range*, size_t& location, size_t& length);
     WEBCORE_EXPORT static Ref<Range> subrange(Range& entireRange, int characterOffset, int characterCount);
@@ -287,4 +289,13 @@
     bool m_didLookAhead { true };
 };
 
+using CharacterCount = std::size_t;
+
+struct CharacterRange {
+    CharacterCount location { 0 };
+    CharacterCount length { 0 };
+};
+
+WEBCORE_EXPORT CharacterCount characterCount(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/editing/VisiblePosition.cpp (258870 => 258871)


--- trunk/Source/WebCore/editing/VisiblePosition.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/VisiblePosition.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
  * Portions Copyright (c) 2011 Motorola Mobility, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -819,6 +819,11 @@
     return m_affinity == other.m_affinity && m_deepPosition.equals(other.m_deepPosition);
 }
 
+Optional<BoundaryPoint> makeBoundaryPoint(const VisiblePosition& position)
+{
+    return makeBoundaryPoint(position.deepEquivalent());
+}
+
 TextStream& operator<<(TextStream& stream, EAffinity affinity)
 {
     switch (affinity) {

Modified: trunk/Source/WebCore/editing/VisiblePosition.h (258870 => 258871)


--- trunk/Source/WebCore/editing/VisiblePosition.h	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/VisiblePosition.h	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,10 +28,6 @@
 #include "EditingBoundary.h"
 #include "Position.h"
 
-namespace WTF {
-class TextStream;
-}
-
 namespace WebCore {
 
 class Range;
@@ -49,9 +45,6 @@
 // position is not at a line break.
 #define VP_UPSTREAM_IF_POSSIBLE UPSTREAM
 
-class InlineBox;
-class Node;
-
 class VisiblePosition {
 public:
     // NOTE: UPSTREAM affinity will be used only if pos is at end of a wrapped line,
@@ -85,21 +78,16 @@
 
     // FIXME: This does not handle [table, 0] correctly.
     Element* rootEditableElement() const { return m_deepPosition.isNotNull() ? m_deepPosition.deprecatedNode()->rootEditableElement() : 0; }
-    
-    void getInlineBoxAndOffset(InlineBox*& inlineBox, int& caretOffset) const
-    {
-        m_deepPosition.getInlineBoxAndOffset(m_affinity, inlineBox, caretOffset);
-    }
 
-    void getInlineBoxAndOffset(TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
-    {
-        m_deepPosition.getInlineBoxAndOffset(m_affinity, primaryDirection, inlineBox, caretOffset);
-    }
+    void getInlineBoxAndOffset(InlineBox*&, int& caretOffset) const;
+    void getInlineBoxAndOffset(TextDirection primaryDirection, InlineBox*&, int& caretOffset) const;
 
     // Rect is local to the returned renderer
     WEBCORE_EXPORT LayoutRect localCaretRect(RenderObject*&) const;
+
     // Bounds of (possibly transformed) caret in absolute coords
     WEBCORE_EXPORT IntRect absoluteCaretBounds(bool* insideFixed = nullptr) const;
+
     // Abs x/y position of the caret ignoring transforms.
     // FIXME: navigation with transforms should be smarter.
     WEBCORE_EXPORT int lineDirectionPointForBlockDirectionNavigation() const;
@@ -107,7 +95,7 @@
     WEBCORE_EXPORT FloatRect absoluteSelectionBoundsForLine() const;
 
     // This is a tentative enhancement of operator== to account for affinity.
-    // FIXME: Combine this function with operator==
+    // FIXME: Combine this function with operator==.
     bool equals(const VisiblePosition&) const;
 
 #if ENABLE(TREE_DEBUGGING)
@@ -115,7 +103,7 @@
     void formatForDebugger(char* buffer, unsigned length) const;
     void showTreeForThis() const;
 #endif
-    
+
 private:
     void init(const Position&, EAffinity);
     Position canonicalPosition(const Position&);
@@ -127,23 +115,50 @@
     EAffinity m_affinity;
 };
 
+bool operator==(const VisiblePosition&, const VisiblePosition&);
+bool operator!=(const VisiblePosition&, const VisiblePosition&);
+bool operator<(const VisiblePosition&, const VisiblePosition&);
+bool operator>(const VisiblePosition&, const VisiblePosition&);
+bool operator<=(const VisiblePosition&, const VisiblePosition&);
+bool operator>=(const VisiblePosition&, const VisiblePosition&);
+
+WEBCORE_EXPORT Optional<BoundaryPoint> makeBoundaryPoint(const VisiblePosition&);
+
+WEBCORE_EXPORT RefPtr<Range> makeRange(const VisiblePosition&, const VisiblePosition&);
+bool setStart(Range*, const VisiblePosition&);
+bool setEnd(Range*, const VisiblePosition&);
+VisiblePosition startVisiblePosition(const Range*, EAffinity);
+VisiblePosition endVisiblePosition(const Range*, EAffinity);
+
+WEBCORE_EXPORT Element* enclosingBlockFlowElement(const VisiblePosition&);
+
+bool isFirstVisiblePositionInNode(const VisiblePosition&, const Node*);
+bool isLastVisiblePositionInNode(const VisiblePosition&, const Node*);
+
+bool areVisiblePositionsInSameTreeScope(const VisiblePosition&, const VisiblePosition&);
+
+WTF::TextStream& operator<<(WTF::TextStream&, EAffinity);
+WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const VisiblePosition&);
+
+// inlines
+
 // FIXME: This shouldn't ignore affinity.
 inline bool operator==(const VisiblePosition& a, const VisiblePosition& b)
 {
     return a.deepEquivalent() == b.deepEquivalent();
 }
- 
+
 inline bool operator!=(const VisiblePosition& a, const VisiblePosition& b)
 {
     return !(a == b);
 }
-    
+
 inline bool operator<(const VisiblePosition& a, const VisiblePosition& b)
 {
     return a.deepEquivalent() < b.deepEquivalent();
 }
 
-inline bool operator>(const VisiblePosition& a, const VisiblePosition& b) 
+inline bool operator>(const VisiblePosition& a, const VisiblePosition& b)
 {
     return a.deepEquivalent() > b.deepEquivalent();
 }
@@ -153,27 +168,21 @@
     return a.deepEquivalent() <= b.deepEquivalent();
 }
 
-inline bool operator>=(const VisiblePosition& a, const VisiblePosition& b) 
+inline bool operator>=(const VisiblePosition& a, const VisiblePosition& b)
 {
     return a.deepEquivalent() >= b.deepEquivalent();
-}    
+}
 
-WEBCORE_EXPORT RefPtr<Range> makeRange(const VisiblePosition&, const VisiblePosition&);
-bool setStart(Range*, const VisiblePosition&);
-bool setEnd(Range*, const VisiblePosition&);
-VisiblePosition startVisiblePosition(const Range*, EAffinity);
-VisiblePosition endVisiblePosition(const Range*, EAffinity);
+inline void VisiblePosition::getInlineBoxAndOffset(InlineBox*& inlineBox, int& caretOffset) const
+{
+    m_deepPosition.getInlineBoxAndOffset(m_affinity, inlineBox, caretOffset);
+}
 
-WEBCORE_EXPORT Element* enclosingBlockFlowElement(const VisiblePosition&);
+inline void VisiblePosition::getInlineBoxAndOffset(TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
+{
+    m_deepPosition.getInlineBoxAndOffset(m_affinity, primaryDirection, inlineBox, caretOffset);
+}
 
-bool isFirstVisiblePositionInNode(const VisiblePosition&, const Node*);
-bool isLastVisiblePositionInNode(const VisiblePosition&, const Node*);
-
-bool areVisiblePositionsInSameTreeScope(const VisiblePosition&, const VisiblePosition&);
-
-WTF::TextStream& operator<<(WTF::TextStream&, EAffinity);
-WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const VisiblePosition&);
-
 } // namespace WebCore
 
 #if ENABLE(TREE_DEBUGGING)

Modified: trunk/Source/WebCore/editing/VisibleUnits.cpp (258870 => 258871)


--- trunk/Source/WebCore/editing/VisibleUnits.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/VisibleUnits.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1901,20 +1901,13 @@
     return Range::create(prevBoundary.deepEquivalent().deprecatedNode()->document(), prevBoundary, nextBoundary);
 }
 
-int distanceBetweenPositions(const VisiblePosition& vp, const VisiblePosition& other)
+std::ptrdiff_t distanceBetweenPositions(const VisiblePosition& a, const VisiblePosition& b)
 {
-    if (vp.isNull() || other.isNull())
+    if (a.isNull() || b.isNull())
         return 0;
-
-    bool thisIsStart = (vp < other);
-
-    // Start must come first in the Range constructor.
-    auto range = Range::create(vp.deepEquivalent().deprecatedNode()->document(),
-                                        (thisIsStart ? vp : other),
-                                        (thisIsStart ? other : vp));
-    int distance = TextIterator::rangeLength(range.ptr());
-
-    return (thisIsStart ? -distance : distance);
+    return a < b
+        ? -characterCount({ *makeBoundaryPoint(a), *makeBoundaryPoint(b) })
+        : characterCount({ *makeBoundaryPoint(b), *makeBoundaryPoint(a) });
 }
 
 void charactersAroundPosition(const VisiblePosition& position, UChar32& oneAfter, UChar32& oneBefore, UChar32& twoBefore)

Modified: trunk/Source/WebCore/editing/VisibleUnits.h (258870 => 258871)


--- trunk/Source/WebCore/editing/VisibleUnits.h	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/VisibleUnits.h	2020-03-23 20:50:15 UTC (rev 258871)
@@ -102,7 +102,7 @@
 WEBCORE_EXPORT bool withinTextUnitOfGranularity(const VisiblePosition&, TextGranularity, SelectionDirection);
 WEBCORE_EXPORT VisiblePosition positionOfNextBoundaryOfGranularity(const VisiblePosition&, TextGranularity, SelectionDirection);
 WEBCORE_EXPORT RefPtr<Range> enclosingTextUnitOfGranularity(const VisiblePosition&, TextGranularity, SelectionDirection);
-WEBCORE_EXPORT int distanceBetweenPositions(const VisiblePosition&, const VisiblePosition&);
+WEBCORE_EXPORT std::ptrdiff_t distanceBetweenPositions(const VisiblePosition&, const VisiblePosition&);
 WEBCORE_EXPORT RefPtr<Range> wordRangeFromPosition(const VisiblePosition&);
 WEBCORE_EXPORT VisiblePosition closestWordBoundaryForPosition(const VisiblePosition& position);
 WEBCORE_EXPORT void charactersAroundPosition(const VisiblePosition&, UChar32& oneAfter, UChar32& oneBefore, UChar32& twoBefore);

Modified: trunk/Source/WebCore/editing/cocoa/DataDetection.mm (258870 => 258871)


--- trunk/Source/WebCore/editing/cocoa/DataDetection.mm	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/cocoa/DataDetection.mm	2020-03-23 20:50:15 UTC (rev 258871)
@@ -71,15 +71,18 @@
 static RetainPtr<DDActionContext> detectItemAtPositionWithRange(VisiblePosition position, RefPtr<Range> contextRange, FloatRect& detectedDataBoundingBox, RefPtr<Range>& detectedDataRange)
 {
     String fullPlainTextString = plainText(contextRange.get());
-    int hitLocation = TextIterator::rangeLength(makeRange(contextRange->startPosition(), position).get());
+    auto start = contextRange->startPosition();
+    if (start.isNull() || position.isNull())
+        return nil;
+    CFIndex hitLocation = characterCount({ *makeBoundaryPoint(start), *makeBoundaryPoint(position) });
 
-    RetainPtr<DDScannerRef> scanner = adoptCF(DDScannerCreate(DDScannerTypeStandard, 0, nullptr));
-    RetainPtr<DDScanQueryRef> scanQuery = adoptCF(DDScanQueryCreateFromString(kCFAllocatorDefault, fullPlainTextString.createCFString().get(), CFRangeMake(0, fullPlainTextString.length())));
+    auto scanner = adoptCF(DDScannerCreate(DDScannerTypeStandard, 0, nullptr));
+    auto scanQuery = adoptCF(DDScanQueryCreateFromString(kCFAllocatorDefault, fullPlainTextString.createCFString().get(), CFRangeMake(0, fullPlainTextString.length())));
 
     if (!DDScannerScanQuery(scanner.get(), scanQuery.get()))
-        return nullptr;
+        return nil;
 
-    RetainPtr<CFArrayRef> results = adoptCF(DDScannerCopyResultsWithOptions(scanner.get(), DDScannerCopyResultsOptionsNoOverlap));
+    auto results = adoptCF(DDScannerCopyResultsWithOptions(scanner.get(), DDScannerCopyResultsOptionsNoOverlap));
 
     // Find the DDResultRef that intersects the hitTestResult's VisiblePosition.
     DDResultRef mainResult = nullptr;
@@ -100,7 +103,7 @@
     }
 
     if (!mainResult)
-        return nullptr;
+        return nil;
 
     RetainPtr<DDActionContext> actionContext = adoptNS([allocDDActionContextInstance() init]);
     [actionContext setAllResults:@[ (__bridge id)mainResult ]];
@@ -112,9 +115,9 @@
     FrameView* frameView = mainResultRange->ownerDocument().view();
     for (const auto& quad : quads)
         detectedDataBoundingBox.unite(frameView->contentsToWindow(quad.enclosingBoundingBox()));
-    
+
     detectedDataRange = mainResultRange;
-    
+
     return actionContext;
 }
 

Modified: trunk/Source/WebCore/editing/cocoa/DictionaryLookup.mm (258870 => 258871)


--- trunk/Source/WebCore/editing/cocoa/DictionaryLookup.mm	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/cocoa/DictionaryLookup.mm	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -264,12 +264,11 @@
 std::tuple<RefPtr<Range>, NSDictionary *> DictionaryLookup::rangeForSelection(const VisibleSelection& selection)
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
-    
+
     if (!RevealLibrary() || !RevealCoreLibrary() || !getRVItemClass())
         return { nullptr, nil };
-    
-    auto selectedRange = selection.toNormalizedRange();
-    if (!selectedRange)
+
+    if (!selection.toNormalizedRange())
         return { nullptr, nil };
 
     // Since we already have the range we want, we just need to grab the returned options.
@@ -279,20 +278,22 @@
     // As context, we are going to use the surrounding paragraphs of text.
     auto paragraphStart = startOfParagraph(selectionStart);
     auto paragraphEnd = endOfParagraph(selectionEnd);
+    if (paragraphStart.isNull() || paragraphEnd.isNull())
+        return { nullptr, nil };
 
-    int lengthToSelectionStart = TextIterator::rangeLength(makeRange(paragraphStart, selectionStart).get());
-    int lengthToSelectionEnd = TextIterator::rangeLength(makeRange(paragraphStart, selectionEnd).get());
-    NSRange rangeToPass = NSMakeRange(lengthToSelectionStart, lengthToSelectionEnd - lengthToSelectionStart);
-    
+    auto lengthToSelectionStart = characterCount({ *makeBoundaryPoint(paragraphStart), *makeBoundaryPoint(selectionStart) });
+    auto selectionCharacterCount = characterCount({ *makeBoundaryPoint(selectionStart), *makeBoundaryPoint(selectionEnd) });
+    NSRange rangeToPass = NSMakeRange(lengthToSelectionStart, selectionCharacterCount);
+
     RefPtr<Range> fullCharacterRange = makeRange(paragraphStart, paragraphEnd);
     String itemString = plainText(fullCharacterRange.get());
     RetainPtr<RVItem> item = adoptNS([allocRVItemInstance() initWithText:itemString selectedRange:rangeToPass]);
     NSRange highlightRange = item.get().highlightRange;
-    
+
     return { TextIterator::subrange(*fullCharacterRange, highlightRange.location, highlightRange.length), nil };
-    
+
     END_BLOCK_OBJC_EXCEPTIONS;
-    
+
     return { nullptr, nil };
 }
 
@@ -322,43 +323,40 @@
 
     auto selection = frame->page()->focusController().focusedOrMainFrame().selection().selection();
     NSRange selectionRange;
-    int hitIndex;
+    NSUInteger hitIndex;
     RefPtr<Range> fullCharacterRange;
     
     if (selection.selectionType() == VisibleSelection::RangeSelection) {
         auto selectionStart = selection.visibleStart();
         auto selectionEnd = selection.visibleEnd();
-        
+
         // As context, we are going to use the surrounding paragraphs of text.
         auto paragraphStart = startOfParagraph(selectionStart);
         auto paragraphEnd = endOfParagraph(selectionEnd);
         
-        auto rangeToSelectionStart = makeRange(paragraphStart, selectionStart);
-        auto rangeToSelectionEnd = makeRange(paragraphStart, selectionEnd);
-        
         fullCharacterRange = makeRange(paragraphStart, paragraphEnd);
         if (!fullCharacterRange)
             return { nullptr, nil };
 
-        selectionRange = NSMakeRange(TextIterator::rangeLength(rangeToSelectionStart.get()), TextIterator::rangeLength(makeRange(selectionStart, selectionEnd).get()));
-        
-        hitIndex = TextIterator::rangeLength(makeRange(paragraphStart, position).get());
+        selectionRange = NSMakeRange(characterCount({ *makeBoundaryPoint(paragraphStart), *makeBoundaryPoint(selectionStart) }),
+            characterCount({ *makeBoundaryPoint(selectionStart), *makeBoundaryPoint(selectionEnd) }));
+        hitIndex = characterCount({ *makeBoundaryPoint(paragraphStart), *makeBoundaryPoint(position) });
     } else {
         VisibleSelection selectionAccountingForLineRules { position };
         selectionAccountingForLineRules.expandUsingGranularity(WordGranularity);
         position = selectionAccountingForLineRules.start();
+
         // As context, we are going to use 250 characters of text before and after the point.
         fullCharacterRange = rangeExpandedAroundPositionByCharacters(position, 250);
-        
         if (!fullCharacterRange)
             return { nullptr, nil };
-        
+
         selectionRange = NSMakeRange(NSNotFound, 0);
-        hitIndex = TextIterator::rangeLength(makeRange(fullCharacterRange->startPosition(), position).get());
+        hitIndex = characterCount({ *makeBoundaryPoint(fullCharacterRange->startPosition()), *makeBoundaryPoint(position) });
     }
-    
+
     NSRange selectedRange = [getRVSelectionClass() revealRangeAtIndex:hitIndex selectedRanges:@[[NSValue valueWithRange:selectionRange]] shouldUpdateSelection:nil];
-    
+
     String itemString = plainText(*fullCharacterRange);
     RetainPtr<RVItem> item = adoptNS([allocRVItemInstance() initWithText:itemString selectedRange:selectedRange]);
     NSRange highlightRange = item.get().highlightRange;

Modified: trunk/Source/WebCore/editing/ios/DictationCommandIOS.cpp (258870 => 258871)


--- trunk/Source/WebCore/editing/ios/DictationCommandIOS.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/ios/DictationCommandIOS.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -48,9 +48,7 @@
 
 void DictationCommandIOS::doApply()
 {
-    VisiblePosition insertionPosition(startingSelection().visibleStart());
-
-    unsigned resultLength = 0;
+    CharacterCount resultLength = 0;
     for (auto& interpretations : m_dictationPhrases) {
         const String& firstInterpretation = interpretations[0];
         resultLength += firstInterpretation.length();
@@ -62,20 +60,23 @@
         setEndingSelection(VisibleSelection(endingSelection().visibleEnd()));
     }
 
-    VisiblePosition afterResults(endingSelection().visibleEnd());
+    // FIXME: Add the result marker using a Position cached before results are inserted, instead of relying on character counts.
 
-    Element* root = afterResults.rootEditableElement();
+    auto endPosition = endingSelection().visibleEnd();
+    auto end = makeBoundaryPoint(endPosition);
+    auto* root = endPosition.rootEditableElement();
+    if (!end || !root)
+        return;
 
-    // FIXME: Add the result marker using a Position cached before results are inserted, instead of relying on TextIterators.
-    auto rangeToEnd = Range::create(document(), createLegacyEditingPosition((Node *)root, 0), afterResults.deepEquivalent());
-    int endIndex = TextIterator::rangeLength(rangeToEnd.ptr(), true);
-    int startIndex = endIndex - resultLength;
+    auto endOffset = characterCount({ { *root, 0 }, WTFMove(*end) });
+    if (endOffset < resultLength)
+        return;
 
-    if (startIndex >= 0) {
-        RefPtr<Range> resultRange = TextIterator::rangeFromLocationAndLength(document().documentElement(), startIndex, endIndex, true);
-        ASSERT(resultRange); // FIXME: What guarantees this?
-        document().markers().addDictationResultMarker(*resultRange, m_metadata);
-    }
+    auto resultRange = TextIterator::rangeFromLocationAndLength(root, endOffset - resultLength, endOffset);
+    if (!resultRange)
+        return;
+
+    document().markers().addDictationResultMarker(*resultRange, m_metadata);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/editing/mac/DictionaryLookupLegacy.mm (258870 => 258871)


--- trunk/Source/WebCore/editing/mac/DictionaryLookupLegacy.mm	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/editing/mac/DictionaryLookupLegacy.mm	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -89,10 +89,12 @@
     // As context, we are going to use the surrounding paragraphs of text.
     auto paragraphStart = startOfParagraph(selectionStart);
     auto paragraphEnd = endOfParagraph(selectionEnd);
+    if (paragraphStart.isNull() || paragraphEnd.isNull())
+        return { nullptr, nil };
 
-    int lengthToSelectionStart = TextIterator::rangeLength(makeRange(paragraphStart, selectionStart).get());
-    int lengthToSelectionEnd = TextIterator::rangeLength(makeRange(paragraphStart, selectionEnd).get());
-    NSRange rangeToPass = NSMakeRange(lengthToSelectionStart, lengthToSelectionEnd - lengthToSelectionStart);
+    auto lengthToSelectionStart = characterCount({ *makeBoundaryPoint(paragraphStart), *makeBoundaryPoint(selectionStart) });
+    auto selectionCharacterCount = characterCount({ *makeBoundaryPoint(selectionStart), *makeBoundaryPoint(selectionEnd) });
+    NSRange rangeToPass = NSMakeRange(lengthToSelectionStart, selectionCharacterCount);
 
     NSDictionary *options = nil;
     tokenRange(plainText(makeRange(paragraphStart, paragraphEnd).get()), rangeToPass, &options);
@@ -133,7 +135,12 @@
     if (!fullCharacterRange)
         return { nullptr, nil };
 
-    NSRange rangeToPass = NSMakeRange(TextIterator::rangeLength(makeRange(fullCharacterRange->startPosition(), position).get()), 0);
+    auto fullCharacterStart = makeBoundaryPoint(fullCharacterRange->startPosition());
+    auto positionBoundary = makeBoundaryPoint(position);
+    if (!fullCharacterStart || !positionBoundary)
+        return { nullptr, nil };
+
+    NSRange rangeToPass = NSMakeRange(characterCount({ *fullCharacterStart, *positionBoundary }), 0);
     NSDictionary *options = nil;
     NSRange extractedRange = tokenRange(plainText(fullCharacterRange.get()), rangeToPass, &options);
 

Modified: trunk/Source/WebCore/page/EventHandler.cpp (258870 => 258871)


--- trunk/Source/WebCore/page/EventHandler.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -654,10 +654,13 @@
     return updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), ParagraphGranularity);
 }
 
-static int textDistance(const Position& start, const Position& end)
+static CharacterCount textDistance(const Position& start, const Position& end)
 {
-    auto range = Range::create(start.anchorNode()->document(), start, end);
-    return TextIterator::rangeLength(range.ptr(), true);
+    auto startBoundary = makeBoundaryPoint(start);
+    auto endBoundary = makeBoundaryPoint(end);
+    if (!startBoundary || !endBoundary)
+        return 0;
+    return characterCount({ *startBoundary, *endBoundary }, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
 }
 
 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)

Modified: trunk/Source/WebKit/ChangeLog (258870 => 258871)


--- trunk/Source/WebKit/ChangeLog	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebKit/ChangeLog	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1,3 +1,25 @@
+2020-03-23  Darin Adler  <[email protected]>
+
+        Change TextIterator::rangeLength to not require a live range
+        https://bugs.webkit.org/show_bug.cgi?id=209207
+
+        Reviewed by Antti Koivisto.
+
+        * Shared/EditingRange.cpp:
+        (WebKit::EditingRange::toRange): Use characterCount.
+        * WebProcess/WebCoreSupport/WebEditorClient.cpp:
+        (WebKit::insertionPointFromCurrentSelection): Changed return type to
+        CharacterCount and use characterCount.
+        (WebKit::WebEditorClient::supportsGlobalSelection): Tweaked #if.
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::targetFrameForEditing): Use characterCount.
+        * WebProcess/WebPage/glib/WebPageGLib.cpp:
+        (WebKit::WebPage::platformEditorState const): Ditto.
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::rangeNearPositionMatchesText): Ditto.
+        * WebProcess/WebPage/mac/WebPageMac.mm:
+        (WebKit::WebPage::platformEditorState const): Ditto.
+
 2020-03-23  youenn fablet  <[email protected]>
 
         Rename blankURL to aboutBlankURL

Modified: trunk/Source/WebKit/Shared/EditingRange.cpp (258870 => 258871)


--- trunk/Source/WebKit/Shared/EditingRange.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebKit/Shared/EditingRange.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -58,18 +58,17 @@
 
     ASSERT(editingRangeIsRelativeTo == EditingRangeIsRelativeTo::Paragraph);
 
-    const WebCore::VisibleSelection& selection = frame.selection().selection();
-    RefPtr<WebCore::Range> selectedRange = selection.toNormalizedRange();
-    if (!selectedRange)
+    auto& selection = frame.selection().selection();
+    if (!selection.toNormalizedRange())
         return nullptr;
 
-    RefPtr<WebCore::Range> paragraphRange = makeRange(startOfParagraph(selection.visibleStart()), selection.visibleEnd());
-    if (!paragraphRange)
+    auto paragraphStart = makeBoundaryPoint(startOfParagraph(selection.visibleStart()));
+    if (!paragraphStart)
         return nullptr;
+    auto& rootNode = paragraphStart->container->treeScope().rootNode();
 
-    auto& rootNode = paragraphRange.get()->startContainer().treeScope().rootNode();
-    int paragraphStartIndex = WebCore::TextIterator::rangeLength(WebCore::Range::create(rootNode.document(), &rootNode, 0, &paragraphRange->startContainer(), paragraphRange->startOffset()).ptr());
-    return WebCore::TextIterator::rangeFromLocationAndLength(&rootNode, paragraphStartIndex + static_cast<int>(range.location), length);
+    auto paragraphStartIndex = WebCore::characterCount({ { rootNode, 0 }, *paragraphStart });
+    return WebCore::TextIterator::rangeFromLocationAndLength(&rootNode, paragraphStartIndex + range.location, length);
 }
 
 EditingRange EditingRange::fromRange(WebCore::Frame& frame, const WebCore::Range* range, EditingRangeIsRelativeTo editingRangeIsRelativeTo)

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.cpp (258870 => 258871)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -361,6 +361,7 @@
 }
 
 #if !PLATFORM(COCOA) && !USE(GLIB)
+
 void WebEditorClient::handleKeyboardEvent(KeyboardEvent& event)
 {
     if (m_page->handleEditingKeyboardEvent(event))
@@ -371,6 +372,7 @@
 {
     notImplemented();
 }
+
 #endif // !PLATFORM(COCOA) && !USE(GLIB)
 
 void WebEditorClient::textFieldDidBeginEditing(Element* element)
@@ -420,6 +422,7 @@
 }
 
 #if !PLATFORM(IOS_FAMILY)
+
 void WebEditorClient::overflowScrollPositionChanged()
 {
     notImplemented();
@@ -429,6 +432,7 @@
 {
     notImplemented();
 }
+
 #endif
 
 static bool getActionTypeForKeyEvent(KeyboardEvent* event, WKInputFieldActionType& type)
@@ -549,14 +553,18 @@
     *badGrammarLength = resultLength;
 }
 
-static int32_t insertionPointFromCurrentSelection(const VisibleSelection& currentSelection)
+static CharacterCount insertionPointFromCurrentSelection(const VisibleSelection& currentSelection)
 {
-    VisiblePosition selectionStart = currentSelection.visibleStart();
-    VisiblePosition paragraphStart = startOfParagraph(selectionStart);
-    return TextIterator::rangeLength(makeRange(paragraphStart, selectionStart).get());
+    auto selectionStart = currentSelection.visibleStart();
+    auto selectionStartBoundary = makeBoundaryPoint(selectionStart);
+    auto paragraphStart = makeBoundaryPoint(startOfParagraph(selectionStart));
+    if (!selectionStartBoundary || !paragraphStart)
+        return 0;
+    return characterCount({ *paragraphStart, *selectionStartBoundary });
 }
 
 #if USE(UNIFIED_TEXT_CHECKING)
+
 Vector<TextCheckingResult> WebEditorClient::checkTextOfParagraph(StringView stringView, OptionSet<WebCore::TextCheckingType> checkingTypes, const VisibleSelection& currentSelection)
 {
     Vector<TextCheckingResult> results;
@@ -563,6 +571,7 @@
     m_page->sendSync(Messages::WebPageProxy::CheckTextOfParagraph(stringView.toStringWithoutCopying(), checkingTypes, insertionPointFromCurrentSelection(currentSelection)), Messages::WebPageProxy::CheckTextOfParagraph::Reply(results));
     return results;
 }
+
 #endif
 
 void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
@@ -616,16 +625,14 @@
 
 bool WebEditorClient::supportsGlobalSelection()
 {
-#if PLATFORM(GTK)
-#if PLATFORM(X11)
+#if PLATFORM(GTK) && PLATFORM(X11)
     if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11)
         return true;
 #endif
-#if PLATFORM(WAYLAND)
+#if PLATFORM(GTK) && PLATFORM(WAYLAND)
     if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland)
         return true;
 #endif
-#endif
     return false;
 }
 

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (258870 => 258871)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -5428,6 +5428,7 @@
 #endif // PLATFORM(COCOA)
 
 #if PLATFORM(GTK) || PLATFORM(WPE)
+
 static Frame* targetFrameForEditing(WebPage& page)
 {
     Frame& targetFrame = page.corePage()->focusController().focusedOrMainFrame();
@@ -5467,7 +5468,7 @@
 
     auto selectionStart = selection.visibleStart();
     auto surroundingRange = makeRange(startOfEditableContent(selectionStart), selectionStart);
-    auto cursorPosition = TextIterator::rangeLength(surroundingRange.get());
+    auto cursorPosition = WebCore::characterCount(*surroundingRange);
     auto& rootNode = surroundingRange->startContainer().treeScope().rootNode();
     auto selectionRange = TextIterator::rangeFromLocationAndLength(&rootNode, cursorPosition + offset, characterCount);
     if (!selectionRange)
@@ -5479,6 +5480,7 @@
     targetFrame->editor().setIgnoreSelectionChanges(false);
     sendEditorStateUpdate();
 }
+
 #endif
 
 void WebPage::didApplyStyle()

Modified: trunk/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp (258870 => 258871)


--- trunk/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp	2020-03-23 20:50:15 UTC (rev 258871)
@@ -116,12 +116,12 @@
             surroundingRange->setEnd(compositionRange->startPosition());
             clonedRange->setStart(compositionRange->endPosition());
             postLayoutData.surroundingContext = plainText(surroundingRange.get()) + plainText(clonedRange.ptr());
-            postLayoutData.surroundingContextCursorPosition = TextIterator::rangeLength(surroundingRange.get());
+            postLayoutData.surroundingContextCursorPosition = characterCount(*surroundingRange);
             postLayoutData.surroundingContextSelectionPosition = postLayoutData.surroundingContextCursorPosition;
         } else {
             postLayoutData.surroundingContext = plainText(surroundingRange.get());
-            postLayoutData.surroundingContextCursorPosition = TextIterator::rangeLength(makeRange(surroundingStart, selectionStart).get());
-            postLayoutData.surroundingContextSelectionPosition = TextIterator::rangeLength(makeRange(surroundingStart, selection.visibleEnd()).get());
+            postLayoutData.surroundingContextCursorPosition = characterCount(*makeRange(surroundingStart, selectionStart));
+            postLayoutData.surroundingContextSelectionPosition = characterCount(*makeRange(surroundingStart, selection.visibleEnd()));
         }
     }
 }

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (258870 => 258871)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1989,13 +1989,16 @@
     }
 }
 
-static Optional<SimpleRange> rangeNearPositionMatchesText(const VisiblePosition& position, const String& matchText, RefPtr<Range> selectionRange)
+static Optional<SimpleRange> rangeNearPositionMatchesText(const VisiblePosition& position, const String& matchText, const VisibleSelection& selection)
 {
-    if (!selectionRange)
+    auto liveRange = selection.firstRange();
+    if (!liveRange)
         return WTF::nullopt;
-    auto range = Range::create(selectionRange->ownerDocument(), selectionRange->startPosition(), position.deepEquivalent().parentAnchoredEquivalent());
-    unsigned targetOffset = TextIterator::rangeLength(range.ptr(), true);
-    return findClosestPlainText(*selectionRange, matchText, { }, targetOffset);
+    SimpleRange range { *liveRange };
+    auto boundaryPoint = makeBoundaryPoint(position);
+    if (!boundaryPoint)
+        return WTF::nullopt;
+    return findClosestPlainText(range, matchText, { }, characterCount({ range.start, *boundaryPoint }, TextIteratorEmitsCharactersBetweenAllVisiblePositions));
 }
 
 void WebPage::getRectsAtSelectionOffsetWithText(int32_t offset, const String& text, CallbackID callbackID)
@@ -2022,7 +2025,7 @@
 
     if (plainTextForDisplay(range.ptr()) != text) {
         // Try to search for a range which is the closest to the position within the selection range that matches the passed in text.
-        if (auto wordRange = rangeNearPositionMatchesText(startPosition, text, selection.toNormalizedRange())) {
+        if (auto wordRange = rangeNearPositionMatchesText(startPosition, text, selection)) {
             if (!wordRange->collapsed())
                 range = createLiveRange(*wordRange);
         }

Modified: trunk/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm (258870 => 258871)


--- trunk/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm	2020-03-23 20:50:15 UTC (rev 258871)
@@ -140,7 +140,7 @@
         return;
     }
 
-    const VisibleSelection& selection = frame.selection().selection();
+    auto& selection = frame.selection().selection();
     RefPtr<Range> selectedRange = selection.toNormalizedRange();
     if (!selectedRange)
         return;
@@ -147,12 +147,15 @@
 
     auto& postLayoutData = result.postLayoutData();
     VisiblePosition selectionStart = selection.visibleStart();
-    VisiblePosition selectionEnd = selection.visibleEnd();
-    VisiblePosition paragraphStart = startOfParagraph(selectionStart);
-    VisiblePosition paragraphEnd = endOfParagraph(selectionEnd);
+    auto selectionStartBoundary = makeBoundaryPoint(selectionStart);
+    auto selectionEnd = makeBoundaryPoint(selection.visibleEnd());
+    auto paragraphStart = makeBoundaryPoint(startOfParagraph(selectionStart));
 
-    postLayoutData.candidateRequestStartPosition = TextIterator::rangeLength(makeRange(paragraphStart, selectionStart).get());
-    postLayoutData.selectedTextLength = TextIterator::rangeLength(makeRange(paragraphStart, selectionEnd).get()) - postLayoutData.candidateRequestStartPosition;
+    if (!selectionStartBoundary || !selectionEnd || !paragraphStart)
+        return;
+
+    postLayoutData.candidateRequestStartPosition = characterCount({ *paragraphStart, *selectionStartBoundary });
+    postLayoutData.selectedTextLength = characterCount({ *selectionStartBoundary, *selectionEnd });
     postLayoutData.paragraphContextForCandidateRequest = plainText(frame.editor().contextRangeForCandidateRequest().get());
     postLayoutData.stringForCandidateRequest = frame.editor().stringForCandidateRequest();
 

Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (258870 => 258871)


--- trunk/Source/WebKitLegacy/mac/ChangeLog	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1,3 +1,16 @@
+2020-03-23  Darin Adler  <[email protected]>
+
+        Change TextIterator::rangeLength to not require a live range
+        https://bugs.webkit.org/show_bug.cgi?id=209207
+
+        Reviewed by Antti Koivisto.
+
+        * WebCoreSupport/WebEditorClient.mm:
+        (insertionPointFromCurrentSelection): Use characterCount.
+        (WebEditorClient::requestCandidatesForSelection): Ditto.
+        * WebView/WebFrame.mm:
+        (-[WebFrame _convertToDOMRange:rangeIsRelativeTo:]): Ditto.
+
 2020-03-23  youenn fablet  <[email protected]>
 
         Rename blankURL to aboutBlankURL

Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm (258870 => 258871)


--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm	2020-03-23 20:50:15 UTC (rev 258871)
@@ -1031,16 +1031,19 @@
     return results;
 }
 
-static int insertionPointFromCurrentSelection(const VisibleSelection& currentSelection)
+static NSUInteger insertionPointFromCurrentSelection(const VisibleSelection& selection)
 {
-    VisiblePosition selectionStart = currentSelection.visibleStart();
-    VisiblePosition paragraphStart = startOfParagraph(selectionStart);
-    return TextIterator::rangeLength(makeRange(paragraphStart, selectionStart).get());
+    auto selectionStart = selection.visibleStart();
+    auto selectionStartBoundary = makeBoundaryPoint(selectionStart);
+    auto paragraphStart = makeBoundaryPoint(startOfParagraph(selectionStart));
+    if (!selectionStartBoundary || !paragraphStart)
+        return 0;
+    return characterCount({ *paragraphStart, *selectionStartBoundary });
 }
 
 Vector<TextCheckingResult> WebEditorClient::checkTextOfParagraph(StringView string, OptionSet<TextCheckingType> coreCheckingTypes, const VisibleSelection& currentSelection)
 {
-    NSDictionary *options = @{ NSTextCheckingInsertionPointKey :  [NSNumber numberWithUnsignedInteger:insertionPointFromCurrentSelection(currentSelection)] };
+    NSDictionary *options = @{ NSTextCheckingInsertionPointKey : @(insertionPointFromCurrentSelection(currentSelection)) };
     return core([[NSSpellChecker sharedSpellChecker] checkString:string.createNSStringWithoutCopying().get() range:NSMakeRange(0, string.length()) types:(nsTextCheckingTypes(coreCheckingTypes) | NSTextCheckingTypeOrthography) options:options inSpellDocumentWithTag:spellCheckerDocumentTag() orthography:NULL wordCount:NULL], coreCheckingTypes);
 }
 
@@ -1083,7 +1086,7 @@
     NSString *language = nil;
     NSOrthography* orthography = nil;
     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
-    NSDictionary *options = @{ NSTextCheckingInsertionPointKey :  [NSNumber numberWithUnsignedInteger:insertionPointFromCurrentSelection(currentSelection)] };
+    NSDictionary *options = @{ NSTextCheckingInsertionPointKey : @(insertionPointFromCurrentSelection(currentSelection)) };
     if (context.length()) {
         [checker checkString:context range:NSMakeRange(0, context.length()) types:NSTextCheckingTypeOrthography options:options inSpellDocumentWithTag:spellCheckerDocumentTag() orthography:&orthography wordCount:0];
         language = [checker languageForWordRange:NSMakeRange(0, context.length()) inString:context orthography:orthography];
@@ -1116,24 +1119,20 @@
     if (![m_webView shouldRequestCandidates])
         return;
 
-    RefPtr<Range> selectedRange = selection.toNormalizedRange();
-    if (!selectedRange)
+    if (!selection.toNormalizedRange())
         return;
-    
-    Frame* frame = core([m_webView _selectedOrMainFrame]);
+
+    auto* frame = core([m_webView _selectedOrMainFrame]);
     if (!frame)
         return;
 
     m_lastSelectionForRequestedCandidates = selection;
 
-    VisiblePosition selectionStart = selection.visibleStart();
-    VisiblePosition selectionEnd = selection.visibleEnd();
-    VisiblePosition paragraphStart = startOfParagraph(selectionStart);
-    VisiblePosition paragraphEnd = endOfParagraph(selectionEnd);
+    auto selectionStart = selection.visibleStart();
+    auto selectionStartOffsetInParagraph = characterCount({ *makeBoundaryPoint(startOfParagraph(selectionStart)), *makeBoundaryPoint(selectionStart) });
+    auto selectionLength = characterCount({ *makeBoundaryPoint(selectionStart), *makeBoundaryPoint(selection.visibleEnd()) });
 
-    int lengthToSelectionStart = TextIterator::rangeLength(makeRange(paragraphStart, selectionStart).get());
-    int lengthToSelectionEnd = TextIterator::rangeLength(makeRange(paragraphStart, selectionEnd).get());
-    m_rangeForCandidates = NSMakeRange(lengthToSelectionStart, lengthToSelectionEnd - lengthToSelectionStart);
+    m_rangeForCandidates = NSMakeRange(selectionStartOffsetInParagraph, selectionLength);
     m_paragraphContextForCandidateRequest = plainText(frame->editor().contextRangeForCandidateRequest().get());
 
     NSTextCheckingTypes checkingTypes = NSTextCheckingTypeSpelling | NSTextCheckingTypeReplacement | NSTextCheckingTypeCorrection;

Modified: trunk/Source/WebKitLegacy/mac/WebView/WebFrame.mm (258870 => 258871)


--- trunk/Source/WebKitLegacy/mac/WebView/WebFrame.mm	2020-03-23 20:19:38 UTC (rev 258870)
+++ trunk/Source/WebKitLegacy/mac/WebView/WebFrame.mm	2020-03-23 20:50:15 UTC (rev 258871)
@@ -835,24 +835,19 @@
         // That fits with AppKit's idea of an input context.
         auto* element = _private->coreFrame->selection().rootEditableElementOrDocumentElement();
         if (!element)
-            return nil;
+            return nullptr;
         return WebCore::TextIterator::rangeFromLocationAndLength(element, nsrange.location, nsrange.length);
     }
 
     ASSERT(rangeIsRelativeTo == WebRangeIsRelativeTo::Paragraph);
 
-    const auto& selection = _private->coreFrame->selection().selection();
-    RefPtr<WebCore::Range> selectedRange = selection.toNormalizedRange();
-    if (!selectedRange)
+    auto paragraphStart = makeBoundaryPoint(startOfParagraph(_private->coreFrame->selection().selection().visibleStart()));
+    if (!paragraphStart)
         return nullptr;
+    auto& rootNode = paragraphStart->container->treeScope().rootNode();
 
-    RefPtr<WebCore::Range> paragraphRange = makeRange(startOfParagraph(selection.visibleStart()), selection.visibleEnd());
-    if (!paragraphRange)
-        return nullptr;
-
-    auto& rootNode = paragraphRange.get()->startContainer().treeScope().rootNode();
-    int paragraphStartIndex = WebCore::TextIterator::rangeLength(WebCore::Range::create(rootNode.document(), &rootNode, 0, &paragraphRange->startContainer(), paragraphRange->startOffset()).ptr());
-    return WebCore::TextIterator::rangeFromLocationAndLength(&rootNode, paragraphStartIndex + static_cast<int>(nsrange.location), nsrange.length);
+    auto paragraphStartIndex = WebCore::characterCount({ { rootNode, 0 }, *paragraphStart });
+    return WebCore::TextIterator::rangeFromLocationAndLength(&rootNode, paragraphStartIndex + nsrange.location, nsrange.length);
 }
 
 - (DOMRange *)_convertNSRangeToDOMRange:(NSRange)nsrange
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to