1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/find_helper.h"
#include "android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h"
#include "base/message_loop.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/stop_find_action.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFindOptions.h"
using content::WebContents;
using WebKit::WebFindOptions;
namespace android_webview {
FindHelper::FindHelper(WebContents* web_contents)
: WebContentsObserver(web_contents),
listener_(NULL),
async_find_started_(false),
sync_find_started_(false),
find_request_id_counter_(0),
current_request_id_(0),
last_match_count_(-1),
last_active_ordinal_(-1),
weak_factory_(this) {
}
FindHelper::~FindHelper() {
}
void FindHelper::SetListener(Listener* listener) {
listener_ = listener;
}
int FindHelper::FindAllSync(const string16& search_string) {
sync_find_started_ = true;
async_find_started_ = false;
WebFindOptions options;
options.forward = true;
options.matchCase = false;
options.findNext = false;
int match_count = 0;
int active_ordinal = 0;
StartNewRequest(search_string);
// Any ongoing asynchronous requests will be stopped in the renderer when
// calling SynchronousFind. Using the asynchronous StopFinding message could
// lead to deadblocks as the message could arrive in the middle of the
// synchronous operation and cancel the reply back.
ScopedAllowWaitForLegacyWebViewApi wait;
web_contents()->GetRenderViewHost()->SynchronousFind(current_request_id_,
search_string,
options,
&match_count,
&active_ordinal);
// Post the task to ourselves to prevent trigerring the notification before
// we actually return from the request.
MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&FindHelper::NotifyResults, weak_factory_.GetWeakPtr(),
active_ordinal, match_count, true));
return match_count;
}
void FindHelper::FindAllAsync(const string16& search_string) {
// Stop any ongoing asynchronous request.
web_contents()->GetRenderViewHost()->StopFinding(
content::STOP_FIND_ACTION_KEEP_SELECTION);
sync_find_started_ = false;
async_find_started_ = true;
WebFindOptions options;
options.forward = true;
options.matchCase = false;
options.findNext = false;
StartNewRequest(search_string);
web_contents()->GetRenderViewHost()->Find(current_request_id_,
search_string, options);
}
void FindHelper::HandleFindReply(int request_id,
int match_count,
int active_ordinal,
bool finished) {
if ((!async_find_started_ && !sync_find_started_) ||
request_id != current_request_id_) {
return;
}
NotifyResults(active_ordinal, match_count, finished);
}
void FindHelper::FindNext(bool forward) {
if (!sync_find_started_ && !async_find_started_)
return;
WebFindOptions options;
options.forward = forward;
options.matchCase = false;
options.findNext = true;
web_contents()->GetRenderViewHost()->Find(current_request_id_,
last_search_string_,
options);
}
void FindHelper::ClearMatches() {
web_contents()->GetRenderViewHost()->StopFinding(
content::STOP_FIND_ACTION_CLEAR_SELECTION);
sync_find_started_ = false;
async_find_started_ = false;
last_search_string_.clear();
last_match_count_ = -1;
last_active_ordinal_ = -1;
}
void FindHelper::StartNewRequest(const string16& search_string) {
current_request_id_ = find_request_id_counter_++;
last_search_string_ = search_string;
last_match_count_ = -1;
last_active_ordinal_ = -1;
}
void FindHelper::NotifyResults(int active_ordinal,
int match_count,
bool finished) {
// Match count or ordinal values set to -1 refer to the received replies.
if (match_count == -1)
match_count = last_match_count_;
else
last_match_count_ = match_count;
if (active_ordinal == -1)
active_ordinal = last_active_ordinal_;
else
last_active_ordinal_ = active_ordinal;
// Skip the update if we don't still have a valid ordinal.
// The next update, final or not, should have this information.
if (!finished && active_ordinal == -1)
return;
// Safeguard in case of errors to prevent reporting -1 to the API listeners.
if (match_count == -1) {
NOTREACHED();
match_count = 0;
}
if (active_ordinal == -1) {
NOTREACHED();
active_ordinal = 0;
}
// WebView.FindListener active match ordinals are 0-based while WebKit sends
// 1-based ordinals. Still we can receive 0 ordinal in case of no results.
active_ordinal = std::max(active_ordinal - 1, 0);
if (listener_)
listener_->OnFindResultReceived(active_ordinal, match_count, finished);
}
} // namespace android_webview
|