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