Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: chrome/browser/extensions/api/input_ime/input_ime_api.cc

Issue 433163005: Refactoring for InputMethodEngine and InputMethodEventRouter. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: error tolerance for missing background page for key events. Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h" 5 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
6 6
7 #include "base/strings/string_number_conversions.h" 7 #include "base/strings/string_number_conversions.h"
8 #include "base/values.h" 8 #include "base/values.h"
9 #include "chrome/browser/chromeos/login/lock/screen_locker.h" 9 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
10 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h" 10 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
11 #include "chrome/browser/chromeos/login/users/user_manager.h" 11 #include "chrome/browser/chromeos/login/users/user_manager.h"
12 #include "chrome/browser/chromeos/profiles/profile_helper.h" 12 #include "chrome/browser/chromeos/profiles/profile_helper.h"
13 #include "chrome/browser/extensions/extension_service.h" 13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/profiles/profile_manager.h" 14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/common/extensions/api/input_ime.h" 15 #include "chrome/common/extensions/api/input_ime.h"
16 #include "chrome/common/extensions/api/input_ime/input_components_handler.h" 16 #include "chrome/common/extensions/api/input_ime/input_components_handler.h"
17 #include "chromeos/ime/component_extension_ime_manager.h"
18 #include "chromeos/ime/extension_ime_util.h"
19 #include "chromeos/ime/input_method_manager.h"
17 #include "extensions/browser/event_router.h" 20 #include "extensions/browser/event_router.h"
18 #include "extensions/browser/extension_function_registry.h" 21 #include "extensions/browser/extension_function_registry.h"
19 #include "extensions/browser/extension_registry.h" 22 #include "extensions/browser/extension_registry.h"
20 #include "extensions/browser/extension_system.h" 23 #include "extensions/browser/extension_system.h"
21 #include "extensions/common/manifest_handlers/background_info.h" 24 #include "extensions/common/manifest_handlers/background_info.h"
22 25
23 #if defined(USE_X11) 26 #if defined(USE_X11)
24 #include "chrome/browser/chromeos/input_method/input_method_engine.h" 27 #include "chrome/browser/chromeos/input_method/input_method_engine.h"
25 #endif 28 #endif
26 29
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 71
69 if (input.checked) 72 if (input.checked)
70 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_CHECKED; 73 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_CHECKED;
71 out->checked = input.checked ? *input.checked : false; 74 out->checked = input.checked ? *input.checked : false;
72 75
73 if (input.enabled) 76 if (input.enabled)
74 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_ENABLED; 77 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_ENABLED;
75 out->enabled = input.enabled ? *input.enabled : true; 78 out->enabled = input.enabled ? *input.enabled : true;
76 } 79 }
77 80
78 static void DispatchEventToExtension(Profile* profile, 81 static void DispatchEventToExtension(const std::string& extension_id,
79 const std::string& extension_id,
80 const std::string& event_name, 82 const std::string& event_name,
81 scoped_ptr<base::ListValue> args) { 83 scoped_ptr<base::ListValue> args) {
84 Profile* profile = ProfileManager::GetActiveUserProfile();
82 scoped_ptr<extensions::Event> event(new extensions::Event( 85 scoped_ptr<extensions::Event> event(new extensions::Event(
83 event_name, args.Pass())); 86 event_name, args.Pass()));
84 event->restrict_to_browser_context = profile; 87 event->restrict_to_browser_context = profile;
85 extensions::EventRouter::Get(profile) 88 extensions::EventRouter::Get(profile)
86 ->DispatchEventToExtension(extension_id, event.Pass()); 89 ->DispatchEventToExtension(extension_id, event.Pass());
87 } 90 }
88 91
89 void CallbackKeyEventHandle(chromeos::input_method::KeyEventHandle* key_data, 92 void CallbackKeyEventHandle(chromeos::input_method::KeyEventHandle* key_data,
90 bool handled) { 93 bool handled) {
91 base::Callback<void(bool consumed)>* callback = 94 base::Callback<void(bool consumed)>* callback =
92 reinterpret_cast<base::Callback<void(bool consumed)>*>(key_data); 95 reinterpret_cast<base::Callback<void(bool consumed)>*>(key_data);
93 callback->Run(handled); 96 callback->Run(handled);
94 delete callback; 97 delete callback;
95 } 98 }
96 99
97 } // namespace 100 } // namespace
98 101
99 namespace chromeos { 102 namespace chromeos {
100 class ImeObserver : public InputMethodEngineInterface::Observer { 103 class ImeObserver : public InputMethodEngineInterface::Observer {
101 public: 104 public:
102 ImeObserver(Profile* profile, const std::string& extension_id) 105 explicit ImeObserver(const std::string& extension_id)
103 : profile_(profile), extension_id_(extension_id), has_background_(false) { 106 : extension_id_(extension_id) {}
104 extensions::ExtensionSystem* extension_system =
105 extensions::ExtensionSystem::Get(profile_);
106 ExtensionService* extension_service = extension_system->extension_service();
107 const extensions::Extension* extension =
108 extension_service->GetExtensionById(extension_id, false);
109 DCHECK(extension);
110 extensions::BackgroundInfo* info = static_cast<extensions::BackgroundInfo*>(
111 extension->GetManifestData("background"));
112 if (info)
113 has_background_ = info->has_background_page();
114 }
115 107
116 virtual ~ImeObserver() {} 108 virtual ~ImeObserver() {}
117 109
118 virtual void OnActivate(const std::string& engine_id) OVERRIDE { 110 virtual void OnActivate(const std::string& component_id) OVERRIDE {
119 if (profile_ == NULL || extension_id_.empty()) 111 if (extension_id_.empty())
120 return;
121
122 scoped_ptr<base::ListValue> args(input_ime::OnActivate::Create(engine_id));
123
124 DispatchEventToExtension(profile_, extension_id_,
125 input_ime::OnActivate::kEventName, args.Pass());
126 }
127
128 virtual void OnDeactivated(const std::string& engine_id) OVERRIDE {
129 if (profile_ == NULL || extension_id_.empty())
130 return; 112 return;
131 113
132 scoped_ptr<base::ListValue> args( 114 scoped_ptr<base::ListValue> args(
133 input_ime::OnDeactivated::Create(engine_id)); 115 input_ime::OnActivate::Create(component_id));
134 116
135 DispatchEventToExtension(profile_, extension_id_, 117 DispatchEventToExtension(
136 input_ime::OnDeactivated::kEventName, args.Pass()); 118 extension_id_, input_ime::OnActivate::kEventName, args.Pass());
119 }
120
121 virtual void OnDeactivated(const std::string& component_id) OVERRIDE {
122 if (extension_id_.empty())
123 return;
124
125 scoped_ptr<base::ListValue> args(
126 input_ime::OnDeactivated::Create(component_id));
127
128 DispatchEventToExtension(
129 extension_id_, input_ime::OnDeactivated::kEventName, args.Pass());
137 } 130 }
138 131
139 virtual void OnFocus( 132 virtual void OnFocus(
140 const InputMethodEngineInterface::InputContext& context) OVERRIDE { 133 const InputMethodEngineInterface::InputContext& context) OVERRIDE {
141 if (profile_ == NULL || extension_id_.empty()) 134 if (extension_id_.empty())
142 return; 135 return;
143 136
144 input_ime::InputContext context_value; 137 input_ime::InputContext context_value;
145 context_value.context_id = context.id; 138 context_value.context_id = context.id;
146 context_value.type = input_ime::InputContext::ParseType(context.type); 139 context_value.type = input_ime::InputContext::ParseType(context.type);
147 140
148 scoped_ptr<base::ListValue> args(input_ime::OnFocus::Create(context_value)); 141 scoped_ptr<base::ListValue> args(input_ime::OnFocus::Create(context_value));
149 142
150 // The component IME extensions need to know the current screen type (e.g. 143 // The component IME extensions need to know the current screen type (e.g.
151 // lock screen, login screen, etc.) so that its on-screen keyboard page 144 // lock screen, login screen, etc.) so that its on-screen keyboard page
152 // won't open new windows/pages. See crbug.com/395621. 145 // won't open new windows/pages. See crbug.com/395621.
153 base::DictionaryValue* val = NULL; 146 base::DictionaryValue* val = NULL;
154 if (args->GetDictionary(0, &val)) { 147 if (args->GetDictionary(0, &val)) {
155 std::string screen_type; 148 std::string screen_type;
156 if (!UserManager::Get()->IsUserLoggedIn()) { 149 if (!UserManager::Get()->IsUserLoggedIn()) {
157 screen_type = "login"; 150 screen_type = "login";
158 } else if (chromeos::ScreenLocker::default_screen_locker() && 151 } else if (chromeos::ScreenLocker::default_screen_locker() &&
159 chromeos::ScreenLocker::default_screen_locker()->locked()) { 152 chromeos::ScreenLocker::default_screen_locker()->locked()) {
160 screen_type = "lock"; 153 screen_type = "lock";
161 } else if (UserAddingScreen::Get()->IsRunning()) { 154 } else if (UserAddingScreen::Get()->IsRunning()) {
162 screen_type = "secondary-login"; 155 screen_type = "secondary-login";
163 } 156 }
164 if (!screen_type.empty()) 157 if (!screen_type.empty())
165 val->SetStringWithoutPathExpansion("screen", screen_type); 158 val->SetStringWithoutPathExpansion("screen", screen_type);
166 } 159 }
167 160
168 DispatchEventToExtension(profile_, extension_id_, 161 DispatchEventToExtension(
169 input_ime::OnFocus::kEventName, args.Pass()); 162 extension_id_, input_ime::OnFocus::kEventName, args.Pass());
170 } 163 }
171 164
172 virtual void OnBlur(int context_id) OVERRIDE { 165 virtual void OnBlur(int context_id) OVERRIDE {
173 if (profile_ == NULL || extension_id_.empty()) 166 if (extension_id_.empty())
174 return; 167 return;
175 168
176 scoped_ptr<base::ListValue> args(input_ime::OnBlur::Create(context_id)); 169 scoped_ptr<base::ListValue> args(input_ime::OnBlur::Create(context_id));
177 170
178 DispatchEventToExtension(profile_, extension_id_, 171 DispatchEventToExtension(
179 input_ime::OnBlur::kEventName, args.Pass()); 172 extension_id_, input_ime::OnBlur::kEventName, args.Pass());
180 } 173 }
181 174
182 virtual void OnInputContextUpdate( 175 virtual void OnInputContextUpdate(
183 const InputMethodEngineInterface::InputContext& context) OVERRIDE { 176 const InputMethodEngineInterface::InputContext& context) OVERRIDE {
184 if (profile_ == NULL || extension_id_.empty()) 177 if (extension_id_.empty())
185 return; 178 return;
186 179
187 input_ime::InputContext context_value; 180 input_ime::InputContext context_value;
188 context_value.context_id = context.id; 181 context_value.context_id = context.id;
189 context_value.type = input_ime::InputContext::ParseType(context.type); 182 context_value.type = input_ime::InputContext::ParseType(context.type);
190 183
191 scoped_ptr<base::ListValue> args( 184 scoped_ptr<base::ListValue> args(
192 input_ime::OnInputContextUpdate::Create(context_value)); 185 input_ime::OnInputContextUpdate::Create(context_value));
193 186
194 DispatchEventToExtension(profile_, 187 DispatchEventToExtension(extension_id_,
195 extension_id_,
196 input_ime::OnInputContextUpdate::kEventName, 188 input_ime::OnInputContextUpdate::kEventName,
197 args.Pass()); 189 args.Pass());
198 } 190 }
199 191
200 virtual void OnKeyEvent( 192 virtual void OnKeyEvent(
201 const std::string& engine_id, 193 const std::string& component_id,
202 const InputMethodEngineInterface::KeyboardEvent& event, 194 const InputMethodEngineInterface::KeyboardEvent& event,
203 chromeos::input_method::KeyEventHandle* key_data) OVERRIDE { 195 chromeos::input_method::KeyEventHandle* key_data) OVERRIDE {
204 if (profile_ == NULL || extension_id_.empty()) 196 if (extension_id_.empty())
205 return; 197 return;
206 198
207 // If there is no listener for the event, no need to dispatch the event to 199 // If there is no listener for the event, no need to dispatch the event to
208 // extension. Instead, releases the key event for default system behavior. 200 // extension. Instead, releases the key event for default system behavior.
209 if (!ShouldForwardKeyEvent()) { 201 if (!ShouldForwardKeyEvent()) {
210 // Continue processing the key event so that the physical keyboard can 202 // Continue processing the key event so that the physical keyboard can
211 // still work. 203 // still work.
212 CallbackKeyEventHandle(key_data, false); 204 CallbackKeyEventHandle(key_data, false);
213 return; 205 return;
214 } 206 }
215 207
216 extensions::InputImeEventRouter* ime_event_router = 208 extensions::InputImeEventRouter* ime_event_router =
217 extensions::InputImeEventRouter::GetInstance(); 209 extensions::InputImeEventRouter::GetInstance();
218 210
219 const std::string request_id = 211 const std::string request_id =
220 ime_event_router->AddRequest(engine_id, key_data); 212 ime_event_router->AddRequest(component_id, key_data);
221 213
222 input_ime::KeyboardEvent key_data_value; 214 input_ime::KeyboardEvent key_data_value;
223 key_data_value.type = input_ime::KeyboardEvent::ParseType(event.type); 215 key_data_value.type = input_ime::KeyboardEvent::ParseType(event.type);
224 key_data_value.request_id = request_id; 216 key_data_value.request_id = request_id;
225 if (!event.extension_id.empty()) 217 if (!event.extension_id.empty())
226 key_data_value.extension_id.reset(new std::string(event.extension_id)); 218 key_data_value.extension_id.reset(new std::string(event.extension_id));
227 key_data_value.key = event.key; 219 key_data_value.key = event.key;
228 key_data_value.code = event.code; 220 key_data_value.code = event.code;
229 key_data_value.alt_key.reset(new bool(event.alt_key)); 221 key_data_value.alt_key.reset(new bool(event.alt_key));
230 key_data_value.ctrl_key.reset(new bool(event.ctrl_key)); 222 key_data_value.ctrl_key.reset(new bool(event.ctrl_key));
231 key_data_value.shift_key.reset(new bool(event.shift_key)); 223 key_data_value.shift_key.reset(new bool(event.shift_key));
232 key_data_value.caps_lock.reset(new bool(event.caps_lock)); 224 key_data_value.caps_lock.reset(new bool(event.caps_lock));
233 225
234 scoped_ptr<base::ListValue> args( 226 scoped_ptr<base::ListValue> args(
235 input_ime::OnKeyEvent::Create(engine_id, key_data_value)); 227 input_ime::OnKeyEvent::Create(component_id, key_data_value));
236 228
237 DispatchEventToExtension(profile_, extension_id_, 229 DispatchEventToExtension(
238 input_ime::OnKeyEvent::kEventName, args.Pass()); 230 extension_id_, input_ime::OnKeyEvent::kEventName, args.Pass());
239 } 231 }
240 232
241 virtual void OnCandidateClicked( 233 virtual void OnCandidateClicked(
242 const std::string& engine_id, 234 const std::string& component_id,
243 int candidate_id, 235 int candidate_id,
244 InputMethodEngineInterface::MouseButtonEvent button) OVERRIDE { 236 InputMethodEngineInterface::MouseButtonEvent button) OVERRIDE {
245 if (profile_ == NULL || extension_id_.empty()) 237 if (extension_id_.empty())
246 return; 238 return;
247 239
248 input_ime::OnCandidateClicked::Button button_enum = 240 input_ime::OnCandidateClicked::Button button_enum =
249 input_ime::OnCandidateClicked::BUTTON_NONE; 241 input_ime::OnCandidateClicked::BUTTON_NONE;
250 switch (button) { 242 switch (button) {
251 case InputMethodEngineInterface::MOUSE_BUTTON_MIDDLE: 243 case InputMethodEngineInterface::MOUSE_BUTTON_MIDDLE:
252 button_enum = input_ime::OnCandidateClicked::BUTTON_MIDDLE; 244 button_enum = input_ime::OnCandidateClicked::BUTTON_MIDDLE;
253 break; 245 break;
254 246
255 case InputMethodEngineInterface::MOUSE_BUTTON_RIGHT: 247 case InputMethodEngineInterface::MOUSE_BUTTON_RIGHT:
256 button_enum = input_ime::OnCandidateClicked::BUTTON_RIGHT; 248 button_enum = input_ime::OnCandidateClicked::BUTTON_RIGHT;
257 break; 249 break;
258 250
259 case InputMethodEngineInterface::MOUSE_BUTTON_LEFT: 251 case InputMethodEngineInterface::MOUSE_BUTTON_LEFT:
260 // Default to left. 252 // Default to left.
261 default: 253 default:
262 button_enum = input_ime::OnCandidateClicked::BUTTON_LEFT; 254 button_enum = input_ime::OnCandidateClicked::BUTTON_LEFT;
263 break; 255 break;
264 } 256 }
265 257
266 scoped_ptr<base::ListValue> args( 258 scoped_ptr<base::ListValue> args(input_ime::OnCandidateClicked::Create(
267 input_ime::OnCandidateClicked::Create(engine_id, 259 component_id, candidate_id, button_enum));
268 candidate_id,
269 button_enum));
270 260
271 DispatchEventToExtension(profile_, 261 DispatchEventToExtension(
272 extension_id_, 262 extension_id_, input_ime::OnCandidateClicked::kEventName, args.Pass());
273 input_ime::OnCandidateClicked::kEventName,
274 args.Pass());
275 } 263 }
276 264
277 virtual void OnMenuItemActivated(const std::string& engine_id, 265 virtual void OnMenuItemActivated(const std::string& component_id,
278 const std::string& menu_id) OVERRIDE { 266 const std::string& menu_id) OVERRIDE {
279 if (profile_ == NULL || extension_id_.empty()) 267 if (extension_id_.empty())
280 return; 268 return;
281 269
282 scoped_ptr<base::ListValue> args( 270 scoped_ptr<base::ListValue> args(
283 input_ime::OnMenuItemActivated::Create(engine_id, menu_id)); 271 input_ime::OnMenuItemActivated::Create(component_id, menu_id));
284 272
285 DispatchEventToExtension(profile_, 273 DispatchEventToExtension(
286 extension_id_, 274 extension_id_, input_ime::OnMenuItemActivated::kEventName, args.Pass());
287 input_ime::OnMenuItemActivated::kEventName,
288 args.Pass());
289 } 275 }
290 276
291 virtual void OnSurroundingTextChanged(const std::string& engine_id, 277 virtual void OnSurroundingTextChanged(const std::string& component_id,
292 const std::string& text, 278 const std::string& text,
293 int cursor_pos, 279 int cursor_pos,
294 int anchor_pos) OVERRIDE { 280 int anchor_pos) OVERRIDE {
295 if (profile_ == NULL || extension_id_.empty()) 281 if (extension_id_.empty())
296 return; 282 return;
297 283
298 input_ime::OnSurroundingTextChanged::SurroundingInfo info; 284 input_ime::OnSurroundingTextChanged::SurroundingInfo info;
299 info.text = text; 285 info.text = text;
300 info.focus = cursor_pos; 286 info.focus = cursor_pos;
301 info.anchor = anchor_pos; 287 info.anchor = anchor_pos;
302 scoped_ptr<base::ListValue> args( 288 scoped_ptr<base::ListValue> args(
303 input_ime::OnSurroundingTextChanged::Create(engine_id, info)); 289 input_ime::OnSurroundingTextChanged::Create(component_id, info));
304 290
305 DispatchEventToExtension(profile_, 291 DispatchEventToExtension(extension_id_,
306 extension_id_,
307 input_ime::OnSurroundingTextChanged::kEventName, 292 input_ime::OnSurroundingTextChanged::kEventName,
308 args.Pass()); 293 args.Pass());
309 } 294 }
310 295
311 virtual void OnReset(const std::string& engine_id) OVERRIDE { 296 virtual void OnReset(const std::string& component_id) OVERRIDE {
312 if (profile_ == NULL || extension_id_.empty()) 297 if (extension_id_.empty())
313 return; 298 return;
314 299
315 scoped_ptr<base::ListValue> args(input_ime::OnReset::Create(engine_id)); 300 scoped_ptr<base::ListValue> args(input_ime::OnReset::Create(component_id));
316 301
317 DispatchEventToExtension(profile_, 302 DispatchEventToExtension(
318 extension_id_, 303 extension_id_, input_ime::OnReset::kEventName, args.Pass());
319 input_ime::OnReset::kEventName,
320 args.Pass());
321 } 304 }
322 305
323 private: 306 private:
324 // Returns true if the extension is ready to accept key event, otherwise 307 // Returns true if the extension is ready to accept key event, otherwise
325 // returns false. 308 // returns false.
326 bool ShouldForwardKeyEvent() const { 309 bool ShouldForwardKeyEvent() const {
327 // Need to check the background page first since the 310 // Only forward key events to extension if there are non-lazy listeners
328 // ExtensionHasEventListner returns true if the extension does not have a 311 // for onKeyEvent. Because if something wrong with the lazy background
329 // background page. See crbug.com/394682. 312 // page which doesn't register listener for onKeyEvent, it will not handle
330 return has_background_ && extensions::EventRouter::Get(profile_) 313 // the key events, and therefore, all key events will be eaten.
331 ->ExtensionHasEventListener(extension_id_, 314 // This is for error-tolerance, and it means that onKeyEvent will never wake
332 input_ime::OnKeyEvent::kEventName); 315 // up lazy background page.
316 const extensions::EventListenerMap::ListenerList& listener_list =
317 extensions::EventRouter::Get(ProfileManager::GetActiveUserProfile())
318 ->listeners().GetEventListenersByName(
319 input_ime::OnKeyEvent::kEventName);
320 for (extensions::EventListenerMap::ListenerList::const_iterator it =
321 listener_list.begin();
322 it != listener_list.end(); it++) {
Yuki 2014/08/06 04:42:24 s/it++/++it/ for iterators. it++ may be slower tha
Shu Chen 2014/08/06 05:45:03 Done.
323 if ((*it)->extension_id() == extension_id_ && !(*it)->IsLazy())
324 return true;
325 }
326 return false;
333 } 327 }
334 328
335 Profile* profile_;
336 std::string extension_id_; 329 std::string extension_id_;
337 bool has_background_;
338 330
339 DISALLOW_COPY_AND_ASSIGN(ImeObserver); 331 DISALLOW_COPY_AND_ASSIGN(ImeObserver);
340 }; 332 };
341 333
342 } // namespace chromeos 334 } // namespace chromeos
343 335
344 namespace extensions { 336 namespace extensions {
345 337
346 InputImeEventRouter* 338 InputImeEventRouter*
347 InputImeEventRouter::GetInstance() { 339 InputImeEventRouter::GetInstance() {
348 return Singleton<InputImeEventRouter>::get(); 340 return Singleton<InputImeEventRouter>::get();
349 } 341 }
350 342
351 bool InputImeEventRouter::RegisterIme( 343 bool InputImeEventRouter::RegisterImeExtension(
352 Profile* profile,
353 const std::string& extension_id, 344 const std::string& extension_id,
354 const extensions::InputComponentInfo& component) { 345 const std::vector<extensions::InputComponentInfo>& input_components) {
355 #if defined(USE_X11) 346 #if defined(USE_X11)
356 VLOG(1) << "RegisterIme: " << extension_id << " id: " << component.id; 347 VLOG(1) << "RegisterImeExtension: " << extension_id;
357 348
358 // Avoid potential mem leaks due to duplicated component IDs. 349 if (engine_map_[extension_id])
359 if (!profile_engine_map_[profile][extension_id][component.id]) { 350 return false;
360 std::vector<std::string> layouts;
361 layouts.assign(component.layouts.begin(), component.layouts.end());
362 351
363 std::vector<std::string> languages; 352 chromeos::input_method::InputMethodManager* manager =
364 languages.assign(component.languages.begin(), component.languages.end()); 353 chromeos::input_method::InputMethodManager::Get();
354 chromeos::ComponentExtensionIMEManager* comp_ext_ime_manager =
355 manager->GetComponentExtensionIMEManager();
365 356
366 // Ideally Observer should be per (extension_id + Profile), and multiple 357 chromeos::input_method::InputMethodDescriptors descriptors;
367 // InputMethodEngine can share one Observer. But it would become tricky 358 // Only creates descriptors for 3rd party IME extension, because the
368 // to maintain an internal map for observers which does nearly nothing 359 // descriptors for component IME extensions are managed by InputMethodUtil.
369 // but just make sure they can properly deleted. 360 if (!comp_ext_ime_manager->IsWhitelistedExtension(extension_id)) {
370 // Making Obesrver per InputMethodEngine can make things cleaner. 361 for (std::vector<extensions::InputComponentInfo>::const_iterator it =
371 scoped_ptr<chromeos::InputMethodEngineInterface::Observer> observer( 362 input_components.begin();
372 new chromeos::ImeObserver(profile, extension_id)); 363 it != input_components.end();
373 chromeos::InputMethodEngine* engine = new chromeos::InputMethodEngine(); 364 ++it) {
374 engine->Initialize(profile, 365 const extensions::InputComponentInfo& component = *it;
375 observer.Pass(), 366 DCHECK(component.type == extensions::INPUT_COMPONENT_TYPE_IME);
376 component.name.c_str(), 367
377 extension_id.c_str(), 368 std::vector<std::string> layouts;
378 component.id.c_str(), 369 layouts.assign(component.layouts.begin(), component.layouts.end());
379 languages, 370 std::vector<std::string> languages;
380 layouts, 371 languages.assign(component.languages.begin(), component.languages.end());
381 component.options_page_url, 372
382 component.input_view_url); 373 const std::string& input_method_id =
383 profile_engine_map_[profile][extension_id][component.id] = engine; 374 chromeos::extension_ime_util::GetInputMethodID(extension_id,
375 component.id);
376 descriptors.push_back(chromeos::input_method::InputMethodDescriptor(
377 input_method_id,
378 component.name,
379 std::string(), // TODO(uekawa): Set short name.
380 layouts,
381 languages,
382 false, // 3rd party IMEs are always not for login.
383 component.options_page_url,
384 component.input_view_url));
385 }
384 } 386 }
385 387
388 scoped_ptr<chromeos::InputMethodEngineInterface::Observer> observer(
389 new chromeos::ImeObserver(extension_id));
390 chromeos::InputMethodEngine* engine = new chromeos::InputMethodEngine();
391 engine->Initialize(observer.Pass(), extension_id.c_str());
392 engine_map_[extension_id] = engine;
393 manager->AddInputMethodExtension(extension_id, descriptors, engine);
394
386 return true; 395 return true;
387 #else 396 #else
388 // TODO(spang): IME support under ozone. 397 // TODO(spang): IME support under ozone.
389 NOTIMPLEMENTED(); 398 NOTIMPLEMENTED();
390 return false; 399 return false;
391 #endif 400 #endif
392 } 401 }
393 402
394 void InputImeEventRouter::UnregisterAllImes(const std::string& extension_id) { 403 void InputImeEventRouter::UnregisterAllImes(const std::string& extension_id) {
395 Profile* profile = ProfileManager::GetActiveUserProfile(); 404 std::map<std::string, InputMethodEngineInterface*>::iterator it =
396 ProfileEngineMap::iterator extension_map = 405 engine_map_.find(extension_id);
397 profile_engine_map_.find(profile); 406 if (it != engine_map_.end()) {
398 if (extension_map == profile_engine_map_.end()) 407 chromeos::input_method::InputMethodManager::Get()
399 return; 408 ->RemoveInputMethodExtension(extension_id);
400 ExtensionMap::iterator engine_map = extension_map->second.find(extension_id); 409 delete it->second;
401 if (engine_map == extension_map->second.end()) 410 engine_map_.erase(it);
402 return; 411 }
403 STLDeleteContainerPairSecondPointers(engine_map->second.begin(),
404 engine_map->second.end());
405 extension_map->second.erase(extension_id);
406 profile_engine_map_.erase(profile);
407 } 412 }
408 413
409 InputMethodEngineInterface* InputImeEventRouter::GetEngine( 414 InputMethodEngineInterface* InputImeEventRouter::GetEngine(
410 const std::string& extension_id, const std::string& engine_id) { 415 const std::string& extension_id,
411 // IME can only work on active user profile. 416 const std::string& component_id) {
412 Profile* profile = ProfileManager::GetActiveUserProfile(); 417 std::map<std::string, InputMethodEngineInterface*>::iterator it =
413 418 engine_map_.find(extension_id);
414 ProfileEngineMap::const_iterator extension_map = 419 if (it != engine_map_.end() &&
415 profile_engine_map_.find(profile); 420 it->second->GetActiveComponentId() == component_id)
416 if (extension_map == profile_engine_map_.end()) 421 return it->second;
417 return NULL; 422 return NULL;
418 ExtensionMap::const_iterator engine_map =
419 extension_map->second.find(extension_id);
420 if (engine_map == extension_map->second.end())
421 return NULL;
422 EngineMap::const_iterator engine = engine_map->second.find(engine_id);
423 if (engine == engine_map->second.end())
424 return NULL;
425 return engine->second;
426 } 423 }
427 424
428 InputMethodEngineInterface* InputImeEventRouter::GetActiveEngine( 425 InputMethodEngineInterface* InputImeEventRouter::GetActiveEngine(
429 const std::string& extension_id) { 426 const std::string& extension_id) {
430 // IME can only work on active user profile. 427 std::map<std::string, InputMethodEngineInterface*>::iterator it =
431 Profile* profile = ProfileManager::GetActiveUserProfile(); 428 engine_map_.find(extension_id);
432 429 if (it != engine_map_.end() && it->second->IsActive())
433 ProfileEngineMap::const_iterator extension_map = 430 return it->second;
434 profile_engine_map_.find(profile);
435 if (extension_map == profile_engine_map_.end())
436 return NULL;
437 ExtensionMap::const_iterator engine_map =
438 extension_map->second.find(extension_id);
439 if (engine_map == extension_map->second.end())
440 return NULL;
441
442 for (EngineMap::const_iterator i = engine_map->second.begin();
443 i != engine_map->second.end();
444 ++i) {
445 if (i->second->IsActive())
446 return i->second;
447 }
448 return NULL; 431 return NULL;
449 } 432 }
450 433
451 void InputImeEventRouter::OnKeyEventHandled( 434 void InputImeEventRouter::OnKeyEventHandled(
452 const std::string& extension_id, 435 const std::string& extension_id,
453 const std::string& request_id, 436 const std::string& request_id,
454 bool handled) { 437 bool handled) {
455 RequestMap::iterator request = request_map_.find(request_id); 438 RequestMap::iterator request = request_map_.find(request_id);
456 if (request == request_map_.end()) { 439 if (request == request_map_.end()) {
457 LOG(ERROR) << "Request ID not found: " << request_id; 440 LOG(ERROR) << "Request ID not found: " << request_id;
458 return; 441 return;
459 } 442 }
460 443
461 std::string engine_id = request->second.first; 444 std::string component_id = request->second.first;
462 chromeos::input_method::KeyEventHandle* key_data = request->second.second; 445 chromeos::input_method::KeyEventHandle* key_data = request->second.second;
463 request_map_.erase(request); 446 request_map_.erase(request);
464 447
465 CallbackKeyEventHandle(key_data, handled); 448 CallbackKeyEventHandle(key_data, handled);
466 } 449 }
467 450
468 std::string InputImeEventRouter::AddRequest( 451 std::string InputImeEventRouter::AddRequest(
469 const std::string& engine_id, 452 const std::string& component_id,
470 chromeos::input_method::KeyEventHandle* key_data) { 453 chromeos::input_method::KeyEventHandle* key_data) {
471 std::string request_id = base::IntToString(next_request_id_); 454 std::string request_id = base::IntToString(next_request_id_);
472 ++next_request_id_; 455 ++next_request_id_;
473 456
474 request_map_[request_id] = std::make_pair(engine_id, key_data); 457 request_map_[request_id] = std::make_pair(component_id, key_data);
475 458
476 return request_id; 459 return request_id;
477 } 460 }
478 461
479 InputImeEventRouter::InputImeEventRouter() 462 InputImeEventRouter::InputImeEventRouter()
480 : next_request_id_(1) { 463 : next_request_id_(1) {
481 } 464 }
482 465
483 InputImeEventRouter::~InputImeEventRouter() {} 466 InputImeEventRouter::~InputImeEventRouter() {}
484 467
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after
821 InputImeEventRouter::GetInstance()->OnKeyEventHandled( 804 InputImeEventRouter::GetInstance()->OnKeyEventHandled(
822 extension_id(), params->request_id, params->response); 805 extension_id(), params->request_id, params->response);
823 return true; 806 return true;
824 } 807 }
825 808
826 InputImeAPI::InputImeAPI(content::BrowserContext* context) 809 InputImeAPI::InputImeAPI(content::BrowserContext* context)
827 : browser_context_(context), extension_registry_observer_(this) { 810 : browser_context_(context), extension_registry_observer_(this) {
828 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); 811 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
829 812
830 EventRouter* event_router = EventRouter::Get(browser_context_); 813 EventRouter* event_router = EventRouter::Get(browser_context_);
831 event_router->RegisterObserver(this, input_ime::OnActivate::kEventName);
832 event_router->RegisterObserver(this, input_ime::OnFocus::kEventName); 814 event_router->RegisterObserver(this, input_ime::OnFocus::kEventName);
833 } 815 }
834 816
835 InputImeAPI::~InputImeAPI() { 817 InputImeAPI::~InputImeAPI() {
836 EventRouter::Get(browser_context_)->UnregisterObserver(this); 818 EventRouter::Get(browser_context_)->UnregisterObserver(this);
837 } 819 }
838 820
839 static base::LazyInstance<BrowserContextKeyedAPIFactory<InputImeAPI> > 821 static base::LazyInstance<BrowserContextKeyedAPIFactory<InputImeAPI> >
840 g_factory = LAZY_INSTANCE_INITIALIZER; 822 g_factory = LAZY_INSTANCE_INITIALIZER;
841 823
842 // static 824 // static
843 BrowserContextKeyedAPIFactory<InputImeAPI>* InputImeAPI::GetFactoryInstance() { 825 BrowserContextKeyedAPIFactory<InputImeAPI>* InputImeAPI::GetFactoryInstance() {
844 return g_factory.Pointer(); 826 return g_factory.Pointer();
845 } 827 }
846 828
847 void InputImeAPI::OnExtensionLoaded(content::BrowserContext* browser_context, 829 void InputImeAPI::OnExtensionLoaded(content::BrowserContext* browser_context,
848 const Extension* extension) { 830 const Extension* extension) {
849 const std::vector<InputComponentInfo>* input_components = 831 const std::vector<InputComponentInfo>* input_components =
850 extensions::InputComponents::GetInputComponents(extension); 832 extensions::InputComponents::GetInputComponents(extension);
851 if (!input_components) 833 if (input_components)
852 return; 834 input_ime_event_router()->RegisterImeExtension(extension->id(),
853 for (std::vector<extensions::InputComponentInfo>::const_iterator component = 835 *input_components);
854 input_components->begin();
855 component != input_components->end();
856 ++component) {
857 if (component->type == extensions::INPUT_COMPONENT_TYPE_IME) {
858 // If |browser_context| looks like signin profile, use the real signin
859 // profile. This is because IME extensions for signin profile are run
860 // in Off-The-Record profile, based on given static defaults.
861 // So if |profile_| is signin profile, we need to make sure
862 // the router/observer runs under its incognito profile, because the
863 // component extensions were installed under its incognito profile.
864 Profile* profile = Profile::FromBrowserContext(browser_context);
865 if (chromeos::ProfileHelper::IsSigninProfile(profile))
866 profile = chromeos::ProfileHelper::GetSigninProfile();
867 input_ime_event_router()->RegisterIme(
868 profile, extension->id(), *component);
869 }
870 }
871 } 836 }
872 837
873 void InputImeAPI::OnExtensionUnloaded(content::BrowserContext* browser_context, 838 void InputImeAPI::OnExtensionUnloaded(content::BrowserContext* browser_context,
874 const Extension* extension, 839 const Extension* extension,
875 UnloadedExtensionInfo::Reason reason) { 840 UnloadedExtensionInfo::Reason reason) {
876 const std::vector<InputComponentInfo>* input_components = 841 const std::vector<InputComponentInfo>* input_components =
877 extensions::InputComponents::GetInputComponents(extension); 842 extensions::InputComponents::GetInputComponents(extension);
878 if (!input_components) 843 if (!input_components)
879 return; 844 return;
880 if (input_components->size() > 0) 845 if (input_components->size() > 0)
881 input_ime_event_router()->UnregisterAllImes(extension->id()); 846 input_ime_event_router()->UnregisterAllImes(extension->id());
882 } 847 }
883 848
884 void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) { 849 void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) {
885 InputMethodEngineInterface* engine = 850 InputMethodEngineInterface* engine =
886 input_ime_event_router()->GetActiveEngine(details.extension_id); 851 input_ime_event_router()->GetActiveEngine(details.extension_id);
852 // Notifies the IME extension for IME ready with onActivate/onFocus events.
887 if (engine) 853 if (engine)
888 engine->NotifyImeReady(); 854 engine->Enable(engine->GetActiveComponentId());
889 } 855 }
890 856
891 InputImeEventRouter* InputImeAPI::input_ime_event_router() { 857 InputImeEventRouter* InputImeAPI::input_ime_event_router() {
892 return InputImeEventRouter::GetInstance(); 858 return InputImeEventRouter::GetInstance();
893 } 859 }
894 860
895 } // namespace extensions 861 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698