Skip to content

Commit a22e76d

Browse files
author
Dan Bernstein
committed
Source/WebCore: WebCore part of <rdar://problem/9281695> Add text search API for getting the DOM range of a text match
https://bugs.webkit.org/show_bug.cgi?id=67230 Reviewed by Darin Adler. Test: TestWebKitAPI/Tests/mac/DOMRangeOfString. * WebCore.exp.in: Export Page::rangeOfString(). * dom/Range.h: Added a default ASSERT_NO_EXCEPTION to a few more member functions. * editing/Editor.cpp: (WebCore::Editor::findString): Moved most of the logic into rangeOfString(), which this function now calls, passing in the current selection as the reference range and setting the selection to the returned range. (WebCore::Editor::rangeOfString): Added. Contains the find logic from findString(). * editing/Editor.h: * page/Page.cpp: (WebCore::Page::rangeOfString): Added. This function is similar to findString(), but it takes an optional reference range and returns a Range, rather than using the current selection as the reference range and setting the selection to the next match. * page/Page.h: Source/WebKit/mac: <rdar://problem/9281695> Add text search API for getting the DOM range of a text match https://bugs.webkit.org/show_bug.cgi?id=67230 Reviewed by Darin Adler. * WebView/WebHTMLView.mm: * WebView/WebView.mm: (coreOptions): Moved this function from WebHTMLView.mm to here and made it accessible from both this file and WebHTMLView.mm. (-[WebView DOMRangeOfString:relativeTo:options:]): Added this new API. * WebView/WebViewInternal.h: * WebView/WebViewPrivate.h: Tools: Test for <rdar://problem/9281695> Add text search API for getting the DOM range of a text match https://bugs.webkit.org/show_bug.cgi?id=67230 Reviewed by Darin Adler. * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/mac/DOMRangeOfString.html: Added. * TestWebKitAPI/Tests/mac/DOMRangeOfString.mm: Added. (-[DOMRangeOfStringFrameLoadDelegate webView:didFinishLoadForFrame:]): (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/83052@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@94124 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 3eb9bca commit a22e76d

16 files changed

Lines changed: 257 additions & 51 deletions

File tree

Source/WebCore/ChangeLog

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
2011-08-30 Dan Bernstein <mitz@apple.com>
2+
3+
WebCore part of <rdar://problem/9281695> Add text search API for getting the DOM range of a text match
4+
https://bugs.webkit.org/show_bug.cgi?id=67230
5+
6+
Reviewed by Darin Adler.
7+
8+
Test: TestWebKitAPI/Tests/mac/DOMRangeOfString.
9+
10+
* WebCore.exp.in: Export Page::rangeOfString().
11+
* dom/Range.h: Added a default ASSERT_NO_EXCEPTION to a few more member functions.
12+
* editing/Editor.cpp:
13+
(WebCore::Editor::findString): Moved most of the logic into rangeOfString(), which this function
14+
now calls, passing in the current selection as the reference range and setting the selection to
15+
the returned range.
16+
(WebCore::Editor::rangeOfString): Added. Contains the find logic from findString().
17+
* editing/Editor.h:
18+
* page/Page.cpp:
19+
(WebCore::Page::rangeOfString): Added. This function is similar to findString(), but it takes an optional
20+
reference range and returns a Range, rather than using the current selection as the reference range and setting the
21+
selection to the next match.
22+
* page/Page.h:
23+
124
2011-08-30 Sam Weinig <sam@webkit.org>
225

326
Add additional convertValue overloads to JSDictionary

Source/WebCore/WebCore.exp.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,7 @@ __ZN7WebCore4Page10findStringERKN3WTF6StringEj
699699
__ZN7WebCore4Page11PageClientsC1Ev
700700
__ZN7WebCore4Page11PageClientsD1Ev
701701
__ZN7WebCore4Page12setGroupNameERKN3WTF6StringE
702+
__ZN7WebCore4Page13rangeOfStringERKN3WTF6StringEPNS_5RangeEj
702703
__ZN7WebCore4Page14setMediaVolumeEf
703704
__ZN7WebCore4Page15addSchedulePairEN3WTF10PassRefPtrINS_12SchedulePairEEE
704705
__ZN7WebCore4Page15didMoveOnscreenEv

