diff options
-rw-r--r-- | base/win/win_util.cc | 27 | ||||
-rw-r--r-- | base/win/win_util.h | 4 | ||||
-rw-r--r-- | chrome/browser/extensions/api/system_display/display_info_provider_win.cc | 2 | ||||
-rw-r--r-- | chrome/browser/fullscreen_win.cc | 2 | ||||
-rw-r--r-- | content/browser/renderer_host/render_widget_host_view_win.cc | 3222 | ||||
-rw-r--r-- | ui/gfx/screen_win.cc | 8 | ||||
-rw-r--r-- | ui/gfx/win/hwnd_util.cc | 4 | ||||
-rw-r--r-- | ui/views/widget/monitor_win.cc | 2 | ||||
-rw-r--r-- | ui/views/win/fullscreen_handler.cc | 4 | ||||
-rw-r--r-- | ui/views/win/hwnd_message_handler.cc | 6 |
10 files changed, 3236 insertions, 45 deletions
diff --git a/base/win/win_util.cc b/base/win/win_util.cc index 7b85418..782df62 100644 --- a/base/win/win_util.cc +++ b/base/win/win_util.cc @@ -329,33 +329,6 @@ bool DismissVirtualKeyboard() { typedef HWND (*MetroRootWindow) (); -// As of this writing, GetMonitorInfo function seem to return wrong values -// for rcWork.left and rcWork.top in case of split screen situation inside -// metro mode. In order to get required values we query for core window screen -// coordinates. -// TODO(shrikant): Remove detour code once GetMonitorInfo is fixed for 8.1. -BOOL GetMonitorInfoWrapper(HMONITOR monitor, MONITORINFO* mi) { - BOOL ret = ::GetMonitorInfo(monitor, mi); -#if !defined(USE_ASH) - if (base::win::IsMetroProcess() && - base::win::GetVersion() >= base::win::VERSION_WIN8_1) { - static MetroRootWindow root_window = NULL; - if (!root_window) { - HMODULE metro = base::win::GetMetroModule(); - // There are apparently instances when current process is inside metro - // environment but metro driver dll is not loaded. - if (!metro) { - return ret; - } - root_window = reinterpret_cast<MetroRootWindow>( - ::GetProcAddress(metro, "GetRootWindow")); - } - ret = ::GetWindowRect(root_window(), &(mi->rcWork)); - } -#endif - return ret; -} - bool IsEnrolledToDomain() { LPWSTR domain; NETSETUP_JOIN_STATUS join_status; diff --git a/base/win/win_util.h b/base/win/win_util.h index eebb64a..d299b14 100644 --- a/base/win/win_util.h +++ b/base/win/win_util.h @@ -126,10 +126,6 @@ BASE_EXPORT bool DisplayVirtualKeyboard(); // above. Returns true on success. BASE_EXPORT bool DismissVirtualKeyboard(); -// Returns monitor info after correcting rcWorkArea based on metro version. -// see bug #247430 for more details. -BASE_EXPORT BOOL GetMonitorInfoWrapper(HMONITOR monitor, MONITORINFO* mi); - // Returns true if the machine is enrolled to a domain. BASE_EXPORT bool IsEnrolledToDomain(); diff --git a/chrome/browser/extensions/api/system_display/display_info_provider_win.cc b/chrome/browser/extensions/api/system_display/display_info_provider_win.cc index ab8fd83..8386921 100644 --- a/chrome/browser/extensions/api/system_display/display_info_provider_win.cc +++ b/chrome/browser/extensions/api/system_display/display_info_provider_win.cc @@ -31,7 +31,7 @@ BOOL CALLBACK EnumMonitorCallback(HMONITOR monitor, MONITORINFOEX monitor_info; ZeroMemory(&monitor_info, sizeof(MONITORINFOEX)); monitor_info.cbSize = sizeof(monitor_info); - base::win::GetMonitorInfoWrapper(monitor, &monitor_info); + GetMonitorInfo(monitor, &monitor_info); DISPLAY_DEVICE device; device.cb = sizeof(device); diff --git a/chrome/browser/fullscreen_win.cc b/chrome/browser/fullscreen_win.cc index 423ff62..06a78b2 100644 --- a/chrome/browser/fullscreen_win.cc +++ b/chrome/browser/fullscreen_win.cc @@ -62,7 +62,7 @@ static bool IsFullScreenWindowMode() { if (!monitor) return false; MONITORINFO monitor_info = { sizeof(monitor_info) }; - if (!base::win::GetMonitorInfoWrapper(monitor, &monitor_info)) + if (!::GetMonitorInfo(monitor, &monitor_info)) return false; // It should be the main monitor. diff --git a/content/browser/renderer_host/render_widget_host_view_win.cc b/content/browser/renderer_host/render_widget_host_view_win.cc new file mode 100644 index 0000000..21cdfb0 --- /dev/null +++ b/content/browser/renderer_host/render_widget_host_view_win.cc @@ -0,0 +1,3222 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/render_widget_host_view_win.h" + +#include <InputScope.h> +#include <wtsapi32.h> +#pragma comment(lib, "wtsapi32.lib") + +#include <algorithm> +#include <map> +#include <stack> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/command_line.h" +#include "base/debug/trace_event.h" +#include "base/i18n/rtl.h" +#include "base/metrics/histogram.h" +#include "base/threading/thread.h" +#include "base/win/metro.h" +#include "base/win/scoped_comptr.h" +#include "base/win/scoped_gdi_object.h" +#include "base/win/win_util.h" +#include "base/win/windows_version.h" +#include "base/win/wrapped_window_proc.h" +#include "content/browser/accessibility/browser_accessibility_manager_win.h" +#include "content/browser/accessibility/browser_accessibility_state_impl.h" +#include "content/browser/accessibility/browser_accessibility_win.h" +#include "content/browser/gpu/gpu_data_manager_impl.h" +#include "content/browser/gpu/gpu_process_host.h" +#include "content/browser/gpu/gpu_process_host_ui_shim.h" +#include "content/browser/renderer_host/backing_store.h" +#include "content/browser/renderer_host/backing_store_win.h" +#include "content/browser/renderer_host/input/web_input_event_builders_win.h" +#include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/browser/renderer_host/ui_events_helper.h" +#include "content/common/accessibility_messages.h" +#include "content/common/gpu/gpu_messages.h" +#include "content/common/plugin_constants_win.h" +#include "content/common/view_messages.h" +#include "content/common/webplugin_geometry.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_data.h" +#include "content/public/browser/content_browser_client.h" +#include "content/public/browser/native_web_keyboard_event.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/common/content_switches.h" +#include "content/public/common/page_zoom.h" +#include "content/public/common/process_type.h" +#include "skia/ext/skia_utils_win.h" +#include "third_party/WebKit/public/web/WebCompositionUnderline.h" +#include "third_party/WebKit/public/web/WebInputEvent.h" +#include "third_party/skia/include/core/SkRegion.h" +#include "ui/base/ime/composition_text.h" +#include "ui/base/ime/win/imm32_manager.h" +#include "ui/base/ime/win/tsf_input_scope.h" +#include "ui/base/l10n/l10n_util_win.h" +#include "ui/base/touch/touch_device.h" +#include "ui/base/touch/touch_enabled.h" +#include "ui/base/ui_base_switches.h" +#include "ui/base/view_prop.h" +#include "ui/base/win/mouse_wheel_util.h" +#include "ui/base/win/touch_input.h" +#include "ui/events/event.h" +#include "ui/events/event_utils.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/rect_conversions.h" +#include "ui/gfx/screen.h" +#include "ui/gfx/sequential_id_generator.h" +#include "ui/gfx/text_elider.h" +#include "ui/gfx/win/dpi.h" +#include "ui/gfx/win/hwnd_util.h" +#include "webkit/common/cursors/webcursor.h" +#include "win8/util/win8_util.h" + +using base::TimeDelta; +using base::TimeTicks; +using ui::ViewProp; +using blink::WebInputEvent; +using blink::WebMouseEvent; +using blink::WebTextDirection; + +namespace content { +namespace { + +// Tooltips will wrap after this width. Yes, wrap. Imagine that! +const int kTooltipMaxWidthPixels = 300; + +// Maximum number of characters we allow in a tooltip. +const int kMaxTooltipLength = 1024; + +// A custom MSAA object id used to determine if a screen reader is actively +// listening for MSAA events. +const int kIdCustom = 1; + +// The delay before the compositor host window is destroyed. This gives the GPU +// process a grace period to stop referencing it. +const int kDestroyCompositorHostWindowDelay = 10000; + +// In mouse lock mode, we need to prevent the (invisible) cursor from hitting +// the border of the view, in order to get valid movement information. However, +// forcing the cursor back to the center of the view after each mouse move +// doesn't work well. It reduces the frequency of useful WM_MOUSEMOVE messages +// significantly. Therefore, we move the cursor to the center of the view only +// if it approaches the border. |kMouseLockBorderPercentage| specifies the width +// of the border area, in percentage of the corresponding dimension. +const int kMouseLockBorderPercentage = 15; + +// A callback function for EnumThreadWindows to enumerate and dismiss +// any owned popup windows. +BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) { + const HWND toplevel_hwnd = reinterpret_cast<HWND>(arg); + + if (::IsWindowVisible(window)) { + const HWND owner = ::GetWindow(window, GW_OWNER); + if (toplevel_hwnd == owner) { + ::PostMessage(window, WM_CANCELMODE, 0, 0); + } + } + + return TRUE; +} + +void SendToGpuProcessHost(int gpu_host_id, scoped_ptr<IPC::Message> message) { + GpuProcessHost* gpu_process_host = GpuProcessHost::FromID(gpu_host_id); + if (!gpu_process_host) + return; + + gpu_process_host->Send(message.release()); +} + +void PostTaskOnIOThread(const tracked_objects::Location& from_here, + base::Closure task) { + BrowserThread::PostTask(BrowserThread::IO, from_here, task); +} + +bool DecodeZoomGesture(HWND hwnd, const GESTUREINFO& gi, + PageZoom* zoom, POINT* zoom_center) { + static long start = 0; + static POINT zoom_first; + + if (gi.dwFlags == GF_BEGIN) { + start = gi.ullArguments; + zoom_first.x = gi.ptsLocation.x; + zoom_first.y = gi.ptsLocation.y; + ScreenToClient(hwnd, &zoom_first); + return false; + } + + if (gi.dwFlags == GF_END) + return false; + + POINT zoom_second = {0}; + zoom_second.x = gi.ptsLocation.x; + zoom_second.y = gi.ptsLocation.y; + ScreenToClient(hwnd, &zoom_second); + + if (zoom_first.x == zoom_second.x && zoom_first.y == zoom_second.y) + return false; + + zoom_center->x = (zoom_first.x + zoom_second.x) / 2; + zoom_center->y = (zoom_first.y + zoom_second.y) / 2; + + double zoom_factor = + static_cast<double>(gi.ullArguments)/static_cast<double>(start); + + *zoom = zoom_factor >= 1 ? PAGE_ZOOM_IN : PAGE_ZOOM_OUT; + + start = gi.ullArguments; + zoom_first = zoom_second; + return true; +} + +bool DecodeScrollGesture(const GESTUREINFO& gi, + POINT* start, + POINT* delta){ + // Windows gestures are streams of messages with begin/end messages that + // separate each new gesture. We key off the begin message to reset + // the static variables. + static POINT last_pt; + static POINT start_pt; + + if (gi.dwFlags == GF_BEGIN) { + delta->x = 0; + delta->y = 0; + start_pt.x = gi.ptsLocation.x; + start_pt.y = gi.ptsLocation.y; + } else { + delta->x = gi.ptsLocation.x - last_pt.x; + delta->y = gi.ptsLocation.y - last_pt.y; + } + last_pt.x = gi.ptsLocation.x; + last_pt.y = gi.ptsLocation.y; + *start = start_pt; + return true; +} + +blink::WebMouseWheelEvent MakeFakeScrollWheelEvent(HWND hwnd, + POINT start, + POINT delta) { + blink::WebMouseWheelEvent result; + result.type = WebInputEvent::MouseWheel; + result.timeStampSeconds = ::GetMessageTime() / 1000.0; + result.button = WebMouseEvent::ButtonNone; + result.globalX = start.x; + result.globalY = start.y; + // Map to window coordinates. + POINT client_point = { result.globalX, result.globalY }; + MapWindowPoints(0, hwnd, &client_point, 1); + result.x = client_point.x; + result.y = client_point.y; + result.windowX = result.x; + result.windowY = result.y; + // Note that we support diagonal scrolling. + result.deltaX = static_cast<float>(delta.x); + result.wheelTicksX = WHEEL_DELTA; + result.deltaY = static_cast<float>(delta.y); + result.wheelTicksY = WHEEL_DELTA; + return result; +} + +static const int kTouchMask = 0x7; + +inline int GetTouchType(const TOUCHINPUT& point) { + return point.dwFlags & kTouchMask; +} + +inline void SetTouchType(TOUCHINPUT* point, int type) { + point->dwFlags = (point->dwFlags & kTouchMask) | type; +} + +ui::EventType ConvertToUIEvent(blink::WebTouchPoint::State t) { + switch (t) { + case blink::WebTouchPoint::StatePressed: + return ui::ET_TOUCH_PRESSED; + case blink::WebTouchPoint::StateMoved: + return ui::ET_TOUCH_MOVED; + case blink::WebTouchPoint::StateStationary: + return ui::ET_TOUCH_STATIONARY; + case blink::WebTouchPoint::StateReleased: + return ui::ET_TOUCH_RELEASED; + case blink::WebTouchPoint::StateCancelled: + return ui::ET_TOUCH_CANCELLED; + default: + DCHECK(false) << "Unexpected ui type. " << t; + return ui::ET_UNKNOWN; + } +} + +// Creates a WebGestureEvent corresponding to the given |gesture| +blink::WebGestureEvent CreateWebGestureEvent(HWND hwnd, + const ui::GestureEvent& gesture) { + blink::WebGestureEvent gesture_event = + MakeWebGestureEventFromUIEvent(gesture); + + POINT client_point = gesture.location().ToPOINT(); + POINT screen_point = gesture.location().ToPOINT(); + MapWindowPoints(hwnd, HWND_DESKTOP, &screen_point, 1); + + gesture_event.x = client_point.x; + gesture_event.y = client_point.y; + gesture_event.globalX = screen_point.x; + gesture_event.globalY = screen_point.y; + + return gesture_event; +} + +blink::WebGestureEvent CreateFlingCancelEvent(double time_stamp) { + blink::WebGestureEvent gesture_event; + gesture_event.timeStampSeconds = time_stamp; + gesture_event.type = blink::WebGestureEvent::GestureFlingCancel; + gesture_event.sourceDevice = blink::WebGestureEvent::Touchscreen; + return gesture_event; +} + +class TouchEventFromWebTouchPoint : public ui::TouchEvent { + public: + TouchEventFromWebTouchPoint(const blink::WebTouchPoint& touch_point, + base::TimeDelta& timestamp) + : ui::TouchEvent(ConvertToUIEvent(touch_point.state), + touch_point.position, + touch_point.id, + timestamp) { + set_radius(touch_point.radiusX, touch_point.radiusY); + set_rotation_angle(touch_point.rotationAngle); + set_force(touch_point.force); + set_flags(ui::GetModifiersFromKeyState()); + } + + virtual ~TouchEventFromWebTouchPoint() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TouchEventFromWebTouchPoint); +}; + +bool ShouldSendPinchGesture() { + static bool pinch_allowed = + CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePinch); + return pinch_allowed; +} + +void GetScreenInfoForWindow(gfx::NativeViewId id, + blink::WebScreenInfo* results) { + HWND window = gfx::NativeViewFromId(id); + + HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY); + + MONITORINFOEX monitor_info; + monitor_info.cbSize = sizeof(MONITORINFOEX); + if (!GetMonitorInfo(monitor, &monitor_info)) + return; + + DEVMODE dev_mode; + dev_mode.dmSize = sizeof(dev_mode); + dev_mode.dmDriverExtra = 0; + EnumDisplaySettings(monitor_info.szDevice, ENUM_CURRENT_SETTINGS, &dev_mode); + + blink::WebScreenInfo screen_info; + screen_info.depth = dev_mode.dmBitsPerPel; + screen_info.depthPerComponent = 8; + screen_info.deviceScaleFactor = gfx::win::GetDeviceScaleFactor(); + screen_info.isMonochrome = dev_mode.dmColor == DMCOLOR_MONOCHROME; + screen_info.rect = gfx::Rect(monitor_info.rcMonitor); + screen_info.availableRect = gfx::Rect(monitor_info.rcWork); + + *results = screen_info; +} + +} // namespace + +const wchar_t kRenderWidgetHostHWNDClass[] = L"Chrome_RenderWidgetHostHWND"; + +// Wrapper for maintaining touchstate associated with a WebTouchEvent. +class WebTouchState { + public: + explicit WebTouchState(const RenderWidgetHostViewWin* window); + + // Updates the current touchpoint state with the supplied touches. + // Touches will be consumed only if they are of the same type (e.g. down, + // up, move). Returns the number of consumed touches. + size_t UpdateTouchPoints(TOUCHINPUT* points, size_t count); + + // Marks all active touchpoints as released. + bool ReleaseTouchPoints(); + + // The contained WebTouchEvent. + const blink::WebTouchEvent& touch_event() { return touch_event_; } + + // Returns if any touches are modified in the event. + bool is_changed() { return touch_event_.changedTouchesLength != 0; } + + private: + // Adds a touch point or returns NULL if there's not enough space. + blink::WebTouchPoint* AddTouchPoint(TOUCHINPUT* touch_input); + + // Copy details from a TOUCHINPUT to an existing WebTouchPoint, returning + // true if the resulting point is a stationary move. + bool UpdateTouchPoint(blink::WebTouchPoint* touch_point, + TOUCHINPUT* touch_input); + + // Find (or create) a mapping for _os_touch_id_. + unsigned int GetMappedTouch(unsigned int os_touch_id); + + // Remove any mappings that are no longer in use. + void RemoveExpiredMappings(); + + blink::WebTouchEvent touch_event_; + const RenderWidgetHostViewWin* const window_; + + ui::SequentialIDGenerator id_generator_; + + DISALLOW_COPY_AND_ASSIGN(WebTouchState); +}; + +typedef void (*MetroSetFrameWindow)(HWND window); +typedef void (*MetroCloseFrameWindow)(HWND window); + +/////////////////////////////////////////////////////////////////////////////// +// RenderWidgetHostViewWin, public: + +RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget) + : render_widget_host_(RenderWidgetHostImpl::From(widget)), + compositor_host_window_(NULL), + hide_compositor_window_at_next_paint_(false), + track_mouse_leave_(false), + imm32_manager_(new ui::IMM32Manager), + ime_notification_(false), + capture_enter_key_(false), + about_to_validate_and_paint_(false), + close_on_deactivate_(false), + being_destroyed_(false), + tooltip_hwnd_(NULL), + tooltip_showing_(false), + weak_factory_(this), + is_loading_(false), + text_input_type_(ui::TEXT_INPUT_TYPE_NONE), + text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT), + can_compose_inline_(true), + is_fullscreen_(false), + ignore_mouse_movement_(true), + composition_range_(gfx::Range::InvalidRange()), + touch_state_(new WebTouchState(this)), + pointer_down_context_(false), + last_touch_location_(-1, -1), + touch_events_enabled_(ui::AreTouchEventsEnabled()), + gesture_recognizer_(ui::GestureRecognizer::Create()) { + render_widget_host_->SetView(this); + registrar_.Add(this, + NOTIFICATION_RENDERER_PROCESS_TERMINATED, + NotificationService::AllBrowserContextsAndSources()); + gesture_recognizer_->AddGestureEventHelper(this); +} + +RenderWidgetHostViewWin::~RenderWidgetHostViewWin() { + gesture_recognizer_->RemoveGestureEventHelper(this); + UnlockMouse(); + ResetTooltip(); +} + +void RenderWidgetHostViewWin::CreateWnd(HWND parent) { + // ATL function to create the window. + Create(parent); +} + +/////////////////////////////////////////////////////////////////////////////// +// RenderWidgetHostViewWin, RenderWidgetHostView implementation: + +void RenderWidgetHostViewWin::InitAsChild( + gfx::NativeView parent_view) { + CreateWnd(parent_view); +} + +void RenderWidgetHostViewWin::InitAsPopup( + RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) { + close_on_deactivate_ = true; + DoPopupOrFullscreenInit(parent_host_view->GetNativeView(), pos, + WS_EX_TOOLWINDOW); +} + +void RenderWidgetHostViewWin::InitAsFullscreen( + RenderWidgetHostView* reference_host_view) { + gfx::Rect pos = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow( + reference_host_view->GetNativeView()).bounds(); + is_fullscreen_ = true; + DoPopupOrFullscreenInit(gfx::GetWindowToParentTo(true), pos, 0); +} + +RenderWidgetHost* RenderWidgetHostViewWin::GetRenderWidgetHost() const { + return render_widget_host_; +} + +void RenderWidgetHostViewWin::WasShown() { + // |render_widget_host_| may be NULL if the WebContentsImpl is in the process + // of closing. + if (!render_widget_host_) + return; + + if (!render_widget_host_->is_hidden()) + return; + + if (web_contents_switch_paint_time_.is_null()) + web_contents_switch_paint_time_ = TimeTicks::Now(); + + render_widget_host_->WasShown(); +} + +void RenderWidgetHostViewWin::WasHidden() { + // |render_widget_host_| may be NULL if the WebContentsImpl is in the process + // of closing. + if (!render_widget_host_) + return; + + if (render_widget_host_->is_hidden()) + return; + + ResetTooltip(); + + // Inform the renderer that we are being hidden so it can reduce its resource + // utilization. + render_widget_host_->WasHidden(); + + if (accelerated_surface_) + accelerated_surface_->WasHidden(); + + if (GetBrowserAccessibilityManager()) + GetBrowserAccessibilityManager()->WasHidden(); + + web_contents_switch_paint_time_ = base::TimeTicks(); +} + +void RenderWidgetHostViewWin::SetSize(const gfx::Size& size) { + SetBounds(gfx::Rect(GetPixelBounds().origin(), size)); +} + +void RenderWidgetHostViewWin::SetBounds(const gfx::Rect& rect) { + if (being_destroyed_) + return; + + // No SWP_NOREDRAW as autofill popups can move and the underneath window + // should redraw in that case. + UINT swp_flags = SWP_NOSENDCHANGING | SWP_NOOWNERZORDER | SWP_NOCOPYBITS | + SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE; + + // If the style is not popup, you have to convert the point to client + // coordinate. + POINT point = { rect.x(), rect.y() }; + if (GetStyle() & WS_CHILD) + ScreenToClient(&point); + + SetWindowPos(NULL, point.x, point.y, rect.width(), rect.height(), swp_flags); + render_widget_host_->WasResized(); +} + +gfx::NativeView RenderWidgetHostViewWin::GetNativeView() const { + return m_hWnd; +} + +gfx::NativeViewId RenderWidgetHostViewWin::GetNativeViewId() const { + return reinterpret_cast<gfx::NativeViewId>(m_hWnd); +} + +gfx::NativeViewAccessible +RenderWidgetHostViewWin::GetNativeViewAccessible() { + if (render_widget_host_ && + !BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) { + // Attempt to detect screen readers by sending an event with our custom id. + NotifyWinEvent(EVENT_SYSTEM_ALERT, m_hWnd, kIdCustom, CHILDID_SELF); + } + + CreateBrowserAccessibilityManagerIfNeeded(); + + return GetBrowserAccessibilityManager()->GetRoot()-> + ToBrowserAccessibilityWin(); +} + +void RenderWidgetHostViewWin::MovePluginWindows( + const gfx::Vector2d& scroll_offset, + const std::vector<WebPluginGeometry>& plugin_window_moves) { + MovePluginWindowsHelper(m_hWnd, plugin_window_moves); +} + +static BOOL CALLBACK AddChildWindowToVector(HWND hwnd, LPARAM lparam) { + std::vector<HWND>* vector = reinterpret_cast<std::vector<HWND>*>(lparam); + vector->push_back(hwnd); + return TRUE; +} + +void RenderWidgetHostViewWin::CleanupCompositorWindow() { + if (!compositor_host_window_) + return; + + gfx::SetWindowUserData(compositor_host_window_, NULL); + + // Hide the compositor and parent it to the desktop rather than destroying + // it immediately. The GPU process has a grace period to stop accessing the + // window. TODO(apatrick): the GPU process should acknowledge that it has + // finished with the window handle and the browser process should destroy it + // at that point. + ::ShowWindow(compositor_host_window_, SW_HIDE); + ::SetParent(compositor_host_window_, NULL); + + BrowserThread::PostDelayedTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(base::IgnoreResult(&::DestroyWindow), + compositor_host_window_), + base::TimeDelta::FromMilliseconds(kDestroyCompositorHostWindowDelay)); + + compositor_host_window_ = NULL; +} + +bool RenderWidgetHostViewWin::IsActivatable() const { + // Popups should not be activated. + return popup_type_ == blink::WebPopupTypeNone; +} + +void RenderWidgetHostViewWin::Focus() { + if (IsWindow()) + SetFocus(); +} + +void RenderWidgetHostViewWin::Blur() { + NOTREACHED(); +} + +bool RenderWidgetHostViewWin::HasFocus() const { + return ::GetFocus() == m_hWnd; +} + +bool RenderWidgetHostViewWin::IsSurfaceAvailableForCopy() const { + if (render_widget_host_->is_accelerated_compositing_active()) + return accelerated_surface_.get() && accelerated_surface_->IsReadyForCopy(); + else + return !!render_widget_host_->GetBackingStore(false); +} + +void RenderWidgetHostViewWin::Show() { + ShowWindow(SW_SHOW); + WasShown(); +} + +void RenderWidgetHostViewWin::Hide() { + if (!is_fullscreen_ && GetParent() == gfx::GetWindowToParentTo(true)) { + LOG(WARNING) << "Hide() called twice in a row: " << this << ":" + << GetParent(); + return; + } + + if (::GetFocus() == m_hWnd) + ::SetFocus(NULL); + ShowWindow(SW_HIDE); + + WasHidden(); +} + +bool RenderWidgetHostViewWin::IsShowing() { + return !!IsWindowVisible(); +} + +gfx::Rect RenderWidgetHostViewWin::GetViewBounds() const { + return gfx::win::ScreenToDIPRect(GetPixelBounds()); +} + +gfx::Rect RenderWidgetHostViewWin::GetPixelBounds() const { + CRect window_rect; + GetWindowRect(&window_rect); + return gfx::Rect(window_rect); +} + +void RenderWidgetHostViewWin::UpdateCursor(const WebCursor& cursor) { + current_cursor_ = cursor; + UpdateCursorIfOverSelf(); +} + +void RenderWidgetHostViewWin::UpdateCursorIfOverSelf() { + static HCURSOR kCursorArrow = LoadCursor(NULL, IDC_ARROW); + static HCURSOR kCursorAppStarting = LoadCursor(NULL, IDC_APPSTARTING); + static HINSTANCE module_handle = GetModuleHandle( + GetContentClient()->browser()->GetResourceDllName()); + + // If the mouse is over our HWND, then update the cursor state immediately. + CPoint pt; + GetCursorPos(&pt); + if (WindowFromPoint(pt) == m_hWnd) { + // We cannot pass in NULL as the module handle as this would only work for + // standard win32 cursors. We can also receive cursor types which are + // defined as webkit resources. We need to specify the module handle of + // chrome.dll while loading these cursors. + HCURSOR display_cursor = current_cursor_.GetCursor(module_handle); + + // If a page is in the loading state, we want to show the Arrow+Hourglass + // cursor only when the current cursor is the ARROW cursor. In all other + // cases we should continue to display the current cursor. + if (is_loading_ && display_cursor == kCursorArrow) + display_cursor = kCursorAppStarting; + + SetCursor(display_cursor); + } +} + +void RenderWidgetHostViewWin::SetIsLoading(bool is_loading) { + is_loading_ = is_loading; + UpdateCursorIfOverSelf(); +} + +void RenderWidgetHostViewWin::TextInputTypeChanged( + ui::TextInputType type, + ui::TextInputMode input_mode, + bool can_compose_inline) { + if (text_input_type_ != type || + text_input_mode_ != input_mode || + can_compose_inline_ != can_compose_inline) { + const bool text_input_type_changed = (text_input_type_ != type) || + (text_input_mode_ != input_mode); + text_input_type_ = type; + text_input_mode_ = input_mode; + can_compose_inline_ = can_compose_inline; + UpdateIMEState(); + if (text_input_type_changed) + UpdateInputScopeIfNecessary(text_input_type_); + } +} + +void RenderWidgetHostViewWin::SelectionBoundsChanged( + const ViewHostMsg_SelectionBounds_Params& params) { + bool is_enabled = (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE && + text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD); + // Only update caret position if the input method is enabled. + if (is_enabled) { + caret_rect_ = gfx::UnionRects(params.anchor_rect, params.focus_rect); + imm32_manager_->UpdateCaretRect(m_hWnd, caret_rect_); + } +} + +void RenderWidgetHostViewWin::ScrollOffsetChanged() { +} + +void RenderWidgetHostViewWin::ImeCancelComposition() { + imm32_manager_->CancelIME(m_hWnd); +} + +void RenderWidgetHostViewWin::ImeCompositionRangeChanged( + const gfx::Range& range, + const std::vector<gfx::Rect>& character_bounds) { + composition_range_ = range; + composition_character_bounds_ = character_bounds; +} + +void RenderWidgetHostViewWin::Redraw() { + RECT damage_bounds; + GetUpdateRect(&damage_bounds, FALSE); + + base::win::ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0)); + GetUpdateRgn(damage_region, FALSE); + + // Paint the invalid region synchronously. Our caller will not paint again + // until we return, so by painting to the screen here, we ensure effective + // rate-limiting of backing store updates. This helps a lot on pages that + // have animations or fairly expensive layout (e.g., google maps). + // + // We paint this window synchronously, however child windows (i.e. plugins) + // are painted asynchronously. By avoiding synchronous cross-process window + // message dispatching we allow scrolling to be smooth, and also avoid the + // browser process locking up if the plugin process is hung. + // + RedrawWindow(NULL, damage_region, RDW_UPDATENOW | RDW_NOCHILDREN); + + // Send the invalid rect in screen coordinates. + gfx::Rect invalid_screen_rect(damage_bounds); + invalid_screen_rect.Offset(GetPixelBounds().OffsetFromOrigin()); + + PaintPluginWindowsHelper(m_hWnd, invalid_screen_rect); +} + +void RenderWidgetHostViewWin::DidUpdateBackingStore( + const gfx::Rect& scroll_rect, + const gfx::Vector2d& scroll_delta, + const std::vector<gfx::Rect>& copy_rects, + const std::vector<ui::LatencyInfo>& latency_info) { + TRACE_EVENT0("content", "RenderWidgetHostViewWin::DidUpdateBackingStore"); + for (size_t i = 0; i < latency_info.size(); i++) + software_latency_info_.push_back(latency_info[i]); + if (render_widget_host_->is_hidden()) + return; + + // Schedule invalidations first so that the ScrollWindowEx call is closer to + // Redraw. That minimizes chances of "flicker" resulting if the screen + // refreshes before we have a chance to paint the exposed area. Somewhat + // surprisingly, this ordering matters. + + for (size_t i = 0; i < copy_rects.size(); ++i) { + gfx::Rect pixel_rect = gfx::win::DIPToScreenRect(copy_rects[i]); + // Damage might not be DIP aligned. + pixel_rect.Inset(-1, -1); + RECT bounds = pixel_rect.ToRECT(); + InvalidateRect(&bounds, false); + } + + if (!scroll_rect.IsEmpty()) { + TRACE_EVENT0("content", "ScrollWindowEx"); + gfx::Rect pixel_rect = gfx::win::DIPToScreenRect(scroll_rect); + // Damage might not be DIP aligned. + pixel_rect.Inset(-1, -1); + RECT clip_rect = pixel_rect.ToRECT(); + float scale = gfx::win::GetDeviceScaleFactor(); + int dx = static_cast<int>(scale * scroll_delta.x()); + int dy = static_cast<int>(scale * scroll_delta.y()); + ScrollWindowEx(dx, dy, NULL, &clip_rect, NULL, NULL, SW_INVALIDATE); + } + + if (!about_to_validate_and_paint_) + Redraw(); +} + +void RenderWidgetHostViewWin::RenderProcessGone(base::TerminationStatus status, + int error_code) { + UpdateCursorIfOverSelf(); + Destroy(); +} + +bool RenderWidgetHostViewWin::CanSubscribeFrame() const { + return render_widget_host_ != NULL; +} + +void RenderWidgetHostViewWin::WillWmDestroy() { + CleanupCompositorWindow(); + if (base::win::IsTSFAwareRequired()) + ui::TSFBridge::GetInstance()->RemoveFocusedClient(this); +} + +void RenderWidgetHostViewWin::Destroy() { + // We've been told to destroy. + // By clearing close_on_deactivate_, we prevent further deactivations + // (caused by windows messages resulting from the DestroyWindow) from + // triggering further destructions. The deletion of this is handled by + // OnFinalMessage(); + close_on_deactivate_ = false; + render_widget_host_ = NULL; + being_destroyed_ = true; + CleanupCompositorWindow(); + + // This releases the resources associated with input scope. + UpdateInputScopeIfNecessary(ui::TEXT_INPUT_TYPE_NONE); + + if (is_fullscreen_ && win8::IsSingleWindowMetroMode()) { + MetroCloseFrameWindow close_frame_window = + reinterpret_cast<MetroCloseFrameWindow>( + ::GetProcAddress(base::win::GetMetroModule(), "CloseFrameWindow")); + DCHECK(close_frame_window); + close_frame_window(m_hWnd); + } + + DestroyWindow(); +} + +void RenderWidgetHostViewWin::SetTooltipText( + const base::string16& tooltip_text) { + if (!render_widget_host_->is_hidden()) + EnsureTooltip(); + + // Clamp the tooltip length to kMaxTooltipLength so that we don't + // accidentally DOS the user with a mega tooltip (since Windows doesn't seem + // to do this itself). + const base::string16 new_tooltip_text = + gfx::TruncateString(tooltip_text, kMaxTooltipLength); + + if (new_tooltip_text != tooltip_text_) { + tooltip_text_ = new_tooltip_text; + + // Need to check if the tooltip is already showing so that we don't + // immediately show the tooltip with no delay when we move the mouse from + // a region with no tooltip to a region with a tooltip. + if (::IsWindow(tooltip_hwnd_) && tooltip_showing_) { + ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0); + ::SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0); + } + } else { + // Make sure the tooltip gets closed after TTN_POP gets sent. For some + // reason this doesn't happen automatically, so moving the mouse around + // within the same link/image/etc doesn't cause the tooltip to re-appear. + if (!tooltip_showing_) { + if (::IsWindow(tooltip_hwnd_)) + ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0); + } + } +} + +BackingStore* RenderWidgetHostViewWin::AllocBackingStore( + const gfx::Size& size) { + return new BackingStoreWin(render_widget_host_, size); +} + +void RenderWidgetHostViewWin::CopyFromCompositingSurface( + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const base::Callback<void(bool, const SkBitmap&)>& callback) { + base::ScopedClosureRunner scoped_callback_runner( + base::Bind(callback, false, SkBitmap())); + if (!accelerated_surface_) + return; + + if (dst_size.IsEmpty() || src_subrect.IsEmpty()) + return; + + ignore_result(scoped_callback_runner.Release()); + accelerated_surface_->AsyncCopyTo(src_subrect, dst_size, callback); +} + +void RenderWidgetHostViewWin::CopyFromCompositingSurfaceToVideoFrame( + const gfx::Rect& src_subrect, + const scoped_refptr<media::VideoFrame>& target, + const base::Callback<void(bool)>& callback) { + base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false)); + if (!accelerated_surface_) + return; + + if (!target || (target->format() != media::VideoFrame::YV12 && + target->format() != media::VideoFrame::I420)) + return; + + if (src_subrect.IsEmpty()) + return; + + ignore_result(scoped_callback_runner.Release()); + accelerated_surface_->AsyncCopyToVideoFrame(src_subrect, target, callback); +} + +bool RenderWidgetHostViewWin::CanCopyToVideoFrame() const { + return accelerated_surface_.get() && render_widget_host_ && + render_widget_host_->is_accelerated_compositing_active(); +} + +void RenderWidgetHostViewWin::SetBackground(const SkBitmap& background) { + RenderWidgetHostViewBase::SetBackground(background); + render_widget_host_->SetBackground(background); +} + +void RenderWidgetHostViewWin::ProcessAckedTouchEvent( + const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) { + DCHECK(touch_events_enabled_); + + ScopedVector<ui::TouchEvent> events; + if (!MakeUITouchEventsFromWebTouchEvents(touch, &events, LOCAL_COORDINATES)) + return; + + ui::EventResult result = (ack_result == + INPUT_EVENT_ACK_STATE_CONSUMED) ? ui::ER_HANDLED : ui::ER_UNHANDLED; + for (ScopedVector<ui::TouchEvent>::iterator iter = events.begin(), + end = events.end(); iter != end; ++iter) { + scoped_ptr<ui::GestureRecognizer::Gestures> gestures; + gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture( + *(*iter), result, this)); + ProcessGestures(gestures.get()); + } +} + +void RenderWidgetHostViewWin::UpdateDesiredTouchMode() { + // Make sure that touch events even make sense. + if (base::win::GetVersion() < base::win::VERSION_WIN7) + return; + if (touch_events_enabled_) { + CHECK(RegisterTouchWindow(m_hWnd, TWF_WANTPALM)); + } +} + +bool RenderWidgetHostViewWin::CanDispatchToConsumer( + ui::GestureConsumer* consumer) { + CHECK_EQ(static_cast<RenderWidgetHostViewWin*>(consumer), this); + return true; +} + +void RenderWidgetHostViewWin::DispatchPostponedGestureEvent( + ui::GestureEvent* event) { + ForwardGestureEventToRenderer(event); +} + +void RenderWidgetHostViewWin::DispatchCancelTouchEvent( + ui::TouchEvent* event) { + if (!render_widget_host_ || !touch_events_enabled_ || + !render_widget_host_->ShouldForwardTouchEvent()) { + return; + } + DCHECK(event->type() == blink::WebInputEvent::TouchCancel); + blink::WebTouchEvent cancel_event; + cancel_event.type = blink::WebInputEvent::TouchCancel; + cancel_event.timeStampSeconds = event->time_stamp().InSecondsF(); + render_widget_host_->ForwardTouchEventWithLatencyInfo( + cancel_event, *event->latency()); +} + +void RenderWidgetHostViewWin::SetHasHorizontalScrollbar( + bool has_horizontal_scrollbar) { +} + +void RenderWidgetHostViewWin::SetScrollOffsetPinning( + bool is_pinned_to_left, bool is_pinned_to_right) { +} + +void RenderWidgetHostViewWin::SetCompositionText( + const ui::CompositionText& composition) { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return; + } + if (!render_widget_host_) + return; + // ui::CompositionUnderline should be identical to + // blink::WebCompositionUnderline, so that we can do reinterpret_cast safely. + COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == + sizeof(blink::WebCompositionUnderline), + ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff); + const std::vector<blink::WebCompositionUnderline>& underlines = + reinterpret_cast<const std::vector<blink::WebCompositionUnderline>&>( + composition.underlines); + render_widget_host_->ImeSetComposition(composition.text, underlines, + composition.selection.end(), + composition.selection.end()); +} + +void RenderWidgetHostViewWin::ConfirmCompositionText() { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return; + } + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); +} + +void RenderWidgetHostViewWin::ClearCompositionText() { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return; + } + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); +} + +void RenderWidgetHostViewWin::InsertText(const base::string16& text) { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return; + } + if (render_widget_host_) + render_widget_host_->ImeConfirmComposition(text, + gfx::Range::InvalidRange(), + false); +} + +void RenderWidgetHostViewWin::InsertChar(base::char16 ch, int flags) { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return; + } + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); +} + +gfx::NativeWindow RenderWidgetHostViewWin::GetAttachedWindow() const { + return m_hWnd; +} + +ui::TextInputType RenderWidgetHostViewWin::GetTextInputType() const { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return ui::TEXT_INPUT_TYPE_NONE; + } + return text_input_type_; +} + +ui::TextInputMode RenderWidgetHostViewWin::GetTextInputMode() const { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return ui::TEXT_INPUT_MODE_DEFAULT; + } + return text_input_mode_; +} + +bool RenderWidgetHostViewWin::CanComposeInline() const { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return false; + } + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); + return false; +} + +gfx::Rect RenderWidgetHostViewWin::GetCaretBounds() const { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return gfx::Rect(0, 0, 0, 0); + } + RECT tmp_rect = caret_rect_.ToRECT(); + ClientToScreen(&tmp_rect); + return gfx::Rect(tmp_rect); +} + +bool RenderWidgetHostViewWin::GetCompositionCharacterBounds( + uint32 index, gfx::Rect* rect) const { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return false; + } + DCHECK(rect); + if (index >= composition_character_bounds_.size()) + return false; + RECT rec = composition_character_bounds_[index].ToRECT(); + ClientToScreen(&rec); + *rect = gfx::Rect(rec); + return true; +} + +bool RenderWidgetHostViewWin::HasCompositionText() const { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return false; + } + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); + return false; +} + +bool RenderWidgetHostViewWin::GetTextRange(gfx::Range* range) const { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return false; + } + range->set_start(selection_text_offset_); + range->set_end(selection_text_offset_ + selection_text_.length()); + return false; +} + +bool RenderWidgetHostViewWin::GetCompositionTextRange(gfx::Range* range) const { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return false; + } + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); + return false; +} + +bool RenderWidgetHostViewWin::GetSelectionRange(gfx::Range* range) const { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return false; + } + range->set_start(selection_range_.start()); + range->set_end(selection_range_.end()); + return false; +} + +bool RenderWidgetHostViewWin::SetSelectionRange(const gfx::Range& range) { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return false; + } + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); + return false; +} + +bool RenderWidgetHostViewWin::DeleteRange(const gfx::Range& range) { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return false; + } + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); + return false; +} + +bool RenderWidgetHostViewWin::GetTextFromRange(const gfx::Range& range, + base::string16* text) const { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return false; + } + gfx::Range selection_text_range(selection_text_offset_, + selection_text_offset_ + selection_text_.length()); + if (!selection_text_range.Contains(range)) { + text->clear(); + return false; + } + if (selection_text_range.EqualsIgnoringDirection(range)) { + *text = selection_text_; + } else { + *text = selection_text_.substr( + range.GetMin() - selection_text_offset_, + range.length()); + } + return true; +} + +void RenderWidgetHostViewWin::OnInputMethodChanged() { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return; + } + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); +} + +bool RenderWidgetHostViewWin::ChangeTextDirectionAndLayoutAlignment( + base::i18n::TextDirection direction) { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return false; + } + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); + return false; +} + +void RenderWidgetHostViewWin::ExtendSelectionAndDelete( + size_t before, + size_t after) { + if (!base::win::IsTSFAwareRequired()) { + NOTREACHED(); + return; + } + if (!render_widget_host_) + return; + render_widget_host_->ExtendSelectionAndDelete(before, after); +} + +void RenderWidgetHostViewWin::EnsureCaretInRect(const gfx::Rect& rect) { + // TODO(nona): Implement this function. + NOTIMPLEMENTED(); +} + +void RenderWidgetHostViewWin::OnCandidateWindowShown() { +} + +void RenderWidgetHostViewWin::OnCandidateWindowUpdated() { +} + +void RenderWidgetHostViewWin::OnCandidateWindowHidden() { +} + +/////////////////////////////////////////////////////////////////////////////// +// RenderWidgetHostViewWin, private: + +LRESULT RenderWidgetHostViewWin::OnCreate(CREATESTRUCT* create_struct) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnCreate"); + // Call the WM_INPUTLANGCHANGE message handler to initialize the input locale + // of a browser process. + OnInputLangChange(0, 0); + // Marks that window as supporting mouse-wheel messages rerouting so it is + // scrolled when under the mouse pointer even if inactive. + props_.push_back(ui::SetWindowSupportsRerouteMouseWheel(m_hWnd)); + + WTSRegisterSessionNotification(m_hWnd, NOTIFY_FOR_THIS_SESSION); + + UpdateDesiredTouchMode(); + UpdateIMEState(); + + return 0; +} + +void RenderWidgetHostViewWin::OnActivate(UINT action, BOOL minimized, + HWND window) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnActivate"); + // If the container is a popup, clicking elsewhere on screen should close the + // popup. + if (close_on_deactivate_ && action == WA_INACTIVE) { + // Send a windows message so that any derived classes + // will get a change to override the default handling + SendMessage(WM_CANCELMODE); + } +} + +void RenderWidgetHostViewWin::OnDestroy() { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnDestroy"); + DetachPluginsHelper(m_hWnd); + + props_.clear(); + + if (base::win::GetVersion() >= base::win::VERSION_WIN7 && + IsTouchWindow(m_hWnd, NULL)) { + UnregisterTouchWindow(m_hWnd); + } + + CleanupCompositorWindow(); + + WTSUnRegisterSessionNotification(m_hWnd); + + ResetTooltip(); + TrackMouseLeave(false); +} + +void RenderWidgetHostViewWin::OnPaint(HDC unused_dc) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnPaint"); + + // Grab the region to paint before creation of paint_dc since it clears the + // damage region. + base::win::ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0)); + GetUpdateRgn(damage_region, FALSE); + + CPaintDC paint_dc(m_hWnd); + + if (!render_widget_host_) + return; + + DCHECK(render_widget_host_->GetProcess()->HasConnection()); + + // If the GPU process is rendering to a child window, compositing is + // already triggered by damage to compositor_host_window_, so all we need to + // do here is clear borders during resize. + if (compositor_host_window_ && + render_widget_host_->is_accelerated_compositing_active()) { + RECT host_rect, child_rect; + GetClientRect(&host_rect); + if (::GetClientRect(compositor_host_window_, &child_rect) && + (child_rect.right < host_rect.right || + child_rect.bottom < host_rect.bottom)) { + paint_dc.FillRect(&host_rect, + reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH))); + } + return; + } + + if (accelerated_surface_.get() && + render_widget_host_->is_accelerated_compositing_active()) { + AcceleratedPaint(paint_dc.m_hDC); + return; + } + + about_to_validate_and_paint_ = true; + BackingStoreWin* backing_store = static_cast<BackingStoreWin*>( + render_widget_host_->GetBackingStore(true)); + + // We initialize |paint_dc| (and thus call BeginPaint()) after calling + // GetBackingStore(), so that if it updates the invalid rect we'll catch the + // changes and repaint them. + about_to_validate_and_paint_ = false; + + if (compositor_host_window_ && hide_compositor_window_at_next_paint_) { + ::ShowWindow(compositor_host_window_, SW_HIDE); + hide_compositor_window_at_next_paint_ = false; + } + + gfx::Rect damaged_rect(paint_dc.m_ps.rcPaint); + if (damaged_rect.IsEmpty()) + return; + + if (backing_store) { + gfx::Rect bitmap_rect(gfx::Point(), + gfx::win::DIPToScreenSize(backing_store->size())); + + bool manage_colors = BackingStoreWin::ColorManagementEnabled(); + if (manage_colors) + SetICMMode(paint_dc.m_hDC, ICM_ON); + + // Blit only the damaged regions from the backing store. + DWORD data_size = GetRegionData(damage_region, 0, NULL); + scoped_ptr<char[]> region_data_buf; + RGNDATA* region_data = NULL; + RECT* region_rects = NULL; + + if (data_size) { + region_data_buf.reset(new char[data_size]); + region_data = reinterpret_cast<RGNDATA*>(region_data_buf.get()); + region_rects = reinterpret_cast<RECT*>(region_data->Buffer); + data_size = GetRegionData(damage_region, data_size, region_data); + } + + if (!data_size) { + // Grabbing the damaged regions failed, fake with the whole rect. + data_size = sizeof(RGNDATAHEADER) + sizeof(RECT); + region_data_buf.reset(new char[data_size]); + region_data = reinterpret_cast<RGNDATA*>(region_data_buf.get()); + region_rects = reinterpret_cast<RECT*>(region_data->Buffer); + region_data->rdh.nCount = 1; + region_rects[0] = damaged_rect.ToRECT(); + } + + for (DWORD i = 0; i < region_data->rdh.nCount; ++i) { + gfx::Rect paint_rect = + gfx::IntersectRects(bitmap_rect, gfx::Rect(region_rects[i])); + if (!paint_rect.IsEmpty()) { + BitBlt(paint_dc.m_hDC, + paint_rect.x(), + paint_rect.y(), + paint_rect.width(), + paint_rect.height(), + backing_store->hdc(), + paint_rect.x(), + paint_rect.y(), + SRCCOPY); + } + } + + if (manage_colors) + SetICMMode(paint_dc.m_hDC, ICM_OFF); + + // Fill the remaining portion of the damaged_rect with the background + if (damaged_rect.right() > bitmap_rect.right()) { + RECT r; + r.left = std::max(bitmap_rect.right(), damaged_rect.x()); + r.right = damaged_rect.right(); + r.top = damaged_rect.y(); + r.bottom = std::min(bitmap_rect.bottom(), damaged_rect.bottom()); + DrawBackground(r, &paint_dc); + } + if (damaged_rect.bottom() > bitmap_rect.bottom()) { + RECT r; + r.left = damaged_rect.x(); + r.right = damaged_rect.right(); + r.top = std::max(bitmap_rect.bottom(), damaged_rect.y()); + r.bottom = damaged_rect.bottom(); + DrawBackground(r, &paint_dc); + } + if (!whiteout_start_time_.is_null()) { + TimeDelta whiteout_duration = TimeTicks::Now() - whiteout_start_time_; + UMA_HISTOGRAM_TIMES("MPArch.RWHH_WhiteoutDuration", whiteout_duration); + + // Reset the start time to 0 so that we start recording again the next + // time the backing store is NULL... + whiteout_start_time_ = TimeTicks(); + } + if (!web_contents_switch_paint_time_.is_null()) { + TimeDelta web_contents_switch_paint_duration = TimeTicks::Now() - + web_contents_switch_paint_time_; + UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", + web_contents_switch_paint_duration); + // Reset contents_switch_paint_time_ to 0 so future tab selections are + // recorded. + web_contents_switch_paint_time_ = TimeTicks(); + } + + for (size_t i = 0; i < software_latency_info_.size(); i++) { + software_latency_info_[i].AddLatencyNumber( + ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0); + render_widget_host_->FrameSwapped(software_latency_info_[i]); + } + software_latency_info_.clear(); + } else { + DrawBackground(paint_dc.m_ps.rcPaint, &paint_dc); + if (whiteout_start_time_.is_null()) + whiteout_start_time_ = TimeTicks::Now(); + } +} + +void RenderWidgetHostViewWin::DrawBackground(const RECT& dirty_rect, + CPaintDC* dc) { + if (!background_.empty()) { + gfx::Rect dirty_area(dirty_rect); + gfx::Canvas canvas(dirty_area.size(), 1.0f, true); + canvas.Translate(-dirty_area.OffsetFromOrigin()); + + gfx::Rect dc_rect(dc->m_ps.rcPaint); + // TODO(pkotwicz): Fix |background_| such that it is an ImageSkia. + canvas.TileImageInt(gfx::ImageSkia::CreateFrom1xBitmap(background_), + 0, 0, dc_rect.width(), dc_rect.height()); + + skia::DrawToNativeContext(canvas.sk_canvas(), *dc, dirty_area.x(), + dirty_area.y(), NULL); + } else { + HBRUSH white_brush = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); + dc->FillRect(&dirty_rect, white_brush); + } +} + +void RenderWidgetHostViewWin::OnNCPaint(HRGN update_region) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnNCPaint"); + // Do nothing. This suppresses the resize corner that Windows would + // otherwise draw for us. +} + +void RenderWidgetHostViewWin::SetClickthroughRegion(SkRegion* region) { + transparent_region_.reset(region); +} + +LRESULT RenderWidgetHostViewWin::OnNCHitTest(const CPoint& point) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnNCHitTest"); + RECT rc; + GetWindowRect(&rc); + if (transparent_region_.get() && + transparent_region_->contains(point.x - rc.left, point.y - rc.top)) { + SetMsgHandled(TRUE); + return HTTRANSPARENT; + } + SetMsgHandled(FALSE); + return 0; +} + +LRESULT RenderWidgetHostViewWin::OnEraseBkgnd(HDC dc) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnEraseBkgnd"); + return 1; +} + +LRESULT RenderWidgetHostViewWin::OnSetCursor(HWND window, UINT hittest_code, + UINT mouse_message_id) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSetCursor"); + UpdateCursorIfOverSelf(); + return 0; +} + +void RenderWidgetHostViewWin::OnSetFocus(HWND window) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSetFocus"); + if (!render_widget_host_) + return; + + if (GetBrowserAccessibilityManager()) + GetBrowserAccessibilityManager()->GotFocus(pointer_down_context_); + + render_widget_host_->GotFocus(); + render_widget_host_->SetActive(true); + + if (base::win::IsTSFAwareRequired()) + ui::TSFBridge::GetInstance()->SetFocusedClient(m_hWnd, this); +} + +void RenderWidgetHostViewWin::OnKillFocus(HWND window) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnKillFocus"); + if (!render_widget_host_) + return; + + render_widget_host_->SetActive(false); + render_widget_host_->Blur(); + + last_touch_location_ = gfx::Point(-1, -1); + + if (base::win::IsTSFAwareRequired()) + ui::TSFBridge::GetInstance()->RemoveFocusedClient(this); +} + +void RenderWidgetHostViewWin::OnCaptureChanged(HWND window) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnCaptureChanged"); + if (render_widget_host_) + render_widget_host_->LostCapture(); + pointer_down_context_ = false; +} + +void RenderWidgetHostViewWin::OnCancelMode() { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnCancelMode"); + if (render_widget_host_) + render_widget_host_->LostCapture(); + + if ((is_fullscreen_ || close_on_deactivate_) && + !weak_factory_.HasWeakPtrs()) { + // Dismiss popups and menus. We do this asynchronously to avoid changing + // activation within this callstack, which may interfere with another window + // being activated. We can synchronously hide the window, but we need to + // not change activation while doing so. + SetWindowPos(NULL, 0, 0, 0, 0, + SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | + SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER); + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&RenderWidgetHostViewWin::ShutdownHost, + weak_factory_.GetWeakPtr())); + } +} + +void RenderWidgetHostViewWin::OnInputLangChange(DWORD character_set, + HKL input_language_id) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnInputLangChange"); + // Send the given Locale ID to the IMM32Manager object and retrieves whether + // or not the current input context has IMEs. + // If the current input context has IMEs, a browser process has to send a + // request to a renderer process that it needs status messages about + // the focused edit control from the renderer process. + // On the other hand, if the current input context does not have IMEs, the + // browser process also has to send a request to the renderer process that + // it does not need the status messages any longer. + // To minimize the number of this notification request, we should check if + // the browser process is actually retrieving the status messages (this + // state is stored in ime_notification_) and send a request only if the + // browser process has to update this status, its details are listed below: + // * If a browser process is not retrieving the status messages, + // (i.e. ime_notification_ == false), + // send this request only if the input context does have IMEs, + // (i.e. ime_status == true); + // When it successfully sends the request, toggle its notification status, + // (i.e.ime_notification_ = !ime_notification_ = true). + // * If a browser process is retrieving the status messages + // (i.e. ime_notification_ == true), + // send this request only if the input context does not have IMEs, + // (i.e. ime_status == false). + // When it successfully sends the request, toggle its notification status, + // (i.e.ime_notification_ = !ime_notification_ = false). + // To analyze the above actions, we can optimize them into the ones + // listed below: + // 1 Sending a request only if ime_status_ != ime_notification_, and; + // 2 Copying ime_status to ime_notification_ if it sends the request + // successfully (because Action 1 shows ime_status = !ime_notification_.) + bool ime_status = imm32_manager_->SetInputLanguage(); + if (ime_status != ime_notification_) { + if (render_widget_host_) { + render_widget_host_->SetInputMethodActive(ime_status); + ime_notification_ = ime_status; + } + } + // Call DefWindowProc() for consistency with other Chrome windows. + // TODO(hbono): This is a speculative fix for Bug 36354 and this code may be + // reverted if it does not fix it. + SetMsgHandled(FALSE); +} + +void RenderWidgetHostViewWin::OnThemeChanged() { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnThemeChanged"); + if (!render_widget_host_) + return; + render_widget_host_->Send(new ViewMsg_ThemeChanged( + render_widget_host_->GetRoutingID())); +} + +LRESULT RenderWidgetHostViewWin::OnNotify(int w_param, NMHDR* header) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnNotify"); + if (tooltip_hwnd_ == NULL) + return 0; + + switch (header->code) { + case TTN_GETDISPINFO: { + NMTTDISPINFOW* tooltip_info = reinterpret_cast<NMTTDISPINFOW*>(header); + tooltip_info->szText[0] = L'\0'; + tooltip_info->lpszText = const_cast<WCHAR*>(tooltip_text_.c_str()); + ::SendMessage( + tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, kTooltipMaxWidthPixels); + SetMsgHandled(TRUE); + break; + } + case TTN_POP: + tooltip_showing_ = false; + SetMsgHandled(TRUE); + break; + case TTN_SHOW: + // Tooltip shouldn't be shown when the mouse is locked. + DCHECK(!mouse_locked_); + tooltip_showing_ = true; + SetMsgHandled(TRUE); + break; + } + return 0; +} + +LRESULT RenderWidgetHostViewWin::OnImeSetContext( + UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeSetContext"); + if (!render_widget_host_) + return 0; + + // We need status messages about the focused input control from a + // renderer process when: + // * the current input context has IMEs, and; + // * an application is activated. + // This seems to tell we should also check if the current input context has + // IMEs before sending a request, however, this WM_IME_SETCONTEXT is + // fortunately sent to an application only while the input context has IMEs. + // Therefore, we just start/stop status messages according to the activation + // status of this application without checks. + bool activated = (wparam == TRUE); + if (render_widget_host_) { + render_widget_host_->SetInputMethodActive(activated); + ime_notification_ = activated; + } + + if (ime_notification_) + imm32_manager_->CreateImeWindow(m_hWnd); + + imm32_manager_->CleanupComposition(m_hWnd); + return imm32_manager_->SetImeWindowStyle( + m_hWnd, message, wparam, lparam, &handled); +} + +LRESULT RenderWidgetHostViewWin::OnImeStartComposition( + UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeStartComposition"); + if (!render_widget_host_) + return 0; + + // Reset the composition status and create IME windows. + imm32_manager_->CreateImeWindow(m_hWnd); + imm32_manager_->ResetComposition(m_hWnd); + // When the focus is on an element that does not draw composition by itself + // (i.e., PPAPI plugin not handling IME), let IME to draw the text. Otherwise + // we have to prevent WTL from calling ::DefWindowProc() because the function + // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to + // over-write the position of IME windows. + handled = (can_compose_inline_ ? TRUE : FALSE); + return 0; +} + +LRESULT RenderWidgetHostViewWin::OnImeComposition( + UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeComposition"); + if (!render_widget_host_) + return 0; + + // At first, update the position of the IME window. + imm32_manager_->UpdateImeWindow(m_hWnd); + + // ui::CompositionUnderline should be identical to + // blink::WebCompositionUnderline, so that we can do reinterpret_cast safely. + COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == + sizeof(blink::WebCompositionUnderline), + ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff); + + // Retrieve the result string and its attributes of the ongoing composition + // and send it to a renderer process. + ui::CompositionText composition; + if (imm32_manager_->GetResult(m_hWnd, lparam, &composition.text)) { + render_widget_host_->ImeConfirmComposition( + composition.text, gfx::Range::InvalidRange(), false); + imm32_manager_->ResetComposition(m_hWnd); + // Fall though and try reading the composition string. + // Japanese IMEs send a message containing both GCS_RESULTSTR and + // GCS_COMPSTR, which means an ongoing composition has been finished + // by the start of another composition. + } + // Retrieve the composition string and its attributes of the ongoing + // composition and send it to a renderer process. + if (imm32_manager_->GetComposition(m_hWnd, lparam, &composition)) { + // TODO(suzhe): due to a bug of webkit, we can't use selection range with + // composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788 + composition.selection = gfx::Range(composition.selection.end()); + + // TODO(suzhe): convert both renderer_host and renderer to use + // ui::CompositionText. + const std::vector<blink::WebCompositionUnderline>& underlines = + reinterpret_cast<const std::vector<blink::WebCompositionUnderline>&>( + composition.underlines); + render_widget_host_->ImeSetComposition( + composition.text, underlines, + composition.selection.start(), composition.selection.end()); + } + // We have to prevent WTL from calling ::DefWindowProc() because we do not + // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages. + handled = TRUE; + if (!can_compose_inline_) { + // When the focus is on an element that does not draw composition by itself + // (i.e., PPAPI plugin not handling IME), let IME to draw the text, which + // is the default behavior of DefWindowProc. Note, however, even in this + // case we don't want GCS_RESULTSTR to be converted to WM_IME_CHAR messages. + // Thus we explicitly drop the flag. + return ::DefWindowProc(m_hWnd, message, wparam, lparam & ~GCS_RESULTSTR); + } + return 0; +} + +LRESULT RenderWidgetHostViewWin::OnImeEndComposition( + UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeEndComposition"); + if (!render_widget_host_) + return 0; + + if (imm32_manager_->is_composing()) { + // A composition has been ended while there is an ongoing composition, + // i.e. the ongoing composition has been canceled. + // We need to reset the composition status both of the IMM32Manager object + // and of the renderer process. + render_widget_host_->ImeCancelComposition(); + imm32_manager_->ResetComposition(m_hWnd); + } + imm32_manager_->DestroyImeWindow(m_hWnd); + // Let WTL call ::DefWindowProc() and release its resources. + handled = FALSE; + return 0; +} + +LRESULT RenderWidgetHostViewWin::OnImeRequest( + UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeRequest"); + if (!render_widget_host_) { + handled = FALSE; + return 0; + } + + // Should not receive WM_IME_REQUEST message, if IME is disabled. + if (text_input_type_ == ui::TEXT_INPUT_TYPE_NONE || + text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD) { + handled = FALSE; + return 0; + } + + switch (wparam) { + case IMR_RECONVERTSTRING: + return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam)); + case IMR_DOCUMENTFEED: + return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam)); + case IMR_QUERYCHARPOSITION: + return OnQueryCharPosition(reinterpret_cast<IMECHARPOSITION*>(lparam)); + default: + handled = FALSE; + return 0; + } +} + +LRESULT RenderWidgetHostViewWin::OnMouseEvent(UINT message, WPARAM wparam, + LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnMouseEvent"); + handled = TRUE; + + if (message == WM_MOUSELEAVE) + ignore_mouse_movement_ = true; + + if (mouse_locked_) { + HandleLockedMouseEvent(message, wparam, lparam); + MoveCursorToCenterIfNecessary(); + return 0; + } + + if (::IsWindow(tooltip_hwnd_)) { + // Forward mouse events through to the tooltip window + MSG msg; + msg.hwnd = m_hWnd; + msg.message = message; + msg.wParam = wparam; + msg.lParam = lparam; + SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, NULL, + reinterpret_cast<LPARAM>(&msg)); + } + + // Due to a bug in Windows, the simulated mouse events for a touch event + // outside our bounds are delivered to us if we were previously focused + // causing crbug.com/159982. As a workaround, we check if this event is a + // simulated mouse event outside our bounds, and if so, we send it to the + // right window. + if ((message == WM_LBUTTONDOWN || message == WM_LBUTTONUP) && + ui::IsMouseEventFromTouch(message)) { + CPoint cursor_pos(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)); + ClientToScreen(&cursor_pos); + if (!GetPixelBounds().Contains(cursor_pos.x, cursor_pos.y)) { + HWND window = WindowFromPoint(cursor_pos); + if (window) { + LRESULT nc_hit_result = SendMessage(window, WM_NCHITTEST, 0, + MAKELPARAM(cursor_pos.x, cursor_pos.y)); + const bool in_client_area = (nc_hit_result == HTCLIENT); + int event_type; + if (message == WM_LBUTTONDOWN) + event_type = in_client_area ? WM_LBUTTONDOWN : WM_NCLBUTTONDOWN; + else + event_type = in_client_area ? WM_LBUTTONUP : WM_NCLBUTTONUP; + + // Convert the coordinates to the target window. + RECT window_bounds; + ::GetWindowRect(window, &window_bounds); + int window_x = cursor_pos.x - window_bounds.left; + int window_y = cursor_pos.y - window_bounds.top; + if (in_client_area) { + ::PostMessage(window, event_type, wparam, + MAKELPARAM(window_x, window_y)); + } else { + ::PostMessage(window, event_type, nc_hit_result, + MAKELPARAM(cursor_pos.x, cursor_pos.y)); + } + return 0; + } + } + } + + // TODO(jcampan): I am not sure if we should forward the message to the + // WebContentsImpl first in the case of popups. If we do, we would need to + // convert the click from the popup window coordinates to the WebContentsImpl' + // window coordinates. For now we don't forward the message in that case to + // address bug #907474. + // Note: GetParent() on popup windows returns the top window and not the + // parent the window was created with (the parent and the owner of the popup + // is the first non-child view of the view that was specified to the create + // call). So the WebContentsImpl's window would have to be specified to the + // RenderViewHostHWND as there is no way to retrieve it from the HWND. + + // Don't forward if the container is a popup or fullscreen widget. + if (!is_fullscreen_ && !close_on_deactivate_) { + switch (message) { + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + // Finish the ongoing composition whenever a mouse click happens. + // It matches IE's behavior. + if (base::win::IsTSFAwareRequired()) { + ui::TSFBridge::GetInstance()->CancelComposition(); + } else { + imm32_manager_->CleanupComposition(m_hWnd); + } + // Fall through. + case WM_MOUSEMOVE: + case WM_MOUSELEAVE: { + // Give the WebContentsImpl first crack at the message. It may want to + // prevent forwarding to the renderer if some higher level browser + // functionality is invoked. + LPARAM parent_msg_lparam = lparam; + if (message != WM_MOUSELEAVE) { + // For the messages except WM_MOUSELEAVE, before forwarding them to + // parent window, we should adjust cursor position from client + // coordinates in current window to client coordinates in its parent + // window. + CPoint cursor_pos(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)); + ClientToScreen(&cursor_pos); + GetParent().ScreenToClient(&cursor_pos); + parent_msg_lparam = MAKELPARAM(cursor_pos.x, cursor_pos.y); + } + if (SendMessage(GetParent(), message, wparam, parent_msg_lparam) != 0) { + TRACE_EVENT0("browser", "EarlyOut_SentToParent"); + return 1; + } + } + } + } + + if (message == WM_LBUTTONDOWN && pointer_down_context_ && + GetBrowserAccessibilityManager()) { + GetBrowserAccessibilityManager()->GotMouseDown(); + } + + if (message == WM_LBUTTONUP && ui::IsMouseEventFromTouch(message) && + base::win::IsMetroProcess()) + pointer_down_context_ = false; + + ForwardMouseEventToRenderer(message, wparam, lparam); + return 0; +} + +LRESULT RenderWidgetHostViewWin::OnKeyEvent(UINT message, WPARAM wparam, + LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnKeyEvent"); + handled = TRUE; + + // When Escape is pressed, force fullscreen windows to close if necessary. + if ((message == WM_KEYDOWN || message == WM_KEYUP) && wparam == VK_ESCAPE) { + if (is_fullscreen_) { + SendMessage(WM_CANCELMODE); + return 0; + } + } + + // If we are a pop-up, forward tab related messages to our parent HWND, so + // that we are dismissed appropriately and so that the focus advance in our + // parent. + // TODO(jcampan): http://b/issue?id=1192881 Could be abstracted in the + // FocusManager. + if (close_on_deactivate_ && + (((message == WM_KEYDOWN || message == WM_KEYUP) && (wparam == VK_TAB)) || + (message == WM_CHAR && wparam == L'\t'))) { + // First close the pop-up. + SendMessage(WM_CANCELMODE); + // Then move the focus by forwarding the tab key to the parent. + return ::SendMessage(GetParent(), message, wparam, lparam); + } + + if (!render_widget_host_) + return 0; + + // Bug 1845: we need to update the text direction when a user releases + // either a right-shift key or a right-control key after pressing both of + // them. So, we just update the text direction while a user is pressing the + // keys, and we notify the text direction when a user releases either of them. + // Bug 9718: http://crbug.com/9718 To investigate IE and notepad, this + // shortcut is enabled only on a PC having RTL keyboard layouts installed. + // We should emulate them. + if (ui::IMM32Manager::IsRTLKeyboardLayoutInstalled()) { + if (message == WM_KEYDOWN) { + if (wparam == VK_SHIFT) { + base::i18n::TextDirection dir; + if (ui::IMM32Manager::IsCtrlShiftPressed(&dir)) { + render_widget_host_->UpdateTextDirection( + dir == base::i18n::RIGHT_TO_LEFT ? + blink::WebTextDirectionRightToLeft : + blink::WebTextDirectionLeftToRight); + } + } else if (wparam != VK_CONTROL) { + // Bug 9762: http://crbug.com/9762 A user pressed a key except shift + // and control keys. + // When a user presses a key while he/she holds control and shift keys, + // we cancel sending an IPC message in NotifyTextDirection() below and + // ignore succeeding UpdateTextDirection() calls while we call + // NotifyTextDirection(). + // To cancel it, this call set a flag that prevents sending an IPC + // message in NotifyTextDirection() only if we are going to send it. + // It is harmless to call this function if we aren't going to send it. + render_widget_host_->CancelUpdateTextDirection(); + } + } else if (message == WM_KEYUP && + (wparam == VK_SHIFT || wparam == VK_CONTROL)) { + // We send an IPC message only if we need to update the text direction. + render_widget_host_->NotifyTextDirection(); + } + } + + // Special processing for enter key: When user hits enter in omnibox + // we change focus to render host after the navigation, so repeat WM_KEYDOWNs + // and WM_KEYUP are going to render host, despite being initiated in other + // window. This code filters out these messages. + bool ignore_keyboard_event = false; + if (wparam == VK_RETURN) { + if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) { + if (KF_REPEAT & HIWORD(lparam)) { + // this is a repeated key + if (!capture_enter_key_) + ignore_keyboard_event = true; + } else { + capture_enter_key_ = true; + } + } else if (message == WM_KEYUP || message == WM_SYSKEYUP) { + if (!capture_enter_key_) + ignore_keyboard_event = true; + capture_enter_key_ = false; + } else { + // Ignore all other keyboard events for the enter key if not captured. + if (!capture_enter_key_) + ignore_keyboard_event = true; + } + } + + if (render_widget_host_ && !ignore_keyboard_event) { + MSG msg = { m_hWnd, message, wparam, lparam }; + render_widget_host_->ForwardKeyboardEvent(NativeWebKeyboardEvent(msg)); + } + + return 0; +} + +LRESULT RenderWidgetHostViewWin::OnWheelEvent(UINT message, WPARAM wparam, + LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnWheelEvent"); + // Forward the mouse-wheel message to the window under the mouse if it belongs + // to us. + if (message == WM_MOUSEWHEEL && + ui::RerouteMouseWheel(m_hWnd, wparam, lparam)) { + handled = TRUE; + return 0; + } + + // We get mouse wheel/scroll messages even if we are not in the foreground. + // So here we check if we have any owned popup windows in the foreground and + // dismiss them. + if (m_hWnd != GetForegroundWindow()) { + HWND toplevel_hwnd = ::GetAncestor(m_hWnd, GA_ROOT); + EnumThreadWindows( + GetCurrentThreadId(), + DismissOwnedPopups, + reinterpret_cast<LPARAM>(toplevel_hwnd)); + } + + if (render_widget_host_) { + blink::WebMouseWheelEvent wheel_event = + WebMouseWheelEventBuilder::Build(m_hWnd, message, wparam, lparam); + float scale = gfx::win::GetDeviceScaleFactor(); + wheel_event.x /= scale; + wheel_event.y /= scale; + wheel_event.deltaX /= scale; + wheel_event.deltaY /= scale; + + render_widget_host_->ForwardWheelEvent(wheel_event); + } + handled = TRUE; + return 0; +} + +WebTouchState::WebTouchState(const RenderWidgetHostViewWin* window) + : window_(window), + id_generator_(0) { +} + +size_t WebTouchState::UpdateTouchPoints( + TOUCHINPUT* points, size_t count) { + // First we reset all touch event state. This involves removing any released + // touchpoints and marking the rest as stationary. After that we go through + // and alter/add any touchpoints (from the touch input buffer) that we can + // coalesce into a single message. The return value is the number of consumed + // input message. + blink::WebTouchPoint* point = touch_event_.touches; + blink::WebTouchPoint* end = point + touch_event_.touchesLength; + while (point < end) { + if (point->state == blink::WebTouchPoint::StateReleased) { + *point = *(--end); + --touch_event_.touchesLength; + } else { + point->state = blink::WebTouchPoint::StateStationary; + point++; + } + } + touch_event_.changedTouchesLength = 0; + touch_event_.modifiers = content::EventFlagsToWebEventModifiers( + ui::GetModifiersFromKeyState()); + + // Consume all events of the same type and add them to the changed list. + int last_type = 0; + for (size_t i = 0; i < count; ++i) { + unsigned int mapped_id = GetMappedTouch(points[i].dwID); + + blink::WebTouchPoint* point = NULL; + for (unsigned j = 0; j < touch_event_.touchesLength; ++j) { + if (static_cast<DWORD>(touch_event_.touches[j].id) == mapped_id) { + point = &touch_event_.touches[j]; + break; + } + } + + // Use a move instead if we see a down on a point we already have. + int type = GetTouchType(points[i]); + if (point && type == TOUCHEVENTF_DOWN) + SetTouchType(&points[i], TOUCHEVENTF_MOVE); + + // Stop processing when the event type changes. + if (touch_event_.changedTouchesLength && type != last_type) + return i; + + touch_event_.timeStampSeconds = points[i].dwTime / 1000.0; + + last_type = type; + switch (type) { + case TOUCHEVENTF_DOWN: { + if (!(point = AddTouchPoint(&points[i]))) + continue; + touch_event_.type = blink::WebInputEvent::TouchStart; + break; + } + + case TOUCHEVENTF_UP: { + if (!point) // Just throw away a stray up. + continue; + point->state = blink::WebTouchPoint::StateReleased; + UpdateTouchPoint(point, &points[i]); + touch_event_.type = blink::WebInputEvent::TouchEnd; + break; + } + + case TOUCHEVENTF_MOVE: { + if (point) { + point->state = blink::WebTouchPoint::StateMoved; + // Don't update the message if the point didn't really move. + if (UpdateTouchPoint(point, &points[i])) + continue; + touch_event_.type = blink::WebInputEvent::TouchMove; + } else if (touch_event_.changedTouchesLength) { + RemoveExpiredMappings(); + // Can't add a point if we're already handling move events. + return i; + } else { + // Treat a move with no existing point as a down. + if (!(point = AddTouchPoint(&points[i]))) + continue; + last_type = TOUCHEVENTF_DOWN; + SetTouchType(&points[i], TOUCHEVENTF_DOWN); + touch_event_.type = blink::WebInputEvent::TouchStart; + } + break; + } + + default: + NOTREACHED(); + continue; + } + touch_event_.changedTouches[touch_event_.changedTouchesLength++] = *point; + } + + RemoveExpiredMappings(); + return count; +} + +void WebTouchState::RemoveExpiredMappings() { + blink::WebTouchPoint* point = touch_event_.touches; + blink::WebTouchPoint* end = point + touch_event_.touchesLength; + for (; point < end; ++point) { + if (point->state == blink::WebTouchPoint::StateReleased) + id_generator_.ReleaseGeneratedID(point->id); + } +} + + +bool WebTouchState::ReleaseTouchPoints() { + if (touch_event_.touchesLength == 0) + return false; + // Mark every active touchpoint as released. + touch_event_.type = blink::WebInputEvent::TouchEnd; + touch_event_.changedTouchesLength = touch_event_.touchesLength; + for (unsigned int i = 0; i < touch_event_.touchesLength; ++i) { + touch_event_.touches[i].state = blink::WebTouchPoint::StateReleased; + touch_event_.changedTouches[i].state = + blink::WebTouchPoint::StateReleased; + } + + return true; +} + +blink::WebTouchPoint* WebTouchState::AddTouchPoint( + TOUCHINPUT* touch_input) { + DCHECK(touch_event_.touchesLength < + blink::WebTouchEvent::touchesLengthCap); + if (touch_event_.touchesLength >= + blink::WebTouchEvent::touchesLengthCap) + return NULL; + blink::WebTouchPoint* point = + &touch_event_.touches[touch_event_.touchesLength++]; + point->state = blink::WebTouchPoint::StatePressed; + point->id = GetMappedTouch(touch_input->dwID); + UpdateTouchPoint(point, touch_input); + return point; +} + +bool WebTouchState::UpdateTouchPoint( + blink::WebTouchPoint* touch_point, + TOUCHINPUT* touch_input) { + CPoint coordinates( + TOUCH_COORD_TO_PIXEL(touch_input->x) / + gfx::win::GetUndocumentedDPITouchScale(), + TOUCH_COORD_TO_PIXEL(touch_input->y) / + gfx::win::GetUndocumentedDPITouchScale()); + int radius_x = 1; + int radius_y = 1; + if (touch_input->dwMask & TOUCHINPUTMASKF_CONTACTAREA) { + // Some touch drivers send a contact area of "-1", yet flag it as valid. + radius_x = std::max(1, + static_cast<int>(TOUCH_COORD_TO_PIXEL(touch_input->cxContact) / + gfx::win::GetUndocumentedDPITouchScale())); + radius_y = std::max(1, + static_cast<int>(TOUCH_COORD_TO_PIXEL(touch_input->cyContact) / + gfx::win::GetUndocumentedDPITouchScale())); + } + + // Detect and exclude stationary moves. + if (GetTouchType(*touch_input) == TOUCHEVENTF_MOVE && + touch_point->screenPosition.x == coordinates.x && + touch_point->screenPosition.y == coordinates.y && + touch_point->radiusX == radius_x && + touch_point->radiusY == radius_y) { + touch_point->state = blink::WebTouchPoint::StateStationary; + return true; + } + + touch_point->screenPosition.x = coordinates.x; + touch_point->screenPosition.y = coordinates.y; + window_->ScreenToClient(&coordinates); + static float scale = gfx::win::GetDeviceScaleFactor(); + touch_point->position.x = coordinates.x / scale; + touch_point->position.y = coordinates.y / scale; + touch_point->radiusX = radius_x; + touch_point->radiusY = radius_y; + touch_point->force = 0; + touch_point->rotationAngle = 0; + return false; +} + +// Find (or create) a mapping for _os_touch_id_. +unsigned int WebTouchState::GetMappedTouch(unsigned int os_touch_id) { + return id_generator_.GetGeneratedID(os_touch_id); +} + +LRESULT RenderWidgetHostViewWin::OnTouchEvent(UINT message, WPARAM wparam, + LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnTouchEvent"); + // Finish the ongoing composition whenever a touch event happens. + // It matches IE's behavior. + if (base::win::IsTSFAwareRequired()) { + ui::TSFBridge::GetInstance()->CancelComposition(); + } else { + imm32_manager_->CleanupComposition(m_hWnd); + } + + // TODO(jschuh): Add support for an arbitrary number of touchpoints. + size_t total = std::min(static_cast<int>(LOWORD(wparam)), + static_cast<int>(blink::WebTouchEvent::touchesLengthCap)); + TOUCHINPUT points[blink::WebTouchEvent::touchesLengthCap]; + + if (!total || !ui::GetTouchInputInfoWrapper((HTOUCHINPUT)lparam, total, + points, sizeof(TOUCHINPUT))) { + TRACE_EVENT0("browser", "EarlyOut_NothingToDo"); + return 0; + } + + if (total == 1 && (points[0].dwFlags & TOUCHEVENTF_DOWN)) { + pointer_down_context_ = true; + last_touch_location_ = gfx::Point( + TOUCH_COORD_TO_PIXEL(points[0].x) / + gfx::win::GetUndocumentedDPITouchScale(), + TOUCH_COORD_TO_PIXEL(points[0].y) / + gfx::win::GetUndocumentedDPITouchScale()); + } + + bool should_forward = render_widget_host_->ShouldForwardTouchEvent() && + touch_events_enabled_; + + // Send a copy of the touch events on to the gesture recognizer. + for (size_t start = 0; start < total;) { + start += touch_state_->UpdateTouchPoints(points + start, total - start); + if (should_forward) { + if (touch_state_->is_changed()) + render_widget_host_->ForwardTouchEventWithLatencyInfo( + touch_state_->touch_event(), ui::LatencyInfo()); + } else { + const blink::WebTouchEvent& touch_event = touch_state_->touch_event(); + base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds( + touch_event.timeStampSeconds * 1000); + for (size_t i = 0; i < touch_event.touchesLength; ++i) { + scoped_ptr<ui::GestureRecognizer::Gestures> gestures; + gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture( + TouchEventFromWebTouchPoint(touch_event.touches[i], timestamp), + ui::ER_UNHANDLED, this)); + ProcessGestures(gestures.get()); + } + } + } + + CloseTouchInputHandle((HTOUCHINPUT)lparam); + + return 0; +} + +void RenderWidgetHostViewWin::ProcessGestures( + ui::GestureRecognizer::Gestures* gestures) { + if ((gestures == NULL) || gestures->empty()) + return; + for (ui::GestureRecognizer::Gestures::iterator g_it = gestures->begin(); + g_it != gestures->end(); + ++g_it) { + ForwardGestureEventToRenderer(*g_it); + } +} + +LRESULT RenderWidgetHostViewWin::OnMouseActivate(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnMouseActivate"); + if (!render_widget_host_) + return MA_NOACTIVATE; + + if (!IsActivatable()) + return MA_NOACTIVATE; + + HWND focus_window = GetFocus(); + if (!::IsWindow(focus_window) || !IsChild(focus_window)) { + // We handle WM_MOUSEACTIVATE to set focus to the underlying plugin + // child window. This is to ensure that keyboard events are received + // by the plugin. The correct way to fix this would be send over + // an event to the renderer which would then eventually send over + // a setFocus call to the plugin widget. This would ensure that + // the renderer (webkit) knows about the plugin widget receiving + // focus. + // TODO(iyengar) Do the right thing as per the above comment. + POINT cursor_pos = {0}; + ::GetCursorPos(&cursor_pos); + ::ScreenToClient(m_hWnd, &cursor_pos); + HWND child_window = ::RealChildWindowFromPoint(m_hWnd, cursor_pos); + if (::IsWindow(child_window) && child_window != m_hWnd) { + if (gfx::GetClassName(child_window) == kWrapperNativeWindowClassName) + child_window = ::GetWindow(child_window, GW_CHILD); + + ::SetFocus(child_window); + return MA_NOACTIVATE; + } + } + handled = FALSE; + render_widget_host_->OnPointerEventActivate(); + return MA_ACTIVATE; +} + +LRESULT RenderWidgetHostViewWin::OnGestureEvent( + UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnGestureEvent"); + + DCHECK(!touch_events_enabled_); + handled = FALSE; + + GESTUREINFO gi = {sizeof(GESTUREINFO)}; + HGESTUREINFO gi_handle = reinterpret_cast<HGESTUREINFO>(lparam); + if (!::GetGestureInfo(gi_handle, &gi)) { + DWORD error = GetLastError(); + NOTREACHED() << "Unable to get gesture info. Error : " << error; + return 0; + } + + if (gi.dwID == GID_ZOOM) { + PageZoom zoom = PAGE_ZOOM_RESET; + POINT zoom_center = {0}; + if (DecodeZoomGesture(m_hWnd, gi, &zoom, &zoom_center)) { + handled = TRUE; + Send(new ViewMsg_ZoomFactor(render_widget_host_->GetRoutingID(), + zoom, zoom_center.x, zoom_center.y)); + } + } else if (gi.dwID == GID_PAN) { + // Right now we only decode scroll gestures and we forward to the page + // as scroll events. + POINT start; + POINT delta; + if (DecodeScrollGesture(gi, &start, &delta)) { + handled = TRUE; + render_widget_host_->ForwardWheelEvent( + MakeFakeScrollWheelEvent(m_hWnd, start, delta)); + } + } + ::CloseGestureInfoHandle(gi_handle); + return 0; +} + +LRESULT RenderWidgetHostViewWin::OnMoveOrSize( + UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { + // Reset the cliping rectangle if the mouse is locked. + if (mouse_locked_) { + CRect rect; + GetWindowRect(&rect); + ::ClipCursor(&rect); + } + return 0; +} + +void RenderWidgetHostViewWin::CreateBrowserAccessibilityManagerIfNeeded() { + if (GetBrowserAccessibilityManager()) + return; + + HRESULT hr = ::CreateStdAccessibleObject( + m_hWnd, OBJID_WINDOW, IID_IAccessible, + reinterpret_cast<void **>(&window_iaccessible_)); + DCHECK(SUCCEEDED(hr)); + + SetBrowserAccessibilityManager( + new BrowserAccessibilityManagerWin( + m_hWnd, + window_iaccessible_.get(), + BrowserAccessibilityManagerWin::GetEmptyDocument(), + this)); +} + +bool RenderWidgetHostViewWin::LockMouse() { + if (mouse_locked_) + return true; + + mouse_locked_ = true; + + // Hide the tooltip window if it is currently visible. When the mouse is + // locked, no mouse message is relayed to the tooltip window, so we don't need + // to worry that it will reappear. + if (::IsWindow(tooltip_hwnd_) && tooltip_showing_) { + ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0); + // Sending a TTM_POP message doesn't seem to actually hide the tooltip + // window, although we will receive a TTN_POP notification. As a result, + // ShowWindow() is explicitly called to hide the window. + ::ShowWindow(tooltip_hwnd_, SW_HIDE); + } + + // TODO(yzshen): ShowCursor(FALSE) causes SetCursorPos() to be ignored on + // Remote Desktop. + ::ShowCursor(FALSE); + + move_to_center_request_.pending = false; + last_mouse_position_.locked_global = last_mouse_position_.unlocked_global; + + // Must set the clip rectangle before MoveCursorToCenterIfNecessary() + // so that if the cursor is moved it uses the clip rect set to the window + // rect. Otherwise, MoveCursorToCenterIfNecessary() may move the cursor + // to the center of the screen, and then we would clip to the window + // rect, thus moving the cursor and causing a movement delta. + CRect rect; + GetWindowRect(&rect); + ::ClipCursor(&rect); + MoveCursorToCenterIfNecessary(); + + return true; +} + +void RenderWidgetHostViewWin::UnlockMouse() { + if (!mouse_locked_) + return; + + mouse_locked_ = false; + + ::ClipCursor(NULL); + ::SetCursorPos(last_mouse_position_.unlocked_global.x(), + last_mouse_position_.unlocked_global.y()); + ::ShowCursor(TRUE); + + if (render_widget_host_) + render_widget_host_->LostMouseLock(); +} + +void RenderWidgetHostViewWin::Observe( + int type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type == NOTIFICATION_RENDERER_PROCESS_TERMINATED); + + // Get the RenderProcessHost that posted this notification, and exit + // if it's not the one associated with this host view. + RenderProcessHost* render_process_host = + Source<RenderProcessHost>(source).ptr(); + DCHECK(render_process_host); + if (!render_widget_host_ || + render_process_host != render_widget_host_->GetProcess()) { + return; + } + + // If it was our RenderProcessHost that posted the notification, + // clear the BrowserAccessibilityManager, because the renderer is + // dead and any accessibility information we have is now stale. + SetBrowserAccessibilityManager(NULL); +} + +static void PaintCompositorHostWindow(HWND hWnd) { + PAINTSTRUCT paint; + BeginPaint(hWnd, &paint); + + RenderWidgetHostViewWin* win = static_cast<RenderWidgetHostViewWin*>( + gfx::GetWindowUserData(hWnd)); + // Trigger composite to rerender window. + if (win) + win->AcceleratedPaint(paint.hdc); + + EndPaint(hWnd, &paint); +} + +// WndProc for the compositor host window. We use this instead of Default so +// we can drop WM_PAINT and WM_ERASEBKGD messages on the floor. +static LRESULT CALLBACK CompositorHostWindowProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam) { + switch (message) { + case WM_ERASEBKGND: + return 0; + case WM_PAINT: + PaintCompositorHostWindow(hWnd); + return 0; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } +} + +void RenderWidgetHostViewWin::AcceleratedPaint(HDC dc) { + if (render_widget_host_) + render_widget_host_->ScheduleComposite(); + if (accelerated_surface_) + accelerated_surface_->Present(dc); +} + +void RenderWidgetHostViewWin::GetScreenInfo(blink::WebScreenInfo* results) { + GetScreenInfoForWindow(GetNativeViewId(), results); +} + +gfx::Rect RenderWidgetHostViewWin::GetBoundsInRootWindow() { + RECT window_rect = {0}; + HWND root_window = GetAncestor(m_hWnd, GA_ROOT); + ::GetWindowRect(root_window, &window_rect); + gfx::Rect rect(window_rect); + + // Maximized windows are outdented from the work area by the frame thickness + // even though this "frame" is not painted. This confuses code (and people) + // that think of a maximized window as corresponding exactly to the work area. + // Correct for this by subtracting the frame thickness back off. + if (::IsZoomed(root_window)) { + rect.Inset(GetSystemMetrics(SM_CXSIZEFRAME), + GetSystemMetrics(SM_CYSIZEFRAME)); + } + + return gfx::win::ScreenToDIPRect(rect); +} + +// Creates a HWND within the RenderWidgetHostView that will serve as a host +// for a HWND that the GPU process will create. The host window is used +// to Z-position the GPU's window relative to other plugin windows. +gfx::GLSurfaceHandle RenderWidgetHostViewWin::GetCompositingSurface() { + // If the window has been created, don't recreate it a second time + if (compositor_host_window_) + return gfx::GLSurfaceHandle(compositor_host_window_, gfx::NATIVE_TRANSPORT); + + // On Vista and later we present directly to the view window rather than a + // child window. + if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface()) { + if (!accelerated_surface_) + accelerated_surface_.reset(new AcceleratedSurface(m_hWnd)); + return gfx::GLSurfaceHandle(m_hWnd, gfx::NATIVE_TRANSPORT); + } + + // On XP we need a child window that can be resized independently of the + // parent. + static ATOM atom = 0; + static HMODULE instance = NULL; + if (!atom) { + WNDCLASSEX window_class; + base::win::InitializeWindowClass( + L"CompositorHostWindowClass", + &base::win::WrappedWindowProc<CompositorHostWindowProc>, + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, + &window_class); + instance = window_class.hInstance; + atom = RegisterClassEx(&window_class); + DCHECK(atom); + } + + RECT currentRect; + GetClientRect(¤tRect); + + // Ensure window does not have zero area because D3D cannot create a zero + // area swap chain. + int width = std::max(1, + static_cast<int>(currentRect.right - currentRect.left)); + int height = std::max(1, + static_cast<int>(currentRect.bottom - currentRect.top)); + + compositor_host_window_ = CreateWindowEx( + WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, + MAKEINTATOM(atom), 0, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED, + 0, 0, width, height, m_hWnd, 0, instance, 0); + gfx::CheckWindowCreated(compositor_host_window_); + + gfx::SetWindowUserData(compositor_host_window_, this); + + gfx::GLSurfaceHandle surface_handle(compositor_host_window_, + gfx::NATIVE_TRANSPORT); + return surface_handle; +} + +void RenderWidgetHostViewWin::ResizeCompositingSurface(const gfx::Size& size) { + // Ensure window does not have zero area because D3D cannot create a zero + // area swap chain. + ::SetWindowPos(compositor_host_window_, + NULL, + 0, 0, + std::max(1, size.width()), + std::max(1, size.height()), + SWP_NOSENDCHANGING | SWP_NOCOPYBITS | SWP_NOZORDER | + SWP_NOACTIVATE | SWP_DEFERERASE | SWP_NOMOVE); +} + +void RenderWidgetHostViewWin::OnAcceleratedCompositingStateChange() { + bool show = render_widget_host_->is_accelerated_compositing_active(); + // When we first create the compositor, we will get a show request from + // the renderer before we have gotten the create request from the GPU. In this + // case, simply ignore the show request. + if (compositor_host_window_ == NULL) + return; + + if (show) { + ::ShowWindow(compositor_host_window_, SW_SHOW); + + // Get all the child windows of this view, including the compositor window. + std::vector<HWND> all_child_windows; + ::EnumChildWindows(m_hWnd, AddChildWindowToVector, + reinterpret_cast<LPARAM>(&all_child_windows)); + + // Build a list of just the plugin window handles + std::vector<HWND> plugin_windows; + bool compositor_host_window_found = false; + for (size_t i = 0; i < all_child_windows.size(); ++i) { + if (all_child_windows[i] != compositor_host_window_) + plugin_windows.push_back(all_child_windows[i]); + else + compositor_host_window_found = true; + } + DCHECK(compositor_host_window_found); + + // Set all the plugin windows to be "after" the compositor window. + // When the compositor window is created, gets placed above plugins. + for (size_t i = 0; i < plugin_windows.size(); ++i) { + HWND next; + if (i + 1 < plugin_windows.size()) + next = plugin_windows[i+1]; + else + next = compositor_host_window_; + ::SetWindowPos(plugin_windows[i], next, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + } + } else { + // Drop the backing store for the accelerated surface when the accelerated + // compositor is disabled. Otherwise, a flash of the last presented frame + // could appear when it is next enabled. + if (accelerated_surface_) + accelerated_surface_->Suspend(); + hide_compositor_window_at_next_paint_ = true; + } +} + +void RenderWidgetHostViewWin::AcceleratedSurfaceInitialized(int host_id, + int route_id) { +} + +void RenderWidgetHostViewWin::AcceleratedSurfaceBuffersSwapped( + const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, + int gpu_host_id) { + NOTREACHED(); +} + +void RenderWidgetHostViewWin::AcceleratedSurfacePostSubBuffer( + const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params, + int gpu_host_id) { + NOTREACHED(); +} + +void RenderWidgetHostViewWin::AcceleratedSurfaceSuspend() { + if (!accelerated_surface_) + return; + + accelerated_surface_->Suspend(); +} + +void RenderWidgetHostViewWin::AcceleratedSurfaceRelease() { +} + +bool RenderWidgetHostViewWin::HasAcceleratedSurface( + const gfx::Size& desired_size) { + // TODO(jbates) Implement this so this view can use GetBackingStore for both + // software and GPU frames. Defaulting to false just makes GetBackingStore + // only useable for software frames. + return false; +} + +void RenderWidgetHostViewWin::SetAccessibilityFocus(int acc_obj_id) { + if (!render_widget_host_) + return; + + render_widget_host_->AccessibilitySetFocus(acc_obj_id); +} + +void RenderWidgetHostViewWin::AccessibilityDoDefaultAction(int acc_obj_id) { + if (!render_widget_host_) + return; + + render_widget_host_->AccessibilityDoDefaultAction(acc_obj_id); +} + +void RenderWidgetHostViewWin::AccessibilityScrollToMakeVisible( + int acc_obj_id, gfx::Rect subfocus) { + if (!render_widget_host_) + return; + + render_widget_host_->AccessibilityScrollToMakeVisible(acc_obj_id, subfocus); +} + +void RenderWidgetHostViewWin::AccessibilityScrollToPoint( + int acc_obj_id, gfx::Point point) { + if (!render_widget_host_) + return; + + render_widget_host_->AccessibilityScrollToPoint(acc_obj_id, point); +} + +void RenderWidgetHostViewWin::AccessibilitySetTextSelection( + int acc_obj_id, int start_offset, int end_offset) { + if (!render_widget_host_) + return; + + render_widget_host_->AccessibilitySetTextSelection( + acc_obj_id, start_offset, end_offset); +} + +gfx::Point RenderWidgetHostViewWin::GetLastTouchEventLocation() const { + return last_touch_location_; +} + +void RenderWidgetHostViewWin::FatalAccessibilityTreeError() { + render_widget_host_->FatalAccessibilityTreeError(); + SetBrowserAccessibilityManager(NULL); +} + +LRESULT RenderWidgetHostViewWin::OnGetObject(UINT message, WPARAM wparam, + LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnGetObject"); + if (kIdCustom == lparam) { + // An MSAA client requestes our custom id. Assume that we have detected an + // active windows screen reader. + BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected(); + render_widget_host_->SetAccessibilityMode( + BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()); + + // Return with failure. + return static_cast<LRESULT>(0L); + } + + if (lparam != OBJID_CLIENT) { + handled = false; + return static_cast<LRESULT>(0L); + } + + IAccessible* iaccessible = GetNativeViewAccessible(); + if (iaccessible) + return LresultFromObject(IID_IAccessible, wparam, iaccessible); + + handled = false; + return static_cast<LRESULT>(0L); +} + +LRESULT RenderWidgetHostViewWin::OnParentNotify(UINT message, WPARAM wparam, + LPARAM lparam, BOOL& handled) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnParentNotify"); + handled = FALSE; + + if (!render_widget_host_) + return 0; + + switch (LOWORD(wparam)) { + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + render_widget_host_->StartUserGesture(); + break; + default: + break; + } + return 0; +} + +void RenderWidgetHostViewWin::OnFinalMessage(HWND window) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnFinalMessage"); + // When the render widget host is being destroyed, it ends up calling + // Destroy() which NULLs render_widget_host_. + // Note: the following bug http://crbug.com/24248 seems to report that + // OnFinalMessage is called with a deleted |render_widget_host_|. It is not + // clear how this could happen, hence the NULLing of render_widget_host_ + // above. + if (!render_widget_host_ && !being_destroyed_) { + // If you hit this NOTREACHED, please add a comment to report it on + // http://crbug.com/24248, including what you did when it happened and if + // you can repro. + NOTREACHED(); + } + if (render_widget_host_) + render_widget_host_->ViewDestroyed(); + if (base::win::IsTSFAwareRequired()) + ui::TSFBridge::GetInstance()->RemoveFocusedClient(this); + delete this; +} + +LRESULT RenderWidgetHostViewWin::OnSessionChange(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL& handled) { + handled = FALSE; + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSessionChange"); + + if (!accelerated_surface_) + return 0; + + switch (wparam) { + case WTS_SESSION_LOCK: + accelerated_surface_->SetIsSessionLocked(true); + break; + case WTS_SESSION_UNLOCK: + // Force a repaint to update the window contents. + if (!render_widget_host_->is_hidden()) + InvalidateRect(NULL, FALSE); + accelerated_surface_->SetIsSessionLocked(false); + break; + default: + break; + } + + return 0; +} + +void RenderWidgetHostViewWin::TrackMouseLeave(bool track) { + if (track == track_mouse_leave_) + return; + track_mouse_leave_ = track; + + DCHECK(m_hWnd); + + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE; + if (!track_mouse_leave_) + tme.dwFlags |= TME_CANCEL; + tme.hwndTrack = m_hWnd; + + TrackMouseEvent(&tme); +} + +bool RenderWidgetHostViewWin::Send(IPC::Message* message) { + if (!render_widget_host_) + return false; + return render_widget_host_->Send(message); +} + +void RenderWidgetHostViewWin::EnsureTooltip() { + UINT message = TTM_NEWTOOLRECT; + + TOOLINFO ti = {0}; + ti.cbSize = sizeof(ti); + ti.hwnd = m_hWnd; + ti.uId = 0; + if (!::IsWindow(tooltip_hwnd_)) { + message = TTM_ADDTOOL; + tooltip_hwnd_ = CreateWindowEx( + WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(), + TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0, m_hWnd, NULL, + NULL, NULL); + if (!tooltip_hwnd_) { + // Tooltip creation can inexplicably fail. See bug 82913 for details. + LOG_GETLASTERROR(WARNING) << + "Tooltip creation failed, tooltips won't work"; + return; + } + ti.uFlags = TTF_TRANSPARENT; + ti.lpszText = LPSTR_TEXTCALLBACK; + + // Ensure web content tooltips are displayed for at least this amount of + // time, to give users a chance to read longer messages. + const int kMinimumAutopopDurationMs = 10 * 1000; + int autopop_duration_ms = + SendMessage(tooltip_hwnd_, TTM_GETDELAYTIME, TTDT_AUTOPOP, NULL); + if (autopop_duration_ms < kMinimumAutopopDurationMs) { + SendMessage(tooltip_hwnd_, TTM_SETDELAYTIME, TTDT_AUTOPOP, + kMinimumAutopopDurationMs); + } + } + + CRect cr; + GetClientRect(&ti.rect); + SendMessage(tooltip_hwnd_, message, NULL, reinterpret_cast<LPARAM>(&ti)); +} + +void RenderWidgetHostViewWin::ResetTooltip() { + if (::IsWindow(tooltip_hwnd_)) + ::DestroyWindow(tooltip_hwnd_); + tooltip_hwnd_ = NULL; +} + +bool RenderWidgetHostViewWin::ForwardGestureEventToRenderer( + ui::GestureEvent* gesture) { + if (!render_widget_host_) + return false; + + // Pinch gestures are disabled by default on windows desktop. See + // crbug.com/128477 and crbug.com/148816 + if ((gesture->type() == ui::ET_GESTURE_PINCH_BEGIN || + gesture->type() == ui::ET_GESTURE_PINCH_UPDATE || + gesture->type() == ui::ET_GESTURE_PINCH_END) && + !ShouldSendPinchGesture()) { + return true; + } + + blink::WebGestureEvent web_gesture = CreateWebGestureEvent(m_hWnd, *gesture); + if (web_gesture.type == blink::WebGestureEvent::Undefined) + return false; + if (web_gesture.type == blink::WebGestureEvent::GestureTapDown) { + render_widget_host_->ForwardGestureEvent( + CreateFlingCancelEvent(gesture->time_stamp().InSecondsF())); + } + render_widget_host_->ForwardGestureEventWithLatencyInfo(web_gesture, + *gesture->latency()); + return true; +} + +void RenderWidgetHostViewWin::ForwardMouseEventToRenderer(UINT message, + WPARAM wparam, + LPARAM lparam) { + TRACE_EVENT0("browser", + "RenderWidgetHostViewWin::ForwardMouseEventToRenderer"); + if (!render_widget_host_) { + TRACE_EVENT0("browser", "EarlyOut_NoRWH"); + return; + } + + gfx::Point point = gfx::win::ScreenToDIPPoint( + gfx::Point(static_cast<short>(LOWORD(lparam)), + static_cast<short>(HIWORD(lparam)))); + lparam = MAKELPARAM(point.x(), point.y()); + + WebMouseEvent event( + WebMouseEventBuilder::Build(m_hWnd, message, wparam, lparam)); + + if (mouse_locked_) { + event.movementX = event.globalX - last_mouse_position_.locked_global.x(); + event.movementY = event.globalY - last_mouse_position_.locked_global.y(); + last_mouse_position_.locked_global.SetPoint(event.globalX, event.globalY); + + event.x = last_mouse_position_.unlocked.x(); + event.y = last_mouse_position_.unlocked.y(); + event.windowX = last_mouse_position_.unlocked.x(); + event.windowY = last_mouse_position_.unlocked.y(); + event.globalX = last_mouse_position_.unlocked_global.x(); + event.globalY = last_mouse_position_.unlocked_global.y(); + } else { + if (ignore_mouse_movement_) { + ignore_mouse_movement_ = false; + event.movementX = 0; + event.movementY = 0; + } else { + event.movementX = + event.globalX - last_mouse_position_.unlocked_global.x(); + event.movementY = + event.globalY - last_mouse_position_.unlocked_global.y(); + } + + last_mouse_position_.unlocked.SetPoint(event.windowX, event.windowY); + last_mouse_position_.unlocked_global.SetPoint(event.globalX, event.globalY); + } + + // Windows sends (fake) mouse messages for touch events. Don't send these to + // the render widget. + if (!touch_events_enabled_ || !ui::IsMouseEventFromTouch(message)) { + // Send the event to the renderer before changing mouse capture, so that + // the capturelost event arrives after mouseup. + render_widget_host_->ForwardMouseEvent(event); + + switch (event.type) { + case WebInputEvent::MouseMove: + TrackMouseLeave(true); + break; + case WebInputEvent::MouseLeave: + TrackMouseLeave(false); + break; + case WebInputEvent::MouseDown: + SetCapture(); + break; + case WebInputEvent::MouseUp: + if (GetCapture() == m_hWnd) + ReleaseCapture(); + break; + } + } + + if (IsActivatable() && event.type == WebInputEvent::MouseDown) { + // This is a temporary workaround for bug 765011 to get focus when the + // mouse is clicked. This happens after the mouse down event is sent to + // the renderer because normally Windows does a WM_SETFOCUS after + // WM_LBUTTONDOWN. + SetFocus(); + } +} + +void RenderWidgetHostViewWin::ShutdownHost() { + weak_factory_.InvalidateWeakPtrs(); + if (render_widget_host_) + render_widget_host_->Shutdown(); + // Do not touch any members at this point, |this| has been deleted. +} + +void RenderWidgetHostViewWin::DoPopupOrFullscreenInit(HWND parent_hwnd, + const gfx::Rect& pos, + DWORD ex_style) { + Create(parent_hwnd, NULL, NULL, WS_POPUP, ex_style); + gfx::Rect screen_rect = gfx::win::DIPToScreenRect(pos); + MoveWindow(screen_rect.x(), screen_rect.y(), screen_rect.width(), + screen_rect.height(), TRUE); + ShowWindow(IsActivatable() ? SW_SHOW : SW_SHOWNA); + + if (is_fullscreen_ && win8::IsSingleWindowMetroMode()) { + MetroSetFrameWindow set_frame_window = + reinterpret_cast<MetroSetFrameWindow>( + ::GetProcAddress(base::win::GetMetroModule(), "SetFrameWindow")); + DCHECK(set_frame_window); + set_frame_window(m_hWnd); + } +} + +CPoint RenderWidgetHostViewWin::GetClientCenter() const { + CRect rect; + GetClientRect(&rect); + return rect.CenterPoint(); +} + +void RenderWidgetHostViewWin::MoveCursorToCenterIfNecessary() { + DCHECK(mouse_locked_); + + CRect rect; + GetClipCursor(&rect); + int border_x = rect.Width() * kMouseLockBorderPercentage / 100; + int border_y = rect.Height() * kMouseLockBorderPercentage / 100; + + bool should_move = + last_mouse_position_.locked_global.x() < rect.left + border_x || + last_mouse_position_.locked_global.x() > rect.right - border_x || + last_mouse_position_.locked_global.y() < rect.top + border_y || + last_mouse_position_.locked_global.y() > rect.bottom - border_y; + + if (should_move) { + move_to_center_request_.pending = true; + move_to_center_request_.target = rect.CenterPoint(); + if (!::SetCursorPos(move_to_center_request_.target.x(), + move_to_center_request_.target.y())) { + LOG_GETLASTERROR(WARNING) << "Failed to set cursor position."; + } + } +} + +void RenderWidgetHostViewWin::HandleLockedMouseEvent(UINT message, + WPARAM wparam, + LPARAM lparam) { + TRACE_EVENT0("browser", "RenderWidgetHostViewWin::HandleLockedMouseEvent"); + DCHECK(mouse_locked_); + + if (message == WM_MOUSEMOVE && move_to_center_request_.pending) { + // Ignore WM_MOUSEMOVE messages generated by + // MoveCursorToCenterIfNecessary(). + CPoint current_position(LOWORD(lparam), HIWORD(lparam)); + ClientToScreen(¤t_position); + if (move_to_center_request_.target.x() == current_position.x && + move_to_center_request_.target.y() == current_position.y) { + move_to_center_request_.pending = false; + last_mouse_position_.locked_global = move_to_center_request_.target; + return; + } + } + + ForwardMouseEventToRenderer(message, wparam, lparam); +} + +LRESULT RenderWidgetHostViewWin::OnDocumentFeed(RECONVERTSTRING* reconv) { + size_t target_offset; + size_t target_length; + bool has_composition; + if (!composition_range_.is_empty()) { + target_offset = composition_range_.GetMin(); + target_length = composition_range_.length(); + has_composition = true; + } else if (selection_range_.IsValid()) { + target_offset = selection_range_.GetMin(); + target_length = selection_range_.length(); + has_composition = false; + } else { + return 0; + } + + size_t len = selection_text_.length(); + size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR); + + if (target_offset < selection_text_offset_ || + target_offset + target_length > selection_text_offset_ + len) { + return 0; + } + + if (!reconv) + return need_size; + + if (reconv->dwSize < need_size) + return 0; + + reconv->dwVersion = 0; + reconv->dwStrLen = len; + reconv->dwStrOffset = sizeof(RECONVERTSTRING); + reconv->dwCompStrLen = has_composition ? target_length: 0; + reconv->dwCompStrOffset = + (target_offset - selection_text_offset_) * sizeof(WCHAR); + reconv->dwTargetStrLen = target_length; + reconv->dwTargetStrOffset = reconv->dwCompStrOffset; + memcpy(reinterpret_cast<char*>(reconv) + sizeof(RECONVERTSTRING), + selection_text_.c_str(), len * sizeof(WCHAR)); + + // According to Microsft API document, IMR_RECONVERTSTRING and + // IMR_DOCUMENTFEED should return reconv, but some applications return + // need_size. + return reinterpret_cast<LRESULT>(reconv); +} + +LRESULT RenderWidgetHostViewWin::OnReconvertString(RECONVERTSTRING* reconv) { + // If there is a composition string already, we don't allow reconversion. + if (imm32_manager_->is_composing()) + return 0; + + if (selection_range_.is_empty()) + return 0; + + if (selection_text_.empty()) + return 0; + + if (selection_range_.GetMin() < selection_text_offset_ || + selection_range_.GetMax() > + selection_text_offset_ + selection_text_.length()) { + return 0; + } + + size_t len = selection_range_.length(); + size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR); + + if (!reconv) + return need_size; + + if (reconv->dwSize < need_size) + return 0; + + reconv->dwVersion = 0; + reconv->dwStrLen = len; + reconv->dwStrOffset = sizeof(RECONVERTSTRING); + reconv->dwCompStrLen = len; + reconv->dwCompStrOffset = 0; + reconv->dwTargetStrLen = len; + reconv->dwTargetStrOffset = 0; + + size_t offset = selection_range_.GetMin() - selection_text_offset_; + memcpy(reinterpret_cast<char*>(reconv) + sizeof(RECONVERTSTRING), + selection_text_.c_str() + offset, len * sizeof(WCHAR)); + + // According to Microsft API document, IMR_RECONVERTSTRING and + // IMR_DOCUMENTFEED should return reconv, but some applications return + // need_size. + return reinterpret_cast<LRESULT>(reconv); +} + +LRESULT RenderWidgetHostViewWin::OnQueryCharPosition( + IMECHARPOSITION* position) { + DCHECK(position); + + if (position->dwSize < sizeof(IMECHARPOSITION)) + return 0; + + RECT target_rect = {}; + if (imm32_manager_->is_composing() && !composition_range_.is_empty() && + position->dwCharPos < composition_character_bounds_.size()) { + target_rect = + composition_character_bounds_[position->dwCharPos].ToRECT(); + } else if (position->dwCharPos == 0) { + // When there is no on-going composition but |position->dwCharPos| is 0, + // use the caret rect. This behavior is the same to RichEdit. In fact, + // CUAS (Cicero Unaware Application Support) relies on this behavior to + // implement ITfContextView::GetTextExt on top of IMM32-based applications. + target_rect = caret_rect_.ToRECT(); + } else { + return 0; + } + ClientToScreen(&target_rect); + + RECT document_rect = GetPixelBounds().ToRECT(); + ClientToScreen(&document_rect); + + position->pt.x = target_rect.left; + position->pt.y = target_rect.top; + position->cLineHeight = target_rect.bottom - target_rect.top; + position->rcDocument = document_rect; + return 1; +} + +void RenderWidgetHostViewWin::UpdateIMEState() { + if (base::win::IsTSFAwareRequired()) { + ui::TSFBridge::GetInstance()->OnTextInputTypeChanged(this); + return; + } + if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE && + text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD) { + imm32_manager_->EnableIME(m_hWnd); + imm32_manager_->SetUseCompositionWindow(!can_compose_inline_); + } else { + imm32_manager_->DisableIME(m_hWnd); + } + + imm32_manager_->SetTextInputMode(m_hWnd, text_input_mode_); +} + +void RenderWidgetHostViewWin::UpdateInputScopeIfNecessary( + ui::TextInputType text_input_type) { + // The text store is responsible for handling input scope when TSF-aware is + // required. + if (base::win::IsTSFAwareRequired()) + return; + + ui::tsf_inputscope::SetInputScopeForTsfUnawareWindow( + m_hWnd, text_input_type, text_input_mode_); +} + +//////////////////////////////////////////////////////////////////////////////// +// RenderWidgetHostView, public: + +// static +RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( + RenderWidgetHost* widget) { + return new RenderWidgetHostViewWin(widget); +} + +// static +void RenderWidgetHostViewPort::GetDefaultScreenInfo( + blink::WebScreenInfo* results) { + GetScreenInfoForWindow(0, results); +} + +} // namespace content diff --git a/ui/gfx/screen_win.cc b/ui/gfx/screen_win.cc index 2a03d65..d207db0 100644 --- a/ui/gfx/screen_win.cc +++ b/ui/gfx/screen_win.cc @@ -19,7 +19,7 @@ MONITORINFOEX GetMonitorInfoForMonitor(HMONITOR monitor) { MONITORINFOEX monitor_info; ZeroMemory(&monitor_info, sizeof(MONITORINFOEX)); monitor_info.cbSize = sizeof(monitor_info); - base::win::GetMonitorInfoWrapper(monitor, &monitor_info); + GetMonitorInfo(monitor, &monitor_info); return monitor_info; } @@ -100,8 +100,8 @@ gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const { MONITORINFOEX monitor_info; monitor_info.cbSize = sizeof(monitor_info); - base::win::GetMonitorInfoWrapper( - MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST), &monitor_info); + GetMonitorInfo(MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST), + &monitor_info); return GetDisplay(monitor_info); } @@ -111,7 +111,7 @@ gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const { MONITORINFOEX mi; ZeroMemory(&mi, sizeof(MONITORINFOEX)); mi.cbSize = sizeof(mi); - if (monitor && base::win::GetMonitorInfoWrapper(monitor, &mi)) { + if (monitor && GetMonitorInfo(monitor, &mi)) { return GetDisplay(mi); } return gfx::Display(); diff --git a/ui/gfx/win/hwnd_util.cc b/ui/gfx/win/hwnd_util.cc index 4f06066..a986e66 100644 --- a/ui/gfx/win/hwnd_util.cc +++ b/ui/gfx/win/hwnd_util.cc @@ -24,7 +24,7 @@ void AdjustWindowToFit(HWND hwnd, const RECT& bounds, bool fit_to_monitor) { if (hmon) { MONITORINFO mi; mi.cbSize = sizeof(mi); - base::win::GetMonitorInfoWrapper(hmon, &mi); + GetMonitorInfo(hmon, &mi); Rect window_rect(bounds); Rect monitor_rect(mi.rcWork); Rect new_window_rect = window_rect; @@ -150,7 +150,7 @@ void CenterAndSizeWindow(HWND parent, if (monitor) { MONITORINFO mi = {0}; mi.cbSize = sizeof(mi); - base::win::GetMonitorInfoWrapper(monitor, &mi); + GetMonitorInfo(monitor, &mi); center_bounds = mi.rcWork; } else { NOTREACHED() << "Unable to get default monitor"; diff --git a/ui/views/widget/monitor_win.cc b/ui/views/widget/monitor_win.cc index 1292692..2c6d830 100644 --- a/ui/views/widget/monitor_win.cc +++ b/ui/views/widget/monitor_win.cc @@ -18,7 +18,7 @@ gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect) { if (monitor) { MONITORINFO mi = {0}; mi.cbSize = sizeof(mi); - base::win::GetMonitorInfoWrapper(monitor, &mi); + GetMonitorInfo(monitor, &mi); return gfx::Rect(mi.rcWork); } NOTREACHED(); diff --git a/ui/views/win/fullscreen_handler.cc b/ui/views/win/fullscreen_handler.cc index 2fe8cea..a6f5156 100644 --- a/ui/views/win/fullscreen_handler.cc +++ b/ui/views/win/fullscreen_handler.cc @@ -76,8 +76,8 @@ void FullscreenHandler::SetFullscreenImpl(bool fullscreen, bool for_metro) { if (!for_metro) { MONITORINFO monitor_info; monitor_info.cbSize = sizeof(monitor_info); - base::win::GetMonitorInfoWrapper( - MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONEAREST), &monitor_info); + GetMonitorInfo(MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONEAREST), + &monitor_info); gfx::Rect window_rect(monitor_info.rcMonitor); SetWindowPos(hwnd_, NULL, window_rect.x(), window_rect.y(), window_rect.width(), window_rect.height(), diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index 5a4e0a8..db8d0cb 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc @@ -186,7 +186,7 @@ bool GetMonitorAndRects(const RECT& rect, return false; MONITORINFO monitor_info = { 0 }; monitor_info.cbSize = sizeof(monitor_info); - base::win::GetMonitorInfoWrapper(*monitor, &monitor_info); + GetMonitorInfo(*monitor, &monitor_info); *monitor_rect = gfx::Rect(monitor_info.rcMonitor); *work_area = gfx::Rect(monitor_info.rcWork); return true; @@ -550,7 +550,7 @@ void HWNDMessageHandler::GetWindowPlacement( } else { MONITORINFO mi; mi.cbSize = sizeof(mi); - const bool succeeded = base::win::GetMonitorInfoWrapper( + const bool succeeded = GetMonitorInfo( MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST), &mi) != 0; DCHECK(succeeded); @@ -1168,7 +1168,7 @@ void HWNDMessageHandler::ResetWindowRegion(bool force, bool redraw) { HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST); MONITORINFO mi; mi.cbSize = sizeof mi; - base::win::GetMonitorInfoWrapper(monitor, &mi); + GetMonitorInfo(monitor, &mi); CRect work_rect = mi.rcWork; work_rect.OffsetRect(-window_rect.left, -window_rect.top); new_region = CreateRectRgnIndirect(&work_rect); |