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
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/render_widget_host_view_win.h"
7 #include <InputScope.h>
9 #pragma comment(lib, "wtsapi32.lib")
15 #include "base/basictypes.h"
16 #include "base/bind.h"
17 #include "base/callback_helpers.h"
18 #include "base/command_line.h"
19 #include "base/debug/trace_event.h"
20 #include "base/i18n/rtl.h"
21 #include "base/metrics/histogram.h"
22 #include "base/threading/thread.h"
23 #include "base/win/metro.h"
24 #include "base/win/scoped_comptr.h"
25 #include "base/win/scoped_gdi_object.h"
26 #include "base/win/win_util.h"
27 #include "base/win/windows_version.h"
28 #include "base/win/wrapped_window_proc.h"
29 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
30 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
31 #include "content/browser/accessibility/browser_accessibility_win.h"
32 #include "content/browser/gpu/gpu_data_manager_impl.h"
33 #include "content/browser/gpu/gpu_process_host.h"
34 #include "content/browser/gpu/gpu_process_host_ui_shim.h"
35 #include "content/browser/renderer_host/backing_store.h"
36 #include "content/browser/renderer_host/backing_store_win.h"
37 #include "content/browser/renderer_host/input/web_input_event_builders_win.h"
38 #include "content/browser/renderer_host/render_process_host_impl.h"
39 #include "content/browser/renderer_host/render_widget_host_impl.h"
40 #include "content/browser/renderer_host/ui_events_helper.h"
41 #include "content/common/accessibility_messages.h"
42 #include "content/common/gpu/gpu_messages.h"
43 #include "content/common/plugin_constants_win.h"
44 #include "content/common/view_messages.h"
45 #include "content/common/webplugin_geometry.h"
46 #include "content/public/browser/browser_thread.h"
47 #include "content/public/browser/child_process_data.h"
48 #include "content/public/browser/content_browser_client.h"
49 #include "content/public/browser/native_web_keyboard_event.h"
50 #include "content/public/browser/notification_service.h"
51 #include "content/public/browser/notification_types.h"
52 #include "content/public/browser/render_view_host.h"
53 #include "content/public/common/content_switches.h"
54 #include "content/public/common/page_zoom.h"
55 #include "content/public/common/process_type.h"
56 #include "skia/ext/skia_utils_win.h"
57 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
58 #include "third_party/WebKit/public/web/WebInputEvent.h"
59 #include "third_party/skia/include/core/SkRegion.h"
60 #include "ui/base/ime/composition_text.h"
61 #include "ui/base/ime/win/imm32_manager.h"
62 #include "ui/base/ime/win/tsf_input_scope.h"
63 #include "ui/base/l10n/l10n_util_win.h"
64 #include "ui/base/touch/touch_device.h"
65 #include "ui/base/touch/touch_enabled.h"
66 #include "ui/base/ui_base_switches.h"
67 #include "ui/base/view_prop.h"
68 #include "ui/base/win/mouse_wheel_util.h"
69 #include "ui/base/win/touch_input.h"
70 #include "ui/events/event.h"
71 #include "ui/events/event_utils.h"
72 #include "ui/gfx/canvas.h"
73 #include "ui/gfx/rect.h"
74 #include "ui/gfx/rect_conversions.h"
75 #include "ui/gfx/screen.h"
76 #include "ui/gfx/sequential_id_generator.h"
77 #include "ui/gfx/text_elider.h"
78 #include "ui/gfx/win/dpi.h"
79 #include "ui/gfx/win/hwnd_util.h"
80 #include "webkit/common/cursors/webcursor.h"
81 #include "win8/util/win8_util.h"
83 using base::TimeDelta
;
84 using base::TimeTicks
;
86 using blink::WebInputEvent
;
87 using blink::WebMouseEvent
;
88 using blink::WebTextDirection
;
93 // Tooltips will wrap after this width. Yes, wrap. Imagine that!
94 const int kTooltipMaxWidthPixels
= 300;
96 // Maximum number of characters we allow in a tooltip.
97 const int kMaxTooltipLength
= 1024;
99 // A custom MSAA object id used to determine if a screen reader is actively
100 // listening for MSAA events.
101 const int kIdCustom
= 1;
103 // The delay before the compositor host window is destroyed. This gives the GPU
104 // process a grace period to stop referencing it.
105 const int kDestroyCompositorHostWindowDelay
= 10000;
107 // In mouse lock mode, we need to prevent the (invisible) cursor from hitting
108 // the border of the view, in order to get valid movement information. However,
109 // forcing the cursor back to the center of the view after each mouse move
110 // doesn't work well. It reduces the frequency of useful WM_MOUSEMOVE messages
111 // significantly. Therefore, we move the cursor to the center of the view only
112 // if it approaches the border. |kMouseLockBorderPercentage| specifies the width
113 // of the border area, in percentage of the corresponding dimension.
114 const int kMouseLockBorderPercentage
= 15;
116 // A callback function for EnumThreadWindows to enumerate and dismiss
117 // any owned popup windows.
118 BOOL CALLBACK
DismissOwnedPopups(HWND window
, LPARAM arg
) {
119 const HWND toplevel_hwnd
= reinterpret_cast<HWND
>(arg
);
121 if (::IsWindowVisible(window
)) {
122 const HWND owner
= ::GetWindow(window
, GW_OWNER
);
123 if (toplevel_hwnd
== owner
) {
124 ::PostMessage(window
, WM_CANCELMODE
, 0, 0);
131 void SendToGpuProcessHost(int gpu_host_id
, scoped_ptr
<IPC::Message
> message
) {
132 GpuProcessHost
* gpu_process_host
= GpuProcessHost::FromID(gpu_host_id
);
133 if (!gpu_process_host
)
136 gpu_process_host
->Send(message
.release());
139 void PostTaskOnIOThread(const tracked_objects::Location
& from_here
,
140 base::Closure task
) {
141 BrowserThread::PostTask(BrowserThread::IO
, from_here
, task
);
144 bool DecodeZoomGesture(HWND hwnd
, const GESTUREINFO
& gi
,
145 PageZoom
* zoom
, POINT
* zoom_center
) {
146 static long start
= 0;
147 static POINT zoom_first
;
149 if (gi
.dwFlags
== GF_BEGIN
) {
150 start
= gi
.ullArguments
;
151 zoom_first
.x
= gi
.ptsLocation
.x
;
152 zoom_first
.y
= gi
.ptsLocation
.y
;
153 ScreenToClient(hwnd
, &zoom_first
);
157 if (gi
.dwFlags
== GF_END
)
160 POINT zoom_second
= {0};
161 zoom_second
.x
= gi
.ptsLocation
.x
;
162 zoom_second
.y
= gi
.ptsLocation
.y
;
163 ScreenToClient(hwnd
, &zoom_second
);
165 if (zoom_first
.x
== zoom_second
.x
&& zoom_first
.y
== zoom_second
.y
)
168 zoom_center
->x
= (zoom_first
.x
+ zoom_second
.x
) / 2;
169 zoom_center
->y
= (zoom_first
.y
+ zoom_second
.y
) / 2;
172 static_cast<double>(gi
.ullArguments
)/static_cast<double>(start
);
174 *zoom
= zoom_factor
>= 1 ? PAGE_ZOOM_IN
: PAGE_ZOOM_OUT
;
176 start
= gi
.ullArguments
;
177 zoom_first
= zoom_second
;
181 bool DecodeScrollGesture(const GESTUREINFO
& gi
,
184 // Windows gestures are streams of messages with begin/end messages that
185 // separate each new gesture. We key off the begin message to reset
186 // the static variables.
187 static POINT last_pt
;
188 static POINT start_pt
;
190 if (gi
.dwFlags
== GF_BEGIN
) {
193 start_pt
.x
= gi
.ptsLocation
.x
;
194 start_pt
.y
= gi
.ptsLocation
.y
;
196 delta
->x
= gi
.ptsLocation
.x
- last_pt
.x
;
197 delta
->y
= gi
.ptsLocation
.y
- last_pt
.y
;
199 last_pt
.x
= gi
.ptsLocation
.x
;
200 last_pt
.y
= gi
.ptsLocation
.y
;
205 blink::WebMouseWheelEvent
MakeFakeScrollWheelEvent(HWND hwnd
,
208 blink::WebMouseWheelEvent result
;
209 result
.type
= WebInputEvent::MouseWheel
;
210 result
.timeStampSeconds
= ::GetMessageTime() / 1000.0;
211 result
.button
= WebMouseEvent::ButtonNone
;
212 result
.globalX
= start
.x
;
213 result
.globalY
= start
.y
;
214 // Map to window coordinates.
215 POINT client_point
= { result
.globalX
, result
.globalY
};
216 MapWindowPoints(0, hwnd
, &client_point
, 1);
217 result
.x
= client_point
.x
;
218 result
.y
= client_point
.y
;
219 result
.windowX
= result
.x
;
220 result
.windowY
= result
.y
;
221 // Note that we support diagonal scrolling.
222 result
.deltaX
= static_cast<float>(delta
.x
);
223 result
.wheelTicksX
= WHEEL_DELTA
;
224 result
.deltaY
= static_cast<float>(delta
.y
);
225 result
.wheelTicksY
= WHEEL_DELTA
;
229 static const int kTouchMask
= 0x7;
231 inline int GetTouchType(const TOUCHINPUT
& point
) {
232 return point
.dwFlags
& kTouchMask
;
235 inline void SetTouchType(TOUCHINPUT
* point
, int type
) {
236 point
->dwFlags
= (point
->dwFlags
& kTouchMask
) | type
;
239 ui::EventType
ConvertToUIEvent(blink::WebTouchPoint::State t
) {
241 case blink::WebTouchPoint::StatePressed
:
242 return ui::ET_TOUCH_PRESSED
;
243 case blink::WebTouchPoint::StateMoved
:
244 return ui::ET_TOUCH_MOVED
;
245 case blink::WebTouchPoint::StateStationary
:
246 return ui::ET_TOUCH_STATIONARY
;
247 case blink::WebTouchPoint::StateReleased
:
248 return ui::ET_TOUCH_RELEASED
;
249 case blink::WebTouchPoint::StateCancelled
:
250 return ui::ET_TOUCH_CANCELLED
;
252 DCHECK(false) << "Unexpected ui type. " << t
;
253 return ui::ET_UNKNOWN
;
257 // Creates a WebGestureEvent corresponding to the given |gesture|
258 blink::WebGestureEvent
CreateWebGestureEvent(HWND hwnd
,
259 const ui::GestureEvent
& gesture
) {
260 blink::WebGestureEvent gesture_event
=
261 MakeWebGestureEventFromUIEvent(gesture
);
263 POINT client_point
= gesture
.location().ToPOINT();
264 POINT screen_point
= gesture
.location().ToPOINT();
265 MapWindowPoints(hwnd
, HWND_DESKTOP
, &screen_point
, 1);
267 gesture_event
.x
= client_point
.x
;
268 gesture_event
.y
= client_point
.y
;
269 gesture_event
.globalX
= screen_point
.x
;
270 gesture_event
.globalY
= screen_point
.y
;
272 return gesture_event
;
275 blink::WebGestureEvent
CreateFlingCancelEvent(double time_stamp
) {
276 blink::WebGestureEvent gesture_event
;
277 gesture_event
.timeStampSeconds
= time_stamp
;
278 gesture_event
.type
= blink::WebGestureEvent::GestureFlingCancel
;
279 gesture_event
.sourceDevice
= blink::WebGestureEvent::Touchscreen
;
280 return gesture_event
;
283 class TouchEventFromWebTouchPoint
: public ui::TouchEvent
{
285 TouchEventFromWebTouchPoint(const blink::WebTouchPoint
& touch_point
,
286 base::TimeDelta
& timestamp
)
287 : ui::TouchEvent(ConvertToUIEvent(touch_point
.state
),
288 touch_point
.position
,
291 set_radius(touch_point
.radiusX
, touch_point
.radiusY
);
292 set_rotation_angle(touch_point
.rotationAngle
);
293 set_force(touch_point
.force
);
294 set_flags(ui::GetModifiersFromKeyState());
297 virtual ~TouchEventFromWebTouchPoint() {}
300 DISALLOW_COPY_AND_ASSIGN(TouchEventFromWebTouchPoint
);
303 bool ShouldSendPinchGesture() {
304 static bool pinch_allowed
=
305 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePinch
);
306 return pinch_allowed
;
309 void GetScreenInfoForWindow(gfx::NativeViewId id
,
310 blink::WebScreenInfo
* results
) {
311 HWND window
= gfx::NativeViewFromId(id
);
313 HMONITOR monitor
= MonitorFromWindow(window
, MONITOR_DEFAULTTOPRIMARY
);
315 MONITORINFOEX monitor_info
;
316 monitor_info
.cbSize
= sizeof(MONITORINFOEX
);
317 if (!base::win::GetMonitorInfoWrapper(monitor
, &monitor_info
))
321 dev_mode
.dmSize
= sizeof(dev_mode
);
322 dev_mode
.dmDriverExtra
= 0;
323 EnumDisplaySettings(monitor_info
.szDevice
, ENUM_CURRENT_SETTINGS
, &dev_mode
);
325 blink::WebScreenInfo screen_info
;
326 screen_info
.depth
= dev_mode
.dmBitsPerPel
;
327 screen_info
.depthPerComponent
= 8;
328 screen_info
.deviceScaleFactor
= gfx::win::GetDeviceScaleFactor();
329 screen_info
.isMonochrome
= dev_mode
.dmColor
== DMCOLOR_MONOCHROME
;
330 screen_info
.rect
= gfx::Rect(monitor_info
.rcMonitor
);
331 screen_info
.availableRect
= gfx::Rect(monitor_info
.rcWork
);
333 *results
= screen_info
;
338 const wchar_t kRenderWidgetHostHWNDClass
[] = L
"Chrome_RenderWidgetHostHWND";
340 // Wrapper for maintaining touchstate associated with a WebTouchEvent.
341 class WebTouchState
{
343 explicit WebTouchState(const RenderWidgetHostViewWin
* window
);
345 // Updates the current touchpoint state with the supplied touches.
346 // Touches will be consumed only if they are of the same type (e.g. down,
347 // up, move). Returns the number of consumed touches.
348 size_t UpdateTouchPoints(TOUCHINPUT
* points
, size_t count
);
350 // Marks all active touchpoints as released.
351 bool ReleaseTouchPoints();
353 // The contained WebTouchEvent.
354 const blink::WebTouchEvent
& touch_event() { return touch_event_
; }
356 // Returns if any touches are modified in the event.
357 bool is_changed() { return touch_event_
.changedTouchesLength
!= 0; }
360 // Adds a touch point or returns NULL if there's not enough space.
361 blink::WebTouchPoint
* AddTouchPoint(TOUCHINPUT
* touch_input
);
363 // Copy details from a TOUCHINPUT to an existing WebTouchPoint, returning
364 // true if the resulting point is a stationary move.
365 bool UpdateTouchPoint(blink::WebTouchPoint
* touch_point
,
366 TOUCHINPUT
* touch_input
);
368 // Find (or create) a mapping for _os_touch_id_.
369 unsigned int GetMappedTouch(unsigned int os_touch_id
);
371 // Remove any mappings that are no longer in use.
372 void RemoveExpiredMappings();
374 blink::WebTouchEvent touch_event_
;
375 const RenderWidgetHostViewWin
* const window_
;
377 ui::SequentialIDGenerator id_generator_
;
379 DISALLOW_COPY_AND_ASSIGN(WebTouchState
);
382 typedef void (*MetroSetFrameWindow
)(HWND window
);
383 typedef void (*MetroCloseFrameWindow
)(HWND window
);
385 ///////////////////////////////////////////////////////////////////////////////
386 // RenderWidgetHostViewWin, public:
388 RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost
* widget
)
389 : render_widget_host_(RenderWidgetHostImpl::From(widget
)),
390 compositor_host_window_(NULL
),
391 hide_compositor_window_at_next_paint_(false),
392 track_mouse_leave_(false),
393 imm32_manager_(new ui::IMM32Manager
),
394 ime_notification_(false),
395 capture_enter_key_(false),
396 about_to_validate_and_paint_(false),
397 close_on_deactivate_(false),
398 being_destroyed_(false),
400 tooltip_showing_(false),
403 text_input_type_(ui::TEXT_INPUT_TYPE_NONE
),
404 text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT
),
405 can_compose_inline_(true),
406 is_fullscreen_(false),
407 ignore_mouse_movement_(true),
408 composition_range_(gfx::Range::InvalidRange()),
409 touch_state_(new WebTouchState(this)),
410 pointer_down_context_(false),
411 last_touch_location_(-1, -1),
412 touch_events_enabled_(ui::AreTouchEventsEnabled()),
413 gesture_recognizer_(ui::GestureRecognizer::Create()) {
414 render_widget_host_
->SetView(this);
416 NOTIFICATION_RENDERER_PROCESS_TERMINATED
,
417 NotificationService::AllBrowserContextsAndSources());
418 gesture_recognizer_
->AddGestureEventHelper(this);
421 RenderWidgetHostViewWin::~RenderWidgetHostViewWin() {
422 gesture_recognizer_
->RemoveGestureEventHelper(this);
427 void RenderWidgetHostViewWin::CreateWnd(HWND parent
) {
428 // ATL function to create the window.
432 ///////////////////////////////////////////////////////////////////////////////
433 // RenderWidgetHostViewWin, RenderWidgetHostView implementation:
435 void RenderWidgetHostViewWin::InitAsChild(
436 gfx::NativeView parent_view
) {
437 CreateWnd(parent_view
);
440 void RenderWidgetHostViewWin::InitAsPopup(
441 RenderWidgetHostView
* parent_host_view
, const gfx::Rect
& pos
) {
442 close_on_deactivate_
= true;
443 DoPopupOrFullscreenInit(parent_host_view
->GetNativeView(), pos
,
447 void RenderWidgetHostViewWin::InitAsFullscreen(
448 RenderWidgetHostView
* reference_host_view
) {
449 gfx::Rect pos
= gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
450 reference_host_view
->GetNativeView()).bounds();
451 is_fullscreen_
= true;
452 DoPopupOrFullscreenInit(gfx::GetWindowToParentTo(true), pos
, 0);
455 RenderWidgetHost
* RenderWidgetHostViewWin::GetRenderWidgetHost() const {
456 return render_widget_host_
;
459 void RenderWidgetHostViewWin::WasShown() {
460 // |render_widget_host_| may be NULL if the WebContentsImpl is in the process
462 if (!render_widget_host_
)
465 if (!render_widget_host_
->is_hidden())
468 if (web_contents_switch_paint_time_
.is_null())
469 web_contents_switch_paint_time_
= TimeTicks::Now();
471 render_widget_host_
->WasShown();
474 void RenderWidgetHostViewWin::WasHidden() {
475 // |render_widget_host_| may be NULL if the WebContentsImpl is in the process
477 if (!render_widget_host_
)
480 if (render_widget_host_
->is_hidden())
485 // Inform the renderer that we are being hidden so it can reduce its resource
487 render_widget_host_
->WasHidden();
489 if (accelerated_surface_
)
490 accelerated_surface_
->WasHidden();
492 if (GetBrowserAccessibilityManager())
493 GetBrowserAccessibilityManager()->WasHidden();
495 web_contents_switch_paint_time_
= base::TimeTicks();
498 void RenderWidgetHostViewWin::SetSize(const gfx::Size
& size
) {
499 SetBounds(gfx::Rect(GetPixelBounds().origin(), size
));
502 void RenderWidgetHostViewWin::SetBounds(const gfx::Rect
& rect
) {
503 if (being_destroyed_
)
506 // No SWP_NOREDRAW as autofill popups can move and the underneath window
507 // should redraw in that case.
508 UINT swp_flags
= SWP_NOSENDCHANGING
| SWP_NOOWNERZORDER
| SWP_NOCOPYBITS
|
509 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_DEFERERASE
;
511 // If the style is not popup, you have to convert the point to client
513 POINT point
= { rect
.x(), rect
.y() };
514 if (GetStyle() & WS_CHILD
)
515 ScreenToClient(&point
);
517 SetWindowPos(NULL
, point
.x
, point
.y
, rect
.width(), rect
.height(), swp_flags
);
518 render_widget_host_
->WasResized();
521 gfx::NativeView
RenderWidgetHostViewWin::GetNativeView() const {
525 gfx::NativeViewId
RenderWidgetHostViewWin::GetNativeViewId() const {
526 return reinterpret_cast<gfx::NativeViewId
>(m_hWnd
);
529 gfx::NativeViewAccessible
530 RenderWidgetHostViewWin::GetNativeViewAccessible() {
531 if (render_widget_host_
&&
532 !BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) {
533 // Attempt to detect screen readers by sending an event with our custom id.
534 NotifyWinEvent(EVENT_SYSTEM_ALERT
, m_hWnd
, kIdCustom
, CHILDID_SELF
);
537 CreateBrowserAccessibilityManagerIfNeeded();
539 return GetBrowserAccessibilityManager()->GetRoot()->
540 ToBrowserAccessibilityWin();
543 void RenderWidgetHostViewWin::CreateBrowserAccessibilityManagerIfNeeded() {
544 if (GetBrowserAccessibilityManager())
547 HRESULT hr
= ::CreateStdAccessibleObject(
548 m_hWnd
, OBJID_WINDOW
, IID_IAccessible
,
549 reinterpret_cast<void **>(&window_iaccessible_
));
550 DCHECK(SUCCEEDED(hr
));
552 SetBrowserAccessibilityManager(
553 new BrowserAccessibilityManagerWin(
555 window_iaccessible_
.get(),
556 BrowserAccessibilityManagerWin::GetEmptyDocument(),
560 void RenderWidgetHostViewWin::MovePluginWindows(
561 const gfx::Vector2d
& scroll_offset
,
562 const std::vector
<WebPluginGeometry
>& plugin_window_moves
) {
563 MovePluginWindowsHelper(m_hWnd
, plugin_window_moves
);
566 static BOOL CALLBACK
AddChildWindowToVector(HWND hwnd
, LPARAM lparam
) {
567 std::vector
<HWND
>* vector
= reinterpret_cast<std::vector
<HWND
>*>(lparam
);
568 vector
->push_back(hwnd
);
572 void RenderWidgetHostViewWin::CleanupCompositorWindow() {
573 if (!compositor_host_window_
)
576 gfx::SetWindowUserData(compositor_host_window_
, NULL
);
578 // Hide the compositor and parent it to the desktop rather than destroying
579 // it immediately. The GPU process has a grace period to stop accessing the
580 // window. TODO(apatrick): the GPU process should acknowledge that it has
581 // finished with the window handle and the browser process should destroy it
583 ::ShowWindow(compositor_host_window_
, SW_HIDE
);
584 ::SetParent(compositor_host_window_
, NULL
);
586 BrowserThread::PostDelayedTask(
589 base::Bind(base::IgnoreResult(&::DestroyWindow
),
590 compositor_host_window_
),
591 base::TimeDelta::FromMilliseconds(kDestroyCompositorHostWindowDelay
));
593 compositor_host_window_
= NULL
;
596 bool RenderWidgetHostViewWin::IsActivatable() const {
597 // Popups should not be activated.
598 return popup_type_
== blink::WebPopupTypeNone
;
601 void RenderWidgetHostViewWin::Focus() {
606 void RenderWidgetHostViewWin::Blur() {
610 bool RenderWidgetHostViewWin::HasFocus() const {
611 return ::GetFocus() == m_hWnd
;
614 bool RenderWidgetHostViewWin::IsSurfaceAvailableForCopy() const {
615 if (render_widget_host_
->is_accelerated_compositing_active())
616 return accelerated_surface_
.get() && accelerated_surface_
->IsReadyForCopy();
618 return !!render_widget_host_
->GetBackingStore(false);
621 void RenderWidgetHostViewWin::Show() {
626 void RenderWidgetHostViewWin::Hide() {
627 if (!is_fullscreen_
&& GetParent() == gfx::GetWindowToParentTo(true)) {
628 LOG(WARNING
) << "Hide() called twice in a row: " << this << ":"
633 if (::GetFocus() == m_hWnd
)
640 bool RenderWidgetHostViewWin::IsShowing() {
641 return !!IsWindowVisible();
644 gfx::Rect
RenderWidgetHostViewWin::GetViewBounds() const {
645 return gfx::win::ScreenToDIPRect(GetPixelBounds());
648 gfx::Rect
RenderWidgetHostViewWin::GetPixelBounds() const {
650 GetWindowRect(&window_rect
);
651 return gfx::Rect(window_rect
);
654 void RenderWidgetHostViewWin::UpdateCursor(const WebCursor
& cursor
) {
655 current_cursor_
= cursor
;
656 UpdateCursorIfOverSelf();
659 void RenderWidgetHostViewWin::UpdateCursorIfOverSelf() {
660 static HCURSOR kCursorArrow
= LoadCursor(NULL
, IDC_ARROW
);
661 static HCURSOR kCursorAppStarting
= LoadCursor(NULL
, IDC_APPSTARTING
);
662 static HINSTANCE module_handle
= GetModuleHandle(
663 GetContentClient()->browser()->GetResourceDllName());
665 // If the mouse is over our HWND, then update the cursor state immediately.
668 if (WindowFromPoint(pt
) == m_hWnd
) {
669 // We cannot pass in NULL as the module handle as this would only work for
670 // standard win32 cursors. We can also receive cursor types which are
671 // defined as webkit resources. We need to specify the module handle of
672 // chrome.dll while loading these cursors.
673 HCURSOR display_cursor
= current_cursor_
.GetCursor(module_handle
);
675 // If a page is in the loading state, we want to show the Arrow+Hourglass
676 // cursor only when the current cursor is the ARROW cursor. In all other
677 // cases we should continue to display the current cursor.
678 if (is_loading_
&& display_cursor
== kCursorArrow
)
679 display_cursor
= kCursorAppStarting
;
681 SetCursor(display_cursor
);
685 void RenderWidgetHostViewWin::SetIsLoading(bool is_loading
) {
686 is_loading_
= is_loading
;
687 UpdateCursorIfOverSelf();
690 void RenderWidgetHostViewWin::TextInputTypeChanged(
691 ui::TextInputType type
,
692 ui::TextInputMode input_mode
,
693 bool can_compose_inline
) {
694 if (text_input_type_
!= type
||
695 text_input_mode_
!= input_mode
||
696 can_compose_inline_
!= can_compose_inline
) {
697 const bool text_input_type_changed
= (text_input_type_
!= type
) ||
698 (text_input_mode_
!= input_mode
);
699 text_input_type_
= type
;
700 text_input_mode_
= input_mode
;
701 can_compose_inline_
= can_compose_inline
;
703 if (text_input_type_changed
)
704 UpdateInputScopeIfNecessary(text_input_type_
);
708 void RenderWidgetHostViewWin::SelectionBoundsChanged(
709 const ViewHostMsg_SelectionBounds_Params
& params
) {
710 bool is_enabled
= (text_input_type_
!= ui::TEXT_INPUT_TYPE_NONE
&&
711 text_input_type_
!= ui::TEXT_INPUT_TYPE_PASSWORD
);
712 // Only update caret position if the input method is enabled.
714 caret_rect_
= gfx::UnionRects(params
.anchor_rect
, params
.focus_rect
);
715 imm32_manager_
->UpdateCaretRect(m_hWnd
, caret_rect_
);
719 void RenderWidgetHostViewWin::ScrollOffsetChanged() {
722 void RenderWidgetHostViewWin::ImeCancelComposition() {
723 imm32_manager_
->CancelIME(m_hWnd
);
726 void RenderWidgetHostViewWin::ImeCompositionRangeChanged(
727 const gfx::Range
& range
,
728 const std::vector
<gfx::Rect
>& character_bounds
) {
729 composition_range_
= range
;
730 composition_character_bounds_
= character_bounds
;
733 void RenderWidgetHostViewWin::Redraw() {
735 GetUpdateRect(&damage_bounds
, FALSE
);
737 base::win::ScopedGDIObject
<HRGN
> damage_region(CreateRectRgn(0, 0, 0, 0));
738 GetUpdateRgn(damage_region
, FALSE
);
740 // Paint the invalid region synchronously. Our caller will not paint again
741 // until we return, so by painting to the screen here, we ensure effective
742 // rate-limiting of backing store updates. This helps a lot on pages that
743 // have animations or fairly expensive layout (e.g., google maps).
745 // We paint this window synchronously, however child windows (i.e. plugins)
746 // are painted asynchronously. By avoiding synchronous cross-process window
747 // message dispatching we allow scrolling to be smooth, and also avoid the
748 // browser process locking up if the plugin process is hung.
750 RedrawWindow(NULL
, damage_region
, RDW_UPDATENOW
| RDW_NOCHILDREN
);
752 // Send the invalid rect in screen coordinates.
753 gfx::Rect
invalid_screen_rect(damage_bounds
);
754 invalid_screen_rect
.Offset(GetPixelBounds().OffsetFromOrigin());
756 PaintPluginWindowsHelper(m_hWnd
, invalid_screen_rect
);
759 void RenderWidgetHostViewWin::DidUpdateBackingStore(
760 const gfx::Rect
& scroll_rect
,
761 const gfx::Vector2d
& scroll_delta
,
762 const std::vector
<gfx::Rect
>& copy_rects
,
763 const ui::LatencyInfo
& latency_info
) {
764 TRACE_EVENT0("content", "RenderWidgetHostViewWin::DidUpdateBackingStore");
765 software_latency_info_
.MergeWith(latency_info
);
766 if (render_widget_host_
->is_hidden())
769 // Schedule invalidations first so that the ScrollWindowEx call is closer to
770 // Redraw. That minimizes chances of "flicker" resulting if the screen
771 // refreshes before we have a chance to paint the exposed area. Somewhat
772 // surprisingly, this ordering matters.
774 for (size_t i
= 0; i
< copy_rects
.size(); ++i
) {
775 gfx::Rect pixel_rect
= gfx::win::DIPToScreenRect(copy_rects
[i
]);
776 // Damage might not be DIP aligned.
777 pixel_rect
.Inset(-1, -1);
778 RECT bounds
= pixel_rect
.ToRECT();
779 InvalidateRect(&bounds
, false);
782 if (!scroll_rect
.IsEmpty()) {
783 TRACE_EVENT0("content", "ScrollWindowEx");
784 gfx::Rect pixel_rect
= gfx::win::DIPToScreenRect(scroll_rect
);
785 // Damage might not be DIP aligned.
786 pixel_rect
.Inset(-1, -1);
787 RECT clip_rect
= pixel_rect
.ToRECT();
788 float scale
= gfx::win::GetDeviceScaleFactor();
789 int dx
= static_cast<int>(scale
* scroll_delta
.x());
790 int dy
= static_cast<int>(scale
* scroll_delta
.y());
791 ScrollWindowEx(dx
, dy
, NULL
, &clip_rect
, NULL
, NULL
, SW_INVALIDATE
);
794 if (!about_to_validate_and_paint_
)
798 void RenderWidgetHostViewWin::RenderProcessGone(base::TerminationStatus status
,
800 UpdateCursorIfOverSelf();
804 bool RenderWidgetHostViewWin::CanSubscribeFrame() const {
805 return render_widget_host_
!= NULL
;
808 void RenderWidgetHostViewWin::WillWmDestroy() {
809 CleanupCompositorWindow();
810 if (base::win::IsTSFAwareRequired())
811 ui::TSFBridge::GetInstance()->RemoveFocusedClient(this);
814 void RenderWidgetHostViewWin::Destroy() {
815 // We've been told to destroy.
816 // By clearing close_on_deactivate_, we prevent further deactivations
817 // (caused by windows messages resulting from the DestroyWindow) from
818 // triggering further destructions. The deletion of this is handled by
820 close_on_deactivate_
= false;
821 render_widget_host_
= NULL
;
822 being_destroyed_
= true;
823 CleanupCompositorWindow();
825 // This releases the resources associated with input scope.
826 UpdateInputScopeIfNecessary(ui::TEXT_INPUT_TYPE_NONE
);
828 if (is_fullscreen_
&& win8::IsSingleWindowMetroMode()) {
829 MetroCloseFrameWindow close_frame_window
=
830 reinterpret_cast<MetroCloseFrameWindow
>(
831 ::GetProcAddress(base::win::GetMetroModule(), "CloseFrameWindow"));
832 DCHECK(close_frame_window
);
833 close_frame_window(m_hWnd
);
839 void RenderWidgetHostViewWin::SetTooltipText(
840 const base::string16
& tooltip_text
) {
841 if (!render_widget_host_
->is_hidden())
844 // Clamp the tooltip length to kMaxTooltipLength so that we don't
845 // accidentally DOS the user with a mega tooltip (since Windows doesn't seem
846 // to do this itself).
847 const base::string16 new_tooltip_text
=
848 gfx::TruncateString(tooltip_text
, kMaxTooltipLength
);
850 if (new_tooltip_text
!= tooltip_text_
) {
851 tooltip_text_
= new_tooltip_text
;
853 // Need to check if the tooltip is already showing so that we don't
854 // immediately show the tooltip with no delay when we move the mouse from
855 // a region with no tooltip to a region with a tooltip.
856 if (::IsWindow(tooltip_hwnd_
) && tooltip_showing_
) {
857 ::SendMessage(tooltip_hwnd_
, TTM_POP
, 0, 0);
858 ::SendMessage(tooltip_hwnd_
, TTM_POPUP
, 0, 0);
861 // Make sure the tooltip gets closed after TTN_POP gets sent. For some
862 // reason this doesn't happen automatically, so moving the mouse around
863 // within the same link/image/etc doesn't cause the tooltip to re-appear.
864 if (!tooltip_showing_
) {
865 if (::IsWindow(tooltip_hwnd_
))
866 ::SendMessage(tooltip_hwnd_
, TTM_POP
, 0, 0);
871 BackingStore
* RenderWidgetHostViewWin::AllocBackingStore(
872 const gfx::Size
& size
) {
873 return new BackingStoreWin(render_widget_host_
, size
);
876 void RenderWidgetHostViewWin::CopyFromCompositingSurface(
877 const gfx::Rect
& src_subrect
,
878 const gfx::Size
& dst_size
,
879 const base::Callback
<void(bool, const SkBitmap
&)>& callback
) {
880 base::ScopedClosureRunner
scoped_callback_runner(
881 base::Bind(callback
, false, SkBitmap()));
882 if (!accelerated_surface_
)
885 if (dst_size
.IsEmpty() || src_subrect
.IsEmpty())
888 ignore_result(scoped_callback_runner
.Release());
889 accelerated_surface_
->AsyncCopyTo(src_subrect
, dst_size
, callback
);
892 void RenderWidgetHostViewWin::CopyFromCompositingSurfaceToVideoFrame(
893 const gfx::Rect
& src_subrect
,
894 const scoped_refptr
<media::VideoFrame
>& target
,
895 const base::Callback
<void(bool)>& callback
) {
896 base::ScopedClosureRunner
scoped_callback_runner(base::Bind(callback
, false));
897 if (!accelerated_surface_
)
900 if (!target
|| (target
->format() != media::VideoFrame::YV12
&&
901 target
->format() != media::VideoFrame::I420
))
904 if (src_subrect
.IsEmpty())
907 ignore_result(scoped_callback_runner
.Release());
908 accelerated_surface_
->AsyncCopyToVideoFrame(src_subrect
, target
, callback
);
911 bool RenderWidgetHostViewWin::CanCopyToVideoFrame() const {
912 return accelerated_surface_
.get() && render_widget_host_
&&
913 render_widget_host_
->is_accelerated_compositing_active();
916 void RenderWidgetHostViewWin::SetBackground(const SkBitmap
& background
) {
917 RenderWidgetHostViewBase::SetBackground(background
);
918 render_widget_host_
->SetBackground(background
);
921 void RenderWidgetHostViewWin::ProcessAckedTouchEvent(
922 const TouchEventWithLatencyInfo
& touch
, InputEventAckState ack_result
) {
923 DCHECK(touch_events_enabled_
);
925 ScopedVector
<ui::TouchEvent
> events
;
926 if (!MakeUITouchEventsFromWebTouchEvents(touch
, &events
, LOCAL_COORDINATES
))
929 ui::EventResult result
= (ack_result
==
930 INPUT_EVENT_ACK_STATE_CONSUMED
) ? ui::ER_HANDLED
: ui::ER_UNHANDLED
;
931 for (ScopedVector
<ui::TouchEvent
>::iterator iter
= events
.begin(),
932 end
= events
.end(); iter
!= end
; ++iter
) {
933 scoped_ptr
<ui::GestureRecognizer::Gestures
> gestures
;
934 gestures
.reset(gesture_recognizer_
->ProcessTouchEventForGesture(
935 *(*iter
), result
, this));
936 ProcessGestures(gestures
.get());
940 void RenderWidgetHostViewWin::UpdateDesiredTouchMode() {
941 // Make sure that touch events even make sense.
942 if (base::win::GetVersion() < base::win::VERSION_WIN7
)
944 if (touch_events_enabled_
) {
945 CHECK(RegisterTouchWindow(m_hWnd
, TWF_WANTPALM
));
949 bool RenderWidgetHostViewWin::CanDispatchToConsumer(
950 ui::GestureConsumer
* consumer
) {
951 CHECK_EQ(static_cast<RenderWidgetHostViewWin
*>(consumer
), this);
955 void RenderWidgetHostViewWin::DispatchPostponedGestureEvent(
956 ui::GestureEvent
* event
) {
957 ForwardGestureEventToRenderer(event
);
960 void RenderWidgetHostViewWin::DispatchCancelTouchEvent(
961 ui::TouchEvent
* event
) {
962 if (!render_widget_host_
|| !touch_events_enabled_
||
963 !render_widget_host_
->ShouldForwardTouchEvent()) {
966 DCHECK(event
->type() == blink::WebInputEvent::TouchCancel
);
967 blink::WebTouchEvent cancel_event
;
968 cancel_event
.type
= blink::WebInputEvent::TouchCancel
;
969 cancel_event
.timeStampSeconds
= event
->time_stamp().InSecondsF();
970 render_widget_host_
->ForwardTouchEventWithLatencyInfo(
971 cancel_event
, *event
->latency());
974 void RenderWidgetHostViewWin::SetHasHorizontalScrollbar(
975 bool has_horizontal_scrollbar
) {
978 void RenderWidgetHostViewWin::SetScrollOffsetPinning(
979 bool is_pinned_to_left
, bool is_pinned_to_right
) {
982 void RenderWidgetHostViewWin::SetCompositionText(
983 const ui::CompositionText
& composition
) {
984 if (!base::win::IsTSFAwareRequired()) {
988 if (!render_widget_host_
)
990 // ui::CompositionUnderline should be identical to
991 // blink::WebCompositionUnderline, so that we can do reinterpret_cast safely.
992 COMPILE_ASSERT(sizeof(ui::CompositionUnderline
) ==
993 sizeof(blink::WebCompositionUnderline
),
994 ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff
);
995 const std::vector
<blink::WebCompositionUnderline
>& underlines
=
996 reinterpret_cast<const std::vector
<blink::WebCompositionUnderline
>&>(
997 composition
.underlines
);
998 render_widget_host_
->ImeSetComposition(composition
.text
, underlines
,
999 composition
.selection
.end(),
1000 composition
.selection
.end());
1003 void RenderWidgetHostViewWin::ConfirmCompositionText() {
1004 if (!base::win::IsTSFAwareRequired()) {
1008 // TODO(nona): Implement this function.
1012 void RenderWidgetHostViewWin::ClearCompositionText() {
1013 if (!base::win::IsTSFAwareRequired()) {
1017 // TODO(nona): Implement this function.
1021 void RenderWidgetHostViewWin::InsertText(const base::string16
& text
) {
1022 if (!base::win::IsTSFAwareRequired()) {
1026 if (render_widget_host_
)
1027 render_widget_host_
->ImeConfirmComposition(text
,
1028 gfx::Range::InvalidRange(),
1032 void RenderWidgetHostViewWin::InsertChar(char16 ch
, int flags
) {
1033 if (!base::win::IsTSFAwareRequired()) {
1037 // TODO(nona): Implement this function.
1041 gfx::NativeWindow
RenderWidgetHostViewWin::GetAttachedWindow() const {
1045 ui::TextInputType
RenderWidgetHostViewWin::GetTextInputType() const {
1046 if (!base::win::IsTSFAwareRequired()) {
1048 return ui::TEXT_INPUT_TYPE_NONE
;
1050 return text_input_type_
;
1053 ui::TextInputMode
RenderWidgetHostViewWin::GetTextInputMode() const {
1054 if (!base::win::IsTSFAwareRequired()) {
1056 return ui::TEXT_INPUT_MODE_DEFAULT
;
1058 return text_input_mode_
;
1061 bool RenderWidgetHostViewWin::CanComposeInline() const {
1062 if (!base::win::IsTSFAwareRequired()) {
1066 // TODO(nona): Implement this function.
1071 gfx::Rect
RenderWidgetHostViewWin::GetCaretBounds() const {
1072 if (!base::win::IsTSFAwareRequired()) {
1074 return gfx::Rect(0, 0, 0, 0);
1076 RECT tmp_rect
= caret_rect_
.ToRECT();
1077 ClientToScreen(&tmp_rect
);
1078 return gfx::Rect(tmp_rect
);
1081 bool RenderWidgetHostViewWin::GetCompositionCharacterBounds(
1082 uint32 index
, gfx::Rect
* rect
) const {
1083 if (!base::win::IsTSFAwareRequired()) {
1088 if (index
>= composition_character_bounds_
.size())
1090 RECT rec
= composition_character_bounds_
[index
].ToRECT();
1091 ClientToScreen(&rec
);
1092 *rect
= gfx::Rect(rec
);
1096 bool RenderWidgetHostViewWin::HasCompositionText() const {
1097 if (!base::win::IsTSFAwareRequired()) {
1101 // TODO(nona): Implement this function.
1106 bool RenderWidgetHostViewWin::GetTextRange(gfx::Range
* range
) const {
1107 if (!base::win::IsTSFAwareRequired()) {
1111 range
->set_start(selection_text_offset_
);
1112 range
->set_end(selection_text_offset_
+ selection_text_
.length());
1116 bool RenderWidgetHostViewWin::GetCompositionTextRange(gfx::Range
* range
) const {
1117 if (!base::win::IsTSFAwareRequired()) {
1121 // TODO(nona): Implement this function.
1126 bool RenderWidgetHostViewWin::GetSelectionRange(gfx::Range
* range
) const {
1127 if (!base::win::IsTSFAwareRequired()) {
1131 range
->set_start(selection_range_
.start());
1132 range
->set_end(selection_range_
.end());
1136 bool RenderWidgetHostViewWin::SetSelectionRange(const gfx::Range
& range
) {
1137 if (!base::win::IsTSFAwareRequired()) {
1141 // TODO(nona): Implement this function.
1146 bool RenderWidgetHostViewWin::DeleteRange(const gfx::Range
& range
) {
1147 if (!base::win::IsTSFAwareRequired()) {
1151 // TODO(nona): Implement this function.
1156 bool RenderWidgetHostViewWin::GetTextFromRange(const gfx::Range
& range
,
1157 base::string16
* text
) const {
1158 if (!base::win::IsTSFAwareRequired()) {
1162 gfx::Range
selection_text_range(selection_text_offset_
,
1163 selection_text_offset_
+ selection_text_
.length());
1164 if (!selection_text_range
.Contains(range
)) {
1168 if (selection_text_range
.EqualsIgnoringDirection(range
)) {
1169 *text
= selection_text_
;
1171 *text
= selection_text_
.substr(
1172 range
.GetMin() - selection_text_offset_
,
1178 void RenderWidgetHostViewWin::OnInputMethodChanged() {
1179 if (!base::win::IsTSFAwareRequired()) {
1183 // TODO(nona): Implement this function.
1187 bool RenderWidgetHostViewWin::ChangeTextDirectionAndLayoutAlignment(
1188 base::i18n::TextDirection direction
) {
1189 if (!base::win::IsTSFAwareRequired()) {
1193 // TODO(nona): Implement this function.
1198 void RenderWidgetHostViewWin::ExtendSelectionAndDelete(
1201 if (!base::win::IsTSFAwareRequired()) {
1205 if (!render_widget_host_
)
1207 render_widget_host_
->ExtendSelectionAndDelete(before
, after
);
1210 void RenderWidgetHostViewWin::EnsureCaretInRect(const gfx::Rect
& rect
) {
1211 // TODO(nona): Implement this function.
1215 void RenderWidgetHostViewWin::OnCandidateWindowShown() {
1218 void RenderWidgetHostViewWin::OnCandidateWindowUpdated() {
1221 void RenderWidgetHostViewWin::OnCandidateWindowHidden() {
1224 ///////////////////////////////////////////////////////////////////////////////
1225 // RenderWidgetHostViewWin, private:
1227 LRESULT
RenderWidgetHostViewWin::OnCreate(CREATESTRUCT
* create_struct
) {
1228 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnCreate");
1229 // Call the WM_INPUTLANGCHANGE message handler to initialize the input locale
1230 // of a browser process.
1231 OnInputLangChange(0, 0);
1232 // Marks that window as supporting mouse-wheel messages rerouting so it is
1233 // scrolled when under the mouse pointer even if inactive.
1234 props_
.push_back(ui::SetWindowSupportsRerouteMouseWheel(m_hWnd
));
1236 WTSRegisterSessionNotification(m_hWnd
, NOTIFY_FOR_THIS_SESSION
);
1238 UpdateDesiredTouchMode();
1244 void RenderWidgetHostViewWin::OnActivate(UINT action
, BOOL minimized
,
1246 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnActivate");
1247 // If the container is a popup, clicking elsewhere on screen should close the
1249 if (close_on_deactivate_
&& action
== WA_INACTIVE
) {
1250 // Send a windows message so that any derived classes
1251 // will get a change to override the default handling
1252 SendMessage(WM_CANCELMODE
);
1256 void RenderWidgetHostViewWin::OnDestroy() {
1257 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnDestroy");
1258 DetachPluginsHelper(m_hWnd
);
1262 if (base::win::GetVersion() >= base::win::VERSION_WIN7
&&
1263 IsTouchWindow(m_hWnd
, NULL
)) {
1264 UnregisterTouchWindow(m_hWnd
);
1267 CleanupCompositorWindow();
1269 WTSUnRegisterSessionNotification(m_hWnd
);
1272 TrackMouseLeave(false);
1275 void RenderWidgetHostViewWin::OnPaint(HDC unused_dc
) {
1276 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnPaint");
1278 // Grab the region to paint before creation of paint_dc since it clears the
1280 base::win::ScopedGDIObject
<HRGN
> damage_region(CreateRectRgn(0, 0, 0, 0));
1281 GetUpdateRgn(damage_region
, FALSE
);
1283 CPaintDC
paint_dc(m_hWnd
);
1285 if (!render_widget_host_
)
1288 DCHECK(render_widget_host_
->GetProcess()->HasConnection());
1290 // If the GPU process is rendering to a child window, compositing is
1291 // already triggered by damage to compositor_host_window_, so all we need to
1292 // do here is clear borders during resize.
1293 if (compositor_host_window_
&&
1294 render_widget_host_
->is_accelerated_compositing_active()) {
1295 RECT host_rect
, child_rect
;
1296 GetClientRect(&host_rect
);
1297 if (::GetClientRect(compositor_host_window_
, &child_rect
) &&
1298 (child_rect
.right
< host_rect
.right
||
1299 child_rect
.bottom
< host_rect
.bottom
)) {
1300 paint_dc
.FillRect(&host_rect
,
1301 reinterpret_cast<HBRUSH
>(GetStockObject(WHITE_BRUSH
)));
1306 if (accelerated_surface_
.get() &&
1307 render_widget_host_
->is_accelerated_compositing_active()) {
1308 AcceleratedPaint(paint_dc
.m_hDC
);
1312 about_to_validate_and_paint_
= true;
1313 BackingStoreWin
* backing_store
= static_cast<BackingStoreWin
*>(
1314 render_widget_host_
->GetBackingStore(true));
1316 // We initialize |paint_dc| (and thus call BeginPaint()) after calling
1317 // GetBackingStore(), so that if it updates the invalid rect we'll catch the
1318 // changes and repaint them.
1319 about_to_validate_and_paint_
= false;
1321 if (compositor_host_window_
&& hide_compositor_window_at_next_paint_
) {
1322 ::ShowWindow(compositor_host_window_
, SW_HIDE
);
1323 hide_compositor_window_at_next_paint_
= false;
1326 gfx::Rect
damaged_rect(paint_dc
.m_ps
.rcPaint
);
1327 if (damaged_rect
.IsEmpty())
1330 if (backing_store
) {
1331 gfx::Rect
bitmap_rect(gfx::Point(),
1332 gfx::win::DIPToScreenSize(backing_store
->size()));
1334 bool manage_colors
= BackingStoreWin::ColorManagementEnabled();
1336 SetICMMode(paint_dc
.m_hDC
, ICM_ON
);
1338 // Blit only the damaged regions from the backing store.
1339 DWORD data_size
= GetRegionData(damage_region
, 0, NULL
);
1340 scoped_ptr
<char[]> region_data_buf
;
1341 RGNDATA
* region_data
= NULL
;
1342 RECT
* region_rects
= NULL
;
1345 region_data_buf
.reset(new char[data_size
]);
1346 region_data
= reinterpret_cast<RGNDATA
*>(region_data_buf
.get());
1347 region_rects
= reinterpret_cast<RECT
*>(region_data
->Buffer
);
1348 data_size
= GetRegionData(damage_region
, data_size
, region_data
);
1352 // Grabbing the damaged regions failed, fake with the whole rect.
1353 data_size
= sizeof(RGNDATAHEADER
) + sizeof(RECT
);
1354 region_data_buf
.reset(new char[data_size
]);
1355 region_data
= reinterpret_cast<RGNDATA
*>(region_data_buf
.get());
1356 region_rects
= reinterpret_cast<RECT
*>(region_data
->Buffer
);
1357 region_data
->rdh
.nCount
= 1;
1358 region_rects
[0] = damaged_rect
.ToRECT();
1361 for (DWORD i
= 0; i
< region_data
->rdh
.nCount
; ++i
) {
1362 gfx::Rect paint_rect
=
1363 gfx::IntersectRects(bitmap_rect
, gfx::Rect(region_rects
[i
]));
1364 if (!paint_rect
.IsEmpty()) {
1365 BitBlt(paint_dc
.m_hDC
,
1369 paint_rect
.height(),
1370 backing_store
->hdc(),
1378 SetICMMode(paint_dc
.m_hDC
, ICM_OFF
);
1380 // Fill the remaining portion of the damaged_rect with the background
1381 if (damaged_rect
.right() > bitmap_rect
.right()) {
1383 r
.left
= std::max(bitmap_rect
.right(), damaged_rect
.x());
1384 r
.right
= damaged_rect
.right();
1385 r
.top
= damaged_rect
.y();
1386 r
.bottom
= std::min(bitmap_rect
.bottom(), damaged_rect
.bottom());
1387 DrawBackground(r
, &paint_dc
);
1389 if (damaged_rect
.bottom() > bitmap_rect
.bottom()) {
1391 r
.left
= damaged_rect
.x();
1392 r
.right
= damaged_rect
.right();
1393 r
.top
= std::max(bitmap_rect
.bottom(), damaged_rect
.y());
1394 r
.bottom
= damaged_rect
.bottom();
1395 DrawBackground(r
, &paint_dc
);
1397 if (!whiteout_start_time_
.is_null()) {
1398 TimeDelta whiteout_duration
= TimeTicks::Now() - whiteout_start_time_
;
1399 UMA_HISTOGRAM_TIMES("MPArch.RWHH_WhiteoutDuration", whiteout_duration
);
1401 // Reset the start time to 0 so that we start recording again the next
1402 // time the backing store is NULL...
1403 whiteout_start_time_
= TimeTicks();
1405 if (!web_contents_switch_paint_time_
.is_null()) {
1406 TimeDelta web_contents_switch_paint_duration
= TimeTicks::Now() -
1407 web_contents_switch_paint_time_
;
1408 UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration",
1409 web_contents_switch_paint_duration
);
1410 // Reset contents_switch_paint_time_ to 0 so future tab selections are
1412 web_contents_switch_paint_time_
= TimeTicks();
1415 software_latency_info_
.AddLatencyNumber(
1416 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT
, 0, 0);
1417 render_widget_host_
->FrameSwapped(software_latency_info_
);
1418 software_latency_info_
.Clear();
1420 DrawBackground(paint_dc
.m_ps
.rcPaint
, &paint_dc
);
1421 if (whiteout_start_time_
.is_null())
1422 whiteout_start_time_
= TimeTicks::Now();
1426 void RenderWidgetHostViewWin::DrawBackground(const RECT
& dirty_rect
,
1428 if (!background_
.empty()) {
1429 gfx::Rect
dirty_area(dirty_rect
);
1430 gfx::Canvas
canvas(dirty_area
.size(), 1.0f
, true);
1431 canvas
.Translate(-dirty_area
.OffsetFromOrigin());
1433 gfx::Rect
dc_rect(dc
->m_ps
.rcPaint
);
1434 // TODO(pkotwicz): Fix |background_| such that it is an ImageSkia.
1435 canvas
.TileImageInt(gfx::ImageSkia::CreateFrom1xBitmap(background_
),
1436 0, 0, dc_rect
.width(), dc_rect
.height());
1438 skia::DrawToNativeContext(canvas
.sk_canvas(), *dc
, dirty_area
.x(),
1439 dirty_area
.y(), NULL
);
1441 HBRUSH white_brush
= reinterpret_cast<HBRUSH
>(GetStockObject(WHITE_BRUSH
));
1442 dc
->FillRect(&dirty_rect
, white_brush
);
1446 void RenderWidgetHostViewWin::OnNCPaint(HRGN update_region
) {
1447 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnNCPaint");
1448 // Do nothing. This suppresses the resize corner that Windows would
1449 // otherwise draw for us.
1452 void RenderWidgetHostViewWin::SetClickthroughRegion(SkRegion
* region
) {
1453 transparent_region_
.reset(region
);
1456 LRESULT
RenderWidgetHostViewWin::OnNCHitTest(const CPoint
& point
) {
1457 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnNCHitTest");
1460 if (transparent_region_
.get() &&
1461 transparent_region_
->contains(point
.x
- rc
.left
, point
.y
- rc
.top
)) {
1462 SetMsgHandled(TRUE
);
1463 return HTTRANSPARENT
;
1465 SetMsgHandled(FALSE
);
1469 LRESULT
RenderWidgetHostViewWin::OnEraseBkgnd(HDC dc
) {
1470 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnEraseBkgnd");
1474 LRESULT
RenderWidgetHostViewWin::OnSetCursor(HWND window
, UINT hittest_code
,
1475 UINT mouse_message_id
) {
1476 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSetCursor");
1477 UpdateCursorIfOverSelf();
1481 void RenderWidgetHostViewWin::OnSetFocus(HWND window
) {
1482 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSetFocus");
1483 if (!render_widget_host_
)
1486 if (GetBrowserAccessibilityManager())
1487 GetBrowserAccessibilityManager()->GotFocus(pointer_down_context_
);
1489 render_widget_host_
->GotFocus();
1490 render_widget_host_
->SetActive(true);
1492 if (base::win::IsTSFAwareRequired())
1493 ui::TSFBridge::GetInstance()->SetFocusedClient(m_hWnd
, this);
1496 void RenderWidgetHostViewWin::OnKillFocus(HWND window
) {
1497 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnKillFocus");
1498 if (!render_widget_host_
)
1501 render_widget_host_
->SetActive(false);
1502 render_widget_host_
->Blur();
1504 last_touch_location_
= gfx::Point(-1, -1);
1506 if (base::win::IsTSFAwareRequired())
1507 ui::TSFBridge::GetInstance()->RemoveFocusedClient(this);
1510 void RenderWidgetHostViewWin::OnCaptureChanged(HWND window
) {
1511 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnCaptureChanged");
1512 if (render_widget_host_
)
1513 render_widget_host_
->LostCapture();
1514 pointer_down_context_
= false;
1517 void RenderWidgetHostViewWin::OnCancelMode() {
1518 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnCancelMode");
1519 if (render_widget_host_
)
1520 render_widget_host_
->LostCapture();
1522 if ((is_fullscreen_
|| close_on_deactivate_
) &&
1523 !weak_factory_
.HasWeakPtrs()) {
1524 // Dismiss popups and menus. We do this asynchronously to avoid changing
1525 // activation within this callstack, which may interfere with another window
1526 // being activated. We can synchronously hide the window, but we need to
1527 // not change activation while doing so.
1528 SetWindowPos(NULL
, 0, 0, 0, 0,
1529 SWP_HIDEWINDOW
| SWP_NOACTIVATE
| SWP_NOMOVE
|
1530 SWP_NOREPOSITION
| SWP_NOSIZE
| SWP_NOZORDER
);
1531 base::MessageLoop::current()->PostTask(
1533 base::Bind(&RenderWidgetHostViewWin::ShutdownHost
,
1534 weak_factory_
.GetWeakPtr()));
1538 void RenderWidgetHostViewWin::OnInputLangChange(DWORD character_set
,
1539 HKL input_language_id
) {
1540 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnInputLangChange");
1541 // Send the given Locale ID to the IMM32Manager object and retrieves whether
1542 // or not the current input context has IMEs.
1543 // If the current input context has IMEs, a browser process has to send a
1544 // request to a renderer process that it needs status messages about
1545 // the focused edit control from the renderer process.
1546 // On the other hand, if the current input context does not have IMEs, the
1547 // browser process also has to send a request to the renderer process that
1548 // it does not need the status messages any longer.
1549 // To minimize the number of this notification request, we should check if
1550 // the browser process is actually retrieving the status messages (this
1551 // state is stored in ime_notification_) and send a request only if the
1552 // browser process has to update this status, its details are listed below:
1553 // * If a browser process is not retrieving the status messages,
1554 // (i.e. ime_notification_ == false),
1555 // send this request only if the input context does have IMEs,
1556 // (i.e. ime_status == true);
1557 // When it successfully sends the request, toggle its notification status,
1558 // (i.e.ime_notification_ = !ime_notification_ = true).
1559 // * If a browser process is retrieving the status messages
1560 // (i.e. ime_notification_ == true),
1561 // send this request only if the input context does not have IMEs,
1562 // (i.e. ime_status == false).
1563 // When it successfully sends the request, toggle its notification status,
1564 // (i.e.ime_notification_ = !ime_notification_ = false).
1565 // To analyze the above actions, we can optimize them into the ones
1567 // 1 Sending a request only if ime_status_ != ime_notification_, and;
1568 // 2 Copying ime_status to ime_notification_ if it sends the request
1569 // successfully (because Action 1 shows ime_status = !ime_notification_.)
1570 bool ime_status
= imm32_manager_
->SetInputLanguage();
1571 if (ime_status
!= ime_notification_
) {
1572 if (render_widget_host_
) {
1573 render_widget_host_
->SetInputMethodActive(ime_status
);
1574 ime_notification_
= ime_status
;
1577 // Call DefWindowProc() for consistency with other Chrome windows.
1578 // TODO(hbono): This is a speculative fix for Bug 36354 and this code may be
1579 // reverted if it does not fix it.
1580 SetMsgHandled(FALSE
);
1583 void RenderWidgetHostViewWin::OnThemeChanged() {
1584 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnThemeChanged");
1585 if (!render_widget_host_
)
1587 render_widget_host_
->Send(new ViewMsg_ThemeChanged(
1588 render_widget_host_
->GetRoutingID()));
1591 LRESULT
RenderWidgetHostViewWin::OnNotify(int w_param
, NMHDR
* header
) {
1592 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnNotify");
1593 if (tooltip_hwnd_
== NULL
)
1596 switch (header
->code
) {
1597 case TTN_GETDISPINFO
: {
1598 NMTTDISPINFOW
* tooltip_info
= reinterpret_cast<NMTTDISPINFOW
*>(header
);
1599 tooltip_info
->szText
[0] = L
'\0';
1600 tooltip_info
->lpszText
= const_cast<WCHAR
*>(tooltip_text_
.c_str());
1602 tooltip_hwnd_
, TTM_SETMAXTIPWIDTH
, 0, kTooltipMaxWidthPixels
);
1603 SetMsgHandled(TRUE
);
1607 tooltip_showing_
= false;
1608 SetMsgHandled(TRUE
);
1611 // Tooltip shouldn't be shown when the mouse is locked.
1612 DCHECK(!mouse_locked_
);
1613 tooltip_showing_
= true;
1614 SetMsgHandled(TRUE
);
1620 LRESULT
RenderWidgetHostViewWin::OnImeSetContext(
1621 UINT message
, WPARAM wparam
, LPARAM lparam
, BOOL
& handled
) {
1622 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeSetContext");
1623 if (!render_widget_host_
)
1626 // We need status messages about the focused input control from a
1627 // renderer process when:
1628 // * the current input context has IMEs, and;
1629 // * an application is activated.
1630 // This seems to tell we should also check if the current input context has
1631 // IMEs before sending a request, however, this WM_IME_SETCONTEXT is
1632 // fortunately sent to an application only while the input context has IMEs.
1633 // Therefore, we just start/stop status messages according to the activation
1634 // status of this application without checks.
1635 bool activated
= (wparam
== TRUE
);
1636 if (render_widget_host_
) {
1637 render_widget_host_
->SetInputMethodActive(activated
);
1638 ime_notification_
= activated
;
1641 if (ime_notification_
)
1642 imm32_manager_
->CreateImeWindow(m_hWnd
);
1644 imm32_manager_
->CleanupComposition(m_hWnd
);
1645 return imm32_manager_
->SetImeWindowStyle(
1646 m_hWnd
, message
, wparam
, lparam
, &handled
);
1649 LRESULT
RenderWidgetHostViewWin::OnImeStartComposition(
1650 UINT message
, WPARAM wparam
, LPARAM lparam
, BOOL
& handled
) {
1651 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeStartComposition");
1652 if (!render_widget_host_
)
1655 // Reset the composition status and create IME windows.
1656 imm32_manager_
->CreateImeWindow(m_hWnd
);
1657 imm32_manager_
->ResetComposition(m_hWnd
);
1658 // When the focus is on an element that does not draw composition by itself
1659 // (i.e., PPAPI plugin not handling IME), let IME to draw the text. Otherwise
1660 // we have to prevent WTL from calling ::DefWindowProc() because the function
1661 // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
1662 // over-write the position of IME windows.
1663 handled
= (can_compose_inline_
? TRUE
: FALSE
);
1667 LRESULT
RenderWidgetHostViewWin::OnImeComposition(
1668 UINT message
, WPARAM wparam
, LPARAM lparam
, BOOL
& handled
) {
1669 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeComposition");
1670 if (!render_widget_host_
)
1673 // At first, update the position of the IME window.
1674 imm32_manager_
->UpdateImeWindow(m_hWnd
);
1676 // ui::CompositionUnderline should be identical to
1677 // blink::WebCompositionUnderline, so that we can do reinterpret_cast safely.
1678 COMPILE_ASSERT(sizeof(ui::CompositionUnderline
) ==
1679 sizeof(blink::WebCompositionUnderline
),
1680 ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff
);
1682 // Retrieve the result string and its attributes of the ongoing composition
1683 // and send it to a renderer process.
1684 ui::CompositionText composition
;
1685 if (imm32_manager_
->GetResult(m_hWnd
, lparam
, &composition
.text
)) {
1686 render_widget_host_
->ImeConfirmComposition(
1687 composition
.text
, gfx::Range::InvalidRange(), false);
1688 imm32_manager_
->ResetComposition(m_hWnd
);
1689 // Fall though and try reading the composition string.
1690 // Japanese IMEs send a message containing both GCS_RESULTSTR and
1691 // GCS_COMPSTR, which means an ongoing composition has been finished
1692 // by the start of another composition.
1694 // Retrieve the composition string and its attributes of the ongoing
1695 // composition and send it to a renderer process.
1696 if (imm32_manager_
->GetComposition(m_hWnd
, lparam
, &composition
)) {
1697 // TODO(suzhe): due to a bug of webkit, we can't use selection range with
1698 // composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788
1699 composition
.selection
= gfx::Range(composition
.selection
.end());
1701 // TODO(suzhe): convert both renderer_host and renderer to use
1702 // ui::CompositionText.
1703 const std::vector
<blink::WebCompositionUnderline
>& underlines
=
1704 reinterpret_cast<const std::vector
<blink::WebCompositionUnderline
>&>(
1705 composition
.underlines
);
1706 render_widget_host_
->ImeSetComposition(
1707 composition
.text
, underlines
,
1708 composition
.selection
.start(), composition
.selection
.end());
1710 // We have to prevent WTL from calling ::DefWindowProc() because we do not
1711 // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
1713 if (!can_compose_inline_
) {
1714 // When the focus is on an element that does not draw composition by itself
1715 // (i.e., PPAPI plugin not handling IME), let IME to draw the text, which
1716 // is the default behavior of DefWindowProc. Note, however, even in this
1717 // case we don't want GCS_RESULTSTR to be converted to WM_IME_CHAR messages.
1718 // Thus we explicitly drop the flag.
1719 return ::DefWindowProc(m_hWnd
, message
, wparam
, lparam
& ~GCS_RESULTSTR
);
1724 LRESULT
RenderWidgetHostViewWin::OnImeEndComposition(
1725 UINT message
, WPARAM wparam
, LPARAM lparam
, BOOL
& handled
) {
1726 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeEndComposition");
1727 if (!render_widget_host_
)
1730 if (imm32_manager_
->is_composing()) {
1731 // A composition has been ended while there is an ongoing composition,
1732 // i.e. the ongoing composition has been canceled.
1733 // We need to reset the composition status both of the IMM32Manager object
1734 // and of the renderer process.
1735 render_widget_host_
->ImeCancelComposition();
1736 imm32_manager_
->ResetComposition(m_hWnd
);
1738 imm32_manager_
->DestroyImeWindow(m_hWnd
);
1739 // Let WTL call ::DefWindowProc() and release its resources.
1744 LRESULT
RenderWidgetHostViewWin::OnImeRequest(
1745 UINT message
, WPARAM wparam
, LPARAM lparam
, BOOL
& handled
) {
1746 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeRequest");
1747 if (!render_widget_host_
) {
1752 // Should not receive WM_IME_REQUEST message, if IME is disabled.
1753 if (text_input_type_
== ui::TEXT_INPUT_TYPE_NONE
||
1754 text_input_type_
== ui::TEXT_INPUT_TYPE_PASSWORD
) {
1760 case IMR_RECONVERTSTRING
:
1761 return OnReconvertString(reinterpret_cast<RECONVERTSTRING
*>(lparam
));
1762 case IMR_DOCUMENTFEED
:
1763 return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING
*>(lparam
));
1764 case IMR_QUERYCHARPOSITION
:
1765 return OnQueryCharPosition(reinterpret_cast<IMECHARPOSITION
*>(lparam
));
1772 LRESULT
RenderWidgetHostViewWin::OnMouseEvent(UINT message
, WPARAM wparam
,
1773 LPARAM lparam
, BOOL
& handled
) {
1774 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnMouseEvent");
1777 if (message
== WM_MOUSELEAVE
)
1778 ignore_mouse_movement_
= true;
1780 if (mouse_locked_
) {
1781 HandleLockedMouseEvent(message
, wparam
, lparam
);
1782 MoveCursorToCenterIfNecessary();
1786 if (::IsWindow(tooltip_hwnd_
)) {
1787 // Forward mouse events through to the tooltip window
1790 msg
.message
= message
;
1791 msg
.wParam
= wparam
;
1792 msg
.lParam
= lparam
;
1793 SendMessage(tooltip_hwnd_
, TTM_RELAYEVENT
, NULL
,
1794 reinterpret_cast<LPARAM
>(&msg
));
1797 // Due to a bug in Windows, the simulated mouse events for a touch event
1798 // outside our bounds are delivered to us if we were previously focused
1799 // causing crbug.com/159982. As a workaround, we check if this event is a
1800 // simulated mouse event outside our bounds, and if so, we send it to the
1802 if ((message
== WM_LBUTTONDOWN
|| message
== WM_LBUTTONUP
) &&
1803 ui::IsMouseEventFromTouch(message
)) {
1804 CPoint
cursor_pos(GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
));
1805 ClientToScreen(&cursor_pos
);
1806 if (!GetPixelBounds().Contains(cursor_pos
.x
, cursor_pos
.y
)) {
1807 HWND window
= WindowFromPoint(cursor_pos
);
1809 LRESULT nc_hit_result
= SendMessage(window
, WM_NCHITTEST
, 0,
1810 MAKELPARAM(cursor_pos
.x
, cursor_pos
.y
));
1811 const bool in_client_area
= (nc_hit_result
== HTCLIENT
);
1813 if (message
== WM_LBUTTONDOWN
)
1814 event_type
= in_client_area
? WM_LBUTTONDOWN
: WM_NCLBUTTONDOWN
;
1816 event_type
= in_client_area
? WM_LBUTTONUP
: WM_NCLBUTTONUP
;
1818 // Convert the coordinates to the target window.
1820 ::GetWindowRect(window
, &window_bounds
);
1821 int window_x
= cursor_pos
.x
- window_bounds
.left
;
1822 int window_y
= cursor_pos
.y
- window_bounds
.top
;
1823 if (in_client_area
) {
1824 ::PostMessage(window
, event_type
, wparam
,
1825 MAKELPARAM(window_x
, window_y
));
1827 ::PostMessage(window
, event_type
, nc_hit_result
,
1828 MAKELPARAM(cursor_pos
.x
, cursor_pos
.y
));
1835 // TODO(jcampan): I am not sure if we should forward the message to the
1836 // WebContentsImpl first in the case of popups. If we do, we would need to
1837 // convert the click from the popup window coordinates to the WebContentsImpl'
1838 // window coordinates. For now we don't forward the message in that case to
1839 // address bug #907474.
1840 // Note: GetParent() on popup windows returns the top window and not the
1841 // parent the window was created with (the parent and the owner of the popup
1842 // is the first non-child view of the view that was specified to the create
1843 // call). So the WebContentsImpl's window would have to be specified to the
1844 // RenderViewHostHWND as there is no way to retrieve it from the HWND.
1846 // Don't forward if the container is a popup or fullscreen widget.
1847 if (!is_fullscreen_
&& !close_on_deactivate_
) {
1849 case WM_LBUTTONDOWN
:
1850 case WM_MBUTTONDOWN
:
1851 case WM_RBUTTONDOWN
:
1852 // Finish the ongoing composition whenever a mouse click happens.
1853 // It matches IE's behavior.
1854 if (base::win::IsTSFAwareRequired()) {
1855 ui::TSFBridge::GetInstance()->CancelComposition();
1857 imm32_manager_
->CleanupComposition(m_hWnd
);
1861 case WM_MOUSELEAVE
: {
1862 // Give the WebContentsImpl first crack at the message. It may want to
1863 // prevent forwarding to the renderer if some higher level browser
1864 // functionality is invoked.
1865 LPARAM parent_msg_lparam
= lparam
;
1866 if (message
!= WM_MOUSELEAVE
) {
1867 // For the messages except WM_MOUSELEAVE, before forwarding them to
1868 // parent window, we should adjust cursor position from client
1869 // coordinates in current window to client coordinates in its parent
1871 CPoint
cursor_pos(GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
));
1872 ClientToScreen(&cursor_pos
);
1873 GetParent().ScreenToClient(&cursor_pos
);
1874 parent_msg_lparam
= MAKELPARAM(cursor_pos
.x
, cursor_pos
.y
);
1876 if (SendMessage(GetParent(), message
, wparam
, parent_msg_lparam
) != 0) {
1877 TRACE_EVENT0("browser", "EarlyOut_SentToParent");
1884 if (message
== WM_LBUTTONDOWN
&& pointer_down_context_
&&
1885 GetBrowserAccessibilityManager()) {
1886 GetBrowserAccessibilityManager()->GotMouseDown();
1889 if (message
== WM_LBUTTONUP
&& ui::IsMouseEventFromTouch(message
) &&
1890 base::win::IsMetroProcess())
1891 pointer_down_context_
= false;
1893 ForwardMouseEventToRenderer(message
, wparam
, lparam
);
1897 LRESULT
RenderWidgetHostViewWin::OnKeyEvent(UINT message
, WPARAM wparam
,
1898 LPARAM lparam
, BOOL
& handled
) {
1899 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnKeyEvent");
1902 // When Escape is pressed, force fullscreen windows to close if necessary.
1903 if ((message
== WM_KEYDOWN
|| message
== WM_KEYUP
) && wparam
== VK_ESCAPE
) {
1904 if (is_fullscreen_
) {
1905 SendMessage(WM_CANCELMODE
);
1910 // If we are a pop-up, forward tab related messages to our parent HWND, so
1911 // that we are dismissed appropriately and so that the focus advance in our
1913 // TODO(jcampan): http://b/issue?id=1192881 Could be abstracted in the
1915 if (close_on_deactivate_
&&
1916 (((message
== WM_KEYDOWN
|| message
== WM_KEYUP
) && (wparam
== VK_TAB
)) ||
1917 (message
== WM_CHAR
&& wparam
== L
'\t'))) {
1918 // First close the pop-up.
1919 SendMessage(WM_CANCELMODE
);
1920 // Then move the focus by forwarding the tab key to the parent.
1921 return ::SendMessage(GetParent(), message
, wparam
, lparam
);
1924 if (!render_widget_host_
)
1927 // Bug 1845: we need to update the text direction when a user releases
1928 // either a right-shift key or a right-control key after pressing both of
1929 // them. So, we just update the text direction while a user is pressing the
1930 // keys, and we notify the text direction when a user releases either of them.
1931 // Bug 9718: http://crbug.com/9718 To investigate IE and notepad, this
1932 // shortcut is enabled only on a PC having RTL keyboard layouts installed.
1933 // We should emulate them.
1934 if (ui::IMM32Manager::IsRTLKeyboardLayoutInstalled()) {
1935 if (message
== WM_KEYDOWN
) {
1936 if (wparam
== VK_SHIFT
) {
1937 base::i18n::TextDirection dir
;
1938 if (ui::IMM32Manager::IsCtrlShiftPressed(&dir
)) {
1939 render_widget_host_
->UpdateTextDirection(
1940 dir
== base::i18n::RIGHT_TO_LEFT
?
1941 blink::WebTextDirectionRightToLeft
:
1942 blink::WebTextDirectionLeftToRight
);
1944 } else if (wparam
!= VK_CONTROL
) {
1945 // Bug 9762: http://crbug.com/9762 A user pressed a key except shift
1946 // and control keys.
1947 // When a user presses a key while he/she holds control and shift keys,
1948 // we cancel sending an IPC message in NotifyTextDirection() below and
1949 // ignore succeeding UpdateTextDirection() calls while we call
1950 // NotifyTextDirection().
1951 // To cancel it, this call set a flag that prevents sending an IPC
1952 // message in NotifyTextDirection() only if we are going to send it.
1953 // It is harmless to call this function if we aren't going to send it.
1954 render_widget_host_
->CancelUpdateTextDirection();
1956 } else if (message
== WM_KEYUP
&&
1957 (wparam
== VK_SHIFT
|| wparam
== VK_CONTROL
)) {
1958 // We send an IPC message only if we need to update the text direction.
1959 render_widget_host_
->NotifyTextDirection();
1963 // Special processing for enter key: When user hits enter in omnibox
1964 // we change focus to render host after the navigation, so repeat WM_KEYDOWNs
1965 // and WM_KEYUP are going to render host, despite being initiated in other
1966 // window. This code filters out these messages.
1967 bool ignore_keyboard_event
= false;
1968 if (wparam
== VK_RETURN
) {
1969 if (message
== WM_KEYDOWN
|| message
== WM_SYSKEYDOWN
) {
1970 if (KF_REPEAT
& HIWORD(lparam
)) {
1971 // this is a repeated key
1972 if (!capture_enter_key_
)
1973 ignore_keyboard_event
= true;
1975 capture_enter_key_
= true;
1977 } else if (message
== WM_KEYUP
|| message
== WM_SYSKEYUP
) {
1978 if (!capture_enter_key_
)
1979 ignore_keyboard_event
= true;
1980 capture_enter_key_
= false;
1982 // Ignore all other keyboard events for the enter key if not captured.
1983 if (!capture_enter_key_
)
1984 ignore_keyboard_event
= true;
1988 if (render_widget_host_
&& !ignore_keyboard_event
) {
1989 MSG msg
= { m_hWnd
, message
, wparam
, lparam
};
1990 render_widget_host_
->ForwardKeyboardEvent(NativeWebKeyboardEvent(msg
));
1996 LRESULT
RenderWidgetHostViewWin::OnWheelEvent(UINT message
, WPARAM wparam
,
1997 LPARAM lparam
, BOOL
& handled
) {
1998 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnWheelEvent");
1999 // Forward the mouse-wheel message to the window under the mouse if it belongs
2001 if (message
== WM_MOUSEWHEEL
&&
2002 ui::RerouteMouseWheel(m_hWnd
, wparam
, lparam
)) {
2007 // We get mouse wheel/scroll messages even if we are not in the foreground.
2008 // So here we check if we have any owned popup windows in the foreground and
2010 if (m_hWnd
!= GetForegroundWindow()) {
2011 HWND toplevel_hwnd
= ::GetAncestor(m_hWnd
, GA_ROOT
);
2013 GetCurrentThreadId(),
2015 reinterpret_cast<LPARAM
>(toplevel_hwnd
));
2018 if (render_widget_host_
) {
2019 blink::WebMouseWheelEvent wheel_event
=
2020 WebMouseWheelEventBuilder::Build(m_hWnd
, message
, wparam
, lparam
);
2021 float scale
= gfx::win::GetDeviceScaleFactor();
2022 wheel_event
.x
/= scale
;
2023 wheel_event
.y
/= scale
;
2024 wheel_event
.deltaX
/= scale
;
2025 wheel_event
.deltaY
/= scale
;
2027 render_widget_host_
->ForwardWheelEvent(wheel_event
);
2033 WebTouchState::WebTouchState(const RenderWidgetHostViewWin
* window
)
2038 size_t WebTouchState::UpdateTouchPoints(
2039 TOUCHINPUT
* points
, size_t count
) {
2040 // First we reset all touch event state. This involves removing any released
2041 // touchpoints and marking the rest as stationary. After that we go through
2042 // and alter/add any touchpoints (from the touch input buffer) that we can
2043 // coalesce into a single message. The return value is the number of consumed
2045 blink::WebTouchPoint
* point
= touch_event_
.touches
;
2046 blink::WebTouchPoint
* end
= point
+ touch_event_
.touchesLength
;
2047 while (point
< end
) {
2048 if (point
->state
== blink::WebTouchPoint::StateReleased
) {
2050 --touch_event_
.touchesLength
;
2052 point
->state
= blink::WebTouchPoint::StateStationary
;
2056 touch_event_
.changedTouchesLength
= 0;
2057 touch_event_
.modifiers
= content::EventFlagsToWebEventModifiers(
2058 ui::GetModifiersFromKeyState());
2060 // Consume all events of the same type and add them to the changed list.
2062 for (size_t i
= 0; i
< count
; ++i
) {
2063 unsigned int mapped_id
= GetMappedTouch(points
[i
].dwID
);
2065 blink::WebTouchPoint
* point
= NULL
;
2066 for (unsigned j
= 0; j
< touch_event_
.touchesLength
; ++j
) {
2067 if (static_cast<DWORD
>(touch_event_
.touches
[j
].id
) == mapped_id
) {
2068 point
= &touch_event_
.touches
[j
];
2073 // Use a move instead if we see a down on a point we already have.
2074 int type
= GetTouchType(points
[i
]);
2075 if (point
&& type
== TOUCHEVENTF_DOWN
)
2076 SetTouchType(&points
[i
], TOUCHEVENTF_MOVE
);
2078 // Stop processing when the event type changes.
2079 if (touch_event_
.changedTouchesLength
&& type
!= last_type
)
2082 touch_event_
.timeStampSeconds
= points
[i
].dwTime
/ 1000.0;
2086 case TOUCHEVENTF_DOWN
: {
2087 if (!(point
= AddTouchPoint(&points
[i
])))
2089 touch_event_
.type
= blink::WebInputEvent::TouchStart
;
2093 case TOUCHEVENTF_UP
: {
2094 if (!point
) // Just throw away a stray up.
2096 point
->state
= blink::WebTouchPoint::StateReleased
;
2097 UpdateTouchPoint(point
, &points
[i
]);
2098 touch_event_
.type
= blink::WebInputEvent::TouchEnd
;
2102 case TOUCHEVENTF_MOVE
: {
2104 point
->state
= blink::WebTouchPoint::StateMoved
;
2105 // Don't update the message if the point didn't really move.
2106 if (UpdateTouchPoint(point
, &points
[i
]))
2108 touch_event_
.type
= blink::WebInputEvent::TouchMove
;
2109 } else if (touch_event_
.changedTouchesLength
) {
2110 RemoveExpiredMappings();
2111 // Can't add a point if we're already handling move events.
2114 // Treat a move with no existing point as a down.
2115 if (!(point
= AddTouchPoint(&points
[i
])))
2117 last_type
= TOUCHEVENTF_DOWN
;
2118 SetTouchType(&points
[i
], TOUCHEVENTF_DOWN
);
2119 touch_event_
.type
= blink::WebInputEvent::TouchStart
;
2128 touch_event_
.changedTouches
[touch_event_
.changedTouchesLength
++] = *point
;
2131 RemoveExpiredMappings();
2135 void WebTouchState::RemoveExpiredMappings() {
2136 blink::WebTouchPoint
* point
= touch_event_
.touches
;
2137 blink::WebTouchPoint
* end
= point
+ touch_event_
.touchesLength
;
2138 for (; point
< end
; ++point
) {
2139 if (point
->state
== blink::WebTouchPoint::StateReleased
)
2140 id_generator_
.ReleaseGeneratedID(point
->id
);
2145 bool WebTouchState::ReleaseTouchPoints() {
2146 if (touch_event_
.touchesLength
== 0)
2148 // Mark every active touchpoint as released.
2149 touch_event_
.type
= blink::WebInputEvent::TouchEnd
;
2150 touch_event_
.changedTouchesLength
= touch_event_
.touchesLength
;
2151 for (unsigned int i
= 0; i
< touch_event_
.touchesLength
; ++i
) {
2152 touch_event_
.touches
[i
].state
= blink::WebTouchPoint::StateReleased
;
2153 touch_event_
.changedTouches
[i
].state
=
2154 blink::WebTouchPoint::StateReleased
;
2160 blink::WebTouchPoint
* WebTouchState::AddTouchPoint(
2161 TOUCHINPUT
* touch_input
) {
2162 DCHECK(touch_event_
.touchesLength
<
2163 blink::WebTouchEvent::touchesLengthCap
);
2164 if (touch_event_
.touchesLength
>=
2165 blink::WebTouchEvent::touchesLengthCap
)
2167 blink::WebTouchPoint
* point
=
2168 &touch_event_
.touches
[touch_event_
.touchesLength
++];
2169 point
->state
= blink::WebTouchPoint::StatePressed
;
2170 point
->id
= GetMappedTouch(touch_input
->dwID
);
2171 UpdateTouchPoint(point
, touch_input
);
2175 bool WebTouchState::UpdateTouchPoint(
2176 blink::WebTouchPoint
* touch_point
,
2177 TOUCHINPUT
* touch_input
) {
2179 TOUCH_COORD_TO_PIXEL(touch_input
->x
) /
2180 gfx::win::GetUndocumentedDPITouchScale(),
2181 TOUCH_COORD_TO_PIXEL(touch_input
->y
) /
2182 gfx::win::GetUndocumentedDPITouchScale());
2185 if (touch_input
->dwMask
& TOUCHINPUTMASKF_CONTACTAREA
) {
2186 // Some touch drivers send a contact area of "-1", yet flag it as valid.
2187 radius_x
= std::max(1,
2188 static_cast<int>(TOUCH_COORD_TO_PIXEL(touch_input
->cxContact
) /
2189 gfx::win::GetUndocumentedDPITouchScale()));
2190 radius_y
= std::max(1,
2191 static_cast<int>(TOUCH_COORD_TO_PIXEL(touch_input
->cyContact
) /
2192 gfx::win::GetUndocumentedDPITouchScale()));
2195 // Detect and exclude stationary moves.
2196 if (GetTouchType(*touch_input
) == TOUCHEVENTF_MOVE
&&
2197 touch_point
->screenPosition
.x
== coordinates
.x
&&
2198 touch_point
->screenPosition
.y
== coordinates
.y
&&
2199 touch_point
->radiusX
== radius_x
&&
2200 touch_point
->radiusY
== radius_y
) {
2201 touch_point
->state
= blink::WebTouchPoint::StateStationary
;
2205 touch_point
->screenPosition
.x
= coordinates
.x
;
2206 touch_point
->screenPosition
.y
= coordinates
.y
;
2207 window_
->ScreenToClient(&coordinates
);
2208 static float scale
= gfx::win::GetDeviceScaleFactor();
2209 touch_point
->position
.x
= coordinates
.x
/ scale
;
2210 touch_point
->position
.y
= coordinates
.y
/ scale
;
2211 touch_point
->radiusX
= radius_x
;
2212 touch_point
->radiusY
= radius_y
;
2213 touch_point
->force
= 0;
2214 touch_point
->rotationAngle
= 0;
2218 // Find (or create) a mapping for _os_touch_id_.
2219 unsigned int WebTouchState::GetMappedTouch(unsigned int os_touch_id
) {
2220 return id_generator_
.GetGeneratedID(os_touch_id
);
2223 LRESULT
RenderWidgetHostViewWin::OnTouchEvent(UINT message
, WPARAM wparam
,
2224 LPARAM lparam
, BOOL
& handled
) {
2225 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnTouchEvent");
2226 // Finish the ongoing composition whenever a touch event happens.
2227 // It matches IE's behavior.
2228 if (base::win::IsTSFAwareRequired()) {
2229 ui::TSFBridge::GetInstance()->CancelComposition();
2231 imm32_manager_
->CleanupComposition(m_hWnd
);
2234 // TODO(jschuh): Add support for an arbitrary number of touchpoints.
2235 size_t total
= std::min(static_cast<int>(LOWORD(wparam
)),
2236 static_cast<int>(blink::WebTouchEvent::touchesLengthCap
));
2237 TOUCHINPUT points
[blink::WebTouchEvent::touchesLengthCap
];
2239 if (!total
|| !ui::GetTouchInputInfoWrapper((HTOUCHINPUT
)lparam
, total
,
2240 points
, sizeof(TOUCHINPUT
))) {
2241 TRACE_EVENT0("browser", "EarlyOut_NothingToDo");
2245 if (total
== 1 && (points
[0].dwFlags
& TOUCHEVENTF_DOWN
)) {
2246 pointer_down_context_
= true;
2247 last_touch_location_
= gfx::Point(
2248 TOUCH_COORD_TO_PIXEL(points
[0].x
) /
2249 gfx::win::GetUndocumentedDPITouchScale(),
2250 TOUCH_COORD_TO_PIXEL(points
[0].y
) /
2251 gfx::win::GetUndocumentedDPITouchScale());
2254 bool should_forward
= render_widget_host_
->ShouldForwardTouchEvent() &&
2255 touch_events_enabled_
;
2257 // Send a copy of the touch events on to the gesture recognizer.
2258 for (size_t start
= 0; start
< total
;) {
2259 start
+= touch_state_
->UpdateTouchPoints(points
+ start
, total
- start
);
2260 if (should_forward
) {
2261 if (touch_state_
->is_changed())
2262 render_widget_host_
->ForwardTouchEventWithLatencyInfo(
2263 touch_state_
->touch_event(), ui::LatencyInfo());
2265 const blink::WebTouchEvent
& touch_event
= touch_state_
->touch_event();
2266 base::TimeDelta timestamp
= base::TimeDelta::FromMilliseconds(
2267 touch_event
.timeStampSeconds
* 1000);
2268 for (size_t i
= 0; i
< touch_event
.touchesLength
; ++i
) {
2269 scoped_ptr
<ui::GestureRecognizer::Gestures
> gestures
;
2270 gestures
.reset(gesture_recognizer_
->ProcessTouchEventForGesture(
2271 TouchEventFromWebTouchPoint(touch_event
.touches
[i
], timestamp
),
2272 ui::ER_UNHANDLED
, this));
2273 ProcessGestures(gestures
.get());
2278 CloseTouchInputHandle((HTOUCHINPUT
)lparam
);
2283 void RenderWidgetHostViewWin::ProcessGestures(
2284 ui::GestureRecognizer::Gestures
* gestures
) {
2285 if ((gestures
== NULL
) || gestures
->empty())
2287 for (ui::GestureRecognizer::Gestures::iterator g_it
= gestures
->begin();
2288 g_it
!= gestures
->end();
2290 ForwardGestureEventToRenderer(*g_it
);
2294 LRESULT
RenderWidgetHostViewWin::OnMouseActivate(UINT message
,
2298 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnMouseActivate");
2299 if (!render_widget_host_
)
2300 return MA_NOACTIVATE
;
2302 if (!IsActivatable())
2303 return MA_NOACTIVATE
;
2305 HWND focus_window
= GetFocus();
2306 if (!::IsWindow(focus_window
) || !IsChild(focus_window
)) {
2307 // We handle WM_MOUSEACTIVATE to set focus to the underlying plugin
2308 // child window. This is to ensure that keyboard events are received
2309 // by the plugin. The correct way to fix this would be send over
2310 // an event to the renderer which would then eventually send over
2311 // a setFocus call to the plugin widget. This would ensure that
2312 // the renderer (webkit) knows about the plugin widget receiving
2314 // TODO(iyengar) Do the right thing as per the above comment.
2315 POINT cursor_pos
= {0};
2316 ::GetCursorPos(&cursor_pos
);
2317 ::ScreenToClient(m_hWnd
, &cursor_pos
);
2318 HWND child_window
= ::RealChildWindowFromPoint(m_hWnd
, cursor_pos
);
2319 if (::IsWindow(child_window
) && child_window
!= m_hWnd
) {
2320 if (gfx::GetClassName(child_window
) == kWrapperNativeWindowClassName
)
2321 child_window
= ::GetWindow(child_window
, GW_CHILD
);
2323 ::SetFocus(child_window
);
2324 return MA_NOACTIVATE
;
2328 render_widget_host_
->OnPointerEventActivate();
2332 LRESULT
RenderWidgetHostViewWin::OnGestureEvent(
2333 UINT message
, WPARAM wparam
, LPARAM lparam
, BOOL
& handled
) {
2334 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnGestureEvent");
2336 DCHECK(!touch_events_enabled_
);
2339 GESTUREINFO gi
= {sizeof(GESTUREINFO
)};
2340 HGESTUREINFO gi_handle
= reinterpret_cast<HGESTUREINFO
>(lparam
);
2341 if (!::GetGestureInfo(gi_handle
, &gi
)) {
2342 DWORD error
= GetLastError();
2343 NOTREACHED() << "Unable to get gesture info. Error : " << error
;
2347 if (gi
.dwID
== GID_ZOOM
) {
2348 PageZoom zoom
= PAGE_ZOOM_RESET
;
2349 POINT zoom_center
= {0};
2350 if (DecodeZoomGesture(m_hWnd
, gi
, &zoom
, &zoom_center
)) {
2352 Send(new ViewMsg_ZoomFactor(render_widget_host_
->GetRoutingID(),
2353 zoom
, zoom_center
.x
, zoom_center
.y
));
2355 } else if (gi
.dwID
== GID_PAN
) {
2356 // Right now we only decode scroll gestures and we forward to the page
2357 // as scroll events.
2360 if (DecodeScrollGesture(gi
, &start
, &delta
)) {
2362 render_widget_host_
->ForwardWheelEvent(
2363 MakeFakeScrollWheelEvent(m_hWnd
, start
, delta
));
2366 ::CloseGestureInfoHandle(gi_handle
);
2370 LRESULT
RenderWidgetHostViewWin::OnMoveOrSize(
2371 UINT message
, WPARAM wparam
, LPARAM lparam
, BOOL
& handled
) {
2372 // Reset the cliping rectangle if the mouse is locked.
2373 if (mouse_locked_
) {
2375 GetWindowRect(&rect
);
2376 ::ClipCursor(&rect
);
2381 void RenderWidgetHostViewWin::OnAccessibilityEvents(
2382 const std::vector
<AccessibilityHostMsg_EventParams
>& params
) {
2383 CreateBrowserAccessibilityManagerIfNeeded();
2384 GetBrowserAccessibilityManager()->OnAccessibilityEvents(params
);
2387 bool RenderWidgetHostViewWin::LockMouse() {
2391 mouse_locked_
= true;
2393 // Hide the tooltip window if it is currently visible. When the mouse is
2394 // locked, no mouse message is relayed to the tooltip window, so we don't need
2395 // to worry that it will reappear.
2396 if (::IsWindow(tooltip_hwnd_
) && tooltip_showing_
) {
2397 ::SendMessage(tooltip_hwnd_
, TTM_POP
, 0, 0);
2398 // Sending a TTM_POP message doesn't seem to actually hide the tooltip
2399 // window, although we will receive a TTN_POP notification. As a result,
2400 // ShowWindow() is explicitly called to hide the window.
2401 ::ShowWindow(tooltip_hwnd_
, SW_HIDE
);
2404 // TODO(yzshen): ShowCursor(FALSE) causes SetCursorPos() to be ignored on
2406 ::ShowCursor(FALSE
);
2408 move_to_center_request_
.pending
= false;
2409 last_mouse_position_
.locked_global
= last_mouse_position_
.unlocked_global
;
2411 // Must set the clip rectangle before MoveCursorToCenterIfNecessary()
2412 // so that if the cursor is moved it uses the clip rect set to the window
2413 // rect. Otherwise, MoveCursorToCenterIfNecessary() may move the cursor
2414 // to the center of the screen, and then we would clip to the window
2415 // rect, thus moving the cursor and causing a movement delta.
2417 GetWindowRect(&rect
);
2418 ::ClipCursor(&rect
);
2419 MoveCursorToCenterIfNecessary();
2424 void RenderWidgetHostViewWin::UnlockMouse() {
2428 mouse_locked_
= false;
2431 ::SetCursorPos(last_mouse_position_
.unlocked_global
.x(),
2432 last_mouse_position_
.unlocked_global
.y());
2435 if (render_widget_host_
)
2436 render_widget_host_
->LostMouseLock();
2439 void RenderWidgetHostViewWin::Observe(
2441 const NotificationSource
& source
,
2442 const NotificationDetails
& details
) {
2443 DCHECK(type
== NOTIFICATION_RENDERER_PROCESS_TERMINATED
);
2445 // Get the RenderProcessHost that posted this notification, and exit
2446 // if it's not the one associated with this host view.
2447 RenderProcessHost
* render_process_host
=
2448 Source
<RenderProcessHost
>(source
).ptr();
2449 DCHECK(render_process_host
);
2450 if (!render_widget_host_
||
2451 render_process_host
!= render_widget_host_
->GetProcess()) {
2455 // If it was our RenderProcessHost that posted the notification,
2456 // clear the BrowserAccessibilityManager, because the renderer is
2457 // dead and any accessibility information we have is now stale.
2458 SetBrowserAccessibilityManager(NULL
);
2461 static void PaintCompositorHostWindow(HWND hWnd
) {
2463 BeginPaint(hWnd
, &paint
);
2465 RenderWidgetHostViewWin
* win
= static_cast<RenderWidgetHostViewWin
*>(
2466 gfx::GetWindowUserData(hWnd
));
2467 // Trigger composite to rerender window.
2469 win
->AcceleratedPaint(paint
.hdc
);
2471 EndPaint(hWnd
, &paint
);
2474 // WndProc for the compositor host window. We use this instead of Default so
2475 // we can drop WM_PAINT and WM_ERASEBKGD messages on the floor.
2476 static LRESULT CALLBACK
CompositorHostWindowProc(HWND hWnd
, UINT message
,
2477 WPARAM wParam
, LPARAM lParam
) {
2482 PaintCompositorHostWindow(hWnd
);
2485 return DefWindowProc(hWnd
, message
, wParam
, lParam
);
2489 void RenderWidgetHostViewWin::AcceleratedPaint(HDC dc
) {
2490 if (render_widget_host_
)
2491 render_widget_host_
->ScheduleComposite();
2492 if (accelerated_surface_
)
2493 accelerated_surface_
->Present(dc
);
2496 void RenderWidgetHostViewWin::GetScreenInfo(blink::WebScreenInfo
* results
) {
2497 GetScreenInfoForWindow(GetNativeViewId(), results
);
2500 gfx::Rect
RenderWidgetHostViewWin::GetBoundsInRootWindow() {
2501 RECT window_rect
= {0};
2502 HWND root_window
= GetAncestor(m_hWnd
, GA_ROOT
);
2503 ::GetWindowRect(root_window
, &window_rect
);
2504 gfx::Rect
rect(window_rect
);
2506 // Maximized windows are outdented from the work area by the frame thickness
2507 // even though this "frame" is not painted. This confuses code (and people)
2508 // that think of a maximized window as corresponding exactly to the work area.
2509 // Correct for this by subtracting the frame thickness back off.
2510 if (::IsZoomed(root_window
)) {
2511 rect
.Inset(GetSystemMetrics(SM_CXSIZEFRAME
),
2512 GetSystemMetrics(SM_CYSIZEFRAME
));
2515 return gfx::win::ScreenToDIPRect(rect
);
2518 // Creates a HWND within the RenderWidgetHostView that will serve as a host
2519 // for a HWND that the GPU process will create. The host window is used
2520 // to Z-position the GPU's window relative to other plugin windows.
2521 gfx::GLSurfaceHandle
RenderWidgetHostViewWin::GetCompositingSurface() {
2522 // If the window has been created, don't recreate it a second time
2523 if (compositor_host_window_
)
2524 return gfx::GLSurfaceHandle(compositor_host_window_
, gfx::NATIVE_TRANSPORT
);
2526 // On Vista and later we present directly to the view window rather than a
2528 if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface()) {
2529 if (!accelerated_surface_
)
2530 accelerated_surface_
.reset(new AcceleratedSurface(m_hWnd
));
2531 return gfx::GLSurfaceHandle(m_hWnd
, gfx::NATIVE_TRANSPORT
);
2534 // On XP we need a child window that can be resized independently of the
2536 static ATOM atom
= 0;
2537 static HMODULE instance
= NULL
;
2539 WNDCLASSEX window_class
;
2540 base::win::InitializeWindowClass(
2541 L
"CompositorHostWindowClass",
2542 &base::win::WrappedWindowProc
<CompositorHostWindowProc
>,
2543 0, 0, 0, NULL
, NULL
, NULL
, NULL
, NULL
,
2545 instance
= window_class
.hInstance
;
2546 atom
= RegisterClassEx(&window_class
);
2551 GetClientRect(¤tRect
);
2553 // Ensure window does not have zero area because D3D cannot create a zero
2555 int width
= std::max(1,
2556 static_cast<int>(currentRect
.right
- currentRect
.left
));
2557 int height
= std::max(1,
2558 static_cast<int>(currentRect
.bottom
- currentRect
.top
));
2560 compositor_host_window_
= CreateWindowEx(
2561 WS_EX_LEFT
| WS_EX_LTRREADING
| WS_EX_RIGHTSCROLLBAR
,
2562 MAKEINTATOM(atom
), 0,
2563 WS_CHILD
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| WS_DISABLED
,
2564 0, 0, width
, height
, m_hWnd
, 0, instance
, 0);
2565 gfx::CheckWindowCreated(compositor_host_window_
);
2567 gfx::SetWindowUserData(compositor_host_window_
, this);
2569 gfx::GLSurfaceHandle
surface_handle(compositor_host_window_
,
2570 gfx::NATIVE_TRANSPORT
);
2571 return surface_handle
;
2574 void RenderWidgetHostViewWin::ResizeCompositingSurface(const gfx::Size
& size
) {
2575 // Ensure window does not have zero area because D3D cannot create a zero
2577 ::SetWindowPos(compositor_host_window_
,
2580 std::max(1, size
.width()),
2581 std::max(1, size
.height()),
2582 SWP_NOSENDCHANGING
| SWP_NOCOPYBITS
| SWP_NOZORDER
|
2583 SWP_NOACTIVATE
| SWP_DEFERERASE
| SWP_NOMOVE
);
2586 void RenderWidgetHostViewWin::OnAcceleratedCompositingStateChange() {
2587 bool show
= render_widget_host_
->is_accelerated_compositing_active();
2588 // When we first create the compositor, we will get a show request from
2589 // the renderer before we have gotten the create request from the GPU. In this
2590 // case, simply ignore the show request.
2591 if (compositor_host_window_
== NULL
)
2595 ::ShowWindow(compositor_host_window_
, SW_SHOW
);
2597 // Get all the child windows of this view, including the compositor window.
2598 std::vector
<HWND
> all_child_windows
;
2599 ::EnumChildWindows(m_hWnd
, AddChildWindowToVector
,
2600 reinterpret_cast<LPARAM
>(&all_child_windows
));
2602 // Build a list of just the plugin window handles
2603 std::vector
<HWND
> plugin_windows
;
2604 bool compositor_host_window_found
= false;
2605 for (size_t i
= 0; i
< all_child_windows
.size(); ++i
) {
2606 if (all_child_windows
[i
] != compositor_host_window_
)
2607 plugin_windows
.push_back(all_child_windows
[i
]);
2609 compositor_host_window_found
= true;
2611 DCHECK(compositor_host_window_found
);
2613 // Set all the plugin windows to be "after" the compositor window.
2614 // When the compositor window is created, gets placed above plugins.
2615 for (size_t i
= 0; i
< plugin_windows
.size(); ++i
) {
2617 if (i
+ 1 < plugin_windows
.size())
2618 next
= plugin_windows
[i
+1];
2620 next
= compositor_host_window_
;
2621 ::SetWindowPos(plugin_windows
[i
], next
, 0, 0, 0, 0,
2622 SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
2625 // Drop the backing store for the accelerated surface when the accelerated
2626 // compositor is disabled. Otherwise, a flash of the last presented frame
2627 // could appear when it is next enabled.
2628 if (accelerated_surface_
)
2629 accelerated_surface_
->Suspend();
2630 hide_compositor_window_at_next_paint_
= true;
2634 void RenderWidgetHostViewWin::AcceleratedSurfaceInitialized(int host_id
,
2638 void RenderWidgetHostViewWin::AcceleratedSurfaceBuffersSwapped(
2639 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params
& params
,
2644 void RenderWidgetHostViewWin::AcceleratedSurfacePostSubBuffer(
2645 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params
& params
,
2650 void RenderWidgetHostViewWin::AcceleratedSurfaceSuspend() {
2651 if (!accelerated_surface_
)
2654 accelerated_surface_
->Suspend();
2657 void RenderWidgetHostViewWin::AcceleratedSurfaceRelease() {
2660 bool RenderWidgetHostViewWin::HasAcceleratedSurface(
2661 const gfx::Size
& desired_size
) {
2662 // TODO(jbates) Implement this so this view can use GetBackingStore for both
2663 // software and GPU frames. Defaulting to false just makes GetBackingStore
2664 // only useable for software frames.
2668 void RenderWidgetHostViewWin::SetAccessibilityFocus(int acc_obj_id
) {
2669 if (!render_widget_host_
)
2672 render_widget_host_
->AccessibilitySetFocus(acc_obj_id
);
2675 void RenderWidgetHostViewWin::AccessibilityDoDefaultAction(int acc_obj_id
) {
2676 if (!render_widget_host_
)
2679 render_widget_host_
->AccessibilityDoDefaultAction(acc_obj_id
);
2682 void RenderWidgetHostViewWin::AccessibilityScrollToMakeVisible(
2683 int acc_obj_id
, gfx::Rect subfocus
) {
2684 if (!render_widget_host_
)
2687 render_widget_host_
->AccessibilityScrollToMakeVisible(acc_obj_id
, subfocus
);
2690 void RenderWidgetHostViewWin::AccessibilityScrollToPoint(
2691 int acc_obj_id
, gfx::Point point
) {
2692 if (!render_widget_host_
)
2695 render_widget_host_
->AccessibilityScrollToPoint(acc_obj_id
, point
);
2698 void RenderWidgetHostViewWin::AccessibilitySetTextSelection(
2699 int acc_obj_id
, int start_offset
, int end_offset
) {
2700 if (!render_widget_host_
)
2703 render_widget_host_
->AccessibilitySetTextSelection(
2704 acc_obj_id
, start_offset
, end_offset
);
2707 gfx::Point
RenderWidgetHostViewWin::GetLastTouchEventLocation() const {
2708 return last_touch_location_
;
2711 void RenderWidgetHostViewWin::FatalAccessibilityTreeError() {
2712 render_widget_host_
->FatalAccessibilityTreeError();
2713 SetBrowserAccessibilityManager(NULL
);
2716 LRESULT
RenderWidgetHostViewWin::OnGetObject(UINT message
, WPARAM wparam
,
2717 LPARAM lparam
, BOOL
& handled
) {
2718 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnGetObject");
2719 if (kIdCustom
== lparam
) {
2720 // An MSAA client requestes our custom id. Assume that we have detected an
2721 // active windows screen reader.
2722 BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected();
2723 render_widget_host_
->SetAccessibilityMode(
2724 BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode());
2726 // Return with failure.
2727 return static_cast<LRESULT
>(0L);
2730 if (lparam
!= OBJID_CLIENT
) {
2732 return static_cast<LRESULT
>(0L);
2735 IAccessible
* iaccessible
= GetNativeViewAccessible();
2737 return LresultFromObject(IID_IAccessible
, wparam
, iaccessible
);
2740 return static_cast<LRESULT
>(0L);
2743 LRESULT
RenderWidgetHostViewWin::OnParentNotify(UINT message
, WPARAM wparam
,
2744 LPARAM lparam
, BOOL
& handled
) {
2745 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnParentNotify");
2748 if (!render_widget_host_
)
2751 switch (LOWORD(wparam
)) {
2752 case WM_LBUTTONDOWN
:
2753 case WM_RBUTTONDOWN
:
2754 case WM_MBUTTONDOWN
:
2755 render_widget_host_
->StartUserGesture();
2763 void RenderWidgetHostViewWin::OnFinalMessage(HWND window
) {
2764 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnFinalMessage");
2765 // When the render widget host is being destroyed, it ends up calling
2766 // Destroy() which NULLs render_widget_host_.
2767 // Note: the following bug http://crbug.com/24248 seems to report that
2768 // OnFinalMessage is called with a deleted |render_widget_host_|. It is not
2769 // clear how this could happen, hence the NULLing of render_widget_host_
2771 if (!render_widget_host_
&& !being_destroyed_
) {
2772 // If you hit this NOTREACHED, please add a comment to report it on
2773 // http://crbug.com/24248, including what you did when it happened and if
2777 if (render_widget_host_
)
2778 render_widget_host_
->ViewDestroyed();
2779 if (base::win::IsTSFAwareRequired())
2780 ui::TSFBridge::GetInstance()->RemoveFocusedClient(this);
2784 LRESULT
RenderWidgetHostViewWin::OnSessionChange(UINT message
,
2789 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSessionChange");
2791 if (!accelerated_surface_
)
2795 case WTS_SESSION_LOCK
:
2796 accelerated_surface_
->SetIsSessionLocked(true);
2798 case WTS_SESSION_UNLOCK
:
2799 // Force a repaint to update the window contents.
2800 if (!render_widget_host_
->is_hidden())
2801 InvalidateRect(NULL
, FALSE
);
2802 accelerated_surface_
->SetIsSessionLocked(false);
2811 void RenderWidgetHostViewWin::TrackMouseLeave(bool track
) {
2812 if (track
== track_mouse_leave_
)
2814 track_mouse_leave_
= track
;
2818 TRACKMOUSEEVENT tme
;
2819 tme
.cbSize
= sizeof(TRACKMOUSEEVENT
);
2820 tme
.dwFlags
= TME_LEAVE
;
2821 if (!track_mouse_leave_
)
2822 tme
.dwFlags
|= TME_CANCEL
;
2823 tme
.hwndTrack
= m_hWnd
;
2825 TrackMouseEvent(&tme
);
2828 bool RenderWidgetHostViewWin::Send(IPC::Message
* message
) {
2829 if (!render_widget_host_
)
2831 return render_widget_host_
->Send(message
);
2834 void RenderWidgetHostViewWin::EnsureTooltip() {
2835 UINT message
= TTM_NEWTOOLRECT
;
2838 ti
.cbSize
= sizeof(ti
);
2841 if (!::IsWindow(tooltip_hwnd_
)) {
2842 message
= TTM_ADDTOOL
;
2843 tooltip_hwnd_
= CreateWindowEx(
2844 WS_EX_TRANSPARENT
| l10n_util::GetExtendedTooltipStyles(),
2845 TOOLTIPS_CLASS
, NULL
, TTS_NOPREFIX
, 0, 0, 0, 0, m_hWnd
, NULL
,
2847 if (!tooltip_hwnd_
) {
2848 // Tooltip creation can inexplicably fail. See bug 82913 for details.
2849 LOG_GETLASTERROR(WARNING
) <<
2850 "Tooltip creation failed, tooltips won't work";
2853 ti
.uFlags
= TTF_TRANSPARENT
;
2854 ti
.lpszText
= LPSTR_TEXTCALLBACK
;
2856 // Ensure web content tooltips are displayed for at least this amount of
2857 // time, to give users a chance to read longer messages.
2858 const int kMinimumAutopopDurationMs
= 10 * 1000;
2859 int autopop_duration_ms
=
2860 SendMessage(tooltip_hwnd_
, TTM_GETDELAYTIME
, TTDT_AUTOPOP
, NULL
);
2861 if (autopop_duration_ms
< kMinimumAutopopDurationMs
) {
2862 SendMessage(tooltip_hwnd_
, TTM_SETDELAYTIME
, TTDT_AUTOPOP
,
2863 kMinimumAutopopDurationMs
);
2868 GetClientRect(&ti
.rect
);
2869 SendMessage(tooltip_hwnd_
, message
, NULL
, reinterpret_cast<LPARAM
>(&ti
));
2872 void RenderWidgetHostViewWin::ResetTooltip() {
2873 if (::IsWindow(tooltip_hwnd_
))
2874 ::DestroyWindow(tooltip_hwnd_
);
2875 tooltip_hwnd_
= NULL
;
2878 bool RenderWidgetHostViewWin::ForwardGestureEventToRenderer(
2879 ui::GestureEvent
* gesture
) {
2880 if (!render_widget_host_
)
2883 // Pinch gestures are disabled by default on windows desktop. See
2884 // crbug.com/128477 and crbug.com/148816
2885 if ((gesture
->type() == ui::ET_GESTURE_PINCH_BEGIN
||
2886 gesture
->type() == ui::ET_GESTURE_PINCH_UPDATE
||
2887 gesture
->type() == ui::ET_GESTURE_PINCH_END
) &&
2888 !ShouldSendPinchGesture()) {
2892 blink::WebGestureEvent web_gesture
= CreateWebGestureEvent(m_hWnd
, *gesture
);
2893 if (web_gesture
.type
== blink::WebGestureEvent::Undefined
)
2895 if (web_gesture
.type
== blink::WebGestureEvent::GestureTapDown
) {
2896 render_widget_host_
->ForwardGestureEvent(
2897 CreateFlingCancelEvent(gesture
->time_stamp().InSecondsF()));
2899 render_widget_host_
->ForwardGestureEventWithLatencyInfo(web_gesture
,
2900 *gesture
->latency());
2904 void RenderWidgetHostViewWin::ForwardMouseEventToRenderer(UINT message
,
2907 TRACE_EVENT0("browser",
2908 "RenderWidgetHostViewWin::ForwardMouseEventToRenderer");
2909 if (!render_widget_host_
) {
2910 TRACE_EVENT0("browser", "EarlyOut_NoRWH");
2914 gfx::Point point
= gfx::win::ScreenToDIPPoint(
2915 gfx::Point(static_cast<short>(LOWORD(lparam
)),
2916 static_cast<short>(HIWORD(lparam
))));
2917 lparam
= MAKELPARAM(point
.x(), point
.y());
2919 WebMouseEvent
event(
2920 WebMouseEventBuilder::Build(m_hWnd
, message
, wparam
, lparam
));
2922 if (mouse_locked_
) {
2923 event
.movementX
= event
.globalX
- last_mouse_position_
.locked_global
.x();
2924 event
.movementY
= event
.globalY
- last_mouse_position_
.locked_global
.y();
2925 last_mouse_position_
.locked_global
.SetPoint(event
.globalX
, event
.globalY
);
2927 event
.x
= last_mouse_position_
.unlocked
.x();
2928 event
.y
= last_mouse_position_
.unlocked
.y();
2929 event
.windowX
= last_mouse_position_
.unlocked
.x();
2930 event
.windowY
= last_mouse_position_
.unlocked
.y();
2931 event
.globalX
= last_mouse_position_
.unlocked_global
.x();
2932 event
.globalY
= last_mouse_position_
.unlocked_global
.y();
2934 if (ignore_mouse_movement_
) {
2935 ignore_mouse_movement_
= false;
2936 event
.movementX
= 0;
2937 event
.movementY
= 0;
2940 event
.globalX
- last_mouse_position_
.unlocked_global
.x();
2942 event
.globalY
- last_mouse_position_
.unlocked_global
.y();
2945 last_mouse_position_
.unlocked
.SetPoint(event
.windowX
, event
.windowY
);
2946 last_mouse_position_
.unlocked_global
.SetPoint(event
.globalX
, event
.globalY
);
2949 // Windows sends (fake) mouse messages for touch events. Don't send these to
2950 // the render widget.
2951 if (!touch_events_enabled_
|| !ui::IsMouseEventFromTouch(message
)) {
2952 // Send the event to the renderer before changing mouse capture, so that
2953 // the capturelost event arrives after mouseup.
2954 render_widget_host_
->ForwardMouseEvent(event
);
2956 switch (event
.type
) {
2957 case WebInputEvent::MouseMove
:
2958 TrackMouseLeave(true);
2960 case WebInputEvent::MouseLeave
:
2961 TrackMouseLeave(false);
2963 case WebInputEvent::MouseDown
:
2966 case WebInputEvent::MouseUp
:
2967 if (GetCapture() == m_hWnd
)
2973 if (IsActivatable() && event
.type
== WebInputEvent::MouseDown
) {
2974 // This is a temporary workaround for bug 765011 to get focus when the
2975 // mouse is clicked. This happens after the mouse down event is sent to
2976 // the renderer because normally Windows does a WM_SETFOCUS after
2982 void RenderWidgetHostViewWin::ShutdownHost() {
2983 weak_factory_
.InvalidateWeakPtrs();
2984 if (render_widget_host_
)
2985 render_widget_host_
->Shutdown();
2986 // Do not touch any members at this point, |this| has been deleted.
2989 void RenderWidgetHostViewWin::DoPopupOrFullscreenInit(HWND parent_hwnd
,
2990 const gfx::Rect
& pos
,
2992 Create(parent_hwnd
, NULL
, NULL
, WS_POPUP
, ex_style
);
2993 gfx::Rect screen_rect
= gfx::win::DIPToScreenRect(pos
);
2994 MoveWindow(screen_rect
.x(), screen_rect
.y(), screen_rect
.width(),
2995 screen_rect
.height(), TRUE
);
2996 ShowWindow(IsActivatable() ? SW_SHOW
: SW_SHOWNA
);
2998 if (is_fullscreen_
&& win8::IsSingleWindowMetroMode()) {
2999 MetroSetFrameWindow set_frame_window
=
3000 reinterpret_cast<MetroSetFrameWindow
>(
3001 ::GetProcAddress(base::win::GetMetroModule(), "SetFrameWindow"));
3002 DCHECK(set_frame_window
);
3003 set_frame_window(m_hWnd
);
3007 CPoint
RenderWidgetHostViewWin::GetClientCenter() const {
3009 GetClientRect(&rect
);
3010 return rect
.CenterPoint();
3013 void RenderWidgetHostViewWin::MoveCursorToCenterIfNecessary() {
3014 DCHECK(mouse_locked_
);
3017 GetClipCursor(&rect
);
3018 int border_x
= rect
.Width() * kMouseLockBorderPercentage
/ 100;
3019 int border_y
= rect
.Height() * kMouseLockBorderPercentage
/ 100;
3022 last_mouse_position_
.locked_global
.x() < rect
.left
+ border_x
||
3023 last_mouse_position_
.locked_global
.x() > rect
.right
- border_x
||
3024 last_mouse_position_
.locked_global
.y() < rect
.top
+ border_y
||
3025 last_mouse_position_
.locked_global
.y() > rect
.bottom
- border_y
;
3028 move_to_center_request_
.pending
= true;
3029 move_to_center_request_
.target
= rect
.CenterPoint();
3030 if (!::SetCursorPos(move_to_center_request_
.target
.x(),
3031 move_to_center_request_
.target
.y())) {
3032 LOG_GETLASTERROR(WARNING
) << "Failed to set cursor position.";
3037 void RenderWidgetHostViewWin::HandleLockedMouseEvent(UINT message
,
3040 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::HandleLockedMouseEvent");
3041 DCHECK(mouse_locked_
);
3043 if (message
== WM_MOUSEMOVE
&& move_to_center_request_
.pending
) {
3044 // Ignore WM_MOUSEMOVE messages generated by
3045 // MoveCursorToCenterIfNecessary().
3046 CPoint
current_position(LOWORD(lparam
), HIWORD(lparam
));
3047 ClientToScreen(¤t_position
);
3048 if (move_to_center_request_
.target
.x() == current_position
.x
&&
3049 move_to_center_request_
.target
.y() == current_position
.y
) {
3050 move_to_center_request_
.pending
= false;
3051 last_mouse_position_
.locked_global
= move_to_center_request_
.target
;
3056 ForwardMouseEventToRenderer(message
, wparam
, lparam
);
3059 LRESULT
RenderWidgetHostViewWin::OnDocumentFeed(RECONVERTSTRING
* reconv
) {
3060 size_t target_offset
;
3061 size_t target_length
;
3062 bool has_composition
;
3063 if (!composition_range_
.is_empty()) {
3064 target_offset
= composition_range_
.GetMin();
3065 target_length
= composition_range_
.length();
3066 has_composition
= true;
3067 } else if (selection_range_
.IsValid()) {
3068 target_offset
= selection_range_
.GetMin();
3069 target_length
= selection_range_
.length();
3070 has_composition
= false;
3075 size_t len
= selection_text_
.length();
3076 size_t need_size
= sizeof(RECONVERTSTRING
) + len
* sizeof(WCHAR
);
3078 if (target_offset
< selection_text_offset_
||
3079 target_offset
+ target_length
> selection_text_offset_
+ len
) {
3086 if (reconv
->dwSize
< need_size
)
3089 reconv
->dwVersion
= 0;
3090 reconv
->dwStrLen
= len
;
3091 reconv
->dwStrOffset
= sizeof(RECONVERTSTRING
);
3092 reconv
->dwCompStrLen
= has_composition
? target_length
: 0;
3093 reconv
->dwCompStrOffset
=
3094 (target_offset
- selection_text_offset_
) * sizeof(WCHAR
);
3095 reconv
->dwTargetStrLen
= target_length
;
3096 reconv
->dwTargetStrOffset
= reconv
->dwCompStrOffset
;
3097 memcpy(reinterpret_cast<char*>(reconv
) + sizeof(RECONVERTSTRING
),
3098 selection_text_
.c_str(), len
* sizeof(WCHAR
));
3100 // According to Microsft API document, IMR_RECONVERTSTRING and
3101 // IMR_DOCUMENTFEED should return reconv, but some applications return
3103 return reinterpret_cast<LRESULT
>(reconv
);
3106 LRESULT
RenderWidgetHostViewWin::OnReconvertString(RECONVERTSTRING
* reconv
) {
3107 // If there is a composition string already, we don't allow reconversion.
3108 if (imm32_manager_
->is_composing())
3111 if (selection_range_
.is_empty())
3114 if (selection_text_
.empty())
3117 if (selection_range_
.GetMin() < selection_text_offset_
||
3118 selection_range_
.GetMax() >
3119 selection_text_offset_
+ selection_text_
.length()) {
3123 size_t len
= selection_range_
.length();
3124 size_t need_size
= sizeof(RECONVERTSTRING
) + len
* sizeof(WCHAR
);
3129 if (reconv
->dwSize
< need_size
)
3132 reconv
->dwVersion
= 0;
3133 reconv
->dwStrLen
= len
;
3134 reconv
->dwStrOffset
= sizeof(RECONVERTSTRING
);
3135 reconv
->dwCompStrLen
= len
;
3136 reconv
->dwCompStrOffset
= 0;
3137 reconv
->dwTargetStrLen
= len
;
3138 reconv
->dwTargetStrOffset
= 0;
3140 size_t offset
= selection_range_
.GetMin() - selection_text_offset_
;
3141 memcpy(reinterpret_cast<char*>(reconv
) + sizeof(RECONVERTSTRING
),
3142 selection_text_
.c_str() + offset
, len
* sizeof(WCHAR
));
3144 // According to Microsft API document, IMR_RECONVERTSTRING and
3145 // IMR_DOCUMENTFEED should return reconv, but some applications return
3147 return reinterpret_cast<LRESULT
>(reconv
);
3150 LRESULT
RenderWidgetHostViewWin::OnQueryCharPosition(
3151 IMECHARPOSITION
* position
) {
3154 if (position
->dwSize
< sizeof(IMECHARPOSITION
))
3157 RECT target_rect
= {};
3158 if (imm32_manager_
->is_composing() && !composition_range_
.is_empty() &&
3159 position
->dwCharPos
< composition_character_bounds_
.size()) {
3161 composition_character_bounds_
[position
->dwCharPos
].ToRECT();
3162 } else if (position
->dwCharPos
== 0) {
3163 // When there is no on-going composition but |position->dwCharPos| is 0,
3164 // use the caret rect. This behavior is the same to RichEdit. In fact,
3165 // CUAS (Cicero Unaware Application Support) relies on this behavior to
3166 // implement ITfContextView::GetTextExt on top of IMM32-based applications.
3167 target_rect
= caret_rect_
.ToRECT();
3171 ClientToScreen(&target_rect
);
3173 RECT document_rect
= GetPixelBounds().ToRECT();
3174 ClientToScreen(&document_rect
);
3176 position
->pt
.x
= target_rect
.left
;
3177 position
->pt
.y
= target_rect
.top
;
3178 position
->cLineHeight
= target_rect
.bottom
- target_rect
.top
;
3179 position
->rcDocument
= document_rect
;
3183 void RenderWidgetHostViewWin::UpdateIMEState() {
3184 if (base::win::IsTSFAwareRequired()) {
3185 ui::TSFBridge::GetInstance()->OnTextInputTypeChanged(this);
3188 if (text_input_type_
!= ui::TEXT_INPUT_TYPE_NONE
&&
3189 text_input_type_
!= ui::TEXT_INPUT_TYPE_PASSWORD
) {
3190 imm32_manager_
->EnableIME(m_hWnd
);
3191 imm32_manager_
->SetUseCompositionWindow(!can_compose_inline_
);
3193 imm32_manager_
->DisableIME(m_hWnd
);
3196 imm32_manager_
->SetTextInputMode(m_hWnd
, text_input_mode_
);
3199 void RenderWidgetHostViewWin::UpdateInputScopeIfNecessary(
3200 ui::TextInputType text_input_type
) {
3201 // The text store is responsible for handling input scope when TSF-aware is
3203 if (base::win::IsTSFAwareRequired())
3206 ui::tsf_inputscope::SetInputScopeForTsfUnawareWindow(
3207 m_hWnd
, text_input_type
, text_input_mode_
);
3210 ////////////////////////////////////////////////////////////////////////////////
3211 // RenderWidgetHostView, public:
3214 RenderWidgetHostView
* RenderWidgetHostView::CreateViewForWidget(
3215 RenderWidgetHost
* widget
) {
3216 return new RenderWidgetHostViewWin(widget
);
3220 void RenderWidgetHostViewPort::GetDefaultScreenInfo(
3221 blink::WebScreenInfo
* results
) {
3222 GetScreenInfoForWindow(0, results
);
3225 } // namespace content