find_helper.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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.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
14using content::WebContents;
15using WebKit::WebFindOptions;
16
17namespace android_webview {
18
19FindHelper::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
31FindHelper::~FindHelper() {
32}
33
34void FindHelper::SetListener(Listener* listener) {
35  listener_ = listener;
36}
37
38void 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
56void 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
68void 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
82void 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
93void 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
100void 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