Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 const int kSurroundingTextSize = 1536; | |
|
Theresa
2016/09/01 16:49:37
nit: where did 1536 come from?
Donn Denman
2016/09/02 16:40:43
Done: added the comment "Context length is set to
| |
| 26 } | |
| 27 | |
| 28 SearchAction::SearchAction(JNIEnv* env, jobject obj) { | |
| 29 java_object_.Reset(env, obj); | |
| 30 } | |
| 31 | |
| 32 SearchAction::~SearchAction() { | |
| 33 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 34 Java_SearchAction_clearNativePointer(env, java_object_.obj()); | |
| 35 } | |
| 36 | |
| 37 void SearchAction::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { | |
| 38 delete this; | |
| 39 } | |
| 40 | |
| 41 void SearchAction::RequestSurroundingText( | |
| 42 JNIEnv* env, | |
| 43 const JavaParamRef<jobject>& obj, | |
| 44 const JavaParamRef<jobject>& j_web_contents) { | |
| 45 WebContents* web_contents = | |
| 46 WebContents::FromJavaWebContents(j_web_contents.obj()); | |
| 47 DCHECK(web_contents); | |
| 48 | |
| 49 GURL url(web_contents->GetURL()); | |
| 50 std::string encoding(web_contents->GetEncoding()); | |
| 51 search_context_.reset(new ContextualSearchContext(true, url, encoding)); | |
| 52 | |
| 53 content::RenderFrameHost* focused_frame = web_contents->GetFocusedFrame(); | |
| 54 if (!focused_frame) { | |
| 55 OnSurroundingTextResponse(base::string16(), 0, 0); | |
| 56 } else { | |
| 57 focused_frame->RequestTextSurroundingSelection( | |
| 58 base::Bind(&SearchAction::OnSurroundingTextResponse, AsWeakPtr()), | |
| 59 kSurroundingTextSize); | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 void SearchAction::OnSurroundingTextResponse( | |
| 64 const base::string16& surrounding_text, | |
| 65 int focus_start, | |
| 66 int focus_end) { | |
| 67 // Record the context, which can be accessed later on demand. | |
| 68 search_context_->surrounding_text = surrounding_text; | |
| 69 search_context_->start_offset = focus_start; | |
| 70 search_context_->end_offset = focus_end; | |
| 71 | |
| 72 // Notify Java. | |
| 73 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 74 Java_SearchAction_onSurroundingTextResponse(env, java_object_.obj()); | |
| 75 } | |
| 76 | |
| 77 std::string SearchAction::FindFocusedWord() { | |
| 78 DCHECK(search_context_); | |
| 79 // Find the focused word. | |
| 80 std::pair<int, int> focus = FindFocusedWord(search_context_->surrounding_text, | |
| 81 search_context_->start_offset, | |
| 82 search_context_->end_offset); | |
| 83 return base::UTF16ToUTF8(search_context_->surrounding_text.substr( | |
| 84 focus.first, focus.second - focus.first)); | |
| 85 } | |
| 86 | |
| 87 std::string SearchAction::GetSampleText(int sample_length) { | |
| 88 DCHECK(search_context_); | |
| 89 // Trim surroundings to the requested sample size. | |
| 90 std::pair<base::string16, int> sample = SampleSurroundings( | |
| 91 search_context_->surrounding_text, search_context_->start_offset, | |
| 92 search_context_->end_offset, sample_length); | |
| 93 return base::UTF16ToUTF8(sample.first); | |
| 94 } | |
| 95 | |
| 96 // static | |
| 97 std::pair<int, int> SearchAction::FindFocusedWord( | |
|
pedro (no code reviews)
2016/08/31 22:38:22
Nit: Why not merge this method with the one with s
Donn Denman
2016/09/02 16:40:43
Done. It was tricky to figure out how to test non
| |
| 98 const base::string16& surrounding_text, | |
| 99 int focus_start, | |
| 100 int focus_end) { | |
| 101 int surrounding_text_length = surrounding_text.length(); | |
| 102 | |
| 103 // First, we need to find the focused word boundaries. | |
| 104 int focused_word_start = focus_start; | |
| 105 int focused_word_end = focus_end; | |
| 106 | |
| 107 if (surrounding_text_length > 0 && | |
| 108 IsValidCharacter(surrounding_text[focused_word_start])) { | |
| 109 // Find focused word start (inclusive) | |
| 110 for (int i = focus_start; i >= 0; i--) { | |
| 111 focused_word_start = i; | |
| 112 | |
| 113 wchar_t character; | |
| 114 if (i > 0) { | |
| 115 character = surrounding_text[i - 1]; | |
| 116 | |
| 117 if (!IsValidCharacter(character)) | |
| 118 break; | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 // Find focused word end (non inclusive) | |
| 123 for (int i = focus_end; i < surrounding_text_length; i++) { | |
| 124 wchar_t character = surrounding_text[i]; | |
| 125 | |
| 126 if (IsValidCharacter(character)) { | |
| 127 focused_word_end = i + 1; | |
| 128 } else { | |
| 129 focused_word_end = i; | |
| 130 break; | |
| 131 } | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 return std::pair<int, int>(focused_word_start, focused_word_end); | |
| 136 } | |
| 137 | |
| 138 // static | |
| 139 std::pair<base::string16, int> SearchAction::SampleSurroundings( | |
| 140 const base::string16& surrounding_text, | |
| 141 int focus_start, | |
| 142 int focus_end, | |
| 143 int surrounding_text_sample_limit) { | |
| 144 int surrounding_text_length = surrounding_text.length(); | |
| 145 | |
| 146 //--------------------------------------------------------------------------- | |
| 147 // Cut the surrounding size so it can be sent to the Java side. | |
| 148 | |
| 149 // Start equally distributing the size around the focal point. | |
| 150 int focal_point_size = focus_end - focus_start; | |
| 151 int sample_margin = (surrounding_text_sample_limit - focal_point_size) / 2; | |
| 152 int sample_start = focus_start - sample_margin; | |
| 153 int sample_end = focus_end + sample_margin; | |
| 154 | |
| 155 // If the the start is out of bounds, compensate the end side. | |
| 156 if (sample_start < 0) { | |
| 157 sample_end -= sample_start; | |
| 158 sample_start = 0; | |
| 159 } | |
| 160 | |
| 161 // If the the end is out of bounds, compensate the start side. | |
| 162 if (sample_end > surrounding_text_length) { | |
| 163 int diff = sample_end - surrounding_text_length; | |
| 164 sample_end = surrounding_text_length; | |
| 165 sample_start -= diff; | |
| 166 } | |
| 167 | |
| 168 // Trim the start and end to make sure they are within bounds. | |
| 169 sample_start = std::max(0, sample_start); | |
| 170 sample_end = std::min(surrounding_text_length, sample_end); | |
| 171 base::string16 sample_string( | |
| 172 surrounding_text.substr(sample_start, sample_end - sample_start)); | |
| 173 std::pair<base::string16, int> sample(sample_string, sample_start); | |
| 174 return sample; | |
| 175 } | |
| 176 | |
| 177 // static | |
| 178 bool SearchAction::IsValidCharacter(int char_code) { | |
| 179 // See http://www.unicode.org/Public/UCD/latest/ucd/NamesList.txt | |
| 180 // See http://jrgraphix.net/research/unicode_blocks.php | |
| 181 | |
| 182 // TODO(pedrosimonetti): should not include CJK characters! | |
|
pedro (no code reviews)
2016/08/31 22:38:22
Take over this TODO? This needs to be addressed or
Donn Denman
2016/09/02 16:40:43
Done.
Note: With the current implementation sur
| |
| 183 // TODO(donnd): consider using regular expressions. | |
| 184 | |
| 185 if ((char_code >= 11264 && char_code <= 55295) || // Asian language symbols | |
| 186 (char_code >= 192 && char_code <= 8191) || // Letters in many languages | |
| 187 (char_code >= 97 && char_code <= 122) || // Lowercase letters | |
| 188 (char_code >= 65 && char_code <= 90) || // Uppercase letters | |
| 189 (char_code >= 48 && char_code <= 57)) { // Numbers | |
| 190 return true; | |
| 191 } | |
| 192 | |
| 193 return false; | |
| 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 } | |
| OLD | NEW |