Move most of TextIterator off of live ranges
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Mar 2020 23:02:10 +0000 (23:02 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Mar 2020 23:02:10 +0000 (23:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=209129

Reviewed by Antti Koivisto.

Source/WebCore:

- Change almost all arguments and return values of functions in TextIterator.h
  to use SimpleRange instead of live ranges. Exceptions are an overload of plainText
  TextIterator::rangeLength, TextIterator::rangeFromLocationAndLength,
  TextIterator::getLocationAndLengthFromRange, and TextIterator::subrange. Those
  five are a little trickier to convert, so I will do them each in separate patches.

- Go with the flow in adding an include of Node.h to BoundaryPoint.h. I had avoided
  this in the initial version, but now it seems practical to just leave it that way.
  This led to removing BoundaryPoint.cpp and moving all functions to the header.

- Converted many member functions of the Position class from using int to unsigned
  for offsets. The DOM specifies unsigned for offsets, but for some reason we used
  int for them a lot historically, even though negative numbers don't make sense.
  New classes like StaticRange, SimpleRange, and BoundaryPoint are already using
  unsigned exclusively and we'll eventually convert everything.

- Remove includes of SimpleRange.h from files that also include TextIterator.h,
  now that TextIterator.h pulls it in.

* Sources.txt: Removed BoundaryPoint.cpp.
* WebCore.xcodeproj/project.pbxproj: Ditto.

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::traverseToOffsetInRange): Updated to pass a reference
to a range rather than a pointer, after null-checking it.
(WebCore::AXObjectCache::lengthForRange): Ditto.
(WebCore::AXObjectCache::nextBoundary): Ditto.
(WebCore::AXObjectCache::previousBoundary): Ditto.
* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::stringForRange const): Ditto.
(WebCore::AccessibilityObject::stringForVisiblePositionRange): Ditto.
(WebCore::AccessibilityObject::lengthForVisiblePositionRange const): Ditto.

* accessibility/AccessibilityObjectInterface.h: Removed an extra include.

* accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(-[WebAccessibilityObjectWrapper arrayOfTextForTextMarkers:attributed:]):
Updated to pass a reference to a range rather than a pointer, after null-checking it.
* accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(-[WebAccessibilityObjectWrapper doAXAttributedStringForTextMarkerRange:spellCheck:]): Ditto.

* dom/BoundaryPoint.cpp: Removed.

* dom/BoundaryPoint.h: Removed redundant includes and forward declarations
since we're now committing to including "Node.h" here. Moved functions
all out of the .cpp file and made them inlines.

* dom/DocumentMarkerController.cpp:
(WebCore::DocumentMarkerController::collectTextRanges): Pass a reference to
a range instead of a pointer.

* dom/Position.cpp:
(WebCore::Position::Position): Take unsigned.
(WebCore::Position::moveToPosition): Ditto.
(WebCore::Position::moveToOffset): Ditto.
(WebCore::Position::parentAnchoredEquivalent const): Cast to unsigned.
(WebCore::Position::anchorTypeForLegacyEditingPosition): Take unsigned.
(WebCore::Position::previous const): Use unsigned.
(WebCore::Position::next const): Ditto.
(WebCore::Position::uncheckedPreviousOffset): Take unsigned.
(WebCore::Position::uncheckedPreviousOffsetForBackwardDeletion): Ditto.
(WebCore::Position::uncheckedNextOffset): Ditto.
(WebCore::Position::atLastEditingPositionForNode const): Cast to unsigned.
(WebCore::Position::atEndOfTree const): Ditto.
(WebCore::Position::rendersInDifferentPosition const): Added casts to
unsigned and also removed unneeded redundant checks. In a place where
we had already checked that both nodes were the same and both offsets
were different, we were checking the types of both nodes (but they are
the same so only need to check one) and we were checking that both
offsets were different (but we already knew they were different).
(WebCore::searchAheadForBetterMatch): Use unsigned.
(WebCore::Position::getInlineBoxAndOffset const): Ditto.
(WebCore::Position::equals const): Removed a cast to int.
(WebCore::makeBoundaryPoint): Moved this function here so now it can be
used in more places.

* dom/Position.h: Changed many argument types to unsigned. Moved declarations
of all the functions up above all the inline implementations of the functions
to separate interface from implementation a bit better. Wrote a FIXME about
the name createLegacyEditingPosition. Moved makeBoundaryPoint here and exported
it from WebCore so we can use it from more places.

* dom/Range.cpp:
(WebCore::createLiveRange): Moved these functions here from SimpleRange.cpp
because a live range is more advanced concept, so makes more sense for live
range to know about simple range rather than vice versa.

* dom/Range.h: Removed some unneeded includes and forward declarations.
Added a FIXME about renaming to LiveRange. Moved the createLiveRange
functions here. Moved declarations of functions above inline function bodies.

* dom/SimpleRange.cpp:
(WebCore::createLiveRange): Moved to Range.cpp.

* dom/SimpleRange.h: Exported the constructor. Removed unneeded overload
that takes a Range*.

* editing/ApplyStyleCommand.cpp:
(WebCore::ApplyStyleCommand::mergeStartWithPreviousIfIdentical):
Refactored code a bit and use unsigned.
(WebCore::ApplyStyleCommand::mergeEndWithNextIfIdentical): Use unsigned.

* editing/Editing.cpp:
(WebCore::visibleImageElementsInRangeWithNonLoadedImages): Use a reference
to a range rather than a pointer.

* editing/Editing.h: Added a forward declaration of Range that now seems to
be needed to compile.

* editing/Editor.cpp:
(WebCore::Editor::selectedText const): Call makeBoundaryPoint twice here to
convert two Position objects into a SimpleRange.

* editing/HTMLInterchange.cpp: Removed some extra includes.
(WebCore::convertHTMLTextToInterchangeFormat): Use variadic
StringBuilder::append.

* editing/TextIterator.cpp:
(WebCore::firstNode): Added. We use this instead of Range::firstNode.
If we find we need it outside TextIterator we can find a header for it.
Not sure it would be great to add it to in BoundaryPoint.h, nor is it
obviously better as a BoundaryPoint member function.
(WebCore::TextIterator::TextIterator): Cut down on the extra constructors
and have the single remaining one take a SimpleRange.
(WebCore::SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator):
Ditto. Also change some int to unsigned.
(WebCore::CharacterIterator::CharacterIterator): Ditto.
(WebCore::BackwardsCharacterIterator::BackwardsCharacterIterator): Ditto.
(WebCore::WordAwareIterator::WordAwareIterator): Ditto.
(WebCore::TextIterator::rangeLength): Since this is one of the functions
that still takes a live range pointer, updated it to check for null and
pass a reference rather than a pointer.
(WebCore::TextIterator::rangeFromLocationAndLength): Ditto.
(WebCore::hasAnyPlainText): Removed now-unneeded call to createLiveRange.
(WebCore::plainText): Updated the main implementation to take a SimpleRange,
eliminating the version that takes two Position objects, but keeping the
one that takes a live range pointer for now.
(WebCore::plainTextReplacingNoBreakSpace): Removed all but the one, and
have that one take a SimpleRange.

* editing/TextIterator.h: Removed the include of SimpleRange.h. Also
Updated for the changes above, eliminating five different constructors
that take a live range and also overloads that take two Position objects.

* editing/TextManipulationController.cpp:
(WebCore::ParagraphContentIterator::ParagraphContentIterator):
Call makeBoundaryPoint twice here to convert two Position objects into
a SimpleRange.

* editing/VisibleSelection.cpp: Removed an include.

* editing/VisibleUnits.cpp:
(WebCore::suffixLengthForRange): Pass a reference to a range known to
not be null.
(WebCore::previousBoundary): Ditto.
(WebCore::nextBoundary): Ditto.

* editing/cocoa/DataDetection.mm:
(WebCore::buildQuery): Take a SimpleRange.
(WebCore::DataDetection::detectContentInRange): Added a null check on
a live range and pass a reference to it.
* editing/cocoa/DictionaryLookup.mm:
(WebCOre::DictionaryLookup::rangeAtHitTestResult): Ditto.

* editing/cocoa/HTMLConverter.mm:
(WebCore::editingAttributedStringFromRange): Pass a reference to a range
known to not be null.
* page/TextIndicator.cpp:
(WebCore::estimatedTextColorsForRange): Ditto.
(WebCore::containsOnlyWhiteSpaceText): Ditto.
* page/ios/FrameIOS.mm:
(WebCore::Frame::interpretationsForCurrentRoot const): Ditto.

* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::selectedText const): Added a null check on
a live range and pass a reference to it.

Source/WebKit:

* WebProcess/InjectedBundle/API/mac/WKDOMTextIterator.mm:
(-[WKDOMTextIterator initWithRange:]): Leave _textIterator as a nullptr
if the passed-in range is nil since we no longer offer a way to create
an empty TextIterator; other clients don't seem to need one.
(-[WKDOMTextIterator advance]): Add a null check.
(-[WKDOMTextIterator atEnd]): Ditto.
(-[WKDOMTextIterator currentRange]): Ditto.
(-[WKDOMTextIterator currentTextPointer]): Ditto.
(-[WKDOMTextIterator currentTextLength]): Ditto.

* WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.mm: Removed include.

* WebProcess/WebPage/ViewGestureGeometryCollector.cpp:
(WebKit::ViewGestureGeometryCollector::computeTextLegibilityScales): Pass
a reference to a range known not to be null.

* WebProcess/WebPage/WebPage.cpp: Removed an include.

* WebProcess/WebPage/ios/WebPageIOS.mm: Removed a "using naemsapce WebCore".
Added two local functions
(WebKit::plainTextForContext): Added. Helper for just this file where calling
plainTextReplacingNoBreakSpace on a possibly null Range is common.
(WebKit::plainTextForDisplay): Ditto. This one passes true for isDisplayString.
Not entirely clear how carefully we chose which of the two to call, or if there
is sufficient test coverage.
(WebKit::WebPage::platformEditorState const): Use plainTextForContext
and plainTextForDisplay.
(WebKit::WebPage::getSelectionContext): Ditto.
(WebKit::WebPage::getRectsAtSelectionOffsetWithText): Use plainTextForDisplay.
(WebKit::WebPage::requestDictationContext): Use plainTextForContext.
(WebKit::WebPage::replaceSelectedText): Ditto.
(WebKit::WebPage::replaceDictatedText): Ditto.
(WebKit::WebPage::requestAutocorrectionData): Ditto.
(WebKit::WebPage::applyAutocorrectionInternal): Ditto.
(WebKit::WebPage::autocorrectionContext): Ditto.
(WebKit::dataDetectorLinkPositionInformation): Use plainTextForDisplay.
(WebKit::WebPage::requestDocumentEditingContext): Use RetainPtr instead of
autorelease. Use makeBoundaryPoint to convert Position objects to SimpleRange.

Source/WebKitLegacy/mac:

* WebView/WebFrame.mm: Removed an include.

* WebView/WebHTMLView.mm:
(-[WebHTMLView _legacyAttributedStringFrom:offset:to:offset:]):
Add casts to unsigned.

* WebView/WebTextIterator.mm:
(-[WebTextIterator initWithRange:]): Leave _private->_textIterator
as a nullptr if the passed-in range is nil since we no longer offer
a way to create an empty TextIterator; other clients don't seem to
need one.
(-[WebTextIterator advance]): Check _private->_textIterator for null.
(-[WebTextIterator atEnd]): Ditto.
(-[WebTextIterator currentRange]): Ditto.
(-[WebTextIterator currentTextPointer]): Ditto.
(-[WebTextIterator currentTextLength]): Ditto.
(-[WebTextIterator currentNode]): Ditto.
(-[WebTextIterator currentText]): Ditto.

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

46 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/accessibility/AXObjectCache.cpp
Source/WebCore/accessibility/AccessibilityObject.cpp
Source/WebCore/accessibility/AccessibilityObjectInterface.h
Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
Source/WebCore/dom/BoundaryPoint.cpp [deleted file]
Source/WebCore/dom/BoundaryPoint.h
Source/WebCore/dom/DocumentMarkerController.cpp
Source/WebCore/dom/Position.cpp
Source/WebCore/dom/Position.h
Source/WebCore/dom/Range.cpp
Source/WebCore/dom/Range.h
Source/WebCore/dom/SimpleRange.cpp
Source/WebCore/dom/SimpleRange.h
Source/WebCore/editing/ApplyStyleCommand.cpp
Source/WebCore/editing/Editing.cpp
Source/WebCore/editing/Editing.h
Source/WebCore/editing/Editor.cpp
Source/WebCore/editing/HTMLInterchange.cpp
Source/WebCore/editing/TextIterator.cpp
Source/WebCore/editing/TextIterator.h
Source/WebCore/editing/TextManipulationController.cpp
Source/WebCore/editing/VisibleSelection.cpp
Source/WebCore/editing/VisibleUnits.cpp
Source/WebCore/editing/cocoa/DataDetection.mm
Source/WebCore/editing/cocoa/DictionaryLookup.mm
Source/WebCore/editing/cocoa/HTMLConverter.mm
Source/WebCore/page/TextIndicator.cpp
Source/WebCore/page/ios/FrameIOS.mm
Source/WebCore/rendering/HitTestResult.cpp
Source/WebCore/rendering/line/LineLayoutTraversal.h
Source/WebCore/testing/Internals.cpp
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMTextIterator.mm
Source/WebKit/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.mm
Source/WebKit/WebProcess/WebPage/ViewGestureGeometryCollector.cpp
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebView/WebFrame.mm
Source/WebKitLegacy/mac/WebView/WebHTMLView.mm
Source/WebKitLegacy/mac/WebView/WebTextIterator.mm

