Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / input_method / component_extension_ime_manager_impl.cc
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 "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h"
6
7 #include "base/file_util.h"
8 #include "base/logging.h"
9 #include "chrome/browser/extensions/component_loader.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_system.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/common/extensions/extension_file_util.h"
15 #include "chrome/common/extensions/extension_l10n_util.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "extensions/common/extension.h"
18 #include "extensions/common/manifest_constants.h"
19 #include "ui/base/l10n/l10n_util.h"
20
21 namespace chromeos {
22
23 namespace {
24
25 struct WhitelistedComponentExtensionIME {
26   const char* id;
27   const char* path;
28 } whitelisted_component_extension[] = {
29   {
30     // ChromeOS Keyboards extension.
31     "jhffeifommiaekmbkkjlpmilogcfdohp",
32     "/usr/share/chromeos-assets/input_methods/keyboard_layouts",
33   },
34   {
35     // ChromeOS Hangul Input.
36     "bdgdidmhaijohebebipajioienkglgfo",
37     "/usr/share/chromeos-assets/input_methods/hangul",
38   },
39 #if defined(OFFICIAL_BUILD)
40   {
41     // Official Google Japanese Input.
42     "fpfbhcjppmaeaijcidgiibchfbnhbelj",
43     "/usr/share/chromeos-assets/input_methods/nacl_mozc",
44   },
45   {
46     // Google Chinese Input (zhuyin)
47     "goedamlknlnjaengojinmfgpmdjmkooo",
48     "/usr/share/chromeos-assets/input_methods/zhuyin",
49   },
50   {
51     // Google Chinese Input (pinyin)
52     "nmblnjkfdkabgdofidlkienfnnbjhnab",
53     "/usr/share/chromeos-assets/input_methods/pinyin",
54   },
55   {
56     // Google Chinese Input (cangjie)
57     "gjhclobljhjhgoebiipblnmdodbmpdgd",
58     "/usr/share/chromeos-assets/input_methods/cangjie",
59   },
60   {
61     // Google input tools.
62     "gjaehgfemfahhmlgpdfknkhdnemmolop",
63     "/usr/share/chromeos-assets/input_methods/input_tools",
64   },
65 #else
66   {
67     // Open-sourced Pinyin Chinese Input Method.
68     "cpgalbafkoofkjmaeonnfijgpfennjjn",
69     "/usr/share/chromeos-assets/input_methods/pinyin",
70   },
71   {
72     // Open-sourced Zhuyin Chinese Input Method.
73     "ekbifjdfhkmdeeajnolmgdlmkllopefi",
74     "/usr/share/chromeos-assets/input_methods/zhuyin",
75   },
76   {
77     // Open-sourced Cangjie Chinese Input Method.
78     "aeebooiibjahgpgmhkeocbeekccfknbj",
79     "/usr/share/chromeos-assets/input_methods/cangjie",
80   },
81   {
82     // Open-sourced Mozc Japanese Input.
83     "bbaiamgfapehflhememkfglaehiobjnk",
84     "/usr/share/chromeos-assets/input_methods/nacl_mozc",
85   },
86 #endif
87 };
88
89 extensions::ComponentLoader* GetComponentLoader() {
90   // TODO(skuhne, nkostylev): At this time the only thing which makes sense here
91   // is to use the active profile. Nkostylev is working on getting IME settings
92   // to work for multi user by collecting all settings from all users. Once that
93   // is done we might have to re-visit this decision.
94   Profile* profile = ProfileManager::GetActiveUserProfile();
95   extensions::ExtensionSystem* extension_system =
96       extensions::ExtensionSystem::Get(profile);
97   ExtensionService* extension_service = extension_system->extension_service();
98   return extension_service->component_loader();
99 }
100 }  // namespace
101
102 ComponentExtensionIMEManagerImpl::ComponentExtensionIMEManagerImpl()
103     : is_initialized_(false),
104       weak_ptr_factory_(this) {
105 }
106
107 ComponentExtensionIMEManagerImpl::~ComponentExtensionIMEManagerImpl() {
108 }
109
110 std::vector<ComponentExtensionIME> ComponentExtensionIMEManagerImpl::ListIME() {
111   DCHECK(thread_checker_.CalledOnValidThread());
112   return component_extension_list_;
113 }
114
115 bool ComponentExtensionIMEManagerImpl::Load(const std::string& extension_id,
116                                             const std::string& manifest,
117                                             const base::FilePath& file_path) {
118   DCHECK(thread_checker_.CalledOnValidThread());
119   if (loaded_extension_id_.find(extension_id) != loaded_extension_id_.end())
120     return false;
121   const std::string loaded_extension_id =
122       GetComponentLoader()->Add(manifest, file_path);
123   DCHECK_EQ(loaded_extension_id, extension_id);
124   loaded_extension_id_.insert(extension_id);
125   return true;
126 }
127
128 bool ComponentExtensionIMEManagerImpl::Unload(const std::string& extension_id,
129                                               const base::FilePath& file_path) {
130   DCHECK(thread_checker_.CalledOnValidThread());
131   if (loaded_extension_id_.find(extension_id) == loaded_extension_id_.end())
132     return false;
133   GetComponentLoader()->Remove(extension_id);
134   loaded_extension_id_.erase(extension_id);
135   return true;
136 }
137
138 scoped_ptr<base::DictionaryValue> ComponentExtensionIMEManagerImpl::GetManifest(
139     const base::FilePath& file_path) {
140   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
141   std::string error;
142   scoped_ptr<base::DictionaryValue> manifest(
143       extension_file_util::LoadManifest(file_path, &error));
144   if (!manifest.get())
145     LOG(ERROR) << "Failed at getting manifest";
146   if (!extension_l10n_util::LocalizeExtension(file_path,
147                                               manifest.get(),
148                                               &error))
149     LOG(ERROR) << "Localization failed";
150
151   return manifest.Pass();
152 }
153
154 void ComponentExtensionIMEManagerImpl::InitializeAsync(
155     const base::Closure& callback) {
156   DCHECK(!is_initialized_);
157   DCHECK(thread_checker_.CalledOnValidThread());
158
159   std::vector<ComponentExtensionIME>* component_extension_ime_list
160       = new std::vector<ComponentExtensionIME>;
161   content::BrowserThread::PostTaskAndReply(
162       content::BrowserThread::FILE,
163       FROM_HERE,
164       base::Bind(&ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo,
165                  base::Unretained(component_extension_ime_list)),
166       base::Bind(
167           &ComponentExtensionIMEManagerImpl::OnReadComponentExtensionsInfo,
168           weak_ptr_factory_.GetWeakPtr(),
169           base::Owned(component_extension_ime_list),
170           callback));
171 }
172
173 bool ComponentExtensionIMEManagerImpl::IsInitialized() {
174   return is_initialized_;
175 }
176
177 // static
178 bool ComponentExtensionIMEManagerImpl::ReadEngineComponent(
179     const base::DictionaryValue& dict,
180     ComponentExtensionEngine* out) {
181   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
182   DCHECK(out);
183   std::string type;
184   if (!dict.GetString(extensions::manifest_keys::kType, &type))
185     return false;
186   if (type != "ime")
187     return false;
188   if (!dict.GetString(extensions::manifest_keys::kId, &out->engine_id))
189     return false;
190   if (!dict.GetString(extensions::manifest_keys::kName, &out->display_name))
191     return false;
192
193   std::set<std::string> languages;
194   const base::Value* language_value = NULL;
195   if (dict.Get(extensions::manifest_keys::kLanguage, &language_value)) {
196     if (language_value->GetType() == base::Value::TYPE_STRING) {
197       std::string language_str;
198       language_value->GetAsString(&language_str);
199       languages.insert(language_str);
200     } else if (language_value->GetType() == base::Value::TYPE_LIST) {
201       const base::ListValue* language_list = NULL;
202       language_value->GetAsList(&language_list);
203       for (size_t j = 0; j < language_list->GetSize(); ++j) {
204         std::string language_str;
205         if (language_list->GetString(j, &language_str))
206           languages.insert(language_str);
207       }
208     }
209   }
210   DCHECK(!languages.empty());
211   out->language_codes.assign(languages.begin(), languages.end());
212
213   const base::ListValue* layouts = NULL;
214   if (!dict.GetList(extensions::manifest_keys::kLayouts, &layouts))
215     return false;
216
217   for (size_t i = 0; i < layouts->GetSize(); ++i) {
218     std::string buffer;
219     if (layouts->GetString(i, &buffer))
220       out->layouts.push_back(buffer);
221   }
222   return true;
223 }
224
225 // static
226 bool ComponentExtensionIMEManagerImpl::ReadExtensionInfo(
227     const base::DictionaryValue& manifest,
228     const std::string& extension_id,
229     ComponentExtensionIME* out) {
230   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
231   if (!manifest.GetString(extensions::manifest_keys::kDescription,
232                           &out->description))
233     return false;
234   std::string url_string;
235   if (manifest.GetString(extensions::manifest_keys::kOptionsPage,
236                          &url_string)) {
237     GURL url = extensions::Extension::GetResourceURL(
238         extensions::Extension::GetBaseURLFromExtensionId(extension_id),
239         url_string);
240     if (!url.is_valid())
241       return false;
242     out->options_page_url = url;
243   }
244   if (manifest.GetString(extensions::manifest_keys::kInputView,
245                          &url_string)) {
246     GURL url = extensions::Extension::GetResourceURL(
247         extensions::Extension::GetBaseURLFromExtensionId(extension_id),
248         url_string);
249     if (!url.is_valid())
250       return false;
251     out->input_view_url = url;
252   }
253   // It's okay to return true on no option page and/or input view page case.
254   return true;
255 }
256
257 // static
258 void ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo(
259     std::vector<ComponentExtensionIME>* out_imes) {
260   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
261   DCHECK(out_imes);
262   for (size_t i = 0; i < arraysize(whitelisted_component_extension); ++i) {
263     ComponentExtensionIME component_ime;
264     component_ime.path = base::FilePath(
265         whitelisted_component_extension[i].path);
266
267     const base::FilePath manifest_path =
268         component_ime.path.Append("manifest.json");
269
270     if (!base::PathExists(component_ime.path) ||
271         !base::PathExists(manifest_path))
272       continue;
273
274     if (!base::ReadFileToString(manifest_path, &component_ime.manifest))
275       continue;
276
277     scoped_ptr<base::DictionaryValue> manifest =
278         GetManifest(component_ime.path);
279     if (!manifest.get())
280       continue;
281
282     if (!ReadExtensionInfo(*manifest.get(),
283                            whitelisted_component_extension[i].id,
284                            &component_ime))
285       continue;
286     component_ime.id = whitelisted_component_extension[i].id;
287
288     const base::ListValue* component_list;
289     if (!manifest->GetList(extensions::manifest_keys::kInputComponents,
290                            &component_list))
291       continue;
292
293     for (size_t i = 0; i < component_list->GetSize(); ++i) {
294       const base::DictionaryValue* dictionary;
295       if (!component_list->GetDictionary(i, &dictionary))
296         continue;
297
298       ComponentExtensionEngine engine;
299       ReadEngineComponent(*dictionary, &engine);
300       component_ime.engines.push_back(engine);
301     }
302     out_imes->push_back(component_ime);
303   }
304 }
305
306 void ComponentExtensionIMEManagerImpl::OnReadComponentExtensionsInfo(
307     std::vector<ComponentExtensionIME>* result,
308     const base::Closure& callback) {
309   DCHECK(thread_checker_.CalledOnValidThread());
310   DCHECK(result);
311   component_extension_list_ = *result;
312   is_initialized_ = true;
313   callback.Run();
314 }
315
316 }  // namespace chromeos