- add sources.
[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.h"
15 #include "chrome/common/extensions/extension_file_util.h"
16 #include "chrome/common/extensions/extension_l10n_util.h"
17 #include "content/public/browser/browser_thread.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   Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
91   extensions::ExtensionSystem* extension_system =
92       extensions::ExtensionSystem::Get(profile);
93   ExtensionService* extension_service = extension_system->extension_service();
94   return extension_service->component_loader();
95 }
96 }  // namespace
97
98 ComponentExtensionIMEManagerImpl::ComponentExtensionIMEManagerImpl()
99     : is_initialized_(false),
100       weak_ptr_factory_(this) {
101 }
102
103 ComponentExtensionIMEManagerImpl::~ComponentExtensionIMEManagerImpl() {
104 }
105
106 std::vector<ComponentExtensionIME> ComponentExtensionIMEManagerImpl::ListIME() {
107   DCHECK(thread_checker_.CalledOnValidThread());
108   return component_extension_list_;
109 }
110
111 bool ComponentExtensionIMEManagerImpl::Load(const std::string& extension_id,
112                                             const std::string& manifest,
113                                             const base::FilePath& file_path) {
114   DCHECK(thread_checker_.CalledOnValidThread());
115   if (loaded_extension_id_.find(extension_id) != loaded_extension_id_.end())
116     return false;
117   const std::string loaded_extension_id =
118       GetComponentLoader()->Add(manifest, file_path);
119   DCHECK_EQ(loaded_extension_id, extension_id);
120   loaded_extension_id_.insert(extension_id);
121   return true;
122 }
123
124 bool ComponentExtensionIMEManagerImpl::Unload(const std::string& extension_id,
125                                               const base::FilePath& file_path) {
126   DCHECK(thread_checker_.CalledOnValidThread());
127   if (loaded_extension_id_.find(extension_id) == loaded_extension_id_.end())
128     return false;
129   GetComponentLoader()->Remove(extension_id);
130   loaded_extension_id_.erase(extension_id);
131   return true;
132 }
133
134 scoped_ptr<DictionaryValue> ComponentExtensionIMEManagerImpl::GetManifest(
135     const base::FilePath& file_path) {
136   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
137   std::string error;
138   scoped_ptr<DictionaryValue> manifest(
139       extension_file_util::LoadManifest(file_path, &error));
140   if (!manifest.get())
141     LOG(ERROR) << "Failed at getting manifest";
142   if (!extension_l10n_util::LocalizeExtension(file_path,
143                                               manifest.get(),
144                                               &error))
145     LOG(ERROR) << "Localization failed";
146
147   return manifest.Pass();
148 }
149
150 void ComponentExtensionIMEManagerImpl::InitializeAsync(
151     const base::Closure& callback) {
152   DCHECK(!is_initialized_);
153   DCHECK(thread_checker_.CalledOnValidThread());
154
155   std::vector<ComponentExtensionIME>* component_extension_ime_list
156       = new std::vector<ComponentExtensionIME>;
157   content::BrowserThread::PostTaskAndReply(
158       content::BrowserThread::FILE,
159       FROM_HERE,
160       base::Bind(&ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo,
161                  base::Unretained(component_extension_ime_list)),
162       base::Bind(
163           &ComponentExtensionIMEManagerImpl::OnReadComponentExtensionsInfo,
164           weak_ptr_factory_.GetWeakPtr(),
165           base::Owned(component_extension_ime_list),
166           callback));
167 }
168
169 bool ComponentExtensionIMEManagerImpl::IsInitialized() {
170   return is_initialized_;
171 }
172
173 // static
174 bool ComponentExtensionIMEManagerImpl::ReadEngineComponent(
175     const DictionaryValue& dict,
176     ComponentExtensionEngine* out) {
177   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
178   DCHECK(out);
179   std::string type;
180   if (!dict.GetString(extensions::manifest_keys::kType, &type))
181     return false;
182   if (type != "ime")
183     return false;
184   if (!dict.GetString(extensions::manifest_keys::kId, &out->engine_id))
185     return false;
186   if (!dict.GetString(extensions::manifest_keys::kName, &out->display_name))
187     return false;
188
189   std::set<std::string> languages;
190   const base::Value* language_value = NULL;
191   if (dict.Get(extensions::manifest_keys::kLanguage, &language_value)) {
192     if (language_value->GetType() == base::Value::TYPE_STRING) {
193       std::string language_str;
194       language_value->GetAsString(&language_str);
195       languages.insert(language_str);
196     } else if (language_value->GetType() == base::Value::TYPE_LIST) {
197       const base::ListValue* language_list = NULL;
198       language_value->GetAsList(&language_list);
199       for (size_t j = 0; j < language_list->GetSize(); ++j) {
200         std::string language_str;
201         if (language_list->GetString(j, &language_str))
202           languages.insert(language_str);
203       }
204     }
205   }
206   DCHECK(!languages.empty());
207   out->language_codes.assign(languages.begin(), languages.end());
208
209   const ListValue* layouts = NULL;
210   if (!dict.GetList(extensions::manifest_keys::kLayouts, &layouts))
211     return false;
212
213   for (size_t i = 0; i < layouts->GetSize(); ++i) {
214     std::string buffer;
215     if (layouts->GetString(i, &buffer))
216       out->layouts.push_back(buffer);
217   }
218   return true;
219 }
220
221 // static
222 bool ComponentExtensionIMEManagerImpl::ReadExtensionInfo(
223     const DictionaryValue& manifest,
224     const std::string& extension_id,
225     ComponentExtensionIME* out) {
226   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
227   if (!manifest.GetString(extensions::manifest_keys::kDescription,
228                           &out->description))
229     return false;
230   std::string url_string;
231   if (!manifest.GetString(extensions::manifest_keys::kOptionsPage, &url_string))
232     return true;  // It's okay to return true on no option page case.
233
234   GURL url = extensions::Extension::GetResourceURL(
235       extensions::Extension::GetBaseURLFromExtensionId(extension_id),
236       url_string);
237   if (!url.is_valid())
238     return false;
239   out->options_page_url = url;
240   return true;
241 }
242
243 // static
244 void ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo(
245     std::vector<ComponentExtensionIME>* out_imes) {
246   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
247   DCHECK(out_imes);
248   for (size_t i = 0; i < arraysize(whitelisted_component_extension); ++i) {
249     ComponentExtensionIME component_ime;
250     component_ime.path = base::FilePath(
251         whitelisted_component_extension[i].path);
252
253     const base::FilePath manifest_path =
254         component_ime.path.Append("manifest.json");
255
256     if (!base::PathExists(component_ime.path) ||
257         !base::PathExists(manifest_path))
258       continue;
259
260     if (!base::ReadFileToString(manifest_path, &component_ime.manifest))
261       continue;
262
263     scoped_ptr<DictionaryValue> manifest = GetManifest(component_ime.path);
264     if (!manifest.get())
265       continue;
266
267     if (!ReadExtensionInfo(*manifest.get(),
268                            whitelisted_component_extension[i].id,
269                            &component_ime))
270       continue;
271     component_ime.id = whitelisted_component_extension[i].id;
272
273     const ListValue* component_list;
274     if (!manifest->GetList(extensions::manifest_keys::kInputComponents,
275                            &component_list))
276       continue;
277
278     for (size_t i = 0; i < component_list->GetSize(); ++i) {
279       const DictionaryValue* dictionary;
280       if (!component_list->GetDictionary(i, &dictionary))
281         continue;
282
283       ComponentExtensionEngine engine;
284       ReadEngineComponent(*dictionary, &engine);
285       component_ime.engines.push_back(engine);
286     }
287     out_imes->push_back(component_ime);
288   }
289 }
290
291 void ComponentExtensionIMEManagerImpl::OnReadComponentExtensionsInfo(
292     std::vector<ComponentExtensionIME>* result,
293     const base::Closure& callback) {
294   DCHECK(thread_checker_.CalledOnValidThread());
295   DCHECK(result);
296   component_extension_list_ = *result;
297   is_initialized_ = true;
298   callback.Run();
299 }
300
301 }  // namespace chromeos