Upstream version 7.36.149.0
[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     if (key_data[i]->alt_key)
556       event.alt_key = *(key_data[i]->alt_key);
557     if (key_data[i]->ctrl_key)
558       event.ctrl_key = *(key_data[i]->ctrl_key);
559     if (key_data[i]->shift_key)
560       event.shift_key = *(key_data[i]->shift_key);
561     if (key_data[i]->caps_lock)
562       event.caps_lock = *(key_data[i]->caps_lock);
563     key_data_out.push_back(event);
564   }
565
566   engine->SendKeyEvents(params.context_id, key_data_out);
567   return true;
568 }
569
570 bool InputImeSetCandidateWindowPropertiesFunction::RunSync() {
571   scoped_ptr<SetCandidateWindowProperties::Params> parent_params(
572       SetCandidateWindowProperties::Params::Create(*args_));
573   const SetCandidateWindowProperties::Params::Parameters&
574       params = parent_params->parameters;
575
576   InputMethodEngineInterface* engine =
577       InputImeEventRouter::GetInstance()->GetEngine(extension_id(),
578                                                     params.engine_id);
579
580   if (!engine) {
581     SetResult(new base::FundamentalValue(false));
582     return true;
583   }
584
585   const SetCandidateWindowProperties::Params::Parameters::Properties&
586       properties = params.properties;
587
588   if (properties.visible &&
589       !engine->SetCandidateWindowVisible(*properties.visible, &error_)) {
590     SetResult(new base::FundamentalValue(false));
591     return true;
592   }
593
594   InputMethodEngineInterface::CandidateWindowProperty properties_out =
595     engine->GetCandidateWindowProperty();
596   bool modified = false;
597
598   if (properties.cursor_visible) {
599     properties_out.is_cursor_visible = *properties.cursor_visible;
600     modified = true;
601   }
602
603   if (properties.vertical) {
604     properties_out.is_vertical = *properties.vertical;
605     modified = true;
606   }
607
608   if (properties.page_size) {
609     properties_out.page_size = *properties.page_size;
610     modified = true;
611   }
612
613   if (properties.window_position ==
614       SetCandidateWindowProperties::Params::Parameters::Properties::
615           WINDOW_POSITION_COMPOSITION) {
616     properties_out.show_window_at_composition = true;
617     modified = true;
618   } else if (properties.window_position ==
619              SetCandidateWindowProperties::Params::Parameters::Properties::
620                  WINDOW_POSITION_CURSOR) {
621     properties_out.show_window_at_composition = false;
622     modified = true;
623   }
624
625   if (properties.auxiliary_text) {
626     properties_out.auxiliary_text = *properties.auxiliary_text;
627     modified = true;
628   }
629
630   if (properties.auxiliary_text_visible) {
631     properties_out.is_auxiliary_text_visible =
632         *properties.auxiliary_text_visible;
633     modified = true;
634   }
635
636   if (modified) {
637     engine->SetCandidateWindowProperty(properties_out);
638   }
639
640   SetResult(new base::FundamentalValue(true));
641
642   return true;
643 }
644
645 bool InputImeSetCandidatesFunction::RunSync() {
646   InputMethodEngineInterface* engine =
647       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
648   if (!engine) {
649     SetResult(new base::FundamentalValue(false));
650     return true;
651   }
652
653   scoped_ptr<SetCandidates::Params> parent_params(
654       SetCandidates::Params::Create(*args_));
655   const SetCandidates::Params::Parameters& params =
656       parent_params->parameters;
657
658   std::vector<InputMethodEngineInterface::Candidate> candidates_out;
659   const std::vector<linked_ptr<
660       SetCandidates::Params::Parameters::CandidatesType> >& candidates_in =
661           params.candidates;
662   for (size_t i = 0; i < candidates_in.size(); ++i) {
663     candidates_out.push_back(InputMethodEngineInterface::Candidate());
664     candidates_out.back().value = candidates_in[i]->candidate;
665     candidates_out.back().id = candidates_in[i]->id;
666     if (candidates_in[i]->label)
667       candidates_out.back().label = *candidates_in[i]->label;
668     if (candidates_in[i]->annotation)
669       candidates_out.back().annotation = *candidates_in[i]->annotation;
670     if (candidates_in[i]->usage) {
671       candidates_out.back().usage.title = candidates_in[i]->usage->title;
672       candidates_out.back().usage.body = candidates_in[i]->usage->body;
673     }
674   }
675
676   SetResult(new base::FundamentalValue(
677       engine->SetCandidates(params.context_id, candidates_out, &error_)));
678   return true;
679 }
680
681 bool InputImeSetCursorPositionFunction::RunSync() {
682   InputMethodEngineInterface* engine =
683       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
684   if (!engine) {
685     SetResult(new base::FundamentalValue(false));
686     return true;
687   }
688
689   scoped_ptr<SetCursorPosition::Params> parent_params(
690       SetCursorPosition::Params::Create(*args_));
691   const SetCursorPosition::Params::Parameters& params =
692       parent_params->parameters;
693
694   SetResult(new base::FundamentalValue(
695       engine->SetCursorPosition(params.context_id, params.candidate_id,
696                                 &error_)));
697   return true;
698 }
699
700 bool InputImeSetMenuItemsFunction::RunSync() {
701   scoped_ptr<SetMenuItems::Params> parent_params(
702       SetMenuItems::Params::Create(*args_));
703   const SetMenuItems::Params::Parameters& params =
704       parent_params->parameters;
705
706   InputMethodEngineInterface* engine =
707       InputImeEventRouter::GetInstance()->GetEngine(extension_id(),
708                                                     params.engine_id);
709   if (!engine) {
710     error_ = kErrorEngineNotAvailable;
711     return false;
712   }
713
714   const std::vector<linked_ptr<input_ime::MenuItem> >& items = params.items;
715   std::vector<InputMethodEngineInterface::MenuItem> items_out;
716
717   for (size_t i = 0; i < items.size(); ++i) {
718     items_out.push_back(InputMethodEngineInterface::MenuItem());
719     SetMenuItemToMenu(*items[i], &items_out.back());
720   }
721
722   if (!engine->SetMenuItems(items_out))
723     error_ = kErrorSetMenuItemsFail;
724   return true;
725 }
726
727 bool InputImeUpdateMenuItemsFunction::RunSync() {
728   scoped_ptr<UpdateMenuItems::Params> parent_params(
729       UpdateMenuItems::Params::Create(*args_));
730   const UpdateMenuItems::Params::Parameters& params =
731       parent_params->parameters;
732
733   InputMethodEngineInterface* engine =
734       InputImeEventRouter::GetInstance()->GetEngine(extension_id(),
735                                                     params.engine_id);
736   if (!engine) {
737     error_ = kErrorEngineNotAvailable;
738     return false;
739   }
740
741   const std::vector<linked_ptr<input_ime::MenuItem> >& items = params.items;
742   std::vector<InputMethodEngineInterface::MenuItem> items_out;
743
744   for (size_t i = 0; i < items.size(); ++i) {
745     items_out.push_back(InputMethodEngineInterface::MenuItem());
746     SetMenuItemToMenu(*items[i], &items_out.back());
747   }
748
749   if (!engine->UpdateMenuItems(items_out))
750     error_ = kErrorUpdateMenuItemsFail;
751   return true;
752 }
753
754 bool InputImeDeleteSurroundingTextFunction::RunSync() {
755   scoped_ptr<DeleteSurroundingText::Params> parent_params(
756       DeleteSurroundingText::Params::Create(*args_));
757   const DeleteSurroundingText::Params::Parameters& params =
758       parent_params->parameters;
759
760   InputMethodEngineInterface* engine =
761       InputImeEventRouter::GetInstance()->GetEngine(extension_id(),
762                                                     params.engine_id);
763   if (!engine) {
764     error_ = kErrorEngineNotAvailable;
765     return false;
766   }
767
768   engine->DeleteSurroundingText(params.context_id, params.offset, params.length,
769                                 &error_);
770   return true;
771 }
772
773 bool InputImeKeyEventHandledFunction::RunAsync() {
774   scoped_ptr<KeyEventHandled::Params> params(
775       KeyEventHandled::Params::Create(*args_));
776   InputImeEventRouter::GetInstance()->OnKeyEventHandled(
777       extension_id(), params->request_id, params->response);
778   return true;
779 }
780
781 InputImeAPI::InputImeAPI(content::BrowserContext* context)
782     : browser_context_(context), extension_registry_observer_(this) {
783   extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
784
785   EventRouter* event_router = EventRouter::Get(browser_context_);
786   event_router->RegisterObserver(this, input_ime::OnActivate::kEventName);
787   event_router->RegisterObserver(this, input_ime::OnFocus::kEventName);
788 }
789
790 InputImeAPI::~InputImeAPI() {
791   EventRouter::Get(browser_context_)->UnregisterObserver(this);
792 }
793
794 static base::LazyInstance<BrowserContextKeyedAPIFactory<InputImeAPI> >
795     g_factory = LAZY_INSTANCE_INITIALIZER;
796
797 // static
798 BrowserContextKeyedAPIFactory<InputImeAPI>* InputImeAPI::GetFactoryInstance() {
799   return g_factory.Pointer();
800 }
801
802 void InputImeAPI::OnExtensionLoaded(content::BrowserContext* browser_context,
803                                     const Extension* extension) {
804   const std::vector<InputComponentInfo>* input_components =
805       extensions::InputComponents::GetInputComponents(extension);
806   if (!input_components)
807     return;
808   for (std::vector<extensions::InputComponentInfo>::const_iterator component =
809            input_components->begin();
810        component != input_components->end();
811        ++component) {
812     if (component->type == extensions::INPUT_COMPONENT_TYPE_IME) {
813       // Don't pass profile_ to register ime, instead always use
814       // GetActiveUserProfile. It is because:
815       // The original profile for login screen is called signin profile.
816       // And the active profile is the incognito profile based on signin
817       // profile. So if |profile_| is signin profile, we need to make sure
818       // the router/observer runs under its incognito profile, because the
819       // component extensions were installed under its incognito profile.
820       input_ime_event_router()->RegisterIme(extension->id(), *component);
821     }
822   }
823 }
824
825 void InputImeAPI::OnExtensionUnloaded(content::BrowserContext* browser_context,
826                                       const Extension* extension,
827                                       UnloadedExtensionInfo::Reason reason) {
828   const std::vector<InputComponentInfo>* input_components =
829       extensions::InputComponents::GetInputComponents(extension);
830   if (!input_components)
831     return;
832   if (input_components->size() > 0)
833     input_ime_event_router()->UnregisterAllImes(extension->id());
834 }
835
836 void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) {
837   InputMethodEngineInterface* engine =
838       input_ime_event_router()->GetActiveEngine(details.extension_id);
839   if (engine)
840     engine->NotifyImeReady();
841 }
842
843 InputImeEventRouter* InputImeAPI::input_ime_event_router() {
844   return InputImeEventRouter::GetInstance();
845 }
846
847 }  // namespace extensions