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