1 // Copyright (c) 2012 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/chromeos/extensions/input_method_api.h"
6 
7 #include <stddef.h>
8 #include <memory>
9 #include <set>
10 #include <string>
11 #include <utility>
12 
13 #include "base/bind.h"
14 #include "base/callback.h"
15 #include "base/lazy_instance.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/values.h"
19 #include "build/build_config.h"
20 #include "chrome/browser/chromeos/extensions/dictionary_event_router.h"
21 #include "chrome/browser/chromeos/extensions/ime_menu_event_router.h"
22 #include "chrome/browser/chromeos/extensions/input_method_event_router.h"
23 #include "chrome/browser/chromeos/input_method/autocorrect_manager.h"
24 #include "chrome/browser/chromeos/input_method/native_input_method_engine.h"
25 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/spellchecker/spellcheck_factory.h"
28 #include "chrome/browser/spellchecker/spellcheck_service.h"
29 #include "chrome/browser/sync/profile_sync_service_factory.h"
30 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
31 #include "chrome/browser/ui/browser.h"
32 #include "chrome/browser/ui/browser_finder.h"
33 #include "chrome/common/extensions/api/input_method_private.h"
34 #include "chrome/common/pref_names.h"
35 #include "components/prefs/pref_service.h"
36 #include "components/prefs/scoped_user_pref_update.h"
37 #include "components/sync/driver/sync_service.h"
38 #include "components/sync/driver/sync_user_settings.h"
39 #include "extensions/browser/extension_function_registry.h"
40 #include "extensions/browser/extension_system.h"
41 #include "ui/base/ime/chromeos/extension_ime_util.h"
42 #include "ui/base/ime/chromeos/ime_bridge.h"
43 #include "ui/base/ime/chromeos/ime_keyboard.h"
44 #include "ui/base/ime/chromeos/input_method_descriptor.h"
45 #include "ui/base/ime/chromeos/input_method_manager.h"
46 #include "ui/base/ime/chromeos/input_method_util.h"
47 
48 namespace input_method_private = extensions::api::input_method_private;
49 namespace AddWordToDictionary =
50     extensions::api::input_method_private::AddWordToDictionary;
51 namespace SetCurrentInputMethod =
52     extensions::api::input_method_private::SetCurrentInputMethod;
53 namespace SetXkbLayout = extensions::api::input_method_private::SetXkbLayout;
54 namespace OpenOptionsPage =
55     extensions::api::input_method_private::OpenOptionsPage;
56 namespace OnChanged = extensions::api::input_method_private::OnChanged;
57 namespace OnDictionaryChanged =
58     extensions::api::input_method_private::OnDictionaryChanged;
59 namespace OnDictionaryLoaded =
60     extensions::api::input_method_private::OnDictionaryLoaded;
61 namespace OnImeMenuActivationChanged =
62     extensions::api::input_method_private::OnImeMenuActivationChanged;
63 namespace OnImeMenuListChanged =
64     extensions::api::input_method_private::OnImeMenuListChanged;
65 namespace OnImeMenuItemsChanged =
66     extensions::api::input_method_private::OnImeMenuItemsChanged;
67 namespace GetSurroundingText =
68     extensions::api::input_method_private::GetSurroundingText;
69 namespace GetSettings = extensions::api::input_method_private::GetSettings;
70 namespace SetSettings = extensions::api::input_method_private::SetSettings;
71 namespace SetCompositionRange =
72     extensions::api::input_method_private::SetCompositionRange;
73 namespace SetComposingRange =
74     extensions::api::input_method_private::SetComposingRange;
75 namespace GetAutocorrectRange =
76     extensions::api::input_method_private::GetAutocorrectRange;
77 namespace GetAutocorrectCharacterBounds =
78     extensions::api::input_method_private::GetAutocorrectCharacterBounds;
79 namespace SetAutocorrectRange =
80     extensions::api::input_method_private::SetAutocorrectRange;
81 namespace SetSelectionRange =
82     extensions::api::input_method_private::SetSelectionRange;
83 namespace OnInputMethodOptionsChanged =
84     extensions::api::input_method_private::OnInputMethodOptionsChanged;
85 namespace OnAutocorrect = extensions::api::input_method_private::OnAutocorrect;
86 
87 using chromeos::InputMethodEngineBase;
88 
89 namespace {
90 
91 // Prefix, which is used by XKB.
92 const char kXkbPrefix[] = "xkb:";
93 const char kErrorFailToShowInputView[] =
94     "Unable to show the input view window because the keyboard is not enabled.";
95 const char kErrorFailToHideInputView[] =
96     "Unable to hide the input view window because the keyboard is not enabled.";
97 const char kErrorRouterNotAvailable[] = "The router is not available.";
98 const char kErrorInvalidInputMethod[] = "Input method not found.";
99 const char kErrorSpellCheckNotAvailable[] =
100     "Spellcheck service is not available.";
101 const char kErrorCustomDictionaryNotLoaded[] =
102     "Custom dictionary is not loaded yet.";
103 const char kErrorInvalidWord[] = "Unable to add invalid word to dictionary.";
104 const char kErrorSyncServiceNotReady[] =
105     "Sync service is not ready for current profile.";
106 const char kErrorInputContextHandlerNotAvailable[] =
107     "Input context handler is not available.";
108 const char kErrorInvalidParametersForGetSurroundingText[] =
109     "Invalid negative parameters for GetSurroundingText.";
110 
GetEngineIfActive(content::BrowserContext * browser_context,const std::string & extension_id,std::string * error)111 InputMethodEngineBase* GetEngineIfActive(
112     content::BrowserContext* browser_context,
113     const std::string& extension_id,
114     std::string* error) {
115   Profile* profile = Profile::FromBrowserContext(browser_context);
116   extensions::InputImeEventRouter* event_router =
117       extensions::GetInputImeEventRouter(profile);
118   DCHECK(event_router) << kErrorRouterNotAvailable;
119   InputMethodEngineBase* engine =
120       event_router->GetEngineIfActive(extension_id, error);
121   return engine;
122 }
123 
124 }  // namespace
125 
126 namespace extensions {
127 
128 ExtensionFunction::ResponseAction
Run()129 InputMethodPrivateGetInputMethodConfigFunction::Run() {
130   std::unique_ptr<base::DictionaryValue> output(new base::DictionaryValue());
131   output->SetBoolean("isPhysicalKeyboardAutocorrectEnabled", true);
132   output->SetBoolean("isImeMenuActivated",
133                      Profile::FromBrowserContext(browser_context())
134                          ->GetPrefs()
135                          ->GetBoolean(prefs::kLanguageImeMenuActivated));
136   return RespondNow(
137       OneArgument(base::Value::FromUniquePtrValue(std::move(output))));
138 }
139 
140 ExtensionFunction::ResponseAction
Run()141 InputMethodPrivateGetCurrentInputMethodFunction::Run() {
142   chromeos::input_method::InputMethodManager* manager =
143       chromeos::input_method::InputMethodManager::Get();
144   return RespondNow(OneArgument(
145       base::Value(manager->GetActiveIMEState()->GetCurrentInputMethod().id())));
146 }
147 
148 ExtensionFunction::ResponseAction
Run()149 InputMethodPrivateSetCurrentInputMethodFunction::Run() {
150   std::unique_ptr<SetCurrentInputMethod::Params> params(
151       SetCurrentInputMethod::Params::Create(*args_));
152   EXTENSION_FUNCTION_VALIDATE(params.get());
153   scoped_refptr<chromeos::input_method::InputMethodManager::State> ime_state =
154       chromeos::input_method::InputMethodManager::Get()->GetActiveIMEState();
155   const std::vector<std::string>& input_methods =
156       ime_state->GetActiveInputMethodIds();
157   for (size_t i = 0; i < input_methods.size(); ++i) {
158     const std::string& input_method = input_methods[i];
159     if (input_method == params->input_method_id) {
160       ime_state->ChangeInputMethod(params->input_method_id,
161                                    false /* show_message */);
162       return RespondNow(NoArguments());
163     }
164   }
165   return RespondNow(Error(InformativeError(
166       base::StringPrintf("%s Input Method: %s", kErrorInvalidInputMethod,
167                          params->input_method_id.c_str()),
168       static_function_name())));
169 }
170 
171 ExtensionFunction::ResponseAction
Run()172 InputMethodPrivateGetInputMethodsFunction::Run() {
173   std::unique_ptr<base::ListValue> output(new base::ListValue());
174   chromeos::input_method::InputMethodManager* manager =
175       chromeos::input_method::InputMethodManager::Get();
176   chromeos::input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
177   scoped_refptr<chromeos::input_method::InputMethodManager::State> ime_state =
178       manager->GetActiveIMEState();
179   std::unique_ptr<chromeos::input_method::InputMethodDescriptors>
180       input_methods = ime_state->GetActiveInputMethods();
181   for (size_t i = 0; i < input_methods->size(); ++i) {
182     const chromeos::input_method::InputMethodDescriptor& input_method =
183         (*input_methods)[i];
184     auto val = std::make_unique<base::DictionaryValue>();
185     val->SetString("id", input_method.id());
186     val->SetString("name", util->GetInputMethodLongName(input_method));
187     val->SetString("indicator", util->GetInputMethodShortName(input_method));
188     output->Append(std::move(val));
189   }
190   return RespondNow(
191       OneArgument(base::Value::FromUniquePtrValue(std::move(output))));
192 }
193 
194 ExtensionFunction::ResponseAction
Run()195 InputMethodPrivateFetchAllDictionaryWordsFunction::Run() {
196   SpellcheckService* spellcheck =
197       SpellcheckServiceFactory::GetForContext(browser_context());
198   if (!spellcheck) {
199     return RespondNow(Error(InformativeError(kErrorSpellCheckNotAvailable,
200                                              static_function_name())));
201   }
202   SpellcheckCustomDictionary* dictionary = spellcheck->GetCustomDictionary();
203   if (!dictionary->IsLoaded()) {
204     return RespondNow(Error(InformativeError(kErrorCustomDictionaryNotLoaded,
205                                              static_function_name())));
206   }
207 
208   const std::set<std::string>& words = dictionary->GetWords();
209   std::unique_ptr<base::ListValue> output(new base::ListValue());
210   for (auto it = words.begin(); it != words.end(); ++it) {
211     output->AppendString(*it);
212   }
213   return RespondNow(
214       OneArgument(base::Value::FromUniquePtrValue(std::move(output))));
215 }
216 
217 ExtensionFunction::ResponseAction
Run()218 InputMethodPrivateAddWordToDictionaryFunction::Run() {
219   std::unique_ptr<AddWordToDictionary::Params> params(
220       AddWordToDictionary::Params::Create(*args_));
221   EXTENSION_FUNCTION_VALIDATE(params.get());
222   SpellcheckService* spellcheck =
223       SpellcheckServiceFactory::GetForContext(browser_context());
224   if (!spellcheck) {
225     return RespondNow(Error(InformativeError(kErrorSpellCheckNotAvailable,
226                                              static_function_name())));
227   }
228   SpellcheckCustomDictionary* dictionary = spellcheck->GetCustomDictionary();
229   if (!dictionary->IsLoaded()) {
230     return RespondNow(Error(InformativeError(kErrorCustomDictionaryNotLoaded,
231                                              static_function_name())));
232   }
233 
234   if (dictionary->AddWord(params->word))
235     return RespondNow(NoArguments());
236   // Invalid words:
237   // - Already in the dictionary.
238   // - Not a UTF8 string.
239   // - Longer than 99 bytes (kMaxCustomDictionaryWordBytes).
240   // - Leading/trailing whitespace.
241   // - Empty.
242   return RespondNow(Error(
243       InformativeError(base::StringPrintf("%s. Word: %s", kErrorInvalidWord,
244                                           params->word.c_str()),
245                        static_function_name())));
246 }
247 
248 ExtensionFunction::ResponseAction
Run()249 InputMethodPrivateGetEncryptSyncEnabledFunction::Run() {
250   syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForProfile(
251       Profile::FromBrowserContext(browser_context()));
252   if (!sync_service)
253     return RespondNow(Error(
254         InformativeError(kErrorSyncServiceNotReady, static_function_name())));
255   std::unique_ptr<base::Value> ret(new base::Value(
256       sync_service->GetUserSettings()->IsEncryptEverythingEnabled()));
257   return RespondNow(
258       OneArgument(base::Value::FromUniquePtrValue(std::move(ret))));
259 }
260 
261 ExtensionFunction::ResponseAction
Run()262 InputMethodPrivateSetXkbLayoutFunction::Run() {
263   std::unique_ptr<SetXkbLayout::Params> params(
264       SetXkbLayout::Params::Create(*args_));
265   EXTENSION_FUNCTION_VALIDATE(params.get());
266   chromeos::input_method::InputMethodManager* manager =
267       chromeos::input_method::InputMethodManager::Get();
268   chromeos::input_method::ImeKeyboard* keyboard = manager->GetImeKeyboard();
269   keyboard->SetCurrentKeyboardLayoutByName(params->xkb_name);
270   return RespondNow(NoArguments());
271 }
272 
273 ExtensionFunction::ResponseAction
Run()274 InputMethodPrivateShowInputViewFunction::Run() {
275   auto* keyboard_client = ChromeKeyboardControllerClient::Get();
276   if (!keyboard_client->is_keyboard_enabled()) {
277     return RespondNow(Error(kErrorFailToShowInputView));
278   }
279 
280   keyboard_client->ShowKeyboard();
281   return RespondNow(NoArguments());
282 }
283 
284 ExtensionFunction::ResponseAction
Run()285 InputMethodPrivateHideInputViewFunction::Run() {
286   auto* keyboard_client = ChromeKeyboardControllerClient::Get();
287   if (!keyboard_client->is_keyboard_enabled()) {
288     return RespondNow(Error(kErrorFailToHideInputView));
289   }
290 
291   keyboard_client->HideKeyboard(ash::HideReason::kUser);
292   return RespondNow(NoArguments());
293 }
294 
295 ExtensionFunction::ResponseAction
Run()296 InputMethodPrivateOpenOptionsPageFunction::Run() {
297   std::unique_ptr<OpenOptionsPage::Params> params(
298       OpenOptionsPage::Params::Create(*args_));
299   EXTENSION_FUNCTION_VALIDATE(params.get());
300   scoped_refptr<chromeos::input_method::InputMethodManager::State> ime_state =
301       chromeos::input_method::InputMethodManager::Get()->GetActiveIMEState();
302   const chromeos::input_method::InputMethodDescriptor* ime =
303       ime_state->GetInputMethodFromId(params->input_method_id);
304   if (!ime)
305     return RespondNow(Error(InformativeError(
306         base::StringPrintf("%s Input Method: %s", kErrorInvalidInputMethod,
307                            params->input_method_id.c_str()),
308         static_function_name())));
309 
310   content::WebContents* web_contents = GetSenderWebContents();
311   if (web_contents) {
312     const GURL& options_page_url = ime->options_page_url();
313     if (!options_page_url.is_empty()) {
314       Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
315       content::OpenURLParams url_params(options_page_url, content::Referrer(),
316                                         WindowOpenDisposition::SINGLETON_TAB,
317                                         ui::PAGE_TRANSITION_LINK, false);
318       browser->OpenURL(url_params);
319     }
320   }
321   return RespondNow(NoArguments());
322 }
323 
324 ExtensionFunction::ResponseAction
Run()325 InputMethodPrivateGetSurroundingTextFunction::Run() {
326   ui::IMEInputContextHandlerInterface* input_context =
327       ui::IMEBridge::Get()->GetInputContextHandler();
328   if (!input_context)
329     return RespondNow(Error(InformativeError(
330         kErrorInputContextHandlerNotAvailable, static_function_name())));
331 
332   std::unique_ptr<GetSurroundingText::Params> params(
333       GetSurroundingText::Params::Create(*args_));
334   if (params->before_length < 0 || params->after_length < 0)
335     return RespondNow(Error(InformativeError(
336         base::StringPrintf("%s before_length = %d, after_length = %d.",
337                            kErrorInvalidParametersForGetSurroundingText,
338                            params->before_length, params->after_length),
339         static_function_name())));
340 
341   uint32_t param_before_length = (uint32_t)params->before_length;
342   uint32_t param_after_length = (uint32_t)params->after_length;
343 
344   ui::SurroundingTextInfo info = input_context->GetSurroundingTextInfo();
345   if (!info.selection_range.IsValid())
346     return RespondNow(OneArgument(base::Value()));
347 
348   auto ret = std::make_unique<base::DictionaryValue>();
349   uint32_t selection_start = info.selection_range.start();
350   uint32_t selection_end = info.selection_range.end();
351   // Makes sure |selection_start| is less or equals to |selection_end|.
352   if (selection_start > selection_end)
353     std::swap(selection_start, selection_end);
354 
355   uint32_t text_before_end = selection_start;
356   uint32_t text_before_start = text_before_end > param_before_length
357                                    ? text_before_end - param_before_length
358                                    : 0;
359   uint32_t text_after_start = selection_end;
360   uint32_t text_after_end =
361       text_after_start + param_after_length < info.surrounding_text.length()
362           ? text_after_start + param_after_length
363           : info.surrounding_text.length();
364 
365   ret->SetString("before",
366                  info.surrounding_text.substr(
367                      text_before_start, text_before_end - text_before_start));
368   ret->SetString("selected",
369                  info.surrounding_text.substr(
370                      text_before_end, text_after_start - text_before_end));
371   ret->SetString(
372       "after", info.surrounding_text.substr(text_after_start,
373                                             text_after_end - text_after_start));
374 
375   return RespondNow(
376       OneArgument(base::Value::FromUniquePtrValue(std::move(ret))));
377 }
378 
Run()379 ExtensionFunction::ResponseAction InputMethodPrivateGetSettingsFunction::Run() {
380   const auto params = GetSettings::Params::Create(*args_);
381   EXTENSION_FUNCTION_VALIDATE(params.get());
382 
383   const base::DictionaryValue* input_methods =
384       Profile::FromBrowserContext(browser_context())
385           ->GetPrefs()
386           ->GetDictionary(prefs::kLanguageInputMethodSpecificSettings);
387   const base::Value* engine_result = input_methods->FindPath(params->engine_id);
388   base::Value result;
389   if (engine_result)
390     result = engine_result->Clone();
391   return RespondNow(OneArgument(std::move(result)));
392 }
393 
Run()394 ExtensionFunction::ResponseAction InputMethodPrivateSetSettingsFunction::Run() {
395   const auto params = SetSettings::Params::Create(*args_);
396   EXTENSION_FUNCTION_VALIDATE(params.get());
397 
398   DictionaryPrefUpdate update(
399       Profile::FromBrowserContext(browser_context())->GetPrefs(),
400       prefs::kLanguageInputMethodSpecificSettings);
401   update->SetPath(params->engine_id, params->settings.ToValue()->Clone());
402 
403   // The router will only send the event to extensions that are listening.
404   extensions::EventRouter* router =
405       extensions::EventRouter::Get(browser_context());
406   if (router->HasEventListener(OnInputMethodOptionsChanged::kEventName)) {
407     auto event = std::make_unique<extensions::Event>(
408         extensions::events::INPUT_IME_ON_INPUT_METHOD_OPTIONS_CHANGED,
409         OnInputMethodOptionsChanged::kEventName,
410         OnInputMethodOptionsChanged::Create(params->engine_id),
411         browser_context());
412     router->BroadcastEvent(std::move(event));
413   }
414 
415   return RespondNow(NoArguments());
416 }
417 
418 ExtensionFunction::ResponseAction
Run()419 InputMethodPrivateSetCompositionRangeFunction::Run() {
420   std::string error;
421   InputMethodEngineBase* engine =
422       GetEngineIfActive(browser_context(), extension_id(), &error);
423   if (!engine)
424     return RespondNow(Error(InformativeError(error, static_function_name())));
425 
426   const auto parent_params = SetCompositionRange::Params::Create(*args_);
427   const auto& params = parent_params->parameters;
428   std::vector<InputMethodEngineBase::SegmentInfo> segments;
429   if (params.segments) {
430     for (const auto& segments_arg : *params.segments) {
431       InputMethodEngineBase::SegmentInfo segment_info;
432       segment_info.start = segments_arg.start;
433       segment_info.end = segments_arg.end;
434       switch (segments_arg.style) {
435         case input_method_private::UNDERLINE_STYLE_UNDERLINE:
436           segment_info.style = InputMethodEngineBase::SEGMENT_STYLE_UNDERLINE;
437           break;
438         case input_method_private::UNDERLINE_STYLE_DOUBLEUNDERLINE:
439           segment_info.style =
440               InputMethodEngineBase::SEGMENT_STYLE_DOUBLE_UNDERLINE;
441           break;
442         case input_method_private::UNDERLINE_STYLE_NOUNDERLINE:
443           segment_info.style =
444               InputMethodEngineBase::SEGMENT_STYLE_NO_UNDERLINE;
445           break;
446         case input_method_private::UNDERLINE_STYLE_NONE:
447           EXTENSION_FUNCTION_VALIDATE(false);
448           break;
449       }
450       segments.push_back(segment_info);
451     }
452   } else {
453     // Default to a single segment that spans the entire range.
454     InputMethodEngineBase::SegmentInfo segment_info;
455     segment_info.start = 0;
456     segment_info.end = params.selection_before + params.selection_after;
457     segment_info.style = InputMethodEngineBase::SEGMENT_STYLE_UNDERLINE;
458     segments.push_back(segment_info);
459   }
460 
461   if (!engine->SetCompositionRange(params.context_id, params.selection_before,
462                                    params.selection_after, segments, &error)) {
463     return RespondNow(Error(InformativeError(error, static_function_name())));
464   }
465   return RespondNow(OneArgument(base::Value(true)));
466 }
467 
468 ExtensionFunction::ResponseAction
Run()469 InputMethodPrivateSetComposingRangeFunction::Run() {
470   std::string error;
471   InputMethodEngineBase* engine =
472       GetEngineIfActive(browser_context(), extension_id(), &error);
473   if (!engine)
474     return RespondNow(Error(InformativeError(error, static_function_name())));
475 
476   const auto parent_params = SetComposingRange::Params::Create(*args_);
477   const auto& params = parent_params->parameters;
478   std::vector<InputMethodEngineBase::SegmentInfo> segments;
479   if (params.segments) {
480     for (const auto& segments_arg : *params.segments) {
481       InputMethodEngineBase::SegmentInfo segment_info;
482       segment_info.start = segments_arg.start;
483       segment_info.end = segments_arg.end;
484       switch (segments_arg.style) {
485         case input_method_private::UNDERLINE_STYLE_UNDERLINE:
486           segment_info.style = InputMethodEngineBase::SEGMENT_STYLE_UNDERLINE;
487           break;
488         case input_method_private::UNDERLINE_STYLE_DOUBLEUNDERLINE:
489           segment_info.style =
490               InputMethodEngineBase::SEGMENT_STYLE_DOUBLE_UNDERLINE;
491           break;
492         case input_method_private::UNDERLINE_STYLE_NOUNDERLINE:
493           segment_info.style =
494               InputMethodEngineBase::SEGMENT_STYLE_NO_UNDERLINE;
495           break;
496         case input_method_private::UNDERLINE_STYLE_NONE:
497           EXTENSION_FUNCTION_VALIDATE(false);
498           break;
499       }
500       segments.push_back(segment_info);
501     }
502   } else {
503     // Default to a single segment that spans the entire composing range.
504     InputMethodEngineBase::SegmentInfo segment_info;
505     segment_info.start = 0;
506     segment_info.end = params.end - params.start;
507     segment_info.style = InputMethodEngineBase::SEGMENT_STYLE_UNDERLINE;
508     segments.push_back(segment_info);
509   }
510 
511   if (!engine->SetComposingRange(params.context_id, params.start, params.end,
512                                  segments, &error)) {
513     return RespondNow(Error(InformativeError(error, static_function_name())));
514   }
515   return RespondNow(NoArguments());
516 }
517 
518 ExtensionFunction::ResponseAction
Run()519 InputMethodPrivateGetAutocorrectRangeFunction::Run() {
520   std::string error;
521   InputMethodEngineBase* engine =
522       GetEngineIfActive(browser_context(), extension_id(), &error);
523   if (!engine)
524     return RespondNow(Error(InformativeError(error, static_function_name())));
525 
526   const auto parent_params = GetAutocorrectRange::Params::Create(*args_);
527   const auto& params = parent_params->parameters;
528   const gfx::Range range =
529       engine->GetAutocorrectRange(params.context_id, &error);
530   auto ret = std::make_unique<base::DictionaryValue>();
531   ret->SetInteger("start", range.is_empty() ? 0 : range.start());
532   ret->SetInteger("end", range.is_empty() ? 0 : range.end());
533   return RespondNow(
534       OneArgument(base::Value::FromUniquePtrValue(std::move(ret))));
535 }
536 
537 ExtensionFunction::ResponseAction
Run()538 InputMethodPrivateGetAutocorrectCharacterBoundsFunction::Run() {
539   std::string error;
540   InputMethodEngineBase* engine =
541       GetEngineIfActive(browser_context(), extension_id(), &error);
542   if (!engine)
543     return RespondNow(Error(InformativeError(error, static_function_name())));
544 
545   const auto parent_params =
546       GetAutocorrectCharacterBounds::Params::Create(*args_);
547   const auto& params = parent_params->parameters;
548   const gfx::Rect rect =
549       engine->GetAutocorrectCharacterBounds(params.context_id, &error);
550   if (rect.IsEmpty()) {
551     return RespondNow(Error(InformativeError(error, static_function_name())));
552   }
553   auto ret = std::make_unique<base::DictionaryValue>();
554   ret->SetInteger("x", rect.x());
555   ret->SetInteger("y", rect.y());
556   ret->SetInteger("width", rect.width());
557   ret->SetInteger("height", rect.height());
558   return RespondNow(
559       OneArgument(base::Value::FromUniquePtrValue(std::move(ret))));
560 }
561 
562 ExtensionFunction::ResponseAction
Run()563 InputMethodPrivateSetAutocorrectRangeFunction::Run() {
564   std::string error;
565   InputMethodEngineBase* engine =
566       GetEngineIfActive(browser_context(), extension_id(), &error);
567   if (!engine)
568     return RespondNow(Error(InformativeError(error, static_function_name())));
569 
570   const auto parent_params = SetAutocorrectRange::Params::Create(*args_);
571   const auto& params = parent_params->parameters;
572   if (!engine->SetAutocorrectRange(
573           params.context_id, base::UTF8ToUTF16(params.autocorrect_string),
574           params.selection_start, params.selection_end, &error)) {
575     auto results = std::make_unique<base::ListValue>();
576     results->Append(std::make_unique<base::Value>(false));
577     return RespondNow(Error(InformativeError(error, static_function_name())));
578   }
579   return RespondNow(NoArguments());
580 }
581 
582 ExtensionFunction::ResponseAction
Run()583 InputMethodPrivateSetSelectionRangeFunction::Run() {
584   std::string error;
585   InputMethodEngineBase* engine =
586       GetEngineIfActive(browser_context(), extension_id(), &error);
587   if (!engine)
588     return RespondNow(Error(InformativeError(error, static_function_name())));
589 
590   std::unique_ptr<SetSelectionRange::Params> parent_params(
591       SetSelectionRange::Params::Create(*args_));
592   const SetSelectionRange::Params::Parameters& params =
593       parent_params->parameters;
594 
595   if (!engine->SetSelectionRange(params.context_id, *params.selection_start,
596                                  *params.selection_end, &error)) {
597     auto results = std::make_unique<base::ListValue>();
598     results->Append(std::make_unique<base::Value>(false));
599     return RespondNow(ErrorWithArguments(
600         std::move(results), InformativeError(error, static_function_name())));
601   }
602   return RespondNow(OneArgument(base::Value(true)));
603 }
604 
Run()605 ExtensionFunction::ResponseAction InputMethodPrivateResetFunction::Run() {
606   std::string error;
607   InputMethodEngineBase* engine =
608       GetEngineIfActive(browser_context(), extension_id(), &error);
609   if (!engine)
610     return RespondNow(Error(InformativeError(error, static_function_name())));
611 
612   engine->Reset();
613   return RespondNow(NoArguments());
614 }
615 
616 ExtensionFunction::ResponseAction
Run()617 InputMethodPrivateOnAutocorrectFunction::Run() {
618   std::unique_ptr<OnAutocorrect::Params> parent_params(
619       OnAutocorrect::Params::Create(*args_));
620   const OnAutocorrect::Params::Parameters& params = parent_params->parameters;
621   std::string error;
622   chromeos::NativeInputMethodEngine* engine =
623       static_cast<chromeos::NativeInputMethodEngine*>(
624           GetEngineIfActive(Profile::FromBrowserContext(browser_context()),
625                             extension_id(), &error));
626   if (!engine)
627     return RespondNow(Error(InformativeError(error, static_function_name())));
628 
629   engine->OnAutocorrect(params.typed_word, params.corrected_word,
630                         params.start_index);
631   return RespondNow(NoArguments());
632 }
633 
InputMethodAPI(content::BrowserContext * context)634 InputMethodAPI::InputMethodAPI(content::BrowserContext* context)
635     : context_(context) {
636   EventRouter::Get(context_)->RegisterObserver(this, OnChanged::kEventName);
637   EventRouter::Get(context_)
638       ->RegisterObserver(this, OnDictionaryChanged::kEventName);
639   EventRouter::Get(context_)
640       ->RegisterObserver(this, OnDictionaryLoaded::kEventName);
641   EventRouter::Get(context_)
642       ->RegisterObserver(this, OnImeMenuActivationChanged::kEventName);
643   EventRouter::Get(context_)
644       ->RegisterObserver(this, OnImeMenuListChanged::kEventName);
645   EventRouter::Get(context_)
646       ->RegisterObserver(this, OnImeMenuItemsChanged::kEventName);
647   ExtensionFunctionRegistry& registry =
648       ExtensionFunctionRegistry::GetInstance();
649   registry.RegisterFunction<InputMethodPrivateGetInputMethodConfigFunction>();
650   registry.RegisterFunction<InputMethodPrivateGetCurrentInputMethodFunction>();
651   registry.RegisterFunction<InputMethodPrivateSetCurrentInputMethodFunction>();
652   registry.RegisterFunction<InputMethodPrivateGetInputMethodsFunction>();
653   registry
654       .RegisterFunction<InputMethodPrivateFetchAllDictionaryWordsFunction>();
655   registry.RegisterFunction<InputMethodPrivateAddWordToDictionaryFunction>();
656   registry.RegisterFunction<InputMethodPrivateGetEncryptSyncEnabledFunction>();
657   registry
658       .RegisterFunction<InputMethodPrivateNotifyImeMenuItemActivatedFunction>();
659   registry.RegisterFunction<InputMethodPrivateOpenOptionsPageFunction>();
660 }
661 
~InputMethodAPI()662 InputMethodAPI::~InputMethodAPI() {
663 }
664 
665 // static
GetInputMethodForXkb(const std::string & xkb_id)666 std::string InputMethodAPI::GetInputMethodForXkb(const std::string& xkb_id) {
667   std::string xkb_prefix =
668       chromeos::extension_ime_util::GetInputMethodIDByEngineID(kXkbPrefix);
669   size_t prefix_length = xkb_prefix.length();
670   DCHECK(xkb_id.substr(0, prefix_length) == xkb_prefix);
671   return xkb_id.substr(prefix_length);
672 }
673 
Shutdown()674 void InputMethodAPI::Shutdown() {
675   EventRouter::Get(context_)->UnregisterObserver(this);
676 }
677 
OnListenerAdded(const extensions::EventListenerInfo & details)678 void InputMethodAPI::OnListenerAdded(
679     const extensions::EventListenerInfo& details) {
680   if (details.event_name == OnChanged::kEventName &&
681       !input_method_event_router_.get()) {
682     input_method_event_router_.reset(
683         new chromeos::ExtensionInputMethodEventRouter(context_));
684   } else if (details.event_name == OnDictionaryChanged::kEventName ||
685              details.event_name == OnDictionaryLoaded::kEventName) {
686     if (!dictionary_event_router_.get()) {
687       dictionary_event_router_.reset(
688           new chromeos::ExtensionDictionaryEventRouter(context_));
689     }
690     if (details.event_name == OnDictionaryLoaded::kEventName) {
691       dictionary_event_router_->DispatchLoadedEventIfLoaded();
692     }
693   } else if ((details.event_name == OnImeMenuActivationChanged::kEventName ||
694               details.event_name == OnImeMenuListChanged::kEventName ||
695               details.event_name == OnImeMenuItemsChanged::kEventName) &&
696              !ime_menu_event_router_.get()) {
697     ime_menu_event_router_.reset(
698         new chromeos::ExtensionImeMenuEventRouter(context_));
699   }
700 }
701 
702 static base::LazyInstance<
703     BrowserContextKeyedAPIFactory<InputMethodAPI>>::DestructorAtExit g_factory =
704     LAZY_INSTANCE_INITIALIZER;
705 
706 // static
707 BrowserContextKeyedAPIFactory<InputMethodAPI>*
GetFactoryInstance()708 InputMethodAPI::GetFactoryInstance() {
709   return g_factory.Pointer();
710 }
711 
712 }  // namespace extensions
713