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 "chrome/browser/profiles/profile_manager.h" |
| 15 #include "content/public/browser/render_frame_host.h" |
| 16 #include "content/public/browser/web_contents.h" |
| 17 #include "jni/SearchAction_jni.h" |
| 18 #include "url/gurl.h" |
| 19 |
| 20 using base::android::JavaParamRef; |
| 21 |
| 22 namespace { |
| 23 const int kSurroundingTextSize = 1536; |
| 24 } |
| 25 |
| 26 SearchAction::SearchAction(JNIEnv* env, jobject obj) { |
| 27 java_object_.Reset(env, obj); |
| 28 } |
| 29 |
| 30 SearchAction::~SearchAction() { |
| 31 JNIEnv* env = base::android::AttachCurrentThread(); |
| 32 Java_SearchAction_clearNativePointer(env, java_object_.obj()); |
| 33 } |
| 34 |
| 35 void SearchAction::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
| 36 delete this; |
| 37 } |
| 38 |
| 39 void SearchAction::RequestSurroundingText( |
| 40 JNIEnv* env, |
| 41 const JavaParamRef<jobject>& obj, |
| 42 const JavaParamRef<jobject>& j_web_contents) { |
| 43 content::WebContents* web_contents = |
| 44 content::WebContents::FromJavaWebContents(j_web_contents.obj()); |
| 45 DCHECK(web_contents); |
| 46 |
| 47 GURL url(web_contents->GetURL()); |
| 48 std::string encoding(web_contents->GetEncoding()); |
| 49 search_context_.reset(new ContextualSearchContext(true, url, encoding)); |
| 50 |
| 51 content::RenderFrameHost* focused_frame = web_contents->GetFocusedFrame(); |
| 52 if (!focused_frame) { |
| 53 OnSurroundingTextResponse(base::string16(), 0, 0); |
| 54 } else { |
| 55 focused_frame->RequestTextSurroundingSelection( |
| 56 base::Bind(&SearchAction::OnSurroundingTextResponse, AsWeakPtr()), |
| 57 kSurroundingTextSize); |
| 58 } |
| 59 } |
| 60 |
| 61 void SearchAction::OnSurroundingTextResponse( |
| 62 const base::string16& surrounding_text, |
| 63 int focus_start, |
| 64 int focus_end) { |
| 65 // Record the context, which can be accessed later on demand. |
| 66 search_context_->surrounding_text = surrounding_text; |
| 67 search_context_->start_offset = focus_start; |
| 68 search_context_->end_offset = focus_end; |
| 69 |
| 70 // Notify Java. |
| 71 JNIEnv* env = base::android::AttachCurrentThread(); |
| 72 Java_SearchAction_onSurroundingTextResponse(env, java_object_.obj()); |
| 73 } |
| 74 |
| 75 base::android::ScopedJavaLocalRef<jstring> SearchAction::GetFocusedWord( |
| 76 JNIEnv* env, |
| 77 const JavaParamRef<jobject>& obj) { |
| 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 std::string focused_word = |
| 84 base::UTF16ToUTF8(search_context_->surrounding_text.substr( |
| 85 focus.first, focus.second - focus.first)); |
| 86 base::android::ScopedJavaLocalRef<jstring> j_focused_word = |
| 87 base::android::ConvertUTF8ToJavaString(env, focused_word.c_str()); |
| 88 return j_focused_word; |
| 89 } |
| 90 |
| 91 base::android::ScopedJavaLocalRef<jstring> SearchAction::GetSampleText( |
| 92 JNIEnv* env, |
| 93 const JavaParamRef<jobject>& obj, |
| 94 int sample_length) { |
| 95 DCHECK(search_context_); |
| 96 // Trim surroundings to the requested sample size. |
| 97 std::pair<base::string16, int> sample = SampleSurroundings( |
| 98 search_context_->surrounding_text, search_context_->start_offset, |
| 99 search_context_->end_offset, sample_length); |
| 100 base::android::ScopedJavaLocalRef<jstring> j_surrounding_text_sample = |
| 101 base::android::ConvertUTF16ToJavaString(env, sample.first); |
| 102 return j_surrounding_text_sample; |
| 103 } |
| 104 |
| 105 // static |
| 106 std::pair<int, int> SearchAction::FindFocusedWord( |
| 107 const base::string16& surrounding_text, |
| 108 int focus_start, |
| 109 int focus_end) { |
| 110 int surrounding_text_length = surrounding_text.length(); |
| 111 |
| 112 // First, we need to find the focused word boundaries. |
| 113 int focused_word_start = focus_start; |
| 114 int focused_word_end = focus_end; |
| 115 |
| 116 if (surrounding_text_length > 0 && |
| 117 IsValidCharacter(surrounding_text[focused_word_start])) { |
| 118 // Find focused word start (inclusive) |
| 119 for (int i = focus_start; i >= 0; i--) { |
| 120 focused_word_start = i; |
| 121 |
| 122 wchar_t character; |
| 123 if (i > 0) { |
| 124 character = surrounding_text[i - 1]; |
| 125 |
| 126 if (!IsValidCharacter(character)) |
| 127 break; |
| 128 } |
| 129 } |
| 130 |
| 131 // Find focused word end (non inclusive) |
| 132 for (int i = focus_end; i < surrounding_text_length; i++) { |
| 133 wchar_t character = surrounding_text[i]; |
| 134 |
| 135 if (IsValidCharacter(character)) { |
| 136 focused_word_end = i + 1; |
| 137 } else { |
| 138 focused_word_end = i; |
| 139 break; |
| 140 } |
| 141 } |
| 142 } |
| 143 |
| 144 return std::pair<int, int>(focused_word_start, focused_word_end); |
| 145 } |
| 146 |
| 147 // static |
| 148 std::pair<base::string16, int> SearchAction::SampleSurroundings( |
| 149 const base::string16& surrounding_text, |
| 150 int focus_start, |
| 151 int focus_end, |
| 152 int surrounding_text_sample_limit) { |
| 153 int surrounding_text_length = surrounding_text.length(); |
| 154 |
| 155 //--------------------------------------------------------------------------- |
| 156 // Cut the surrounding size so it can be sent to the Java side. |
| 157 |
| 158 // Start equally distributing the size around the focal point. |
| 159 int focal_point_size = focus_end - focus_start; |
| 160 int sample_margin = (surrounding_text_sample_limit - focal_point_size) / 2; |
| 161 int sample_start = focus_start - sample_margin; |
| 162 int sample_end = focus_end + sample_margin; |
| 163 |
| 164 // If the the start is out of bounds, compensate the end side. |
| 165 if (sample_start < 0) { |
| 166 sample_end -= sample_start; |
| 167 sample_start = 0; |
| 168 } |
| 169 |
| 170 // If the the end is out of bounds, compensate the start side. |
| 171 if (sample_end > surrounding_text_length) { |
| 172 int diff = sample_end - surrounding_text_length; |
| 173 sample_end = surrounding_text_length; |
| 174 sample_start -= diff; |
| 175 } |
| 176 |
| 177 // Trim the start and end to make sure they are within bounds. |
| 178 sample_start = std::max(0, sample_start); |
| 179 sample_end = std::min(surrounding_text_length, sample_end); |
| 180 base::string16 sample_string( |
| 181 surrounding_text.substr(sample_start, sample_end - sample_start)); |
| 182 std::pair<base::string16, int> sample(sample_string, sample_start); |
| 183 return sample; |
| 184 } |
| 185 |
| 186 // static |
| 187 bool SearchAction::IsValidCharacter(int char_code) { |
| 188 // See http://www.unicode.org/Public/UCD/latest/ucd/NamesList.txt |
| 189 // See http://jrgraphix.net/research/unicode_blocks.php |
| 190 |
| 191 // TODO(pedrosimonetti): should not include CJK characters! |
| 192 // TODO(donnd): consider using regular expressions. |
| 193 |
| 194 if ((char_code >= 11264 && char_code <= 55295) || // Asian language symbols |
| 195 (char_code >= 192 && char_code <= 8191) || // Letters in many languages |
| 196 (char_code >= 97 && char_code <= 122) || // Lowercase letters |
| 197 (char_code >= 65 && char_code <= 90) || // Uppercase letters |
| 198 (char_code >= 48 && char_code <= 57)) { // Numbers |
| 199 return true; |
| 200 } |
| 201 |
| 202 return false; |
| 203 } |
| 204 |
| 205 bool RegisterSearchAction(JNIEnv* env) { |
| 206 return RegisterNativesImpl(env); |
| 207 } |
| 208 |
| 209 jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
| 210 SearchAction* content = new SearchAction(env, obj); |
| 211 return reinterpret_cast<intptr_t>(content); |
| 212 } |
OLD | NEW |