index 122b5a5..5b6f412 100644 (file)
@@ -1,3 +1,187 @@
+2020-03-15  Darin Adler  <darin@apple.com>
+
+        Move most of TextIterator off of live ranges
+        https://bugs.webkit.org/show_bug.cgi?id=209129
+
+        Reviewed by Antti Koivisto.
+
+        - Change almost all arguments and return values of functions in TextIterator.h
+          to use SimpleRange instead of live ranges. Exceptions are an overload of plainText
+          TextIterator::rangeLength, TextIterator::rangeFromLocationAndLength,
+          TextIterator::getLocationAndLengthFromRange, and TextIterator::subrange. Those
+          five are a little trickier to convert, so I will do them each in separate patches.
+
+        - Go with the flow in adding an include of Node.h to BoundaryPoint.h. I had avoided
+          this in the initial version, but now it seems practical to just leave it that way.
+          This led to removing BoundaryPoint.cpp and moving all functions to the header.
+
+        - Converted many member functions of the Position class from using int to unsigned
+          for offsets. The DOM specifies unsigned for offsets, but for some reason we used
+          int for them a lot historically, even though negative numbers don't make sense.
+          New classes like StaticRange, SimpleRange, and BoundaryPoint are already using
+          unsigned exclusively and we'll eventually convert everything.
+
+        - Remove includes of SimpleRange.h from files that also include TextIterator.h,
+          now that TextIterator.h pulls it in.
+
+        * Sources.txt: Removed BoundaryPoint.cpp.
+        * WebCore.xcodeproj/project.pbxproj: Ditto.
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::traverseToOffsetInRange): Updated to pass a reference
+        to a range rather than a pointer, after null-checking it.
+        (WebCore::AXObjectCache::lengthForRange): Ditto.
+        (WebCore::AXObjectCache::nextBoundary): Ditto.
+        (WebCore::AXObjectCache::previousBoundary): Ditto.
+        * accessibility/AccessibilityObject.cpp:
+        (WebCore::AccessibilityObject::stringForRange const): Ditto.
+        (WebCore::AccessibilityObject::stringForVisiblePositionRange): Ditto.
+        (WebCore::AccessibilityObject::lengthForVisiblePositionRange const): Ditto.
+
+        * accessibility/AccessibilityObjectInterface.h: Removed an extra include.
+
+        * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+        (-[WebAccessibilityObjectWrapper arrayOfTextForTextMarkers:attributed:]):
+        Updated to pass a reference to a range rather than a pointer, after null-checking it.
+        * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+        (-[WebAccessibilityObjectWrapper doAXAttributedStringForTextMarkerRange:spellCheck:]): Ditto.
+
+        * dom/BoundaryPoint.cpp: Removed.
+
+        * dom/BoundaryPoint.h: Removed redundant includes and forward declarations
+        since we're now committing to including "Node.h" here. Moved functions
+        all out of the .cpp file and made them inlines.
+
+        * dom/DocumentMarkerController.cpp:
+        (WebCore::DocumentMarkerController::collectTextRanges): Pass a reference to
+        a range instead of a pointer.
+
+        * dom/Position.cpp:
+        (WebCore::Position::Position): Take unsigned.
+        (WebCore::Position::moveToPosition): Ditto.
+        (WebCore::Position::moveToOffset): Ditto.
+        (WebCore::Position::parentAnchoredEquivalent const): Cast to unsigned.
+        (WebCore::Position::anchorTypeForLegacyEditingPosition): Take unsigned.
+        (WebCore::Position::previous const): Use unsigned.
+        (WebCore::Position::next const): Ditto.
+        (WebCore::Position::uncheckedPreviousOffset): Take unsigned.
+        (WebCore::Position::uncheckedPreviousOffsetForBackwardDeletion): Ditto.
+        (WebCore::Position::uncheckedNextOffset): Ditto.
+        (WebCore::Position::atLastEditingPositionForNode const): Cast to unsigned.
+        (WebCore::Position::atEndOfTree const): Ditto.
+        (WebCore::Position::rendersInDifferentPosition const): Added casts to
+        unsigned and also removed unneeded redundant checks. In a place where
+        we had already checked that both nodes were the same and both offsets
+        were different, we were checking the types of both nodes (but they are
+        the same so only need to check one) and we were checking that both
+        offsets were different (but we already knew they were different).
+        (WebCore::searchAheadForBetterMatch): Use unsigned.
+        (WebCore::Position::getInlineBoxAndOffset const): Ditto.
+        (WebCore::Position::equals const): Removed a cast to int.
+        (WebCore::makeBoundaryPoint): Moved this function here so now it can be
+        used in more places.
+
+        * dom/Position.h: Changed many argument types to unsigned. Moved declarations
+        of all the functions up above all the inline implementations of the functions
+        to separate interface from implementation a bit better. Wrote a FIXME about
+        the name createLegacyEditingPosition. Moved makeBoundaryPoint here and exported
+        it from WebCore so we can use it from more places.
+
+        * dom/Range.cpp:
+        (WebCore::createLiveRange): Moved these functions here from SimpleRange.cpp
+        because a live range is more advanced concept, so makes more sense for live
+        range to know about simple range rather than vice versa.
+
+        * dom/Range.h: Removed some unneeded includes and forward declarations.
+        Added a FIXME about renaming to LiveRange. Moved the createLiveRange
+        functions here. Moved declarations of functions above inline function bodies.
+
+        * dom/SimpleRange.cpp:
+        (WebCore::createLiveRange): Moved to Range.cpp.
+
+        * dom/SimpleRange.h: Exported the constructor. Removed unneeded overload
+        that takes a Range*.
+
+        * editing/ApplyStyleCommand.cpp:
+        (WebCore::ApplyStyleCommand::mergeStartWithPreviousIfIdentical):
+        Refactored code a bit and use unsigned.
+        (WebCore::ApplyStyleCommand::mergeEndWithNextIfIdentical): Use unsigned.
+
+        * editing/Editing.cpp:
+        (WebCore::visibleImageElementsInRangeWithNonLoadedImages): Use a reference
+        to a range rather than a pointer.
+
+        * editing/Editing.h: Added a forward declaration of Range that now seems to
+        be needed to compile.
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::selectedText const): Call makeBoundaryPoint twice here to
+        convert two Position objects into a SimpleRange.
+
+        * editing/HTMLInterchange.cpp: Removed some extra includes.
+        (WebCore::convertHTMLTextToInterchangeFormat): Use variadic
+        StringBuilder::append.
+
+        * editing/TextIterator.cpp:
+        (WebCore::firstNode): Added. We use this instead of Range::firstNode.
+        If we find we need it outside TextIterator we can find a header for it.
+        Not sure it would be great to add it to in BoundaryPoint.h, nor is it
+        obviously better as a BoundaryPoint member function.
+        (WebCore::TextIterator::TextIterator): Cut down on the extra constructors
+        and have the single remaining one take a SimpleRange.
+        (WebCore::SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator):
+        Ditto. Also change some int to unsigned.
+        (WebCore::CharacterIterator::CharacterIterator): Ditto.
+        (WebCore::BackwardsCharacterIterator::BackwardsCharacterIterator): Ditto.
+        (WebCore::WordAwareIterator::WordAwareIterator): Ditto.
+        (WebCore::TextIterator::rangeLength): Since this is one of the functions
+        that still takes a live range pointer, updated it to check for null and
+        pass a reference rather than a pointer.
+        (WebCore::TextIterator::rangeFromLocationAndLength): Ditto.
+        (WebCore::hasAnyPlainText): Removed now-unneeded call to createLiveRange.
+        (WebCore::plainText): Updated the main implementation to take a SimpleRange,
+        eliminating the version that takes two Position objects, but keeping the
+        one that takes a live range pointer for now.
+        (WebCore::plainTextReplacingNoBreakSpace): Removed all but the one, and
+        have that one take a SimpleRange.
+
+        * editing/TextIterator.h: Removed the include of SimpleRange.h. Also
+        Updated for the changes above, eliminating five different constructors
+        that take a live range and also overloads that take two Position objects.
+
+        * editing/TextManipulationController.cpp:
+        (WebCore::ParagraphContentIterator::ParagraphContentIterator):
+        Call makeBoundaryPoint twice here to convert two Position objects into
+        a SimpleRange.
+
+        * editing/VisibleSelection.cpp: Removed an include.
+
+        * editing/VisibleUnits.cpp:
+        (WebCore::suffixLengthForRange): Pass a reference to a range known to
+        not be null.
+        (WebCore::previousBoundary): Ditto.
+        (WebCore::nextBoundary): Ditto.
+
+        * editing/cocoa/DataDetection.mm:
+        (WebCore::buildQuery): Take a SimpleRange.
+        (WebCore::DataDetection::detectContentInRange): Added a null check on
+        a live range and pass a reference to it.
+        * editing/cocoa/DictionaryLookup.mm:
+        (WebCOre::DictionaryLookup::rangeAtHitTestResult): Ditto.
+
+        * editing/cocoa/HTMLConverter.mm:
+        (WebCore::editingAttributedStringFromRange): Pass a reference to a range
+        known to not be null.
+        * page/TextIndicator.cpp:
+        (WebCore::estimatedTextColorsForRange): Ditto.
+        (WebCore::containsOnlyWhiteSpaceText): Ditto.
+        * page/ios/FrameIOS.mm:
+        (WebCore::Frame::interpretationsForCurrentRoot const): Ditto.
+
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::selectedText const): Added a null check on
+        a live range and pass a reference to it.
+
 2020-03-16  Pinki Gyanchandani  <pgyanchandani@apple.com>
 
         Crash in CSSValue::isPrimitiveValue
@@ -231,6 +415,9 @@ r       By default, the method does nothing and RealtimeOutgoingVideoSource will
         * Modules/mediastream/RTCRtpSender.cpp:
         (WebCore::RTCRtpSender::dtmf):
 
+        * rendering/line/LineLayoutTraversal.h: Removed some unneeded includes.
+        * testing/Internals.cpp: Ditto.
+
 2020-03-13  Sergio Villar Senin  <svillar@igalia.com>
 
         [WebXR] IDLs, stubs and build configuration for WPE
index 401cad4..cfcefb9 100644 (file)
@@ -850,7 +850,6 @@ dom/Attr.cpp
 dom/BeforeLoadEvent.cpp
 dom/BeforeTextInsertedEvent.cpp
 dom/BeforeUnloadEvent.cpp
-dom/BoundaryPoint.cpp
 dom/CDATASection.cpp
 dom/CharacterData.cpp
 dom/ChildListMutationScope.cpp
index 6fbc8b0..753f7e4 100644 (file)
                93153BE114195A5700FCF5BE /* missingImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = missingImage.png; sourceTree = "<group>"; };
                9316DDF8240C64B3009340AA /* SimpleRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleRange.h; sourceTree = "<group>"; };
                9316DDFA240C64B3009340AA /* SimpleRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleRange.cpp; sourceTree = "<group>"; };
-               9316DDFD240C64F8009340AA /* BoundaryPoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BoundaryPoint.cpp; sourceTree = "<group>"; };
                9316DDFE240C64F8009340AA /* BoundaryPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BoundaryPoint.h; sourceTree = "<group>"; };
                931AE3B81FB80EAE00F5EFB2 /* JSValueInWrappedObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSValueInWrappedObject.h; sourceTree = "<group>"; };
                931BCC601124DFCB00BE70DD /* MediaCanStartListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaCanStartListener.h; sourceTree = "<group>"; };
                                85031B260A44EFC700F992E0 /* BeforeUnloadEvent.cpp */,
                                85031B270A44EFC700F992E0 /* BeforeUnloadEvent.h */,
                                7C1E8CFF1ED0C2BE00B1D983 /* BeforeUnloadEvent.idl */,
-                               9316DDFD240C64F8009340AA /* BoundaryPoint.cpp */,
                                9316DDFE240C64F8009340AA /* BoundaryPoint.h */,
                                7C1E8D001ED0C2BE00B1D983 /* CallbackResult.h */,
                                6550B693099DF0270090D781 /* CDATASection.cpp */,
index 1eb626b..d4e5c98 100644 (file)
@@ -99,7 +99,6 @@
 #include "SVGElement.h"
 #include "ScriptDisallowedScope.h"
 #include "ScrollView.h"
-#include "SimpleRange.h"
 #include "TextBoundaries.h"
 #include "TextControlInnerElements.h"
 #include "TextIterator.h"
