// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chromeos/ime/component_extension_ime_manager.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "chromeos/ime/extension_ime_util.h" namespace chromeos { namespace { // The whitelist for enabling extension based xkb keyboards at login session. const char* kLoginLayoutWhitelist[] = { "be", "br", "ca", "ca(eng)", "ca(multix)", "ch", "ch(fr)", "cz", "cz(qwerty)", "de", "de(neo)", "dk", "ee", "es", "es(cat)", "fi", "fr", "gb(dvorak)", "gb(extd)", "hr", "hu", "is", "it", "jp", "latam", "lt", "lv(apostrophe)", "no", "pl", "pt", "ro", "se", "si", "tr", "us", "us(altgr-intl)", "us(colemak)", "us(dvorak)", "us(intl)" }; // Gets the input method category according to the given input method id. // This is used for sorting a list of input methods. int GetInputMethodCategory(const std::string& id) { const std::string engine_id = chromeos::extension_ime_util::GetComponentIDByInputMethodID(id); if (StartsWithASCII(engine_id, "xkb:", true)) return 0; if (StartsWithASCII(engine_id, "vkd_", true)) return 1; if (engine_id.find("-t-i0-") != std::string::npos && !StartsWithASCII(engine_id, "zh-", true)) { return 2; } return 3; } bool InputMethodCompare(const input_method::InputMethodDescriptor& im1, const input_method::InputMethodDescriptor& im2) { return GetInputMethodCategory(im1.id()) < GetInputMethodCategory(im2.id()); } } // namespace ComponentExtensionEngine::ComponentExtensionEngine() { } ComponentExtensionEngine::~ComponentExtensionEngine() { } ComponentExtensionIME::ComponentExtensionIME() { } ComponentExtensionIME::~ComponentExtensionIME() { } ComponentExtensionIMEManagerDelegate::ComponentExtensionIMEManagerDelegate() { } ComponentExtensionIMEManagerDelegate::~ComponentExtensionIMEManagerDelegate() { } ComponentExtensionIMEManager::ComponentExtensionIMEManager() { for (size_t i = 0; i < arraysize(kLoginLayoutWhitelist); ++i) { login_layout_set_.insert(kLoginLayoutWhitelist[i]); } } ComponentExtensionIMEManager::~ComponentExtensionIMEManager() { } void ComponentExtensionIMEManager::Initialize( scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate) { delegate_ = delegate.Pass(); std::vector<ComponentExtensionIME> ext_list = delegate_->ListIME(); for (size_t i = 0; i < ext_list.size(); ++i) { ComponentExtensionIME& ext = ext_list[i]; bool extension_exists = IsWhitelistedExtension(ext.id); if (!extension_exists) component_extension_imes_[ext.id] = ext; for (size_t j = 0; j < ext.engines.size(); ++j) { ComponentExtensionEngine& ime = ext.engines[j]; const std::string input_method_id = extension_ime_util::GetComponentInputMethodID(ext.id, ime.engine_id); if (extension_exists && !IsWhitelisted(input_method_id)) component_extension_imes_[ext.id].engines.push_back(ime); input_method_id_set_.insert(input_method_id); } } } bool ComponentExtensionIMEManager::LoadComponentExtensionIME( Profile* profile, const std::string& input_method_id) { ComponentExtensionIME ime; if (FindEngineEntry(input_method_id, &ime)) { delegate_->Load(profile, ime.id, ime.manifest, ime.path); return true; } return false; } bool ComponentExtensionIMEManager::UnloadComponentExtensionIME( Profile* profile, const std::string& input_method_id) { ComponentExtensionIME ime; if (!FindEngineEntry(input_method_id, &ime)) return false; delegate_->Unload(profile, ime.id, ime.path); return true; } bool ComponentExtensionIMEManager::IsWhitelisted( const std::string& input_method_id) { return input_method_id_set_.find(input_method_id) != input_method_id_set_.end(); } bool ComponentExtensionIMEManager::IsWhitelistedExtension( const std::string& extension_id) { return component_extension_imes_.find(extension_id) != component_extension_imes_.end(); } input_method::InputMethodDescriptors ComponentExtensionIMEManager::GetAllIMEAsInputMethodDescriptor() { input_method::InputMethodDescriptors result; for (std::map<std::string, ComponentExtensionIME>::const_iterator it = component_extension_imes_.begin(); it != component_extension_imes_.end(); ++it) { const ComponentExtensionIME& ext = it->second; for (size_t j = 0; j < ext.engines.size(); ++j) { const ComponentExtensionEngine& ime = ext.engines[j]; const std::string input_method_id = extension_ime_util::GetComponentInputMethodID( ext.id, ime.engine_id); const std::vector<std::string>& layouts = ime.layouts; result.push_back( input_method::InputMethodDescriptor( input_method_id, ime.display_name, std::string(), // TODO(uekawa): Set short name. layouts, ime.language_codes, // Enables extension based xkb keyboards on login screen. extension_ime_util::IsKeyboardLayoutExtension( input_method_id) && IsInLoginLayoutWhitelist(layouts), ime.options_page_url, ime.input_view_url)); } } std::stable_sort(result.begin(), result.end(), InputMethodCompare); return result; } input_method::InputMethodDescriptors ComponentExtensionIMEManager::GetXkbIMEAsInputMethodDescriptor() { input_method::InputMethodDescriptors result; const input_method::InputMethodDescriptors& descriptors = GetAllIMEAsInputMethodDescriptor(); for (size_t i = 0; i < descriptors.size(); ++i) { if (extension_ime_util::IsKeyboardLayoutExtension(descriptors[i].id())) result.push_back(descriptors[i]); } return result; } bool ComponentExtensionIMEManager::FindEngineEntry( const std::string& input_method_id, ComponentExtensionIME* out_extension) { if (!IsWhitelisted(input_method_id)) return false; std::string extension_id = extension_ime_util::GetExtensionIDFromInputMethodID(input_method_id); std::map<std::string, ComponentExtensionIME>::iterator it = component_extension_imes_.find(extension_id); if (it == component_extension_imes_.end()) return false; if (out_extension) *out_extension = it->second; return true; } bool ComponentExtensionIMEManager::IsInLoginLayoutWhitelist( const std::vector<std::string>& layouts) { for (size_t i = 0; i < layouts.size(); ++i) { if (login_layout_set_.find(layouts[i]) != login_layout_set_.end()) return true; } return false; } } // namespace chromeos