File: spellchecker_session_bridge_android.cc

package info (click to toggle)
chromium-browser 57.0.2987.98-1~deb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 2,637,852 kB
  • ctags: 2,544,394
  • sloc: cpp: 12,815,961; ansic: 3,676,222; python: 1,147,112; asm: 526,608; java: 523,212; xml: 286,794; perl: 92,654; sh: 86,408; objc: 73,271; makefile: 27,698; cs: 18,487; yacc: 13,031; tcl: 12,957; pascal: 4,875; ml: 4,716; lex: 3,904; sql: 3,862; ruby: 1,982; lisp: 1,508; php: 1,368; exp: 404; awk: 325; csh: 117; jsp: 39; sed: 37
file content (151 lines) | stat: -rw-r--r-- 5,248 bytes parent folder | download
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
// 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 "components/spellcheck/browser/spellchecker_session_bridge_android.h"

#include <stddef.h>
#include <utility>

#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/metrics/histogram_macros.h"
#include "components/spellcheck/common/spellcheck_messages.h"
#include "components/spellcheck/common/spellcheck_result.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "jni/SpellCheckerSessionBridge_jni.h"

using base::android::JavaParamRef;

namespace {

void RecordAvailabilityUMA(bool spellcheck_available) {
  UMA_HISTOGRAM_BOOLEAN("Spellcheck.Android.Available", spellcheck_available);
}

}  // namespace

SpellCheckerSessionBridge::SpellCheckerSessionBridge(int render_process_id)
    : render_process_id_(render_process_id),
      java_object_initialization_failed_(false),
      active_session_(false) {}

SpellCheckerSessionBridge::~SpellCheckerSessionBridge() {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  // Clean-up java side to avoid any stale JNI callbacks.
  DisconnectSession();
}

// static
bool SpellCheckerSessionBridge::RegisterJNI(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

void SpellCheckerSessionBridge::RequestTextCheck(int route_id,
                                                 int identifier,
                                                 const base::string16& text) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  // SpellCheckerSessionBridge#create() will return null if spell checker
  // service is unavailable.
  if (java_object_initialization_failed_) {
    if (!active_session_) {
      RecordAvailabilityUMA(false);
      active_session_ = true;
    }
    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<intptr_t>(this)));
    if (!active_session_) {
      RecordAvailabilityUMA(!java_object_.is_null());
      active_session_ = true;
    }
    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_, base::android::ConvertUTF16ToJavaString(env, text));
}

void SpellCheckerSessionBridge::ProcessSpellCheckResults(
    JNIEnv* env,
    const JavaParamRef<jobject>& jobj,
    const JavaParamRef<jintArray>& offset_array,
    const JavaParamRef<jintArray>& length_array) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  std::vector<int> offsets;
  std::vector<int> lengths;

  base::android::JavaIntArrayToIntVector(env, offset_array, &offsets);
  base::android::JavaIntArrayToIntVector(env, length_array, &lengths);

  std::vector<SpellCheckResult> 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_,
        base::android::ConvertUTF16ToJavaString(env, active_request_->text));
  }
}

void SpellCheckerSessionBridge::DisconnectSession() {
  // Needs to be executed on the same thread as the RequestTextCheck and
  // ProcessSpellCheckResults methods, which is the UI thread.
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  active_request_.reset();
  pending_request_.reset();
  active_session_ = false;

  if (!java_object_.is_null()) {
    Java_SpellCheckerSessionBridge_disconnect(
        base::android::AttachCurrentThread(), java_object_);
    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() {}