Source/WebCore/dom/Range.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,18 @@ class Range : public RefCounted<Range> {
9393
void detach(ExceptionCode&);
9494
PassRefPtr<Range> cloneRange(ExceptionCode&) const;
9595

96-
void setStartAfter(Node*, ExceptionCode&);
97-
void setEndBefore(Node*, ExceptionCode&);
98-
void setEndAfter(Node*, ExceptionCode&);
99-
void selectNode(Node*, ExceptionCode&);
96+
void setStartAfter(Node*, ExceptionCode& = ASSERT_NO_EXCEPTION);
97+
void setEndBefore(Node*, ExceptionCode& = ASSERT_NO_EXCEPTION);
98+
void setEndAfter(Node*, ExceptionCode& = ASSERT_NO_EXCEPTION);
99+
void selectNode(Node*, ExceptionCode& = ASSERT_NO_EXCEPTION);
100100
void selectNodeContents(Node*, ExceptionCode&);
101101
void surroundContents(PassRefPtr<Node>, ExceptionCode&);
102102
void setStartBefore(Node*, ExceptionCode&);
103103

104104
const Position startPosition() const { return m_start.toPosition(); }
105105
const Position endPosition() const { return m_end.toPosition(); }
106-
void setStart(const Position&, ExceptionCode&);
107-
void setEnd(const Position&, ExceptionCode&);
106+
void setStart(const Position&, ExceptionCode& = ASSERT_NO_EXCEPTION);
107+
void setEnd(const Position&, ExceptionCode& = ASSERT_NO_EXCEPTION);
108108

109109
Node* firstNode() const;
110110
Node* pastLastNode() const;

Source/WebCore/editing/Editor.cpp

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
2+
* Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
33
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -2913,90 +2913,96 @@ bool Editor::findString(const String& target, bool forward, bool caseFlag, bool
29132913

29142914
bool Editor::findString(const String& target, FindOptions options)
29152915
{
2916-
if (target.isEmpty())
2916+
VisibleSelection selection = m_frame->selection()->selection();
2917+
2918+
RefPtr<Range> resultRange = rangeOfString(target, selection.firstRange().get(), options);
2919+
2920+
if (!resultRange)
29172921
return false;
29182922

2923+
m_frame->selection()->setSelection(VisibleSelection(resultRange.get(), DOWNSTREAM));
2924+
m_frame->selection()->revealSelection();
2925+
return true;
2926+
}
2927+
2928+
PassRefPtr<Range> Editor::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
2929+
{
2930+
if (target.isEmpty())
2931+
return 0;
2932+
29192933
if (m_frame->excludeFromTextSearch())
2920-
return false;
2934+
return 0;
29212935

2922-
// Start from an edge of the selection, if there's a selection that's not in shadow content. Which edge
2936+
// Start from an edge of the reference range, if there's a reference range that's not in shadow content. Which edge
29232937
// is used depends on whether we're searching forward or backward, and whether startInSelection is set.
29242938
RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
2925-
VisibleSelection selection = m_frame->selection()->selection();
29262939

29272940
bool forward = !(options & Backwards);
2928-
bool startInSelection = options & StartInSelection;
2929-
if (forward)
2930-
setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd());
2931-
else
2932-
setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart());
2941+
bool startInReferenceRange = referenceRange && (options & StartInSelection);
2942+
if (referenceRange) {
2943+
if (forward)
2944+
searchRange->setStart(startInReferenceRange ? referenceRange->startPosition() : referenceRange->endPosition());
2945+
else
2946+
searchRange->setEnd(startInReferenceRange ? referenceRange->endPosition() : referenceRange->startPosition());
2947+
}
29332948

2934-
RefPtr<Node> shadowTreeRoot = selection.nonBoundaryShadowTreeRootNode();
2949+
RefPtr<Node> shadowTreeRoot = referenceRange && referenceRange->startContainer() ? referenceRange->startContainer()->nonBoundaryShadowTreeRootNode() : 0;
29352950
if (shadowTreeRoot) {
2936-
ExceptionCode ec = 0;
29372951
if (forward)
2938-
searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->childNodeCount(), ec);
2952+
searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->childNodeCount());
29392953
else
2940-
searchRange->setStart(shadowTreeRoot.get(), 0, ec);
2954+
searchRange->setStart(shadowTreeRoot.get(), 0);
29412955
}
29422956

29432957
RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, options));
2944-
// If we started in the selection and the found range exactly matches the existing selection, find again.
2958+
// If we started in the reference range and the found range exactly matches the reference range, find again.
29452959
// Build a selection with the found range to remove collapsed whitespace.
29462960
// Compare ranges instead of selection objects to ignore the way that the current selection was made.
2947-
if (startInSelection && areRangesEqual(VisibleSelection(resultRange.get()).toNormalizedRange().get(), selection.toNormalizedRange().get())) {
2961+
if (startInReferenceRange && areRangesEqual(VisibleSelection(resultRange.get()).toNormalizedRange().get(), referenceRange)) {
29482962
searchRange = rangeOfContents(m_frame->document());
29492963
if (forward)
2950-
setStart(searchRange.get(), selection.visibleEnd());
2964+
searchRange->setStart(referenceRange->endPosition());
29512965
else
2952-
setEnd(searchRange.get(), selection.visibleStart());
2966+
searchRange->setEnd(referenceRange->startPosition());
29532967

29542968
if (shadowTreeRoot) {
2955-
ExceptionCode ec = 0;
29562969
if (forward)
2957-
searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->childNodeCount(), ec);
2970+
searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->childNodeCount());
29582971
else
2959-
searchRange->setStart(shadowTreeRoot.get(), 0, ec);
2972+
searchRange->setStart(shadowTreeRoot.get(), 0);
29602973
}
29612974