@@ -1791,7 +1790,7 @@ CharacterOffset AXObjectCache::traverseToOffsetInRange(RefPtr<Range>range, int o
     bool finished = false;
     int lastStartOffset = 0;
     
-    TextIterator iterator(range.get(), doNotEnterTextControls ? TextIteratorDefaultBehavior : TextIteratorEntersTextControls);
+    TextIterator iterator(*range, doNotEnterTextControls ? TextIteratorDefaultBehavior : TextIteratorEntersTextControls);
     
     // When the range has zero length, there might be replaced node or brTag that we need to increment the characterOffset.
     if (iterator.atEnd()) {
@@ -1902,7 +1901,7 @@ int AXObjectCache::lengthForRange(Range* range)
     if (!range)
         return -1;
     int length = 0;
-    for (TextIterator it(range); !it.atEnd(); it.advance()) {
+    for (TextIterator it(*range); !it.atEnd(); it.advance()) {
         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
         if (it.text().length())
             length += it.text().length();
@@ -2602,7 +2601,7 @@ CharacterOffset AXObjectCache::nextBoundary(const CharacterOffset& characterOffs
         return { };
     CharacterOffset end = startOrEndCharacterOffsetForRange(searchRange, false);
     
-    TextIterator it(searchRange.get(), TextIteratorEmitsObjectReplacementCharacters);
+    TextIterator it(*searchRange, TextIteratorEmitsObjectReplacementCharacters);
     unsigned next = forwardSearchForBoundaryWithTextIterator(it, string, prefixLength, searchFunction);
     
     if (it.atEnd() && next == string.size())
@@ -2643,7 +2642,7 @@ CharacterOffset AXObjectCache::previousBoundary(const CharacterOffset& character
             return { };
         if (!setRangeStartOrEndWithCharacterOffset(forwardsScanRange, endOfCurrentParagraph, false))
             return { };
-        for (TextIterator forwardsIterator(forwardsScanRange.ptr()); !forwardsIterator.atEnd(); forwardsIterator.advance())
+        for (TextIterator forwardsIterator(forwardsScanRange); !forwardsIterator.atEnd(); forwardsIterator.advance())
             append(string, forwardsIterator.text());
         suffixLength = string.size();
     } else if (requiresContextForWordBoundary(characterBefore(characterOffset))) {
@@ -2666,7 +2665,7 @@ CharacterOffset AXObjectCache::previousBoundary(const CharacterOffset& character
         return it.atEnd() ? start : characterOffset;
     
     auto& node = it.atEnd() ? searchRange->startContainer() : it.range().start.container.get();
-    
+
     // SimplifiedBackwardsTextIterator ignores replaced elements.
     if (AccessibilityObject::replacedNodeNeedsCharacter(characterOffset.node))
         return characterOffsetForNodeAndOffset(*characterOffset.node, 0);
index 619121d..45c0b07 100644 (file)
@@ -1267,7 +1267,7 @@ String AccessibilityObject::stringForRange(RefPtr<Range> range) const
     if (!range)
         return String();
     
-    TextIterator it(range.get());
+    TextIterator it(*range);
     if (it.atEnd())
         return String();
     
@@ -1296,7 +1296,10 @@ String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionR
 
     StringBuilder builder;
     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
-    for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
+    if (!range)
+        return String();
+
+    for (TextIterator it(*range); !it.atEnd(); it.advance()) {
         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
         if (it.text().length()) {
             // Add a textual representation for list marker text.
@@ -1318,9 +1321,12 @@ int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRang
     if (visiblePositionRange.isNull())
         return -1;
 
-    int length = 0;
     RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
-    for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
+    if (!range)
+        return -1;
+
+    int length = 0;
+    for (TextIterator it(*range); !it.atEnd(); it.advance()) {
         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
         if (it.text().length())
             length += it.text().length();
@@ -1329,7 +1335,6 @@ int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRang
                 ++length;
         }
     }
-
     return length;
 }
 
index e4d1d9a..cbb6208 100644 (file)
@@ -29,7 +29,6 @@
 #include "LayoutRect.h"
 #include "Range.h"
 #include "TextIterator.h"
-#include "TextIteratorBehavior.h"
 #include "VisiblePosition.h"
 #include "VisibleSelection.h"
 #include <wtf/RefCounted.h>
index c31308e..101eb2d 100644 (file)
@@ -54,7 +54,6 @@
 #import "SVGNames.h"
 #import "SVGElement.h"
 #import "SelectionRect.h"
-#import "SimpleRange.h"
 #import "TextIterator.h"
 #import "WAKScrollView.h"
 #import "WAKWindow.h"
@@ -2253,10 +2252,14 @@ static void AXAttributedStringAppendText(NSMutableAttributedString* attrString,
     VisiblePosition endVisiblePosition = [endMarker visiblePosition];
     if (endVisiblePosition.isNull())
         return nil;
-    
+
+    auto range = makeRange(startVisiblePosition, endVisiblePosition);
+    if (!range)
+        return nil;
+
     // iterate over the range to build the AX attributed string
     NSMutableArray* array = [[NSMutableArray alloc] init];
-    TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
+    TextIterator it(*range);
     for (; !it.atEnd(); it.advance()) {
         Node& node = it.range().start.container;
 
index 85351a2..2b08454 100644 (file)
@@ -70,7 +70,6 @@
 #import "RenderView.h"
 #import "RenderWidget.h"
 #import "ScrollView.h"
-#import "SimpleRange.h"
 #import "TextCheckerClient.h"
 #import "TextCheckingHelper.h"
 #import "TextDecorationPainter.h"
@@ -1255,7 +1254,9 @@ static NSString* nsStringForReplacedNode(Node* replacedNode)
 
         RefPtr<Range> range = [protectedSelf rangeForTextMarkerRange:textMarkerRange];
         NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
-        TextIterator it(range.get());
+        if (!range)
+            return nil;
+        TextIterator it(*range);
         while (!it.atEnd()) {
             Node& node = it.range().start.container;
 
diff --git a/Source/WebCore/dom/BoundaryPoint.cpp b/Source/WebCore/dom/BoundaryPoint.cpp
deleted file mode 100644 (file)
index 87e0f36..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 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
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "BoundaryPoint.h"
-
-#include "Node.h"
-
-namespace WebCore {
-
-BoundaryPoint::BoundaryPoint(const BoundaryPoint& other)
-    : container(other.container.copyRef())
-    , offset(other.offset)
-{
-}
-
-BoundaryPoint& BoundaryPoint::operator=(const BoundaryPoint& other)
-{
-    container = other.container.copyRef();
-    offset = other.offset;
-    return *this;
-}
-
-BoundaryPoint& BoundaryPoint::operator=(BoundaryPoint&&) = default;
-
-Document& BoundaryPoint::document() const
-{
-    return container->document();
-}
-
-}
index 690f6f9..a5d8e3e 100644 (file)
 
 #include "Node.h"
 
-#include <wtf/Ref.h>
-
 namespace WebCore {
 
-class Document;
-
 struct BoundaryPoint {
     Ref<Node> container;
     unsigned offset { 0 };
@@ -43,7 +39,7 @@ struct BoundaryPoint {
     BoundaryPoint(const BoundaryPoint&);
     BoundaryPoint(BoundaryPoint&&) = default;
     BoundaryPoint& operator=(const BoundaryPoint&);
-    BoundaryPoint& operator=(BoundaryPoint&&);
+    BoundaryPoint& operator=(BoundaryPoint&&) = default;
 
     Document& document() const;
 };
@@ -56,6 +52,24 @@ inline BoundaryPoint::BoundaryPoint(Ref<Node>&& container, unsigned offset)
 {
 }
 
+inline BoundaryPoint::BoundaryPoint(const BoundaryPoint& other)
+    : container(other.container.copyRef())
+    , offset(other.offset)
+{
+}
+
+inline BoundaryPoint& BoundaryPoint::operator=(const BoundaryPoint& other)
+{
+    container = other.container.copyRef();
+    offset = other.offset;
+    return *this;
+}
+
+inline Document& BoundaryPoint::document() const
+{
+    return container->document();
+}
+
 inline bool operator==(const BoundaryPoint& a, const BoundaryPoint& b)
 {
     return a.container.ptr() == b.container.ptr() && a.offset == b.offset;
index cc72847..f4e5175 100644 (file)
@@ -63,7 +63,7 @@ void DocumentMarkerController::detach()
 Vector<RefPtr<Range>> DocumentMarkerController::collectTextRanges(const Range& range)
 {
     Vector<RefPtr<Range>> textRange;
-    for (TextIterator textIterator(&range); !textIterator.atEnd(); textIterator.advance())
+    for (TextIterator textIterator(range); !textIterator.atEnd(); textIterator.advance())
         textRange.append(createLiveRange(textIterator.range()));
     return textRange;
 }
index a820098..38bd413 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004, 2005, 2006, 2009, 2013 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
@@ -125,7 +125,7 @@ Position::Position(Node* anchorNode, AnchorType anchorType)
         && (is<Text>(*m_anchorNode) || editingIgnoresContent(*m_anchorNode))));
 }
 
-Position::Position(Node* anchorNode, int offset, AnchorType anchorType)
+Position::Position(Node* anchorNode, unsigned offset, AnchorType anchorType)
     : m_anchorNode(anchorNode)
     , m_offset(offset)
     , m_anchorType(anchorType)
@@ -145,7 +145,7 @@ Position::Position(Text* textNode, unsigned offset)
     ASSERT(m_anchorNode);
 }
 
-void Position::moveToPosition(Node* node, int offset)
+void Position::moveToPosition(Node* node, unsigned offset)
 {
     ASSERT(!editingIgnoresContent(*node));
     ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
@@ -154,7 +154,8 @@ void Position::moveToPosition(Node* node, int offset)
     if (m_isLegacyEditingPosition)
         m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
 }
-void Position::moveToOffset(int offset)
+
+void Position::moveToOffset(unsigned offset)
 {
     ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
     m_offset = offset;
@@ -247,7 +248,7 @@ Position Position::parentAnchoredEquivalent() const
         return positionInParentAfterNode(m_anchorNode.get());
     }
 
-    return { containerNode(), computeOffsetInContainerNode(), PositionIsOffsetInAnchor };
+    return { containerNode(), static_cast<unsigned>(computeOffsetInContainerNode()), PositionIsOffsetInAnchor };
 }
 
 RefPtr<Node> Position::firstNode() const
@@ -306,7 +307,7 @@ Node* Position::computeNodeAfterPosition() const
     return nullptr;
 }
 
-Position::AnchorType Position::anchorTypeForLegacyEditingPosition(Node* anchorNode, int offset)
+Position::AnchorType Position::anchorTypeForLegacyEditingPosition(Node* anchorNode, unsigned offset)
 {
     if (anchorNode && editingIgnoresContent(*anchorNode)) {
         if (offset == 0)
@@ -331,9 +332,10 @@ Position Position::previous(PositionMoveType moveType) const
     if (!node)
         return *this;
 
-    int offset = deprecatedEditingOffset();
     // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
-    ASSERT(offset >= 0);
+    ASSERT(deprecatedEditingOffset() >= 0);
+
+    unsigned offset = deprecatedEditingOffset();
 
     if (anchorType() == PositionIsBeforeAnchor) {
         node = containerNode();
@@ -384,9 +386,10 @@ Position Position::next(PositionMoveType moveType) const
     if (!node)
         return *this;
 
-    int offset = deprecatedEditingOffset();
     // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
-    ASSERT(offset >= 0);
+    ASSERT(deprecatedEditingOffset() >= 0);
+
+    unsigned offset = deprecatedEditingOffset();
 
     if (anchorType() == PositionIsAfterAnchor) {
         node = containerNode();
@@ -397,7 +400,7 @@ Position Position::next(PositionMoveType moveType) const
     }
 
     Node* child = node->traverseToChildAt(offset);
-    if (child || (!node->hasChildNodes() && offset < lastOffsetForEditing(*node))) {
+    if (child || (!node->hasChildNodes() && offset < static_cast<unsigned>(lastOffsetForEditing(*node)))) {
         if (child)
             return firstPositionInOrBeforeNode(child);
 
@@ -423,17 +426,17 @@ Position Position::next(PositionMoveType moveType) const
     return createLegacyEditingPosition(parent, node->computeNodeIndex() + 1);
 }
 
-int Position::uncheckedPreviousOffset(const Node* n, int current)
+int Position::uncheckedPreviousOffset(const Node* n, unsigned current)
 {
     return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
 }
 
-int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current)
+int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, unsigned current)
 {
     return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1;
 }
 
-int Position::uncheckedNextOffset(const Node* n, int current)
+int Position::uncheckedNextOffset(const Node* n, unsigned current)
 {
     return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
 }
@@ -462,9 +465,8 @@ bool Position::atLastEditingPositionForNode() const
 {
     if (isNull())
         return true;
-    // FIXME: Position after anchor shouldn't be considered as at the first editing position for node
-    // since that position resides outside of the node.
-    return m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || m_offset >= lastOffsetForEditing(*deprecatedNode());
+    // FIXME: Position after anchor shouldn't be considered as at the first editing position for node since that position resides outside of the node.
+    return m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || m_offset >= static_cast<unsigned>(lastOffsetForEditing(*deprecatedNode()));
 }
 
 // A position is considered at editing boundary if one of the following is true:
@@ -541,7 +543,7 @@ bool Position::atEndOfTree() const
 
     switch (m_anchorType) {
     case PositionIsOffsetInAnchor:
-        return m_offset >= lastOffsetForEditing(*m_anchorNode);
+        return m_offset >= static_cast<unsigned>(lastOffsetForEditing(*m_anchorNode));
     case PositionIsBeforeAnchor:
         return false;
     case PositionIsAfterAnchor:
@@ -1038,13 +1040,11 @@ bool Position::rendersInDifferentPosition(const Position& position) const
         if (is<HTMLBRElement>(*deprecatedNode()))
             return false;
 
-        if (m_offset == position.deprecatedEditingOffset())
+        if (m_offset == static_cast<unsigned>(position.deprecatedEditingOffset()))
             return false;
 
-        if (!is<Text>(*deprecatedNode()) && !is<Text>(*position.deprecatedNode())) {
-            if (m_offset != position.deprecatedEditingOffset())
-                return true;
-        }
+        if (!is<Text>(*deprecatedNode()))
+            return true;
     }
 
     if (is<HTMLBRElement>(*deprecatedNode()) && position.isCandidate())
@@ -1062,8 +1062,8 @@ bool Position::rendersInDifferentPosition(const Position& position) const
     if (is<RenderText>(*positionRenderer) && !downcast<RenderText>(*positionRenderer).containsCaretOffset(position.m_offset))
         return false;
 
-    int thisRenderedOffset = is<RenderText>(*renderer) ? downcast<RenderText>(*renderer).countRenderedCharacterOffsetsUntil(m_offset) : m_offset;
-    int positionRenderedOffset = is<RenderText>(*positionRenderer) ? downcast<RenderText>(*positionRenderer).countRenderedCharacterOffsetsUntil(position.m_offset) : position.m_offset;
+    unsigned thisRenderedOffset = is<RenderText>(*renderer) ? downcast<RenderText>(*renderer).countRenderedCharacterOffsetsUntil(m_offset) : m_offset;
+    unsigned positionRenderedOffset = is<RenderText>(*positionRenderer) ? downcast<RenderText>(*positionRenderer).countRenderedCharacterOffsetsUntil(position.m_offset) : position.m_offset;
 
     if (renderer == positionRenderer && thisRenderedOffset == positionRenderedOffset)
         return false;
@@ -1091,12 +1091,12 @@ bool Position::rendersInDifferentPosition(const Position& position) const
     }
 
     if (nextRenderedEditable(deprecatedNode()) == position.deprecatedNode()
-        && thisRenderedOffset == caretMaxOffset(*deprecatedNode()) && !positionRenderedOffset) {
+        && thisRenderedOffset == static_cast<unsigned>(caretMaxOffset(*deprecatedNode())) && !positionRenderedOffset) {
         return false;
     }
     
     if (previousRenderedEditable(deprecatedNode()) == position.deprecatedNode()
-        && !thisRenderedOffset && positionRenderedOffset == caretMaxOffset(*position.deprecatedNode())) {
+        && !thisRenderedOffset && positionRenderedOffset == static_cast<unsigned>(caretMaxOffset(*position.deprecatedNode()))) {
         return false;
     }
 
@@ -1167,9 +1167,9 @@ static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
             return nullptr;
         if (is<RenderText>(*next)) {
             InlineTextBox* match = nullptr;
-            int minOffset = INT_MAX;
+            unsigned minOffset = std::numeric_limits<unsigned>::max();
             for (InlineTextBox* box = downcast<RenderText>(*next).firstTextBox(); box; box = box->nextTextBox()) {
-                int caretMinOffset = box->caretMinOffset();
+                unsigned caretMinOffset = box->caretMinOffset();
                 if (caretMinOffset < minOffset) {
                     match = box;
                     minOffset = caretMinOffset;
@@ -1219,20 +1219,20 @@ void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi
         InlineTextBox* candidate = nullptr;
 
         for (box = textRenderer.firstTextBox(); box; box = box->nextTextBox()) {
-            int caretMinOffset = box->caretMinOffset();
-            int caretMaxOffset = box->caretMaxOffset();
+            unsigned caretMinOffset = box->caretMinOffset();
+            unsigned caretMaxOffset = box->caretMaxOffset();
 
-            if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
+            if (static_cast<unsigned>(caretOffset) < caretMinOffset || static_cast<unsigned>(caretOffset) > caretMaxOffset || (static_cast<unsigned>(caretOffset) == caretMaxOffset && box->isLineBreak()))
                 continue;
 
-            if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
+            if (static_cast<unsigned>(caretOffset) > caretMinOffset && static_cast<unsigned>(caretOffset) < caretMaxOffset) {
                 inlineBox = box;
                 return;
             }
 
-            if (((caretOffset == caretMaxOffset) ^ (affinity == DOWNSTREAM))
-                || ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM))
-                || (caretOffset == caretMaxOffset && box->nextLeafOnLine() && box->nextLeafOnLine()->isLineBreak()))
+            if (((static_cast<unsigned>(caretOffset) == caretMaxOffset) ^ (affinity == DOWNSTREAM))
+                || ((static_cast<unsigned>(caretOffset) == caretMinOffset) ^ (affinity == UPSTREAM))
+                || (static_cast<unsigned>(caretOffset) == caretMaxOffset && box->nextLeafOnLine() && box->nextLeafOnLine()->isLineBreak()))
                 break;
 
             candidate = box;
@@ -1478,7 +1478,7 @@ bool Position::equals(const Position& other) const
             return m_anchorNode == other.m_anchorNode && !m_offset;
         case PositionIsAfterChildren:
             ASSERT(!is<Text>(*other.m_anchorNode));
-            return m_anchorNode == other.m_anchorNode && m_offset == static_cast<int>(other.m_anchorNode->countChildNodes());
+            return m_anchorNode == other.m_anchorNode && m_offset == other.m_anchorNode->countChildNodes();
         case PositionIsOffsetInAnchor:
             return m_anchorNode == other.m_anchorNode && m_offset == other.m_offset;
         case PositionIsBeforeAnchor:
@@ -1598,6 +1598,13 @@ Position createLegacyEditingPosition(const BoundaryPoint& point)
     return createLegacyEditingPosition(point.container.ptr(), point.offset);
 }
 
+Optional<BoundaryPoint> makeBoundaryPoint(const Position& position)
+{
+    if (position.isNull())
+        return WTF::nullopt;
+    return BoundaryPoint { *position.containerNode(), static_cast<unsigned>(position.computeOffsetInContainerNode()) };
+}
+
 } // namespace WebCore
 
 #if ENABLE(TREE_DEBUGGING)
index 64c2d18..993e951 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004, 2006, 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
@@ -69,7 +69,7 @@ public:
 
     // For creating offset positions:
     // FIXME: This constructor should eventually go away. See bug 63040.
-    WEBCORE_EXPORT Position(Node* anchorNode, int offset, AnchorType);
+    WEBCORE_EXPORT Position(Node* anchorNode, unsigned offset, AnchorType);
 
     AnchorType anchorType() const { return static_cast<AnchorType>(m_anchorType); }
 
@@ -121,8 +121,8 @@ public:
 
     // These should only be used for PositionIsOffsetInAnchor positions, unless
     // the position is a legacy editing position.
-    void moveToPosition(Node* anchorNode, int offset);
-    void moveToOffset(int offset);
+    void moveToPosition(Node* anchorNode, unsigned offset);
+    void moveToOffset(unsigned offset);
 
     bool isNull() const { return !m_anchorNode; }
     bool isNotNull() const { return m_anchorNode; }
@@ -135,9 +135,9 @@ public:
     // using composed characters, the result may be inside a single user-visible character if a ligature is formed.
     WEBCORE_EXPORT Position previous(PositionMoveType = CodePoint) const;
     WEBCORE_EXPORT Position next(PositionMoveType = CodePoint) const;
-    static int uncheckedPreviousOffset(const Node*, int current);
-    static int uncheckedPreviousOffsetForBackwardDeletion(const Node*, int current);
-    static int uncheckedNextOffset(const Node*, int current);
+    static int uncheckedPreviousOffset(const Node*, unsigned current);
+    static int uncheckedPreviousOffsetForBackwardDeletion(const Node*, unsigned current);
+    static int uncheckedNextOffset(const Node*, unsigned current);
 
     // These can be either inside or just before/after the node, depending on
     // if the node is ignored by editing or not.
@@ -206,19 +206,52 @@ private:
     Position previousCharacterPosition(EAffinity) const;
     Position nextCharacterPosition(EAffinity) const;
 
-    static AnchorType anchorTypeForLegacyEditingPosition(Node* anchorNode, int offset);
+    static AnchorType anchorTypeForLegacyEditingPosition(Node* anchorNode, unsigned offset);
 
     RefPtr<Node> m_anchorNode;
     // m_offset can be the offset inside m_anchorNode, or if editingIgnoresContent(m_anchorNode)
     // returns true, then other places in editing will treat m_offset == 0 as "before the anchor"
     // and m_offset > 0 as "after the anchor node".  See parentAnchoredEquivalent for more info.
-    int m_offset { 0 };
+    unsigned m_offset { 0 };
     unsigned m_anchorType : 3;
     bool m_isLegacyEditingPosition : 1;
 };
 
+bool operator==(const Position&, const Position&);
+bool operator!=(const Position&, const Position&);
+bool operator<(const Position&, const Position&);
+bool operator>(const Position&, const Position&);
+bool operator>=(const Position&, const Position&);
+bool operator<=(const Position&, const Position&);
+
+// FIXME: Consider renaming this to "make" instead of "create" since we normally use "create" for functions that allocate heap objects.
+Position createLegacyEditingPosition(Node*, unsigned offset);
 Position createLegacyEditingPosition(const BoundaryPoint&);
 
+WEBCORE_EXPORT Optional<BoundaryPoint> makeBoundaryPoint(const Position&);
+
+Position positionInParentBeforeNode(Node*);
+Position positionInParentAfterNode(Node*);
+
+// positionBeforeNode and positionAfterNode return neighbor-anchored positions, construction is O(1)
+Position positionBeforeNode(Node* anchorNode);
+Position positionAfterNode(Node* anchorNode);
+
+int lastOffsetInNode(Node*);
+
+// firstPositionInNode and lastPositionInNode return parent-anchored positions, lastPositionInNode construction is O(n) due to countChildNodes()
+Position firstPositionInNode(Node* anchorNode);
+Position lastPositionInNode(Node* anchorNode);
+
+int minOffsetForNode(Node* anchorNode, unsigned offset);
+bool offsetIsBeforeLastNodeOffset(unsigned offset, Node* anchorNode);
+
+RefPtr<Node> commonShadowIncludingAncestor(const Position&, const Position&);
+
+WTF::TextStream& operator<<(WTF::TextStream&, const Position&);
+
+// inlines
+
 inline Position createLegacyEditingPosition(Node* node, unsigned offset)
 {
     return { node, offset, Position::LegacyEditingPositionFlag::On };
@@ -260,9 +293,6 @@ inline bool operator<=(const Position& a, const Position& b)
     return !a.isNull() && !b.isNull() && (a == b || a < b);
 }
 
-Position positionInParentBeforeNode(Node*);
-Position positionInParentAfterNode(Node*);
-
 // positionBeforeNode and positionAfterNode return neighbor-anchored positions, construction is O(1)
 inline Position positionBeforeNode(Node* anchorNode)
 {
@@ -278,7 +308,7 @@ inline Position positionAfterNode(Node* anchorNode)
 
 inline int lastOffsetInNode(Node* node)
 {
-    return node->isCharacterDataNode() ? node->maxCharacterOffset() : static_cast<int>(node->countChildNodes());
+    return node->isCharacterDataNode() ? node->maxCharacterOffset() : node->countChildNodes();
 }
 
 // firstPositionInNode and lastPositionInNode return parent-anchored positions, lastPositionInNode construction is O(n) due to countChildNodes()
@@ -296,24 +326,24 @@ inline Position lastPositionInNode(Node* anchorNode)
     return Position(anchorNode, Position::PositionIsAfterChildren);
 }
 
-inline int minOffsetForNode(Node* anchorNode, int offset)
+inline int minOffsetForNode(Node* anchorNode, unsigned offset)
 {
     if (anchorNode->isCharacterDataNode())
-        return std::min(offset, anchorNode->maxCharacterOffset());
+        return std::min<unsigned>(offset, anchorNode->maxCharacterOffset());
 
-    int newOffset = 0;
+    unsigned newOffset = 0;
     for (Node* node = anchorNode->firstChild(); node && newOffset < offset; node = node->nextSibling())
         newOffset++;
     
     return newOffset;
 }
 
-inline bool offsetIsBeforeLastNodeOffset(int offset, Node* anchorNode)
+inline bool offsetIsBeforeLastNodeOffset(unsigned offset, Node* anchorNode)
 {
     if (anchorNode->isCharacterDataNode())
-        return offset < anchorNode->maxCharacterOffset();
+        return offset < static_cast<unsigned>(anchorNode->maxCharacterOffset());
 
-    int currentOffset = 0;
+    unsigned currentOffset = 0;
     for (Node* node = anchorNode->firstChild(); node && currentOffset < offset; node = node->nextSibling())
         currentOffset++;
     
@@ -321,10 +351,6 @@ inline bool offsetIsBeforeLastNodeOffset(int offset, Node* anchorNode)
     return offset < currentOffset;
 }
 
-RefPtr<Node> commonShadowIncludingAncestor(const Position&, const Position&);
-
-WTF::TextStream& operator<<(WTF::TextStream&, const Position&);
-
 } // namespace WebCore
 
 #if ENABLE(TREE_DEBUGGING)
index 9c11340..45c1bcf 100644 (file)
@@ -1869,6 +1869,18 @@ FloatRect Range::absoluteBoundingRect(OptionSet<BoundingRectBehavior> rectOption
     return boundingRect(CoordinateSpace::Absolute, rectOptions);
 }
 
+Ref<Range> createLiveRange(const SimpleRange& range)
+{
+    return Range::create(range.start.document(), range.start.container.ptr(), range.start.offset, range.end.container.ptr(), range.end.offset);
+}
+
+RefPtr<Range> createLiveRange(const Optional<SimpleRange>& range)
+{
+    if (!range)
+        return nullptr;
+    return createLiveRange(*range);
+}
+
 WTF::TextStream& operator<<(WTF::TextStream& ts, const RangeBoundaryPoint& r)
 {
     return ts << r.toPosition();
index b493c7c..69cf2b9 100644 (file)
@@ -3,7 +3,7 @@
  * (C) 2000 Gunnstein Lye (gunnstein@netcom.no)
  * (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include "FloatRect.h"
 #include "IntRect.h"
 #include "RangeBoundaryPoint.h"
-#include <wtf/Forward.h>
 #include <wtf/OptionSet.h>
-#include <wtf/RefCounted.h>
-#include <wtf/Vector.h>
 
 namespace WebCore {
 
-class ContainerNode;
 class DOMRect;
 class DOMRectList;
-class Document;
 class DocumentFragment;
 class FloatQuad;
-class Node;
 class NodeWithIndex;
 class RenderText;
 class SelectionRect;
 class Text;
 class VisiblePosition;
 
+struct SimpleRange;
+
+// FIXME: Rename to LiveRange, while leaving the DOM-exposed name as Range.
 class Range : public RefCounted<Range> {
 public:
     WEBCORE_EXPORT static Ref<Range> create(Document&);
@@ -185,15 +182,20 @@ WEBCORE_EXPORT Ref<Range> rangeOfContents(Node&);
 WEBCORE_EXPORT bool areRangesEqual(const Range*, const Range*);
 WEBCORE_EXPORT bool rangesOverlap(const Range*, const Range*);
 
+WEBCORE_EXPORT Ref<Range> createLiveRange(const SimpleRange&);
+WEBCORE_EXPORT RefPtr<Range> createLiveRange(const Optional<SimpleRange>&);
+
+bool documentOrderComparator(const Node*, const Node*);
+
+WTF::TextStream& operator<<(WTF::TextStream&, const RangeBoundaryPoint&);
+WTF::TextStream& operator<<(WTF::TextStream&, const Range&);
+
 inline bool documentOrderComparator(const Node* a, const Node* b)
 {
     return Range::compareBoundaryPoints(const_cast<Node*>(a), 0, const_cast<Node*>(b), 0).releaseReturnValue() < 0;
 }
-    
-WTF::TextStream& operator<<(WTF::TextStream&, const RangeBoundaryPoint&);
-WTF::TextStream& operator<<(WTF::TextStream&, const Range&);
 
-} // namespace
+} // namespace WebCore
 
 #if ENABLE(TREE_DEBUGGING)
 // Outside the WebCore namespace for ease of invocation from the debugger.
index 09df99c..b4fe2b8 100644 (file)
@@ -53,16 +53,4 @@ bool operator==(const SimpleRange& a, const SimpleRange& b)
     return a.start == b.start && a.end == b.end;
 }
 
-Ref<Range> createLiveRange(const SimpleRange& range)
-{
-    return Range::create(range.start.document(), range.start.container.ptr(), range.start.offset, range.end.container.ptr(), range.end.offset);
-}
-
-RefPtr<Range> createLiveRange(const Optional<SimpleRange>& range)
-{
-    if (!range)
-        return nullptr;
-    return createLiveRange(*range);
-}
-
 }
index 665c9b8..127f2f1 100644 (file)
@@ -43,25 +43,16 @@ struct SimpleRange {
     bool collapsed() const { return start == end; }
 
     SimpleRange(const BoundaryPoint&, const BoundaryPoint&);
-    SimpleRange(BoundaryPoint&&, BoundaryPoint&&);
+    WEBCORE_EXPORT SimpleRange(BoundaryPoint&&, BoundaryPoint&&);
 
+    // Convenience overloads to help with transition from using a lot of live ranges.
+    // FIXME: Move to the Range class header as either makeSimpleRange or Range::operator SimpleRange.
     WEBCORE_EXPORT SimpleRange(const Range&);
-
-    // Convenience overloads to help with transition from using a lot of live ranges. Consider removing these eventually.
-    SimpleRange(const Range*); // Crashes if passed a nullptr.
     SimpleRange(const Ref<Range>&);
 };
 
 bool operator==(const SimpleRange&, const SimpleRange&);
 
-WEBCORE_EXPORT Ref<Range> createLiveRange(const SimpleRange&);
-WEBCORE_EXPORT RefPtr<Range> createLiveRange(const Optional<SimpleRange>&);
-
-inline SimpleRange::SimpleRange(const Range* range)
-    : SimpleRange(*range)
-{
-}
-
 inline SimpleRange::SimpleRange(const Ref<Range>& range)
     : SimpleRange(range.get())
 {
index a83f0cd..fe07f56 100644 (file)
@@ -1266,8 +1266,7 @@ bool ApplyStyleCommand::isValidCaretPositionInTextNode(const Position& position)
 bool ApplyStyleCommand::mergeStartWithPreviousIfIdentical(const Position& start, const Position& end)
 {
     auto* startNode = start.containerNode();
-    int startOffset = start.computeOffsetInContainerNode();
-    if (startOffset)
+    if (start.computeOffsetInContainerNode())
         return false;
 
     if (isAtomicNode(startNode)) {
@@ -1289,10 +1288,11 @@ bool ApplyStyleCommand::mergeStartWithPreviousIfIdentical(const Position& start,
     ASSERT(startChild);
     mergeIdenticalElements(previousElement, element);
 
-    int startOffsetAdjustment = startChild->computeNodeIndex();
-    int endOffsetAdjustment = startNode == end.deprecatedNode() ? startOffsetAdjustment : 0;
-    updateStartEnd({ startNode, startOffsetAdjustment, Position::PositionIsOffsetInAnchor},
-        { end.deprecatedNode(), end.deprecatedEditingOffset() + endOffsetAdjustment, Position::PositionIsOffsetInAnchor });
+    // FIXME: Inconsistent that we use computeOffsetInContainerNode for start, but deprecatedEditingOffset for end.
+    unsigned startOffset = startChild->computeNodeIndex();
+    unsigned endOffset = end.deprecatedEditingOffset() + (startNode == end.deprecatedNode() ? startOffset : 0);
+    updateStartEnd({ startNode, startOffset, Position::PositionIsOffsetInAnchor },
+        { end.deprecatedNode(), endOffset, Position::PositionIsOffsetInAnchor });
     return true;
 }
 
@@ -1322,7 +1322,7 @@ bool ApplyStyleCommand::mergeEndWithNextIfIdentical(const Position& start, const
     mergeIdenticalElements(element, nextElement);
 
     bool shouldUpdateStart = start.containerNode() == endNode;
-    int endOffset = nextChild ? nextChild->computeNodeIndex() : nextElement.countChildNodes();
+    unsigned endOffset = nextChild ? nextChild->computeNodeIndex() : nextElement.countChildNodes();
     updateStartEnd(shouldUpdateStart ? Position(&nextElement, start.offsetInContainerNode(), Position::PositionIsOffsetInAnchor) : start,
         { &nextElement, endOffset, Position::PositionIsOffsetInAnchor });
     return true;
index ff91fe0..8d6bdf4 100644 (file)
@@ -51,7 +51,6 @@
 #include "RenderElement.h"
 #include "RenderTableCell.h"
 #include "ShadowRoot.h"
-#include "SimpleRange.h"
 #include "Text.h"
 #include "TextIterator.h"
 #include "VisibleUnits.h"
@@ -1308,7 +1307,7 @@ IntRect absoluteBoundsForLocalCaretRect(RenderBlock* rendererForCaretPainting, c
 HashSet<RefPtr<HTMLImageElement>> visibleImageElementsInRangeWithNonLoadedImages(const Range& range)
 {
     HashSet<RefPtr<HTMLImageElement>> result;
-    for (TextIterator iterator(&range); !iterator.atEnd(); iterator.advance()) {
+    for (TextIterator iterator(range); !iterator.atEnd(); iterator.advance()) {
         if (!is<HTMLImageElement>(iterator.node()))
             continue;
 
index 745b763..ded63dd 100644 (file)
@@ -37,6 +37,7 @@ class HTMLElement;
 class HTMLImageElement;
 class HTMLSpanElement;
 class HTMLTextFormControlElement;
+class Range;
 class RenderBlock;
 class VisiblePosition;
 class VisibleSelection;
index 7df4aaa..43ac0fc 100644 (file)
@@ -3313,7 +3313,11 @@ String Editor::selectedText(TextIteratorBehavior behavior) const
 {
     // We remove '\0' characters because they are not visibly rendered to the user.
     auto& selection = m_frame.selection().selection();
-    return plainText(selection.start(), selection.end(), behavior).replaceWithLiteral('\0', "");
+    auto start = selection.start();
+    auto end = selection.end();
+    if (start.isNull() || start.isOrphan() || end.isNull() || end.isOrphan())
+        return emptyString();
+    return plainText(SimpleRange { *makeBoundaryPoint(start), *makeBoundaryPoint(end) }, behavior).replaceWithLiteral('\0', "");
 }
 
 RefPtr<TextPlaceholderElement> Editor::insertTextPlaceholder(const IntSize& size)
index b22343b..4b84fc7 100644 (file)
 #include "HTMLInterchange.h"
 
 #include "Editing.h"
-#include "RenderElement.h"
 #include "RenderText.h"
 #include "Text.h"
-#include "TextIterator.h"
 #include <wtf/text/StringBuilder.h>
 #include <wtf/unicode/CharacterNames.h>
 
@@ -62,9 +60,7 @@ String convertHTMLTextToInterchangeFormat(const String& in, const Text* node)
                 unsigned add = count % 3;
                 switch (add) {
                     case 0:
-                        s.appendLiteral(convertedSpaceString);
-                        s.append(' ');
-                        s.appendLiteral(convertedSpaceString);
+                        s.append(convertedSpaceString, ' ', convertedSpaceString);
                         add = 3;
                         break;
                     case 1:
@@ -76,15 +72,12 @@ String convertHTMLTextToInterchangeFormat(const String& in, const Text* node)
                     case 2:
                         if (i == 0) {
                              // at start of string
-                            s.appendLiteral(convertedSpaceString);
-                            s.append(' ');
+                            s.append(convertedSpaceString, ' ');
                         } else if (i + 2 == in.length()) {
                              // at end of string
-                            s.appendLiteral(convertedSpaceString);
-                            s.appendLiteral(convertedSpaceString);
+                            s.append(convertedSpaceString, convertedSpaceString);
                         } else {
-                            s.appendLiteral(convertedSpaceString);
-                            s.append(' ');
+                            s.append(convertedSpaceString, ' ');
                         }
                         break;
                 }
index db29b9b..e84412b 100644 (file)
@@ -329,51 +329,28 @@ void TextIteratorCopyableText::appendToStringBuilder(StringBuilder& builder) con
 
 // --------
 
-
-TextIterator::TextIterator(Position start, Position end, TextIteratorBehavior behavior)
-    : m_behavior(behavior)
+static Node* firstNode(const BoundaryPoint& point)
 {
-    if (start.isNull() || end.isNull())
-        return;
-    ASSERT(comparePositions(start, end) <= 0);
-
-    RELEASE_ASSERT(behavior & TextIteratorTraversesFlatTree || start.treeScope() == end.treeScope());
-
-    start.document()->updateLayoutIgnorePendingStylesheets();
-
-    // FIXME: Use Position / PositionIterator instead to avoid offset computation.
-    m_startContainer = start.containerNode();
-    m_startOffset = start.computeOffsetInContainerNode();
-
-    m_endContainer = end.containerNode();
-    m_endOffset = end.computeOffsetInContainerNode();
-
-    m_node = start.firstNode().get();
-    if (!m_node)
-        return;
-
-    init();
+    if (point.container->isCharacterDataNode())
+        return point.container.ptr();
+    if (Node* child = point.container->traverseToChildAt(point.offset))
+        return child;
+    if (!point.offset)
+        return point.container.ptr();
+    return NodeTraversal::nextSkippingChildren(point.container);
 }
 
-TextIterator::TextIterator(const Range* range, TextIteratorBehavior behavior)
+TextIterator::TextIterator(const SimpleRange& range, TextIteratorBehavior behavior)
     : m_behavior(behavior)
 {
-    if (!range)
-        return;
+    range.start.document().updateLayoutIgnorePendingStylesheets();
 
-    range->ownerDocument().updateLayoutIgnorePendingStylesheets();
+    m_startContainer = range.start.container.ptr();
+    m_startOffset = range.start.offset;
+    m_endContainer = range.end.container.ptr();
+    m_endOffset = range.end.offset;
 
-    m_startContainer = &range->startContainer();
-
-    // Callers should be handing us well-formed ranges. If we discover that this isn't
-    // the case, we could consider changing this assertion to an early return.
-    ASSERT(range->boundaryPointsValid());
-
-    m_startOffset = range->startOffset();
-    m_endContainer = &range->endContainer();
-    m_endOffset = range->endOffset();
-
-    m_node = range->firstNode();
+    m_node = firstNode(range.start);
     if (!m_node)
         return;
 
@@ -1140,23 +1117,23 @@ Node* TextIterator::node() const
 
 // --------
 
-SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range& range)
+SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const SimpleRange& range)
 {
-    range.ownerDocument().updateLayoutIgnorePendingStylesheets();
+    range.start.document().updateLayoutIgnorePendingStylesheets();
 
-    Node* startNode = &range.startContainer();
-    Node* endNode = &range.endContainer();
-    int startOffset = range.startOffset();
-    int endOffset = range.endOffset();
+    Node* startNode = range.start.container.ptr();
+    Node* endNode = range.end.container.ptr();
+    unsigned startOffset = range.start.offset;
+    unsigned endOffset = range.end.offset;
 
     if (!startNode->isCharacterDataNode()) {
-        if (startOffset >= 0 && startOffset < static_cast<int>(startNode->countChildNodes())) {
+        if (startOffset < startNode->countChildNodes()) {
             startNode = startNode->traverseToChildAt(startOffset);
             startOffset = 0;
         }
     }
     if (!endNode->isCharacterDataNode()) {
-        if (endOffset > 0 && endOffset <= static_cast<int>(endNode->countChildNodes())) {
+        if (endOffset > 0 && endOffset <= endNode->countChildNodes()) {
             endNode = endNode->traverseToChildAt(endOffset - 1);
             endOffset = lastOffsetInNode(endNode);
         }
@@ -1391,15 +1368,8 @@ SimpleRange SimplifiedBackwardsTextIterator::range() const
 
 // --------
 
-CharacterIterator::CharacterIterator(const Range& range, TextIteratorBehavior behavior)
-    : m_underlyingIterator(&range, behavior)
-{
-    while (!atEnd() && !m_underlyingIterator.text().length())
-        m_underlyingIterator.advance();
-}
-
-CharacterIterator::CharacterIterator(Position start, Position end, TextIteratorBehavior behavior)
-    : m_underlyingIterator(start, end, behavior)
+CharacterIterator::CharacterIterator(const SimpleRange& range, TextIteratorBehavior behavior)
+    : m_underlyingIterator(range, behavior)
 {
     while (!atEnd() && !m_underlyingIterator.text().length())
         m_underlyingIterator.advance();
@@ -1483,7 +1453,7 @@ static Ref<Range> characterSubrange(Document& document, CharacterIterator& it, i
     return createLiveRange(SimpleRange { start, end });
 }
 
-BackwardsCharacterIterator::BackwardsCharacterIterator(const Range& range)
+BackwardsCharacterIterator::BackwardsCharacterIterator(const SimpleRange& range)
     : m_underlyingIterator(range)
 {
     while (!atEnd() && !m_underlyingIterator.text().length())
@@ -1546,8 +1516,8 @@ void BackwardsCharacterIterator::advance(int count)
 
 // --------
 
-WordAwareIterator::WordAwareIterator(const Range& range)
-    : m_underlyingIterator(&range)
+WordAwareIterator::WordAwareIterator(const SimpleRange& range)
+    : m_underlyingIterator(range)
 {
     advance(); // get in position over the first chunk of text
 }
@@ -2375,8 +2345,10 @@ size_t SearchBuffer::length() const
 
 int TextIterator::rangeLength(const Range* range, bool forSelectionPreservation)
 {
+    if (!range)
+        return 0;
     unsigned length = 0;
-    for (TextIterator it(range, forSelectionPreservation ? TextIteratorEmitsCharactersBetweenAllVisiblePositions : TextIteratorDefaultBehavior); !it.atEnd(); it.advance())
+    for (TextIterator it(*range, forSelectionPreservation ? TextIteratorEmitsCharactersBetweenAllVisiblePositions : TextIteratorDefaultBehavior); !it.atEnd(); it.advance())
         length += it.text().length();
     return length;
 }
@@ -2405,7 +2377,7 @@ RefPtr<Range> TextIterator::rangeFromLocationAndLength(ContainerNode* scope, int
 
     Ref<Range> textRunRange = rangeOfContents(*scope);
 
-    TextIterator it(textRunRange.ptr(), forSelectionPreservation ? TextIteratorEmitsCharactersBetweenAllVisiblePositions : TextIteratorDefaultBehavior);
+    TextIterator it(textRunRange, forSelectionPreservation ? TextIteratorEmitsCharactersBetweenAllVisiblePositions : TextIteratorDefaultBehavior);
     
     // FIXME: the atEnd() check shouldn't be necessary, workaround for <http://bugs.webkit.org/show_bug.cgi?id=6289>.
     if (!rangeLocation && !rangeLength && it.atEnd()) {
@@ -2506,21 +2478,19 @@ bool TextIterator::getLocationAndLengthFromRange(Node* scope, const Range* range
 
 bool hasAnyPlainText(const SimpleRange& range, TextIteratorBehavior behavior)
 {
-    for (TextIterator iterator { createLiveRange(range).ptr(), behavior }; !iterator.atEnd(); iterator.advance()) {
+    for (TextIterator iterator { range, behavior }; !iterator.atEnd(); iterator.advance()) {
         if (!iterator.text().isEmpty())
             return true;
     }
     return false;
 }
 
-String plainText(Position start, Position end, TextIteratorBehavior defaultBehavior, bool isDisplayString)
+String plainText(const SimpleRange& range, TextIteratorBehavior defaultBehavior, bool isDisplayString)
 {
     // The initial buffer size can be critical for performance: https://bugs.webkit.org/show_bug.cgi?id=81192
     static const unsigned initialCapacity = 1 << 15;
 
-    if (!start.document())
-        return { };
-    auto document = makeRef(*start.document());
+    auto document = makeRef(range.start.document());
 
     unsigned bufferLength = 0;
     StringBuilder builder;
@@ -2529,7 +2499,7 @@ String plainText(Position start, Position end, TextIteratorBehavior defaultBehav
     if (!isDisplayString)
         behavior = static_cast<TextIteratorBehavior>(behavior | TextIteratorEmitsTextsWithoutTranscoding);
 
-    for (TextIterator it(start, end, behavior); !it.atEnd(); it.advance()) {
+    for (TextIterator it(range, behavior); !it.atEnd(); it.advance()) {
         it.appendTextToStringBuilder(builder);
         bufferLength += it.text().length();
     }
@@ -2545,16 +2515,11 @@ String plainText(Position start, Position end, TextIteratorBehavior defaultBehav
     return result;
 }
 
-String plainTextReplacingNoBreakSpace(Position start, Position end, TextIteratorBehavior defaultBehavior, bool isDisplayString)
-{
-    return plainText(start, end, defaultBehavior, isDisplayString).replace(noBreakSpace, ' ');
-}
-
 String plainText(const Range* range, TextIteratorBehavior defaultBehavior, bool isDisplayString)
 {
     if (!range)
         return emptyString();
-    return plainText(range->startPosition(), range->endPosition(), defaultBehavior, isDisplayString);
+    return plainText(*range, defaultBehavior, isDisplayString);
 }
 
 String plainTextUsingBackwardsTextIteratorForTesting(const SimpleRange& range)
@@ -2565,7 +2530,7 @@ String plainTextUsingBackwardsTextIteratorForTesting(const SimpleRange& range)
     return result;
 }
 
-String plainTextReplacingNoBreakSpace(const Range* range, TextIteratorBehavior defaultBehavior, bool isDisplayString)
+String plainTextReplacingNoBreakSpace(const SimpleRange& range, TextIteratorBehavior defaultBehavior, bool isDisplayString)
 {
     return plainText(range, defaultBehavior, isDisplayString).replace(noBreakSpace, ' ');
 }
index a5d0ea1..157f1da 100644 (file)
 #include "SimpleRange.h"
 #include "TextIteratorBehavior.h"
 #include <wtf/Vector.h>
-#include <wtf/text/StringView.h>
 
 namespace WebCore {
 
 class Range;
-class RenderText;
 class RenderTextFragment;
 
-WEBCORE_EXPORT String plainText(Position start, Position end, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
-WEBCORE_EXPORT String plainTextReplacingNoBreakSpace(Position start, Position end, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
-
 WEBCORE_EXPORT String plainText(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
-WEBCORE_EXPORT String plainTextReplacingNoBreakSpace(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
+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&);
 
 SimpleRange findPlainText(const SimpleRange&, const String&, FindOptions);
@@ -91,8 +87,7 @@ private:
 class TextIterator {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    WEBCORE_EXPORT TextIterator(Position start, Position end, TextIteratorBehavior = TextIteratorDefaultBehavior);
-    WEBCORE_EXPORT explicit TextIterator(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior);
+    WEBCORE_EXPORT explicit TextIterator(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
     WEBCORE_EXPORT ~TextIterator();
 
     bool atEnd() const { return !m_positionNode; }
@@ -177,7 +172,7 @@ private:
 // chunks so as to optimize for performance of the iteration.
 class SimplifiedBackwardsTextIterator {
 public:
-    explicit SimplifiedBackwardsTextIterator(const Range&);
+    explicit SimplifiedBackwardsTextIterator(const SimpleRange&);
 
     bool atEnd() const { return !m_positionNode; }
     void advance();
@@ -232,8 +227,7 @@ private:
 // character at a time, or faster, as needed. Useful for searching.
 class CharacterIterator {
 public:
-    WEBCORE_EXPORT explicit CharacterIterator(const Range&, TextIteratorBehavior = TextIteratorDefaultBehavior);
-    WEBCORE_EXPORT explicit CharacterIterator(Position start, Position end, TextIteratorBehavior = TextIteratorDefaultBehavior);
+    WEBCORE_EXPORT explicit CharacterIterator(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
     
     bool atEnd() const { return m_underlyingIterator.atEnd(); }
     WEBCORE_EXPORT void advance(int numCharacters);
@@ -254,7 +248,7 @@ private:
     
 class BackwardsCharacterIterator {
 public:
-    explicit BackwardsCharacterIterator(const Range&);
+    explicit BackwardsCharacterIterator(const SimpleRange&);
 
     bool atEnd() const { return m_underlyingIterator.atEnd(); }
     void advance(int numCharacters);
@@ -273,7 +267,7 @@ private:
 // they never split up a word. This is useful for spell checking and perhaps one day for searching as well.
 class WordAwareIterator {
 public:
-    explicit WordAwareIterator(const Range&);
+    explicit WordAwareIterator(const SimpleRange&);
 
     bool atEnd() const { return !m_didLookAhead && m_underlyingIterator.atEnd(); }
     void advance();
index bb358a9..cb94713 100644 (file)
@@ -141,7 +141,7 @@ void TextManipulationController::startObservingParagraphs(ManipulationItemCallba
 class ParagraphContentIterator {
 public:
     ParagraphContentIterator(const Position& start, const Position& end)
-        : m_iterator(start, end)
+        : m_iterator({ *makeBoundaryPoint(start), *makeBoundaryPoint(end) })
         , m_iteratorNode(m_iterator.atEnd() ? nullptr : createLiveRange(m_iterator.range())->firstNode())
         , m_currentNodeForFindingInvisibleContent(start.firstNode())
         , m_pastEndNode(end.firstNode())
@@ -462,7 +462,7 @@ auto TextManipulationController::replace(const ManipulationItemData& item, const
     size_t currentTokenIndex = 0;
     HashMap<TokenIdentifier, TokenExchangeData> tokenExchangeMap;
 
-    if (item.start.isNull() && item.end.isNull()) {
+    if (item.start.isNull() || item.end.isNull()) {
         RELEASE_ASSERT(item.tokens.size() == 1);
         auto element = makeRefPtr(item.element.get());
         if (!element)
index b306d47..33fc850 100644 (file)
@@ -33,7 +33,6 @@
 #include "Range.h"
 #include "Settings.h"
 #include "ShadowRoot.h"
-#include "SimpleRange.h"
 #include "TextIterator.h"
 #include "VisibleUnits.h"
 #include <stdio.h>
index 7522b10..9109ab9 100644 (file)
@@ -489,7 +489,7 @@ static void appendRepeatedCharacter(Vector<UChar, 1024>& buffer, UChar character
 unsigned suffixLengthForRange(const Range& forwardsScanRange, Vector<UChar, 1024>& string)
 {
     unsigned suffixLength = 0;
-    TextIterator forwardsIterator(&forwardsScanRange);
+    TextIterator forwardsIterator(forwardsScanRange);
     while (!forwardsIterator.atEnd()) {
         StringView text = forwardsIterator.text();
         unsigned i = endOfFirstWordBoundaryContext(text);
@@ -609,7 +609,7 @@ static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearch
         result = forwardsScanRange->setStart(start);
         if (result.hasException())
             return { };
-        for (TextIterator forwardsIterator(forwardsScanRange.ptr()); !forwardsIterator.atEnd(); forwardsIterator.advance())
+        for (TextIterator forwardsIterator(forwardsScanRange); !forwardsIterator.atEnd(); forwardsIterator.advance())
             append(string, forwardsIterator.text());
         suffixLength = string.size();
     } else if (requiresContextForWordBoundary(c.characterBefore())) {
@@ -674,7 +674,7 @@ static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunc
     searchRange->selectNodeContents(*boundary);
     if (start.deprecatedNode())
         searchRange->setStart(*start.deprecatedNode(), start.deprecatedEditingOffset());
-    TextIterator it(searchRange.ptr(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
+    TextIterator it(searchRange, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
     unsigned next = forwardSearchForBoundaryWithTextIterator(it, string, prefixLength, searchFunction);
     
     if (it.atEnd() && next == string.size())
index c61e356..103e553 100644 (file)
@@ -43,7 +43,6 @@
 #import "NodeTraversal.h"
 #import "Range.h"
 #import "RenderObject.h"
-#import "SimpleRange.h"
 #import "StyleProperties.h"
 #import "Text.h"
 #import "TextIterator.h"
@@ -162,6 +161,7 @@ RetainPtr<DDActionContext> DataDetection::detectItemAroundHitTestResult(const Hi
 
     return detectItemAtPositionWithRange(position, contextRange, detectedDataBoundingBox, detectedDataRange);
 }
+
 #endif // PLATFORM(MAC)
 
 #if PLATFORM(IOS_FAMILY)
@@ -345,7 +345,7 @@ static String dataDetectorStringForPath(NSIndexPath *path)
     }
 }
 
-static void buildQuery(DDScanQueryRef scanQuery, Range* contextRange)
+static void buildQuery(DDScanQueryRef scanQuery, const SimpleRange& contextRange)
 {
     // Once we're over this number of fragments, stop at the first hard break.
     const CFIndex maxFragmentWithHardBreak = 1000;
@@ -444,9 +444,12 @@ void DataDetection::removeDataDetectedLinksInDocument(Document& document)
 
 NSArray *DataDetection::detectContentInRange(RefPtr<Range>& contextRange, DataDetectorTypes types, NSDictionary *context)
 {
+    if (!contextRange)
+        return nil;
+
     RetainPtr<DDScannerRef> scanner = adoptCF(softLink_DataDetectorsCore_DDScannerCreate(DDScannerTypeStandard, 0, nullptr));
     RetainPtr<DDScanQueryRef> scanQuery = adoptCF(softLink_DataDetectorsCore_DDScanQueryCreate(NULL));
-    buildQuery(scanQuery.get(), contextRange.get());
+    buildQuery(scanQuery.get(), *contextRange);
     
     if (types & DataDetectorTypeLookupSuggestion)
         softLink_DataDetectorsCore_DDScannerEnableOptionalSource(scanner.get(), DDScannerSourceSpotlight, true);
@@ -487,7 +490,7 @@ NSArray *DataDetection::detectContentInRange(RefPtr<Range>& contextRange, DataDe
     }
 
     Vector<Vector<RefPtr<Range>>> allResultRanges;
-    TextIterator iterator(contextRange.get());
+    TextIterator iterator(*contextRange);
     CFIndex iteratorCount = 0;
 
     // Iterate through the array of the expanded results to create a vector of Range objects that indicate
index d35539a..8797220 100644 (file)
@@ -337,7 +337,9 @@ std::tuple<RefPtr<Range>, NSDictionary *> DictionaryLookup::rangeAtHitTestResult
         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());
@@ -357,7 +359,7 @@ std::tuple<RefPtr<Range>, NSDictionary *> DictionaryLookup::rangeAtHitTestResult
     
     NSRange selectedRange = [getRVSelectionClass() revealRangeAtIndex:hitIndex selectedRanges:@[[NSValue valueWithRange:selectionRange]] shouldUpdateSelection:nil];
     
-    String itemString = plainText(fullCharacterRange.get());
+    String itemString = plainText(*fullCharacterRange);
     RetainPtr<RVItem> item = adoptNS([allocRVItemInstance() initWithText:itemString selectedRange:selectedRange]);
     NSRange highlightRange = item.get().highlightRange;
 
index 4f7faa0..a543ac2 100644 (file)
@@ -61,7 +61,6 @@
 #import "Range.h"
 #import "RenderImage.h"
 #import "RenderText.h"
-#import "SimpleRange.h"
 #import "StyleProperties.h"
 #import "StyledElement.h"
 #import "TextIterator.h"
@@ -2396,7 +2395,7 @@ NSAttributedString *editingAttributedStringFromRange(Range& range, IncludeImages
     NSUInteger stringLength = 0;
     RetainPtr<NSMutableDictionary> attrs = adoptNS([[NSMutableDictionary alloc] init]);
 
-    for (TextIterator it(&range); !it.atEnd(); it.advance()) {
+    for (TextIterator it(range); !it.atEnd(); it.advance()) {
         SimpleRange currentTextRange = it.range();
         Node& startContainer = currentTextRange.start.container;
         Node& endContainer = currentTextRange.end.container;
index 2d21104..42efead 100644 (file)
@@ -43,7 +43,6 @@
 #include "RenderElement.h"
 #include "RenderObject.h"
 #include "RenderText.h"
-#include "SimpleRange.h"
 #include "TextIterator.h"
 #include "TextPaintStyle.h"
 
@@ -213,7 +212,7 @@ static bool styleContainsComplexBackground(const RenderStyle& style)
 static HashSet<Color> estimatedTextColorsForRange(const Range& range)
 {
     HashSet<Color> colors;
-    for (TextIterator iterator(&range); !iterator.atEnd(); iterator.advance()) {
+    for (TextIterator iterator(range); !iterator.atEnd(); iterator.advance()) {
         auto* node = iterator.node();
         if (!is<Text>(node) || !is<RenderText>(node->renderer()))
             continue;
@@ -299,7 +298,7 @@ static bool containsOnlyWhiteSpaceText(const Range& range)
         if (!is<RenderText>(node->renderer()))
             return false;
     }
-    return plainTextReplacingNoBreakSpace(&range).stripWhiteSpace().isEmpty();
+    return plainTextReplacingNoBreakSpace(range).stripWhiteSpace().isEmpty();
 }
 
 static bool initializeIndicator(TextIndicatorData& data, Frame& frame, const Range& range, FloatSize margin, bool indicatesCurrentSelection)
index 3009138..6ee4fb4 100644 (file)
@@ -760,7 +760,7 @@ NSArray *Frame::interpretationsForCurrentRoot() const
             }
 
             auto rangeForMarker = Range::create(*document(), createLegacyEditingPosition(node, marker->startOffset()), createLegacyEditingPosition(node, marker->endOffset()));
-            String visibleTextForMarker = plainText(rangeForMarker.ptr());
+            String visibleTextForMarker = plainText(rangeForMarker);
             size_t interpretationsCountForCurrentMarker = marker->alternatives().size() + 1;
             for (size_t i = 0; i < interpretationsCount; ++i) {
                 // Determine text for the ith interpretation. It will either be the visible text, or one of its
@@ -781,7 +781,7 @@ NSArray *Frame::interpretationsForCurrentRoot() const
 
     // Finally, add any text after the last marker.
     auto afterLastMarkerRange = Range::create(*document(), precedingTextStartPosition, createLegacyEditingPosition(root, rootChildCount));
-    String textAfterLastMarker = plainText(afterLastMarkerRange.ptr());
+    String textAfterLastMarker = plainText(afterLastMarkerRange);
     if (!textAfterLastMarker.isEmpty()) {
         for (auto& interpretation : interpretations)
             append(interpretation, textAfterLastMarker);
index c15c74d..8d28d71 100644 (file)
@@ -202,8 +202,12 @@ String HitTestResult::selectedText() const
     if (!frame)
         return emptyString();
 
+    auto range = frame->selection().toNormalizedRange();
+    if (!range)
+        return emptyString();
+
     // Look for a character that's not just a separator.
-    for (TextIterator it(frame->selection().toNormalizedRange().get()); !it.atEnd(); it.advance()) {
+    for (TextIterator it(*range); !it.atEnd(); it.advance()) {
         int length = it.text().length();
         for (int i = 0; i < length; ++i) {
             if (!(U_GET_GC_MASK(it.text()[i]) & U_GC_Z_MASK))
index 94ab96d..b968ef7 100644 (file)
 #include "LineLayoutTraversalComplexPath.h"
 #include "LineLayoutTraversalDisplayRunPath.h"
 #include "LineLayoutTraversalSimplePath.h"
-#include "RenderText.h"
-#include <wtf/HashMap.h>
-#include <wtf/IteratorRange.h>
 #include <wtf/Variant.h>
-#include <wtf/text/StringView.h>
 
 namespace WebCore {
 
 class RenderLineBreak;
+class RenderText;
 
 namespace LineLayoutTraversal {
 
index 923ee95..2b98800 100644 (file)
 #include "ServiceWorkerRegistrationData.h"
 #include "Settings.h"
 #include "ShadowRoot.h"
-#include "SimpleRange.h"
 #include "SourceBuffer.h"
 #include "SpellChecker.h"
 #include "StaticNodeList.h"
index 08438bc..fd7bfcb 100644 (file)
@@ -1,3 +1,49 @@
+2020-03-15  Darin Adler  <darin@apple.com>
+
+        Move most of TextIterator off of live ranges
+        https://bugs.webkit.org/show_bug.cgi?id=209129
+
+        Reviewed by Antti Koivisto.
+
+        * WebProcess/InjectedBundle/API/mac/WKDOMTextIterator.mm:
+        (-[WKDOMTextIterator initWithRange:]): Leave _textIterator as a nullptr
+        if the passed-in range is nil since we no longer offer a way to create
+        an empty TextIterator; other clients don't seem to need one.
+        (-[WKDOMTextIterator advance]): Add a null check.
+        (-[WKDOMTextIterator atEnd]): Ditto.
+        (-[WKDOMTextIterator currentRange]): Ditto.
+        (-[WKDOMTextIterator currentTextPointer]): Ditto.
+        (-[WKDOMTextIterator currentTextLength]): Ditto.
+
+        * WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.mm: Removed include.
+
+        * WebProcess/WebPage/ViewGestureGeometryCollector.cpp:
+        (WebKit::ViewGestureGeometryCollector::computeTextLegibilityScales): Pass
+        a reference to a range known not to be null.
+
+        * WebProcess/WebPage/WebPage.cpp: Removed an include.
+
+        * WebProcess/WebPage/ios/WebPageIOS.mm: Removed a "using naemsapce WebCore".
+        Added two local functions
+        (WebKit::plainTextForContext): Added. Helper for just this file where calling
+        plainTextReplacingNoBreakSpace on a possibly null Range is common.
+        (WebKit::plainTextForDisplay): Ditto. This one passes true for isDisplayString.
+        Not entirely clear how carefully we chose which of the two to call, or if there
+        is sufficient test coverage.
+        (WebKit::WebPage::platformEditorState const): Use plainTextForContext
+        and plainTextForDisplay.
+        (WebKit::WebPage::getSelectionContext): Ditto.
+        (WebKit::WebPage::getRectsAtSelectionOffsetWithText): Use plainTextForDisplay.
+        (WebKit::WebPage::requestDictationContext): Use plainTextForContext.
+        (WebKit::WebPage::replaceSelectedText): Ditto.
+        (WebKit::WebPage::replaceDictatedText): Ditto.
+        (WebKit::WebPage::requestAutocorrectionData): Ditto.
+        (WebKit::WebPage::applyAutocorrectionInternal): Ditto.
+        (WebKit::WebPage::autocorrectionContext): Ditto.
+        (WebKit::dataDetectorLinkPositionInformation): Use plainTextForDisplay.
+        (WebKit::WebPage::requestDocumentEditingContext): Use RetainPtr instead of
+        autorelease. Use makeBoundaryPoint to convert Position objects to SimpleRange.
+
 2020-03-16  Chris Dumez  <cdumez@apple.com>
 
         Crash under WebCookieCache::clearForHost()
         * WebProcess/cocoa/UserMediaCaptureManager.cpp:
         (WebKit::UserMediaCaptureManager::Source::setShouldApplyRotation):
 
+        * WebProcess/WebPage/mac/WebPageMac.mm: Removed an include.
+
 2020-03-13  Sergio Villar Senin  <svillar@igalia.com>
 
         [WebXR] IDLs, stubs and build configuration for WPE
index 79b2e4f..b9693a8 100644 (file)
@@ -28,7 +28,6 @@
 
 #import "WKDOMInternals.h"
 #import "WKDOMRange.h"
-#import <WebCore/SimpleRange.h>
 #import <WebCore/TextIterator.h>
 
 @interface WKDOMTextIterator () {
     if (!self)
         return nil;
 
-    _textIterator = makeUnique<WebCore::TextIterator>(WebKit::toWebCoreRange(range));
+    if (!range)
+        return self;
+
+    _textIterator = makeUnique<WebCore::TextIterator>(*WebKit::toWebCoreRange(range));
     return self;
 }
 
 - (void)advance
 {
-    _textIterator->advance();
+    if (_textIterator)
+        _textIterator->advance();
     _upconvertedText.shrink(0);
 }
 
 - (BOOL)atEnd
 {
-    return _textIterator->atEnd();
+    return _textIterator && _textIterator->atEnd();
 }
 
 - (WKDOMRange *)currentRange
 {
-    return WebKit::toWKDOMRange(createLiveRange(_textIterator->range()).ptr());
+    return _textIterator ? WebKit::toWKDOMRange(createLiveRange(_textIterator->range()).ptr()) : nil;
 }
 
 // FIXME: Consider deprecating this method and creating one that does not require copying 8-bit characters.
 - (const unichar*)currentTextPointer
 {
+    if (!_textIterator)
+        return nullptr;
     StringView text = _textIterator->text();
     unsigned length = text.length();
     if (!length)
@@ -83,7 +88,7 @@
 
 - (NSUInteger)currentTextLength
 {
-    return _textIterator->text().length();
+    return _textIterator ? _textIterator->text().length() : 0;
 }
 
 @end
index 7f3f4d9..dec3aca 100644 (file)
@@ -40,7 +40,6 @@
 #import <WebCore/FocusController.h>
 #import <WebCore/RenderObject.h>
 #import <WebCore/RenderedDocumentMarker.h>
-#import <WebCore/SimpleRange.h>
 #import <WebCore/TextIterator.h>
 #import <WebCore/VisibleUnits.h>
 
index 5fb5329..0d276e4 100644 (file)
@@ -161,7 +161,7 @@ Optional<std::pair<double, double>> ViewGestureGeometryCollector::computeTextLeg
     unsigned numberOfIterations = 0;
     unsigned totalSampledTextLength = 0;
 
-    for (TextIterator documentTextIterator { documentRange.ptr(), TextIteratorEntersTextControls }; !documentTextIterator.atEnd(); documentTextIterator.advance()) {
+    for (TextIterator documentTextIterator { documentRange.get(), TextIteratorEntersTextControls }; !documentTextIterator.atEnd(); documentTextIterator.advance()) {
         if (++numberOfIterations >= maximumNumberOfTextRunsToConsider)
             break;
 
index f16ee0c..d8d58e7 100644 (file)
 #include <WebCore/Settings.h>
 #include <WebCore/ShadowRoot.h>
 #include <WebCore/SharedBuffer.h>
-#include <WebCore/SimpleRange.h>
 #include <WebCore/StyleProperties.h>
 #include <WebCore/SubframeLoader.h>
 #include <WebCore/SubstituteData.h>
index fed6c04..e745763 100644 (file)
 #import <WebCore/Settings.h>
 #import <WebCore/ShadowRoot.h>
 #import <WebCore/SharedBuffer.h>
-#import <WebCore/SimpleRange.h>
 #import <WebCore/StyleProperties.h>
 #import <WebCore/TextIndicator.h>
 #import <WebCore/TextIterator.h>
 #define RELEASE_LOG_ERROR_IF_ALLOWED(channel, fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), channel, "%p - WebPage::" fmt, this, ##__VA_ARGS__)
 
 namespace WebKit {
-using namespace WebCore;
+
+// FIXME: Unclear if callers in this file are correctly choosing which of these two functions to use.
+
+static String plainTextForContext(const Range* range)
+{
+    if (!range)
+        return emptyString();
+    return WebCore::plainTextReplacingNoBreakSpace(*range);
+}
+
+static String plainTextForDisplay(const Range* range)
+{
+    if (!range)
+        return emptyString();
+    return WebCore::plainTextReplacingNoBreakSpace(*range, TextIteratorDefaultBehavior, true);
+}
 
 void WebPage::platformInitialize()
 {
@@ -228,7 +242,7 @@ void WebPage::platformEditorState(Frame& frame, EditorState& result, IncludePost
                 result.lastMarkedRect = view->contentsToRootView(compositionRects.last().rect());
             else
                 result.lastMarkedRect = result.firstMarkedRect;
-            result.markedText = plainTextReplacingNoBreakSpace(compositionRange.get());
+            result.markedText = plainTextForContext(compositionRange.get());
         }
     }
 
@@ -258,7 +272,7 @@ void WebPage::platformEditorState(Frame& frame, EditorState& result, IncludePost
         postLayoutData.caretRectAtEnd = postLayoutData.caretRectAtStart;
         // FIXME: The following check should take into account writing direction.
         postLayoutData.isReplaceAllowed = result.isContentEditable && atBoundaryOfGranularity(selection.start(), WordGranularity, DirectionForward);
-        postLayoutData.wordAtSelection = plainTextReplacingNoBreakSpace(wordRangeFromPosition(selection.start()).get());
+        postLayoutData.wordAtSelection = plainTextForContext(wordRangeFromPosition(selection.start()).get());
         if (selection.isContentEditable())
             charactersAroundPosition(selection.start(), postLayoutData.characterAfterSelection, postLayoutData.characterBeforeSelection, postLayoutData.twoCharacterBeforeSelection);
     } else if (selection.isRange()) {
@@ -269,7 +283,7 @@ void WebPage::platformEditorState(Frame& frame, EditorState& result, IncludePost
         if (selectedRange) {
             selectedRange->collectSelectionRects(postLayoutData.selectionRects);
             convertSelectionRectsToRootView(view, postLayoutData.selectionRects);
-            selectedText = plainTextReplacingNoBreakSpace(selectedRange.get(), TextIteratorDefaultBehavior, true);
+            selectedText = plainTextForDisplay(selectedRange.get());
             postLayoutData.selectedTextLength = selectedText.length();
             const int maxSelectedTextLength = 200;
             postLayoutData.wordAtSelection = selectedText.left(maxSelectedTextLength);
@@ -502,9 +516,9 @@ void WebPage::getSelectionContext(CallbackID callbackID)
     }
     const int selectionExtendedContextLength = 350;
     
-    String selectedText = plainTextReplacingNoBreakSpace(frame.selection().selection().toNormalizedRange().get());
-    String textBefore = plainTextReplacingNoBreakSpace(rangeExpandedByCharactersInDirectionAtWordBoundary(frame.selection().selection().start(), selectionExtendedContextLength, DirectionBackward).get(), TextIteratorDefaultBehavior, true);
-    String textAfter = plainTextReplacingNoBreakSpace(rangeExpandedByCharactersInDirectionAtWordBoundary(frame.selection().selection().end(), selectionExtendedContextLength, DirectionForward).get(), TextIteratorDefaultBehavior, true);
+    String selectedText = plainTextForContext(frame.selection().selection().toNormalizedRange().get());
+    String textBefore = plainTextForDisplay(rangeExpandedByCharactersInDirectionAtWordBoundary(frame.selection().selection().start(), selectionExtendedContextLength, DirectionBackward).get());
+    String textAfter = plainTextForDisplay(rangeExpandedByCharactersInDirectionAtWordBoundary(frame.selection().selection().end(), selectionExtendedContextLength, DirectionForward).get());
 
     send(Messages::WebPageProxy::SelectionContextCallback(selectedText, textBefore, textAfter, callbackID));
 }
@@ -2006,7 +2020,7 @@ void WebPage::getRectsAtSelectionOffsetWithText(int32_t offset, const String& te
         return;
     }
 
-    if (plainTextReplacingNoBreakSpace(range.ptr(), TextIteratorDefaultBehavior, true) != text) {
+    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 (!wordRange->collapsed())
@@ -2226,7 +2240,7 @@ void WebPage::requestDictationContext(CallbackID callbackID)
 
     String selectedText;
     if (frame.selection().isRange())
-        selectedText = plainTextReplacingNoBreakSpace(frame.selection().selection().toNormalizedRange().get());
+        selectedText = plainTextForContext(frame.selection().selection().toNormalizedRange().get());
 
     String contextBefore;
     if (startPosition != startOfEditableContent(startPosition)) {
@@ -2239,7 +2253,7 @@ void WebPage::requestDictationContext(CallbackID callbackID)
             lastPosition = currentPosition;
         }
         if (lastPosition.isNotNull() && lastPosition != startPosition)
-            contextBefore = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), lastPosition, startPosition).ptr());
+            contextBefore = plainTextForContext(Range::create(*frame.document(), lastPosition, startPosition).ptr());
     }
 
     String contextAfter;
@@ -2253,7 +2267,7 @@ void WebPage::requestDictationContext(CallbackID callbackID)
             lastPosition = currentPosition;
         }
         if (lastPosition.isNotNull() && lastPosition != endPosition)
-            contextAfter = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), endPosition, lastPosition).ptr());
+            contextAfter = plainTextForContext(Range::create(*frame.document(), endPosition, lastPosition).ptr());
     }
 
     send(Messages::WebPageProxy::SelectionContextCallback(selectedText, contextBefore, contextAfter, callbackID));
@@ -2263,7 +2277,7 @@ void WebPage::replaceSelectedText(const String& oldText, const String& newText)
 {
     Frame& frame = m_page->focusController().focusedOrMainFrame();
     RefPtr<Range> wordRange = frame.selection().isCaret() ? wordRangeFromPosition(frame.selection().selection().start()) : frame.selection().toNormalizedRange();
-    if (plainTextReplacingNoBreakSpace(wordRange.get()) != oldText)
+    if (plainTextForContext(wordRange.get()) != oldText)
         return;
     
     frame.editor().setIgnoreSelectionChanges(true);
@@ -2289,7 +2303,7 @@ void WebPage::replaceDictatedText(const String& oldText, const String& newText)
         position = startOfDocument(static_cast<Node*>(frame.document()->documentElement()));
     auto range = Range::create(*frame.document(), position, frame.selection().selection().start());
 
-    if (plainTextReplacingNoBreakSpace(range.ptr()) != oldText)
+    if (plainTextForContext(range.ptr()) != oldText)
         return;
 
     // We don't want to notify the client that the selection has changed until we are done inserting the new text.
@@ -2314,7 +2328,7 @@ void WebPage::requestAutocorrectionData(const String& textForAutocorrection, Com
         return;
     }
 
-    auto textForRange = plainTextReplacingNoBreakSpace(range.get());
+    auto textForRange = plainTextForContext(range.get());
     const unsigned maxSearchAttempts = 5;
     for (size_t i = 0;  i < maxSearchAttempts && textForRange != textForAutocorrection; ++i)
     {
@@ -2322,7 +2336,7 @@ void WebPage::requestAutocorrectionData(const String& textForAutocorrection, Com
         if (position.isNull() || position == range->startPosition())
             break;
         range = Range::create(*frame.document(), wordRangeFromPosition(position)->startPosition(), range->endPosition());
-        textForRange = plainTextReplacingNoBreakSpace(range.get());
+        textForRange = plainTextForContext(range.get());
     }
 
     Vector<SelectionRect> selectionRects;
@@ -2385,7 +2399,7 @@ bool WebPage::applyAutocorrectionInternal(const String& correction, const String
     if (frame.selection().isCaret()) {
         VisiblePosition position = frame.selection().selection().start();
         range = wordRangeFromPosition(position);
-        textForRange = plainTextReplacingNoBreakSpace(range.get());
+        textForRange = plainTextForContext(range.get());
         
         // If 'originalText' is not the same as 'textForRange' we need to move 'range'
         // forward such that it matches the original selection as much as possible.
@@ -2396,7 +2410,7 @@ bool WebPage::applyAutocorrectionInternal(const String& correction, const String
             if (position.isNull())
                 position = startOfDocument(static_cast<Node*>(frame.document()->documentElement()));
             range = Range::create(*frame.document(), position, frame.selection().selection().start());
-            textForRange = plainTextReplacingNoBreakSpace(range.get());
+            textForRange = plainTextForContext(range.get());
             unsigned loopCount = 0;
             const unsigned maxPositionsAttempts = 10;
             while (textForRange.length() && textForRange.length() > originalText.length() && loopCount < maxPositionsAttempts) {
@@ -2405,7 +2419,7 @@ bool WebPage::applyAutocorrectionInternal(const String& correction, const String
                     range = nullptr;
                 else
                     range = Range::create(*frame.document(), position, frame.selection().selection().start());
-                textForRange = plainTextReplacingNoBreakSpace(range.get());
+                textForRange = plainTextForContext(range.get());
                 loopCount++;
             }
         } else if (textForRange.isEmpty() && range && !range->collapsed()) {
@@ -2421,7 +2435,7 @@ bool WebPage::applyAutocorrectionInternal(const String& correction, const String
         if (!range)
             return false;
 
-        textForRange = plainTextReplacingNoBreakSpace(range.get());
+        textForRange = plainTextForContext(range.get());
     }
 
     if (foldQuoteMarks(textForRange) != originalTextWithFoldedQuoteMarks)
@@ -2457,17 +2471,17 @@ WebAutocorrectionContext WebPage::autocorrectionContext()
     const unsigned maxContextLength = 30;
 
     if (frame.selection().isRange())
-        selectedText = plainTextReplacingNoBreakSpace(frame.selection().selection().toNormalizedRange().get());
+        selectedText = plainTextForContext(frame.selection().selection().toNormalizedRange().get());
 
     if (auto compositionRange = frame.editor().compositionRange()) {
         range = Range::create(*frame.document(), compositionRange->startPosition(), startPosition);
         String markedTextBefore;
         if (range)
-            markedTextBefore = plainTextReplacingNoBreakSpace(range.get());
+            markedTextBefore = plainTextForContext(range.get());
         range = Range::create(*frame.document(), endPosition, compositionRange->endPosition());
         String markedTextAfter;
         if (range)
-            markedTextAfter = plainTextReplacingNoBreakSpace(range.get());
+            markedTextAfter = plainTextForContext(range.get());
         markedText = markedTextBefore + selectedText + markedTextAfter;
         if (!markedText.isEmpty()) {
             markedTextRange.location = markedTextBefore.length();
@@ -2484,14 +2498,14 @@ WebAutocorrectionContext WebPage::autocorrectionContext()
                 previousPosition = startOfWord(positionOfNextBoundaryOfGranularity(currentPosition, WordGranularity, DirectionBackward));
                 if (previousPosition.isNull())
                     break;
-                String currentWord = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), previousPosition, currentPosition).ptr());
+                String currentWord = plainTextForContext(Range::create(*frame.document(), previousPosition, currentPosition).ptr());
                 totalContextLength += currentWord.length();
                 if (totalContextLength >= maxContextLength)
                     break;
                 currentPosition = previousPosition;
             }
             if (currentPosition.isNotNull() && currentPosition != startPosition) {
-                contextBefore = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), currentPosition, startPosition).ptr());
+                contextBefore = plainTextForContext(Range::create(*frame.document(), currentPosition, startPosition).ptr());
                 if (atBoundaryOfGranularity(currentPosition, ParagraphGranularity, DirectionBackward))
                     contextBefore = makeString("\n "_s, contextBefore);
             }
@@ -2502,7 +2516,7 @@ WebAutocorrectionContext WebPage::autocorrectionContext()
             if (!atBoundaryOfGranularity(endPosition, WordGranularity, DirectionForward) && withinTextUnitOfGranularity(endPosition, WordGranularity, DirectionForward))
                 nextPosition = positionOfNextBoundaryOfGranularity(endPosition, WordGranularity, DirectionForward);
             if (nextPosition.isNotNull())
-                contextAfter = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), endPosition, nextPosition).ptr());
+                contextAfter = plainTextForContext(Range::create(*frame.document(), endPosition, nextPosition).ptr());
         }
     }
 
@@ -2631,10 +2645,10 @@ static void dataDetectorLinkPositionInformation(Element& element, InteractionInf
     
     auto linkRange = Range::create(element.document());
     linkRange->selectNodeContents(element);
-    info.textBefore = plainTextReplacingNoBreakSpace(rangeExpandedByCharactersInDirectionAtWordBoundary(linkRange->startPosition(),
-        dataDetectionExtendedContextLength, DirectionBackward).get(), TextIteratorDefaultBehavior, true);
-    info.textAfter = plainTextReplacingNoBreakSpace(rangeExpandedByCharactersInDirectionAtWordBoundary(linkRange->endPosition(),
-        dataDetectionExtendedContextLength, DirectionForward).get(), TextIteratorDefaultBehavior, true);
+    info.textBefore = plainTextForDisplay(rangeExpandedByCharactersInDirectionAtWordBoundary(linkRange->startPosition(),
+        dataDetectionExtendedContextLength, DirectionBackward).get());
+    info.textAfter = plainTextForDisplay(rangeExpandedByCharactersInDirectionAtWordBoundary(linkRange->endPosition(),
+        dataDetectionExtendedContextLength, DirectionForward).get());
 }
 #endif
 
@@ -4186,20 +4200,22 @@ void WebPage::requestDocumentEditingContext(DocumentEditingContextRequest reques
         }
     }
 
-    auto makeString = [&](VisiblePosition& start, VisiblePosition& end) -> NSAttributedString * {
-        if (start.isNull() || end.isNull() || start == end)
+    auto makeString = [] (const VisiblePosition& start, const VisiblePosition& end) -> RetainPtr<NSAttributedString> {
+        auto startBoundary = makeBoundaryPoint(start.deepEquivalent());
+        auto endBoundary = makeBoundaryPoint(end.deepEquivalent());
+        if (!startBoundary || !endBoundary || *startBoundary == *endBoundary)
             return nil;
         // FIXME: This should return editing-offset-compatible attributed strings if that option is requested.
-        return adoptNS([[NSAttributedString alloc] initWithString:plainTextReplacingNoBreakSpace(start.deepEquivalent(), end.deepEquivalent())]).autorelease();
+        return adoptNS([[NSAttributedString alloc] initWithString:WebCore::plainTextReplacingNoBreakSpace({ WTFMove(*startBoundary), WTFMove(*endBoundary) })]);
     };
 
-    context.contextBefore = makeString(contextBeforeStart, startOfRangeOfInterestInSelection);
-    context.selectedText = makeString(startOfRangeOfInterestInSelection, endOfRangeOfInterestInSelection);
-    context.contextAfter = makeString(endOfRangeOfInterestInSelection, contextAfterEnd);
+    context.contextBefore = makeString(contextBeforeStart, startOfRangeOfInterestInSelection).get();
+    context.selectedText = makeString(startOfRangeOfInterestInSelection, endOfRangeOfInterestInSelection).get();
+    context.contextAfter = makeString(endOfRangeOfInterestInSelection, contextAfterEnd).get();
     if (compositionRange && rangesOverlap(rangeOfInterest.get(), compositionRange.get())) {
         VisiblePosition compositionStart(compositionRange->startPosition());
         VisiblePosition compositionEnd(compositionRange->endPosition());
-        context.markedText = makeString(compositionStart, compositionEnd);
+        context.markedText = makeString(compositionStart, compositionEnd).get();
         context.selectedRangeInMarkedText.location = distanceBetweenPositions(startOfRangeOfInterestInSelection, compositionStart);
         context.selectedRangeInMarkedText.length = [context.selectedText.string length];
     }
@@ -4226,7 +4242,11 @@ void WebPage::requestDocumentEditingContext(DocumentEditingContextRequest reques
         if (auto contextRange = makeRange(contextBeforeStart, contextAfterEnd))
             context.textRects = characterRectsForRange(*contextRange, 0);
     } else if (wantsMarkedTextRects && compositionRange) {
-        auto compositionStartOffset = plainTextReplacingNoBreakSpace(contextBeforeStart.deepEquivalent(), compositionRange->startPosition()).length();
+        auto start = makeBoundaryPoint(contextBeforeStart.deepEquivalent());
+        auto end = makeBoundaryPoint(compositionRange->startPosition());
+        unsigned compositionStartOffset = 0;
+        if (start && end)
+            compositionStartOffset = WebCore::plainText(SimpleRange { WTFMove(*start), WTFMove(*end) }).length();
         context.textRects = characterRectsForRange(*compositionRange, compositionStartOffset);
     }
 
index d25dbef..3a0dc45 100644 (file)
@@ -86,7 +86,6 @@
 #import <WebCore/RenderView.h>
 #import <WebCore/RuntimeApplicationChecks.h>
 #import <WebCore/ScrollView.h>
-#import <WebCore/SimpleRange.h>
 #import <WebCore/StyleInheritedData.h>
 #import <WebCore/TextIterator.h>
 #import <WebCore/VisibleUnits.h>
index efbc548..409f944 100644 (file)
@@ -1,3 +1,29 @@
+2020-03-15  Darin Adler  <darin@apple.com>
+
+        Move most of TextIterator off of live ranges
+        https://bugs.webkit.org/show_bug.cgi?id=209129
+
+        Reviewed by Antti Koivisto.
+
+        * WebView/WebFrame.mm: Removed an include.
+
+        * WebView/WebHTMLView.mm:
+        (-[WebHTMLView _legacyAttributedStringFrom:offset:to:offset:]):
+        Add casts to unsigned.
+
+        * WebView/WebTextIterator.mm:
+        (-[WebTextIterator initWithRange:]): Leave _private->_textIterator
+        as a nullptr if the passed-in range is nil since we no longer offer
+        a way to create an empty TextIterator; other clients don't seem to
+        need one.
+        (-[WebTextIterator advance]): Check _private->_textIterator for null.
+        (-[WebTextIterator atEnd]): Ditto.
+        (-[WebTextIterator currentRange]): Ditto.
+        (-[WebTextIterator currentTextPointer]): Ditto.
+        (-[WebTextIterator currentTextLength]): Ditto.
+        (-[WebTextIterator currentNode]): Ditto.
+        (-[WebTextIterator currentText]): Ditto.
+
 2020-03-16  Timothy Horton  <timothy_horton@apple.com>
 
         Always include System.framework in WebKitLegacy's CPLUSPLUSFLAGS
index eb9268c..bc3bebd 100644 (file)
 #import <WebCore/RuntimeApplicationChecks.h>
 #import <WebCore/ScriptController.h>
 #import <WebCore/SecurityOrigin.h>
-#import <WebCore/SimpleRange.h>
 #import <WebCore/SmartReplace.h>
 #import <WebCore/StyleProperties.h>
 #import <WebCore/SubframeLoader.h>
index eeaf0a0..5ba2e78 100644 (file)
@@ -7023,8 +7023,8 @@ static CGImageRef selectionImage(WebCore::Frame* frame, bool forceBlackText)
 - (NSAttributedString *)_legacyAttributedStringFrom:(DOMNode*)startContainer offset:(int)startOffset to:(DOMNode*)endContainer offset:(int)endOffset
 {
     return attributedStringBetweenStartAndEnd(
-        WebCore::Position { core(startContainer), startOffset, WebCore::Position::PositionIsOffsetInAnchor },
-        WebCore::Position { core(endContainer), endOffset, WebCore::Position::PositionIsOffsetInAnchor });
+        WebCore::Position { core(startContainer), static_cast<unsigned>(startOffset), WebCore::Position::PositionIsOffsetInAnchor },
+        WebCore::Position { core(endContainer), static_cast<unsigned>(endOffset), WebCore::Position::PositionIsOffsetInAnchor });
 }
 
 - (NSAttributedString *)attributedString
index 357c528..6b88bbf 100644 (file)
@@ -30,7 +30,6 @@
 #import "WebTypesInternal.h"
 #import <JavaScriptCore/InitializeThreading.h>
 #import <WebCore/Range.h>
-#import <WebCore/SimpleRange.h>
 #import <WebCore/TextIterator.h>
 #import <wtf/MainThread.h>
 #import <wtf/RunLoop.h>
         return self;
     
     _private = [[WebTextIteratorPrivate alloc] init];
-    _private->_textIterator = makeUnique<WebCore::TextIterator>(core(range));
+    if (!range)
+        return self;
+
+    _private->_textIterator = makeUnique<WebCore::TextIterator>(*core(range));
     return self;
 }
 
 - (void)advance
 {
-    _private->_textIterator->advance();
+    if (_private->_textIterator)
+        _private->_textIterator->advance();
     _private->_upconvertedText.shrink(0);
 }
 
 - (BOOL)atEnd
 {
-    return _private->_textIterator->atEnd();
+    return _private->_textIterator && _private->_textIterator->atEnd();
 }
 
 - (DOMRange *)currentRange
 {
+    if (!_private->_textIterator)
+        return nil;
     auto& textIterator = *_private->_textIterator;
     if (textIterator.atEnd())
-        return nullptr;
+        return nil;
     return kit(createLiveRange(textIterator.range()).ptr());
 }
 
 // FIXME: Consider deprecating this method and creating one that does not require copying 8-bit characters.
 - (const unichar*)currentTextPointer
 {
+    if (!_private->_textIterator)
+        return nullptr;
     StringView text = _private->_textIterator->text();
     unsigned length = text.length();
     if (!length)
 
 - (NSUInteger)currentTextLength
 {
-    return _private->_textIterator->text().length();
+    return _private->_textIterator ? _private->_textIterator->text().length() : 0;
 }
 
 @end
 
 - (DOMNode *)currentNode
 {
-    return kit(_private->_textIterator->node());
+    return _private->_textIterator ? kit(_private->_textIterator->node()) : nil;
 }
 
 - (NSString *)currentText
 {
-    return [[_private->_textIterator->text().createNSString().get() retain] autorelease];
+    return _private->_textIterator ? _private->_textIterator->text().createNSString().autorelease() : @"";
 }
 
 @end