Roll src/third_party/WebKit 8b42d1d:744641d (svn 186770:186771)
[chromium-blink-merge.git] / chrome / browser / chromeos / input_method / component_extension_ime_manager_impl.cc
blob38b0182904b7de8f49b79d6276d22fdcd20db9fc
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.
5 #include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h"
7 #include <algorithm>
9 #include "base/files/file_util.h"
10 #include "base/json/json_string_value_serializer.h"
11 #include "base/logging.h"
12 #include "base/path_service.h"
13 #include "base/strings/string_util.h"
14 #include "base/sys_info.h"
15 #include "chrome/browser/extensions/component_loader.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/extensions/extension_constants.h"
21 #include "chrome/grit/browser_resources.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/extension_l10n_util.h"
27 #include "extensions/common/manifest_constants.h"
28 #include "ui/base/ime/chromeos/extension_ime_util.h"
29 #include "ui/base/l10n/l10n_util.h"
30 #include "ui/base/resource/resource_bundle.h"
32 namespace chromeos {
34 namespace {
36 struct WhitelistedComponentExtensionIME {
37 const char* id;
38 int manifest_resource_id;
39 } whitelisted_component_extension[] = {
40 {// ChromeOS Hangul Input.
41 extension_ime_util::kHangulExtensionId, IDR_HANGUL_MANIFEST,
43 #if defined(GOOGLE_CHROME_BUILD)
44 {// Official Google XKB Input.
45 extension_ime_util::kXkbExtensionId, IDR_GOOGLE_XKB_MANIFEST,
47 {// Google input tools.
48 extension_ime_util::kT13nExtensionId, IDR_GOOGLE_INPUT_TOOLS_MANIFEST,
50 #else
51 {// Open-sourced ChromeOS xkb extension.
52 extension_ime_util::kXkbExtensionId, IDR_XKB_MANIFEST,
54 {// Open-sourced ChromeOS Keyboards extension.
55 extension_ime_util::kM17nExtensionId, IDR_M17N_MANIFEST,
57 {// Open-sourced Pinyin Chinese Input Method.
58 extension_ime_util::kChinesePinyinExtensionId, IDR_PINYIN_MANIFEST,
60 {// Open-sourced Zhuyin Chinese Input Method.
61 extension_ime_util::kChineseZhuyinExtensionId, IDR_ZHUYIN_MANIFEST,
63 {// Open-sourced Cangjie Chinese Input Method.
64 extension_ime_util::kChineseCangjieExtensionId, IDR_CANGJIE_MANIFEST,
66 {// Japanese Mozc Input.
67 extension_ime_util::kMozcExtensionId, IDR_MOZC_MANIFEST,
69 #endif
70 {// Braille hardware keyboard IME that works together with ChromeVox.
71 extension_misc::kBrailleImeExtensionId, IDR_BRAILLE_MANIFEST,
75 const struct InputMethodNameMap {
76 const char* message_name;
77 int resource_id;
78 bool operator<(const InputMethodNameMap& other) const {
79 return strcmp(message_name, other.message_name) < 0;
81 } kInputMethodNameMap[] = {
82 {"__MSG_INPUTMETHOD_ARRAY__", IDS_IME_NAME_INPUTMETHOD_ARRAY},
83 {"__MSG_INPUTMETHOD_CANGJIE__", IDS_IME_NAME_INPUTMETHOD_CANGJIE},
84 {"__MSG_INPUTMETHOD_DAYI__", IDS_IME_NAME_INPUTMETHOD_DAYI},
85 {"__MSG_INPUTMETHOD_HANGUL_2_SET__",
86 IDS_IME_NAME_INPUTMETHOD_HANGUL_2_SET},
87 {"__MSG_INPUTMETHOD_HANGUL_3_SET_390__",
88 IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_390},
89 {"__MSG_INPUTMETHOD_HANGUL_3_SET_FINAL__",
90 IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_FINAL},
91 {"__MSG_INPUTMETHOD_HANGUL_3_SET_NO_SHIFT__",
92 IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_NO_SHIFT},
93 {"__MSG_INPUTMETHOD_HANGUL_AHNMATAE__",
94 IDS_IME_NAME_INPUTMETHOD_HANGUL_AHNMATAE},
95 {"__MSG_INPUTMETHOD_HANGUL_ROMAJA__",
96 IDS_IME_NAME_INPUTMETHOD_HANGUL_ROMAJA},
97 {"__MSG_INPUTMETHOD_HANGUL__", IDS_IME_NAME_INPUTMETHOD_HANGUL},
98 {"__MSG_INPUTMETHOD_MOZC_JP__", IDS_IME_NAME_INPUTMETHOD_MOZC_JP},
99 {"__MSG_INPUTMETHOD_MOZC_US__", IDS_IME_NAME_INPUTMETHOD_MOZC_US},
100 {"__MSG_INPUTMETHOD_PINYIN__", IDS_IME_NAME_INPUTMETHOD_PINYIN},
101 {"__MSG_INPUTMETHOD_QUICK__", IDS_IME_NAME_INPUTMETHOD_QUICK},
102 {"__MSG_INPUTMETHOD_TRADITIONAL_PINYIN__",
103 IDS_IME_NAME_INPUTMETHOD_TRADITIONAL_PINYIN},
104 {"__MSG_INPUTMETHOD_WUBI__", IDS_IME_NAME_INPUTMETHOD_WUBI},
105 {"__MSG_INPUTMETHOD_ZHUYIN__", IDS_IME_NAME_INPUTMETHOD_ZHUYIN},
106 {"__MSG_KEYBOARD_ARABIC__", IDS_IME_NAME_KEYBOARD_ARABIC},
107 {"__MSG_KEYBOARD_ARMENIAN_PHONETIC__",
108 IDS_IME_NAME_KEYBOARD_ARMENIAN_PHONETIC},
109 {"__MSG_KEYBOARD_BELARUSIAN__", IDS_IME_NAME_KEYBOARD_BELARUSIAN},
110 {"__MSG_KEYBOARD_BELGIAN__", IDS_IME_NAME_KEYBOARD_BELGIAN},
111 {"__MSG_KEYBOARD_BENGALI_PHONETIC__",
112 IDS_IME_NAME_KEYBOARD_BENGALI_PHONETIC},
113 {"__MSG_KEYBOARD_BRAZILIAN__", IDS_IME_NAME_KEYBOARD_BRAZILIAN},
114 {"__MSG_KEYBOARD_BULGARIAN_PHONETIC__",
115 IDS_IME_NAME_KEYBOARD_BULGARIAN_PHONETIC},
116 {"__MSG_KEYBOARD_BULGARIAN__", IDS_IME_NAME_KEYBOARD_BULGARIAN},
117 {"__MSG_KEYBOARD_CANADIAN_ENGLISH__",
118 IDS_IME_NAME_KEYBOARD_CANADIAN_ENGLISH},
119 {"__MSG_KEYBOARD_CANADIAN_FRENCH__",
120 IDS_IME_NAME_KEYBOARD_CANADIAN_FRENCH},
121 {"__MSG_KEYBOARD_CANADIAN_MULTILINGUAL__",
122 IDS_IME_NAME_KEYBOARD_CANADIAN_MULTILINGUAL},
123 {"__MSG_KEYBOARD_CATALAN__", IDS_IME_NAME_KEYBOARD_CATALAN},
124 {"__MSG_KEYBOARD_CROATIAN__", IDS_IME_NAME_KEYBOARD_CROATIAN},
125 {"__MSG_KEYBOARD_CZECH_QWERTY__", IDS_IME_NAME_KEYBOARD_CZECH_QWERTY},
126 {"__MSG_KEYBOARD_CZECH__", IDS_IME_NAME_KEYBOARD_CZECH},
127 {"__MSG_KEYBOARD_DANISH__", IDS_IME_NAME_KEYBOARD_DANISH},
128 {"__MSG_KEYBOARD_DEVANAGARI_PHONETIC__",
129 IDS_IME_NAME_KEYBOARD_DEVANAGARI_PHONETIC},
130 {"__MSG_KEYBOARD_ESTONIAN__", IDS_IME_NAME_KEYBOARD_ESTONIAN},
131 {"__MSG_KEYBOARD_ETHIOPIC__", IDS_IME_NAME_KEYBOARD_ETHIOPIC},
132 {"__MSG_KEYBOARD_FINNISH__", IDS_IME_NAME_KEYBOARD_FINNISH},
133 {"__MSG_KEYBOARD_FRENCH__", IDS_IME_NAME_KEYBOARD_FRENCH},
134 {"__MSG_KEYBOARD_GEORGIAN__", IDS_IME_NAME_KEYBOARD_GEORGIAN},
135 {"__MSG_KEYBOARD_GERMAN_NEO_2__", IDS_IME_NAME_KEYBOARD_GERMAN_NEO_2},
136 {"__MSG_KEYBOARD_GERMAN__", IDS_IME_NAME_KEYBOARD_GERMAN},
137 {"__MSG_KEYBOARD_GREEK__", IDS_IME_NAME_KEYBOARD_GREEK},
138 {"__MSG_KEYBOARD_GUJARATI_PHONETIC__",
139 IDS_IME_NAME_KEYBOARD_GUJARATI_PHONETIC},
140 {"__MSG_KEYBOARD_HEBREW__", IDS_IME_NAME_KEYBOARD_HEBREW},
141 {"__MSG_KEYBOARD_HUNGARIAN__", IDS_IME_NAME_KEYBOARD_HUNGARIAN},
142 {"__MSG_KEYBOARD_ICELANDIC__", IDS_IME_NAME_KEYBOARD_ICELANDIC},
143 {"__MSG_KEYBOARD_IRISH__", IDS_IME_NAME_KEYBOARD_IRISH},
144 {"__MSG_KEYBOARD_ITALIAN__", IDS_IME_NAME_KEYBOARD_ITALIAN},
145 {"__MSG_KEYBOARD_JAPANESE__", IDS_IME_NAME_KEYBOARD_JAPANESE},
146 {"__MSG_KEYBOARD_KANNADA_PHONETIC__",
147 IDS_IME_NAME_KEYBOARD_KANNADA_PHONETIC},
148 {"__MSG_KEYBOARD_KHMER__", IDS_IME_NAME_KEYBOARD_KHMER},
149 {"__MSG_KEYBOARD_LAO__", IDS_IME_NAME_KEYBOARD_LAO},
150 {"__MSG_KEYBOARD_LATIN_AMERICAN__", IDS_IME_NAME_KEYBOARD_LATIN_AMERICAN},
151 {"__MSG_KEYBOARD_LATVIAN__", IDS_IME_NAME_KEYBOARD_LATVIAN},
152 {"__MSG_KEYBOARD_LITHUANIAN__", IDS_IME_NAME_KEYBOARD_LITHUANIAN},
153 {"__MSG_KEYBOARD_MALAYALAM_PHONETIC__",
154 IDS_IME_NAME_KEYBOARD_MALAYALAM_PHONETIC},
155 {"__MSG_KEYBOARD_MALTESE__", IDS_IME_NAME_KEYBOARD_MALTESE},
156 {"__MSG_KEYBOARD_MONGOLIAN__", IDS_IME_NAME_KEYBOARD_MONGOLIAN},
157 {"__MSG_KEYBOARD_MYANMAR_MYANSAN__",
158 IDS_IME_NAME_KEYBOARD_MYANMAR_MYANSAN},
159 {"__MSG_KEYBOARD_MYANMAR__", IDS_IME_NAME_KEYBOARD_MYANMAR},
160 {"__MSG_KEYBOARD_NEPALI_INSCRIPT__",
161 IDS_IME_NAME_KEYBOARD_NEPALI_INSCRIPT},
162 {"__MSG_KEYBOARD_NEPALI_PHONETIC__",
163 IDS_IME_NAME_KEYBOARD_NEPALI_PHONETIC},
164 {"__MSG_KEYBOARD_NORWEGIAN__", IDS_IME_NAME_KEYBOARD_NORWEGIAN},
165 {"__MSG_KEYBOARD_PERSIAN__", IDS_IME_NAME_KEYBOARD_PERSIAN},
166 {"__MSG_KEYBOARD_POLISH__", IDS_IME_NAME_KEYBOARD_POLISH},
167 {"__MSG_KEYBOARD_PORTUGUESE__", IDS_IME_NAME_KEYBOARD_PORTUGUESE},
168 {"__MSG_KEYBOARD_ROMANIAN__", IDS_IME_NAME_KEYBOARD_ROMANIAN},
169 {"__MSG_KEYBOARD_RUSSIAN_PHONETIC_AATSEEL__",
170 IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC_AATSEEL},
171 {"__MSG_KEYBOARD_RUSSIAN_PHONETIC_YAZHERT__",
172 IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC_YAZHERT},
173 {"__MSG_KEYBOARD_RUSSIAN_PHONETIC__",
174 IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC},
175 {"__MSG_KEYBOARD_RUSSIAN__", IDS_IME_NAME_KEYBOARD_RUSSIAN},
176 {"__MSG_KEYBOARD_SERBIAN__", IDS_IME_NAME_KEYBOARD_SERBIAN},
177 {"__MSG_KEYBOARD_SINHALA__", IDS_IME_NAME_KEYBOARD_SINHALA},
178 {"__MSG_KEYBOARD_SLOVAKIAN__", IDS_IME_NAME_KEYBOARD_SLOVAKIAN},
179 {"__MSG_KEYBOARD_SLOVENIAN__", IDS_IME_NAME_KEYBOARD_SLOVENIAN},
180 {"__MSG_KEYBOARD_SORANIKURDISH_AR__",
181 IDS_IME_NAME_KEYBOARD_SORANIKURDISH_AR},
182 {"__MSG_KEYBOARD_SORANIKURDISH_EN__",
183 IDS_IME_NAME_KEYBOARD_SORANIKURDISH_EN},
184 {"__MSG_KEYBOARD_SPANISH__", IDS_IME_NAME_KEYBOARD_SPANISH},
185 {"__MSG_KEYBOARD_SWEDISH__", IDS_IME_NAME_KEYBOARD_SWEDISH},
186 {"__MSG_KEYBOARD_SWISS_FRENCH__", IDS_IME_NAME_KEYBOARD_SWISS_FRENCH},
187 {"__MSG_KEYBOARD_SWISS__", IDS_IME_NAME_KEYBOARD_SWISS},
188 {"__MSG_KEYBOARD_TAMIL_INSCRIPT__", IDS_IME_NAME_KEYBOARD_TAMIL_INSCRIPT},
189 {"__MSG_KEYBOARD_TAMIL_ITRANS__", IDS_IME_NAME_KEYBOARD_TAMIL_ITRANS},
190 {"__MSG_KEYBOARD_TAMIL_PHONETIC__", IDS_IME_NAME_KEYBOARD_TAMIL_PHONETIC},
191 {"__MSG_KEYBOARD_TAMIL_TAMIL99__", IDS_IME_NAME_KEYBOARD_TAMIL_TAMIL99},
192 {"__MSG_KEYBOARD_TAMIL_TYPEWRITER__",
193 IDS_IME_NAME_KEYBOARD_TAMIL_TYPEWRITER},
194 {"__MSG_KEYBOARD_TELUGU_PHONETIC__",
195 IDS_IME_NAME_KEYBOARD_TELUGU_PHONETIC},
196 {"__MSG_KEYBOARD_THAI_KEDMANEE__", IDS_IME_NAME_KEYBOARD_THAI_KEDMANEE},
197 {"__MSG_KEYBOARD_THAI_PATTACHOTE__",
198 IDS_IME_NAME_KEYBOARD_THAI_PATTACHOTE},
199 {"__MSG_KEYBOARD_THAI_TIS__", IDS_IME_NAME_KEYBOARD_THAI_TIS},
200 {"__MSG_KEYBOARD_TURKISH__", IDS_IME_NAME_KEYBOARD_TURKISH},
201 {"__MSG_KEYBOARD_UKRAINIAN__", IDS_IME_NAME_KEYBOARD_UKRAINIAN},
202 {"__MSG_KEYBOARD_UK_DVORAK__", IDS_IME_NAME_KEYBOARD_UK_DVORAK},
203 {"__MSG_KEYBOARD_UK__", IDS_IME_NAME_KEYBOARD_UK},
204 {"__MSG_KEYBOARD_US_COLEMAK__", IDS_IME_NAME_KEYBOARD_US_COLEMAK},
205 {"__MSG_KEYBOARD_US_DVORAK__", IDS_IME_NAME_KEYBOARD_US_DVORAK},
206 {"__MSG_KEYBOARD_US_EXTENDED__", IDS_IME_NAME_KEYBOARD_US_EXTENDED},
207 {"__MSG_KEYBOARD_US_INTERNATIONAL__",
208 IDS_IME_NAME_KEYBOARD_US_INTERNATIONAL},
209 {"__MSG_KEYBOARD_US__", IDS_IME_NAME_KEYBOARD_US},
210 {"__MSG_KEYBOARD_VIETNAMESE_TCVN__",
211 IDS_IME_NAME_KEYBOARD_VIETNAMESE_TCVN},
212 {"__MSG_KEYBOARD_VIETNAMESE_TELEX__",
213 IDS_IME_NAME_KEYBOARD_VIETNAMESE_TELEX},
214 {"__MSG_KEYBOARD_VIETNAMESE_VIQR__",
215 IDS_IME_NAME_KEYBOARD_VIETNAMESE_VIQR},
216 {"__MSG_KEYBOARD_VIETNAMESE_VNI__", IDS_IME_NAME_KEYBOARD_VIETNAMESE_VNI},
217 {"__MSG_TRANSLITERATION_AM__", IDS_IME_NAME_TRANSLITERATION_AM},
218 {"__MSG_TRANSLITERATION_AR__", IDS_IME_NAME_TRANSLITERATION_AR},
219 {"__MSG_TRANSLITERATION_BN__", IDS_IME_NAME_TRANSLITERATION_BN},
220 {"__MSG_TRANSLITERATION_EL__", IDS_IME_NAME_TRANSLITERATION_EL},
221 {"__MSG_TRANSLITERATION_FA__", IDS_IME_NAME_TRANSLITERATION_FA},
222 {"__MSG_TRANSLITERATION_GU__", IDS_IME_NAME_TRANSLITERATION_GU},
223 {"__MSG_TRANSLITERATION_HE__", IDS_IME_NAME_TRANSLITERATION_HE},
224 {"__MSG_TRANSLITERATION_HI__", IDS_IME_NAME_TRANSLITERATION_HI},
225 {"__MSG_TRANSLITERATION_KN__", IDS_IME_NAME_TRANSLITERATION_KN},
226 {"__MSG_TRANSLITERATION_ML__", IDS_IME_NAME_TRANSLITERATION_ML},
227 {"__MSG_TRANSLITERATION_MR__", IDS_IME_NAME_TRANSLITERATION_MR},
228 {"__MSG_TRANSLITERATION_NE__", IDS_IME_NAME_TRANSLITERATION_NE},
229 {"__MSG_TRANSLITERATION_OR__", IDS_IME_NAME_TRANSLITERATION_OR},
230 {"__MSG_TRANSLITERATION_PA__", IDS_IME_NAME_TRANSLITERATION_PA},
231 {"__MSG_TRANSLITERATION_SA__", IDS_IME_NAME_TRANSLITERATION_SA},
232 {"__MSG_TRANSLITERATION_SR__", IDS_IME_NAME_TRANSLITERATION_SR},
233 {"__MSG_TRANSLITERATION_TA__", IDS_IME_NAME_TRANSLITERATION_TA},
234 {"__MSG_TRANSLITERATION_TE__", IDS_IME_NAME_TRANSLITERATION_TE},
235 {"__MSG_TRANSLITERATION_TI__", IDS_IME_NAME_TRANSLITERATION_TI},
236 {"__MSG_TRANSLITERATION_UR__", IDS_IME_NAME_TRANSLITERATION_UR},
239 const char kImePathKeyName[] = "ime_path";
241 extensions::ComponentLoader* GetComponentLoader(Profile* profile) {
242 extensions::ExtensionSystem* extension_system =
243 extensions::ExtensionSystem::Get(profile);
244 ExtensionService* extension_service = extension_system->extension_service();
245 return extension_service->component_loader();
248 void DoLoadExtension(Profile* profile,
249 const std::string& extension_id,
250 const std::string& manifest,
251 const base::FilePath& file_path) {
252 extensions::ExtensionSystem* extension_system =
253 extensions::ExtensionSystem::Get(profile);
254 ExtensionService* extension_service = extension_system->extension_service();
255 DCHECK(extension_service);
256 if (extension_service->GetExtensionById(extension_id, false))
257 return;
258 const std::string loaded_extension_id =
259 GetComponentLoader(profile)->Add(manifest, file_path);
260 DCHECK_EQ(loaded_extension_id, extension_id);
263 bool CheckFilePath(const base::FilePath* file_path) {
264 return base::PathExists(*file_path);
267 void OnFilePathChecked(Profile* profile,
268 const std::string* extension_id,
269 const std::string* manifest,
270 const base::FilePath* file_path,
271 bool result) {
272 if (result)
273 DoLoadExtension(profile, *extension_id, *manifest, *file_path);
274 else
275 LOG(ERROR) << "IME extension file path not exists: " << file_path->value();
278 } // namespace
280 ComponentExtensionIMEManagerImpl::ComponentExtensionIMEManagerImpl() {
281 ReadComponentExtensionsInfo(&component_extension_list_);
284 ComponentExtensionIMEManagerImpl::~ComponentExtensionIMEManagerImpl() {
287 std::vector<ComponentExtensionIME> ComponentExtensionIMEManagerImpl::ListIME() {
288 return component_extension_list_;
291 void ComponentExtensionIMEManagerImpl::Load(Profile* profile,
292 const std::string& extension_id,
293 const std::string& manifest,
294 const base::FilePath& file_path) {
295 // For Athena, should always do async extension loading because the extension
296 // service may not be initialized yet.
297 #if !defined(USE_ATHENA)
298 if (base::SysInfo::IsRunningOnChromeOS()) {
299 // In the case of real Chrome OS device, the no need to check the file path
300 // for preinstalled files existence.
301 DoLoadExtension(profile, extension_id, manifest, file_path);
302 return;
304 #endif
305 // If current environment is linux_chromeos, check the existence of file path
306 // to avoid unnecessary extension loading and InputMethodEngine creation, so
307 // that the virtual keyboard web content url won't be override by IME
308 // component extensions.
309 base::FilePath* copied_file_path = new base::FilePath(file_path);
310 content::BrowserThread::PostTaskAndReplyWithResult(
311 content::BrowserThread::FILE,
312 FROM_HERE,
313 base::Bind(&CheckFilePath,
314 base::Unretained(copied_file_path)),
315 base::Bind(&OnFilePathChecked,
316 base::Unretained(profile),
317 base::Owned(new std::string(extension_id)),
318 base::Owned(new std::string(manifest)),
319 base::Owned(copied_file_path)));
322 void ComponentExtensionIMEManagerImpl::Unload(Profile* profile,
323 const std::string& extension_id,
324 const base::FilePath& file_path) {
325 // Remove(extension_id) does nothing when the extension has already been
326 // removed or not been registered.
327 GetComponentLoader(profile)->Remove(extension_id);
330 scoped_ptr<base::DictionaryValue> ComponentExtensionIMEManagerImpl::GetManifest(
331 const std::string& manifest_string) {
332 std::string error;
333 JSONStringValueSerializer serializer(manifest_string);
334 scoped_ptr<base::Value> manifest(serializer.Deserialize(NULL, &error));
335 if (!manifest.get())
336 LOG(ERROR) << "Failed at getting manifest";
338 return scoped_ptr<base::DictionaryValue>(
339 static_cast<base::DictionaryValue*>(manifest.release())).Pass();
342 // static
343 bool ComponentExtensionIMEManagerImpl::ReadEngineComponent(
344 const ComponentExtensionIME& component_extension,
345 const base::DictionaryValue& dict,
346 ComponentExtensionEngine* out) {
347 DCHECK(out);
348 std::string type;
349 if (!dict.GetString(extensions::manifest_keys::kType, &type))
350 return false;
351 if (type != "ime")
352 return false;
353 if (!dict.GetString(extensions::manifest_keys::kId, &out->engine_id))
354 return false;
355 if (!dict.GetString(extensions::manifest_keys::kName, &out->display_name))
356 return false;
357 if (!dict.GetString(extensions::manifest_keys::kIndicator, &out->indicator))
358 out->indicator = "";
360 // Localizes the input method name.
361 if (out->display_name.find("__MSG_") == 0) {
362 const InputMethodNameMap* map = kInputMethodNameMap;
363 size_t map_size = arraysize(kInputMethodNameMap);
364 std::string name = StringToUpperASCII(out->display_name);
365 const InputMethodNameMap map_key = {name.c_str(), 0};
366 const InputMethodNameMap* p =
367 std::lower_bound(map, map + map_size, map_key);
368 if (p != map + map_size && name == p->message_name)
369 out->display_name = l10n_util::GetStringUTF8(p->resource_id);
371 DCHECK(out->display_name.find("__MSG_") == std::string::npos);
373 std::set<std::string> languages;
374 const base::Value* language_value = NULL;
375 if (dict.Get(extensions::manifest_keys::kLanguage, &language_value)) {
376 if (language_value->GetType() == base::Value::TYPE_STRING) {
377 std::string language_str;
378 language_value->GetAsString(&language_str);
379 languages.insert(language_str);
380 } else if (language_value->GetType() == base::Value::TYPE_LIST) {
381 const base::ListValue* language_list = NULL;
382 language_value->GetAsList(&language_list);
383 for (size_t j = 0; j < language_list->GetSize(); ++j) {
384 std::string language_str;
385 if (language_list->GetString(j, &language_str))
386 languages.insert(language_str);
390 DCHECK(!languages.empty());
391 out->language_codes.assign(languages.begin(), languages.end());
393 const base::ListValue* layouts = NULL;
394 if (!dict.GetList(extensions::manifest_keys::kLayouts, &layouts))
395 return false;
397 for (size_t i = 0; i < layouts->GetSize(); ++i) {
398 std::string buffer;
399 if (layouts->GetString(i, &buffer))
400 out->layouts.push_back(buffer);
403 std::string url_string;
404 if (dict.GetString(extensions::manifest_keys::kInputView,
405 &url_string)) {
406 GURL url = extensions::Extension::GetResourceURL(
407 extensions::Extension::GetBaseURLFromExtensionId(
408 component_extension.id),
409 url_string);
410 if (!url.is_valid())
411 return false;
412 out->input_view_url = url;
415 if (dict.GetString(extensions::manifest_keys::kOptionsPage,
416 &url_string)) {
417 GURL url = extensions::Extension::GetResourceURL(
418 extensions::Extension::GetBaseURLFromExtensionId(
419 component_extension.id),
420 url_string);
421 if (!url.is_valid())
422 return false;
423 out->options_page_url = url;
424 } else {
425 // Fallback to extension level options page.
426 out->options_page_url = component_extension.options_page_url;
429 return true;
432 // static
433 bool ComponentExtensionIMEManagerImpl::ReadExtensionInfo(
434 const base::DictionaryValue& manifest,
435 const std::string& extension_id,
436 ComponentExtensionIME* out) {
437 if (!manifest.GetString(extensions::manifest_keys::kDescription,
438 &out->description))
439 return false;
440 std::string path;
441 if (manifest.GetString(kImePathKeyName, &path))
442 out->path = base::FilePath(path);
443 std::string url_string;
444 if (manifest.GetString(extensions::manifest_keys::kOptionsPage,
445 &url_string)) {
446 GURL url = extensions::Extension::GetResourceURL(
447 extensions::Extension::GetBaseURLFromExtensionId(extension_id),
448 url_string);
449 if (!url.is_valid())
450 return false;
451 out->options_page_url = url;
453 // It's okay to return true on no option page and/or input view page case.
454 return true;
457 // static
458 void ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo(
459 std::vector<ComponentExtensionIME>* out_imes) {
460 DCHECK(out_imes);
461 for (size_t i = 0; i < arraysize(whitelisted_component_extension); ++i) {
462 ComponentExtensionIME component_ime;
463 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
464 component_ime.manifest =
465 rb.GetRawDataResource(
466 whitelisted_component_extension[i].manifest_resource_id)
467 .as_string();
468 if (component_ime.manifest.empty())
469 continue;
471 scoped_ptr<base::DictionaryValue> manifest =
472 GetManifest(component_ime.manifest);
473 if (!manifest.get())
474 continue;
476 if (!ReadExtensionInfo(*manifest.get(),
477 whitelisted_component_extension[i].id,
478 &component_ime))
479 continue;
480 component_ime.id = whitelisted_component_extension[i].id;
482 if (!component_ime.path.IsAbsolute()) {
483 base::FilePath resources_path;
484 if (!PathService::Get(chrome::DIR_RESOURCES, &resources_path))
485 NOTREACHED();
486 component_ime.path = resources_path.Append(component_ime.path);
489 const base::ListValue* component_list;
490 if (!manifest->GetList(extensions::manifest_keys::kInputComponents,
491 &component_list))
492 continue;
494 for (size_t i = 0; i < component_list->GetSize(); ++i) {
495 const base::DictionaryValue* dictionary;
496 if (!component_list->GetDictionary(i, &dictionary))
497 continue;
499 ComponentExtensionEngine engine;
500 ReadEngineComponent(component_ime, *dictionary, &engine);
501 component_ime.engines.push_back(engine);
503 out_imes->push_back(component_ime);
507 } // namespace chromeos