Changeset 211356 in webkit


Ignore:
Timestamp:
Jan 29, 2017 9:03:11 PM (7 years ago)
Author:
n_wang@apple.com
Message:

AX: WKContentView needs to implement UITextInput methods to make speak selection highlighting work
https://bugs.webkit.org/show_bug.cgi?id=166955

Reviewed by Ryosuke Niwa.

Source/WebCore:

Created a new version of Range::collectSelectionRect() that returns rects for each
line, so that Speak Selection doesn't need to handle searching for soft line breaks.
Also added a variant of findPlainText to search for the closest matched range to the given position.

Test: editing/text-iterator/range-of-string-closest-to-position.html

  • dom/Range.cpp:

(WebCore::Range::collectSelectionRectsWithoutUnionInteriorLines):
(WebCore::Range::collectSelectionRects):

  • dom/Range.h:
  • editing/TextIterator.cpp:

(WebCore::findPlainTextMatches):
(WebCore::updateSearchBuffer):
(WebCore::findIteratorOptions):
(WebCore::rangeMatches):
(WebCore::findClosestPlainText):
(WebCore::findPlainText):
(WebCore::findPlainTextOffset): Deleted.

  • editing/TextIterator.h:
  • editing/htmlediting.h:
  • testing/Internals.cpp:

(WebCore::Internals::rangeOfStringNearLocation):

  • testing/Internals.h:
  • testing/Internals.idl:

Source/WebKit2:

Implemented methods that Speak Selection can use to retrieve the word/sentence highlighting rects.

  • Scripts/webkit/messages.py:

(headers_for_type):

  • UIProcess/WebPageProxy.h:
  • UIProcess/WebPageProxy.messages.in:
  • UIProcess/ios/WKContentViewInteraction.h:
  • UIProcess/ios/WKContentViewInteraction.mm:

(-[WKContentView webSelectionRectsForSelectionRects:]):
(-[WKContentView webSelectionRects]):
(-[WKContentView _accessibilityRetrieveRectsEnclosingSelectionOffset:withGranularity:]):
(-[WKContentView _accessibilityRetrieveRectsAtSelectionOffset:withText:]):

  • UIProcess/ios/WebPageProxyIOS.mm:

(WebKit::WebPageProxy::selectionRectsCallback):
(WebKit::WebPageProxy::requestRectsForGranularityWithSelectionOffset):
(WebKit::WebPageProxy::requestRectsAtSelectionOffsetWithText):

  • WebProcess/WebPage/WebPage.h:
  • WebProcess/WebPage/WebPage.messages.in:
  • WebProcess/WebPage/ios/WebPageIOS.mm:

(WebKit::visiblePositionForPositionWithOffset):
(WebKit::WebPage::getRectsForGranularityWithSelectionOffset):
(WebKit::rangeNearPositionMatchesText):
(WebKit::WebPage::getRectsAtSelectionOffsetWithText):

LayoutTests:

  • editing/text-iterator/range-of-string-closest-to-position-expected.txt: Added.
  • editing/text-iterator/range-of-string-closest-to-position.html: Added.
