Home | History | Annotate | Download | only in find_bar
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
      6 
      7 #include <vector>
      8 
      9 #include "chrome/browser/chrome_notification_types.h"
     10 #include "chrome/browser/profiles/profile.h"
     11 #include "chrome/browser/ui/find_bar/find_bar_state.h"
     12 #include "chrome/browser/ui/find_bar/find_bar_state_factory.h"
     13 #include "content/public/browser/notification_service.h"
     14 #include "content/public/browser/render_view_host.h"
     15 #include "content/public/browser/web_contents.h"
     16 #include "content/public/common/stop_find_action.h"
     17 #include "third_party/WebKit/public/web/WebFindOptions.h"
     18 #include "ui/gfx/rect_f.h"
     19 
     20 using blink::WebFindOptions;
     21 using content::WebContents;
     22 
     23 DEFINE_WEB_CONTENTS_USER_DATA_KEY(FindTabHelper);
     24 
     25 // static
     26 int FindTabHelper::find_request_id_counter_ = -1;
     27 
     28 FindTabHelper::FindTabHelper(WebContents* web_contents)
     29     : content::WebContentsObserver(web_contents),
     30       find_ui_active_(false),
     31       find_op_aborted_(false),
     32       current_find_request_id_(find_request_id_counter_++),
     33       last_search_case_sensitive_(false),
     34       last_search_result_() {
     35 }
     36 
     37 FindTabHelper::~FindTabHelper() {
     38 }
     39 
     40 void FindTabHelper::StartFinding(base::string16 search_string,
     41                                  bool forward_direction,
     42                                  bool case_sensitive) {
     43   // If search_string is empty, it means FindNext was pressed with a keyboard
     44   // shortcut so unless we have something to search for we return early.
     45   if (search_string.empty() && find_text_.empty()) {
     46     Profile* profile =
     47         Profile::FromBrowserContext(web_contents()->GetBrowserContext());
     48     base::string16 last_search_prepopulate_text =
     49         FindBarStateFactory::GetLastPrepopulateText(profile);
     50 
     51     // Try the last thing we searched for on this tab, then the last thing
     52     // searched for on any tab.
     53     if (!previous_find_text_.empty())
     54       search_string = previous_find_text_;
     55     else if (!last_search_prepopulate_text.empty())
     56       search_string = last_search_prepopulate_text;
     57     else
     58       return;
     59   }
     60 
     61   // Keep track of the previous search.
     62   previous_find_text_ = find_text_;
     63 
     64   // This is a FindNext operation if we are searching for the same text again,
     65   // or if the passed in search text is empty (FindNext keyboard shortcut). The
     66   // exception to this is if the Find was aborted (then we don't want FindNext
     67   // because the highlighting has been cleared and we need it to reappear). We
     68   // therefore treat FindNext after an aborted Find operation as a full fledged
     69   // Find.
     70   bool find_next = (find_text_ == search_string || search_string.empty()) &&
     71                    (last_search_case_sensitive_ == case_sensitive) &&
     72                    !find_op_aborted_;
     73   if (!find_next)
     74     current_find_request_id_ = find_request_id_counter_++;
     75 
     76   if (!search_string.empty())
     77     find_text_ = search_string;
     78   last_search_case_sensitive_ = case_sensitive;
     79 
     80   find_op_aborted_ = false;
     81 
     82   // Keep track of what the last search was across the tabs.
     83   Profile* profile =
     84       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
     85   FindBarState* find_bar_state = FindBarStateFactory::GetForProfile(profile);
     86   find_bar_state->set_last_prepopulate_text(find_text_);
     87 
     88   WebFindOptions options;
     89   options.forward = forward_direction;
     90   options.matchCase = case_sensitive;
     91   options.findNext = find_next;
     92   web_contents()->Find(current_find_request_id_, find_text_, options);
     93 }
     94 
     95 void FindTabHelper::StopFinding(
     96     FindBarController::SelectionAction selection_action) {
     97   if (selection_action == FindBarController::kClearSelectionOnPage) {
     98     // kClearSelection means the find string has been cleared by the user, but
     99     // the UI has not been dismissed. In that case we want to clear the
    100     // previously remembered search (http://crbug.com/42639).
    101     previous_find_text_ = base::string16();
    102   } else {
    103     find_ui_active_ = false;
    104     if (!find_text_.empty())
    105       previous_find_text_ = find_text_;
    106   }
    107   find_text_.clear();
    108   find_op_aborted_ = true;
    109   last_search_result_ = FindNotificationDetails();
    110 
    111   content::StopFindAction action;
    112   switch (selection_action) {
    113     case FindBarController::kClearSelectionOnPage:
    114       action = content::STOP_FIND_ACTION_CLEAR_SELECTION;
    115       break;
    116     case FindBarController::kKeepSelectionOnPage:
    117       action = content::STOP_FIND_ACTION_KEEP_SELECTION;
    118       break;
    119     case FindBarController::kActivateSelectionOnPage:
    120       action = content::STOP_FIND_ACTION_ACTIVATE_SELECTION;
    121       break;
    122     default:
    123       NOTREACHED();
    124       action = content::STOP_FIND_ACTION_KEEP_SELECTION;
    125   }
    126   web_contents()->StopFinding(action);
    127 }
    128 
    129 #if defined(OS_ANDROID)
    130 void FindTabHelper::ActivateNearestFindResult(float x, float y) {
    131   if (!find_op_aborted_ && !find_text_.empty()) {
    132     web_contents()->GetRenderViewHost()->ActivateNearestFindResult(
    133         current_find_request_id_, x, y);
    134   }
    135 }
    136 
    137 void FindTabHelper::RequestFindMatchRects(int current_version) {
    138   if (!find_op_aborted_ && !find_text_.empty())
    139     web_contents()->GetRenderViewHost()->RequestFindMatchRects(current_version);
    140 }
    141 #endif
    142 
    143 void FindTabHelper::HandleFindReply(int request_id,
    144                                     int number_of_matches,
    145                                     const gfx::Rect& selection_rect,
    146                                     int active_match_ordinal,
    147                                     bool final_update) {
    148   // Ignore responses for requests that have been aborted.
    149   // Ignore responses for requests other than the one we have most recently
    150   // issued. That way we won't act on stale results when the user has
    151   // already typed in another query.
    152   if (!find_op_aborted_ && request_id == current_find_request_id_) {
    153     if (number_of_matches == -1)
    154       number_of_matches = last_search_result_.number_of_matches();
    155     if (active_match_ordinal == -1)
    156       active_match_ordinal = last_search_result_.active_match_ordinal();
    157 
    158     gfx::Rect selection = selection_rect;
    159     if (final_update && active_match_ordinal == 0)
    160       selection = gfx::Rect();
    161     else if (selection_rect.IsEmpty())
    162       selection = last_search_result_.selection_rect();
    163 
    164     // Notify the UI, automation and any other observers that a find result was
    165     // found.
    166     last_search_result_ = FindNotificationDetails(
    167         request_id, number_of_matches, selection, active_match_ordinal,
    168         final_update);
    169     content::NotificationService::current()->Notify(
    170         chrome::NOTIFICATION_FIND_RESULT_AVAILABLE,
    171         content::Source<WebContents>(web_contents()),
    172         content::Details<FindNotificationDetails>(&last_search_result_));
    173   }
    174 }
    175