diff options
Diffstat (limited to 'chromium/content/browser/renderer_host/render_widget_host_view_win.cc')
-rw-r--r-- | chromium/content/browser/renderer_host/render_widget_host_view_win.cc | 3225 |
1 files changed, 0 insertions, 3225 deletions
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_win.cc b/chromium/content/browser/renderer_host/render_widget_host_view_win.cc deleted file mode 100644 index 8238a82b4ca..00000000000 --- a/chromium/content/browser/renderer_host/render_widget_host_view_win.cc +++ /dev/null @@ -1,3225 +0,0 @@ -// 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 (!base::win::GetMonitorInfoWrapper(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::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)); -} - -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 ui::LatencyInfo& latency_info) { - TRACE_EVENT0("content", "RenderWidgetHostViewWin::DidUpdateBackingStore"); - software_latency_info_.MergeWith(latency_info); - 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(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(); - } - - software_latency_info_.AddLatencyNumber( - ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0); - render_widget_host_->FrameSwapped(software_latency_info_); - 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::OnAccessibilityEvents( - const std::vector<AccessibilityHostMsg_EventParams>& params) { - CreateBrowserAccessibilityManagerIfNeeded(); - GetBrowserAccessibilityManager()->OnAccessibilityEvents(params); -} - -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 |