29622975
resultRange = findPlainText(searchRange.get(), target, options);
29632976
}
29642977

2965-
ExceptionCode exception = 0;
2966-
29672978
// If nothing was found in the shadow tree, search in main content following the shadow tree.
2968-
if (resultRange->collapsed(exception) && shadowTreeRoot) {
2979+
if (resultRange->collapsed() && shadowTreeRoot) {
29692980
searchRange = rangeOfContents(m_frame->document());
29702981
if (forward)
2971-
searchRange->setStartAfter(shadowTreeRoot->shadowAncestorNode(), exception);
2982+
searchRange->setStartAfter(shadowTreeRoot->shadowAncestorNode());
29722983
else
2973-
searchRange->setEndBefore(shadowTreeRoot->shadowAncestorNode(), exception);
2984+
searchRange->setEndBefore(shadowTreeRoot->shadowAncestorNode());
29742985

29752986
resultRange = findPlainText(searchRange.get(), target, options);
29762987
}
29772988

29782989
if (!insideVisibleArea(resultRange.get())) {
29792990
resultRange = nextVisibleRange(resultRange.get(), target, options);
29802991
if (!resultRange)
2981-
return false;
2992+
return 0;
29822993
}
29832994

29842995
// If we didn't find anything and we're wrapping, search again in the entire document (this will
29852996
// redundantly re-search the area already searched in some cases).
2986-
if (resultRange->collapsed(exception) && options & WrapAround) {
2997+
if (resultRange->collapsed() && options & WrapAround) {
29872998
searchRange = rangeOfContents(m_frame->document());
29882999
resultRange = findPlainText(searchRange.get(), target, options);
29893000
// We used to return false here if we ended up with the same range that we started with
2990-
// (e.g., the selection was already the only instance of this text). But we decided that
3001+
// (e.g., the reference range was already the only instance of this text). But we decided that
29913002
// this should be a success case instead, so we'll just fall through in that case.
29923003
}
29933004

2994-
if (resultRange->collapsed(exception))
2995-
return false;
2996-
2997-
m_frame->selection()->setSelection(VisibleSelection(resultRange.get(), DOWNSTREAM));
2998-
m_frame->selection()->revealSelection();
2999-
return true;
3005+
return resultRange->collapsed() ? 0 : resultRange.release();
30003006
}
30013007

30023008
static bool isFrameInRange(Frame* frame, Range* range)

Source/WebCore/editing/Editor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,8 @@ class Editor {
335335
// FIXME: Switch callers over to the FindOptions version and retire this one.
336336
bool findString(const String&, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection);
337337

338+
PassRefPtr<Range> rangeOfString(const String&, Range*, FindOptions);
339+
338340
const VisibleSelection& mark() const; // Mark, to be used as emacs uses it.
339341
void setMark(const VisibleSelection&);
340342

Source/WebCore/page/Page.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,34 @@ bool Page::findString(const String& target, FindOptions options)
499499
return false;
500500
}
501501

502+
PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
503+
{
504+
if (target.isEmpty() || !mainFrame())
505+
return 0;
506+
507+
if (referenceRange && referenceRange->ownerDocument()->page() != this)
508+
return 0;
509+
510+
bool shouldWrap = options & WrapAround;
511+
Frame* frame = referenceRange ? referenceRange->ownerDocument()->frame() : mainFrame();
512+
Frame* startFrame = frame;
513+
do {
514+
if (RefPtr<Range> resultRange = frame->editor()->rangeOfString(target, frame == startFrame ? referenceRange : 0, (options & ~WrapAround) | StartInSelection))
515+
return resultRange.release();
516+
517+
frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
518+
} while (frame && frame != startFrame);
519+
520+
// Search contents of startFrame, on the other side of the reference range that we did earlier.
521+
// We cheat a bit and just search again with wrap on.
522+
if (shouldWrap && referenceRange) {
523+
if (RefPtr<Range> resultRange = startFrame->editor()->rangeOfString(target, referenceRange, options | WrapAround | StartInSelection))
524+
return resultRange.release();
525+
}
526+
527+
return 0;
528+
}
529+
502530
unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
503531
{
504532
return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit);

Source/WebCore/page/Page.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ namespace WebCore {
7575
class PageGroup;
7676
class PluginData;
7777
class ProgressTracker;
78+
class Range;
7879
class RenderTheme;
7980
class VisibleSelection;
8081
class ScrollableArea;
@@ -210,6 +211,9 @@ namespace WebCore {
210211
bool findString(const String&, FindOptions);
211212
// FIXME: Switch callers over to the FindOptions version and retire this one.
212213
bool findString(const String&, TextCaseSensitivity, FindDirection, bool shouldWrap);
214+
215+
PassRefPtr<Range> rangeOfString(const String&, Range*, FindOptions);
216+
213217
unsigned markAllMatchesForText(const String&, FindOptions, bool shouldHighlight, unsigned);
214218
// FIXME: Switch callers over to the FindOptions version and retire this one.
215219
unsigned markAllMatchesForText(const String&, TextCaseSensitivity, bool shouldHighlight, unsigned);

Source/WebKit/mac/ChangeLog

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
2011-08-30 Dan Bernstein <mitz@apple.com>
2+
3+
<rdar://problem/9281695> Add text search API for getting the DOM range of a text match
4+
https://bugs.webkit.org/show_bug.cgi?id=67230
5+
6+
Reviewed by Darin Adler.
7+
8+
* WebView/WebHTMLView.mm:
9+
* WebView/WebView.mm:
10+
(coreOptions): Moved this function from WebHTMLView.mm to here and made
11+
it accessible from both this file and WebHTMLView.mm.
12+
(-[WebView DOMRangeOfString:relativeTo:options:]): Added this new API.
13+
* WebView/WebViewInternal.h:
14+
* WebView/WebViewPrivate.h:
15+
116
2011-08-30 Beth Dakin <bdakin@apple.com>
217

318
https://bugs.webkit.org/show_bug.cgi?id=67150

Source/WebKit/mac/WebView/WebHTMLView.mm

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -534,16 +534,6 @@ static NSCellStateValue kit(TriState state)
534534
return NSOffState;
535535
}
536536

537-
static FindOptions coreOptions(WebFindOptions options)
538-
{
539-
return (options & WebFindOptionsCaseInsensitive ? CaseInsensitive : 0)
540-
| (options & WebFindOptionsAtWordStarts ? AtWordStarts : 0)
541-
| (options & WebFindOptionsTreatMedialCapitalAsWordStart ? TreatMedialCapitalAsWordStart : 0)
542-
| (options & WebFindOptionsBackwards ? Backwards : 0)
543-
| (options & WebFindOptionsWrapAround ? WrapAround : 0)
544-
| (options & WebFindOptionsStartInSelection ? StartInSelection : 0);
545-
}
546-
547537
@implementation WebHTMLViewPrivate
548538

549539
+ (void)initialize

Source/WebKit/mac/WebView/WebView.mm

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,16 @@ @interface _WebSafeForwarder : NSObject
374374
- (id)initWithTarget:(id)target defaultTarget:(id)defaultTarget catchExceptions:(BOOL)catchExceptions;
375375
@end
376376

377+
FindOptions coreOptions(WebFindOptions options)
378+
{
379+
return (options & WebFindOptionsCaseInsensitive ? CaseInsensitive : 0)
380+
| (options & WebFindOptionsAtWordStarts ? AtWordStarts : 0)
381+
| (options & WebFindOptionsTreatMedialCapitalAsWordStart ? TreatMedialCapitalAsWordStart : 0)
382+
| (options & WebFindOptionsBackwards ? Backwards : 0)
383+
| (options & WebFindOptionsWrapAround ? WrapAround : 0)
384+
| (options & WebFindOptionsStartInSelection ? StartInSelection : 0);
385+
}
386+
377387
@interface WebView (WebFileInternal)
378388
- (float)_deviceScaleFactor;
379389
- (BOOL)_isLoading;
@@ -4547,6 +4557,14 @@ - (BOOL)findString:(NSString *)string options:(WebFindOptions)options
45474557
return NO;
45484558
}
45494559

4560+
- (DOMRange *)DOMRangeOfString:(NSString *)string relativeTo:(DOMRange *)previousRange options:(WebFindOptions)options
4561+
{
4562+
if (!_private->page)
4563+
return nil;
4564+
4565+
return kit(_private->page->rangeOfString(string, core(previousRange), coreOptions(options)).get());
4566+
}
4567+
45504568
- (void)setHoverFeedbackSuspended:(BOOL)newValue
45514569
{
45524570
if (_private->hoverFeedbackSuspended == newValue)

0 commit comments

Comments
 (0)