Remove all uses of live ranges from TextIterator
https://bugs.webkit.org/show_bug.cgi?id=209723
Reviewed by Antti Koivisto.
Source/WebCore:
- Replaced TextIterator::getLocationAndLengthFromRange with a function named
characterRange that computes a CharacterRange given a scope and a range.
- Removed the overload of plainText that takes a pointer to a live range.
- Update the many callers of plainText that pass a pointer to a live range
to pass a reference instead, adding null checks as needed to preserve behavior.
- Rewrote some call sites to not use live ranges at all, or use them minimally.
* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::nextSentenceEndPosition const): Streamlined
the logic in this function, using a smaller number of null checks since the
functions we are calling also do null checks, simpler variable names and
fewer local variables. Pass a reference to a live range rather than a
pointer to the plainText function.
(WebCore::AccessibilityObject::previousSentenceStartPosition const): Ditto.
(WebCore::AccessibilityObject::nextParagraphEndPosition const): Ditto.
(WebCore::AccessibilityObject::previousParagraphStartPosition const): Ditto.
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::textUnderElement const): Ditto.
(WebCore::boundsForRects): Converted this to a file-local function and changed
it to take a SimpleRange instead of a live range.
(WebCore::AccessibilityRenderObject::boundsForVisiblePositionRange const): Pass
a reference to a live range instead of a pointer.
(WebCore::AccessibilityRenderObject::boundsForRange const): Ditto.
* accessibility/AccessibilityRenderObject.h: Removed boundsForRects.
* accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(-[WebAccessibilityObjectWrapper _convertToNSRange:]): Rewrote to use
characterRange instead of TextIterator::getLocationAndLengthFromRange.
* dom/BoundaryPoint.h:
(WebCore::makeBoundaryPointBeforeNodeContents): Added.
* dom/Element.cpp:
(WebCore::Element::innerText): Pass a SimpleRange instead of a live range
to the plainText function.
* dom/Range.cpp:
(WebCore::Range::text const): Pass a reference to a live range instead of a
pointer to the plainText function.
* dom/SimpleRange.cpp:
(WebCore::makeBoundaryPointAfterNodeContents): Added.
(WebCore::makeRangeSelectingNodeContents): Use makeBoundaryPointBeforeNodeContents
and makeBoundaryPointAfterNodeContents
* editing/AlternativeTextController.cpp:
(WebCore::AlternativeTextController::applyPendingCorrection): Pass a reference
to a live range to plainText.
(WebCore::AlternativeTextController::show): Ditto.
(WebCore::AlternativeTextController::timerFired): Ditto.
(WebCore::AlternativeTextController::handleAlternativeTextUIResult): Ditto.
(WebCore::AlternativeTextController::recordAutocorrectionResponse): Ditto. Also
take a SimpleRange argument.
(WebCore::AlternativeTextController::markPrecedingWhitespaceForDeletedAutocorrectionAfterCommand):
Ditto.
(WebCore::AlternativeTextController::respondToMarkerAtEndOfWord):Ditto.
* editing/AlternativeTextController.h: Update for the above changes.
* editing/Editor.cpp:
(WebCore::Editor::markMisspellingsAfterTypingToWord): Pass a reference
to a live range to plainText.
(WebCore::correctSpellcheckingPreservingTextCheckingParagraph): Ditto.
Also refactor for simplicity and clarity.
(WebCore::Editor::markAndReplaceFor): Ditto.
(WebCore::Editor::changeBackToReplacedString): Ditto.
(WebCore::Editor::transpose): Ditto.
(WebCore::Editor::addRangeToKillRing): Ditto.
(WebCore::Editor::stringForCandidateRequest const): Ditto.
* editing/ReplaceRangeWithTextCommand.cpp:
(WebCore::ReplaceRangeWithTextCommand::doApply): Ditto.
* editing/ReplaceSelectionCommand.cpp:
(WebCore::ReplacementFragment::ReplacementFragment): Ditto.
* editing/SpellingCorrectionCommand.cpp:
(WebCore::SpellingCorrectionCommand::doApply): Ditto.
* editing/TextCheckingHelper.cpp:
(WebCore::TextCheckingParagraph::text const): Ditto.
(WebCore::TextCheckingHelper::findFirstMisspellingOrBadGrammar): Ditto.
* editing/TextIterator.cpp: Use more constexpr.
(WebCore::characterSubrange): Deleted. Moved the logic from this function
into the one place using it, the rangeForMatch function.
(WebCore::resolveCharacterLocation): Deleted. Moved to the header file.
(WebCore::TextIterator::getLocationAndLengthFromRange): Deleted.
(WebCore::plainText): Deleted the overload that takes a live range pointer.
(WebCore::plainTextUsingBackwardsTextIteratorForTesting): Deleted. Moved
the implementation to Internals. There's nothing special about the algorithm,
it uses SimplifiedBackwardsTextIterator in a simple way.
(WebCore::collapsedToBoundary): Deleted. Moved the code to the one place
it's used, the rangeForMatch function.
(WebCore::forEachMatch): Renamed from findPlainTextMatches and changed to
work without any use of live ranges and to use CharacterRange.
(WebCore::rangeForMatch): Rewrote to include more of the logic, removing
the collapsedToBoundary and characterSubrange functions, and to not use
any live ranges.
(WebCore::findClosestPlainText): Rewrote to tighten up the algorithm a
bit, break ties based on the search direction, and have less repetitive code.
(WebCore::findPlainText): Rewrote for clarity.
* editing/TextIterator.h: Removed the forward declaration of Range.
Removed the overload of plainText that takes a live range pointer. Moved
the functions that work with character ranges up to the top of the file,
grouped the other functions more logically. Deleted the
TextIterator::getLocationAndLengthFromRange function. Put some inline
function definitions here.
* editing/TypingCommand.cpp:
(WebCore::TypingCommand::markMisspellingsAfterTyping): Pass a reference
to a live range to plainText.
* editing/VisibleUnits.cpp:
(WebCore::charactersAroundPosition): Pass a SimpleRange to plainText
rather than a live range.
* editing/cocoa/DataDetection.mm:
(WebCore::detectItemAtPositionWithRange): Pass a reference to a live
range to plainText.
* editing/cocoa/DictionaryLookup.mm:
(WebCore::DictionaryLookup::rangeForSelection): Ditto.
* editing/cocoa/HTMLConverter.h: Tweaked #if a bit.
* editing/mac/DictionaryLookupLegacy.mm:
(WebCore::DictionaryLookup::rangeForSelection): Pass a reference to a
live range to plainText. Also rewrote logic to use mostly SimpleRange.
(WebCore::DictionaryLookup::rangeAtHitTestResult): Ditto.
* editing/markup.cpp:
(WebCore::StyledMarkupAccumulator::renderedTextRespectingRange): Ditto.
* html/HTMLTextAreaElement.cpp:
(WebCore::HTMLTextAreaElement::handleBeforeTextInsertedEvent const): Ditto.
* page/ContextMenuController.cpp:
(WebCore::ContextMenuController::contextMenuItemSelected): Ditto.
* page/DOMSelection.cpp:
(WebCore::DOMSelection::toString): Ditto.
* page/Page.cpp:
(WebCore::Page::replaceRangesWithText): Rewrote to replaces use of
TextIterator::getLocationAndLengthFromRange with characterRange.
* page/ios/FrameIOS.mm:
(WebCore::Frame::interpretationsForCurrentRoot const): Pass a
reference to a live range to plainText.
* testing/Internals.cpp:
(WebCore::Internals::locationFromRange): Use characterRange.
(WebCore::Internals::lengthFromRange): Ditto.
(WebCore::Internals::rangeAsTextUsingBackwardsTextIterator):
USe SimplifiedBackwardsTextIterator directly since we no longer have
the function plainTextUsingBackwardsTextIteratorForTesting.
Source/WebKit:
* Shared/EditingRange.cpp:
(WebKit::EditingRange::fromRange): Use characterRange.
* Shared/mac/AttributedString.h: Added a constructor that takes rvalue
references so we can initialize this slightly more efficiently.
* Shared/mac/AttributedString.mm:
(IPC::ArgumentCoder<WebKit::AttributedString>::decode): Pass rvalue
references when creating an AttributedString.
* UIProcess/mac/TextCheckerMac.mm:
(WebKit::TextChecker::updateSpellingUIWithGrammarString): Simplify the
code to remove some local variables that weren't helpful.
* WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.h: Made the
annotatedSubstringBetweenPositions a static member function. Also used
const& argument types to cut down on reference count churn a bit.
* WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.mm:
(WebKit::TextCheckingControllerProxy::rangeAndOffsetRelativeToSelection):
Streamlined and made this use characterCount instead of
TextIterator::getLocationAndLengthFromRange.
(WebKit::TextCheckingControllerProxy::replaceRelativeToSelection): Tweaked
the argument type.
(WebKit::TextCheckingControllerProxy::removeAnnotationRelativeToSelection):
Ditto. Also removed some unnecessary use of NSString.
(WebKit::TextCheckingControllerProxy::annotatedSubstringBetweenPositions):
Rewrote to no longer use live ranges.
* WebProcess/WebPage/Cocoa/WebPageCocoa.mm:
(WebKit::WebPage::getContentsAsAttributedString): Use construction and
rvalue references to tigten things up a bit.
* WebProcess/WebPage/WebFrame.cpp:
(WebKit::WebFrame::contentsAsString const): Use a SimpleRange instead of
a live range to pass to plainText.
* WebProcess/WebPage/glib/WebPageGLib.cpp:
(WebKit::WebPage::getPlatformEditorState const): Pass references to
live ranges to plainText.
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::updateSelectionWithDelta): Rewrote to minimize use of
live ranges.
(WebKit::WebPage::requestDocumentEditingContext): Ditto.
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::getPlatformEditorState const): Pass reference to
a live range to plainText.
Source/WebKitLegacy/mac:
* WebCoreSupport/WebEditorClient.mm:
(WebEditorClient::updateSpellingUIWithGrammarString): Remove some unnecessary
use of local variabels for NSString.
(WebEditorClient::requestCandidatesForSelection): Pass a reference to a live
range to plainText.
* WebView/WebFrame.mm:
(-[WebFrame _stringForRange:]): Ditto.
(-[WebFrame _convertToNSRange:]): Use characterRange instead of
TextIterator::getLocationAndLengthFromRange.
Source/WebKitLegacy/win:
* WebFrame.cpp:
(WebFrame::string): Use a SimpleRange instead of a live range
to call plainText.
* WebView.cpp:
(WebView::selectedRangeForTesting): Use a SimpleRange instead
of a live range to call characterRange instead of
TextIterator::getLocationAndLengthFromRange.
LayoutTests:
* editing/text-iterator/find-string-on-flat-tree-expected.txt:
* editing/text-iterator/find-string-on-flat-tree.html:
Updated test for a progress where we properly find strings across a shadow boundary.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@259401 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 794f1f3..c8ecf24 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,14 @@
+2020-04-01 Darin Adler <darin@apple.com>
+
+ Remove all uses of live ranges from TextIterator
+ https://bugs.webkit.org/show_bug.cgi?id=209723
+
+ Reviewed by Antti Koivisto.
+
+ * editing/text-iterator/find-string-on-flat-tree-expected.txt:
+ * editing/text-iterator/find-string-on-flat-tree.html:
+ Updated test for a progress where we properly find strings across a shadow boundary.
+
2020-04-02 David Kilzer <ddkilzer@apple.com>
API::PageConfiguration may have conflicting preference values between WebPreferences and WebPreferencesStore::ValueMap instance variables
diff --git a/LayoutTests/editing/text-iterator/find-string-on-flat-tree-expected.txt b/LayoutTests/editing/text-iterator/find-string-on-flat-tree-expected.txt
index 598d0d4..6a36821 100644
--- a/LayoutTests/editing/text-iterator/find-string-on-flat-tree-expected.txt
+++ b/LayoutTests/editing/text-iterator/find-string-on-flat-tree-expected.txt
@@ -76,7 +76,7 @@
PASS internals.countFindMatches('in-', ['DoNotTraverseFlatTree']) is 2
PASS internals.countFindMatches('in-', []) is 4
PASS internals.countFindMatches('in-shadow in-document', ['DoNotTraverseFlatTree']) is 0
-PASS internals.countFindMatches('in-shadow in-document', []) is 0
+PASS internals.countFindMatches('in-shadow in-document', []) is 1
PASS rangeText(internals.rangeOfString('inside-display-none', null, [])) is null
PASS successfullyParsed is true
diff --git a/LayoutTests/editing/text-iterator/find-string-on-flat-tree.html b/LayoutTests/editing/text-iterator/find-string-on-flat-tree.html
index 1905253..3659ff2 100644
--- a/LayoutTests/editing/text-iterator/find-string-on-flat-tree.html
+++ b/LayoutTests/editing/text-iterator/find-string-on-flat-tree.html
@@ -160,7 +160,7 @@
shouldBe("internals.countFindMatches('in-', [])", "4");
shouldBe("internals.countFindMatches('in-shadow in-document', ['DoNotTraverseFlatTree'])", "0");
- shouldBe("internals.countFindMatches('in-shadow in-document', [])", "0");
+ shouldBe("internals.countFindMatches('in-shadow in-document', [])", "1");
shouldBe("rangeText(internals.rangeOfString('inside-display-none', null, []))", "null");
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 15c584a..7d8f2b9 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,157 @@
+2020-04-01 Darin Adler <darin@apple.com>
+
+ Remove all uses of live ranges from TextIterator
+ https://bugs.webkit.org/show_bug.cgi?id=209723
+
+ Reviewed by Antti Koivisto.
+
+ - Replaced TextIterator::getLocationAndLengthFromRange with a function named
+ characterRange that computes a CharacterRange given a scope and a range.
+ - Removed the overload of plainText that takes a pointer to a live range.
+ - Update the many callers of plainText that pass a pointer to a live range
+ to pass a reference instead, adding null checks as needed to preserve behavior.
+ - Rewrote some call sites to not use live ranges at all, or use them minimally.
+
+ * accessibility/AccessibilityObject.cpp:
+ (WebCore::AccessibilityObject::nextSentenceEndPosition const): Streamlined
+ the logic in this function, using a smaller number of null checks since the
+ functions we are calling also do null checks, simpler variable names and
+ fewer local variables. Pass a reference to a live range rather than a
+ pointer to the plainText function.
+ (WebCore::AccessibilityObject::previousSentenceStartPosition const): Ditto.
+ (WebCore::AccessibilityObject::nextParagraphEndPosition const): Ditto.
+ (WebCore::AccessibilityObject::previousParagraphStartPosition const): Ditto.
+ * accessibility/AccessibilityRenderObject.cpp:
+ (WebCore::AccessibilityRenderObject::textUnderElement const): Ditto.
+ (WebCore::boundsForRects): Converted this to a file-local function and changed
+ it to take a SimpleRange instead of a live range.
+ (WebCore::AccessibilityRenderObject::boundsForVisiblePositionRange const): Pass
+ a reference to a live range instead of a pointer.
+ (WebCore::AccessibilityRenderObject::boundsForRange const): Ditto.
+ * accessibility/AccessibilityRenderObject.h: Removed boundsForRects.
+
+ * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+ (-[WebAccessibilityObjectWrapper _convertToNSRange:]): Rewrote to use
+ characterRange instead of TextIterator::getLocationAndLengthFromRange.
+
+ * dom/BoundaryPoint.h:
+ (WebCore::makeBoundaryPointBeforeNodeContents): Added.
+
+ * dom/Element.cpp:
+ (WebCore::Element::innerText): Pass a SimpleRange instead of a live range
+ to the plainText function.
+
+ * dom/Range.cpp:
+ (WebCore::Range::text const): Pass a reference to a live range instead of a
+ pointer to the plainText function.
+
+ * dom/SimpleRange.cpp:
+ (WebCore::makeBoundaryPointAfterNodeContents): Added.
+ (WebCore::makeRangeSelectingNodeContents): Use makeBoundaryPointBeforeNodeContents
+ and makeBoundaryPointAfterNodeContents
+
+ * editing/AlternativeTextController.cpp:
+ (WebCore::AlternativeTextController::applyPendingCorrection): Pass a reference
+ to a live range to plainText.
+ (WebCore::AlternativeTextController::show): Ditto.
+ (WebCore::AlternativeTextController::timerFired): Ditto.
+ (WebCore::AlternativeTextController::handleAlternativeTextUIResult): Ditto.
+ (WebCore::AlternativeTextController::recordAutocorrectionResponse): Ditto. Also
+ take a SimpleRange argument.
+ (WebCore::AlternativeTextController::markPrecedingWhitespaceForDeletedAutocorrectionAfterCommand):
+ Ditto.
+ (WebCore::AlternativeTextController::respondToMarkerAtEndOfWord):Ditto.
+ * editing/AlternativeTextController.h: Update for the above changes.
+
+ * editing/Editor.cpp:
+ (WebCore::Editor::markMisspellingsAfterTypingToWord): Pass a reference
+ to a live range to plainText.
+ (WebCore::correctSpellcheckingPreservingTextCheckingParagraph): Ditto.
+ Also refactor for simplicity and clarity.
+ (WebCore::Editor::markAndReplaceFor): Ditto.
+ (WebCore::Editor::changeBackToReplacedString): Ditto.
+ (WebCore::Editor::transpose): Ditto.
+ (WebCore::Editor::addRangeToKillRing): Ditto.
+ (WebCore::Editor::stringForCandidateRequest const): Ditto.
+ * editing/ReplaceRangeWithTextCommand.cpp:
+ (WebCore::ReplaceRangeWithTextCommand::doApply): Ditto.
+ * editing/ReplaceSelectionCommand.cpp:
+ (WebCore::ReplacementFragment::ReplacementFragment): Ditto.
+ * editing/SpellingCorrectionCommand.cpp:
+ (WebCore::SpellingCorrectionCommand::doApply): Ditto.
+ * editing/TextCheckingHelper.cpp:
+ (WebCore::TextCheckingParagraph::text const): Ditto.
+ (WebCore::TextCheckingHelper::findFirstMisspellingOrBadGrammar): Ditto.
+
+ * editing/TextIterator.cpp: Use more constexpr.
+ (WebCore::characterSubrange): Deleted. Moved the logic from this function
+ into the one place using it, the rangeForMatch function.
+ (WebCore::resolveCharacterLocation): Deleted. Moved to the header file.
+ (WebCore::TextIterator::getLocationAndLengthFromRange): Deleted.
+ (WebCore::plainText): Deleted the overload that takes a live range pointer.
+ (WebCore::plainTextUsingBackwardsTextIteratorForTesting): Deleted. Moved
+ the implementation to Internals. There's nothing special about the algorithm,
+ it uses SimplifiedBackwardsTextIterator in a simple way.
+ (WebCore::collapsedToBoundary): Deleted. Moved the code to the one place
+ it's used, the rangeForMatch function.
+ (WebCore::forEachMatch): Renamed from findPlainTextMatches and changed to
+ work without any use of live ranges and to use CharacterRange.
+ (WebCore::rangeForMatch): Rewrote to include more of the logic, removing
+ the collapsedToBoundary and characterSubrange functions, and to not use
+ any live ranges.
+ (WebCore::findClosestPlainText): Rewrote to tighten up the algorithm a
+ bit, break ties based on the search direction, and have less repetitive code.
+ (WebCore::findPlainText): Rewrote for clarity.
+
+ * editing/TextIterator.h: Removed the forward declaration of Range.
+ Removed the overload of plainText that takes a live range pointer. Moved
+ the functions that work with character ranges up to the top of the file,
+ grouped the other functions more logically. Deleted the
+ TextIterator::getLocationAndLengthFromRange function. Put some inline
+ function definitions here.
+
+ * editing/TypingCommand.cpp:
+ (WebCore::TypingCommand::markMisspellingsAfterTyping): Pass a reference
+ to a live range to plainText.
+ * editing/VisibleUnits.cpp:
+ (WebCore::charactersAroundPosition): Pass a SimpleRange to plainText
+ rather than a live range.
+ * editing/cocoa/DataDetection.mm:
+ (WebCore::detectItemAtPositionWithRange): Pass a reference to a live
+ range to plainText.
+ * editing/cocoa/DictionaryLookup.mm:
+ (WebCore::DictionaryLookup::rangeForSelection): Ditto.
+
+ * editing/cocoa/HTMLConverter.h: Tweaked #if a bit.
+
+ * editing/mac/DictionaryLookupLegacy.mm:
+ (WebCore::DictionaryLookup::rangeForSelection): Pass a reference to a
+ live range to plainText. Also rewrote logic to use mostly SimpleRange.
+ (WebCore::DictionaryLookup::rangeAtHitTestResult): Ditto.
+ * editing/markup.cpp:
+ (WebCore::StyledMarkupAccumulator::renderedTextRespectingRange): Ditto.
+ * html/HTMLTextAreaElement.cpp:
+ (WebCore::HTMLTextAreaElement::handleBeforeTextInsertedEvent const): Ditto.
+ * page/ContextMenuController.cpp:
+ (WebCore::ContextMenuController::contextMenuItemSelected): Ditto.
+ * page/DOMSelection.cpp:
+ (WebCore::DOMSelection::toString): Ditto.
+
+ * page/Page.cpp:
+ (WebCore::Page::replaceRangesWithText): Rewrote to replaces use of
+ TextIterator::getLocationAndLengthFromRange with characterRange.
+
+ * page/ios/FrameIOS.mm:
+ (WebCore::Frame::interpretationsForCurrentRoot const): Pass a
+ reference to a live range to plainText.
+
+ * testing/Internals.cpp:
+ (WebCore::Internals::locationFromRange): Use characterRange.
+ (WebCore::Internals::lengthFromRange): Ditto.
+ (WebCore::Internals::rangeAsTextUsingBackwardsTextIterator):
+ USe SimplifiedBackwardsTextIterator directly since we no longer have
+ the function plainTextUsingBackwardsTextIteratorForTesting.
+
2020-04-02 Ryosuke Niwa <rniwa@webkit.org>
Remove a superflous blank line added in the previous commit as pointed out during the code review.
diff --git a/Source/WebCore/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp
index 51ca4cf..e887524 100644
--- a/Source/WebCore/accessibility/AccessibilityObject.cpp
+++ b/Source/WebCore/accessibility/AccessibilityObject.cpp
@@ -1443,79 +1443,47 @@
return startPosition;
}
-VisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePosition& visiblePos) const
+VisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePosition& position) const
{
// FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
// Related? <rdar://problem/3927736> Text selection broken in 8A336
- if (visiblePos.isNull())
- return VisiblePosition();
- // make sure we move off of a sentence end
- VisiblePosition nextVisiblePos = visiblePos.next();
- if (nextVisiblePos.isNull())
- return VisiblePosition();
+ // Make sure we move off of a sentence end.
+ auto nextPosition = position.next();
+ auto lineRange = makeRange(startOfLine(nextPosition), endOfLine(nextPosition));
+ if (!lineRange)
+ return { };
- // an empty line is considered a sentence. If it's skipped, then the sentence parser will not
- // see this empty line. Instead, return the end position of the empty line.
- VisiblePosition endPosition;
-
- String lineString = plainText(makeRange(startOfLine(nextVisiblePos), endOfLine(nextVisiblePos)).get());
- if (lineString.isEmpty())
- endPosition = nextVisiblePos;
- else
- endPosition = endOfSentence(nextVisiblePos);
-
- return endPosition;
+ // An empty line is considered a sentence. If it's skipped, then the sentence parser will not
+ // see this empty line. Instead, return the end position of the empty line.
+ // FIXME: It would be more efficient to use hasAnyPlainText instead of plainText.isEmpty.
+ return plainText(*lineRange).isEmpty() ? nextPosition : endOfSentence(nextPosition);
}
-VisiblePosition AccessibilityObject::previousSentenceStartPosition(const VisiblePosition& visiblePos) const
+VisiblePosition AccessibilityObject::previousSentenceStartPosition(const VisiblePosition& position) const
{
// FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
// Related? <rdar://problem/3927736> Text selection broken in 8A336
- if (visiblePos.isNull())
- return VisiblePosition();
- // make sure we move off of a sentence start
- VisiblePosition previousVisiblePos = visiblePos.previous();
- if (previousVisiblePos.isNull())
- return VisiblePosition();
+ // Make sure we move off of a sentence start.
+ auto previousPosition = position.previous();
+ auto lineRange = makeRange(startOfLine(previousPosition), endOfLine(previousPosition));
+ if (!lineRange)
+ return { };
- // treat empty line as a separate sentence.
- VisiblePosition startPosition;
-
- String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get());
- if (lineString.isEmpty())
- startPosition = previousVisiblePos;
- else
- startPosition = startOfSentence(previousVisiblePos);
-
- return startPosition;
+ // Treat empty line as a separate sentence.
+ // FIXME: It would be more efficient to use hasAnyPlainText instead of plainText.isEmpty.
+ return plainText(*lineRange).isEmpty() ? previousPosition : startOfSentence(previousPosition);
}
-VisiblePosition AccessibilityObject::nextParagraphEndPosition(const VisiblePosition& visiblePos) const
+VisiblePosition AccessibilityObject::nextParagraphEndPosition(const VisiblePosition& position) const
{
- if (visiblePos.isNull())
- return VisiblePosition();
-
- // make sure we move off of a paragraph end
- VisiblePosition nextPos = visiblePos.next();
- if (nextPos.isNull())
- return VisiblePosition();
-
- return endOfParagraph(nextPos);
+ return endOfParagraph(position.next());
}
-VisiblePosition AccessibilityObject::previousParagraphStartPosition(const VisiblePosition& visiblePos) const
+VisiblePosition AccessibilityObject::previousParagraphStartPosition(const VisiblePosition& position) const
{
- if (visiblePos.isNull())
- return VisiblePosition();
-
- // make sure we move off of a paragraph start
- VisiblePosition previousPos = visiblePos.previous();
- if (previousPos.isNull())
- return VisiblePosition();
-
- return startOfParagraph(previousPos);
+ return startOfParagraph(position.previous());
}
AccessibilityObject* AccessibilityObject::accessibilityObjectForPosition(const VisiblePosition& visiblePos) const
diff --git a/Source/WebCore/accessibility/AccessibilityRenderObject.cpp b/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
index e616ea9..35a66be 100644
--- a/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
+++ b/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
@@ -664,7 +664,7 @@
// style update/layout here. See also AXObjectCache::deferTextChangedIfNeeded().
ASSERT_WITH_SECURITY_IMPLICATION(!nodeDocument->childNeedsStyleRecalc());
ASSERT_WITH_SECURITY_IMPLICATION(!nodeDocument->view()->layoutContext().isInRenderTreeLayout());
- return plainText(textRange.get(), textIteratorBehaviorForTextRange());
+ return plainText(*textRange, textIteratorBehaviorForTextRange());
}
}
@@ -2081,16 +2081,15 @@
return false;
}
-IntRect AccessibilityRenderObject::boundsForRects(LayoutRect const& rect1, LayoutRect const& rect2, RefPtr<Range> const& dataRange)
+static IntRect boundsForRects(const LayoutRect& rect1, const LayoutRect& rect2, const SimpleRange& dataRange)
{
LayoutRect ourRect = rect1;
ourRect.unite(rect2);
-
- // if the rectangle spans lines and contains multiple text chars, use the range's bounding box intead
+
+ // If the rectangle spans lines and contains multiple text characters, use the range's bounding box intead.
if (rect1.maxY() != rect2.maxY()) {
- LayoutRect boundingBox = dataRange->absoluteBoundingBox();
- String rangeString = plainText(dataRange.get());
- if (rangeString.length() > 1 && !boundingBox.isEmpty())
+ LayoutRect boundingBox = createLiveRange(dataRange)->absoluteBoundingBox();
+ if (characterCount(dataRange) > 1 && !boundingBox.isEmpty())
ourRect = boundingBox;
}
@@ -2120,8 +2119,7 @@
}
}
- RefPtr<Range> dataRange = makeRange(range.start, range.end);
- return boundsForRects(rect1, rect2, dataRange);
+ return boundsForRects(rect1, rect2, *makeRange(range.start, range.end));
}
IntRect AccessibilityRenderObject::boundsForRange(const RefPtr<Range> range) const
@@ -2152,7 +2150,7 @@
}
}
- return boundsForRects(rect1, rect2, range);
+ return boundsForRects(rect1, rect2, *range);
}
bool AccessibilityRenderObject::isVisiblePositionRangeInDifferentDocument(const VisiblePositionRange& range) const
diff --git a/Source/WebCore/accessibility/AccessibilityRenderObject.h b/Source/WebCore/accessibility/AccessibilityRenderObject.h
index 776b48f..7ecf04a 100644
--- a/Source/WebCore/accessibility/AccessibilityRenderObject.h
+++ b/Source/WebCore/accessibility/AccessibilityRenderObject.h
@@ -293,8 +293,6 @@
bool canHavePlainText() const;
// Special handling of click point for links.
IntPoint linkClickPoint();
- // Rects utilities.
- static IntRect boundsForRects(LayoutRect const&, LayoutRect const&, RefPtr<Range> const&);
};
} // namespace WebCore
diff --git a/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm b/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
index f6a7231..88f8948 100644
--- a/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
+++ b/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
@@ -3636,21 +3636,18 @@
{
ASSERT(isMainThread());
- NSRange result = NSMakeRange(NSNotFound, 0);
if (!range)
- return result;
+ return NSMakeRange(NSNotFound, 0);
- Document* document = self.axBackingObject->document();
+ auto document = self.axBackingObject->document();
if (!document)
- return result;
-
- size_t location;
- size_t length;
- TextIterator::getLocationAndLengthFromRange(document->documentElement(), range, location, length);
- result.location = location;
- result.length = length;
-
- return result;
+ return NSMakeRange(NSNotFound, 0);
+
+ auto documentElement = document->documentElement();
+ if (!documentElement)
+ return NSMakeRange(NSNotFound, 0);
+
+ return characterRange(makeBoundaryPointBeforeNodeContents(*documentElement), *range);
}
- (NSInteger)_indexForTextMarker:(id)marker
diff --git a/Source/WebCore/dom/BoundaryPoint.h b/Source/WebCore/dom/BoundaryPoint.h
index a5d8e3e..5cbbfdc 100644
--- a/Source/WebCore/dom/BoundaryPoint.h
+++ b/Source/WebCore/dom/BoundaryPoint.h
@@ -46,6 +46,8 @@
bool operator==(const BoundaryPoint&, const BoundaryPoint&);
+BoundaryPoint makeBoundaryPointBeforeNodeContents(Node&);
+
inline BoundaryPoint::BoundaryPoint(Ref<Node>&& container, unsigned offset)
: container(WTFMove(container))
, offset(offset)
@@ -75,4 +77,9 @@
return a.container.ptr() == b.container.ptr() && a.offset == b.offset;
}
+inline BoundaryPoint makeBoundaryPointBeforeNodeContents(Node& node)
+{
+ return { node, 0 };
+}
+
}
diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp
index 6002c3d..c9dbd5e 100644
--- a/Source/WebCore/dom/Element.cpp
+++ b/Source/WebCore/dom/Element.cpp
@@ -3197,7 +3197,7 @@
if (!renderer())
return textContent(true);
- return plainText(rangeOfContents(*this).ptr());
+ return plainText(makeRangeSelectingNodeContents(*this));
}
String Element::outerText()
diff --git a/Source/WebCore/dom/Range.cpp b/Source/WebCore/dom/Range.cpp
index 45c1bcf..be4eb69 100644
--- a/Source/WebCore/dom/Range.cpp
+++ b/Source/WebCore/dom/Range.cpp
@@ -951,7 +951,7 @@
// FIXME: As with innerText, we'd like this to work even if there are no render objects.
startContainer().document().updateLayout();
- return plainText(this);
+ return plainText(*this);
}
// https://w3c.github.io/DOM-Parsing/#widl-Range-createContextualFragment-DocumentFragment-DOMString-fragment
diff --git a/Source/WebCore/dom/SimpleRange.cpp b/Source/WebCore/dom/SimpleRange.cpp
index a7d91cd2..8eead06 100644
--- a/Source/WebCore/dom/SimpleRange.cpp
+++ b/Source/WebCore/dom/SimpleRange.cpp
@@ -68,9 +68,14 @@
return node.countChildNodes();
}
+static BoundaryPoint makeBoundaryPointAfterNodeContents(Node& node)
+{
+ return { node, length(node) };
+}
+
SimpleRange makeRangeSelectingNodeContents(Node& node)
{
- return { { node, 0 }, { node, length(node) } };
+ return { makeBoundaryPointBeforeNodeContents(node), makeBoundaryPointAfterNodeContents(node) };
}
}
diff --git a/Source/WebCore/editing/AlternativeTextController.cpp b/Source/WebCore/editing/AlternativeTextController.cpp
index f70da58..f1128b9 100644
--- a/Source/WebCore/editing/AlternativeTextController.cpp
+++ b/Source/WebCore/editing/AlternativeTextController.cpp
@@ -130,9 +130,11 @@
VisiblePosition startOfSelection = selectionAfterTyping.visibleStart();
VisibleSelection currentWord = VisibleSelection(startOfWord(startOfSelection, LeftWordIfOnBoundary), endOfWord(startOfSelection, RightWordIfOnBoundary));
if (currentWord.visibleEnd() == startOfSelection) {
- String wordText = plainText(currentWord.toNormalizedRange().get());
- if (wordText.length() > 0 && isAmbiguousBoundaryCharacter(wordText[wordText.length() - 1]))
- doApplyCorrection = false;
+ if (auto wordRange = currentWord.firstRange()) {
+ String wordText = plainText(*wordRange);
+ if (!wordText.isEmpty() && isAmbiguousBoundaryCharacter(wordText[wordText.length() - 1]))
+ doApplyCorrection = false;
+ }
}
if (doApplyCorrection)
handleAlternativeTextUIResult(dismissSoon(ReasonForDismissingAlternativeTextAccepted));
@@ -155,7 +157,7 @@
FloatRect boundingBox = rootViewRectForRange(&rangeToReplace);
if (boundingBox.isEmpty())
return;
- m_originalText = plainText(&rangeToReplace);
+ m_originalText = plainText(rangeToReplace);
m_rangeWithAlternative = &rangeToReplace;
m_details = replacement;
m_isActive = true;
@@ -249,7 +251,7 @@
if (replacementString.isEmpty())
break;
m_isActive = true;
- m_originalText = plainText(m_rangeWithAlternative.get());
+ m_originalText = plainText(*m_rangeWithAlternative);
FloatRect boundingBox = rootViewRectForRange(m_rangeWithAlternative.get());
if (!boundingBox.isEmpty()) {
if (AlternativeTextClient* client = alternativeTextClient())
@@ -258,9 +260,9 @@
}
break;
case AlternativeTextTypeSpellingSuggestions: {
- if (!m_rangeWithAlternative || plainText(m_rangeWithAlternative.get()) != m_originalText)
+ if (!m_rangeWithAlternative || plainText(*m_rangeWithAlternative) != m_originalText)
break;
- String paragraphText = plainText(&TextCheckingParagraph(*m_rangeWithAlternative).paragraphRange());
+ String paragraphText = plainText(TextCheckingParagraph(*m_rangeWithAlternative).paragraphRange());
Vector<String> suggestions;
textChecker()->getGuessesForWord(m_originalText, paragraphText, m_frame.selection().selection(), suggestions);
if (suggestions.isEmpty()) {
@@ -303,7 +305,7 @@
if (!rangeWithAlternative || m_frame.document() != &rangeWithAlternative->ownerDocument())
return;
- String currentWord = plainText(rangeWithAlternative);
+ String currentWord = plainText(*rangeWithAlternative);
// Check to see if the word we are about to correct has been changed between timer firing and callback being triggered.
if (currentWord != m_originalText)
return;
@@ -416,7 +418,7 @@
return nullptr;
}
-void AlternativeTextController::recordAutocorrectionResponse(AutocorrectionResponse response, const String& replacedString, Range* replacementRange)
+void AlternativeTextController::recordAutocorrectionResponse(AutocorrectionResponse response, const String& replacedString, const SimpleRange& replacementRange)
{
if (auto client = alternativeTextClient())
client->recordAutocorrectionResponse(response, replacedString, plainText(replacementRange));
@@ -475,7 +477,7 @@
return;
auto precedingCharacterRange = Range::create(*m_frame.document(), precedingCharacterPosition, endOfSelection);
- String string = plainText(precedingCharacterRange.ptr());
+ String string = plainText(precedingCharacterRange);
if (string.isEmpty() || !deprecatedIsEditingWhitespace(string[string.length() - 1]))
return;
@@ -524,7 +526,7 @@
return false;
Node* node = endOfWordPosition.containerNode();
auto wordRange = Range::create(*m_frame.document(), node, marker.startOffset(), node, marker.endOffset());
- String currentWord = plainText(wordRange.ptr());
+ String currentWord = plainText(wordRange);
if (!currentWord.length())
return false;
m_originalText = currentWord;
diff --git a/Source/WebCore/editing/AlternativeTextController.h b/Source/WebCore/editing/AlternativeTextController.h
index 27021ec..981d270 100644
--- a/Source/WebCore/editing/AlternativeTextController.h
+++ b/Source/WebCore/editing/AlternativeTextController.h
@@ -45,6 +45,7 @@
class VisibleSelection;
struct DictationAlternative;
+struct SimpleRange;
struct TextCheckingResult;
#if USE(AUTOCORRECTION_PANEL)
@@ -88,7 +89,7 @@
bool isAutomaticSpellingCorrectionEnabled() UNLESS_ENABLED({ return false; })
bool shouldRemoveMarkersUponEditing();
- void recordAutocorrectionResponse(AutocorrectionResponse, const String& replacedString, Range* replacementRange) UNLESS_ENABLED({ UNUSED_PARAM(replacedString); UNUSED_PARAM(replacementRange); })
+ void recordAutocorrectionResponse(AutocorrectionResponse, const String& replacedString, const SimpleRange& replacementRange) UNLESS_ENABLED({ UNUSED_PARAM(replacedString); UNUSED_PARAM(replacementRange); })
void markReversed(Range& changedRange) UNLESS_ENABLED({ UNUSED_PARAM(changedRange); })
void markCorrection(Range& replacedRange, const String& replacedString) UNLESS_ENABLED({ UNUSED_PARAM(replacedRange); UNUSED_PARAM(replacedString); })
diff --git a/Source/WebCore/editing/Editor.cpp b/Source/WebCore/editing/Editor.cpp
index 093b12b..a4e0602 100644
--- a/Source/WebCore/editing/Editor.cpp
+++ b/Source/WebCore/editing/Editor.cpp
@@ -2592,8 +2592,7 @@
return;
// Get the misspelled word.
- const String misspelledWord = plainText(misspellingRange.get());
- String autocorrectedString = textChecker()->getAutoCorrectSuggestionForMisspelledWord(misspelledWord);
+ String autocorrectedString = textChecker()->getAutoCorrectSuggestionForMisspelledWord(plainText(*misspellingRange));
// If autocorrected word is non empty, replace the misspelled word by this word.
if (!autocorrectedString.isEmpty()) {
@@ -2773,21 +2772,19 @@
SpellingCorrectionCommand::create(rangeToReplace, replacement)->apply();
}
-static void correctSpellcheckingPreservingTextCheckingParagraph(TextCheckingParagraph& paragraph, Range& rangeToReplace, const String& replacement, CharacterRange resultRange)
+static void correctSpellcheckingPreservingTextCheckingParagraph(TextCheckingParagraph& paragraph, Range& rangeToReplace, const String& replacement, CharacterRange resultCharacterRange)
{
- auto& scope = downcast<ContainerNode>(paragraph.paragraphRange().startContainer().rootNode());
-
- size_t paragraphLocation;
- size_t paragraphLength;
- TextIterator::getLocationAndLengthFromRange(&scope, ¶graph.paragraphRange(), paragraphLocation, paragraphLength);
+ auto scopeNode = makeRef(downcast<ContainerNode>(paragraph.paragraphRange().startContainer().rootNode()));
+ auto paragraphCharacterRange = characterRange(makeBoundaryPointBeforeNodeContents(scopeNode), paragraph.paragraphRange());
SpellingCorrectionCommand::create(rangeToReplace, replacement)->apply();
// TextCheckingParagraph may be orphaned after SpellingCorrectionCommand mutated DOM.
// See <rdar://10305315>, http://webkit.org/b/89526.
- auto newParagraphRange = resolveCharacterRange(makeRangeSelectingNodeContents(scope), { paragraphLocation, paragraphLength + replacement.length() - resultRange.length });
- auto spellCheckingRange = resolveCharacterRange(newParagraphRange, { resultRange.location, replacement.length() });
+ paragraphCharacterRange.length += replacement.length() - resultCharacterRange.length;
+ auto newParagraphRange = resolveCharacterRange(makeRangeSelectingNodeContents(scopeNode), paragraphCharacterRange);
+ auto spellCheckingRange = resolveCharacterRange(newParagraphRange, { resultCharacterRange.location, replacement.length() });
paragraph = TextCheckingParagraph(createLiveRange(spellCheckingRange), createLiveRange(spellCheckingRange), createLiveRange(newParagraphRange));
}
@@ -2885,7 +2882,7 @@
if (!(shouldPerformReplacement || shouldCheckForCorrection || shouldMarkLink) || !doReplacement)
continue;
- String replacedString = plainText(rangeToReplace.ptr());
+ String replacedString = plainText(rangeToReplace);
const bool existingMarkersPermitReplacement = m_alternativeTextController->processMarkersOnTextToBeReplacedByResult(results[i], rangeToReplace, replacedString);
if (!existingMarkersPermitReplacement)
continue;
@@ -2931,7 +2928,7 @@
if (resultType == TextCheckingType::Correction) {
auto replacementRange = paragraph.subrange({ resultLocation, replacement.length() });
- m_alternativeTextController->recordAutocorrectionResponse(AutocorrectionResponse::Accepted, replacedString, replacementRange.ptr());
+ m_alternativeTextController->recordAutocorrectionResponse(AutocorrectionResponse::Accepted, replacedString, replacementRange.get());
// Add a marker so that corrections can easily be undone and won't be re-corrected.
m_alternativeTextController->markCorrection(replacementRange, replacedString);
@@ -2966,10 +2963,10 @@
return;
RefPtr<Range> selection = selectedRange();
- if (!shouldInsertText(replacedString, selection.get(), EditorInsertAction::Pasted))
+ if (!selection || !shouldInsertText(replacedString, selection.get(), EditorInsertAction::Pasted))
return;
- m_alternativeTextController->recordAutocorrectionResponse(AutocorrectionResponse::Reverted, replacedString, selection.get());
+ m_alternativeTextController->recordAutocorrectionResponse(AutocorrectionResponse::Reverted, replacedString, *selection);
TextCheckingParagraph paragraph(*selection);
replaceSelectionWithText(replacedString, SelectReplacement::No, SmartReplace::No, EditAction::Insert);
auto changedRange = paragraph.subrange(CharacterRange(paragraph.checkingStart(), replacedString.length()));
@@ -3201,7 +3198,7 @@
VisibleSelection newSelection(*range, DOWNSTREAM);
// Transpose the two characters.
- String text = plainText(range.get());
+ String text = plainText(*range);
if (text.length() != 2)
return;
String transposed = text.right(1) + text.left(1);
@@ -3221,7 +3218,7 @@
void Editor::addRangeToKillRing(const Range& range, KillRingInsertionMode mode)
{
- addTextToKillRing(plainText(&range), mode);
+ addTextToKillRing(plainText(range), mode);
}
void Editor::addTextToKillRing(const String& text, KillRingInsertionMode mode)
@@ -3975,7 +3972,7 @@
const VisibleSelection& selection = m_frame.selection().selection();
RefPtr<Range> rangeForCurrentlyTypedString = candidateRangeForSelection(m_frame);
if (rangeForCurrentlyTypedString && candidateWouldReplaceText(selection))
- return plainText(rangeForCurrentlyTypedString.get());
+ return plainText(*rangeForCurrentlyTypedString);
return String();
}
diff --git a/Source/WebCore/editing/ReplaceRangeWithTextCommand.cpp b/Source/WebCore/editing/ReplaceRangeWithTextCommand.cpp
index ad78232..5460b75 100644
--- a/Source/WebCore/editing/ReplaceRangeWithTextCommand.cpp
+++ b/Source/WebCore/editing/ReplaceRangeWithTextCommand.cpp
@@ -63,8 +63,7 @@
if (!frame().selection().shouldChangeSelection(selection))
return;
- String previousText = plainText(m_rangeToBeReplaced.get());
- if (!previousText.length())
+ if (!characterCount(*m_rangeToBeReplaced))
return;
applyCommandToComposite(SetSelectionCommand::create(selection, FrameSelection::defaultSetSelectionOptions()));
diff --git a/Source/WebCore/editing/ReplaceSelectionCommand.cpp b/Source/WebCore/editing/ReplaceSelectionCommand.cpp
index d866e85..5278db9 100644
--- a/Source/WebCore/editing/ReplaceSelectionCommand.cpp
+++ b/Source/WebCore/editing/ReplaceSelectionCommand.cpp
@@ -191,7 +191,7 @@
}
RefPtr<Range> range = VisibleSelection::selectionFromContentsOfNode(holder.get()).toNormalizedRange();
- String text = plainText(range.get(), static_cast<TextIteratorBehavior>(TextIteratorEmitsOriginalText | TextIteratorIgnoresStyleVisibility));
+ String text = range ? plainText(*range, static_cast<TextIteratorBehavior>(TextIteratorEmitsOriginalText | TextIteratorIgnoresStyleVisibility)) : emptyString();
removeInterchangeNodes(holder.get());
removeUnrenderedNodes(holder.get());
diff --git a/Source/WebCore/editing/SpellingCorrectionCommand.cpp b/Source/WebCore/editing/SpellingCorrectionCommand.cpp
index 5133145..99e8f15 100644
--- a/Source/WebCore/editing/SpellingCorrectionCommand.cpp
+++ b/Source/WebCore/editing/SpellingCorrectionCommand.cpp
@@ -99,7 +99,7 @@
void SpellingCorrectionCommand::doApply()
{
- m_corrected = plainText(m_rangeToBeCorrected.ptr());
+ m_corrected = plainText(m_rangeToBeCorrected);
if (!m_corrected.length())
return;
diff --git a/Source/WebCore/editing/TextCheckingHelper.cpp b/Source/WebCore/editing/TextCheckingHelper.cpp
index 99b8e31..d72e07f 100644
--- a/Source/WebCore/editing/TextCheckingHelper.cpp
+++ b/Source/WebCore/editing/TextCheckingHelper.cpp
@@ -187,7 +187,7 @@
StringView TextCheckingParagraph::text() const
{
if (m_text.isNull())
- m_text = plainText(¶graphRange());
+ m_text = plainText(paragraphRange());
return m_text;
}
@@ -337,7 +337,7 @@
lastIteration = true;
}
if (currentStartOffset < currentEndOffset) {
- String paragraphString = plainText(paragraphRange.ptr());
+ String paragraphString = plainText(paragraphRange);
if (paragraphString.length() > 0) {
bool foundGrammar = false;
uint64_t spellingLocation = 0;
diff --git a/Source/WebCore/editing/TextIterator.cpp b/Source/WebCore/editing/TextIterator.cpp
index 21864c8..172e2644 100644
--- a/Source/WebCore/editing/TextIterator.cpp
+++ b/Source/WebCore/editing/TextIterator.cpp
@@ -46,7 +46,6 @@
#include "HTMLTextFormControlElement.h"
#include "InlineTextBox.h"
#include "NodeTraversal.h"
-#include "Range.h"
#include "RenderImage.h"
#include "RenderIterator.h"
#include "RenderTableCell.h"
@@ -141,8 +140,8 @@
// --------
-static constexpr unsigned bitsInWord = sizeof(unsigned) * 8;
-static constexpr unsigned bitInWordMask = bitsInWord - 1;
+constexpr unsigned bitsInWord = sizeof(unsigned) * 8;
+constexpr unsigned bitInWordMask = bitsInWord - 1;
void BitStack::push(bool bit)
{
@@ -1435,24 +1434,6 @@
m_runOffset = 0;
}
-static Ref<Range> characterSubrange(Document& document, CharacterIterator& it, int offset, int length)
-{
- it.advance(offset);
- if (it.atEnd())
- return Range::create(document);
-
- auto start = it.range().start;
-
- if (length > 1)
- it.advance(length - 1);
- if (it.atEnd())
- return Range::create(document);
-
- auto end = it.range().end;
-
- return createLiveRange(SimpleRange { start, end });
-}
-
BackwardsCharacterIterator::BackwardsCharacterIterator(const SimpleRange& range)
: m_underlyingIterator(range)
{
@@ -1623,7 +1604,7 @@
#if !UCONFIG_NO_COLLATION
-const size_t minimumSearchBufferSize = 8192;
+constexpr size_t minimumSearchBufferSize = 8192;
#ifndef NDEBUG
static bool searcherInUse;
@@ -1876,7 +1857,7 @@
static inline bool isSeparator(UChar32 character)
{
- static const bool latin1SeparatorTable[256] = {
+ static constexpr bool latin1SeparatorTable[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // space ! " # $ % & ' ( ) * + , - . /
@@ -2276,7 +2257,7 @@
append(characters[0], true);
return 1;
}
- const int maxFoldedCharacters = 16; // sensible maximum is 3, this should be more than enough
+ constexpr int maxFoldedCharacters = 16; // sensible maximum is 3, this should be more than enough
UChar foldedCharacters[maxFoldedCharacters];
UErrorCode status = U_ZERO_ERROR;
int numFoldedCharacters = u_strFoldCase(foldedCharacters, maxFoldedCharacters, characters, 1, U_FOLD_CASE_DEFAULT, &status);
@@ -2415,31 +2396,6 @@
return resultRange;
}
-BoundaryPoint resolveCharacterLocation(const SimpleRange& scope, uint64_t location, TextIteratorBehavior behavior)
-{
- return resolveCharacterRange(scope, { location, 0 }, behavior).start;
-}
-
-bool TextIterator::getLocationAndLengthFromRange(Node* scope, const Range* range, size_t& location, size_t& length)
-{
- location = notFound;
- length = 0;
-
- // The critical assumption is that this only gets called with ranges that
- // concentrate on a given area containing the selection root. This is done
- // because of text fields and textareas. The DOM for those is not directly
- // in the document DOM, so ensure that the range does not cross a boundary
- // of one of those.
- if (&range->startContainer() != scope && !range->startContainer().isDescendantOf(scope))
- return false;
- if (&range->endContainer() != scope && !range->endContainer().isDescendantOf(scope))
- return false;
-
- location = characterCount({ { *scope, 0 }, { range->startContainer(), range->startOffset() } });
- length = characterCount({ { *scope, 0 }, { range->endContainer(), range->endOffset() } }) - location;
- return true;
-}
-
// --------
bool hasAnyPlainText(const SimpleRange& range, TextIteratorBehavior behavior)
@@ -2454,7 +2410,7 @@
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;
+ constexpr unsigned initialCapacity = 1 << 15;
auto document = makeRef(range.start.document());
@@ -2481,32 +2437,11 @@
return result;
}
-String plainText(const Range* range, TextIteratorBehavior defaultBehavior, bool isDisplayString)
-{
- if (!range)
- return emptyString();
- return plainText(*range, defaultBehavior, isDisplayString);
-}
-
-String plainTextUsingBackwardsTextIteratorForTesting(const SimpleRange& range)
-{
- String result;
- for (SimplifiedBackwardsTextIterator backwardsIterator(createLiveRange(range)); !backwardsIterator.atEnd(); backwardsIterator.advance())
- result.insert(backwardsIterator.text().toString(), 0);
- return result;
-}
-
String plainTextReplacingNoBreakSpace(const SimpleRange& range, TextIteratorBehavior defaultBehavior, bool isDisplayString)
{
return plainText(range, defaultBehavior, isDisplayString).replace(noBreakSpace, ' ');
}
-static SimpleRange collapsedToBoundary(const SimpleRange& range, bool forward)
-{
- auto& boundary = forward ? range.end : range.start;
- return { boundary, boundary };
-}
-
static TextIteratorBehavior findIteratorOptions(FindOptions options)
{
TextIteratorBehavior iteratorOptions = TextIteratorEntersTextControls | TextIteratorClipsToFrameAncestors;
@@ -2515,20 +2450,19 @@
return iteratorOptions;
}
-static void findPlainTextMatches(const SimpleRange& range, const String& target, FindOptions options, const WTF::Function<bool(size_t, size_t)>& match)
+static void forEachMatch(const SimpleRange& range, const String& target, FindOptions options, const Function<bool(CharacterRange)>& match)
{
SearchBuffer buffer(target, options);
if (buffer.needsMoreContext()) {
- Ref<Range> beforeStartRange = range.start.document().createRange();
- beforeStartRange->setEnd(range.start.container.copyRef(), range.start.offset);
- for (SimplifiedBackwardsTextIterator backwardsIterator(beforeStartRange.get()); !backwardsIterator.atEnd(); backwardsIterator.advance()) {
+ auto beforeStartRange = SimpleRange { makeBoundaryPointBeforeNodeContents(range.start.document()), range.start };
+ for (SimplifiedBackwardsTextIterator backwardsIterator(beforeStartRange); !backwardsIterator.atEnd(); backwardsIterator.advance()) {
buffer.prependContext(backwardsIterator.text());
if (!buffer.needsMoreContext())
break;
}
}
- CharacterIterator findIterator(createLiveRange(range), findIteratorOptions(options));
+ CharacterIterator findIterator(range, findIteratorOptions(options));
while (!findIterator.atEnd()) {
findIterator.advance(buffer.append(findIterator.text()));
while (1) {
@@ -2543,53 +2477,69 @@
}
size_t lastCharacterInBufferOffset = findIterator.characterOffset();
ASSERT(lastCharacterInBufferOffset >= matchStartOffset);
- if (match(lastCharacterInBufferOffset - matchStartOffset, newMatchLength))
+ if (match(CharacterRange(lastCharacterInBufferOffset - matchStartOffset, newMatchLength)))
return;
}
}
}
-static SimpleRange rangeForMatch(const SimpleRange& range, FindOptions options, size_t matchStart, size_t matchLength, bool searchForward)
+static SimpleRange rangeForMatch(const SimpleRange& range, FindOptions options, CharacterRange match)
{
- if (!matchLength)
- return collapsedToBoundary(range, searchForward);
- CharacterIterator rangeComputeIterator(createLiveRange(range), findIteratorOptions(options));
- return characterSubrange(range.start.document(), rangeComputeIterator, matchStart, matchLength);
-}
-
-SimpleRange findClosestPlainText(const SimpleRange& range, const String& target, FindOptions options, unsigned targetOffset)
-{
- size_t matchStart = 0;
- size_t matchLength = 0;
- size_t distance = std::numeric_limits<size_t>::max();
- auto match = [targetOffset, &distance, &matchStart, &matchLength] (size_t start, size_t length) {
- size_t newDistance = std::min(abs(static_cast<signed>(start - targetOffset)), abs(static_cast<signed>(start + length - targetOffset)));
- if (newDistance < distance) {
- matchStart = start;
- matchLength = length;
- distance = newDistance;
- }
- return false;
+ auto noMatchResult = [&] () {
+ auto& boundary = options.contains(Backwards) ? range.start : range.end;
+ return SimpleRange { boundary, boundary };
};
- findPlainTextMatches(range, target, options, WTFMove(match));
- return rangeForMatch(range, options, matchStart, matchLength, !options.contains(Backwards));
+ if (!match.length)
+ return noMatchResult();
+
+ CharacterIterator it(range, findIteratorOptions(options));
+
+ it.advance(match.location);
+ if (it.atEnd())
+ return noMatchResult();
+ auto start = it.range().start;
+
+ it.advance(match.length - 1);
+ if (it.atEnd())
+ return noMatchResult();
+
+ return { WTFMove(start), it.range().end };
+}
+
+SimpleRange findClosestPlainText(const SimpleRange& range, const String& target, FindOptions options, uint64_t targetOffset)
+{
+ CharacterRange closestMatch;
+ uint64_t closestMatchDistance = std::numeric_limits<uint64_t>::max();
+ forEachMatch(range, target, options, [&] (CharacterRange match) {
+ auto distance = [] (uint64_t a, uint64_t b) -> uint64_t {
+ return std::abs(static_cast<int64_t>(a - b));
+ };
+ auto matchDistance = std::min(distance(match.location, targetOffset), distance(match.location + match.length, targetOffset));
+ if (matchDistance > closestMatchDistance)
+ return false;
+ if (matchDistance == closestMatchDistance && !options.contains(Backwards))
+ return false;
+ closestMatch = match;
+ if (!matchDistance && !options.contains(Backwards))
+ return true;
+ closestMatchDistance = matchDistance;
+ return false;
+ });
+ return rangeForMatch(range, options, closestMatch);
}
SimpleRange findPlainText(const SimpleRange& range, const String& target, FindOptions options)
{
- bool searchForward = !options.contains(Backwards);
- size_t matchStart = 0;
- size_t matchLength = 0;
- auto match = [searchForward, &matchStart, &matchLength] (size_t start, size_t length) {
- matchStart = start;
- matchLength = length;
- // Look for the last match when searching backwards instead.
- return searchForward;
- };
-
- findPlainTextMatches(range, target, options, WTFMove(match));
- return rangeForMatch(range, options, matchStart, matchLength, searchForward);
+ // When searching forward stop since we want the first match.
+ // When searching backward keep going since we want the last match.
+ bool stopAfterFindingMatch = !options.contains(Backwards);
+ CharacterRange lastMatchFound;
+ forEachMatch(range, target, options, [&] (CharacterRange match) {
+ lastMatchFound = match;
+ return stopAfterFindingMatch;
+ });
+ return rangeForMatch(range, options, lastMatchFound);
}
bool containsPlainText(const String& document, const String& target, FindOptions options)
diff --git a/Source/WebCore/editing/TextIterator.h b/Source/WebCore/editing/TextIterator.h
index e160287..9dea733 100644
--- a/Source/WebCore/editing/TextIterator.h
+++ b/Source/WebCore/editing/TextIterator.h
@@ -34,23 +34,27 @@
namespace WebCore {
-class Range;
class RenderTextFragment;
-// FIXME: Delete this overload after moving all the callers to the SimpleRange version.
-WEBCORE_EXPORT String plainText(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
+// Character ranges based on characters from the text iterator.
+WEBCORE_EXPORT uint64_t characterCount(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
+CharacterRange characterRange(const BoundaryPoint& start, const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
+CharacterRange characterRange(const SimpleRange& scope, const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
+BoundaryPoint resolveCharacterLocation(const SimpleRange& scope, uint64_t, TextIteratorBehavior = TextIteratorDefaultBehavior);
+WEBCORE_EXPORT SimpleRange resolveCharacterRange(const SimpleRange& scope, CharacterRange, TextIteratorBehavior = TextIteratorDefaultBehavior);
+// Text from the text iterator.
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);
-WEBCORE_EXPORT SimpleRange findClosestPlainText(const SimpleRange&, const String&, FindOptions, unsigned);
WEBCORE_EXPORT bool hasAnyPlainText(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
+WEBCORE_EXPORT String plainTextReplacingNoBreakSpace(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
+
+// Find within the document, based on the text from the text iterator.
+SimpleRange findPlainText(const SimpleRange&, const String&, FindOptions);
+WEBCORE_EXPORT SimpleRange findClosestPlainText(const SimpleRange&, const String&, FindOptions, uint64_t targetCharacterOffset);
bool containsPlainText(const String& document, const String&, FindOptions); // Lets us use the search algorithm on a string.
WEBCORE_EXPORT String foldQuoteMarks(const String&);
-// FIXME: Move this somewhere else in the editing directory. It doesn't belong here.
+// FIXME: Move this somewhere else in the editing directory. It doesn't belong in the header with TextIterator.
bool isRendererReplacedElement(RenderObject*);
// FIXME: Move each iterator class into a separate header file.
@@ -103,9 +107,6 @@
const TextIteratorCopyableText& copyableText() const { ASSERT(!atEnd()); return m_copyableText; }
void appendTextToStringBuilder(StringBuilder& builder) const { copyableText().appendToStringBuilder(builder); }
- // FIXME: Move this to SimpleRange and CharacterRange and move out of this class to the top level.
- WEBCORE_EXPORT static bool getLocationAndLengthFromRange(Node* scope, const Range*, size_t& location, size_t& length);
-
private:
void init();
void exitNode(Node*);
@@ -173,10 +174,10 @@
// chunks so as to optimize for performance of the iteration.
class SimplifiedBackwardsTextIterator {
public:
- explicit SimplifiedBackwardsTextIterator(const SimpleRange&);
+ WEBCORE_EXPORT explicit SimplifiedBackwardsTextIterator(const SimpleRange&);
bool atEnd() const { return !m_positionNode; }
- void advance();
+ WEBCORE_EXPORT void advance();
StringView text() const { ASSERT(!atEnd()); return m_text; }
WEBCORE_EXPORT SimpleRange range() const;
@@ -288,9 +289,19 @@
bool m_didLookAhead { true };
};
+inline CharacterRange characterRange(const BoundaryPoint& start, const SimpleRange& range, TextIteratorBehavior behavior)
+{
+ return { characterCount({ start, range.start }, behavior), characterCount(range, behavior) };
+}
-WEBCORE_EXPORT uint64_t characterCount(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
-WEBCORE_EXPORT BoundaryPoint resolveCharacterLocation(const SimpleRange&, uint64_t, TextIteratorBehavior = TextIteratorDefaultBehavior);
-WEBCORE_EXPORT SimpleRange resolveCharacterRange(const SimpleRange&, CharacterRange, TextIteratorBehavior = TextIteratorDefaultBehavior);
+inline CharacterRange characterRange(const SimpleRange& scope, const SimpleRange& range, TextIteratorBehavior behavior)
+{
+ return characterRange(scope.start, range, behavior);
+}
+
+inline BoundaryPoint resolveCharacterLocation(const SimpleRange& scope, uint64_t location, TextIteratorBehavior behavior)
+{
+ return resolveCharacterRange(scope, { location, 0 }, behavior).start;
+}
} // namespace WebCore
diff --git a/Source/WebCore/editing/TypingCommand.cpp b/Source/WebCore/editing/TypingCommand.cpp
index c4d80fb..5a6c53c 100644
--- a/Source/WebCore/editing/TypingCommand.cpp
+++ b/Source/WebCore/editing/TypingCommand.cpp
@@ -465,7 +465,7 @@
RefPtr<Range> range = makeRange(p1, p2);
String strippedPreviousWord;
if (range && (commandType == TypingCommand::InsertText || commandType == TypingCommand::InsertLineBreak || commandType == TypingCommand::InsertParagraphSeparator || commandType == TypingCommand::InsertParagraphSeparatorInQuotedContent))
- strippedPreviousWord = plainText(range.get()).stripWhiteSpace();
+ strippedPreviousWord = plainText(*range).stripWhiteSpace();
frame.editor().markMisspellingsAfterTypingToWord(p1, endingSelection(), !strippedPreviousWord.isEmpty());
} else if (commandType == TypingCommand::InsertText)
frame.editor().startAlternativeTextUITimer();
diff --git a/Source/WebCore/editing/VisibleUnits.cpp b/Source/WebCore/editing/VisibleUnits.cpp
index d6f7178..3253b6f 100644
--- a/Source/WebCore/editing/VisibleUnits.cpp
+++ b/Source/WebCore/editing/VisibleUnits.cpp
@@ -1934,7 +1934,7 @@
}
if (startPosition != endPosition) {
- String characterString = plainText(Range::create(position.deepEquivalent().anchorNode()->document(), startPosition, endPosition).ptr()).replace(noBreakSpace, ' ');
+ String characterString = plainText({ *makeBoundaryPoint(startPosition), *makeBoundaryPoint(endPosition) }).replace(noBreakSpace, ' ');
for (int i = characterString.length() - 1, index = 0; i >= 0 && index < maxCharacters; --i) {
if (!index && nextPosition.isNull())
index++;
diff --git a/Source/WebCore/editing/cocoa/DataDetection.mm b/Source/WebCore/editing/cocoa/DataDetection.mm
index 99e6159..557bfec 100644
--- a/Source/WebCore/editing/cocoa/DataDetection.mm
+++ b/Source/WebCore/editing/cocoa/DataDetection.mm
@@ -70,10 +70,10 @@
static RetainPtr<DDActionContext> detectItemAtPositionWithRange(VisiblePosition position, RefPtr<Range> contextRange, FloatRect& detectedDataBoundingBox, RefPtr<Range>& detectedDataRange)
{
- String fullPlainTextString = plainText(contextRange.get());
auto start = contextRange->startPosition();
if (start.isNull() || position.isNull())
return nil;
+ String fullPlainTextString = plainText(*contextRange);
CFIndex hitLocation = characterCount({ *makeBoundaryPoint(start), *makeBoundaryPoint(position) });
auto scanner = adoptCF(DDScannerCreate(DDScannerTypeStandard, 0, nullptr));
diff --git a/Source/WebCore/editing/cocoa/DictionaryLookup.mm b/Source/WebCore/editing/cocoa/DictionaryLookup.mm
index 47ad47a..a23dc40 100644
--- a/Source/WebCore/editing/cocoa/DictionaryLookup.mm
+++ b/Source/WebCore/editing/cocoa/DictionaryLookup.mm
@@ -286,7 +286,7 @@
NSRange rangeToPass = NSMakeRange(lengthToSelectionStart, selectionCharacterCount);
RefPtr<Range> fullCharacterRange = makeRange(paragraphStart, paragraphEnd);
- String itemString = plainText(fullCharacterRange.get());
+ String itemString = plainText(*fullCharacterRange);
NSRange highlightRange = adoptNS([allocRVItemInstance() initWithText:itemString selectedRange:rangeToPass]).get().highlightRange;
return { createLiveRange(resolveCharacterRange(*fullCharacterRange, highlightRange)), nil };
diff --git a/Source/WebCore/editing/cocoa/HTMLConverter.h b/Source/WebCore/editing/cocoa/HTMLConverter.h
index aab49c4..097078d 100644
--- a/Source/WebCore/editing/cocoa/HTMLConverter.h
+++ b/Source/WebCore/editing/cocoa/HTMLConverter.h
@@ -36,12 +36,10 @@
enum class IncludeImagesInAttributedString { Yes, No };
NSAttributedString *attributedStringFromSelection(const VisibleSelection&, NSDictionary** documentAttributes = nullptr);
-
-// For testing purpose only
WEBCORE_EXPORT NSAttributedString *attributedStringBetweenStartAndEnd(const Position&, const Position&, NSDictionary** documentAttributes = nullptr);
-
WEBCORE_EXPORT NSAttributedString *attributedStringFromRange(Range&, NSDictionary** documentAttributes = nullptr);
-#if !PLATFORM(IOS_FAMILY)
+
+#if PLATFORM(MAC)
WEBCORE_EXPORT NSAttributedString *editingAttributedStringFromRange(Range&, IncludeImagesInAttributedString = IncludeImagesInAttributedString::Yes);
#endif
diff --git a/Source/WebCore/editing/mac/DictionaryLookupLegacy.mm b/Source/WebCore/editing/mac/DictionaryLookupLegacy.mm
index c0e3f55..aecbcd1 100644
--- a/Source/WebCore/editing/mac/DictionaryLookupLegacy.mm
+++ b/Source/WebCore/editing/mac/DictionaryLookupLegacy.mm
@@ -87,17 +87,16 @@
auto selectionEnd = selection.visibleEnd();
// As context, we are going to use the surrounding paragraphs of text.
- auto paragraphStart = startOfParagraph(selectionStart);
- auto paragraphEnd = endOfParagraph(selectionEnd);
- if (paragraphStart.isNull() || paragraphEnd.isNull())
+ auto paragraphStart = makeBoundaryPoint(startOfParagraph(selectionStart));
+ auto paragraphEnd = makeBoundaryPoint(endOfParagraph(selectionEnd));
+ if (!paragraphStart || !paragraphEnd)
return { nullptr, nil };
- auto lengthToSelectionStart = characterCount({ *makeBoundaryPoint(paragraphStart), *makeBoundaryPoint(selectionStart) });
- auto selectionCharacterCount = characterCount({ *makeBoundaryPoint(selectionStart), *makeBoundaryPoint(selectionEnd) });
- NSRange rangeToPass = NSMakeRange(lengthToSelectionStart, selectionCharacterCount);
+ auto selectionRange = SimpleRange { *makeBoundaryPoint(selectionStart), *makeBoundaryPoint(selectionEnd) };
+ auto paragraphRange = SimpleRange { *paragraphStart, *paragraphEnd };
NSDictionary *options = nil;
- tokenRange(plainText(makeRange(paragraphStart, paragraphEnd).get()), rangeToPass, &options);
+ tokenRange(plainText(paragraphRange), characterRange(paragraphRange, selectionRange), &options);
return { selectedRange, options };
}
@@ -142,7 +141,7 @@
NSRange rangeToPass = NSMakeRange(characterCount({ *fullCharacterStart, *positionBoundary }), 0);
NSDictionary *options = nil;
- auto extractedRange = tokenRange(plainText(fullCharacterRange.get()), rangeToPass, &options);
+ auto extractedRange = tokenRange(plainText(*fullCharacterRange), rangeToPass, &options);
// tokenRange sometimes returns {NSNotFound, 0} if it was unable to determine a good string.
// FIXME (159063): We shouldn't need to check for zero length here.
diff --git a/Source/WebCore/editing/markup.cpp b/Source/WebCore/editing/markup.cpp
index 42f9bca..cbf6288 100644
--- a/Source/WebCore/editing/markup.cpp
+++ b/Source/WebCore/editing/markup.cpp
@@ -435,7 +435,12 @@
behavior = TextIteratorBehavesAsIfNodesFollowing;
}
- return plainText(Range::create(text.document(), start, end).ptr(), behavior);
+ auto startBoundary = makeBoundaryPoint(start);
+ auto endBoundary = makeBoundaryPoint(end);
+ if (!startBoundary || !endBoundary)
+ return emptyString();
+
+ return plainText({ WTFMove(*startBoundary), WTFMove(*endBoundary) }, behavior);
}
String StyledMarkupAccumulator::textContentRespectingRange(const Text& text)
diff --git a/Source/WebCore/html/HTMLTextAreaElement.cpp b/Source/WebCore/html/HTMLTextAreaElement.cpp
index 681ca78..5c297ca 100644
--- a/Source/WebCore/html/HTMLTextAreaElement.cpp
+++ b/Source/WebCore/html/HTMLTextAreaElement.cpp
@@ -318,7 +318,8 @@
// If the text field has no focus, we don't need to take account of the
// selection length. The selection is the source of text drag-and-drop in
// that case, and nothing in the text field will be removed.
- unsigned selectionLength = focused() ? computeLengthForSubmission(plainText(document().frame()->selection().selection().toNormalizedRange().get())) : 0;
+ auto selectionRange = focused() ? document().frame()->selection().selection().toNormalizedRange() : nullptr;
+ unsigned selectionLength = selectionRange ? computeLengthForSubmission(plainText(*selectionRange)) : 0;
ASSERT(currentLength >= selectionLength);
unsigned baseLength = currentLength - selectionLength;
unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLength - baseLength : 0;
diff --git a/Source/WebCore/page/ContextMenuController.cpp b/Source/WebCore/page/ContextMenuController.cpp
index 72b1306..2c32b2f 100644
--- a/Source/WebCore/page/ContextMenuController.cpp
+++ b/Source/WebCore/page/ContextMenuController.cpp
@@ -431,7 +431,7 @@
if (auto* element = document.documentElement())
selectedRange->selectNode(*element);
}
- m_client.speak(plainText(selectedRange.get()));
+ m_client.speak(plainText(*selectedRange));
break;
}
case ContextMenuItemTagStopSpeaking:
diff --git a/Source/WebCore/page/DOMSelection.cpp b/Source/WebCore/page/DOMSelection.cpp
index 475e64b..dd7f8e8 100644
--- a/Source/WebCore/page/DOMSelection.cpp
+++ b/Source/WebCore/page/DOMSelection.cpp
@@ -448,7 +448,8 @@
auto* frame = this->frame();
if (!frame)
return String();
- return plainText(frame->selection().selection().toNormalizedRange().get());
+ auto range = frame->selection().selection().toNormalizedRange();
+ return range ? plainText(*range) : emptyString();
}
Node* DOMSelection::shadowAdjustedNode(const Position& position) const
diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp
index 90e75d5..b3712e4 100644
--- a/Source/WebCore/page/Page.cpp
+++ b/Source/WebCore/page/Page.cpp
@@ -884,22 +884,10 @@
for (auto& range : rangesToReplace) {
auto highestRoot = makeRefPtr(highestEditableRoot(range->startPosition()));
- if (!highestRoot || highestRoot != highestEditableRoot(range->endPosition()))
+ if (!highestRoot || highestRoot != highestEditableRoot(range->endPosition()) || !highestRoot->document().frame())
continue;
-
- auto frame = makeRefPtr(highestRoot->document().frame());
- if (!frame)
- continue;
-
- size_t replacementLocation = notFound;
- size_t replacementLength = 0;
- if (!TextIterator::getLocationAndLengthFromRange(highestRoot.get(), range.ptr(), replacementLocation, replacementLength))
- continue;
-
- if (replacementLocation == notFound || !replacementLength)
- continue;
-
- replacementRanges.append({ WTFMove(highestRoot), { replacementLocation, replacementLength } });
+ auto scope = makeRangeSelectingNodeContents(*highestRoot);
+ replacementRanges.append({ WTFMove(highestRoot), characterRange(scope, range) });
}
replaceRanges(*this, replacementRanges, replacementText);
diff --git a/Source/WebCore/page/ios/FrameIOS.mm b/Source/WebCore/page/ios/FrameIOS.mm
index 6ee4fb4..06285a5 100644
--- a/Source/WebCore/page/ios/FrameIOS.mm
+++ b/Source/WebCore/page/ios/FrameIOS.mm
@@ -730,7 +730,7 @@
// There are no phrases with alternatives, so there is just one interpretation.
if (markersInRoot.isEmpty())
- return [NSArray arrayWithObject:plainText(rangeOfRootContents.ptr())];
+ return [NSArray arrayWithObject:plainText(rangeOfRootContents)];
// The number of interpretations will be i1 * i2 * ... * iN, where iX is the number of interpretations for the Xth phrase with alternatives.
size_t interpretationsCount = 1;
@@ -752,7 +752,7 @@
// First, add text that precede the marker.
if (precedingTextStartPosition != createLegacyEditingPosition(node, marker->startOffset())) {
auto precedingTextRange = Range::create(*document(), precedingTextStartPosition, createLegacyEditingPosition(node, marker->startOffset()));
- String precedingText = plainText(precedingTextRange.ptr());
+ String precedingText = plainText(precedingTextRange);
if (!precedingText.isEmpty()) {
for (auto& interpretation : interpretations)
append(interpretation, precedingText);
diff --git a/Source/WebCore/testing/Internals.cpp b/Source/WebCore/testing/Internals.cpp
index b2af0bc..034bc32 100644
--- a/Source/WebCore/testing/Internals.cpp
+++ b/Source/WebCore/testing/Internals.cpp
@@ -2051,18 +2051,12 @@
unsigned Internals::locationFromRange(Element& scope, const Range& range)
{
- size_t location = 0;
- size_t unusedLength = 0;
- TextIterator::getLocationAndLengthFromRange(&scope, &range, location, unusedLength);
- return location;
+ return clampTo<unsigned>(characterRange(makeBoundaryPointBeforeNodeContents(scope), range).location);
}
unsigned Internals::lengthFromRange(Element& scope, const Range& range)
{
- size_t unusedLocation = 0;
- size_t length = 0;
- TextIterator::getLocationAndLengthFromRange(&scope, &range, unusedLocation, length);
- return length;
+ return clampTo<unsigned>(characterRange(makeBoundaryPointBeforeNodeContents(scope), range).length);
}
String Internals::rangeAsText(const Range& range)
@@ -2072,7 +2066,10 @@
String Internals::rangeAsTextUsingBackwardsTextIterator(const Range& range)
{
- return plainTextUsingBackwardsTextIteratorForTesting(range);
+ String result;
+ for (SimplifiedBackwardsTextIterator backwardsIterator(range); !backwardsIterator.atEnd(); backwardsIterator.advance())
+ result.insert(backwardsIterator.text().toString(), 0);
+ return result;
}
Ref<Range> Internals::subrange(Range& range, unsigned rangeLocation, unsigned rangeLength)
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index 550725b..46f1b96 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,57 @@
+2020-04-01 Darin Adler <darin@apple.com>
+
+ Remove all uses of live ranges from TextIterator
+ https://bugs.webkit.org/show_bug.cgi?id=209723
+
+ Reviewed by Antti Koivisto.
+
+ * Shared/EditingRange.cpp:
+ (WebKit::EditingRange::fromRange): Use characterRange.
+
+ * Shared/mac/AttributedString.h: Added a constructor that takes rvalue
+ references so we can initialize this slightly more efficiently.
+
+ * Shared/mac/AttributedString.mm:
+ (IPC::ArgumentCoder<WebKit::AttributedString>::decode): Pass rvalue
+ references when creating an AttributedString.
+
+ * UIProcess/mac/TextCheckerMac.mm:
+ (WebKit::TextChecker::updateSpellingUIWithGrammarString): Simplify the
+ code to remove some local variables that weren't helpful.
+
+ * WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.h: Made the
+ annotatedSubstringBetweenPositions a static member function. Also used
+ const& argument types to cut down on reference count churn a bit.
+
+ * WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.mm:
+ (WebKit::TextCheckingControllerProxy::rangeAndOffsetRelativeToSelection):
+ Streamlined and made this use characterCount instead of
+ TextIterator::getLocationAndLengthFromRange.
+ (WebKit::TextCheckingControllerProxy::replaceRelativeToSelection): Tweaked
+ the argument type.
+ (WebKit::TextCheckingControllerProxy::removeAnnotationRelativeToSelection):
+ Ditto. Also removed some unnecessary use of NSString.
+ (WebKit::TextCheckingControllerProxy::annotatedSubstringBetweenPositions):
+ Rewrote to no longer use live ranges.
+
+ * WebProcess/WebPage/Cocoa/WebPageCocoa.mm:
+ (WebKit::WebPage::getContentsAsAttributedString): Use construction and
+ rvalue references to tigten things up a bit.
+
+ * WebProcess/WebPage/WebFrame.cpp:
+ (WebKit::WebFrame::contentsAsString const): Use a SimpleRange instead of
+ a live range to pass to plainText.
+ * WebProcess/WebPage/glib/WebPageGLib.cpp:
+ (WebKit::WebPage::getPlatformEditorState const): Pass references to
+ live ranges to plainText.
+ * WebProcess/WebPage/ios/WebPageIOS.mm:
+ (WebKit::WebPage::updateSelectionWithDelta): Rewrote to minimize use of
+ live ranges.
+ (WebKit::WebPage::requestDocumentEditingContext): Ditto.
+ * WebProcess/WebPage/mac/WebPageMac.mm:
+ (WebKit::WebPage::getPlatformEditorState const): Pass reference to
+ a live range to plainText.
+
2020-04-02 David Kilzer <ddkilzer@apple.com>
API::PageConfiguration may have conflicting preference values between WebPreferences and WebPreferencesStore::ValueMap instance variables
diff --git a/Source/WebKit/Shared/EditingRange.cpp b/Source/WebKit/Shared/EditingRange.cpp
index 76ef472..86ac553 100644
--- a/Source/WebKit/Shared/EditingRange.cpp
+++ b/Source/WebKit/Shared/EditingRange.cpp
@@ -65,16 +65,15 @@
{
ASSERT(editingRangeIsRelativeTo == EditingRangeIsRelativeTo::EditableRoot);
- size_t location = 0;
- size_t length = 0;
- if (!range || !WebCore::TextIterator::getLocationAndLengthFromRange(frame.selection().rootEditableElementOrDocumentElement(), range, location, length))
+ if (!range)
return { };
- EditingRange editingRange(location, length);
- if (!editingRange.isValid())
+ auto* element = frame.selection().rootEditableElementOrDocumentElement();
+ if (!element)
return { };
- return editingRange;
+ auto relativeRange = characterRange(makeBoundaryPointBeforeNodeContents(*element), *range);
+ return EditingRange(relativeRange.location, relativeRange.length);
}
} // namespace WebKit
diff --git a/Source/WebKit/Shared/mac/AttributedString.h b/Source/WebKit/Shared/mac/AttributedString.h
index 8530f81..02d6b01 100644
--- a/Source/WebKit/Shared/mac/AttributedString.h
+++ b/Source/WebKit/Shared/mac/AttributedString.h
@@ -33,9 +33,10 @@
namespace WebKit {
struct AttributedString {
- AttributedString()
- {
- }
+ RetainPtr<NSAttributedString> string;
+ RetainPtr<NSDictionary> documentAttributes;
+
+ AttributedString() = default;
#if defined(__OBJC__)
AttributedString(NSAttributedString *attributedString, NSDictionary *documentAttributes = nil)
@@ -44,22 +45,26 @@
{
}
+ AttributedString(RetainPtr<NSAttributedString>&& attributedString, RetainPtr<NSDictionary>&& documentAttributes = { })
+ : string(WTFMove(attributedString))
+ , documentAttributes(WTFMove(documentAttributes))
+ {
+ }
+
operator NSAttributedString *() const
{
return string.get();
}
#endif
-
- RetainPtr<NSAttributedString> string;
- RetainPtr<NSDictionary> documentAttributes;
};
}
namespace IPC {
+
template<> struct ArgumentCoder<WebKit::AttributedString> {
static void encode(Encoder&, const WebKit::AttributedString&);
static Optional<WebKit::AttributedString> decode(Decoder&);
};
-}
+}
diff --git a/Source/WebKit/Shared/mac/AttributedString.mm b/Source/WebKit/Shared/mac/AttributedString.mm
index 3c47005..0f2e92d 100644
--- a/Source/WebKit/Shared/mac/AttributedString.mm
+++ b/Source/WebKit/Shared/mac/AttributedString.mm
@@ -45,7 +45,7 @@
RetainPtr<NSDictionary> documentAttributes;
if (!IPC::decode(decoder, documentAttributes))
return WTF::nullopt;
- return WebKit::AttributedString { attributedString.get(), documentAttributes.get() };
+ return { { WTFMove(attributedString), WTFMove(documentAttributes) } };
}
}
diff --git a/Source/WebKit/UIProcess/mac/TextCheckerMac.mm b/Source/WebKit/UIProcess/mac/TextCheckerMac.mm
index 0d19e4b..d786f11 100644
--- a/Source/WebKit/UIProcess/mac/TextCheckerMac.mm
+++ b/Source/WebKit/UIProcess/mac/TextCheckerMac.mm
@@ -436,18 +436,13 @@
void TextChecker::updateSpellingUIWithGrammarString(SpellDocumentTag, const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
{
auto corrections = adoptNS([[NSMutableArray alloc] init]);
- for (auto& guess : grammarDetail.guesses) {
- NSString *guessNSString = guess;
- [corrections addObject:guessNSString];
- }
-
- NSString *descriptionNSString = grammarDetail.userDescription;
+ for (auto& guess : grammarDetail.guesses)
+ [corrections addObject:guess];
NSDictionary *detail = @{
NSGrammarRange : [NSValue valueWithRange:grammarDetail.range],
- NSGrammarUserDescription : descriptionNSString,
+ NSGrammarUserDescription : grammarDetail.userDescription,
NSGrammarCorrections : corrections.get(),
};
-
[[NSSpellChecker sharedSpellChecker] updateSpellingPanelWithGrammarString:badGrammarPhrase detail:detail];
}
diff --git a/Source/WebKit/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.h b/Source/WebKit/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.h
index 07413cf..f48f0b6 100644
--- a/Source/WebKit/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.h
+++ b/Source/WebKit/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.h
@@ -52,7 +52,7 @@
TextCheckingControllerProxy(WebPage&);
~TextCheckingControllerProxy();
- AttributedString annotatedSubstringBetweenPositions(const WebCore::VisiblePosition&, const WebCore::VisiblePosition&);
+ static AttributedString annotatedSubstringBetweenPositions(const WebCore::VisiblePosition&, const WebCore::VisiblePosition&);
private:
// IPC::MessageReceiver
@@ -65,8 +65,8 @@
Optional<RangeAndOffset> rangeAndOffsetRelativeToSelection(int64_t offset, uint64_t length);
// Message handlers.
- void replaceRelativeToSelection(AttributedString, int64_t selectionOffset, uint64_t length, uint64_t relativeReplacementLocation, uint64_t relativeReplacementLength);
- void removeAnnotationRelativeToSelection(String annotationName, int64_t selectionOffset, uint64_t length);
+ void replaceRelativeToSelection(const AttributedString&, int64_t selectionOffset, uint64_t length, uint64_t relativeReplacementLocation, uint64_t relativeReplacementLength);
+ void removeAnnotationRelativeToSelection(const String& annotationName, int64_t selectionOffset, uint64_t length);
WebPage& m_page;
};
diff --git a/Source/WebKit/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.mm b/Source/WebKit/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.mm
index 659d5af..e449bfd 100644
--- a/Source/WebKit/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.mm
+++ b/Source/WebKit/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.mm
@@ -72,28 +72,28 @@
Optional<TextCheckingControllerProxy::RangeAndOffset> TextCheckingControllerProxy::rangeAndOffsetRelativeToSelection(int64_t offset, uint64_t length)
{
- Frame& frame = m_page.corePage()->focusController().focusedOrMainFrame();
- auto& frameSelection = frame.selection();
+ auto& frameSelection = m_page.corePage()->focusController().focusedOrMainFrame().selection();
auto& selection = frameSelection.selection();
- if (selection.isNone())
- return WTF::nullopt;
auto root = frameSelection.rootEditableElementOrDocumentElement();
if (!root)
return WTF::nullopt;
- auto range = selection.toNormalizedRange();
- range->collapse(true);
+ auto selectionLiveRange = selection.toNormalizedRange();
+ if (!selectionLiveRange)
+ return WTF::nullopt;
+ auto selectionRange = SimpleRange { *selectionLiveRange };
- size_t selectionLocation;
- size_t selectionLength;
- TextIterator::getLocationAndLengthFromRange(root, range.get(), selectionLocation, selectionLength);
- selectionLocation += offset;
+ auto scope = makeRangeSelectingNodeContents(*root);
+ int64_t adjustedStartLocation = characterCount({ scope.start, selectionRange.start }) + offset;
+ if (adjustedStartLocation < 0)
+ return WTF::nullopt;
+ auto adjustedSelectionCharacterRange = CharacterRange { static_cast<uint64_t>(adjustedStartLocation), length };
- return { { createLiveRange(resolveCharacterRange(makeRangeSelectingNodeContents(*root), { selectionLocation, length })), selectionLocation } };
+ return { { createLiveRange(resolveCharacterRange(scope, adjustedSelectionCharacterRange)), adjustedSelectionCharacterRange.location } };
}
-void TextCheckingControllerProxy::replaceRelativeToSelection(AttributedString annotatedString, int64_t selectionOffset, uint64_t length, uint64_t relativeReplacementLocation, uint64_t relativeReplacementLength)
+void TextCheckingControllerProxy::replaceRelativeToSelection(const AttributedString& annotatedString, int64_t selectionOffset, uint64_t length, uint64_t relativeReplacementLocation, uint64_t relativeReplacementLength)
{
Frame& frame = m_page.corePage()->focusController().focusedOrMainFrame();
FrameSelection& frameSelection = frame.selection();
@@ -154,7 +154,7 @@
}];
}
-void TextCheckingControllerProxy::removeAnnotationRelativeToSelection(String annotation, int64_t selectionOffset, uint64_t length)
+void TextCheckingControllerProxy::removeAnnotationRelativeToSelection(const String& annotation, int64_t selectionOffset, uint64_t length)
{
Frame& frame = m_page.corePage()->focusController().focusedOrMainFrame();
auto rangeAndOffset = rangeAndOffsetRelativeToSelection(selectionOffset, length);
@@ -164,7 +164,7 @@
if (!range)
return;
- bool removeCoreSpellingMarkers = (annotation == String(@"NSSpellingState"));
+ bool removeCoreSpellingMarkers = annotation == "NSSpellingState";
frame.document()->markers().filterMarkers(*range, [&] (DocumentMarker* marker) {
if (!WTF::holds_alternative<DocumentMarker::PlatformTextCheckingData>(marker->data()))
return false;
@@ -175,51 +175,30 @@
AttributedString TextCheckingControllerProxy::annotatedSubstringBetweenPositions(const WebCore::VisiblePosition& start, const WebCore::VisiblePosition& end)
{
- RetainPtr<NSMutableAttributedString> string = adoptNS([[NSMutableAttributedString alloc] init]);
- NSUInteger stringLength = 0;
-
- RefPtr<Document> document = start.deepEquivalent().document();
- if (!document)
+ auto startBoundary = makeBoundaryPoint(start);
+ auto endBoundary = makeBoundaryPoint(end);
+ if (!startBoundary || !endBoundary)
return { };
+ auto entireRange = SimpleRange { *startBoundary, *endBoundary };
- auto entireRange = makeRange(start, end);
- if (!entireRange)
- return { };
+ auto string = adoptNS([[NSMutableAttributedString alloc] init]);
- RefPtr<Node> commonAncestor = entireRange->commonAncestorContainer();
- size_t entireRangeLocation;
- size_t entireRangeLength;
- TextIterator::getLocationAndLengthFromRange(commonAncestor.get(), entireRange.get(), entireRangeLocation, entireRangeLength);
-
- for (TextIterator it({ *makeBoundaryPoint(start.deepEquivalent()), *makeBoundaryPoint(end.deepEquivalent()) }); !it.atEnd(); it.advance()) {
- int currentTextLength = it.text().length();
- if (!currentTextLength)
+ for (TextIterator it(entireRange); !it.atEnd(); it.advance()) {
+ if (!it.text().length())
continue;
-
- [string appendAttributedString:[[[NSAttributedString alloc] initWithString:it.text().createNSStringWithoutCopying().get()] autorelease]];
-
- SimpleRange currentTextRange = it.range();
- auto markers = document->markers().markersInRange(createLiveRange(currentTextRange), DocumentMarker::PlatformTextChecking);
+ [string appendAttributedString:adoptNS([[NSAttributedString alloc] initWithString:it.text().createNSStringWithoutCopying().get()]).get()];
+ auto range = it.range();
+ auto markers = range.start.document().markers().markersInRange(createLiveRange(range), DocumentMarker::PlatformTextChecking);
for (const auto* marker : markers) {
if (!WTF::holds_alternative<DocumentMarker::PlatformTextCheckingData>(marker->data()))
continue;
-
- auto& textCheckingData = WTF::get<DocumentMarker::PlatformTextCheckingData>(marker->data());
- auto subrange = resolveCharacterRange(currentTextRange, { marker->startOffset(), marker->endOffset() - marker->startOffset() });
-
- size_t subrangeLocation;
- size_t subrangeLength;
- TextIterator::getLocationAndLengthFromRange(commonAncestor.get(), createLiveRange(subrange).ptr(), subrangeLocation, subrangeLength);
-
- ASSERT(subrangeLocation > entireRangeLocation);
- ASSERT(subrangeLocation + subrangeLength < entireRangeLength);
- [string addAttribute:textCheckingData.key value:textCheckingData.value range:NSMakeRange(subrangeLocation - entireRangeLocation, subrangeLength)];
+ auto& data = WTF::get<DocumentMarker::PlatformTextCheckingData>(marker->data());
+ auto subrange = resolveCharacterRange(range, { marker->startOffset(), marker->endOffset() - marker->startOffset() });
+ [string addAttribute:data.key value:data.value range:characterRange(entireRange, subrange)];
}
-
- stringLength += currentTextLength;
}
- return string.autorelease();
+ return { { WTFMove(string) } };
}
} // namespace WebKit
diff --git a/Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm b/Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm
index 0c1720f..33ecd7b 100644
--- a/Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm
+++ b/Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm
@@ -239,12 +239,9 @@
}
NSDictionary* documentAttributes = nil;
+ auto attributedString = attributedStringFromRange(rangeOfContents(*documentElement), &documentAttributes);
- AttributedString result;
- result.string = attributedStringFromRange(rangeOfContents(*documentElement), &documentAttributes);
- result.documentAttributes = documentAttributes;
-
- completionHandler({ result });
+ completionHandler({ WTFMove(attributedString), WTFMove(documentAttributes) });
}
void WebPage::setRemoteObjectRegistry(WebRemoteObjectRegistry* registry)
diff --git a/Source/WebKit/WebProcess/WebPage/WebFrame.cpp b/Source/WebKit/WebProcess/WebPage/WebFrame.cpp
index 4a513b6..468c359 100644
--- a/Source/WebKit/WebProcess/WebPage/WebFrame.cpp
+++ b/Source/WebKit/WebProcess/WebPage/WebFrame.cpp
@@ -362,20 +362,15 @@
return builder.toString();
}
- Document* document = m_coreFrame->document();
+ auto document = m_coreFrame->document();
if (!document)
return String();
- RefPtr<Element> documentElement = document->documentElement();
+ auto documentElement = document->documentElement();
if (!documentElement)
return String();
- RefPtr<Range> range = document->createRange();
-
- if (range->selectNode(*documentElement).hasException())
- return String();
-
- return plainText(range.get());
+ return plainText(makeRangeSelectingNodeContents(*documentElement));
}
String WebFrame::selectionAsString() const
diff --git a/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp b/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp
index 4e86f05..16b538c 100644
--- a/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp
+++ b/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp
@@ -113,11 +113,11 @@
auto clonedRange = surroundingRange->cloneRange();
surroundingRange->setEnd(compositionRange->startPosition());
clonedRange->setStart(compositionRange->endPosition());
- postLayoutData.surroundingContext = plainText(surroundingRange.get()) + plainText(clonedRange.ptr());
+ postLayoutData.surroundingContext = plainText(*surroundingRange) + plainText(clonedRange);
postLayoutData.surroundingContextCursorPosition = characterCount(*surroundingRange);
postLayoutData.surroundingContextSelectionPosition = postLayoutData.surroundingContextCursorPosition;
} else {
- postLayoutData.surroundingContext = plainText(surroundingRange.get());
+ postLayoutData.surroundingContext = plainText(*surroundingRange);
if (surroundingStart.isNull() || selectionStart.isNull())
postLayoutData.surroundingContextCursorPosition = 0;
else
diff --git a/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm b/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
index 961e2c1..70e5285 100644
--- a/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
+++ b/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-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
@@ -4041,38 +4041,28 @@
void WebPage::updateSelectionWithDelta(int64_t locationDelta, int64_t lengthDelta, CompletionHandler<void()>&& completionHandler)
{
- Ref<Frame> frame = corePage()->focusController().focusedOrMainFrame();
- VisibleSelection selection = frame->selection().selection();
- if (selection.isNone()) {
+ auto frame = makeRef(corePage()->focusController().focusedOrMainFrame());
+ auto root = makeRefPtr(frame->selection().rootEditableElementOrDocumentElement());
+ auto selectionRange = frame->selection().selection().toNormalizedRange();
+ if (!root || !selectionRange) {
completionHandler();
return;
}
- auto root = frame->selection().rootEditableElementOrDocumentElement();
- auto range = selection.toNormalizedRange();
- if (!root || !range) {
- completionHandler();
- return;
- }
-
- size_t selectionLocation;
- size_t selectionLength;
- TextIterator::getLocationAndLengthFromRange(root, range.get(), selectionLocation, selectionLength);
-
- CheckedInt64 newSelectionLocation { selectionLocation };
- CheckedInt64 newSelectionLength { selectionLength };
+ auto scope = makeRangeSelectingNodeContents(*root);
+ auto selectionCharacterRange = characterRange(scope, *selectionRange);
+ CheckedInt64 newSelectionLocation { selectionCharacterRange.location };
+ CheckedInt64 newSelectionLength { selectionCharacterRange.length };
newSelectionLocation += locationDelta;
newSelectionLength += lengthDelta;
-
if (newSelectionLocation.hasOverflowed() || newSelectionLength.hasOverflowed()) {
completionHandler();
return;
}
auto newSelectionRange = CharacterRange(newSelectionLocation.unsafeGet(), newSelectionLength.unsafeGet());
- auto resolvedRange = resolveCharacterRange(makeRangeSelectingNodeContents(*root), newSelectionRange);
- frame->selection().setSelectedRange(createLiveRange(resolvedRange).ptr(), DOWNSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
-
+ auto updatedSelectionRange = resolveCharacterRange(makeRangeSelectingNodeContents(*root), newSelectionRange);
+ frame->selection().setSelectedRange(createLiveRange(updatedSelectionRange).ptr(), DOWNSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
completionHandler();
}
@@ -4175,25 +4165,25 @@
startOfRangeOfInterestInSelection = rangeOfInterestStart > selectionStart ? rangeOfInterestStart : selectionStart;
endOfRangeOfInterestInSelection = rangeOfInterestEnd < selectionEnd ? rangeOfInterestEnd : selectionEnd;
} else {
- size_t rangeOfInterestLocation;
- size_t rangeOfInterestLength;
- RefPtr<Node> rootNode = rangeOfInterest->commonAncestorContainer();
+ auto rootNode = makeRefPtr(rangeOfInterest->commonAncestorContainer());
if (!rootNode) {
completionHandler({ });
return;
}
+ auto rootContainerNode = rootNode->isContainerNode() ? downcast<ContainerNode>(rootNode.get()) : rootNode->parentNode();
+ if (!rootContainerNode) {
+ completionHandler({ });
+ return;
+ }
+ auto scope = makeRangeSelectingNodeContents(*rootContainerNode);
- RefPtr<ContainerNode> rootContainerNode = rootNode->isContainerNode() ? downcast<ContainerNode>(rootNode.get()) : rootNode->parentNode();
- TextIterator::getLocationAndLengthFromRange(rootContainerNode.get(), rangeOfInterest.get(), rangeOfInterestLocation, rangeOfInterestLength);
-
- Checked<uint64_t, RecordOverflow> midpointLocation { rangeOfInterestLocation };
- midpointLocation += rangeOfInterestLength / 2;
+ auto characterRangeOfInterest = characterRange(scope, *rangeOfInterest);
+ auto midpointLocation = checkedSum<uint64_t>(characterRangeOfInterest.location, characterRangeOfInterest.length / 2);
if (midpointLocation.hasOverflowed()) {
completionHandler({ });
return;
}
-
- auto midpoint = createLegacyEditingPosition(resolveCharacterLocation(makeRangeSelectingNodeContents(*rootContainerNode), midpointLocation.unsafeGet()));
+ auto midpoint = createLegacyEditingPosition(resolveCharacterLocation(scope, midpointLocation.unsafeGet()));
startOfRangeOfInterestInSelection = startOfWord(midpoint);
if (startOfRangeOfInterestInSelection < rangeOfInterestStart) {
@@ -4201,7 +4191,6 @@
if (startOfRangeOfInterestInSelection > rangeOfInterestEnd)
startOfRangeOfInterestInSelection = midpoint;
}
-
endOfRangeOfInterestInSelection = startOfRangeOfInterestInSelection;
}
diff --git a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm
index 96281ab..da1132c 100644
--- a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm
+++ b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm
@@ -154,9 +154,11 @@
if (!selectionStartBoundary || !selectionEnd || !paragraphStart)
return;
+ auto contextRangeForCandidateRequest = frame.editor().contextRangeForCandidateRequest();
+
postLayoutData.candidateRequestStartPosition = characterCount({ *paragraphStart, *selectionStartBoundary });
postLayoutData.selectedTextLength = characterCount({ *selectionStartBoundary, *selectionEnd });
- postLayoutData.paragraphContextForCandidateRequest = plainText(frame.editor().contextRangeForCandidateRequest().get());
+ postLayoutData.paragraphContextForCandidateRequest = contextRangeForCandidateRequest ? plainText(*contextRangeForCandidateRequest) : String();
postLayoutData.stringForCandidateRequest = frame.editor().stringForCandidateRequest();
IntRect rectForSelectionCandidates;
diff --git a/Source/WebKitLegacy/mac/ChangeLog b/Source/WebKitLegacy/mac/ChangeLog
index 800ca13..a140b96 100644
--- a/Source/WebKitLegacy/mac/ChangeLog
+++ b/Source/WebKitLegacy/mac/ChangeLog
@@ -1,3 +1,20 @@
+2020-04-01 Darin Adler <darin@apple.com>
+
+ Remove all uses of live ranges from TextIterator
+ https://bugs.webkit.org/show_bug.cgi?id=209723
+
+ Reviewed by Antti Koivisto.
+
+ * WebCoreSupport/WebEditorClient.mm:
+ (WebEditorClient::updateSpellingUIWithGrammarString): Remove some unnecessary
+ use of local variabels for NSString.
+ (WebEditorClient::requestCandidatesForSelection): Pass a reference to a live
+ range to plainText.
+ * WebView/WebFrame.mm:
+ (-[WebFrame _stringForRange:]): Ditto.
+ (-[WebFrame _convertToNSRange:]): Use characterRange instead of
+ TextIterator::getLocationAndLengthFromRange.
+
2020-04-01 Ryosuke Niwa <rniwa@webkit.org>
HTMLFormElement should use WeakPtr to keep track of its associated elements
diff --git a/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm b/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm
index 692ee07..3c30d57 100644
--- a/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm
+++ b/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm
@@ -1039,14 +1039,11 @@
void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
{
NSMutableArray *corrections = [NSMutableArray array];
- for (auto& guess : grammarDetail.guesses) {
- NSString *guessNSString = guess;
- [corrections addObject:guessNSString];
- }
- NSString *descriptionNSString = grammarDetail.userDescription;
+ for (auto& guess : grammarDetail.guesses)
+ [corrections addObject:guess];
NSDictionary *dictionary = @{
NSGrammarRange : [NSValue valueWithRange:grammarDetail.range],
- NSGrammarUserDescription : descriptionNSString,
+ NSGrammarUserDescription : grammarDetail.userDescription,
NSGrammarCorrections : corrections,
};
[[NSSpellChecker sharedSpellChecker] updateSpellingPanelWithGrammarString:badGrammarPhrase detail:dictionary];
@@ -1122,9 +1119,11 @@
auto selectionStart = selection.visibleStart();
auto selectionStartOffsetInParagraph = characterCount({ *makeBoundaryPoint(startOfParagraph(selectionStart)), *makeBoundaryPoint(selectionStart) });
auto selectionLength = characterCount({ *makeBoundaryPoint(selectionStart), *makeBoundaryPoint(selection.visibleEnd()) });
+ auto contextRangeForCandidateRequest = frame->editor().contextRangeForCandidateRequest();
+ String contextForCandidateReqeuest = contextRangeForCandidateRequest ? plainText(*contextRangeForCandidateRequest) : String();
m_rangeForCandidates = NSMakeRange(selectionStartOffsetInParagraph, selectionLength);
- m_paragraphContextForCandidateRequest = plainText(frame->editor().contextRangeForCandidateRequest().get());
+ m_paragraphContextForCandidateRequest = contextForCandidateReqeuest;
NSTextCheckingTypes checkingTypes = NSTextCheckingTypeSpelling | NSTextCheckingTypeReplacement | NSTextCheckingTypeCorrection;
auto weakEditor = makeWeakPtr(*this);
diff --git a/Source/WebKitLegacy/mac/WebView/WebFrame.mm b/Source/WebKitLegacy/mac/WebView/WebFrame.mm
index fe66d1b..e55c309 100644
--- a/Source/WebKitLegacy/mac/WebView/WebFrame.mm
+++ b/Source/WebKitLegacy/mac/WebView/WebFrame.mm
@@ -587,7 +587,9 @@
- (NSString *)_stringForRange:(DOMRange *)range
{
- return plainText(core(range), WebCore::TextIteratorDefaultBehavior, true);
+ if (!range)
+ return @"";
+ return plainText(*core(range), WebCore::TextIteratorDefaultBehavior, true);
}
- (OptionSet<WebCore::PaintBehavior>)_paintBehaviorForDestinationContext:(CGContextRef)context
@@ -806,12 +808,15 @@
if (!range)
return NSMakeRange(NSNotFound, 0);
- size_t location = 0;
- size_t length = 0;
- if (!WebCore::TextIterator::getLocationAndLengthFromRange(_private->coreFrame->selection().rootEditableElementOrDocumentElement(), range, location, length))
+ auto frame = _private->coreFrame;
+ if (!frame)
return NSMakeRange(NSNotFound, 0);
- return NSMakeRange(location, length);
+ auto* element = frame->selection().rootEditableElementOrDocumentElement();
+ if (!element)
+ return NSMakeRange(NSNotFound, 0);
+
+ return characterRange(makeBoundaryPointBeforeNodeContents(*element), *range);
}
- (RefPtr<WebCore::Range>)_convertToDOMRange:(NSRange)nsrange
diff --git a/Source/WebKitLegacy/win/ChangeLog b/Source/WebKitLegacy/win/ChangeLog
index aa2e30b..13d4f42 100644
--- a/Source/WebKitLegacy/win/ChangeLog
+++ b/Source/WebKitLegacy/win/ChangeLog
@@ -1,3 +1,18 @@
+2020-04-01 Darin Adler <darin@apple.com>
+
+ Remove all uses of live ranges from TextIterator
+ https://bugs.webkit.org/show_bug.cgi?id=209723
+
+ Reviewed by Antti Koivisto.
+
+ * WebFrame.cpp:
+ (WebFrame::string): Use a SimpleRange instead of a live range
+ to call plainText.
+ * WebView.cpp:
+ (WebView::selectedRangeForTesting): Use a SimpleRange instead
+ of a live range to call characterRange instead of
+ TextIterator::getLocationAndLengthFromRange.
+
2020-03-30 Simon Fraser <simon.fraser@apple.com>
scrollIntoView() erroneously scrolls non-containing block scrollers
diff --git a/Source/WebKitLegacy/win/WebFrame.cpp b/Source/WebKitLegacy/win/WebFrame.cpp
index 368d7ce..d42e451 100644
--- a/Source/WebKitLegacy/win/WebFrame.cpp
+++ b/Source/WebKitLegacy/win/WebFrame.cpp
@@ -1923,13 +1923,15 @@
*result = nullptr;
- Frame* coreFrame = core(this);
- if (!coreFrame)
+ auto* frame = core(this);
+ if (!frame)
return E_UNEXPECTED;
- RefPtr<Range> allRange(rangeOfContents(*coreFrame->document()));
- String allString = plainText(allRange.get());
- *result = BString(allString).release();
+ auto* document = frame->document();
+ if (!document)
+ return E_FAIL;
+
+ *result = BString(plainText(makeRangeSelectingNodeContents(*document))).release();
return S_OK;
}
diff --git a/Source/WebKitLegacy/win/WebView.cpp b/Source/WebKitLegacy/win/WebView.cpp
index 4da0aff..ad138e1 100644
--- a/Source/WebKitLegacy/win/WebView.cpp
+++ b/Source/WebKitLegacy/win/WebView.cpp
@@ -7801,14 +7801,16 @@
Frame& frame = m_page->focusController().focusedOrMainFrame();
RefPtr<Range> range = frame.editor().selectedRange();
+ if (!range)
+ return E_FAIL;
- size_t locationSize;
- size_t lengthSize;
- if (range && TextIterator::getLocationAndLengthFromRange(frame.selection().rootEditableElementOrDocumentElement(), range.get(), locationSize, lengthSize)) {
- *location = static_cast<UINT>(locationSize);
- *length = static_cast<UINT>(lengthSize);
- }
+ auto* element = frame.selection().rootEditableElementOrDocumentElement();
+ if (!element)
+ return E_FAIL;
+ auto relativeRange = characterRange(makeBoundaryPointBeforeNodeContents(*element), *range);
+ *location = static_cast<UINT>(relativeRange.location);
+ *length = static_cast<UINT>(relativeRange.length);
return S_OK;
}