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