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

Side by Side Diff: webkit/plugins/npapi/webplugin_ime_win.cc

Issue 7082034: Send IME events to windowless plug-ins (Chromium side) (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 6 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 | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "webkit/plugins/npapi/webplugin_ime_win.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "app/win/iat_patch_function.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/synchronization/lock.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
15 #include "webkit/plugins/npapi/plugin_constants_win.h"
16 #include "webkit/plugins/npapi/plugin_instance.h"
17
18 #pragma comment(lib, "imm32.lib")
19
20 using WebKit::WebInputEvent;
21 using WebKit::WebCompositionEvent;
22
23 namespace webkit {
24 namespace npapi {
25
26 // A critical section that prevents two or more plug-ins from accessing a
27 // WebPluginIMEWin instance through our patch function.
28 base::LazyInstance<base::Lock> g_webplugin_ime_lock(base::LINKER_INITIALIZED);
29
30 WebPluginIMEWin* WebPluginIMEWin::instance_ = NULL;
31
32 WebPluginIMEWin::WebPluginIMEWin()
33 : cursor_position_(0),
34 delta_start_(0),
35 composing_text_(false),
36 support_ime_messages_(false),
37 status_updated_(false),
38 input_type_(1) {
39 }
40
41 WebPluginIMEWin::~WebPluginIMEWin() {
42 }
43
44 void WebPluginIMEWin::Update(const WebInputEvent* event) {
45 if (!WebInputEvent::isCompositionEventType(event->type))
46 return;
47
48 const WebCompositionEvent* e =
49 static_cast<const WebCompositionEvent*>(event);
50
51 NPEvent np_event;
52 if (e->type == WebInputEvent::RawCompositionSet) {
53 // We need to send a WM_IME_STARTCOMPOSITION message when a user starts an
54 // IME composition.
55 if (!composing_text_) {
56 composing_text_ = true;
57 result_text_.clear();
58
59 np_event.event = WM_IME_STARTCOMPOSITION;
60 np_event.wParam = 0;
61 np_event.lParam = 0;
62 events_.push_back(np_event);
63 }
64
cpu_(ooo_6.6-7.5) 2011/06/10 18:38:06 I worry that Justin's new UIPI sandbox hardening h
jschuh 2011/06/11 17:31:50 Yeah, this definitely needs to be tested against t
Hironori Bono 2011/06/13 09:51:09 Thank you for your comments. This change sends the
65 // We can update the following values from a RawCompositionSet event:
66 // GCS_COMPSTR, GCS_COMPATTR, GCSCOMPCLAUSE, GCS_CURSORPOS, and
67 // GCS_DELTASTART. We send a WM_IME_COMPOSITION message to notify the list
68 // of updated values.
69 np_event.event = WM_IME_COMPOSITION;
70 np_event.wParam = 0;
71 np_event.lParam = GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE |
72 GCS_CURSORPOS | GCS_DELTASTART;
73 events_.push_back(np_event);
74
75 // Converts the given WebCompositionEvent to the platform-dependent IME
76 // data. (See the comment in the WebPluginCompositionData object above for
77 // the parameters.)
78 composition_text_.assign(e->text, e->textLength);
79
80 // Create the composition clauses returned when a plug-in calls
81 // ImmGetCompositionString() with GCS_COMPCLAUSE.
82 composition_clauses_.clear();
83 const WebKit::WebCompositionUnderline* target = NULL;
84 for (int i = 0; i < e->underlineSize; ++i) {
85 const WebKit::WebCompositionUnderline* underline = &e->underlines[i];
86 composition_clauses_.push_back(underline->startOffset);
87 composition_clauses_.push_back(underline->endOffset);
88 if (underline->thick)
89 target = underline;
90 }
91
92 // Create the composition attributes used by GCS_COMPATTR.
93 if (target) {
94 composition_attributes_.assign(e->textLength, ATTR_CONVERTED);
95 for (unsigned int i = target->startOffset; i < target->endOffset; ++i)
96 composition_attributes_[i] = ATTR_TARGET_CONVERTED;
97 } else {
98 composition_attributes_.assign(e->textLength, ATTR_INPUT);
99 }
100
101 cursor_position_ = e->selectionEnd;
102 delta_start_ = e->selectionEnd;
103 } else if (e->type == WebInputEvent::RawCompositionConfirm) {
104 composing_text_ = false;
105
106 // We can update the following values from a RawCompositionConfirm event:
107 // GCS_RESULTSTR, GCS_RESULTCLAUSE, GCS_CURSORPOS, and GCS_DELTASTART. We
108 // send a WM_IME_COMPOSITION message to notify the list of updated values.
109 np_event.event = WM_IME_COMPOSITION;
110 np_event.wParam = 0;
111 np_event.lParam = GCS_CURSORPOS | GCS_DELTASTART | GCS_RESULTSTR |
112 GCS_RESULTCLAUSE;
113 events_.push_back(np_event);
114
115 // We also send a WM_IME_ENDCOMPOSITION message after the final
116 // WM_IME_COMPOSITION message (i.e. after finishing a composition).
117 np_event.event = WM_IME_ENDCOMPOSITION;
118 np_event.wParam = 0;
119 np_event.lParam = 0;
120 events_.push_back(np_event);
121
122 // If the target plug-in does not seem to support IME messages, we send
123 // each character in IME text with a WM_CHAR message so the plug-in can
124 // insert the IME text.
125 if (!support_ime_messages_) {
126 np_event.event = WM_CHAR;
127 np_event.wParam = 0;
128 np_event.lParam = 0;
129 for (size_t i = 0; i < result_text_.length(); ++i) {
130 np_event.wParam = result_text_[i];
131 events_.push_back(np_event);
132 }
133 }
134
135 // Updated the result text and its clause.
136 result_text_.assign(e->text, e->textLength);
137
138 result_clauses_[0] = 0;
139 result_clauses_[0] = e->textLength;
140
141 cursor_position_ = e->selectionEnd;
142 delta_start_ = e->selectionEnd;
143 } else {
144 NOTREACHED();
145 }
146 }
147
148 bool WebPluginIMEWin::SendEvents(PluginInstance* instance) {
149 // We allow the patch functions to access this WebPluginIMEWin instance only
150 // while we send IME events to the plug-in.
151 ScopedLock lock(this);
152
153 bool ret = true;
154 for (std::vector<NPEvent>::iterator it = events_.begin();
155 it != events_.end(); ++it) {
156 if (!instance->NPP_HandleEvent(&(*it)))
157 ret = false;
158 }
159
160 events_.clear();
161 return ret;
162 }
163
164 bool WebPluginIMEWin::GetStatus(int* input_type, gfx::Rect* caret_rect) {
165 bool status_updated = status_updated_;
166 if (status_updated) {
167 *input_type = input_type_;
168 *caret_rect = caret_rect_;
169 status_updated_ = false;
170 }
171 return status_updated;
172 }
173
174 // static
175 bool WebPluginIMEWin::NPEventFromWebCompositionEvent(const WebInputEvent* event,
176 NPEvent* np_event) {
177 switch (event->type) {
178 case WebInputEvent::RawCompositionSet:
179 np_event->event = WM_IME_COMPOSITION;
180 np_event->wParam = 0;
181 np_event->lParam = GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE |
182 GCS_CURSORPOS | GCS_DELTASTART;
183 return true;
184 case WebInputEvent::RawCompositionConfirm:
185 np_event->event = WM_IME_COMPOSITION;
186 np_event->wParam = 0;
187 np_event->lParam = GCS_CURSORPOS | GCS_DELTASTART | GCS_RESULTSTR |
188 GCS_RESULTCLAUSE;
189 return true;
190 default:
191 return false;
192 }
193 }
194
195 // static
196 FARPROC WebPluginIMEWin::GetProcAddress(LPCSTR name) {
197 static const struct {
198 const char* name;
199 FARPROC function;
200 } kImm32Functions[] = {
201 { "ImmAssociateContextEx",
202 reinterpret_cast<FARPROC>(ImmAssociateContextEx) },
203 { "ImmGetCompositionStringW",
204 reinterpret_cast<FARPROC>(ImmGetCompositionStringW) },
205 { "ImmGetContext", reinterpret_cast<FARPROC>(ImmGetContext) },
206 { "ImmReleaseContext", reinterpret_cast<FARPROC>(ImmReleaseContext) },
207 { "ImmSetCandidateWindow",
208 reinterpret_cast<FARPROC>(ImmSetCandidateWindow) },
209 { "ImmSetOpenStatus", reinterpret_cast<FARPROC>(ImmSetOpenStatus) },
210 };
211 for (int i = 0; i < arraysize(kImm32Functions); ++i) {
212 if (!lstrcmpiA(name, kImm32Functions[i].name))
213 return kImm32Functions[i].function;
214 }
215 return NULL;
216 }
217
218 void WebPluginIMEWin::Lock() {
219 g_webplugin_ime_lock.Pointer()->Acquire();
220 instance_ = this;
221 }
222
223 void WebPluginIMEWin::Unlock() {
224 instance_ = NULL;
225 g_webplugin_ime_lock.Pointer()->Release();
226 }
227
228 // static
229 WebPluginIMEWin* WebPluginIMEWin::GetInstance(HIMC context) {
230 return instance_ && context == reinterpret_cast<HIMC>(instance_) ?
231 instance_ : NULL;
232 }
233
234 // static
235 BOOL WINAPI WebPluginIMEWin::ImmAssociateContextEx(HWND window,
236 HIMC context,
237 DWORD flags) {
238 return TRUE;
239 }
240
241 // static
242 LONG WINAPI WebPluginIMEWin::ImmGetCompositionStringW(HIMC context,
243 DWORD index,
244 LPVOID dst_data,
245 DWORD dst_size) {
246 WebPluginIMEWin* instance = GetInstance(context);
247 if (!instance)
248 return ::ImmGetCompositionStringW(context, index, dst_data, dst_size);
249
250 const void* src_data = NULL;
251 DWORD src_size = 0;
252 switch (index) {
253 case GCS_COMPSTR:
254 src_data = instance->composition_text_.c_str();
255 src_size = instance->composition_text_.length() * sizeof(wchar_t);
256 break;
257
258 case GCS_COMPATTR:
259 src_data = instance->composition_attributes_.c_str();
260 src_size = instance->composition_attributes_.length();
261 break;
262
263 case GCS_COMPCLAUSE:
264 src_data = &instance->composition_clauses_[0];
265 src_size = instance->composition_clauses_.size() * sizeof(uint32);
266 break;
267
268 case GCS_CURSORPOS:
269 return instance->cursor_position_;
270
271 case GCS_DELTASTART:
272 return instance->delta_start_;
273
274 case GCS_RESULTSTR:
275 src_data = instance->result_text_.c_str();
276 src_size = instance->result_text_.length() * sizeof(wchar_t);
277 break;
278
279 case GCS_RESULTCLAUSE:
280 src_data = &instance->result_clauses_[0];
281 src_size = sizeof(instance->result_clauses_);
282 break;
283
284 default:
285 break;
286 }
287 if (!src_data || !src_size)
288 return IMM_ERROR_NODATA;
289
290 if (dst_size >= src_size)
291 memcpy(dst_data, src_data, src_size);
292
293 return src_size;
294 }
295
296 // static
297 HIMC WINAPI WebPluginIMEWin::ImmGetContext(HWND window) {
298 // Call the original ImmGetContext() function if the given window is the one
299 // created in WebPluginDelegateImpl::WindowedCreatePlugin(). (We attached IME
300 // context only with the windows created in this function.) On the other hand,
301 // some windowless plug-ins (such as Flash) call this function with a dummy
302 // window handle. We return our dummy IME context for these plug-ins so they
303 // can use our IME emulator.
304 if (IsWindow(window)) {
305 wchar_t name[128];
306 GetClassName(window, &name[0], arraysize(name));
307 if (!wcscmp(&name[0], kNativeWindowClassName))
308 return ::ImmGetContext(window);
309 }
310
311 WebPluginIMEWin* instance = instance_;
312 if (instance)
313 instance->support_ime_messages_ = true;
314 return reinterpret_cast<HIMC>(instance);
315 }
316
317 // static
318 BOOL WINAPI WebPluginIMEWin::ImmReleaseContext(HWND window, HIMC context) {
319 if (!GetInstance(context))
320 return ::ImmReleaseContext(window, context);
321 return TRUE;
322 }
323
324 // static
325 BOOL WINAPI WebPluginIMEWin::ImmSetCandidateWindow(HIMC context,
326 CANDIDATEFORM* candidate) {
327 WebPluginIMEWin* instance = GetInstance(context);
328 if (!instance)
329 return ::ImmSetCandidateWindow(context, candidate);
330
331 gfx::Rect caret_rect(candidate->rcArea);
332 if ((candidate->dwStyle & CFS_EXCLUDE) &&
333 instance->caret_rect_ != caret_rect) {
334 instance->caret_rect_ = caret_rect;
335 instance->status_updated_ = true;
336 }
337 return TRUE;
338 }
339
340 // static
341 BOOL WINAPI WebPluginIMEWin::ImmSetOpenStatus(HIMC context, BOOL open) {
342 WebPluginIMEWin* instance = GetInstance(context);
343 if (!instance)
344 return ::ImmSetOpenStatus(context, open);
345
346 int input_type = open ? 1 : 0;
347 if (instance->input_type_ != input_type) {
348 instance->input_type_ = input_type;
349 instance->status_updated_ = true;
350 }
351
352 return TRUE;
353 }
354
355 } // namespace npapi
356 } // namespace webkit
OLDNEW
« content/renderer/webplugin_delegate_proxy.cc ('K') | « webkit/plugins/npapi/webplugin_ime_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698