diff options
author | finnur@google.com <finnur@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-24 23:46:50 +0000 |
---|---|---|
committer | finnur@google.com <finnur@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-24 23:46:50 +0000 |
commit | 884db41554423ec017c57709f92cc2379e0cc02d (patch) | |
tree | 275e81e0c6ab0717912dd4864d91ad719bd2a55c /webkit/glue | |
parent | 498c1a6b2dc98869e0703127565247830227d075 (diff) | |
download | chromium_src-884db41554423ec017c57709f92cc2379e0cc02d.zip chromium_src-884db41554423ec017c57709f92cc2379e0cc02d.tar.gz chromium_src-884db41554423ec017c57709f92cc2379e0cc02d.tar.bz2 |
Find now uses WebKit's TextMatch highlighting for Find-in-page.
This allows us to discard a bunch of code and plumbing related to
maintaining and passing around the tickmark vector.
WebKit now owns the drawing of the highlights for inactive matches and
we use the selection controller to draw the active highlight.
I also simplified the code by eliminating the separate FindNext
function, which has been merged into Find.
This change also requires minor changes to WebKit upstream (sold
seperately, void where prohibited).
It simply consists of adding one empty virtual paint function to
ScrollbarThemeComposite.h (paintTickmarks) and in
ScrollbarThemeComposite::paint call paintTickmarks().
This fixes/makes obsolete a slew of bugs:
BUG=1326399, 1241554,1143991, 1070190, 1023019, 984786, 893737, 868599
... and a couple of external ones as well. Full list:
1326399 Find highlighting disappears on ThinkPad x60s
1241554 Find doesn't highlight word inside blinky tag
1143991 Have find-in-page code use skia and have inspected node highlighting set the right xfermode
1070190 Find should begin searching from caret/selection
1023019 Find not highlighting correctly
984786 Find highlight drawing code causes ClearType text to look bad
893737 Find in page should search textareas
868599 Find in page tick marks incorrectly appear on nested scrollbars
298 Find-In-page should highlight elided entries
4389 Find-in-box is not highlighting all the instances of the search word
3908 Find in page highlighting and tickmarks are broken
Review URL: http://codereview.chromium.org/11364
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@5946 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue')
-rw-r--r-- | webkit/glue/webframe.h | 10 | ||||
-rw-r--r-- | webkit/glue/webframe_impl.cc | 466 | ||||
-rw-r--r-- | webkit/glue/webframe_impl.h | 73 | ||||
-rw-r--r-- | webkit/glue/webview_impl.cc | 23 | ||||
-rw-r--r-- | webkit/glue/webview_impl.h | 3 | ||||
-rw-r--r-- | webkit/glue/webwidget_impl.cc | 9 |
6 files changed, 217 insertions, 367 deletions
diff --git a/webkit/glue/webframe.h b/webkit/glue/webframe.h index 2962173..1a8d19e 100644 --- a/webkit/glue/webframe.h +++ b/webkit/glue/webframe.h @@ -197,16 +197,6 @@ class WebFrame : public base::RefCounted<WebFrame> { bool wrap_within_frame, gfx::Rect* selection_rect) = 0; - // Searches a frame for the next (or previous occurrence of a given string. - // - // This function works similarly to Find (documented above), except that it - // uses an index into the tick-mark vector to figure out what the next - // match is, alleviating the need to call findString on the content again. - // - // Returns true if the search string was found, false otherwise. - virtual bool FindNext(const FindInPageRequest& request, - bool wrap_within_frame) = 0; - // Notifies the frame that we are no longer interested in searching. This will // abort any asynchronous scoping effort already under way (see the function // ScopeStringMatches for details) and erase all tick-marks and highlighting diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc index ecd839b..e3f9d47 100644 --- a/webkit/glue/webframe_impl.cc +++ b/webkit/glue/webframe_impl.cc @@ -80,6 +80,7 @@ MSVC_PUSH_WARNING_LEVEL(0); #include "Document.h" #include "DocumentFragment.h" // Only needed for ReplaceSelectionCommand.h :( #include "DocumentLoader.h" +#include "DocumentMarker.h" #include "DOMWindow.h" #include "Editor.h" #include "EventHandler.h" @@ -97,6 +98,9 @@ MSVC_PUSH_WARNING_LEVEL(0); #include "Page.h" #include "PlatformContextSkia.h" #include "RenderFrame.h" +#if defined(OS_WIN) +#include "RenderThemeWin.h" +#endif #include "RenderWidget.h" #include "ReplaceSelectionCommand.h" #include "ResourceHandle.h" @@ -178,11 +182,6 @@ using WebCore::TextIterator; using WebCore::VisiblePosition; using WebCore::XPathResult; -// TODO(darin): This used to be defined on WidgetClientChromium, but that -// interface no longer exists. We'll need to come up with something better -// once we figure out how to make tickmark support work again! -static const size_t kNoTickmark = size_t(-1); - // Key for a StatsCounter tracking how many WebFrames are active. static const char* const kWebFrameActiveCount = "WebFrameActiveCount"; @@ -278,10 +277,10 @@ MSVC_POP_WARNING() currently_loading_request_(NULL), plugin_delegate_(NULL), inspected_node_(NULL), - active_tickmark_frame_(NULL), - active_tickmark_(kNoTickmark), + active_match_frame_(NULL), + active_match_index_(-1), locating_active_rect_(false), - last_active_range_(NULL), + resume_scoping_from_range_(NULL), last_match_count_(-1), total_matchcount_(-1), frames_scoping_count_(-1), @@ -769,18 +768,6 @@ void WebFrameImpl::InvalidateArea(AreaToInvalidate area) { #endif } -void WebFrameImpl::InvalidateTickmark(RefPtr<WebCore::Range> tickmark) { - ASSERT(frame() && frame()->view()); -#if defined(OS_WIN) - // TODO(pinkerton): Fix Mac invalidation to be more like Win ScrollView - FrameView* view = frame()->view(); - - IntRect pos = tickmark->boundingBox(); - pos.move(-view->scrollX(), -view->scrollY()); - view->invalidateRect(pos); -#endif -} - void WebFrameImpl::IncreaseMatchCount(int count, int request_id) { total_matchcount_ += count; @@ -817,34 +804,29 @@ bool WebFrameImpl::Find(const FindInPageRequest& request, WebCore::String webcore_string = webkit_glue::StdWStringToString(request.search_string); + WebFrameImpl* const main_frame_impl = + static_cast<WebFrameImpl*>(GetView()->GetMainFrame()); + + if (!request.find_next) + frame()->page()->unmarkAllTextMatches(); + // Starts the search from the current selection. - bool start_in_selection = true; // Policy. Can it be made configurable? - - // If the user has selected something since the last Find operation we want - // to start from there. Otherwise, we start searching from where the last Find - // operation left off (either a Find or a FindNext operation). - Selection selection(frame()->selection()->selection()); - if (selection.isNone() && last_active_range_) { - selection = Selection(last_active_range_.get()); - frame()->selection()->setSelection(selection); - } + bool start_in_selection = true; DCHECK(frame() && frame()->view()); bool found = frame()->findString(webcore_string, request.forward, request.match_case, wrap_within_frame, start_in_selection); - // If we find something on the page, we'll need to have the scoping effort - // locate it so that we can highlight it as active. - locating_active_rect_ = found; - if (found) { - // Set this frame as the active frame (the one with the active tick-mark). - WebFrameImpl* const main_frame_impl = - static_cast<WebFrameImpl*>(GetView()->GetMainFrame()); - main_frame_impl->active_tickmark_frame_ = this; +#if defined(OS_WIN) + WebCore::RenderThemeWin::setFindInPageMode(true); +#endif + // Set this frame as the active frame (the one with the active highlight). + main_frame_impl->active_match_frame_ = this; // We found something, so we can now query the selection for its position. Selection new_selection(frame()->selection()->selection()); + IntRect curr_selection_rect; // If we thought we found something, but it couldn't be selected (perhaps // because it was marked -webkit-user-select: none), we can't set it to @@ -853,151 +835,62 @@ bool WebFrameImpl::Find(const FindInPageRequest& request, // are mixed on a page: see https://bugs.webkit.org/show_bug.cgi?id=19127. if (new_selection.isNone() || (new_selection.start() == new_selection.end())) { - // The selection controller is not giving us a valid selection so we don't - // know what the active rect is. The scoping effort should still continue, - // in case there are other selectable matches on the page. Setting the - // active_selection_rect to a default rect causes the scoping effort to - // mark the first match it finds as active and continue scoping. - active_selection_rect_ = IntRect(); - last_active_range_ = new_selection.toRange(); - *selection_rect = gfx::Rect(); + active_match_ = NULL; } else { - last_active_range_ = new_selection.toRange(); - active_selection_rect_ = new_selection.toRange()->boundingBox(); - // TODO(finnur): Uncomment this when bug http://crbug.com/3908 is fixed. - // ClearSelection(); // We'll draw our own highlight for the active item. - -#if defined(OS_WIN) - // TODO(pinkerton): Fix Mac scrolling to be more like Win ScrollView - if (selection_rect) { - gfx::Rect rect = webkit_glue::FromIntRect( - frame()->view()->convertToContainingWindow(active_selection_rect_)); - rect.Offset(-frameview()->scrollOffset().width(), - -frameview()->scrollOffset().height()); - *selection_rect = rect; - } -#endif + active_match_ = new_selection.toRange(); + curr_selection_rect = active_match_->boundingBox(); } - } - if (!found) { - active_selection_rect_ = IntRect(); - last_active_range_ = NULL; - - if (!tickmarks_.isEmpty()) { - // Let the frame know that we found no matches. - tickmarks_.clear(); - // Erase all previous tickmarks and highlighting. - InvalidateArea(INVALIDATE_ALL); + if (!request.find_next) { + // This is a Find operation, so we set the flag to ask the scoping effort + // to find the active rect for us so we can update the ordinal (n of m). + locating_active_rect_ = true; + } else { + // This is FindNext so we need to increment (or decrement) the count and + // wrap if needed. + request.forward ? ++active_match_index_ : --active_match_index_; + if (active_match_index_ + 1 > last_match_count_) + active_match_index_ = 0; + if (active_match_index_ + 1 == 0) + active_match_index_ = last_match_count_ - 1; } - } - - return found; -} - -bool WebFrameImpl::FindNext(const FindInPageRequest& request, - bool wrap_within_frame) { - if (tickmarks_.isEmpty()) - return false; - - // Save the old tickmark (if any). We will use this to invalidate the area - // of the tickmark that becomes unselected. - WebFrameImpl* const main_frame_impl = - static_cast<WebFrameImpl*>(GetView()->GetMainFrame()); - WebFrameImpl* const active_frame = main_frame_impl->active_tickmark_frame_; - RefPtr<WebCore::Range> old_tickmark = NULL; - if (active_frame && - (active_frame->active_tickmark_ != kNoTickmark)) { - // When we get a reference to |old_tickmark| we can be in a state where - // the |active_tickmark_| points outside the tickmark vector, possibly - // during teardown of the frame. This doesn't reproduce normally, so if you - // hit this during debugging, update issue http://b/1277569 with - // reproduction steps - or contact the assignee. In release, we can ignore - // this and continue on (and let |old_tickmark| be null). - if (active_frame->active_tickmark_ >= active_frame->tickmarks_.size()) - NOTREACHED() << L"Active tickmark points outside the tickmark vector!"; - else - old_tickmark = active_frame->tickmarks_[active_frame->active_tickmark_]; - } - // See if we have another match to select, and select it. - if (request.forward) { - const bool at_end = (active_tickmark_ == (tickmarks_.size() - 1)); - if ((active_tickmark_ == kNoTickmark) || - (at_end && wrap_within_frame)) { - // Wrapping within a frame is only done for single frame pages. So when we - // reach the end we go back to the beginning (or back to the end if - // searching backwards). - active_tickmark_ = 0; - } else if (at_end) { - return false; - } else { - ++active_tickmark_; - DCHECK(active_tickmark_ < tickmarks_.size()); +#if defined(OS_WIN) + // TODO(pinkerton): Fix Mac scrolling to be more like Win ScrollView + if (selection_rect) { + gfx::Rect rect = webkit_glue::FromIntRect( + frame()->view()->convertToContainingWindow(curr_selection_rect)); + rect.Offset(-frameview()->scrollOffset().width(), + -frameview()->scrollOffset().height()); + *selection_rect = rect; + + ReportFindInPageSelection(rect, + active_match_index_ + 1, + request.request_id); } +#endif } else { - const bool at_end = (active_tickmark_ == 0); - if ((active_tickmark_ == kNoTickmark) || - (at_end && wrap_within_frame)) { - // Wrapping within a frame is not done for multi-frame pages, but if no - // tickmark is active we still need to set the index to the end so that - // we don't skip the frame during FindNext when searching backwards. - active_tickmark_ = tickmarks_.size() - 1; - } else if (at_end) { - return false; - } else { - --active_tickmark_; - DCHECK(active_tickmark_ < tickmarks_.size()); - } - } + // Nothing was found in this frame. + active_match_ = NULL; - if (active_frame != this) { - // If we are jumping between frames, reset the active tickmark in the old - // frame and invalidate the area. - active_frame->active_tickmark_ = kNoTickmark; - active_frame->InvalidateArea(INVALIDATE_CONTENT_AREA); - main_frame_impl->active_tickmark_frame_ = this; - } else { - // Invalidate the old tickmark. - if (old_tickmark) - active_frame->InvalidateTickmark(old_tickmark); + // Erase all previous tickmarks and highlighting. + InvalidateArea(INVALIDATE_ALL); } - Selection selection(tickmarks_[active_tickmark_].get()); - frame()->selection()->setSelection(selection); - frame()->revealSelection(); // Scroll the selection into view if necessary. - // Make sure we save where the selection was after the operation so that - // we can set the selection to it for the next Find operation (if needed). - last_active_range_ = tickmarks_[active_tickmark_]; - // TODO(finnur): Uncomment this when bug http://crbug.com/3908 is fixed. - // ClearSelection(); // We will draw our own highlighting. - -#if defined(OS_WIN) - // TODO(pinkerton): Fix Mac invalidation to be more like Win ScrollView - // Notify browser of new location for the selected rectangle. - IntRect pos = tickmarks_[active_tickmark_]->boundingBox(); - pos.move(-frameview()->scrollOffset().width(), - -frameview()->scrollOffset().height()); - ReportFindInPageSelection( - webkit_glue::FromIntRect(frame()->view()->convertToContainingWindow(pos)), - active_tickmark_ + 1, - request.request_id); -#endif - - return true; // Found a match. + return found; } int WebFrameImpl::OrdinalOfFirstMatchForFrame(WebFrameImpl* frame) const { int ordinal = 0; WebFrameImpl* const main_frame_impl = static_cast<WebFrameImpl*>(GetView()->GetMainFrame()); - // Iterate from the main frame up to (but not including) this frame and - // add up the number of tickmarks. - for (WebFrameImpl* frame = main_frame_impl; - frame != this; - frame = static_cast<WebFrameImpl*>( - webview_impl_->GetNextFrameAfter(frame, true))) { - ordinal += frame->tickmarks().size(); + // Iterate from the main frame up to (but not including) |frame| and + // add up the number of matches found so far. + for (WebFrameImpl* it = main_frame_impl; + it != frame; + it = static_cast<WebFrameImpl*>( + webview_impl_->GetNextFrameAfter(it, true))) { + ordinal += it->last_match_count_; } return ordinal; @@ -1042,54 +935,66 @@ void WebFrameImpl::InvalidateIfNecessary() { int i = (last_match_count_ / start_slowing_down_after); next_invalidate_after_ += i * slowdown; - // Invalidating content area draws both highlighting and in-page - // tickmarks, but not the scrollbar. - // TODO(finnur): (http://b/1088165) invalidate content area only if - // match found on-screen. - InvalidateArea(INVALIDATE_CONTENT_AREA); InvalidateArea(INVALIDATE_SCROLLBAR); } } -// static -bool WebFrameImpl::RangeShouldBeHighlighted(Range* range) { - ExceptionCode exception = 0; - Node* common_ancestor_container = range->commonAncestorContainer(exception); - - if (exception) - return false; - - RenderObject* renderer = common_ancestor_container->renderer(); - - if (!renderer) - return false; - - IntRect overflow_clip_rect = renderer->absoluteClippedOverflowRect(); - return range->boundingBox().intersects(overflow_clip_rect); -} - void WebFrameImpl::selectNodeFromInspector(WebCore::Node* node) { inspected_node_ = node; } +void WebFrameImpl::AddMarker(WebCore::Range* range) { + // Use a TextIterator to visit the potentially multiple nodes the range + // covers. + TextIterator markedText(range); + for (; !markedText.atEnd(); markedText.advance()) { + RefPtr<Range> textPiece = markedText.range(); + int exception = 0; + + WebCore::DocumentMarker marker = { + WebCore::DocumentMarker::TextMatch, + textPiece->startOffset(exception), + textPiece->endOffset(exception), + "" }; + + // Find the node to add a marker to and add it. + Node* node = textPiece->startContainer(exception); + frame()->document()->addMarker(node, marker); + + // Rendered rects for markers in WebKit are not populated until each time + // the markers are painted. However, we need it to happen sooner, because + // the whole purpose of tickmarks on the scrollbar is to show where matches + // off-screen are (that haven't been painted yet). + Vector<WebCore::DocumentMarker> markers = + frame()->document()->markersForNode(node); + frame()->document()->setRenderedRectForMarker( + textPiece->startContainer(exception), + markers[markers.size() - 1], + range->boundingBox()); + } +} + void WebFrameImpl::ScopeStringMatches(FindInPageRequest request, bool reset) { if (!ShouldScopeMatches(request)) return; WebFrameImpl* main_frame_impl = - static_cast<WebFrameImpl*>(GetView()->GetMainFrame()); + static_cast<WebFrameImpl*>(GetView()->GetMainFrame()); if (reset) { // This is a brand new search, so we need to reset everything. // Scoping is just about to begin. scoping_complete_ = false; - // First of all, all previous tickmarks need to be erased. - tickmarks_.clear(); + // Clear highlighting for this frame. + if (frame()->markedTextMatchesAreHighlighted()) + frame()->page()->unmarkAllTextMatches(); // Clear the counters from last operation. last_match_count_ = 0; next_invalidate_after_ = 0; + resume_scoping_from_range_ = NULL; + main_frame_impl->frames_scoping_count_++; // Now, defer scoping until later to allow find operation to finish quickly. @@ -1104,15 +1009,15 @@ void WebFrameImpl::ScopeStringMatches(FindInPageRequest request, WebCore::String webcore_string = webkit_glue::StdWStringToString(request.search_string); - RefPtr<Range> searchRange(rangeOfContents(frame()->document())); + RefPtr<Range> search_range(rangeOfContents(frame()->document())); ExceptionCode ec = 0, ec2 = 0; - if (!reset && !tickmarks_.isEmpty()) { + if (!reset && resume_scoping_from_range_.get()) { // This is a continuation of a scoping operation that timed out and didn't // complete last time around, so we should start from where we left off. - RefPtr<Range> start_range = tickmarks_.last(); - searchRange->setStart(start_range->startContainer(), - start_range->startOffset(ec2) + 1, ec); + search_range->setStart(resume_scoping_from_range_->startContainer(), + resume_scoping_from_range_->startOffset(ec2) + 1, + ec); if (ec != 0 || ec2 != 0) { NOTREACHED(); return; @@ -1124,7 +1029,7 @@ void WebFrameImpl::ScopeStringMatches(FindInPageRequest request, // is periodically checked to see if we have exceeded our allocated time. static const int kTimeout = 100; // ms - int matchCount = 0; + int match_count = 0; bool timeout = false; Time start_time = Time::Now(); do { @@ -1133,69 +1038,79 @@ void WebFrameImpl::ScopeStringMatches(FindInPageRequest request, // for longer than the timeout value, and is not interruptible as it is // currently written. We may need to rewrite it with interruptibility in // mind, or find an alternative. - RefPtr<Range> resultRange(findPlainText(searchRange.get(), + RefPtr<Range> result_range(findPlainText(search_range.get(), webcore_string, true, request.match_case)); - if (resultRange->collapsed(ec)) - break; // no further matches. + if (result_range->collapsed(ec)) { + if (!result_range->startContainer()->isInShadowTree()) + break; + + search_range = rangeOfContents(frame()->document()); + search_range->setStartAfter( + result_range->startContainer()->shadowAncestorNode(), ec); + continue; + } // A non-collapsed result range can in some funky whitespace cases still not // advance the range's start position (4509328). Break to avoid infinite - // loop. (This function is based on the implementation of Frame::FindString, - // which is where this safeguard comes from). - VisiblePosition newStart = - endVisiblePosition(resultRange.get(), WebCore::DOWNSTREAM); - if (newStart == - startVisiblePosition(searchRange.get(), WebCore::DOWNSTREAM)) + // loop. (This function is based on the implementation of + // Frame::markAllMatchesForText, which is where this safeguard comes from). + VisiblePosition new_start = endVisiblePosition(result_range.get(), + WebCore::DOWNSTREAM); + if (new_start == startVisiblePosition(search_range.get(), + WebCore::DOWNSTREAM)) break; - ++matchCount; - - // Add the location we just found to the tickmarks collection. - tickmarks_.append(resultRange); - - setStart(searchRange.get(), newStart); - - // Catch a special case where Find found something but doesn't know - // what the bounding box for it is. In this case we set the first match - // we find as the active rect. Note: This does not affect FindNext, it will - // still do the right thing. This is only affecting the initial Find, so if - // you start searching from the middle of the page AND there is a match - // below AND we don't have a bounding box for that match, then we will mark - // the first match as active. We probably should look into converting Find - // to use the same function as the scoping effort (findPlainText), since it - // seems to always get the right bounding box. - IntRect result_bounds = resultRange->boundingBox(); - if (locating_active_rect_ && active_selection_rect_.isEmpty()) { - active_selection_rect_ = result_bounds; - } - - // If the Find function found a match it will have stored where the - // match was found in active_selection_rect_ on the current frame. If we - // find this rect during scoping it means we have found the active - // tickmark. - if (locating_active_rect_ && (active_selection_rect_ == result_bounds)) { - // We have found the active tickmark frame. - main_frame_impl->active_tickmark_frame_ = this; - // We also know which tickmark is active now. - active_tickmark_ = tickmarks_.size() - 1; - // To stop looking for the active tickmark, we set this flag. - locating_active_rect_ = false; + // Only treat the result as a match if it is visible + if (frame()->editor()->insideVisibleArea(result_range.get())) { + ++match_count; + + AddMarker(result_range.get()); + + setStart(search_range.get(), new_start); + Node* shadow_tree_root = search_range->shadowTreeRootNode(); + if (search_range->collapsed(ec) && shadow_tree_root) + search_range->setEnd(shadow_tree_root, + shadow_tree_root->childNodeCount(), ec); + + // Catch a special case where Find found something but doesn't know what + // the bounding box for it is. In this case we set the first match we find + // as the active rect. + IntRect result_bounds = result_range->boundingBox(); + IntRect active_selection_rect; + if (locating_active_rect_) { + active_selection_rect = active_match_.get() ? + active_match_->boundingBox() : result_bounds; + } -#if defined(OS_WIN) - // TODO(pinkerton): Fix Mac invalidation to be more like Win ScrollView - // Notify browser of new location for the selected rectangle. - IntRect pos = tickmarks_[active_tickmark_]->boundingBox(); - pos.move(-frameview()->scrollOffset().width(), - -frameview()->scrollOffset().height()); - ReportFindInPageSelection( - webkit_glue::FromIntRect(frame()->view()->convertToContainingWindow(pos)), - active_tickmark_ + 1, - request.request_id); -#endif + // If the Find function found a match it will have stored where the + // match was found in active_selection_rect_ on the current frame. If we + // find this rect during scoping it means we have found the active + // tickmark. + if (locating_active_rect_ && (active_selection_rect == result_bounds)) { + // We have found the active tickmark frame. + main_frame_impl->active_match_frame_ = this; + // We also know which tickmark is active now. + active_match_index_ = match_count - 1; + // To stop looking for the active tickmark, we set this flag. + locating_active_rect_ = false; + + #if defined(OS_WIN) + // TODO(pinkerton): Fix Mac invalidation to be more like Win ScrollView + // Notify browser of new location for the selected rectangle. + result_bounds.move(-frameview()->scrollOffset().width(), + -frameview()->scrollOffset().height()); + ReportFindInPageSelection( + webkit_glue::FromIntRect( + frame()->view()->convertToContainingWindow(result_bounds)), + OrdinalOfFirstMatchForFrame(this) + active_match_index_ + 1, + request.request_id); + #endif + } } + resume_scoping_from_range_ = result_range; timeout = (Time::Now() - start_time).InMilliseconds() >= kTimeout; } while (!timeout); @@ -1203,18 +1118,20 @@ void WebFrameImpl::ScopeStringMatches(FindInPageRequest request, // letters are added to the search string (and last outcome was 0). last_search_string_ = request.search_string; - if (matchCount > 0) { - last_match_count_ += matchCount; + if (match_count > 0) { + frame()->setMarkedTextMatchesAreHighlighted(true); + + last_match_count_ += match_count; // Let the mainframe know how much we found during this pass. - main_frame_impl->IncreaseMatchCount(matchCount, request.request_id); + main_frame_impl->IncreaseMatchCount(match_count, request.request_id); } if (timeout) { // If we found anything during this pass, we should redraw. However, we // don't want to spam too much if the page is extremely long, so if we // reach a certain point we start throttling the redraw requests. - if (matchCount > 0) + if (match_count > 0) InvalidateIfNecessary(); // Scoping effort ran out of time, lets ask for another time-slice. @@ -1237,28 +1154,29 @@ void WebFrameImpl::ScopeStringMatches(FindInPageRequest request, if (main_frame_impl->frames_scoping_count_ == 0) main_frame_impl->IncreaseMatchCount(0, request.request_id); - // This frame is done, so show any tickmark/highlight we haven't drawn yet. - InvalidateArea(INVALIDATE_ALL); + // This frame is done, so show any scrollbar tickmarks we haven't drawn yet. + InvalidateArea(INVALIDATE_SCROLLBAR); return; } void WebFrameImpl::CancelPendingScopingEffort() { scope_matches_factory_.RevokeAll(); - active_tickmark_ = kNoTickmark; + active_match_index_ = -1; } void WebFrameImpl::SetFindEndstateFocusAndSelection() { WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(GetView()->GetMainFrame()); - if (this == main_frame_impl->active_tickmark_frame() && - active_tickmark_ != kNoTickmark) { - RefPtr<Range> range = tickmarks_[active_tickmark_]; - - // Set the selection to what the active match is. - frame()->selection()->setSelectedRange( - range.get(), WebCore::DOWNSTREAM, false); + if (this == main_frame_impl->active_match_frame() && + active_match_.get()) { + // If the user has changed the selection since the match was found, we + // don't focus anything. + Selection selection(frame()->selection()->selection()); + if (selection.isNone() || (selection.start() == selection.end()) || + active_match_->boundingBox() != selection.toRange()->boundingBox()) + return; // We will be setting focus ourselves, so we want the view to forget its // stored focus node so that it won't change it after we are done. @@ -1266,7 +1184,7 @@ void WebFrameImpl::SetFindEndstateFocusAndSelection() { // Try to find the first focusable node up the chain, which will, for // example, focus links if we have found text within the link. - Node* node = range->firstNode(); + Node* node = active_match_->firstNode(); while (node && !node->isFocusable() && node != frame()->document()) node = node->parent(); @@ -1277,8 +1195,8 @@ void WebFrameImpl::SetFindEndstateFocusAndSelection() { // Iterate over all the nodes in the range until we find a focusable node. // This, for example, sets focus to the first link if you search for // text and text that is within one or more links. - node = range->firstNode(); - while (node && node != range->pastLastNode()) { + node = active_match_->firstNode(); + while (node && node != active_match_->pastLastNode()) { if (node->isFocusable()) { frame()->document()->setFocusedNode(node); break; @@ -1294,8 +1212,16 @@ void WebFrameImpl::StopFinding(bool clear_selection) { SetFindEndstateFocusAndSelection(); CancelPendingScopingEffort(); +#if defined(OS_WIN) + WebCore::RenderThemeWin::setFindInPageMode(false); +#endif + + // Remove all markers for matches found and turn off the highlighting. + if (this == static_cast<WebFrameImpl*>(GetView()->GetMainFrame())) + frame()->document()->removeMarkers(WebCore::DocumentMarker::TextMatch); + frame()->setMarkedTextMatchesAreHighlighted(false); + // Let the frame know that we don't want tickmarks or highlighting anymore. - tickmarks_.clear(); InvalidateArea(INVALIDATE_ALL); } @@ -1607,7 +1533,7 @@ void WebFrameImpl::LoadAlternateHTMLErrorPage(const WebRequest* request, void WebFrameImpl::ExecuteJavaScript(const std::string& js_code, const std::string& script_url) { frame_->loader()->executeScript(webkit_glue::StdStringToString(script_url), - 1, // base line number (for errors) + 1, // base line number (for errors) webkit_glue::StdStringToString(js_code)); } @@ -1705,7 +1631,7 @@ PassRefPtr<Frame> WebFrameImpl::CreateChildFrame( } } } - + child_frame->loader()->loadURL( new_url, request.resourceRequest().httpReferrer(), request.frameName(), child_load_type, 0, 0); diff --git a/webkit/glue/webframe_impl.h b/webkit/glue/webframe_impl.h index fefe2ba..497b698 100644 --- a/webkit/glue/webframe_impl.h +++ b/webkit/glue/webframe_impl.h @@ -126,8 +126,6 @@ class WebFrameImpl : public WebFrame { virtual bool Find(const FindInPageRequest& request, bool wrap_within_frame, gfx::Rect* selection_rect); - virtual bool FindNext(const FindInPageRequest& request, - bool wrap_within_frame); virtual void StopFinding(bool clear_selection); virtual void ScopeStringMatches(FindInPageRequest request, bool reset); virtual void CancelPendingScopingEffort(); @@ -226,31 +224,17 @@ class WebFrameImpl : public WebFrame { WebDataSourceImpl* GetDataSourceImpl() const; WebDataSourceImpl* GetProvisionalDataSourceImpl() const; - // Gets the tickmarks for drawing on the scrollbars of a particular frame. - const Vector<RefPtr<WebCore::Range> >& tickmarks() const { - return tickmarks_; - } - - // Returns whether a range representing a tickmark should be highlighted. - // We use this to avoid highlighting ranges that are currently hidden. - static bool RangeShouldBeHighlighted(WebCore::Range* range); - const WebCore::Node* inspected_node() const { return inspected_node_; } void selectNodeFromInspector(WebCore::Node* node); - // Returns which frame has an active tickmark. This function should only be + // Returns which frame has an active match. This function should only be // called on the main frame, as it is the only frame keeping track. Returned - // value can be NULL if no frame has an active tickmark. - const WebFrameImpl* active_tickmark_frame() const { - return active_tickmark_frame_; - } - - // Returns the index of the active tickmark for this frame. - size_t active_tickmark_index() const { - return active_tickmark_; + // value can be NULL if no frame has an active match. + const WebFrameImpl* active_match_frame() const { + return active_match_frame_; } // When a Find operation ends, we want to set the selection to what was active @@ -345,39 +329,24 @@ class WebFrameImpl : public WebFrame { // The node selected in the web inspector. Used for highlighting it on the page. WebCore::Node* inspected_node_; - // This vector maintains a list of Ranges representing locations for search - // string matches that were found in the frame during a FindInPage operation. - Vector<RefPtr<WebCore::Range> > tickmarks_; - // A way for the main frame to keep track of which frame has an active - // tickmark. Should be NULL for all other frames. - WebFrameImpl* active_tickmark_frame_; + // match. Should be NULL for all other frames. + WebFrameImpl* active_match_frame_; + + // The range of the active match for the current frame. + RefPtr<WebCore::Range> active_match_; - // The index of the active tickmark for the current frame. - size_t active_tickmark_; + // The index of the active match. + size_t active_match_index_; // This flag is used by the scoping effort to determine if we need to figure - // out which rectangle is the active tickmark. Once we find the active + // out which rectangle is the active match. Once we find the active // rectangle we clear this flag. bool locating_active_rect_; - // This rectangle is used during the scoping effort to figure out what rect - // got selected during the Find operation. In other words, first the Find - // operation iterates to the next match and then scoping will happen for all - // matches. When we encounter this rectangle during scoping we mark that - // tickmark as active (see active_tickmark_). This avoids having to iterate - // through a potentially very large tickmark vector to see which hit is - // active. An empty rect means that we don't know the rectangle for the - // selection (ie. because the selection controller couldn't tell us what the - // bounding box for it is) and the scoping effort should mark the first - // match it finds as the active rectangle. - WebCore::IntRect active_selection_rect_; - - // This range represents the range that got selected during the Find or - // FindNext operation. We will set this range as the selection (unless the - // user selects something between Find/FindNext operations) so that we can - // continue from where we left off. - RefPtr<WebCore::Range> last_active_range_; + // The scoping effort can time out and we need to keep track of where we + // ended our last search so we can continue from where we left of. + RefPtr<WebCore::Range> resume_scoping_from_range_; // Keeps track of the last string this frame searched for. This is used for // short-circuiting searches in the following scenarios: When a frame has @@ -389,12 +358,12 @@ class WebFrameImpl : public WebFrame { // don't loose count between scoping efforts, and is also used (in conjunction // with last_search_string_ and scoping_complete_) to figure out if we need to // search the frame again. - int last_match_count_; + size_t last_match_count_; // This variable keeps a cumulative total of matches found so far for ALL the // frames on the page, and is only incremented by calling IncreaseMatchCount // (on the main frame only). It should be -1 for all other frames. - int total_matchcount_; + size_t total_matchcount_; // This variable keeps a cumulative total of how many frames are currently // scoping, and is incremented/decremented on the main frame only. @@ -407,7 +376,7 @@ class WebFrameImpl : public WebFrame { // Keeps track of when the scoping effort should next invalidate the scrollbar // and the frame area. - int next_invalidate_after_; + size_t next_invalidate_after_; private: // A bit mask specifying area of the frame to invalidate. @@ -421,13 +390,13 @@ class WebFrameImpl : public WebFrame { // Invalidates a certain area within the frame. void InvalidateArea(AreaToInvalidate area); - // Invalidates the tickmark area represented by the range passed in. - void InvalidateTickmark(RefPtr<WebCore::Range> tickmark); + // Add a WebKit TextMatch-highlight marker to nodes in a range. + void AddMarker(WebCore::Range* range); // Returns the ordinal of the first match in the frame specified. This // function enumerates the frames, starting with the main frame and up to (but // not including) the frame passed in as a parameter and counts how many - // tickmarks there are. + // matches have been found. int OrdinalOfFirstMatchForFrame(WebFrameImpl* frame) const; // Determines whether the scoping effort is required for a particular frame. diff --git a/webkit/glue/webview_impl.cc b/webkit/glue/webview_impl.cc index 34a87ea..419c0e2 100644 --- a/webkit/glue/webview_impl.cc +++ b/webkit/glue/webview_impl.cc @@ -1579,29 +1579,6 @@ void WebViewImpl::onScrollPositionChanged(WebCore::Widget* widget) { delegate_->OnNavStateChanged(this); } -const WTF::Vector<RefPtr<WebCore::Range> >* WebViewImpl::getTickmarks( - WebCore::Frame* frame) { - DCHECK(frame); - WebFrameImpl* webframe_impl = WebFrameImpl::FromFrame(frame); - if (!webframe_impl) - return NULL; - - return &webframe_impl->tickmarks(); -} - -size_t WebViewImpl::getActiveTickmarkIndex(WebCore::Frame* frame) { - DCHECK(frame); - WebFrameImpl* webframe_impl = WebFrameImpl::FromFrame(frame); - if (!webframe_impl) - return kNoTickmark; - - // The mainframe can tell us if we are the frame with the active tick-mark. - if (webframe_impl != main_frame_->active_tickmark_frame()) - return kNoTickmark; - - return webframe_impl->active_tickmark_index(); -} - bool WebViewImpl::isHidden() { if (!delegate_) return true; diff --git a/webkit/glue/webview_impl.h b/webkit/glue/webview_impl.h index a9b4763..ed457e9 100644 --- a/webkit/glue/webview_impl.h +++ b/webkit/glue/webview_impl.h @@ -206,9 +206,6 @@ class WebViewImpl : public WebView, public WebCore::BackForwardListClient { // WebCore::WidgetClientWin virtual const SkBitmap* getPreloadedResourceBitmap(int resource_id); virtual void onScrollPositionChanged(WebCore::Widget* widget); - virtual const WTF::Vector<RefPtr<WebCore::Range> >* getTickmarks( - WebCore::Frame* frame); - virtual size_t getActiveTickmarkIndex(WebCore::Frame* frame); virtual bool isHidden(); #endif diff --git a/webkit/glue/webwidget_impl.cc b/webkit/glue/webwidget_impl.cc index d15e015..97287b2 100644 --- a/webkit/glue/webwidget_impl.cc +++ b/webkit/glue/webwidget_impl.cc @@ -266,15 +266,6 @@ const SkBitmap* WebWidgetImpl::getPreloadedResourceBitmap(int resource_id) { void WebWidgetImpl::onScrollPositionChanged(Widget* widget) { } -const WTF::Vector<RefPtr<WebCore::Range> >* WebWidgetImpl::getTickmarks( - WebCore::Frame* frame) { - return NULL; -} - -size_t WebWidgetImpl::getActiveTickmarkIndex(WebCore::Frame* frame) { - return kNoTickmark; -} - bool WebWidgetImpl::isHidden() { if (!delegate_) return true; |