Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: chrome/browser/android/contextualsearch/search_action.cc

Issue 2211353002: [TTS] Gather surrounding text on Tap before any UX. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Reworked the native accessors to tapped text and the associated unit tests. Destroying Actions on … Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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/android/contextualsearch/search_action.h"
6
7 #include <set>
8
9 #include "base/android/jni_string.h"
10 #include "base/bind.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/android/contextualsearch/contextual_search_context.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/web_contents.h"
16 #include "jni/SearchAction_jni.h"
17 #include "url/gurl.h"
18
19 using base::android::ConvertUTF8ToJavaString;
20 using base::android::JavaParamRef;
21 using base::android::ScopedJavaGlobalRef;
22 using content::WebContents;
23
24 namespace {
25 // Context length is set to 1.5K characters for historical reasons:
26 // This provides the largest context that would fit in a GET request along with
Theresa 2016/09/02 17:04:07 nit: s/would/will
Donn Denman 2016/09/02 20:48:35 Done slightly differently -- now phrased fully in
27 // our other required parameters."
28 const int kSurroundingTextSize = 1536;
29 }
30
31 SearchAction::SearchAction(JNIEnv* env, jobject obj) {
32 java_object_.Reset(env, obj);
33 }
34
35 SearchAction::~SearchAction() {
36 // The Java object can be null in tests only, by calling the default
37 // constructor.
38 if (!java_object_.is_null()) {
39 JNIEnv* env = base::android::AttachCurrentThread();
40 Java_SearchAction_clearNativePointer(env, java_object_.obj());
41 }
42 }
43
44 void SearchAction::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
45 delete this;
46 }
47
48 void SearchAction::RequestSurroundingText(
49 JNIEnv* env,
50 const JavaParamRef<jobject>& obj,
51 const JavaParamRef<jobject>& j_web_contents) {
52 WebContents* web_contents =
53 WebContents::FromJavaWebContents(j_web_contents.obj());
54 DCHECK(web_contents);
55
56 GURL url(web_contents->GetURL());
57 std::string encoding(web_contents->GetEncoding());
58 search_context_.reset(new ContextualSearchContext(true, url, encoding));
59
60 content::RenderFrameHost* focused_frame = web_contents->GetFocusedFrame();
61 if (!focused_frame) {
62 OnSurroundingTextResponse(base::string16(), 0, 0);
63 } else {
64 focused_frame->RequestTextSurroundingSelection(
65 base::Bind(&SearchAction::OnSurroundingTextResponse, AsWeakPtr()),
66 kSurroundingTextSize);
67 }
68 }
69
70 void SearchAction::OnSurroundingTextResponse(
71 const base::string16& surrounding_text,
72 int focus_start,
73 int focus_end) {
74 // Record the context, which can be accessed later on demand.
75 search_context_->surrounding_text = surrounding_text;
76 search_context_->start_offset = focus_start;
77 search_context_->end_offset = focus_end;
78
79 // Notify Java.
80 JNIEnv* env = base::android::AttachCurrentThread();
81 Java_SearchAction_onSurroundingTextReady(env, java_object_.obj());
82 }
83
84 std::string SearchAction::FindFocusedWord() {
85 DCHECK(search_context_);
86
87 const base::string16& surrounding_text = search_context_->surrounding_text;
88 int focus_start = search_context_->start_offset;
89 int focus_end = search_context_->end_offset;
90 int surrounding_text_length = surrounding_text.length();
91
92 // First, we need to find the focused word boundaries.
93 int focused_word_start = focus_start;
94 int focused_word_end = focus_end;
95
96 if (surrounding_text_length > 0 &&
97 IsValidCharacter(surrounding_text[focused_word_start])) {
98 // Find focused word start (inclusive)
99 for (int i = focus_start; i >= 0; i--) {
100 focused_word_start = i;
101
102 wchar_t character;
103 if (i > 0) {
104 character = surrounding_text[i - 1];
105
106 if (!IsValidCharacter(character))
107 break;
108 }
109 }
110
111 // Find focused word end (non inclusive)
112 for (int i = focus_end; i < surrounding_text_length; i++) {
113 wchar_t character = surrounding_text[i];
114
115 if (IsValidCharacter(character)) {
116 focused_word_end = i + 1;
117 } else {
118 focused_word_end = i;
119 break;
120 }
121 }
122 }
123
124 return base::UTF16ToUTF8(surrounding_text.substr(
125 focused_word_start, focused_word_end - focused_word_start));
126 }
127
128 std::string SearchAction::GetSampleText(int sample_length) {
129 DCHECK(search_context_);
130
131 const base::string16& surrounding_text = search_context_->surrounding_text;
132 int focus_start = search_context_->start_offset;
133 int focus_end = search_context_->end_offset;
134 int surrounding_text_length = surrounding_text.length();
135
136 //---------------------------------------------------------------------------
137 // Cut the surrounding size so it can be sent to the Java side.
138
139 // Start equally distributing the size around the focal point.
140 int focal_point_size = focus_end - focus_start;
141 int sample_margin = (sample_length - focal_point_size) / 2;
142 int sample_start = focus_start - sample_margin;
143 int sample_end = focus_end + sample_margin;
144
145 // If the the start is out of bounds, compensate the end side.
146 if (sample_start < 0) {
147 sample_end -= sample_start;
148 sample_start = 0;
149 }
150
151 // If the the end is out of bounds, compensate the start side.
152 if (sample_end > surrounding_text_length) {
153 int diff = sample_end - surrounding_text_length;
154 sample_end = surrounding_text_length;
155 sample_start -= diff;
156 }
157
158 // Trim the start and end to make sure they are within bounds.
159 sample_start = std::max(0, sample_start);
160 sample_end = std::min(surrounding_text_length, sample_end);
161 return base::UTF16ToUTF8(
162 surrounding_text.substr(sample_start, sample_end - sample_start));
163 }
164
165 bool SearchAction::IsValidCharacter(int char_code) {
166 // See http://www.unicode.org/Public/UCD/latest/ucd/NamesList.txt
167 // See http://jrgraphix.net/research/unicode_blocks.php
168
169 // TODO(donnd): should not include CJK characters!
170 // TODO(donnd): consider using regular expressions.
171
172 if ((char_code >= 11264 && char_code <= 55295) || // Asian language symbols
173 (char_code >= 192 && char_code <= 8191) || // Letters in many languages
174 (char_code >= 97 && char_code <= 122) || // Lowercase letters
175 (char_code >= 65 && char_code <= 90) || // Uppercase letters
176 (char_code >= 48 && char_code <= 57)) { // Numbers
177 return true;
178 }
179
180 return false;
181 }
182
183 // Testing
184
185 SearchAction::SearchAction() {}
186
187 void SearchAction::SetContext(std::string surrounding_text,
188 int focus_start,
189 int focus_end) {
190 search_context_.reset(new ContextualSearchContext(false, GURL(), ""));
191 search_context_->surrounding_text = base::UTF8ToUTF16(surrounding_text);
192 search_context_->start_offset = focus_start;
193 search_context_->end_offset = focus_end;
194 }
195
196 bool RegisterSearchAction(JNIEnv* env) {
197 return RegisterNativesImpl(env);
198 }
199
200 jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
201 SearchAction* content = new SearchAction(env, obj);
202 return reinterpret_cast<intptr_t>(content);
203 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698