Location:
trunk
Files:
2 added
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r211352 r211356  
     12017-01-29  Nan Wang  <n_wang@apple.com>
     2
     3        AX: WKContentView needs to implement UITextInput methods to make speak selection highlighting work
     4        https://bugs.webkit.org/show_bug.cgi?id=166955
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        * editing/text-iterator/range-of-string-closest-to-position-expected.txt: Added.
     9        * editing/text-iterator/range-of-string-closest-to-position.html: Added.
     10
    1112017-01-29  Yoav Weiss  <yoav@yoav.ws>
    212
  • trunk/Source/WebCore/ChangeLog

    r211355 r211356  
     12017-01-29  Nan Wang  <n_wang@apple.com>
     2
     3        AX: WKContentView needs to implement UITextInput methods to make speak selection highlighting work
     4        https://bugs.webkit.org/show_bug.cgi?id=166955
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Created a new version of Range::collectSelectionRect() that returns rects for each
     9        line, so that Speak Selection doesn't need to handle searching for soft line breaks.
     10        Also added a variant of findPlainText to search for the closest matched range to the given position.
     11
     12        Test: editing/text-iterator/range-of-string-closest-to-position.html
     13
     14        * dom/Range.cpp:
     15        (WebCore::Range::collectSelectionRectsWithoutUnionInteriorLines):
     16        (WebCore::Range::collectSelectionRects):
     17        * dom/Range.h:
     18        * editing/TextIterator.cpp:
     19        (WebCore::findPlainTextMatches):
     20        (WebCore::updateSearchBuffer):
     21        (WebCore::findIteratorOptions):
     22        (WebCore::rangeMatches):
     23        (WebCore::findClosestPlainText):
     24        (WebCore::findPlainText):
     25        (WebCore::findPlainTextOffset): Deleted.
     26        * editing/TextIterator.h:
     27        * editing/htmlediting.h:
     28        * testing/Internals.cpp:
     29        (WebCore::Internals::rangeOfStringNearLocation):
     30        * testing/Internals.h:
     31        * testing/Internals.idl:
     32
    1332017-01-29  Andy Estes  <aestes@apple.com>
    234
  • trunk/Source/WebCore/dom/Range.cpp

    r210833 r211356  
    12671267// This function is similar in spirit to addLineBoxRects, but annotates the returned rectangles
    12681268// with additional state which helps iOS draw selections in its unique way.
    1269 void Range::collectSelectionRects(Vector<SelectionRect>& rects)
     1269int Range::collectSelectionRectsWithoutUnionInteriorLines(Vector<SelectionRect>& rects)
    12701270{
    12711271    auto& startContainer = this->startContainer();
     
    13261326        VisiblePosition brPosition(createLegacyEditingPosition(stopNode, 0), VP_DEFAULT_AFFINITY);
    13271327        if (endPosition == brPosition)
    1328             rects.last().setIsLineBreak(true);   
     1328            rects.last().setIsLineBreak(true);
    13291329    }
    13301330
     
    14231423            selectionRect.setLogicalWidth(selectionRect.maxX() - selectionRect.logicalLeft());
    14241424    }
    1425 
     1425   
     1426    return maxLineNumber;
     1427}
     1428
     1429void Range::collectSelectionRects(Vector<SelectionRect>& rects)
     1430{
     1431    int maxLineNumber = collectSelectionRectsWithoutUnionInteriorLines(rects);
     1432    const size_t numberOfRects = rects.size();
     1433   
    14261434    // Union all the rectangles on interior lines (i.e. not first or last).
    14271435    // On first and last lines, just avoid having overlaps by merging intersecting rectangles.
  • trunk/Source/WebCore/dom/Range.h

    r210758 r211356  
    126126#if PLATFORM(IOS)
    127127    WEBCORE_EXPORT void collectSelectionRects(Vector<SelectionRect>&);
     128    WEBCORE_EXPORT int collectSelectionRectsWithoutUnionInteriorLines(Vector<SelectionRect>&);
    128129#endif
    129130
  • trunk/Source/WebCore/editing/TextIterator.cpp

    r210432 r211356  
    26572657}
    26582658
    2659 static std::optional<std::pair<size_t, size_t>> findPlainTextOffset(SearchBuffer& buffer, CharacterIterator& findIterator, bool searchForward)
    2660 {
    2661     size_t matchStart = 0;
    2662     size_t matchLength = 0;
     2659static TextIteratorBehavior findIteratorOptions(FindOptions options)
     2660{
     2661    TextIteratorBehavior iteratorOptions = TextIteratorEntersTextControls | TextIteratorClipsToFrameAncestors;
     2662    if (!(options & DoNotTraverseFlatTree))
     2663        iteratorOptions |= TextIteratorTraversesFlatTree;
     2664    return iteratorOptions;
     2665}
     2666
     2667static void findPlainTextMatches(const Range& range, const String& target, FindOptions options, const std::function<bool(size_t, size_t)>& match)
     2668{
     2669    SearchBuffer buffer(target, options);
     2670    if (buffer.needsMoreContext()) {
     2671        Ref<Range> beforeStartRange = range.ownerDocument().createRange();
     2672        beforeStartRange->setEnd(range.startContainer(), range.startOffset());
     2673        for (SimplifiedBackwardsTextIterator backwardsIterator(beforeStartRange.get()); !backwardsIterator.atEnd(); backwardsIterator.advance()) {
     2674            buffer.prependContext(backwardsIterator.text());
     2675            if (!buffer.needsMoreContext())
     2676                break;
     2677        }
     2678    }
     2679
     2680    CharacterIterator findIterator(range, findIteratorOptions(options));
    26632681    while (!findIterator.atEnd()) {
    26642682        findIterator.advance(buffer.append(findIterator.text()));
     
    26752693            size_t lastCharacterInBufferOffset = findIterator.characterOffset();
    26762694            ASSERT(lastCharacterInBufferOffset >= matchStartOffset);
    2677             matchStart = lastCharacterInBufferOffset - matchStartOffset;
    2678             matchLength = newMatchLength;
    2679             if (searchForward) // Look for the last match when searching backwards instead.
    2680                 return std::pair<size_t, size_t> { matchStart, matchLength };
    2681         }
    2682     }
    2683 
     2695            if (match(lastCharacterInBufferOffset - matchStartOffset, newMatchLength))
     2696                return;
     2697        }
     2698    }
     2699}
     2700
     2701static Ref<Range> rangeForMatch(const Range& range, FindOptions options, size_t matchStart, size_t matchLength, bool searchForward)
     2702{
    26842703    if (!matchLength)
    2685         return std::nullopt;
    2686 
    2687     return std::pair<size_t, size_t> { matchStart, matchLength };
     2704        return collapsedToBoundary(range, searchForward);
     2705    CharacterIterator rangeComputeIterator(range, findIteratorOptions(options));
     2706    return characterSubrange(range.ownerDocument(), rangeComputeIterator, matchStart, matchLength);
     2707}
     2708
     2709Ref<Range> findClosestPlainText(const Range& range, const String& target, FindOptions options, unsigned targetOffset)
     2710{
     2711    size_t matchStart = 0;
     2712    size_t matchLength = 0;
     2713    size_t distance = std::numeric_limits<size_t>::max();
     2714    auto match = [targetOffset, &distance, &matchStart, &matchLength] (size_t start, size_t length) {
     2715        size_t newDistance = std::min(abs(static_cast<signed>(start - targetOffset)), abs(static_cast<signed>(start + length - targetOffset)));
     2716        if (newDistance < distance) {
     2717            matchStart = start;
     2718            matchLength = length;
     2719            distance = newDistance;
     2720        }
     2721        return false;
     2722    };
     2723
     2724    findPlainTextMatches(range, target, options, match);
     2725    return rangeForMatch(range, options, matchStart, matchLength, !(options & Backwards));
    26882726}
    26892727
    26902728Ref<Range> findPlainText(const Range& range, const String& target, FindOptions options)
    26912729{
    2692     SearchBuffer buffer(target, options);
    2693 
    2694     if (buffer.needsMoreContext()) {
    2695         Ref<Range> beforeStartRange = range.ownerDocument().createRange();
    2696         beforeStartRange->setEnd(range.startContainer(), range.startOffset());
    2697         for (SimplifiedBackwardsTextIterator backwardsIterator(beforeStartRange.get()); !backwardsIterator.atEnd(); backwardsIterator.advance()) {
    2698             buffer.prependContext(backwardsIterator.text());
    2699             if (!buffer.needsMoreContext())
    2700                 break;
    2701         }
    2702     }
    2703 
    27042730    bool searchForward = !(options & Backwards);
    2705     TextIteratorBehavior iteratorOptions = TextIteratorEntersTextControls | TextIteratorClipsToFrameAncestors;
    2706     if (!(options & DoNotTraverseFlatTree))
    2707         iteratorOptions |= TextIteratorTraversesFlatTree;
    2708 
    2709     CharacterIterator findIterator(range, iteratorOptions);
    2710     auto result = findPlainTextOffset(buffer, findIterator, searchForward);
    2711     if (!result)
    2712         return collapsedToBoundary(range, searchForward);
    2713 
    2714     CharacterIterator rangeComputeIterator(range, iteratorOptions);
    2715     return characterSubrange(range.ownerDocument(), rangeComputeIterator, result->first, result->second);
    2716 }
    2717 
    2718 }
     2731    size_t matchStart = 0;
     2732    size_t matchLength = 0;
     2733    auto match = [searchForward, &matchStart, &matchLength] (size_t start, size_t length) {
     2734        matchStart = start;
     2735        matchLength = length;
     2736        // Look for the last match when searching backwards instead.
     2737        return searchForward;
     2738    };
     2739
     2740    findPlainTextMatches(range, target, options, match);
     2741    return rangeForMatch(range, options, matchStart, matchLength, searchForward);
     2742}
     2743
     2744}
  • trunk/Source/WebCore/editing/TextIterator.h

    r210131 r211356  
    4646WEBCORE_EXPORT String plainTextReplacingNoBreakSpace(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
    4747Ref<Range> findPlainText(const Range&, const String&, FindOptions);
     48WEBCORE_EXPORT Ref<Range> findClosestPlainText(const Range&, const String&, FindOptions, unsigned);
    4849
    4950// FIXME: Move this somewhere else in the editing directory. It doesn't belong here.
  • trunk/Source/WebCore/editing/htmlediting.h

    r210842 r211356  
    145145int comparePositions(const VisiblePosition&, const VisiblePosition&);
    146146
    147 int indexForVisiblePosition(const VisiblePosition&, RefPtr<ContainerNode>& scope);
     147WEBCORE_EXPORT int indexForVisiblePosition(const VisiblePosition&, RefPtr<ContainerNode>& scope);
    148148int indexForVisiblePosition(Node&, const VisiblePosition&, bool forSelectionPreservation);
    149 VisiblePosition visiblePositionForIndex(int index, ContainerNode* scope);
     149WEBCORE_EXPORT VisiblePosition visiblePositionForIndex(int index, ContainerNode* scope);
    150150VisiblePosition visiblePositionForIndexUsingCharacterIterator(Node&, int index); // FIXME: Why do we need this version?
    151151
  • trunk/Source/WebCore/testing/Internals.cpp

    r211324 r211356  
    14571457}
    14581458
     1459RefPtr<Range> Internals::rangeOfStringNearLocation(const Range& searchRange, const String& text, unsigned targetOffset)
     1460{
     1461    return findClosestPlainText(searchRange, text, 0, targetOffset);
     1462}
     1463
    14591464ExceptionOr<RefPtr<Range>> Internals::rangeForDictionaryLookupAtLocation(int x, int y)
    14601465{
  • trunk/Source/WebCore/testing/Internals.h

    r211324 r211356  
    202202    Ref<Range> subrange(Range&, int rangeLocation, int rangeLength);
    203203    ExceptionOr<RefPtr<Range>> rangeForDictionaryLookupAtLocation(int x, int y);
     204    RefPtr<Range> rangeOfStringNearLocation(const Range&, const String&, unsigned);
    204205
    205206    ExceptionOr<void> setDelegatesScrolling(bool enabled);
  • trunk/Source/WebCore/testing/Internals.idl

    r211253 r211356  
    196196    Range subrange(Range range, long rangeLocation, long rangeLength);
    197197    [MayThrowException] Range? rangeForDictionaryLookupAtLocation(long x, long y);
     198    Range? rangeOfStringNearLocation(Range range, DOMString text, long targetOffset);
    198199
    199200    [MayThrowException] void setDelegatesScrolling(boolean enabled);
  • trunk/Source/WebKit2/ChangeLog

    r211354 r211356  
     12017-01-29  Nan Wang  <n_wang@apple.com>
     2
     3        AX: WKContentView needs to implement UITextInput methods to make speak selection highlighting work
     4        https://bugs.webkit.org/show_bug.cgi?id=166955
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Implemented methods that Speak Selection can use to retrieve the word/sentence highlighting rects.
     9
     10        * Scripts/webkit/messages.py:
     11        (headers_for_type):
     12        * UIProcess/WebPageProxy.h:
     13        * UIProcess/WebPageProxy.messages.in:
     14        * UIProcess/ios/WKContentViewInteraction.h:
     15        * UIProcess/ios/WKContentViewInteraction.mm:
     16        (-[WKContentView webSelectionRectsForSelectionRects:]):
     17        (-[WKContentView webSelectionRects]):
     18        (-[WKContentView _accessibilityRetrieveRectsEnclosingSelectionOffset:withGranularity:]):
     19        (-[WKContentView _accessibilityRetrieveRectsAtSelectionOffset:withText:]):
     20        * UIProcess/ios/WebPageProxyIOS.mm:
     21        (WebKit::WebPageProxy::selectionRectsCallback):
     22        (WebKit::WebPageProxy::requestRectsForGranularityWithSelectionOffset):
     23        (WebKit::WebPageProxy::requestRectsAtSelectionOffsetWithText):
     24        * WebProcess/WebPage/WebPage.h:
     25        * WebProcess/WebPage/WebPage.messages.in:
     26        * WebProcess/WebPage/ios/WebPageIOS.mm:
     27        (WebKit::visiblePositionForPositionWithOffset):
     28        (WebKit::WebPage::getRectsForGranularityWithSelectionOffset):
     29        (WebKit::rangeNearPositionMatchesText):
     30        (WebKit::WebPage::getRectsAtSelectionOffsetWithText):
     31
    1322017-01-29  Dan Bernstein  <mitz@apple.com>
    233
  • trunk/Source/WebKit2/Scripts/webkit/messages.py

    r210887 r211356  
    366366        'WebCore::TextureMapperAnimations': ['<WebCore/TextureMapperAnimation.h>'],
    367367        'WebCore::ViewportAttributes': ['<WebCore/ViewportArguments.h>'],
     368        'WebCore::SelectionRect': ['"EditorState.h"'],
    368369        'WebKit::BackForwardListItemState': ['"SessionState.h"'],
    369370        'WebKit::LayerHostingMode': ['"LayerTreeContext.h"'],
  • trunk/Source/WebKit2/UIProcess/WebPageProxy.h

    r211226 r211356  
    257257typedef GenericCallback<const WebCore::IntPoint&, uint32_t, uint32_t, uint32_t> GestureCallback;
    258258typedef GenericCallback<const WebCore::IntPoint&, uint32_t, uint32_t> TouchesCallback;
     259typedef GenericCallback<const Vector<WebCore::SelectionRect>&> SelectionRectsCallback;
    259260struct NodeAssistanceArguments {
    260261    AssistedNodeInformation m_nodeInformation;
     
    546547    void setForceAlwaysUserScalable(bool);
    547548    void setIsScrollingOrZooming(bool);
     549    void requestRectsForGranularityWithSelectionOffset(WebCore::TextGranularity, uint32_t offset, std::function<void(const Vector<WebCore::SelectionRect>&, CallbackBase::Error)>);
     550    void requestRectsAtSelectionOffsetWithText(int32_t offset, const String&, std::function<void(const Vector<WebCore::SelectionRect>&, CallbackBase::Error)>);
    548551#if ENABLE(DATA_INTERACTION)
    549552    void didPerformDataInteractionControllerOperation();
     
    14781481    void interpretKeyEvent(const EditorState&, bool isCharEvent, bool& handled);
    14791482    void showPlaybackTargetPicker(bool hasVideo, const WebCore::IntRect& elementRect);
     1483    void selectionRectsCallback(const Vector<WebCore::SelectionRect>&, uint64_t);
    14801484#endif
    14811485#if PLATFORM(GTK)
  • trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in

    r211226 r211356  
    196196    DisableDoubleTapGesturesDuringTapIfNecessary(uint64_t requestID)
    197197    DrawToPDFCallback(IPC::DataReference pdfData, uint64_t callbackID)
     198    SelectionRectsCallback(Vector<WebCore::SelectionRect> selectionRects, uint64_t callbackID);
    198199#endif
    199200#if ENABLE(DATA_DETECTION)
  • trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h

    r211342 r211356  
    248248- (NSArray<NSValue *> *)_uiTextSelectionRects;
    249249- (void)accessibilityRetrieveSpeakSelectionContent;
     250- (void)_accessibilityRetrieveRectsEnclosingSelectionOffset:(NSInteger)offset withGranularity:(UITextGranularity)granularity;
     251- (void)_accessibilityRetrieveRectsAtSelectionOffset:(NSInteger)offset withText:(NSString *)text;
    250252
    251253#if ENABLE(DATA_INTERACTION)
  • trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm

    r211342 r211356  
    496496@interface WKContentView (WKInteractionPrivate)
    497497- (void)accessibilitySpeakSelectionSetContent:(NSString *)string;
     498- (NSArray *)webSelectionRectsForSelectionRects:(const Vector<WebCore::SelectionRect>&)selectionRects;
     499- (void)_accessibilityDidGetSelectionRects:(NSArray *)selectionRects withGranularity:(UITextGranularity)granularity atOffset:(NSInteger)offset;
    498500@end
    499501
     
    14971499}
    14981500
    1499 - (NSArray *)webSelectionRects
    1500 {
    1501     if (_page->editorState().selectionIsNone)
    1502         return nil;
    1503     const auto& selectionRects = _page->editorState().postLayoutData().selectionRects;
     1501- (NSArray *)webSelectionRectsForSelectionRects:(const Vector<WebCore::SelectionRect>&)selectionRects
     1502{
    15041503    unsigned size = selectionRects.size();
    15051504    if (!size)
     
    15231522
    15241523    return webRects;
     1524}
     1525
     1526- (NSArray *)webSelectionRects
     1527{
     1528    if (_page->editorState().selectionIsNone)
     1529        return nil;
     1530    const auto& selectionRects = _page->editorState().postLayoutData().selectionRects;
     1531    return [self webSelectionRectsForSelectionRects:selectionRects];
    15251532}
    15261533
     
    21952202        if ([view respondsToSelector:@selector(accessibilitySpeakSelectionSetContent:)])
    21962203            [view accessibilitySpeakSelectionSetContent:string];
     2204    });
     2205}
     2206
     2207- (void)_accessibilityRetrieveRectsEnclosingSelectionOffset:(NSInteger)offset withGranularity:(UITextGranularity)granularity
     2208{
     2209    RetainPtr<WKContentView> view = self;
     2210    _page->requestRectsForGranularityWithSelectionOffset(toWKTextGranularity(granularity), offset , [view, offset, granularity](const Vector<WebCore::SelectionRect>& selectionRects, CallbackBase::Error error) {
     2211        if (error != WebKit::CallbackBase::Error::None)
     2212            return;
     2213        if ([view respondsToSelector:@selector(_accessibilityDidGetSelectionRects:withGranularity:atOffset:)])
     2214            [view _accessibilityDidGetSelectionRects:[view webSelectionRectsForSelectionRects:selectionRects] withGranularity:granularity atOffset:offset];
     2215    });
     2216}
     2217
     2218- (void)_accessibilityRetrieveRectsAtSelectionOffset:(NSInteger)offset withText:(NSString *)text
     2219{
     2220    RetainPtr<WKContentView> view = self;
     2221    _page->requestRectsAtSelectionOffsetWithText(offset, text, [view, offset](const Vector<WebCore::SelectionRect>& selectionRects, CallbackBase::Error error) {
     2222        if (error != WebKit::CallbackBase::Error::None)
     2223            return;
     2224        if ([view respondsToSelector:@selector(_accessibilityDidGetSelectionRects:withGranularity:atOffset:)])
     2225            [view _accessibilityDidGetSelectionRects:[view webSelectionRectsForSelectionRects:selectionRects] withGranularity:UITextGranularityWord atOffset:offset];
    21972226    });
    21982227}
  • trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm

    r211199 r211356  
    187187}
    188188
     189void WebPageProxy::selectionRectsCallback(const Vector<WebCore::SelectionRect>& selectionRects, uint64_t callbackID)
     190{
     191    auto callback = m_callbacks.take<SelectionRectsCallback>(callbackID);
     192    if (!callback) {
     193        ASSERT_NOT_REACHED();
     194        return;
     195    }
     196   
     197    callback->performCallbackWithReturnValue(selectionRects);
     198}
     199
    189200void WebPageProxy::updateVisibleContentRects(const VisibleContentRectUpdateInfo& visibleContentRectUpdate)
    190201{
     
    723734}
    724735
     736void WebPageProxy::requestRectsForGranularityWithSelectionOffset(WebCore::TextGranularity granularity, uint32_t offset, std::function<void(const Vector<WebCore::SelectionRect>&, CallbackBase::Error)> callbackFunction)
     737{
     738    if (!isValid()) {
     739        callbackFunction(Vector<WebCore::SelectionRect>(), CallbackBase::Error::Unknown);
     740        return;
     741    }
     742   
     743    uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
     744    m_process->send(Messages::WebPage::GetRectsForGranularityWithSelectionOffset(static_cast<uint32_t>(granularity), offset, callbackID), m_pageID);
     745}
     746
     747void WebPageProxy::requestRectsAtSelectionOffsetWithText(int32_t offset, const String& text, std::function<void(const Vector<WebCore::SelectionRect>&, CallbackBase::Error)> callbackFunction)
     748{
     749    if (!isValid()) {
     750        callbackFunction(Vector<WebCore::SelectionRect>(), CallbackBase::Error::Unknown);
     751        return;
     752    }
     753   
     754    uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
     755    m_process->send(Messages::WebPage::GetRectsAtSelectionOffsetWithText(offset, text, callbackID), m_pageID);
     756}
     757
    725758void WebPageProxy::moveSelectionByOffset(int32_t offset, std::function<void (CallbackBase::Error)> callbackFunction)
    726759{
  • trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h

    r211312 r211356  
    578578    void getSelectionContext(uint64_t callbackID);
    579579    void handleTwoFingerTapAtPoint(const WebCore::IntPoint&, uint64_t requestID);
     580    void getRectsForGranularityWithSelectionOffset(uint32_t, int32_t, uint64_t callbackID);
     581    void getRectsAtSelectionOffsetWithText(int32_t, const String&, uint64_t callbackID);
    580582#if ENABLE(IOS_TOUCH_EVENTS)
    581583    void dispatchAsynchronousTouchEvents(const Vector<WebTouchEvent, 1>& queue);
  • trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in

    r211221 r211356  
    9797    HandleTwoFingerTapAtPoint(WebCore::IntPoint point, uint64_t requestID)
    9898    SetForceAlwaysUserScalable(bool userScalable)
     99    GetRectsForGranularityWithSelectionOffset(uint32_t granularity, int32_t offset, uint64_t callbackID);
     100    GetRectsAtSelectionOffsetWithText(int32_t offset, String text, uint64_t callbackID);
    99101#endif
    100102
  • trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm

    r211343 r211356  
    106106#import <WebCore/WKContentObservation.h>
    107107#import <WebCore/WebEvent.h>
     108#import <WebCore/htmlediting.h>
    108109#import <wtf/MathExtras.h>
    109110#import <wtf/SetForScope.h>
     
    18181819        frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), true);
    18191820    send(Messages::WebPageProxy::VoidCallback(callbackID));
     1821}
     1822
     1823static VisiblePosition visiblePositionForPositionWithOffset(const VisiblePosition& position, int32_t offset)
     1824{
     1825    RefPtr<ContainerNode> root;
     1826    unsigned startIndex = indexForVisiblePosition(position, root);
     1827    return visiblePositionForIndex(startIndex + offset, root.get());
     1828}
     1829
     1830void WebPage::getRectsForGranularityWithSelectionOffset(uint32_t granularity, int32_t offset, uint64_t callbackID)
     1831{
     1832    Frame& frame = m_page->focusController().focusedOrMainFrame();
     1833    VisibleSelection selection = frame.selection().selection();
     1834    VisiblePosition selectionStart = selection.visibleStart();
     1835
     1836    if (selectionStart.isNull()) {
     1837        send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
     1838        return;
     1839    }
     1840
     1841    auto position = visiblePositionForPositionWithOffset(selectionStart, offset);
     1842    SelectionDirection direction = offset < 0 ? DirectionBackward : DirectionForward;
     1843
     1844    auto range = enclosingTextUnitOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), direction);
     1845    if (!range || range->collapsed()) {
     1846        send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
     1847        return;
     1848    }
     1849
     1850    Vector<WebCore::SelectionRect> selectionRects;
     1851    range->collectSelectionRectsWithoutUnionInteriorLines(selectionRects);
     1852    convertSelectionRectsToRootView(frame.view(), selectionRects);
     1853    send(Messages::WebPageProxy::SelectionRectsCallback(selectionRects, callbackID));
     1854}
     1855
     1856static RefPtr<Range> rangeNearPositionMatchesText(const VisiblePosition& position, RefPtr<Range> originalRange, const String& matchText, RefPtr<Range> selectionRange)
     1857{
     1858    auto range = Range::create(selectionRange->ownerDocument(), selectionRange->startPosition(), position.deepEquivalent().parentAnchoredEquivalent());
     1859    unsigned targetOffset = TextIterator::rangeLength(range.ptr(), true);
     1860    return findClosestPlainText(*selectionRange.get(), matchText, 0, targetOffset);
     1861}
     1862
     1863void WebPage::getRectsAtSelectionOffsetWithText(int32_t offset, const String& text, uint64_t callbackID)
     1864{
     1865    Frame& frame = m_page->focusController().focusedOrMainFrame();
     1866    uint32_t length = text.length();
     1867    VisibleSelection selection = frame.selection().selection();
     1868    VisiblePosition selectionStart = selection.visibleStart();
     1869    VisiblePosition selectionEnd = selection.visibleEnd();
     1870
     1871    if (selectionStart.isNull() || selectionEnd.isNull()) {
     1872        send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
     1873        return;
     1874    }
     1875
     1876    auto startPosition = visiblePositionForPositionWithOffset(selectionStart, offset);
     1877    auto endPosition = visiblePositionForPositionWithOffset(startPosition, length);
     1878    auto range = Range::create(*frame.document(), startPosition, endPosition);
     1879
     1880    if (range->collapsed()) {
     1881        send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
     1882        return;
     1883    }
     1884
     1885    String rangeText = plainTextReplacingNoBreakSpace(range.ptr(), TextIteratorDefaultBehavior, true);
     1886    if (rangeText != text) {
     1887        auto selectionRange = selection.toNormalizedRange();
     1888        // Try to search for a range which is the closest to the position within the selection range that matches the passed in text.
     1889        if (auto wordRange = rangeNearPositionMatchesText(startPosition, range.ptr(), text, selectionRange)) {
     1890            if (!wordRange->collapsed())
     1891                range = *wordRange;
     1892        }
     1893    }
     1894
     1895    Vector<WebCore::SelectionRect> selectionRects;
     1896    range->collectSelectionRectsWithoutUnionInteriorLines(selectionRects);
     1897    convertSelectionRectsToRootView(frame.view(), selectionRects);
     1898    send(Messages::WebPageProxy::SelectionRectsCallback(selectionRects, callbackID));
    18201899}
    18211900
Note: See TracChangeset for help on using the changeset viewer.