diff options
-rw-r--r-- | DEPS | 2 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 14 | ||||
-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 | ||||
-rw-r--r-- | webkit/port/platform/chromium/ScrollbarThemeChromium.cpp | 45 | ||||
-rw-r--r-- | webkit/port/platform/chromium/ScrollbarThemeChromium.h | 1 | ||||
-rw-r--r-- | webkit/port/rendering/RenderThemeWin.cpp | 26 | ||||
-rw-r--r-- | webkit/port/rendering/RenderThemeWin.h | 7 |
12 files changed, 298 insertions, 381 deletions
@@ -12,7 +12,7 @@ deps = { "http://googletest.googlecode.com/svn/trunk@63", "src/third_party/WebKit": - "/trunk/deps/third_party/WebKit@5870", + "/trunk/deps/third_party/WebKit@5945", "src/third_party/icu38": "/trunk/deps/third_party/icu38@5827", diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 6b84f9f..4d4d4e9 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -2057,10 +2057,7 @@ void RenderView::OnFind(const FindInPageRequest& request) { bool result = false; do { - if (request.find_next) - result = search_frame->FindNext(request, wrap_within_frame); - else - result = search_frame->Find(request, wrap_within_frame, &selection_rect); + result = search_frame->Find(request, wrap_within_frame, &selection_rect); if (!result) { // don't leave text selected as you move to the next frame. @@ -2075,7 +2072,7 @@ void RenderView::OnFind(const FindInPageRequest& request) { webview()->GetPreviousFrameBefore(search_frame, true); } while (!search_frame->Visible() && search_frame != focused_frame); - // make sure selection doesn't affect the search operation in new frame. + // Make sure selection doesn't affect the search operation in new frame. search_frame->ClearSelection(); // If we have multiple frames and we have wrapped back around to the @@ -2084,11 +2081,8 @@ void RenderView::OnFind(const FindInPageRequest& request) { // reported matches, but no frames after the focused_frame contain a // match for the search word(s). if (multi_frame && search_frame == focused_frame) { - if (request.find_next) - result = search_frame->FindNext(request, true); // Force wrapping. - else - result = search_frame->Find(request, true, // Force wrapping. - &selection_rect); + result = search_frame->Find(request, true, // Force wrapping. + &selection_rect); } } 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; diff --git a/webkit/port/platform/chromium/ScrollbarThemeChromium.cpp b/webkit/port/platform/chromium/ScrollbarThemeChromium.cpp index 0cbf018..f9d961c 100644 --- a/webkit/port/platform/chromium/ScrollbarThemeChromium.cpp +++ b/webkit/port/platform/chromium/ScrollbarThemeChromium.cpp @@ -28,6 +28,8 @@ #include "ChromiumBridge.h" #include "PlatformMouseEvent.h" +#include "Frame.h" +#include "FrameView.h" #include "Scrollbar.h" #include "ScrollbarThemeComposite.h" @@ -112,6 +114,49 @@ void ScrollbarThemeChromium::paintTrackBackground(GraphicsContext* context, Scro paintTrackPiece(context, scrollbar, rect, ForwardTrackPart); } +void ScrollbarThemeChromium::paintTickmarks(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) +{ + if (scrollbar->orientation() != VerticalScrollbar) + return; + + if (rect.height() <= 0 || rect.width() <= 0) + return; // nothing to draw on. + + // Get the frameview. + // FIXME: Stop relying on high-level WebCore types such as Frame and FrameView. + if (!scrollbar->parent()->isFrameView()) + return; + FrameView* frameView = static_cast<FrameView*>(scrollbar->parent()); + Document* doc = frameView->frame()->document(); + + // Get the text markers for the frameview. + Vector<IntRect> markers = doc->renderedRectsForMarkers(DocumentMarker::TextMatch); + if (!markers.size()) + return; + + // Get the image for the tickmarks. + static RefPtr<Image> dash = Image::loadPlatformResource("tickmarkDash"); + if (dash->isNull()) { + ASSERT_NOT_REACHED(); + return; + } + + context->save(); + + for (Vector<IntRect>::const_iterator i = markers.begin(); i != markers.end(); ++i) { + // Calculate how far down (in %) the tick-mark should appear. + const float percent = static_cast<float>(i->y()) / scrollbar->totalSize(); + + // Calculate how far down (in pixels) the tick-mark should appear. + const int yPos = rect.topLeft().y() + (rect.height() * percent); + + IntPoint tick(scrollbar->x(), yPos); + context->drawImage(dash.get(), tick); + } + + context->restore(); +} + void ScrollbarThemeChromium::paintScrollCorner(ScrollView* view, GraphicsContext* context, const IntRect& cornerRect) { // ScrollbarThemeComposite::paintScrollCorner incorrectly assumes that the diff --git a/webkit/port/platform/chromium/ScrollbarThemeChromium.h b/webkit/port/platform/chromium/ScrollbarThemeChromium.h index f75b052..c198222 100644 --- a/webkit/port/platform/chromium/ScrollbarThemeChromium.h +++ b/webkit/port/platform/chromium/ScrollbarThemeChromium.h @@ -65,6 +65,7 @@ protected: virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&); + virtual void paintTickmarks(GraphicsContext*, Scrollbar*, const IntRect&); private: IntSize buttonSize(Scrollbar*); diff --git a/webkit/port/rendering/RenderThemeWin.cpp b/webkit/port/rendering/RenderThemeWin.cpp index aa6322b..24f6b20 100644 --- a/webkit/port/rendering/RenderThemeWin.cpp +++ b/webkit/port/rendering/RenderThemeWin.cpp @@ -108,6 +108,8 @@ WebCore::FontDescription labelFont; namespace WebCore { +bool RenderThemeWin::m_findInPageMode = false; + // Internal static helper functions. We don't put them in an anonymous // namespace so they have easier access to the WebCore namespace. @@ -331,7 +333,9 @@ bool RenderThemeWin::supportsFocusRing(const RenderStyle* style) const Color RenderThemeWin::platformActiveSelectionBackgroundColor() const { if (ChromiumBridge::layoutTestMode()) - return Color("#0000FF"); // Royal blue + return Color("#0000FF"); // Royal blue. + if (m_findInPageMode) + return Color(255, 150, 50, 200); // Orange. COLORREF color = GetSysColor(COLOR_HIGHLIGHT); return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); } @@ -339,7 +343,9 @@ Color RenderThemeWin::platformActiveSelectionBackgroundColor() const Color RenderThemeWin::platformInactiveSelectionBackgroundColor() const { if (ChromiumBridge::layoutTestMode()) - return Color("#999999"); // Medium grey + return Color("#999999"); // Medium gray. + if (m_findInPageMode) + return Color(255, 150, 50, 200); // Orange. COLORREF color = GetSysColor(COLOR_GRAYTEXT); return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); } @@ -347,7 +353,7 @@ Color RenderThemeWin::platformInactiveSelectionBackgroundColor() const Color RenderThemeWin::platformActiveSelectionForegroundColor() const { if (ChromiumBridge::layoutTestMode()) - return Color("#FFFFCC"); // Pale yellow + return Color("#FFFFCC"); // Pale yellow. COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); } @@ -357,6 +363,11 @@ Color RenderThemeWin::platformInactiveSelectionForegroundColor() const return Color::white; } +Color RenderThemeWin::platformTextSearchHighlightColor() const +{ + return Color(255, 255, 150); +} + double RenderThemeWin::caretBlinkFrequency() const { // Disable the blinking caret in layout test mode, as it introduces @@ -872,4 +883,13 @@ int RenderThemeWin::menuListInternalPadding(RenderStyle* style, int paddingType) return padding; } +// static +void RenderThemeWin::setFindInPageMode(bool enable) { + if (m_findInPageMode == enable) + return; + + m_findInPageMode = enable; + theme()->platformColorsDidChange(); +} + } // namespace WebCore diff --git a/webkit/port/rendering/RenderThemeWin.h b/webkit/port/rendering/RenderThemeWin.h index 2ca8c70..9398cfe 100644 --- a/webkit/port/rendering/RenderThemeWin.h +++ b/webkit/port/rendering/RenderThemeWin.h @@ -57,6 +57,7 @@ public: virtual Color platformInactiveSelectionBackgroundColor() const; virtual Color platformActiveSelectionForegroundColor() const; virtual Color platformInactiveSelectionForegroundColor() const; + virtual Color platformTextSearchHighlightColor() const; virtual double caretBlinkFrequency() const; @@ -118,6 +119,9 @@ public: // the value to get it directly from the appropriate Settings object. static void setDefaultFontSize(int); + // Enables/Disables FindInPage mode, which (if enabled) overrides the + // selection rect color to be orange. + static void setFindInPageMode(bool); private: unsigned determineState(RenderObject*); unsigned determineClassicState(RenderObject*); @@ -130,6 +134,9 @@ private: void getMinimalButtonPadding(Length* minXPadding) const; int menuListInternalPadding(RenderStyle* style, int paddingType) const; + + // A flag specifying whether we are in Find-in-page mode or not. + static bool m_findInPageMode; }; } |