OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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/renderer_host/render_widget_host_view_win.h" | 5 #include "chrome/browser/renderer_host/render_widget_host_view_win.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 #include "content/browser/plugin_process_host.h" | 25 #include "content/browser/plugin_process_host.h" |
26 #include "content/browser/renderer_host/backing_store.h" | 26 #include "content/browser/renderer_host/backing_store.h" |
27 #include "content/browser/renderer_host/backing_store_win.h" | 27 #include "content/browser/renderer_host/backing_store_win.h" |
28 #include "content/browser/renderer_host/render_process_host.h" | 28 #include "content/browser/renderer_host/render_process_host.h" |
29 #include "content/browser/renderer_host/render_widget_host.h" | 29 #include "content/browser/renderer_host/render_widget_host.h" |
30 #include "content/common/native_web_keyboard_event.h" | 30 #include "content/common/native_web_keyboard_event.h" |
31 #include "content/common/notification_service.h" | 31 #include "content/common/notification_service.h" |
32 #include "content/common/plugin_messages.h" | 32 #include "content/common/plugin_messages.h" |
33 #include "grit/webkit_resources.h" | 33 #include "grit/webkit_resources.h" |
34 #include "skia/ext/skia_utils_win.h" | 34 #include "skia/ext/skia_utils_win.h" |
| 35 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderli
ne.h" |
35 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" | 36 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
36 #include "third_party/WebKit/Source/WebKit/chromium/public/win/WebInputEventFact
ory.h" | 37 #include "third_party/WebKit/Source/WebKit/chromium/public/win/WebInputEventFact
ory.h" |
| 38 #include "ui/base/ime/composition_text.h" |
37 #include "ui/base/l10n/l10n_util.h" | 39 #include "ui/base/l10n/l10n_util.h" |
38 #include "ui/base/l10n/l10n_util_win.h" | 40 #include "ui/base/l10n/l10n_util_win.h" |
39 #include "ui/base/resource/resource_bundle.h" | 41 #include "ui/base/resource/resource_bundle.h" |
40 #include "ui/base/view_prop.h" | 42 #include "ui/base/view_prop.h" |
41 #include "ui/base/win/hwnd_util.h" | 43 #include "ui/base/win/hwnd_util.h" |
42 #include "ui/gfx/canvas.h" | 44 #include "ui/gfx/canvas.h" |
43 #include "ui/gfx/canvas_skia.h" | 45 #include "ui/gfx/canvas_skia.h" |
44 #include "ui/gfx/gdi_util.h" | 46 #include "ui/gfx/gdi_util.h" |
45 #include "ui/gfx/rect.h" | 47 #include "ui/gfx/rect.h" |
46 #include "views/accessibility/native_view_accessibility_win.h" | 48 #include "views/accessibility/native_view_accessibility_win.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 if (::IsWindowVisible(window)) { | 89 if (::IsWindowVisible(window)) { |
88 const HWND owner = ::GetWindow(window, GW_OWNER); | 90 const HWND owner = ::GetWindow(window, GW_OWNER); |
89 if (toplevel_hwnd == owner) { | 91 if (toplevel_hwnd == owner) { |
90 ::PostMessage(window, WM_CANCELMODE, 0, 0); | 92 ::PostMessage(window, WM_CANCELMODE, 0, 0); |
91 } | 93 } |
92 } | 94 } |
93 | 95 |
94 return TRUE; | 96 return TRUE; |
95 } | 97 } |
96 | 98 |
97 // Enumerates the installed keyboard layouts in this system and returns true | |
98 // if an RTL keyboard layout is installed. | |
99 // TODO(hbono): to be moved to "src/chrome/common/l10n_util.cc"? | |
100 static bool IsRTLKeyboardLayoutInstalled() { | |
101 static enum { | |
102 RTL_KEYBOARD_LAYOUT_NOT_INITIALIZED, | |
103 RTL_KEYBOARD_LAYOUT_INSTALLED, | |
104 RTL_KEYBOARD_LAYOUT_NOT_INSTALLED, | |
105 RTL_KEYBOARD_LAYOUT_ERROR, | |
106 } layout = RTL_KEYBOARD_LAYOUT_NOT_INITIALIZED; | |
107 | |
108 // Cache the result value. | |
109 if (layout != RTL_KEYBOARD_LAYOUT_NOT_INITIALIZED) | |
110 return layout == RTL_KEYBOARD_LAYOUT_INSTALLED; | |
111 | |
112 // Retrieve the number of layouts installed in this system. | |
113 int size = GetKeyboardLayoutList(0, NULL); | |
114 if (size <= 0) { | |
115 layout = RTL_KEYBOARD_LAYOUT_ERROR; | |
116 return false; | |
117 } | |
118 | |
119 // Retrieve the keyboard layouts in an array and check if there is an RTL | |
120 // layout in it. | |
121 scoped_array<HKL> layouts(new HKL[size]); | |
122 GetKeyboardLayoutList(size, layouts.get()); | |
123 for (int i = 0; i < size; ++i) { | |
124 if (PRIMARYLANGID(layouts[i]) == LANG_ARABIC || | |
125 PRIMARYLANGID(layouts[i]) == LANG_HEBREW || | |
126 PRIMARYLANGID(layouts[i]) == LANG_PERSIAN) { | |
127 layout = RTL_KEYBOARD_LAYOUT_INSTALLED; | |
128 return true; | |
129 } | |
130 } | |
131 | |
132 layout = RTL_KEYBOARD_LAYOUT_NOT_INSTALLED; | |
133 return false; | |
134 } | |
135 | |
136 // Returns the text direction according to the keyboard status. | |
137 // This function retrieves the status of all keys and returns the following | |
138 // values: | |
139 // * WEB_TEXT_DIRECTION_RTL | |
140 // If only a control key and a right-shift key are down. | |
141 // * WEB_TEXT_DIRECTION_LTR | |
142 // If only a control key and a left-shift key are down. | |
143 | |
144 static bool GetNewTextDirection(WebTextDirection* direction) { | |
145 uint8_t keystate[256]; | |
146 if (!GetKeyboardState(&keystate[0])) | |
147 return false; | |
148 | |
149 // To check if a user is pressing only a control key and a right-shift key | |
150 // (or a left-shift key), we use the steps below: | |
151 // 1. Check if a user is pressing a control key and a right-shift key (or | |
152 // a left-shift key). | |
153 // 2. If the condition 1 is true, we should check if there are any other | |
154 // keys pressed at the same time. | |
155 // To ignore the keys checked in 1, we set their status to 0 before | |
156 // checking the key status. | |
157 const int kKeyDownMask = 0x80; | |
158 if ((keystate[VK_CONTROL] & kKeyDownMask) == 0) | |
159 return false; | |
160 | |
161 if (keystate[VK_RSHIFT] & kKeyDownMask) { | |
162 keystate[VK_RSHIFT] = 0; | |
163 *direction = WebKit::WebTextDirectionRightToLeft; | |
164 } else if (keystate[VK_LSHIFT] & kKeyDownMask) { | |
165 keystate[VK_LSHIFT] = 0; | |
166 *direction = WebKit::WebTextDirectionLeftToRight; | |
167 } else { | |
168 return false; | |
169 } | |
170 | |
171 // Scan the key status to find pressed keys. We should adandon changing the | |
172 // text direction when there are other pressed keys. | |
173 // This code is executed only when a user is pressing a control key and a | |
174 // right-shift key (or a left-shift key), i.e. we should ignore the status of | |
175 // the keys: VK_SHIFT, VK_CONTROL, VK_RCONTROL, and VK_LCONTROL. | |
176 // So, we reset their status to 0 and ignore them. | |
177 keystate[VK_SHIFT] = 0; | |
178 keystate[VK_CONTROL] = 0; | |
179 keystate[VK_RCONTROL] = 0; | |
180 keystate[VK_LCONTROL] = 0; | |
181 for (int i = 0; i <= VK_PACKET; ++i) { | |
182 if (keystate[i] & kKeyDownMask) | |
183 return false; | |
184 } | |
185 return true; | |
186 } | |
187 | |
188 class NotifyPluginProcessHostTask : public Task { | 99 class NotifyPluginProcessHostTask : public Task { |
189 public: | 100 public: |
190 NotifyPluginProcessHostTask(HWND window, HWND parent) | 101 NotifyPluginProcessHostTask(HWND window, HWND parent) |
191 : window_(window), parent_(parent), tries_(kMaxTries) { } | 102 : window_(window), parent_(parent), tries_(kMaxTries) { } |
192 | 103 |
193 private: | 104 private: |
194 void Run() { | 105 void Run() { |
195 DWORD plugin_process_id; | 106 DWORD plugin_process_id; |
196 bool found_starting_plugin_process = false; | 107 bool found_starting_plugin_process = false; |
197 GetWindowThreadProcessId(window_, &plugin_process_id); | 108 GetWindowThreadProcessId(window_, &plugin_process_id); |
(...skipping 991 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1189 bool activated = (wparam == TRUE); | 1100 bool activated = (wparam == TRUE); |
1190 if (render_widget_host_) { | 1101 if (render_widget_host_) { |
1191 render_widget_host_->SetInputMethodActive(activated); | 1102 render_widget_host_->SetInputMethodActive(activated); |
1192 ime_notification_ = activated; | 1103 ime_notification_ = activated; |
1193 } | 1104 } |
1194 | 1105 |
1195 if (ime_notification_) | 1106 if (ime_notification_) |
1196 ime_input_.CreateImeWindow(m_hWnd); | 1107 ime_input_.CreateImeWindow(m_hWnd); |
1197 | 1108 |
1198 ime_input_.CleanupComposition(m_hWnd); | 1109 ime_input_.CleanupComposition(m_hWnd); |
1199 ime_input_.SetImeWindowStyle(m_hWnd, message, wparam, lparam, &handled); | 1110 return ime_input_.SetImeWindowStyle( |
1200 return 0; | 1111 m_hWnd, message, wparam, lparam, &handled); |
1201 } | 1112 } |
1202 | 1113 |
1203 LRESULT RenderWidgetHostViewWin::OnImeStartComposition( | 1114 LRESULT RenderWidgetHostViewWin::OnImeStartComposition( |
1204 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | 1115 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { |
1205 if (!render_widget_host_) | 1116 if (!render_widget_host_) |
1206 return 0; | 1117 return 0; |
1207 | 1118 |
1208 // Reset the composition status and create IME windows. | 1119 // Reset the composition status and create IME windows. |
1209 ime_input_.CreateImeWindow(m_hWnd); | 1120 ime_input_.CreateImeWindow(m_hWnd); |
1210 ime_input_.ResetComposition(m_hWnd); | 1121 ime_input_.ResetComposition(m_hWnd); |
1211 // We have to prevent WTL from calling ::DefWindowProc() because the function | 1122 // We have to prevent WTL from calling ::DefWindowProc() because the function |
1212 // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to | 1123 // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to |
1213 // over-write the position of IME windows. | 1124 // over-write the position of IME windows. |
1214 handled = TRUE; | 1125 handled = TRUE; |
1215 return 0; | 1126 return 0; |
1216 } | 1127 } |
1217 | 1128 |
1218 LRESULT RenderWidgetHostViewWin::OnImeComposition( | 1129 LRESULT RenderWidgetHostViewWin::OnImeComposition( |
1219 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | 1130 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { |
1220 if (!render_widget_host_) | 1131 if (!render_widget_host_) |
1221 return 0; | 1132 return 0; |
1222 | 1133 |
1223 // At first, update the position of the IME window. | 1134 // At first, update the position of the IME window. |
1224 ime_input_.UpdateImeWindow(m_hWnd); | 1135 ime_input_.UpdateImeWindow(m_hWnd); |
1225 | 1136 |
| 1137 // ui::CompositionUnderline should be identical to |
| 1138 // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely. |
| 1139 COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == |
| 1140 sizeof(WebKit::WebCompositionUnderline), |
| 1141 ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff); |
| 1142 |
1226 // Retrieve the result string and its attributes of the ongoing composition | 1143 // Retrieve the result string and its attributes of the ongoing composition |
1227 // and send it to a renderer process. | 1144 // and send it to a renderer process. |
1228 ImeComposition composition; | 1145 ui::CompositionText composition; |
1229 if (ime_input_.GetResult(m_hWnd, lparam, &composition)) { | 1146 if (ime_input_.GetResult(m_hWnd, lparam, &composition.text)) { |
1230 render_widget_host_->ImeConfirmComposition(composition.ime_string); | 1147 render_widget_host_->ImeConfirmComposition(composition.text); |
1231 ime_input_.ResetComposition(m_hWnd); | 1148 ime_input_.ResetComposition(m_hWnd); |
1232 // Fall though and try reading the composition string. | 1149 // Fall though and try reading the composition string. |
1233 // Japanese IMEs send a message containing both GCS_RESULTSTR and | 1150 // Japanese IMEs send a message containing both GCS_RESULTSTR and |
1234 // GCS_COMPSTR, which means an ongoing composition has been finished | 1151 // GCS_COMPSTR, which means an ongoing composition has been finished |
1235 // by the start of another composition. | 1152 // by the start of another composition. |
1236 } | 1153 } |
1237 // Retrieve the composition string and its attributes of the ongoing | 1154 // Retrieve the composition string and its attributes of the ongoing |
1238 // composition and send it to a renderer process. | 1155 // composition and send it to a renderer process. |
1239 if (ime_input_.GetComposition(m_hWnd, lparam, &composition)) { | 1156 if (ime_input_.GetComposition(m_hWnd, lparam, &composition)) { |
| 1157 // TODO(suzhe): due to a bug of webkit, we can't use selection range with |
| 1158 // composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788 |
| 1159 composition.selection = ui::Range(composition.selection.end()); |
| 1160 |
| 1161 // TODO(suzhe): convert both renderer_host and renderer to use |
| 1162 // ui::CompositionText. |
| 1163 const std::vector<WebKit::WebCompositionUnderline>& underlines = |
| 1164 reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>( |
| 1165 composition.underlines); |
1240 render_widget_host_->ImeSetComposition( | 1166 render_widget_host_->ImeSetComposition( |
1241 composition.ime_string, composition.underlines, | 1167 composition.text, underlines, |
1242 composition.selection_start, composition.selection_end); | 1168 composition.selection.start(), composition.selection.end()); |
1243 } | 1169 } |
1244 // We have to prevent WTL from calling ::DefWindowProc() because we do not | 1170 // We have to prevent WTL from calling ::DefWindowProc() because we do not |
1245 // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages. | 1171 // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages. |
1246 handled = TRUE; | 1172 handled = TRUE; |
1247 return 0; | 1173 return 0; |
1248 } | 1174 } |
1249 | 1175 |
1250 LRESULT RenderWidgetHostViewWin::OnImeEndComposition( | 1176 LRESULT RenderWidgetHostViewWin::OnImeEndComposition( |
1251 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | 1177 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { |
1252 if (!render_widget_host_) | 1178 if (!render_widget_host_) |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1348 if (!render_widget_host_) | 1274 if (!render_widget_host_) |
1349 return 0; | 1275 return 0; |
1350 | 1276 |
1351 // Bug 1845: we need to update the text direction when a user releases | 1277 // Bug 1845: we need to update the text direction when a user releases |
1352 // either a right-shift key or a right-control key after pressing both of | 1278 // either a right-shift key or a right-control key after pressing both of |
1353 // them. So, we just update the text direction while a user is pressing the | 1279 // them. So, we just update the text direction while a user is pressing the |
1354 // keys, and we notify the text direction when a user releases either of them. | 1280 // keys, and we notify the text direction when a user releases either of them. |
1355 // Bug 9718: http://crbug.com/9718 To investigate IE and notepad, this | 1281 // Bug 9718: http://crbug.com/9718 To investigate IE and notepad, this |
1356 // shortcut is enabled only on a PC having RTL keyboard layouts installed. | 1282 // shortcut is enabled only on a PC having RTL keyboard layouts installed. |
1357 // We should emulate them. | 1283 // We should emulate them. |
1358 if (IsRTLKeyboardLayoutInstalled()) { | 1284 if (ui::ImeInput::IsRTLKeyboardLayoutInstalled()) { |
1359 if (message == WM_KEYDOWN) { | 1285 if (message == WM_KEYDOWN) { |
1360 if (wparam == VK_SHIFT) { | 1286 if (wparam == VK_SHIFT) { |
1361 WebTextDirection direction; | 1287 base::i18n::TextDirection dir; |
1362 if (GetNewTextDirection(&direction)) | 1288 if (ui::ImeInput::IsCtrlShiftPressed(&dir)) { |
1363 render_widget_host_->UpdateTextDirection(direction); | 1289 render_widget_host_->UpdateTextDirection( |
| 1290 dir == base::i18n::RIGHT_TO_LEFT ? |
| 1291 WebKit::WebTextDirectionRightToLeft : |
| 1292 WebKit::WebTextDirectionLeftToRight); |
| 1293 } |
1364 } else if (wparam != VK_CONTROL) { | 1294 } else if (wparam != VK_CONTROL) { |
1365 // Bug 9762: http://crbug.com/9762 A user pressed a key except shift | 1295 // Bug 9762: http://crbug.com/9762 A user pressed a key except shift |
1366 // and control keys. | 1296 // and control keys. |
1367 // When a user presses a key while he/she holds control and shift keys, | 1297 // When a user presses a key while he/she holds control and shift keys, |
1368 // we cancel sending an IPC message in NotifyTextDirection() below and | 1298 // we cancel sending an IPC message in NotifyTextDirection() below and |
1369 // ignore succeeding UpdateTextDirection() calls while we call | 1299 // ignore succeeding UpdateTextDirection() calls while we call |
1370 // NotifyTextDirection(). | 1300 // NotifyTextDirection(). |
1371 // To cancel it, this call set a flag that prevents sending an IPC | 1301 // To cancel it, this call set a flag that prevents sending an IPC |
1372 // message in NotifyTextDirection() only if we are going to send it. | 1302 // message in NotifyTextDirection() only if we are going to send it. |
1373 // It is harmless to call this function if we aren't going to send it. | 1303 // It is harmless to call this function if we aren't going to send it. |
(...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1866 } | 1796 } |
1867 | 1797 |
1868 // static | 1798 // static |
1869 RenderWidgetHostView* | 1799 RenderWidgetHostView* |
1870 RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView( | 1800 RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView( |
1871 gfx::NativeView native_view) { | 1801 gfx::NativeView native_view) { |
1872 return ::IsWindow(native_view) ? | 1802 return ::IsWindow(native_view) ? |
1873 reinterpret_cast<RenderWidgetHostView*>( | 1803 reinterpret_cast<RenderWidgetHostView*>( |
1874 ViewProp::GetValue(native_view, kRenderWidgetHostViewKey)) : NULL; | 1804 ViewProp::GetValue(native_view, kRenderWidgetHostViewKey)) : NULL; |
1875 } | 1805 } |
OLD | NEW |