Home | History | Annotate | Download | only in browser
      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 "android_webview/browser/find_helper.h"
      6 
      7 #include "android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "content/public/browser/render_view_host.h"
     10 #include "content/public/browser/web_contents.h"
     11 #include "content/public/common/stop_find_action.h"
     12 #include "third_party/WebKit/public/web/WebFindOptions.h"
     13 
     14 using content::WebContents;
     15 using WebKit::WebFindOptions;
     16 
     17 namespace android_webview {
     18 
     19 FindHelper::FindHelper(WebContents* web_contents)
     20     : WebContentsObserver(web_contents),
     21       listener_(NULL),
     22       async_find_started_(false),
     23       sync_find_started_(false),
     24       find_request_id_counter_(0),
     25       current_request_id_(0),
     26       last_match_count_(-1),
     27       last_active_ordinal_(-1),
     28       weak_factory_(this) {
     29 }
     30 
     31 FindHelper::~FindHelper() {
     32 }
     33 
     34 void FindHelper::SetListener(Listener* listener) {
     35   listener_ = listener;
     36 }
     37 
     38 void FindHelper::FindAllAsync(const string16& search_string) {
     39   // Stop any ongoing asynchronous request.
     40   web_contents()->GetRenderViewHost()->StopFinding(
     41       content::STOP_FIND_ACTION_KEEP_SELECTION);
     42 
     43   sync_find_started_ = false;
     44   async_find_started_ = true;
     45 
     46   WebFindOptions options;
     47   options.forward = true;
     48   options.matchCase = false;
     49   options.findNext = false;
     50 
     51   StartNewRequest(search_string);
     52   web_contents()->GetRenderViewHost()->Find(current_request_id_,
     53                                             search_string, options);
     54 }
     55 
     56 void FindHelper::HandleFindReply(int request_id,
     57                                    int match_count,
     58                                    int active_ordinal,
     59                                    bool finished) {
     60   if ((!async_find_started_ && !sync_find_started_) ||
     61       request_id != current_request_id_) {
     62     return;
     63   }
     64 
     65   NotifyResults(active_ordinal, match_count, finished);
     66 }
     67 
     68 void FindHelper::FindNext(bool forward) {
     69   if (!sync_find_started_ && !async_find_started_)
     70     return;
     71 
     72   WebFindOptions options;
     73   options.forward = forward;
     74   options.matchCase = false;
     75   options.findNext = true;
     76 
     77   web_contents()->GetRenderViewHost()->Find(current_request_id_,
     78                                             last_search_string_,
     79                                             options);
     80 }
     81 
     82 void FindHelper::ClearMatches() {
     83   web_contents()->GetRenderViewHost()->StopFinding(
     84       content::STOP_FIND_ACTION_CLEAR_SELECTION);
     85 
     86   sync_find_started_ = false;
     87   async_find_started_ = false;
     88   last_search_string_.clear();
     89   last_match_count_ = -1;
     90   last_active_ordinal_ = -1;
     91 }
     92 
     93 void FindHelper::StartNewRequest(const string16& search_string) {
     94   current_request_id_ = find_request_id_counter_++;
     95   last_search_string_ = search_string;
     96   last_match_count_ = -1;
     97   last_active_ordinal_ = -1;
     98 }
     99 
    100 void FindHelper::NotifyResults(int active_ordinal,
    101                                  int match_count,
    102                                  bool finished) {
    103   // Match count or ordinal values set to -1 refer to the received replies.
    104   if (match_count == -1)
    105     match_count = last_match_count_;
    106   else
    107     last_match_count_ = match_count;
    108 
    109   if (active_ordinal == -1)
    110     active_ordinal = last_active_ordinal_;
    111   else
    112     last_active_ordinal_ = active_ordinal;
    113 
    114   // Skip the update if we don't still have a valid ordinal.
    115   // The next update, final or not, should have this information.
    116   if (!finished && active_ordinal == -1)
    117     return;
    118 
    119   // Safeguard in case of errors to prevent reporting -1 to the API listeners.
    120   if (match_count == -1) {
    121     NOTREACHED();
    122     match_count = 0;
    123   }
    124 
    125   if (active_ordinal == -1) {
    126     NOTREACHED();
    127     active_ordinal = 0;
    128   }
    129 
    130   // WebView.FindListener active match ordinals are 0-based while WebKit sends
    131   // 1-based ordinals. Still we can receive 0 ordinal in case of no results.
    132   active_ordinal = std::max(active_ordinal - 1, 0);
    133 
    134   if (listener_)
    135     listener_->OnFindResultReceived(active_ordinal, match_count, finished);
    136 }
    137 
    138 }  // namespace android_webview
    139