// Copyright 2015 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 "chrome/browser/spellchecker/spellchecker_session_bridge_android.h" #include #include #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "chrome/common/spellcheck_messages.h" #include "chrome/common/spellcheck_result.h" #include "content/public/browser/render_process_host.h" #include "jni/SpellCheckerSessionBridge_jni.h" SpellCheckerSessionBridge::SpellCheckerSessionBridge(int render_process_id) : render_process_id_(render_process_id) {} SpellCheckerSessionBridge::~SpellCheckerSessionBridge() {} // static bool SpellCheckerSessionBridge::RegisterJNI(JNIEnv* env) { return RegisterNativesImpl(env); } void SpellCheckerSessionBridge::RequestTextCheck(int route_id, int identifier, const base::string16& text) { // SpellCheckerSessionBridge#create() will return null if spell checker // service is unavailable. if (java_object_initialization_failed_) return; // RequestTextCheck IPC arrives at the message filter before // ToggleSpellCheck IPC when the user focuses an input field that already // contains completed text. We need to initialize the spellchecker here // rather than in response to ToggleSpellCheck so that the existing text // will be spellchecked immediately. if (java_object_.is_null()) { java_object_.Reset(Java_SpellCheckerSessionBridge_create( base::android::AttachCurrentThread(), reinterpret_cast(this))); if (java_object_.is_null()) { java_object_initialization_failed_ = true; return; } } // Save incoming requests to run at the end of the currently active request. // If multiple requests arrive during one active request, only the most // recent request will run (the others get overwritten). if (active_request_) { pending_request_.reset(new SpellingRequest(route_id, identifier, text)); return; } active_request_.reset(new SpellingRequest(route_id, identifier, text)); JNIEnv* env = base::android::AttachCurrentThread(); Java_SpellCheckerSessionBridge_requestTextCheck( env, java_object_.obj(), base::android::ConvertUTF16ToJavaString(env, text).obj()); } void SpellCheckerSessionBridge::ProcessSpellCheckResults( JNIEnv* env, const JavaParamRef& jobj, const JavaParamRef& offset_array, const JavaParamRef& length_array) { std::vector offsets; std::vector lengths; base::android::JavaIntArrayToIntVector(env, offset_array, &offsets); base::android::JavaIntArrayToIntVector(env, length_array, &lengths); std::vector results; for (size_t i = 0; i < offsets.size(); i++) { results.push_back( SpellCheckResult(SpellCheckResult::SPELLING, offsets[i], lengths[i])); } content::RenderProcessHost* sender = content::RenderProcessHost::FromID(render_process_id_); if (sender != nullptr) { sender->Send(new SpellCheckMsg_RespondTextCheck( active_request_->route_id, active_request_->identifier, active_request_->text, results)); } active_request_ = std::move(pending_request_); if (active_request_) { JNIEnv* env = base::android::AttachCurrentThread(); Java_SpellCheckerSessionBridge_requestTextCheck( env, java_object_.obj(), base::android::ConvertUTF16ToJavaString(env, active_request_->text) .obj()); } } void SpellCheckerSessionBridge::DisconnectSession() { java_object_.Reset(); } SpellCheckerSessionBridge::SpellingRequest::SpellingRequest( int route_id, int identifier, const base::string16& text) : route_id(route_id), identifier(identifier), text(text) {} SpellCheckerSessionBridge::SpellingRequest::~SpellingRequest() {}