Home | History | Annotate | Download | only in ime
      1 // Copyright 2013 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 "chromeos/ime/component_extension_ime_manager.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/string_util.h"
      9 #include "chromeos/ime/extension_ime_util.h"
     10 
     11 namespace chromeos {
     12 
     13 namespace {
     14 
     15 // The whitelist for enabling extension based xkb keyboards at login session.
     16 const char* kLoginLayoutWhitelist[] = {
     17   "be",
     18   "br",
     19   "ca",
     20   "ca(eng)",
     21   "ca(multix)",
     22   "ch",
     23   "ch(fr)",
     24   "cz",
     25   "cz(qwerty)",
     26   "de",
     27   "de(neo)",
     28   "dk",
     29   "ee",
     30   "es",
     31   "es(cat)",
     32   "fi",
     33   "fr",
     34   "gb(dvorak)",
     35   "gb(extd)",
     36   "hr",
     37   "hu",
     38   "is",
     39   "it",
     40   "jp",
     41   "latam",
     42   "lt",
     43   "lv(apostrophe)",
     44   "no",
     45   "pl",
     46   "pt",
     47   "ro",
     48   "se",
     49   "si",
     50   "tr",
     51   "us",
     52   "us(altgr-intl)",
     53   "us(colemak)",
     54   "us(dvorak)",
     55   "us(intl)"
     56 };
     57 
     58 // Gets the input method category according to the given input method id.
     59 // This is used for sorting a list of input methods.
     60 int GetInputMethodCategory(const std::string& id) {
     61   const std::string engine_id =
     62       chromeos::extension_ime_util::GetComponentIDByInputMethodID(id);
     63   if (StartsWithASCII(engine_id, "xkb:", true))
     64     return 0;
     65   if (StartsWithASCII(engine_id, "vkd_", true))
     66     return 1;
     67   if (engine_id.find("-t-i0-") != std::string::npos &&
     68       !StartsWithASCII(engine_id, "zh-", true)) {
     69     return 2;
     70   }
     71   return 3;
     72 }
     73 
     74 bool InputMethodCompare(const input_method::InputMethodDescriptor& im1,
     75                         const input_method::InputMethodDescriptor& im2) {
     76   return GetInputMethodCategory(im1.id()) < GetInputMethodCategory(im2.id());
     77 }
     78 
     79 } // namespace
     80 
     81 ComponentExtensionEngine::ComponentExtensionEngine() {
     82 }
     83 
     84 ComponentExtensionEngine::~ComponentExtensionEngine() {
     85 }
     86 
     87 ComponentExtensionIME::ComponentExtensionIME() {
     88 }
     89 
     90 ComponentExtensionIME::~ComponentExtensionIME() {
     91 }
     92 
     93 ComponentExtensionIMEManagerDelegate::ComponentExtensionIMEManagerDelegate() {
     94 }
     95 
     96 ComponentExtensionIMEManagerDelegate::~ComponentExtensionIMEManagerDelegate() {
     97 }
     98 
     99 ComponentExtensionIMEManager::ComponentExtensionIMEManager() {
    100   for (size_t i = 0; i < arraysize(kLoginLayoutWhitelist); ++i) {
    101     login_layout_set_.insert(kLoginLayoutWhitelist[i]);
    102   }
    103 }
    104 
    105 ComponentExtensionIMEManager::~ComponentExtensionIMEManager() {
    106 }
    107 
    108 void ComponentExtensionIMEManager::Initialize(
    109     scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate) {
    110   delegate_ = delegate.Pass();
    111   std::vector<ComponentExtensionIME> ext_list = delegate_->ListIME();
    112   for (size_t i = 0; i < ext_list.size(); ++i) {
    113     ComponentExtensionIME& ext = ext_list[i];
    114     bool extension_exists = IsWhitelistedExtension(ext.id);
    115     if (!extension_exists)
    116       component_extension_imes_[ext.id] = ext;
    117     for (size_t j = 0; j < ext.engines.size(); ++j) {
    118       ComponentExtensionEngine& ime = ext.engines[j];
    119       const std::string input_method_id =
    120           extension_ime_util::GetComponentInputMethodID(ext.id, ime.engine_id);
    121       if (extension_exists && !IsWhitelisted(input_method_id))
    122         component_extension_imes_[ext.id].engines.push_back(ime);
    123       input_method_id_set_.insert(input_method_id);
    124     }
    125   }
    126 }
    127 
    128 bool ComponentExtensionIMEManager::LoadComponentExtensionIME(
    129     Profile* profile,
    130     const std::string& input_method_id) {
    131   ComponentExtensionIME ime;
    132   if (FindEngineEntry(input_method_id, &ime)) {
    133     delegate_->Load(profile, ime.id, ime.manifest, ime.path);
    134     return true;
    135   }
    136   return false;
    137 }
    138 
    139 bool ComponentExtensionIMEManager::UnloadComponentExtensionIME(
    140     Profile* profile,
    141     const std::string& input_method_id) {
    142   ComponentExtensionIME ime;
    143   if (!FindEngineEntry(input_method_id, &ime))
    144     return false;
    145   delegate_->Unload(profile, ime.id, ime.path);
    146   return true;
    147 }
    148 
    149 bool ComponentExtensionIMEManager::IsWhitelisted(
    150     const std::string& input_method_id) {
    151   return input_method_id_set_.find(input_method_id) !=
    152          input_method_id_set_.end();
    153 }
    154 
    155 bool ComponentExtensionIMEManager::IsWhitelistedExtension(
    156     const std::string& extension_id) {
    157   return component_extension_imes_.find(extension_id) !=
    158          component_extension_imes_.end();
    159 }
    160 
    161 input_method::InputMethodDescriptors
    162     ComponentExtensionIMEManager::GetAllIMEAsInputMethodDescriptor() {
    163   input_method::InputMethodDescriptors result;
    164   for (std::map<std::string, ComponentExtensionIME>::const_iterator it =
    165           component_extension_imes_.begin();
    166        it != component_extension_imes_.end(); ++it) {
    167     const ComponentExtensionIME& ext = it->second;
    168     for (size_t j = 0; j < ext.engines.size(); ++j) {
    169       const ComponentExtensionEngine& ime = ext.engines[j];
    170       const std::string input_method_id =
    171           extension_ime_util::GetComponentInputMethodID(
    172               ext.id, ime.engine_id);
    173       const std::vector<std::string>& layouts = ime.layouts;
    174       result.push_back(
    175           input_method::InputMethodDescriptor(
    176               input_method_id,
    177               ime.display_name,
    178               std::string(), // TODO(uekawa): Set short name.
    179               layouts,
    180               ime.language_codes,
    181               // Enables extension based xkb keyboards on login screen.
    182               extension_ime_util::IsKeyboardLayoutExtension(
    183                   input_method_id) && IsInLoginLayoutWhitelist(layouts),
    184               ime.options_page_url,
    185               ime.input_view_url));
    186     }
    187   }
    188   std::stable_sort(result.begin(), result.end(), InputMethodCompare);
    189   return result;
    190 }
    191 
    192 input_method::InputMethodDescriptors
    193 ComponentExtensionIMEManager::GetXkbIMEAsInputMethodDescriptor() {
    194   input_method::InputMethodDescriptors result;
    195   const input_method::InputMethodDescriptors& descriptors =
    196       GetAllIMEAsInputMethodDescriptor();
    197   for (size_t i = 0; i < descriptors.size(); ++i) {
    198     if (extension_ime_util::IsKeyboardLayoutExtension(descriptors[i].id()))
    199       result.push_back(descriptors[i]);
    200   }
    201   return result;
    202 }
    203 
    204 bool ComponentExtensionIMEManager::FindEngineEntry(
    205     const std::string& input_method_id,
    206     ComponentExtensionIME* out_extension) {
    207   if (!IsWhitelisted(input_method_id))
    208     return false;
    209 
    210   std::string extension_id =
    211       extension_ime_util::GetExtensionIDFromInputMethodID(input_method_id);
    212   std::map<std::string, ComponentExtensionIME>::iterator it =
    213       component_extension_imes_.find(extension_id);
    214   if (it == component_extension_imes_.end())
    215     return false;
    216 
    217   if (out_extension)
    218     *out_extension = it->second;
    219   return true;
    220 }
    221 
    222 bool ComponentExtensionIMEManager::IsInLoginLayoutWhitelist(
    223     const std::vector<std::string>& layouts) {
    224   for (size_t i = 0; i < layouts.size(); ++i) {
    225     if (login_layout_set_.find(layouts[i]) != login_layout_set_.end())
    226       return true;
    227   }
    228   return false;
    229 }
    230 
    231 }  // namespace chromeos
    232