2ae8213740bad1be5763c555282ca790d3e47f4f
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / input_ime / input_ime_api.cc
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/extensions/api/input_ime/input_ime_api.h"
6
7 #include "base/strings/string_number_conversions.h"
8 #include "base/values.h"
9 #include "chrome/browser/chromeos/profiles/profile_helper.h"
10 #include "chrome/browser/profiles/profile_manager.h"
11 #include "chrome/common/extensions/api/input_ime.h"
12 #include "chrome/common/extensions/api/input_ime/input_components_handler.h"
13 #include "extensions/browser/event_router.h"
14 #include "extensions/browser/extension_function_registry.h"
15 #include "extensions/browser/extension_registry.h"
16
17 #if defined(USE_X11)
18 #include "chrome/browser/chromeos/input_method/input_method_engine.h"
19 #endif
20
21 namespace input_ime = extensions::api::input_ime;
22 namespace KeyEventHandled = extensions::api::input_ime::KeyEventHandled;
23 namespace DeleteSurroundingText =
24     extensions::api::input_ime::DeleteSurroundingText;
25 namespace UpdateMenuItems = extensions::api::input_ime::UpdateMenuItems;
26 namespace SendKeyEvents = extensions::api::input_ime::SendKeyEvents;
27 namespace HideInputView = extensions::api::input_ime::HideInputView;
28 namespace SetMenuItems = extensions::api::input_ime::SetMenuItems;
29 namespace SetCursorPosition = extensions::api::input_ime::SetCursorPosition;
30 namespace SetCandidates = extensions::api::input_ime::SetCandidates;
31 namespace SetCandidateWindowProperties =
32     extensions::api::input_ime::SetCandidateWindowProperties;
33 namespace CommitText = extensions::api::input_ime::CommitText;
34 namespace ClearComposition = extensions::api::input_ime::ClearComposition;
35 namespace SetComposition = extensions::api::input_ime::SetComposition;
36 using chromeos::InputMethodEngineInterface;
37
38 namespace {
39
40 const char kErrorEngineNotAvailable[] = "Engine is not available";
41 const char kErrorSetMenuItemsFail[] = "Could not create menu Items";
42 const char kErrorUpdateMenuItemsFail[] = "Could not update menu Items";
43
44 void SetMenuItemToMenu(const input_ime::MenuItem& input,
45                        InputMethodEngineInterface::MenuItem* out) {
46   out->modified = 0;
47   out->id = input.id;
48   if (input.label) {
49     out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_LABEL;
50     out->label = *input.label;
51   }
52
53   if (input.style != input_ime::MenuItem::STYLE_NONE) {
54     out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_STYLE;
55     out->style = static_cast<InputMethodEngineInterface::MenuItemStyle>(
56         input.style);
57   }
58
59   if (input.visible)
60     out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_VISIBLE;
61   out->visible = input.visible ? *input.visible : true;
62
63   if (input.checked)
64     out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_CHECKED;
65   out->checked = input.checked ? *input.checked : false;
66
67   if (input.enabled)
68     out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_ENABLED;
69   out->enabled = input.enabled ? *input.enabled : true;
70 }
71
72 static void DispatchEventToExtension(Profile* profile,
73                                      const std::string& extension_id,
74                                      const std::string& event_name,
75                                      scoped_ptr<base::ListValue> args) {
76   scoped_ptr<extensions::Event> event(new extensions::Event(
77       event_name, args.Pass()));
78   event->restrict_to_browser_context = profile;
79   extensions::EventRouter::Get(profile)
80       ->DispatchEventToExtension(extension_id, event.Pass());
81 }
82
83 }  // namespace
84
85 namespace chromeos {
86 class ImeObserver : public InputMethodEngineInterface::Observer {
87  public:
88   ImeObserver(Profile* profile, const std::string& extension_id)
89       : profile_(profile), extension_id_(extension_id) {}
90
91   virtual ~ImeObserver() {}
92
93   virtual void OnActivate(const std::string& engine_id) OVERRIDE {
94     if (profile_ == NULL || extension_id_.empty())
95       return;
96
97     scoped_ptr<base::ListValue> args(input_ime::OnActivate::Create(engine_id));
98
99     DispatchEventToExtension(profile_, extension_id_,
100                              input_ime::OnActivate::kEventName, args.Pass());
101   }
102
103   virtual void OnDeactivated(const std::string& engine_id) OVERRIDE {
104     if (profile_ == NULL || extension_id_.empty())
105       return;
106
107     scoped_ptr<base::ListValue> args(
108         input_ime::OnDeactivated::Create(engine_id));
109
110     DispatchEventToExtension(profile_, extension_id_,
111                              input_ime::OnDeactivated::kEventName, args.Pass());
112   }
113
114   virtual void OnFocus(
115       const InputMethodEngineInterface::InputContext& context) OVERRIDE {
116     if (profile_ == NULL || extension_id_.empty())
117       return;
118
119     input_ime::InputContext context_value;
120     context_value.context_id = context.id;
121     context_value.type = input_ime::InputContext::ParseType(context.type);
122
123     scoped_ptr<base::ListValue> args(input_ime::OnFocus::Create(context_value));
124
125     DispatchEventToExtension(profile_, extension_id_,
126                              input_ime::OnFocus::kEventName, args.Pass());
127   }
128
129   virtual void OnBlur(int context_id) OVERRIDE {
130     if (profile_ == NULL || extension_id_.empty())
131       return;
132
133     scoped_ptr<base::ListValue> args(input_ime::OnBlur::Create(context_id));
134
135     DispatchEventToExtension(profile_, extension_id_,
136                              input_ime::OnBlur::kEventName, args.Pass());
137   }
138
139   virtual void OnInputContextUpdate(
140       const InputMethodEngineInterface::InputContext& context) OVERRIDE {
141     if (profile_ == NULL || extension_id_.empty())
142       return;
143
144     input_ime::InputContext context_value;
145     context_value.context_id = context.id;
146     context_value.type = input_ime::InputContext::ParseType(context.type);
147
148     scoped_ptr<base::ListValue> args(
149         input_ime::OnInputContextUpdate::Create(context_value));
150
151     DispatchEventToExtension(profile_,
152                              extension_id_,
153                              input_ime::OnInputContextUpdate::kEventName,
154                              args.Pass());
155   }
156
157   virtual void OnKeyEvent(
158       const std::string& engine_id,
159       const InputMethodEngineInterface::KeyboardEvent& event,
160       chromeos::input_method::KeyEventHandle* key_data) OVERRIDE {
161     if (profile_ == NULL || extension_id_.empty())
162       return;
163
164     // If there is no listener for the event, no need to dispatch the event to
165     // extension. Instead, releases the key event for default system behavior.
166     if (!HasKeyEventListener()) {
167       // Continue processing the key event so that the physical keyboard can
168       // still work.
169       base::Callback<void(bool consumed)>* callback =
170           reinterpret_cast<base::Callback<void(bool consumed)>*>(key_data);
171       callback->Run(false);
172       delete callback;
173       return;
174     }
175
176     extensions::InputImeEventRouter* ime_event_router =
177         extensions::InputImeEventRouter::GetInstance();
178
179     const std::string request_id =
180         ime_event_router->AddRequest(engine_id, key_data);
181
182     input_ime::KeyboardEvent key_data_value;
183     key_data_value.type = input_ime::KeyboardEvent::ParseType(event.type);
184     key_data_value.request_id = request_id;
185     if (!event.extension_id.empty())
186       key_data_value.extension_id.reset(new std::string(event.extension_id));
187     key_data_value.key = event.key;
188     key_data_value.code = event.code;
189     key_data_value.alt_key.reset(new bool(event.alt_key));
190     key_data_value.ctrl_key.reset(new bool(event.ctrl_key));
191     key_data_value.shift_key.reset(new bool(event.shift_key));
192     key_data_value.caps_lock.reset(new bool(event.caps_lock));
193
194     scoped_ptr<base::ListValue> args(
195         input_ime::OnKeyEvent::Create(engine_id, key_data_value));
196
197     DispatchEventToExtension(profile_, extension_id_,
198                              input_ime::OnKeyEvent::kEventName, args.Pass());
199   }
200
201   virtual void OnCandidateClicked(
202       const std::string& engine_id,
203       int candidate_id,
204       InputMethodEngineInterface::MouseButtonEvent button) OVERRIDE {
205     if (profile_ == NULL || extension_id_.empty())
206       return;
207
208     input_ime::OnCandidateClicked::Button button_enum =
209         input_ime::OnCandidateClicked::BUTTON_NONE;
210     switch (button) {
211       case InputMethodEngineInterface::MOUSE_BUTTON_MIDDLE:
212         button_enum = input_ime::OnCandidateClicked::BUTTON_MIDDLE;
213         break;
214
215       case InputMethodEngineInterface::MOUSE_BUTTON_RIGHT:
216         button_enum = input_ime::OnCandidateClicked::BUTTON_RIGHT;
217         break;
218
219       case InputMethodEngineInterface::MOUSE_BUTTON_LEFT:
220       // Default to left.
221       default:
222         button_enum = input_ime::OnCandidateClicked::BUTTON_LEFT;
223         break;
224     }
225
226     scoped_ptr<base::ListValue> args(
227         input_ime::OnCandidateClicked::Create(engine_id,
228                                               candidate_id,
229                                               button_enum));
230
231     DispatchEventToExtension(profile_,
232                              extension_id_,
233                              input_ime::OnCandidateClicked::kEventName,
234                              args.Pass());
235   }
236
237   virtual void OnMenuItemActivated(const std::string& engine_id,
238                                    const std::string& menu_id) OVERRIDE {
239     if (profile_ == NULL || extension_id_.empty())
240       return;
241
242     scoped_ptr<base::ListValue> args(
243         input_ime::OnMenuItemActivated::Create(engine_id, menu_id));
244
245     DispatchEventToExtension(profile_,
246                              extension_id_,
247                              input_ime::OnMenuItemActivated::kEventName,
248                              args.Pass());
249   }
250
251   virtual void OnSurroundingTextChanged(const std::string& engine_id,
252                                         const std::string& text,
253                                         int cursor_pos,
254                                         int anchor_pos) OVERRIDE {
255     if (profile_ == NULL || extension_id_.empty())
256       return;
257
258     input_ime::OnSurroundingTextChanged::SurroundingInfo info;
259     info.text = text;
260     info.focus = cursor_pos;
261     info.anchor = anchor_pos;
262     scoped_ptr<base::ListValue> args(
263         input_ime::OnSurroundingTextChanged::Create(engine_id, info));
264
265     DispatchEventToExtension(profile_,
266                              extension_id_,
267                              input_ime::OnSurroundingTextChanged::kEventName,
268                              args.Pass());
269   }
270
271   virtual void OnReset(const std::string& engine_id) OVERRIDE {
272     if (profile_ == NULL || extension_id_.empty())
273       return;
274
275     scoped_ptr<base::ListValue> args(input_ime::OnReset::Create(engine_id));
276
277     DispatchEventToExtension(profile_,
278                              extension_id_,
279                              input_ime::OnReset::kEventName,
280                              args.Pass());
281   }
282
283  private:
284   bool HasKeyEventListener() const {
285     return extensions::EventRouter::Get(profile_)
286         ->ExtensionHasEventListener(extension_id_,
287                                     input_ime::OnKeyEvent::kEventName);
288   }
289
290   Profile* profile_;
291   std::string extension_id_;
292
293   DISALLOW_COPY_AND_ASSIGN(ImeObserver);
294 };
295
296 }  // namespace chromeos
297
298 namespace extensions {
299
300 InputImeEventRouter*
301 InputImeEventRouter::GetInstance() {
302   return Singleton<InputImeEventRouter>::get();
303 }
304
305 bool InputImeEventRouter::RegisterIme(
306     const std::string& extension_id,
307     const extensions::InputComponentInfo& component) {
308 #if defined(USE_X11)
309   VLOG(1) << "RegisterIme: " << extension_id << " id: " << component.id;
310
311   std::vector<std::string> layouts;
312   layouts.assign(component.layouts.begin(), component.layouts.end());
313
314   std::vector<std::string> languages;
315   languages.assign(component.languages.begin(), component.languages.end());
316
317   // Ideally Observer should be per (extension_id + Profile), and multiple
318   // InputMethodEngine can share one Observer. But it would become tricky
319   // to maintain an internal map for observers which does nearly nothing
320   // but just make sure they can properly deleted.
321   // Making Obesrver per InputMethodEngine can make things cleaner.
322   Profile* profile = ProfileManager::GetActiveUserProfile();
323   scoped_ptr<chromeos::InputMethodEngineInterface::Observer> observer(
324       new chromeos::ImeObserver(profile, extension_id));
325   chromeos::InputMethodEngine* engine = new chromeos::InputMethodEngine();
326   engine->Initialize(observer.Pass(),
327                      component.name.c_str(),
328                      extension_id.c_str(),
329                      component.id.c_str(),
330                      languages,
331                      layouts,
332                      component.options_page_url,
333                      component.input_view_url);
334   profile_engine_map_[profile][extension_id][component.id] = engine;
335
336   return true;
337 #else
338   // TODO(spang): IME support under ozone.
339   NOTIMPLEMENTED();
340   return false;
341 #endif
342 }
343
344 void InputImeEventRouter::UnregisterAllImes(const std::string& extension_id) {
345   Profile* profile = ProfileManager::GetActiveUserProfile();
346   ProfileEngineMap::iterator extension_map =
347       profile_engine_map_.find(profile);
348   if (extension_map == profile_engine_map_.end())
349     return;
350   ExtensionMap::iterator engine_map = extension_map->second.find(extension_id);
351   if (engine_map == extension_map->second.end())
352     return;
353   STLDeleteContainerPairSecondPointers(engine_map->second.begin(),
354                                        engine_map->second.end());
355   extension_map->second.erase(extension_id);
356   profile_engine_map_.erase(profile);
357 }
358
359 InputMethodEngineInterface* InputImeEventRouter::GetEngine(
360     const std::string& extension_id, const std::string& engine_id) {
361   // IME can only work on active user profile.
362   Profile* profile = ProfileManager::GetActiveUserProfile();
363
364   ProfileEngineMap::const_iterator extension_map =
365       profile_engine_map_.find(profile);
366   if (extension_map == profile_engine_map_.end())
367     return NULL;
368   ExtensionMap::const_iterator engine_map =
369       extension_map->second.find(extension_id);
370   if (engine_map == extension_map->second.end())
371     return NULL;
372   EngineMap::const_iterator engine = engine_map->second.find(engine_id);
373   if (engine == engine_map->second.end())
374     return NULL;
375   return engine->second;
376 }
377
378 InputMethodEngineInterface* InputImeEventRouter::GetActiveEngine(
379     const std::string& extension_id) {
380   // IME can only work on active user profile.
381   Profile* profile = ProfileManager::GetActiveUserProfile();
382
383   ProfileEngineMap::const_iterator extension_map =
384       profile_engine_map_.find(profile);
385   if (extension_map == profile_engine_map_.end())
386     return NULL;
387   ExtensionMap::const_iterator engine_map =
388       extension_map->second.find(extension_id);
389   if (engine_map == extension_map->second.end())
390     return NULL;
391
392   for (EngineMap::const_iterator i = engine_map->second.begin();
393        i != engine_map->second.end();
394        ++i) {
395     if (i->second->IsActive())
396       return i->second;
397   }
398   return NULL;
399 }
400
401 void InputImeEventRouter::OnKeyEventHandled(
402     const std::string& extension_id,
403     const std::string& request_id,
404     bool handled) {
405   RequestMap::iterator request = request_map_.find(request_id);
406   if (request == request_map_.end()) {
407     LOG(ERROR) << "Request ID not found: " << request_id;
408     return;
409   }
410
411   std::string engine_id = request->second.first;
412   chromeos::input_method::KeyEventHandle* key_data = request->second.second;
413   request_map_.erase(request);
414
415   InputMethodEngineInterface* engine = GetEngine(extension_id, engine_id);
416   if (!engine) {
417     LOG(ERROR) << "Engine does not exist: " << engine_id;
418     return;
419   }
420
421   engine->KeyEventDone(key_data, handled);
422 }
423
424 std::string InputImeEventRouter::AddRequest(
425     const std::string& engine_id,
426     chromeos::input_method::KeyEventHandle* key_data) {
427   std::string request_id = base::IntToString(next_request_id_);
428   ++next_request_id_;
429
430   request_map_[request_id] = std::make_pair(engine_id, key_data);
431
432   return request_id;
433 }
434
435 InputImeEventRouter::InputImeEventRouter()
436   : next_request_id_(1) {
437 }
438
439 InputImeEventRouter::~InputImeEventRouter() {}
440
441 bool InputImeSetCompositionFunction::RunSync() {
442   InputMethodEngineInterface* engine =
443       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
444   if (!engine) {
445     SetResult(new base::FundamentalValue(false));
446     return true;
447   }
448
449   scoped_ptr<SetComposition::Params> parent_params(
450       SetComposition::Params::Create(*args_));
451   const SetComposition::Params::Parameters& params = parent_params->parameters;
452   std::vector<InputMethodEngineInterface::SegmentInfo> segments;
453   if (params.segments) {
454     const std::vector<linked_ptr<
455         SetComposition::Params::Parameters::SegmentsType> >&
456             segments_args = *params.segments;
457     for (size_t i = 0; i < segments_args.size(); ++i) {
458       EXTENSION_FUNCTION_VALIDATE(
459           segments_args[i]->style !=
460           SetComposition::Params::Parameters::SegmentsType::STYLE_NONE);
461       segments.push_back(InputMethodEngineInterface::SegmentInfo());
462       segments.back().start = segments_args[i]->start;
463       segments.back().end = segments_args[i]->end;
464       if (segments_args[i]->style ==
465           SetComposition::Params::Parameters::SegmentsType::STYLE_UNDERLINE) {
466         segments.back().style =
467             InputMethodEngineInterface::SEGMENT_STYLE_UNDERLINE;
468       } else {
469         segments.back().style =
470             InputMethodEngineInterface::SEGMENT_STYLE_DOUBLE_UNDERLINE;
471       }
472     }
473   }
474
475   int selection_start =
476       params.selection_start ? *params.selection_start : params.cursor;
477   int selection_end =
478       params.selection_end ? *params.selection_end : params.cursor;
479
480   SetResult(new base::FundamentalValue(
481       engine->SetComposition(params.context_id, params.text.c_str(),
482                              selection_start, selection_end, params.cursor,
483                              segments, &error_)));
484   return true;
485 }
486
487 bool InputImeClearCompositionFunction::RunSync() {
488   InputMethodEngineInterface* engine =
489       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
490   if (!engine) {
491     SetResult(new base::FundamentalValue(false));
492     return true;
493   }
494
495   scoped_ptr<ClearComposition::Params> parent_params(
496       ClearComposition::Params::Create(*args_));
497   const ClearComposition::Params::Parameters& params =
498       parent_params->parameters;
499
500   SetResult(new base::FundamentalValue(
501       engine->ClearComposition(params.context_id, &error_)));
502   return true;
503 }
504
505 bool InputImeCommitTextFunction::RunSync() {
506   // TODO(zork): Support committing when not active.
507   InputMethodEngineInterface* engine =
508       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
509   if (!engine) {
510     SetResult(new base::FundamentalValue(false));
511     return true;
512   }
513
514   scoped_ptr<CommitText::Params> parent_params(
515       CommitText::Params::Create(*args_));
516   const CommitText::Params::Parameters& params =
517       parent_params->parameters;
518
519   SetResult(new base::FundamentalValue(
520       engine->CommitText(params.context_id, params.text.c_str(), &error_)));
521   return true;
522 }
523
524 bool InputImeHideInputViewFunction::RunAsync() {
525   InputMethodEngineInterface* engine =
526       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
527   if (!engine) {
528     return true;
529   }
530   engine->HideInputView();
531   return true;
532 }
533
534 bool InputImeSendKeyEventsFunction::RunAsync() {
535   scoped_ptr<SendKeyEvents::Params> parent_params(
536       SendKeyEvents::Params::Create(*args_));
537   const SendKeyEvents::Params::Parameters& params =
538       parent_params->parameters;
539   chromeos::InputMethodEngineInterface* engine =
540       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
541   if (!engine) {
542     error_ = kErrorEngineNotAvailable;
543     return false;
544   }
545
546   const std::vector<linked_ptr<input_ime::KeyboardEvent> >& key_data =
547       params.key_data;
548   std::vector<chromeos::InputMethodEngineInterface::KeyboardEvent> key_data_out;
549
550   for (size_t i = 0; i < key_data.size(); ++i) {
551     chromeos::InputMethodEngineInterface::KeyboardEvent event;
552     event.type = input_ime::KeyboardEvent::ToString(key_data[i]->type);
553     event.key = key_data[i]->key;
554     event.code = key_data[i]->code;
555     event.key_code = key_data[i]->key_code.get() ? *(key_data[i]->key_code) : 0;
556     if (key_data[i]->alt_key)
557       event.alt_key = *(key_data[i]->alt_key);
558     if (key_data[i]->ctrl_key)
559       event.ctrl_key = *(key_data[i]->ctrl_key);
560     if (key_data[i]->shift_key)
561       event.shift_key = *(key_data[i]->shift_key);
562     if (key_data[i]->caps_lock)
563       event.caps_lock = *(key_data[i]->caps_lock);
564     key_data_out.push_back(event);
565   }
566
567   engine->SendKeyEvents(params.context_id, key_data_out);
568   return true;
569 }
570
571 bool InputImeSetCandidateWindowPropertiesFunction::RunSync() {
572   scoped_ptr<SetCandidateWindowProperties::Params> parent_params(
573       SetCandidateWindowProperties::Params::Create(*args_));
574   const SetCandidateWindowProperties::Params::Parameters&
575       params = parent_params->parameters;
576
577   InputMethodEngineInterface* engine =
578       InputImeEventRouter::GetInstance()->GetEngine(extension_id(),
579                                                     params.engine_id);
580
581   if (!engine) {
582     SetResult(new base::FundamentalValue(false));
583     return true;
584   }
585
586   const SetCandidateWindowProperties::Params::Parameters::Properties&
587       properties = params.properties;
588
589   if (properties.visible &&
590       !engine->SetCandidateWindowVisible(*properties.visible, &error_)) {
591     SetResult(new base::FundamentalValue(false));
592     return true;
593   }
594
595   InputMethodEngineInterface::CandidateWindowProperty properties_out =
596     engine->GetCandidateWindowProperty();
597   bool modified = false;
598
599   if (properties.cursor_visible) {
600     properties_out.is_cursor_visible = *properties.cursor_visible;
601     modified = true;
602   }
603
604   if (properties.vertical) {
605     properties_out.is_vertical = *properties.vertical;
606     modified = true;
607   }
608
609   if (properties.page_size) {
610     properties_out.page_size = *properties.page_size;
611     modified = true;
612   }
613
614   if (properties.window_position ==
615       SetCandidateWindowProperties::Params::Parameters::Properties::
616           WINDOW_POSITION_COMPOSITION) {
617     properties_out.show_window_at_composition = true;
618     modified = true;
619   } else if (properties.window_position ==
620              SetCandidateWindowProperties::Params::Parameters::Properties::
621                  WINDOW_POSITION_CURSOR) {
622     properties_out.show_window_at_composition = false;
623     modified = true;
624   }
625
626   if (properties.auxiliary_text) {
627     properties_out.auxiliary_text = *properties.auxiliary_text;
628     modified = true;
629   }
630
631   if (properties.auxiliary_text_visible) {
632     properties_out.is_auxiliary_text_visible =
633         *properties.auxiliary_text_visible;
634     modified = true;
635   }
636
637   if (modified) {
638     engine->SetCandidateWindowProperty(properties_out);
639   }
640
641   SetResult(new base::FundamentalValue(true));
642
643   return true;
644 }
645
646 bool InputImeSetCandidatesFunction::RunSync() {
647   InputMethodEngineInterface* engine =
648       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
649   if (!engine) {
650     SetResult(new base::FundamentalValue(false));
651     return true;
652   }
653
654   scoped_ptr<SetCandidates::Params> parent_params(
655       SetCandidates::Params::Create(*args_));
656   const SetCandidates::Params::Parameters& params =
657       parent_params->parameters;
658
659   std::vector<InputMethodEngineInterface::Candidate> candidates_out;
660   const std::vector<linked_ptr<
661       SetCandidates::Params::Parameters::CandidatesType> >& candidates_in =
662           params.candidates;
663   for (size_t i = 0; i < candidates_in.size(); ++i) {
664     candidates_out.push_back(InputMethodEngineInterface::Candidate());
665     candidates_out.back().value = candidates_in[i]->candidate;
666     candidates_out.back().id = candidates_in[i]->id;
667     if (candidates_in[i]->label)
668       candidates_out.back().label = *candidates_in[i]->label;
669     if (candidates_in[i]->annotation)
670       candidates_out.back().annotation = *candidates_in[i]->annotation;
671     if (candidates_in[i]->usage) {
672       candidates_out.back().usage.title = candidates_in[i]->usage->title;
673       candidates_out.back().usage.body = candidates_in[i]->usage->body;
674     }
675   }
676
677   SetResult(new base::FundamentalValue(
678       engine->SetCandidates(params.context_id, candidates_out, &error_)));
679   return true;
680 }
681
682 bool InputImeSetCursorPositionFunction::RunSync() {
683   InputMethodEngineInterface* engine =
684       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
685   if (!engine) {
686     SetResult(new base::FundamentalValue(false));
687     return true;
688   }
689
690   scoped_ptr<SetCursorPosition::Params> parent_params(
691       SetCursorPosition::Params::Create(*args_));
692   const SetCursorPosition::Params::Parameters& params =
693       parent_params->parameters;
694
695   SetResult(new base::FundamentalValue(
696       engine->SetCursorPosition(params.context_id, params.candidate_id,
697                                 &error_)));
698   return true;
699 }
700
701 bool InputImeSetMenuItemsFunction::RunSync() {
702   scoped_ptr<SetMenuItems::Params> parent_params(
703       SetMenuItems::Params::Create(*args_));
704   const SetMenuItems::Params::Parameters& params =
705       parent_params->parameters;
706
707   InputMethodEngineInterface* engine =
708       InputImeEventRouter::GetInstance()->GetEngine(extension_id(),
709                                                     params.engine_id);
710   if (!engine) {
711     error_ = kErrorEngineNotAvailable;
712     return false;
713   }
714
715   const std::vector<linked_ptr<input_ime::MenuItem> >& items = params.items;
716   std::vector<InputMethodEngineInterface::MenuItem> items_out;
717
718   for (size_t i = 0; i < items.size(); ++i) {
719     items_out.push_back(InputMethodEngineInterface::MenuItem());
720     SetMenuItemToMenu(*items[i], &items_out.back());
721   }
722
723   if (!engine->SetMenuItems(items_out))
724     error_ = kErrorSetMenuItemsFail;
725   return true;
726 }
727
728 bool InputImeUpdateMenuItemsFunction::RunSync() {
729   scoped_ptr<UpdateMenuItems::Params> parent_params(
730       UpdateMenuItems::Params::Create(*args_));
731   const UpdateMenuItems::Params::Parameters& params =
732       parent_params->parameters;
733
734   InputMethodEngineInterface* engine =
735       InputImeEventRouter::GetInstance()->GetEngine(extension_id(),
736                                                     params.engine_id);
737   if (!engine) {
738     error_ = kErrorEngineNotAvailable;
739     return false;
740   }
741
742   const std::vector<linked_ptr<input_ime::MenuItem> >& items = params.items;
743   std::vector<InputMethodEngineInterface::MenuItem> items_out;
744
745   for (size_t i = 0; i < items.size(); ++i) {
746     items_out.push_back(InputMethodEngineInterface::MenuItem());
747     SetMenuItemToMenu(*items[i], &items_out.back());
748   }
749
750   if (!engine->UpdateMenuItems(items_out))
751     error_ = kErrorUpdateMenuItemsFail;
752   return true;
753 }
754
755 bool InputImeDeleteSurroundingTextFunction::RunSync() {
756   scoped_ptr<DeleteSurroundingText::Params> parent_params(
757       DeleteSurroundingText::Params::Create(*args_));
758   const DeleteSurroundingText::Params::Parameters& params =
759       parent_params->parameters;
760
761   InputMethodEngineInterface* engine =
762       InputImeEventRouter::GetInstance()->GetEngine(extension_id(),
763                                                     params.engine_id);
764   if (!engine) {
765     error_ = kErrorEngineNotAvailable;
766     return false;
767   }
768
769   engine->DeleteSurroundingText(params.context_id, params.offset, params.length,
770                                 &error_);
771   return true;
772 }
773
774 bool InputImeKeyEventHandledFunction::RunAsync() {
775   scoped_ptr<KeyEventHandled::Params> params(
776       KeyEventHandled::Params::Create(*args_));
777   InputImeEventRouter::GetInstance()->OnKeyEventHandled(
778       extension_id(), params->request_id, params->response);
779   return true;
780 }
781
782 InputImeAPI::InputImeAPI(content::BrowserContext* context)
783     : browser_context_(context), extension_registry_observer_(this) {
784   extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
785
786   EventRouter* event_router = EventRouter::Get(browser_context_);
787   event_router->RegisterObserver(this, input_ime::OnActivate::kEventName);
788   event_router->RegisterObserver(this, input_ime::OnFocus::kEventName);
789 }
790
791 InputImeAPI::~InputImeAPI() {
792   EventRouter::Get(browser_context_)->UnregisterObserver(this);
793 }
794
795 static base::LazyInstance<BrowserContextKeyedAPIFactory<InputImeAPI> >
796     g_factory = LAZY_INSTANCE_INITIALIZER;
797
798 // static
799 BrowserContextKeyedAPIFactory<InputImeAPI>* InputImeAPI::GetFactoryInstance() {
800   return g_factory.Pointer();
801 }
802
803 void InputImeAPI::OnExtensionLoaded(content::BrowserContext* browser_context,
804                                     const Extension* extension) {
805   const std::vector<InputComponentInfo>* input_components =
806       extensions::InputComponents::GetInputComponents(extension);
807   if (!input_components)
808     return;
809   for (std::vector<extensions::InputComponentInfo>::const_iterator component =
810            input_components->begin();
811        component != input_components->end();
812        ++component) {
813     if (component->type == extensions::INPUT_COMPONENT_TYPE_IME) {
814       // Don't pass profile_ to register ime, instead always use
815       // GetActiveUserProfile. It is because:
816       // The original profile for login screen is called signin profile.
817       // And the active profile is the incognito profile based on signin
818       // profile. So if |profile_| is signin profile, we need to make sure
819       // the router/observer runs under its incognito profile, because the
820       // component extensions were installed under its incognito profile.
821       input_ime_event_router()->RegisterIme(extension->id(), *component);
822     }
823   }
824 }
825
826 void InputImeAPI::OnExtensionUnloaded(content::BrowserContext* browser_context,
827                                       const Extension* extension,
828                                       UnloadedExtensionInfo::Reason reason) {
829   const std::vector<InputComponentInfo>* input_components =
830       extensions::InputComponents::GetInputComponents(extension);
831   if (!input_components)
832     return;
833   if (input_components->size() > 0)
834     input_ime_event_router()->UnregisterAllImes(extension->id());
835 }
836
837 void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) {
838   InputMethodEngineInterface* engine =
839       input_ime_event_router()->GetActiveEngine(details.extension_id);
840   if (engine)
841     engine->NotifyImeReady();
842 }
843
844 InputImeEventRouter* InputImeAPI::input_ime_event_router() {
845   return InputImeEventRouter::GetInstance();
846 }
847
848 }  // namespace extensions