Index: content/browser/renderer_host/render_widget_host_view_win.cc |
diff --git a/content/browser/renderer_host/render_widget_host_view_win.cc b/content/browser/renderer_host/render_widget_host_view_win.cc |
index a5cb6cf1b8a5b7ee3f6f8e99ebffe09db3efc787..f1f8df00e5691acabff577d742c68caea3acb105 100644 |
--- a/content/browser/renderer_host/render_widget_host_view_win.cc |
+++ b/content/browser/renderer_host/render_widget_host_view_win.cc |
@@ -1,3104 +1,3105 @@ |
-// 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 <algorithm> |
-#include <map> |
-#include <stack> |
-#include <wtsapi32.h> |
-#pragma comment(lib, "wtsapi32.lib") |
- |
-#include "base/bind.h" |
-#include "base/bind_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/process_util.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_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/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_messages.h" |
-#include "content/common/view_messages.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/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/skia/include/core/SkRegion.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/win/WebInputEventFactory.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/win/WebScreenInfoFactory.h" |
-#include "ui/base/events/event.h" |
-#include "ui/base/events/event_utils.h" |
-#include "ui/base/ime/composition_text.h" |
-#include "ui/base/ime/win/tsf_input_scope.h" |
-#include "ui/base/l10n/l10n_util_win.h" |
-#include "ui/base/text/text_elider.h" |
-#include "ui/base/touch/touch_device.h" |
-#include "ui/base/ui_base_switches.h" |
-#include "ui/base/view_prop.h" |
-#include "ui/base/win/dpi.h" |
-#include "ui/base/win/hwnd_util.h" |
-#include "ui/base/win/mouse_wheel_util.h" |
-#include "ui/gfx/canvas.h" |
-#include "ui/gfx/rect.h" |
-#include "ui/gfx/rect_conversions.h" |
-#include "ui/gfx/screen.h" |
-#include "webkit/glue/webcursor.h" |
-#include "webkit/plugins/npapi/plugin_constants_win.h" |
-#include "webkit/plugins/npapi/webplugin.h" |
-#include "webkit/plugins/npapi/webplugin_delegate_impl.h" |
-#include "win8/util/win8_util.h" |
- |
-using base::TimeDelta; |
-using base::TimeTicks; |
-using ui::ViewProp; |
-using WebKit::WebInputEvent; |
-using WebKit::WebInputEventFactory; |
-using WebKit::WebMouseEvent; |
-using WebKit::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; |
-} |
- |
-WebKit::WebMouseWheelEvent MakeFakeScrollWheelEvent(HWND hwnd, |
- POINT start, |
- POINT delta) { |
- WebKit::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(WebKit::WebTouchPoint::State t) { |
- switch (t) { |
- case WebKit::WebTouchPoint::StatePressed: |
- return ui::ET_TOUCH_PRESSED; |
- case WebKit::WebTouchPoint::StateMoved: |
- return ui::ET_TOUCH_MOVED; |
- case WebKit::WebTouchPoint::StateStationary: |
- return ui::ET_TOUCH_STATIONARY; |
- case WebKit::WebTouchPoint::StateReleased: |
- return ui::ET_TOUCH_RELEASED; |
- case WebKit::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| |
-WebKit::WebGestureEvent CreateWebGestureEvent(HWND hwnd, |
- const ui::GestureEvent& gesture) { |
- WebKit::WebGestureEvent gesture_event = |
- MakeWebGestureEventFromUIEvent(gesture); |
- |
- POINT client_point = gesture.location().ToPOINT(); |
- POINT screen_point = gesture.location().ToPOINT(); |
- MapWindowPoints(::GetParent(hwnd), hwnd, &client_point, 1); |
- 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; |
-} |
- |
-WebKit::WebGestureEvent CreateFlingCancelEvent(double time_stamp) { |
- WebKit::WebGestureEvent gesture_event; |
- gesture_event.timeStampSeconds = time_stamp; |
- gesture_event.type = WebKit::WebGestureEvent::GestureFlingCancel; |
- gesture_event.sourceDevice = WebKit::WebGestureEvent::Touchscreen; |
- return gesture_event; |
-} |
- |
-class TouchEventFromWebTouchPoint : public ui::TouchEvent { |
- public: |
- TouchEventFromWebTouchPoint(const WebKit::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(WebKit::WebScreenInfo* results, |
- gfx::NativeViewId id) { |
- *results = WebKit::WebScreenInfoFactory::screenInfo( |
- gfx::NativeViewFromId(id)); |
- results->deviceScaleFactor = ui::win::GetDeviceScaleFactor(); |
-} |
- |
-} // 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 WebKit::WebTouchEvent& touch_event() { return touch_event_; } |
- |
- // Returns if any touches are modified in the event. |
- bool is_changed() { return touch_event_.changedTouchesLength != 0; } |
- |
- private: |
- typedef std::map<unsigned int, int> MapType; |
- |
- // Adds a touch point or returns NULL if there's not enough space. |
- WebKit::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(WebKit::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(); |
- |
- WebKit::WebTouchEvent touch_event_; |
- const RenderWidgetHostViewWin* const window_; |
- |
- // Maps OS touch Id's into an internal (WebKit-friendly) touch-id. |
- // WebKit expects small consecutive integers, starting at 0. |
- MapType touch_map_; |
- |
- 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), |
- ime_notification_(false), |
- capture_enter_key_(false), |
- is_hidden_(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), |
- can_compose_inline_(true), |
- is_fullscreen_(false), |
- ignore_mouse_movement_(true), |
- composition_range_(ui::Range::InvalidRange()), |
- ALLOW_THIS_IN_INITIALIZER_LIST( |
- touch_state_(new WebTouchState(this))), |
- pointer_down_context_(false), |
- last_touch_location_(-1, -1), |
- touch_events_enabled_(false), |
- ALLOW_THIS_IN_INITIALIZER_LIST( |
- gesture_recognizer_(ui::GestureRecognizer::Create(this))) { |
- render_widget_host_->SetView(this); |
- registrar_.Add(this, |
- NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
- NotificationService::AllBrowserContextsAndSources()); |
-} |
- |
-RenderWidgetHostViewWin::~RenderWidgetHostViewWin() { |
- 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(ui::GetWindowToParentTo(true), pos, 0); |
-} |
- |
-RenderWidgetHost* RenderWidgetHostViewWin::GetRenderWidgetHost() const { |
- return render_widget_host_; |
-} |
- |
-void RenderWidgetHostViewWin::WasShown() { |
- if (!is_hidden_) |
- return; |
- |
- if (web_contents_switch_paint_time_.is_null()) |
- web_contents_switch_paint_time_ = TimeTicks::Now(); |
- is_hidden_ = false; |
- |
- // |render_widget_host_| may be NULL if the WebContentsImpl is in the process |
- // of closing. |
- if (render_widget_host_) |
- render_widget_host_->WasShown(); |
-} |
- |
-void RenderWidgetHostViewWin::WasHidden() { |
- if (is_hidden_) |
- return; |
- |
- // If we receive any more paint messages while we are hidden, we want to |
- // ignore them so we don't re-allocate the backing store. We will paint |
- // everything again when we become selected again. |
- is_hidden_ = true; |
- |
- ResetTooltip(); |
- |
- // If we have a renderer, then inform it that we are being hidden so it can |
- // reduce its resource utilization. |
- if (render_widget_host_) |
- render_widget_host_->WasHidden(); |
- |
- if (accelerated_surface_.get()) |
- accelerated_surface_->WasHidden(); |
- |
- if (GetBrowserAccessibilityManager()) |
- GetBrowserAccessibilityManager()->WasHidden(); |
-} |
- |
-void RenderWidgetHostViewWin::SetSize(const gfx::Size& size) { |
- SetBounds(gfx::Rect(GetPixelBounds().origin(), size)); |
-} |
- |
-void RenderWidgetHostViewWin::SetBounds(const gfx::Rect& rect) { |
- if (is_hidden_) |
- 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); |
- } |
- |
- if (!GetBrowserAccessibilityManager()) { |
- // Return busy document tree while renderer accessibility tree loads. |
- AccessibilityNodeData::State busy_state = |
- static_cast<AccessibilityNodeData::State>( |
- 1 << AccessibilityNodeData::STATE_BUSY); |
- SetBrowserAccessibilityManager( |
- BrowserAccessibilityManager::CreateEmptyDocument( |
- m_hWnd, busy_state, this)); |
- } |
- |
- return GetBrowserAccessibilityManager()->GetRoot()-> |
- ToBrowserAccessibilityWin(); |
-} |
- |
-void RenderWidgetHostViewWin::MovePluginWindows( |
- const gfx::Vector2d& scroll_offset, |
- const std::vector<webkit::npapi::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; |
- |
- // 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_ == WebKit::WebPopupTypeNone; |
-} |
- |
-void RenderWidgetHostViewWin::Focus() { |
- if (IsWindow()) |
- SetFocus(); |
-} |
- |
-void RenderWidgetHostViewWin::Blur() { |
- NOTREACHED(); |
-} |
- |
-bool RenderWidgetHostViewWin::HasFocus() const { |
- return ::GetFocus() == m_hWnd; |
-} |
- |
-bool RenderWidgetHostViewWin::IsSurfaceAvailableForCopy() const { |
- return !!render_widget_host_->GetBackingStore(false) || |
- !!accelerated_surface_.get(); |
-} |
- |
-void RenderWidgetHostViewWin::Show() { |
- ShowWindow(SW_SHOW); |
- WasShown(); |
-} |
- |
-void RenderWidgetHostViewWin::Hide() { |
- if (!is_fullscreen_ && GetParent() == ui::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 ui::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::TextInputStateChanged( |
- const ViewHostMsg_TextInputState_Params& params) { |
- if (text_input_type_ != params.type || |
- can_compose_inline_ != params.can_compose_inline) { |
- const bool text_input_type_changed = (text_input_type_ != params.type); |
- text_input_type_ = params.type; |
- can_compose_inline_ = params.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); |
- ime_input_.UpdateCaretRect(m_hWnd, caret_rect_); |
- } |
-} |
- |
-void RenderWidgetHostViewWin::ScrollOffsetChanged() { |
-} |
- |
-void RenderWidgetHostViewWin::ImeCancelComposition() { |
- ime_input_.CancelIME(m_hWnd); |
-} |
- |
-void RenderWidgetHostViewWin::ImeCompositionRangeChanged( |
- const ui::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) { |
- if (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 = ui::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()) { |
- gfx::Rect pixel_rect = ui::win::DIPToScreenRect(scroll_rect); |
- // Damage might not be DIP aligned. |
- pixel_rect.Inset(-1, -1); |
- RECT clip_rect = pixel_rect.ToRECT(); |
- float scale = ui::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::RenderViewGone(base::TerminationStatus status, |
- int error_code) { |
- UpdateCursorIfOverSelf(); |
- Destroy(); |
-} |
- |
-void RenderWidgetHostViewWin::WillWmDestroy() { |
- CleanupCompositorWindow(); |
-} |
- |
-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 string16& tooltip_text) { |
- if (!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 string16 new_tooltip_text = |
- ui::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_.get()) |
- return; |
- |
- if (dst_size.IsEmpty() || src_subrect.IsEmpty()) |
- return; |
- |
- 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_.get()) |
- return; |
- |
- if (!target || target->format() != media::VideoFrame::YV12) |
- return; |
- |
- if (src_subrect.IsEmpty()) |
- return; |
- |
- 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 WebKit::WebTouchEvent& touch, InputEventAckState ack_result) { |
- DCHECK(touch_events_enabled_); |
- |
- ScopedVector<ui::TouchEvent> events; |
- if (!MakeUITouchEventsFromWebTouchEvents(touch, &events)) |
- 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. |
- CommandLine* cmdline = CommandLine::ForCurrentProcess(); |
- static bool touch_mode = base::win::GetVersion() >= base::win::VERSION_WIN7 && |
- ui::IsTouchDevicePresent() && ( |
- !cmdline->HasSwitch(switches::kTouchEvents) || |
- cmdline->GetSwitchValueASCII(switches::kTouchEvents) != |
- switches::kTouchEventsDisabled); |
- |
- if (!touch_mode) |
- return; |
- |
- // Now we know that the window's current state doesn't match the desired |
- // state. If we want touch mode, then we attempt to register for touch |
- // events, and otherwise to unregister. |
- touch_events_enabled_ = RegisterTouchWindow(m_hWnd, TWF_WANTPALM) == TRUE; |
- |
- if (!touch_events_enabled_) { |
- UnregisterTouchWindow(m_hWnd); |
- // Single finger panning is consistent with other windows applications. |
- const DWORD gesture_allow = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | |
- GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; |
- const DWORD gesture_block = GC_PAN_WITH_GUTTER; |
- GESTURECONFIG gc[] = { |
- { GID_ZOOM, GC_ZOOM, 0 }, |
- { GID_PAN, gesture_allow , gesture_block}, |
- { GID_TWOFINGERTAP, GC_TWOFINGERTAP , 0}, |
- { GID_PRESSANDTAP, GC_PRESSANDTAP , 0} |
- }; |
- if (!SetGestureConfig(m_hWnd, 0, arraysize(gc), gc, sizeof(GESTURECONFIG))) |
- NOTREACHED(); |
- } |
-} |
- |
-bool RenderWidgetHostViewWin::DispatchLongPressGestureEvent( |
- ui::GestureEvent* event) { |
- return ForwardGestureEventToRenderer(event); |
-} |
- |
-bool RenderWidgetHostViewWin::DispatchCancelTouchEvent( |
- ui::TouchEvent* event) { |
- if (!render_widget_host_ || !touch_events_enabled_ || |
- !render_widget_host_->ShouldForwardTouchEvent()) { |
- return false; |
- } |
- DCHECK(event->type() == WebKit::WebInputEvent::TouchCancel); |
- WebKit::WebTouchEvent cancel_event; |
- cancel_event.type = WebKit::WebInputEvent::TouchCancel; |
- cancel_event.timeStampSeconds = event->time_stamp().InSecondsF(); |
- render_widget_host_->ForwardTouchEvent(cancel_event); |
- return true; |
-} |
- |
-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 |
- // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely. |
- COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == |
- sizeof(WebKit::WebCompositionUnderline), |
- ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff); |
- const std::vector<WebKit::WebCompositionUnderline>& underlines = |
- reinterpret_cast<const std::vector<WebKit::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 string16& text) { |
- if (!base::win::IsTSFAwareRequired()) { |
- NOTREACHED(); |
- return; |
- } |
- if (render_widget_host_) |
- render_widget_host_->ImeConfirmComposition(text); |
-} |
- |
-void RenderWidgetHostViewWin::InsertChar(char16 ch, int flags) { |
- if (!base::win::IsTSFAwareRequired()) { |
- NOTREACHED(); |
- return; |
- } |
- // TODO(nona): Implement this function. |
- NOTIMPLEMENTED(); |
-} |
- |
-ui::TextInputType RenderWidgetHostViewWin::GetTextInputType() const { |
- if (!base::win::IsTSFAwareRequired()) { |
- NOTREACHED(); |
- return ui::TEXT_INPUT_TYPE_NONE; |
- } |
- return text_input_type_; |
-} |
- |
-bool RenderWidgetHostViewWin::CanComposeInline() const { |
- if (!base::win::IsTSFAwareRequired()) { |
- NOTREACHED(); |
- return false; |
- } |
- // TODO(nona): Implement this function. |
- NOTIMPLEMENTED(); |
- return false; |
-} |
- |
-gfx::Rect RenderWidgetHostViewWin::GetCaretBounds() { |
- 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) { |
- 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() { |
- if (!base::win::IsTSFAwareRequired()) { |
- NOTREACHED(); |
- return false; |
- } |
- // TODO(nona): Implement this function. |
- NOTIMPLEMENTED(); |
- return false; |
-} |
- |
-bool RenderWidgetHostViewWin::GetTextRange(ui::Range* range) { |
- 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(ui::Range* range) { |
- if (!base::win::IsTSFAwareRequired()) { |
- NOTREACHED(); |
- return false; |
- } |
- // TODO(nona): Implement this function. |
- NOTIMPLEMENTED(); |
- return false; |
-} |
- |
-bool RenderWidgetHostViewWin::GetSelectionRange(ui::Range* range) { |
- 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 ui::Range& range) { |
- if (!base::win::IsTSFAwareRequired()) { |
- NOTREACHED(); |
- return false; |
- } |
- // TODO(nona): Implement this function. |
- NOTIMPLEMENTED(); |
- return false; |
-} |
- |
-bool RenderWidgetHostViewWin::DeleteRange(const ui::Range& range) { |
- if (!base::win::IsTSFAwareRequired()) { |
- NOTREACHED(); |
- return false; |
- } |
- // TODO(nona): Implement this function. |
- NOTIMPLEMENTED(); |
- return false; |
-} |
- |
-bool RenderWidgetHostViewWin::GetTextFromRange(const ui::Range& range, |
- string16* text) { |
- if (!base::win::IsTSFAwareRequired()) { |
- NOTREACHED(); |
- return false; |
- } |
- ui::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); |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// 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(), |
- ui::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_array<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(); |
- } |
- } 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(), ui::SCALE_FACTOR_100P, 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); |
- 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 ImeInput 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 = ime_input_.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_) |
- ime_input_.CreateImeWindow(m_hWnd); |
- |
- ime_input_.CleanupComposition(m_hWnd); |
- return ime_input_.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. |
- ime_input_.CreateImeWindow(m_hWnd); |
- ime_input_.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. |
- ime_input_.UpdateImeWindow(m_hWnd); |
- |
- // ui::CompositionUnderline should be identical to |
- // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely. |
- COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == |
- sizeof(WebKit::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 (ime_input_.GetResult(m_hWnd, lparam, &composition.text)) { |
- render_widget_host_->ImeConfirmComposition(composition.text); |
- ime_input_.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 (ime_input_.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 = ui::Range(composition.selection.end()); |
- |
- // TODO(suzhe): convert both renderer_host and renderer to use |
- // ui::CompositionText. |
- const std::vector<WebKit::WebCompositionUnderline>& underlines = |
- reinterpret_cast<const std::vector<WebKit::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 (ime_input_.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 ImeInput object and |
- // of the renderer process. |
- render_widget_host_->ImeCancelComposition(); |
- ime_input_.ResetComposition(m_hWnd); |
- } |
- ime_input_.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)); |
- } |
- |
- // 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 { |
- ime_input_.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::ImeInput::IsRTLKeyboardLayoutInstalled()) { |
- if (message == WM_KEYDOWN) { |
- if (wparam == VK_SHIFT) { |
- base::i18n::TextDirection dir; |
- if (ui::ImeInput::IsCtrlShiftPressed(&dir)) { |
- render_widget_host_->UpdateTextDirection( |
- dir == base::i18n::RIGHT_TO_LEFT ? |
- WebKit::WebTextDirectionRightToLeft : |
- WebKit::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_) { |
- render_widget_host_->ForwardWheelEvent( |
- WebInputEventFactory::mouseWheelEvent(m_hWnd, message, wparam, |
- lparam)); |
- } |
- handled = TRUE; |
- return 0; |
-} |
- |
-WebTouchState::WebTouchState(const RenderWidgetHostViewWin* window) |
- : window_(window) { } |
- |
-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. |
- WebKit::WebTouchPoint* point = touch_event_.touches; |
- WebKit::WebTouchPoint* end = point + touch_event_.touchesLength; |
- while (point < end) { |
- if (point->state == WebKit::WebTouchPoint::StateReleased) { |
- *point = *(--end); |
- --touch_event_.touchesLength; |
- } else { |
- point->state = WebKit::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); |
- |
- WebKit::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 = WebKit::WebInputEvent::TouchStart; |
- break; |
- } |
- |
- case TOUCHEVENTF_UP: { |
- if (!point) // Just throw away a stray up. |
- continue; |
- point->state = WebKit::WebTouchPoint::StateReleased; |
- UpdateTouchPoint(point, &points[i]); |
- touch_event_.type = WebKit::WebInputEvent::TouchEnd; |
- break; |
- } |
- |
- case TOUCHEVENTF_MOVE: { |
- if (point) { |
- point->state = WebKit::WebTouchPoint::StateMoved; |
- // Don't update the message if the point didn't really move. |
- if (UpdateTouchPoint(point, &points[i])) |
- continue; |
- touch_event_.type = WebKit::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 = WebKit::WebInputEvent::TouchStart; |
- } |
- break; |
- } |
- |
- default: |
- NOTREACHED(); |
- continue; |
- } |
- touch_event_.changedTouches[touch_event_.changedTouchesLength++] = *point; |
- } |
- |
- RemoveExpiredMappings(); |
- return count; |
-} |
- |
-void WebTouchState::RemoveExpiredMappings() { |
- WebTouchState::MapType new_map; |
- for (MapType::iterator it = touch_map_.begin(); |
- it != touch_map_.end(); |
- ++it) { |
- WebKit::WebTouchPoint* point = touch_event_.touches; |
- WebKit::WebTouchPoint* end = point + touch_event_.touchesLength; |
- while (point < end) { |
- if ((point->id == it->second) && |
- (point->state != WebKit::WebTouchPoint::StateReleased)) { |
- new_map.insert(*it); |
- break; |
- } |
- point++; |
- } |
- } |
- touch_map_.swap(new_map); |
-} |
- |
- |
-bool WebTouchState::ReleaseTouchPoints() { |
- if (touch_event_.touchesLength == 0) |
- return false; |
- // Mark every active touchpoint as released. |
- touch_event_.type = WebKit::WebInputEvent::TouchEnd; |
- touch_event_.changedTouchesLength = touch_event_.touchesLength; |
- for (unsigned int i = 0; i < touch_event_.touchesLength; ++i) { |
- touch_event_.touches[i].state = WebKit::WebTouchPoint::StateReleased; |
- touch_event_.changedTouches[i].state = |
- WebKit::WebTouchPoint::StateReleased; |
- } |
- |
- return true; |
-} |
- |
-WebKit::WebTouchPoint* WebTouchState::AddTouchPoint( |
- TOUCHINPUT* touch_input) { |
- DCHECK(touch_event_.touchesLength < |
- WebKit::WebTouchEvent::touchesLengthCap); |
- if (touch_event_.touchesLength >= |
- WebKit::WebTouchEvent::touchesLengthCap) |
- return NULL; |
- WebKit::WebTouchPoint* point = |
- &touch_event_.touches[touch_event_.touchesLength++]; |
- point->state = WebKit::WebTouchPoint::StatePressed; |
- point->id = GetMappedTouch(touch_input->dwID); |
- UpdateTouchPoint(point, touch_input); |
- return point; |
-} |
- |
-bool WebTouchState::UpdateTouchPoint( |
- WebKit::WebTouchPoint* touch_point, |
- TOUCHINPUT* touch_input) { |
- CPoint coordinates(TOUCH_COORD_TO_PIXEL(touch_input->x), |
- TOUCH_COORD_TO_PIXEL(touch_input->y)); |
- int radius_x = 1; |
- int radius_y = 1; |
- if (touch_input->dwMask & TOUCHINPUTMASKF_CONTACTAREA) { |
- radius_x = TOUCH_COORD_TO_PIXEL(touch_input->cxContact); |
- radius_y = TOUCH_COORD_TO_PIXEL(touch_input->cyContact); |
- } |
- |
- // 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 = WebKit::WebTouchPoint::StateStationary; |
- return true; |
- } |
- |
- touch_point->screenPosition.x = coordinates.x; |
- touch_point->screenPosition.y = coordinates.y; |
- window_->GetParent().ScreenToClient(&coordinates); |
- touch_point->position.x = coordinates.x; |
- touch_point->position.y = coordinates.y; |
- 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) { |
- MapType::iterator it = touch_map_.find(os_touch_id); |
- if (it != touch_map_.end()) |
- return it->second; |
- int next_value = 0; |
- for (it = touch_map_.begin(); it != touch_map_.end(); ++it) |
- next_value = std::max(next_value, it->second + 1); |
- touch_map_[os_touch_id] = next_value; |
- return next_value; |
-} |
- |
-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 { |
- ime_input_.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>(WebKit::WebTouchEvent::touchesLengthCap)); |
- TOUCHINPUT points[WebKit::WebTouchEvent::touchesLengthCap]; |
- |
- if (!total || !GetTouchInputInfo((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), |
- TOUCH_COORD_TO_PIXEL(points[0].y)); |
- } |
- |
- 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_->ForwardTouchEvent(touch_state_->touch_event()); |
- } else { |
- const WebKit::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 (ui::GetClassName(child_window) == |
- webkit::npapi::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"); |
- |
- // Note that as of M22, touch events are enabled by default on Windows. |
- // This code should not be reachable. |
- 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::OnAccessibilityNotifications( |
- const std::vector<AccessibilityHostMsg_NotificationParams>& params) { |
- if (!GetBrowserAccessibilityManager()) { |
- SetBrowserAccessibilityManager( |
- BrowserAccessibilityManager::CreateEmptyDocument( |
- m_hWnd, |
- static_cast<AccessibilityNodeData::State>(0), |
- this)); |
- } |
- GetBrowserAccessibilityManager()->OnAccessibilityNotifications(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; |
- MoveCursorToCenterIfNecessary(); |
- |
- CRect rect; |
- GetWindowRect(&rect); |
- ::ClipCursor(&rect); |
- |
- 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*>( |
- ui::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_DESTROY: |
- ui::SetWindowUserData(hWnd, NULL); |
- 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_.get()) |
- accelerated_surface_->Present(dc); |
-} |
- |
-void RenderWidgetHostViewWin::GetScreenInfo(WebKit::WebScreenInfo* results) { |
- GetScreenInfoForWindow(results, GetNativeViewId()); |
-} |
- |
-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 ui::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_.get()) |
- 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); |
- ui::CheckWindowCreated(compositor_host_window_); |
- |
- ui::SetWindowUserData(compositor_host_window_, this); |
- |
- gfx::GLSurfaceHandle surface_handle(compositor_host_window_, |
- gfx::NATIVE_TRANSPORT); |
- |
- return surface_handle; |
-} |
- |
-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_.get()) |
- accelerated_surface_->Suspend(); |
- hide_compositor_window_at_next_paint_ = true; |
- } |
-} |
- |
-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_.get()) |
- 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()->GetAccessibilityMode()); |
- |
- // 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(); |
- delete this; |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnSessionChange(UINT message, |
- WPARAM wparam, |
- LPARAM lparam, |
- BOOL& handled) { |
- handled = FALSE; |
- TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSessionChange"); |
- |
- if (!accelerated_surface_.get()) |
- 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 (!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; |
- } |
- |
- WebKit::WebGestureEvent web_gesture = CreateWebGestureEvent(m_hWnd, *gesture); |
- if (web_gesture.type == WebKit::WebGestureEvent::Undefined) |
- return false; |
- if (web_gesture.type == WebKit::WebGestureEvent::GestureTapDown) { |
- render_widget_host_->ForwardGestureEvent( |
- CreateFlingCancelEvent(gesture->time_stamp().InSecondsF())); |
- } |
- render_widget_host_->ForwardGestureEvent(web_gesture); |
- 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 = ui::win::ScreenToDIPPoint( |
- gfx::Point(static_cast<short>(LOWORD(lparam)), |
- static_cast<short>(HIWORD(lparam)))); |
- lparam = (point.y() << 16) + point.x(); |
- |
- WebMouseEvent event( |
- WebInputEventFactory::mouseEvent(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 = ui::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 (ime_input_.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 (ime_input_.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) { |
- ime_input_.EnableIME(m_hWnd); |
- ime_input_.SetUseCompositionWindow(!can_compose_inline_); |
- } else { |
- ime_input_.DisableIME(m_hWnd); |
- } |
-} |
- |
-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); |
-} |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// RenderWidgetHostView, public: |
- |
-// static |
-RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( |
- RenderWidgetHost* widget) { |
- return new RenderWidgetHostViewWin(widget); |
-} |
- |
-// static |
-void RenderWidgetHostViewPort::GetDefaultScreenInfo( |
- WebKit::WebScreenInfo* results) { |
- GetScreenInfoForWindow(results, 0); |
-} |
- |
-} // namespace content |
+// 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 <algorithm> |
+#include <map> |
+#include <stack> |
+#include <wtsapi32.h> |
+#pragma comment(lib, "wtsapi32.lib") |
+ |
+#include "base/bind.h" |
+#include "base/bind_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/process_util.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_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/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_messages.h" |
+#include "content/common/view_messages.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/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/skia/include/core/SkRegion.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/win/WebInputEventFactory.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/win/WebScreenInfoFactory.h" |
+#include "ui/base/events/event.h" |
+#include "ui/base/events/event_utils.h" |
+#include "ui/base/ime/composition_text.h" |
+#include "ui/base/ime/win/tsf_input_scope.h" |
+#include "ui/base/l10n/l10n_util_win.h" |
+#include "ui/base/text/text_elider.h" |
+#include "ui/base/touch/touch_device.h" |
+#include "ui/base/ui_base_switches.h" |
+#include "ui/base/view_prop.h" |
+#include "ui/base/win/dpi.h" |
+#include "ui/base/win/hwnd_util.h" |
+#include "ui/base/win/mouse_wheel_util.h" |
+#include "ui/base/win/touch_input.h" |
+#include "ui/gfx/canvas.h" |
+#include "ui/gfx/rect.h" |
+#include "ui/gfx/rect_conversions.h" |
+#include "ui/gfx/screen.h" |
+#include "webkit/glue/webcursor.h" |
+#include "webkit/plugins/npapi/plugin_constants_win.h" |
+#include "webkit/plugins/npapi/webplugin.h" |
+#include "webkit/plugins/npapi/webplugin_delegate_impl.h" |
+#include "win8/util/win8_util.h" |
+ |
+using base::TimeDelta; |
+using base::TimeTicks; |
+using ui::ViewProp; |
+using WebKit::WebInputEvent; |
+using WebKit::WebInputEventFactory; |
+using WebKit::WebMouseEvent; |
+using WebKit::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; |
+} |
+ |
+WebKit::WebMouseWheelEvent MakeFakeScrollWheelEvent(HWND hwnd, |
+ POINT start, |
+ POINT delta) { |
+ WebKit::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(WebKit::WebTouchPoint::State t) { |
+ switch (t) { |
+ case WebKit::WebTouchPoint::StatePressed: |
+ return ui::ET_TOUCH_PRESSED; |
+ case WebKit::WebTouchPoint::StateMoved: |
+ return ui::ET_TOUCH_MOVED; |
+ case WebKit::WebTouchPoint::StateStationary: |
+ return ui::ET_TOUCH_STATIONARY; |
+ case WebKit::WebTouchPoint::StateReleased: |
+ return ui::ET_TOUCH_RELEASED; |
+ case WebKit::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| |
+WebKit::WebGestureEvent CreateWebGestureEvent(HWND hwnd, |
+ const ui::GestureEvent& gesture) { |
+ WebKit::WebGestureEvent gesture_event = |
+ MakeWebGestureEventFromUIEvent(gesture); |
+ |
+ POINT client_point = gesture.location().ToPOINT(); |
+ POINT screen_point = gesture.location().ToPOINT(); |
+ MapWindowPoints(::GetParent(hwnd), hwnd, &client_point, 1); |
+ 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; |
+} |
+ |
+WebKit::WebGestureEvent CreateFlingCancelEvent(double time_stamp) { |
+ WebKit::WebGestureEvent gesture_event; |
+ gesture_event.timeStampSeconds = time_stamp; |
+ gesture_event.type = WebKit::WebGestureEvent::GestureFlingCancel; |
+ gesture_event.sourceDevice = WebKit::WebGestureEvent::Touchscreen; |
+ return gesture_event; |
+} |
+ |
+class TouchEventFromWebTouchPoint : public ui::TouchEvent { |
+ public: |
+ TouchEventFromWebTouchPoint(const WebKit::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(WebKit::WebScreenInfo* results, |
+ gfx::NativeViewId id) { |
+ *results = WebKit::WebScreenInfoFactory::screenInfo( |
+ gfx::NativeViewFromId(id)); |
+ results->deviceScaleFactor = ui::win::GetDeviceScaleFactor(); |
+} |
+ |
+} // 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 WebKit::WebTouchEvent& touch_event() { return touch_event_; } |
+ |
+ // Returns if any touches are modified in the event. |
+ bool is_changed() { return touch_event_.changedTouchesLength != 0; } |
+ |
+ private: |
+ typedef std::map<unsigned int, int> MapType; |
+ |
+ // Adds a touch point or returns NULL if there's not enough space. |
+ WebKit::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(WebKit::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(); |
+ |
+ WebKit::WebTouchEvent touch_event_; |
+ const RenderWidgetHostViewWin* const window_; |
+ |
+ // Maps OS touch Id's into an internal (WebKit-friendly) touch-id. |
+ // WebKit expects small consecutive integers, starting at 0. |
+ MapType touch_map_; |
+ |
+ 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), |
+ ime_notification_(false), |
+ capture_enter_key_(false), |
+ is_hidden_(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), |
+ can_compose_inline_(true), |
+ is_fullscreen_(false), |
+ ignore_mouse_movement_(true), |
+ composition_range_(ui::Range::InvalidRange()), |
+ ALLOW_THIS_IN_INITIALIZER_LIST( |
+ touch_state_(new WebTouchState(this))), |
+ pointer_down_context_(false), |
+ last_touch_location_(-1, -1), |
+ touch_events_enabled_(false), |
+ ALLOW_THIS_IN_INITIALIZER_LIST( |
+ gesture_recognizer_(ui::GestureRecognizer::Create(this))) { |
+ render_widget_host_->SetView(this); |
+ registrar_.Add(this, |
+ NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
+ NotificationService::AllBrowserContextsAndSources()); |
+} |
+ |
+RenderWidgetHostViewWin::~RenderWidgetHostViewWin() { |
+ 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(ui::GetWindowToParentTo(true), pos, 0); |
+} |
+ |
+RenderWidgetHost* RenderWidgetHostViewWin::GetRenderWidgetHost() const { |
+ return render_widget_host_; |
+} |
+ |
+void RenderWidgetHostViewWin::WasShown() { |
+ if (!is_hidden_) |
+ return; |
+ |
+ if (web_contents_switch_paint_time_.is_null()) |
+ web_contents_switch_paint_time_ = TimeTicks::Now(); |
+ is_hidden_ = false; |
+ |
+ // |render_widget_host_| may be NULL if the WebContentsImpl is in the process |
+ // of closing. |
+ if (render_widget_host_) |
+ render_widget_host_->WasShown(); |
+} |
+ |
+void RenderWidgetHostViewWin::WasHidden() { |
+ if (is_hidden_) |
+ return; |
+ |
+ // If we receive any more paint messages while we are hidden, we want to |
+ // ignore them so we don't re-allocate the backing store. We will paint |
+ // everything again when we become selected again. |
+ is_hidden_ = true; |
+ |
+ ResetTooltip(); |
+ |
+ // If we have a renderer, then inform it that we are being hidden so it can |
+ // reduce its resource utilization. |
+ if (render_widget_host_) |
+ render_widget_host_->WasHidden(); |
+ |
+ if (accelerated_surface_.get()) |
+ accelerated_surface_->WasHidden(); |
+ |
+ if (GetBrowserAccessibilityManager()) |
+ GetBrowserAccessibilityManager()->WasHidden(); |
+} |
+ |
+void RenderWidgetHostViewWin::SetSize(const gfx::Size& size) { |
+ SetBounds(gfx::Rect(GetPixelBounds().origin(), size)); |
+} |
+ |
+void RenderWidgetHostViewWin::SetBounds(const gfx::Rect& rect) { |
+ if (is_hidden_) |
+ 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); |
+ } |
+ |
+ if (!GetBrowserAccessibilityManager()) { |
+ // Return busy document tree while renderer accessibility tree loads. |
+ AccessibilityNodeData::State busy_state = |
+ static_cast<AccessibilityNodeData::State>( |
+ 1 << AccessibilityNodeData::STATE_BUSY); |
+ SetBrowserAccessibilityManager( |
+ BrowserAccessibilityManager::CreateEmptyDocument( |
+ m_hWnd, busy_state, this)); |
+ } |
+ |
+ return GetBrowserAccessibilityManager()->GetRoot()-> |
+ ToBrowserAccessibilityWin(); |
+} |
+ |
+void RenderWidgetHostViewWin::MovePluginWindows( |
+ const gfx::Vector2d& scroll_offset, |
+ const std::vector<webkit::npapi::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; |
+ |
+ // 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_ == WebKit::WebPopupTypeNone; |
+} |
+ |
+void RenderWidgetHostViewWin::Focus() { |
+ if (IsWindow()) |
+ SetFocus(); |
+} |
+ |
+void RenderWidgetHostViewWin::Blur() { |
+ NOTREACHED(); |
+} |
+ |
+bool RenderWidgetHostViewWin::HasFocus() const { |
+ return ::GetFocus() == m_hWnd; |
+} |
+ |
+bool RenderWidgetHostViewWin::IsSurfaceAvailableForCopy() const { |
+ return !!render_widget_host_->GetBackingStore(false) || |
+ !!accelerated_surface_.get(); |
+} |
+ |
+void RenderWidgetHostViewWin::Show() { |
+ ShowWindow(SW_SHOW); |
+ WasShown(); |
+} |
+ |
+void RenderWidgetHostViewWin::Hide() { |
+ if (!is_fullscreen_ && GetParent() == ui::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 ui::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::TextInputStateChanged( |
+ const ViewHostMsg_TextInputState_Params& params) { |
+ if (text_input_type_ != params.type || |
+ can_compose_inline_ != params.can_compose_inline) { |
+ const bool text_input_type_changed = (text_input_type_ != params.type); |
+ text_input_type_ = params.type; |
+ can_compose_inline_ = params.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); |
+ ime_input_.UpdateCaretRect(m_hWnd, caret_rect_); |
+ } |
+} |
+ |
+void RenderWidgetHostViewWin::ScrollOffsetChanged() { |
+} |
+ |
+void RenderWidgetHostViewWin::ImeCancelComposition() { |
+ ime_input_.CancelIME(m_hWnd); |
+} |
+ |
+void RenderWidgetHostViewWin::ImeCompositionRangeChanged( |
+ const ui::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) { |
+ if (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 = ui::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()) { |
+ gfx::Rect pixel_rect = ui::win::DIPToScreenRect(scroll_rect); |
+ // Damage might not be DIP aligned. |
+ pixel_rect.Inset(-1, -1); |
+ RECT clip_rect = pixel_rect.ToRECT(); |
+ float scale = ui::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::RenderViewGone(base::TerminationStatus status, |
+ int error_code) { |
+ UpdateCursorIfOverSelf(); |
+ Destroy(); |
+} |
+ |
+void RenderWidgetHostViewWin::WillWmDestroy() { |
+ CleanupCompositorWindow(); |
+} |
+ |
+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 string16& tooltip_text) { |
+ if (!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 string16 new_tooltip_text = |
+ ui::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_.get()) |
+ return; |
+ |
+ if (dst_size.IsEmpty() || src_subrect.IsEmpty()) |
+ return; |
+ |
+ 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_.get()) |
+ return; |
+ |
+ if (!target || target->format() != media::VideoFrame::YV12) |
+ return; |
+ |
+ if (src_subrect.IsEmpty()) |
+ return; |
+ |
+ 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 WebKit::WebTouchEvent& touch, InputEventAckState ack_result) { |
+ DCHECK(touch_events_enabled_); |
+ |
+ ScopedVector<ui::TouchEvent> events; |
+ if (!MakeUITouchEventsFromWebTouchEvents(touch, &events)) |
+ 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. |
+ CommandLine* cmdline = CommandLine::ForCurrentProcess(); |
+ static bool touch_mode = base::win::GetVersion() >= base::win::VERSION_WIN7 && |
+ ui::IsTouchDevicePresent() && ( |
+ !cmdline->HasSwitch(switches::kTouchEvents) || |
+ cmdline->GetSwitchValueASCII(switches::kTouchEvents) != |
+ switches::kTouchEventsDisabled); |
+ |
+ if (!touch_mode) |
+ return; |
+ |
+ // Now we know that the window's current state doesn't match the desired |
+ // state. If we want touch mode, then we attempt to register for touch |
+ // events, and otherwise to unregister. |
+ touch_events_enabled_ = RegisterTouchWindow(m_hWnd, TWF_WANTPALM) == TRUE; |
+ |
+ if (!touch_events_enabled_) { |
+ UnregisterTouchWindow(m_hWnd); |
+ // Single finger panning is consistent with other windows applications. |
+ const DWORD gesture_allow = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | |
+ GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; |
+ const DWORD gesture_block = GC_PAN_WITH_GUTTER; |
+ GESTURECONFIG gc[] = { |
+ { GID_ZOOM, GC_ZOOM, 0 }, |
+ { GID_PAN, gesture_allow , gesture_block}, |
+ { GID_TWOFINGERTAP, GC_TWOFINGERTAP , 0}, |
+ { GID_PRESSANDTAP, GC_PRESSANDTAP , 0} |
+ }; |
+ if (!SetGestureConfig(m_hWnd, 0, arraysize(gc), gc, sizeof(GESTURECONFIG))) |
+ NOTREACHED(); |
+ } |
+} |
+ |
+bool RenderWidgetHostViewWin::DispatchLongPressGestureEvent( |
+ ui::GestureEvent* event) { |
+ return ForwardGestureEventToRenderer(event); |
+} |
+ |
+bool RenderWidgetHostViewWin::DispatchCancelTouchEvent( |
+ ui::TouchEvent* event) { |
+ if (!render_widget_host_ || !touch_events_enabled_ || |
+ !render_widget_host_->ShouldForwardTouchEvent()) { |
+ return false; |
+ } |
+ DCHECK(event->type() == WebKit::WebInputEvent::TouchCancel); |
+ WebKit::WebTouchEvent cancel_event; |
+ cancel_event.type = WebKit::WebInputEvent::TouchCancel; |
+ cancel_event.timeStampSeconds = event->time_stamp().InSecondsF(); |
+ render_widget_host_->ForwardTouchEvent(cancel_event); |
+ return true; |
+} |
+ |
+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 |
+ // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely. |
+ COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == |
+ sizeof(WebKit::WebCompositionUnderline), |
+ ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff); |
+ const std::vector<WebKit::WebCompositionUnderline>& underlines = |
+ reinterpret_cast<const std::vector<WebKit::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 string16& text) { |
+ if (!base::win::IsTSFAwareRequired()) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ if (render_widget_host_) |
+ render_widget_host_->ImeConfirmComposition(text); |
+} |
+ |
+void RenderWidgetHostViewWin::InsertChar(char16 ch, int flags) { |
+ if (!base::win::IsTSFAwareRequired()) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ // TODO(nona): Implement this function. |
+ NOTIMPLEMENTED(); |
+} |
+ |
+ui::TextInputType RenderWidgetHostViewWin::GetTextInputType() const { |
+ if (!base::win::IsTSFAwareRequired()) { |
+ NOTREACHED(); |
+ return ui::TEXT_INPUT_TYPE_NONE; |
+ } |
+ return text_input_type_; |
+} |
+ |
+bool RenderWidgetHostViewWin::CanComposeInline() const { |
+ if (!base::win::IsTSFAwareRequired()) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ // TODO(nona): Implement this function. |
+ NOTIMPLEMENTED(); |
+ return false; |
+} |
+ |
+gfx::Rect RenderWidgetHostViewWin::GetCaretBounds() { |
+ 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) { |
+ 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() { |
+ if (!base::win::IsTSFAwareRequired()) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ // TODO(nona): Implement this function. |
+ NOTIMPLEMENTED(); |
+ return false; |
+} |
+ |
+bool RenderWidgetHostViewWin::GetTextRange(ui::Range* range) { |
+ 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(ui::Range* range) { |
+ if (!base::win::IsTSFAwareRequired()) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ // TODO(nona): Implement this function. |
+ NOTIMPLEMENTED(); |
+ return false; |
+} |
+ |
+bool RenderWidgetHostViewWin::GetSelectionRange(ui::Range* range) { |
+ 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 ui::Range& range) { |
+ if (!base::win::IsTSFAwareRequired()) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ // TODO(nona): Implement this function. |
+ NOTIMPLEMENTED(); |
+ return false; |
+} |
+ |
+bool RenderWidgetHostViewWin::DeleteRange(const ui::Range& range) { |
+ if (!base::win::IsTSFAwareRequired()) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ // TODO(nona): Implement this function. |
+ NOTIMPLEMENTED(); |
+ return false; |
+} |
+ |
+bool RenderWidgetHostViewWin::GetTextFromRange(const ui::Range& range, |
+ string16* text) { |
+ if (!base::win::IsTSFAwareRequired()) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ ui::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); |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// 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(), |
+ ui::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_array<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(); |
+ } |
+ } 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(), ui::SCALE_FACTOR_100P, 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); |
+ 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 ImeInput 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 = ime_input_.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_) |
+ ime_input_.CreateImeWindow(m_hWnd); |
+ |
+ ime_input_.CleanupComposition(m_hWnd); |
+ return ime_input_.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. |
+ ime_input_.CreateImeWindow(m_hWnd); |
+ ime_input_.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. |
+ ime_input_.UpdateImeWindow(m_hWnd); |
+ |
+ // ui::CompositionUnderline should be identical to |
+ // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely. |
+ COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == |
+ sizeof(WebKit::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 (ime_input_.GetResult(m_hWnd, lparam, &composition.text)) { |
+ render_widget_host_->ImeConfirmComposition(composition.text); |
+ ime_input_.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 (ime_input_.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 = ui::Range(composition.selection.end()); |
+ |
+ // TODO(suzhe): convert both renderer_host and renderer to use |
+ // ui::CompositionText. |
+ const std::vector<WebKit::WebCompositionUnderline>& underlines = |
+ reinterpret_cast<const std::vector<WebKit::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 (ime_input_.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 ImeInput object and |
+ // of the renderer process. |
+ render_widget_host_->ImeCancelComposition(); |
+ ime_input_.ResetComposition(m_hWnd); |
+ } |
+ ime_input_.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)); |
+ } |
+ |
+ // 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 { |
+ ime_input_.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::ImeInput::IsRTLKeyboardLayoutInstalled()) { |
+ if (message == WM_KEYDOWN) { |
+ if (wparam == VK_SHIFT) { |
+ base::i18n::TextDirection dir; |
+ if (ui::ImeInput::IsCtrlShiftPressed(&dir)) { |
+ render_widget_host_->UpdateTextDirection( |
+ dir == base::i18n::RIGHT_TO_LEFT ? |
+ WebKit::WebTextDirectionRightToLeft : |
+ WebKit::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_) { |
+ render_widget_host_->ForwardWheelEvent( |
+ WebInputEventFactory::mouseWheelEvent(m_hWnd, message, wparam, |
+ lparam)); |
+ } |
+ handled = TRUE; |
+ return 0; |
+} |
+ |
+WebTouchState::WebTouchState(const RenderWidgetHostViewWin* window) |
+ : window_(window) { } |
+ |
+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. |
+ WebKit::WebTouchPoint* point = touch_event_.touches; |
+ WebKit::WebTouchPoint* end = point + touch_event_.touchesLength; |
+ while (point < end) { |
+ if (point->state == WebKit::WebTouchPoint::StateReleased) { |
+ *point = *(--end); |
+ --touch_event_.touchesLength; |
+ } else { |
+ point->state = WebKit::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); |
+ |
+ WebKit::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 = WebKit::WebInputEvent::TouchStart; |
+ break; |
+ } |
+ |
+ case TOUCHEVENTF_UP: { |
+ if (!point) // Just throw away a stray up. |
+ continue; |
+ point->state = WebKit::WebTouchPoint::StateReleased; |
+ UpdateTouchPoint(point, &points[i]); |
+ touch_event_.type = WebKit::WebInputEvent::TouchEnd; |
+ break; |
+ } |
+ |
+ case TOUCHEVENTF_MOVE: { |
+ if (point) { |
+ point->state = WebKit::WebTouchPoint::StateMoved; |
+ // Don't update the message if the point didn't really move. |
+ if (UpdateTouchPoint(point, &points[i])) |
+ continue; |
+ touch_event_.type = WebKit::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 = WebKit::WebInputEvent::TouchStart; |
+ } |
+ break; |
+ } |
+ |
+ default: |
+ NOTREACHED(); |
+ continue; |
+ } |
+ touch_event_.changedTouches[touch_event_.changedTouchesLength++] = *point; |
+ } |
+ |
+ RemoveExpiredMappings(); |
+ return count; |
+} |
+ |
+void WebTouchState::RemoveExpiredMappings() { |
+ WebTouchState::MapType new_map; |
+ for (MapType::iterator it = touch_map_.begin(); |
+ it != touch_map_.end(); |
+ ++it) { |
+ WebKit::WebTouchPoint* point = touch_event_.touches; |
+ WebKit::WebTouchPoint* end = point + touch_event_.touchesLength; |
+ while (point < end) { |
+ if ((point->id == it->second) && |
+ (point->state != WebKit::WebTouchPoint::StateReleased)) { |
+ new_map.insert(*it); |
+ break; |
+ } |
+ point++; |
+ } |
+ } |
+ touch_map_.swap(new_map); |
+} |
+ |
+ |
+bool WebTouchState::ReleaseTouchPoints() { |
+ if (touch_event_.touchesLength == 0) |
+ return false; |
+ // Mark every active touchpoint as released. |
+ touch_event_.type = WebKit::WebInputEvent::TouchEnd; |
+ touch_event_.changedTouchesLength = touch_event_.touchesLength; |
+ for (unsigned int i = 0; i < touch_event_.touchesLength; ++i) { |
+ touch_event_.touches[i].state = WebKit::WebTouchPoint::StateReleased; |
+ touch_event_.changedTouches[i].state = |
+ WebKit::WebTouchPoint::StateReleased; |
+ } |
+ |
+ return true; |
+} |
+ |
+WebKit::WebTouchPoint* WebTouchState::AddTouchPoint( |
+ TOUCHINPUT* touch_input) { |
+ DCHECK(touch_event_.touchesLength < |
+ WebKit::WebTouchEvent::touchesLengthCap); |
+ if (touch_event_.touchesLength >= |
+ WebKit::WebTouchEvent::touchesLengthCap) |
+ return NULL; |
+ WebKit::WebTouchPoint* point = |
+ &touch_event_.touches[touch_event_.touchesLength++]; |
+ point->state = WebKit::WebTouchPoint::StatePressed; |
+ point->id = GetMappedTouch(touch_input->dwID); |
+ UpdateTouchPoint(point, touch_input); |
+ return point; |
+} |
+ |
+bool WebTouchState::UpdateTouchPoint( |
+ WebKit::WebTouchPoint* touch_point, |
+ TOUCHINPUT* touch_input) { |
+ CPoint coordinates(TOUCH_COORD_TO_PIXEL(touch_input->x), |
+ TOUCH_COORD_TO_PIXEL(touch_input->y)); |
+ int radius_x = 1; |
+ int radius_y = 1; |
+ if (touch_input->dwMask & TOUCHINPUTMASKF_CONTACTAREA) { |
+ radius_x = TOUCH_COORD_TO_PIXEL(touch_input->cxContact); |
+ radius_y = TOUCH_COORD_TO_PIXEL(touch_input->cyContact); |
+ } |
+ |
+ // 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 = WebKit::WebTouchPoint::StateStationary; |
+ return true; |
+ } |
+ |
+ touch_point->screenPosition.x = coordinates.x; |
+ touch_point->screenPosition.y = coordinates.y; |
+ window_->GetParent().ScreenToClient(&coordinates); |
+ touch_point->position.x = coordinates.x; |
+ touch_point->position.y = coordinates.y; |
+ 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) { |
+ MapType::iterator it = touch_map_.find(os_touch_id); |
+ if (it != touch_map_.end()) |
+ return it->second; |
+ int next_value = 0; |
+ for (it = touch_map_.begin(); it != touch_map_.end(); ++it) |
+ next_value = std::max(next_value, it->second + 1); |
+ touch_map_[os_touch_id] = next_value; |
+ return next_value; |
+} |
+ |
+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 { |
+ ime_input_.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>(WebKit::WebTouchEvent::touchesLengthCap)); |
+ TOUCHINPUT points[WebKit::WebTouchEvent::touchesLengthCap]; |
+ |
+ if (!total || !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), |
+ TOUCH_COORD_TO_PIXEL(points[0].y)); |
+ } |
+ |
+ 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_->ForwardTouchEvent(touch_state_->touch_event()); |
+ } else { |
+ const WebKit::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 (ui::GetClassName(child_window) == |
+ webkit::npapi::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"); |
+ |
+ // Note that as of M22, touch events are enabled by default on Windows. |
+ // This code should not be reachable. |
+ 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::OnAccessibilityNotifications( |
+ const std::vector<AccessibilityHostMsg_NotificationParams>& params) { |
+ if (!GetBrowserAccessibilityManager()) { |
+ SetBrowserAccessibilityManager( |
+ BrowserAccessibilityManager::CreateEmptyDocument( |
+ m_hWnd, |
+ static_cast<AccessibilityNodeData::State>(0), |
+ this)); |
+ } |
+ GetBrowserAccessibilityManager()->OnAccessibilityNotifications(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; |
+ MoveCursorToCenterIfNecessary(); |
+ |
+ CRect rect; |
+ GetWindowRect(&rect); |
+ ::ClipCursor(&rect); |
+ |
+ 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*>( |
+ ui::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_DESTROY: |
+ ui::SetWindowUserData(hWnd, NULL); |
+ 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_.get()) |
+ accelerated_surface_->Present(dc); |
+} |
+ |
+void RenderWidgetHostViewWin::GetScreenInfo(WebKit::WebScreenInfo* results) { |
+ GetScreenInfoForWindow(results, GetNativeViewId()); |
+} |
+ |
+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 ui::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_.get()) |
+ 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); |
+ ui::CheckWindowCreated(compositor_host_window_); |
+ |
+ ui::SetWindowUserData(compositor_host_window_, this); |
+ |
+ gfx::GLSurfaceHandle surface_handle(compositor_host_window_, |
+ gfx::NATIVE_TRANSPORT); |
+ |
+ return surface_handle; |
+} |
+ |
+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_.get()) |
+ accelerated_surface_->Suspend(); |
+ hide_compositor_window_at_next_paint_ = true; |
+ } |
+} |
+ |
+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_.get()) |
+ 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()->GetAccessibilityMode()); |
+ |
+ // 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(); |
+ delete this; |
+} |
+ |
+LRESULT RenderWidgetHostViewWin::OnSessionChange(UINT message, |
+ WPARAM wparam, |
+ LPARAM lparam, |
+ BOOL& handled) { |
+ handled = FALSE; |
+ TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSessionChange"); |
+ |
+ if (!accelerated_surface_.get()) |
+ 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 (!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; |
+ } |
+ |
+ WebKit::WebGestureEvent web_gesture = CreateWebGestureEvent(m_hWnd, *gesture); |
+ if (web_gesture.type == WebKit::WebGestureEvent::Undefined) |
+ return false; |
+ if (web_gesture.type == WebKit::WebGestureEvent::GestureTapDown) { |
+ render_widget_host_->ForwardGestureEvent( |
+ CreateFlingCancelEvent(gesture->time_stamp().InSecondsF())); |
+ } |
+ render_widget_host_->ForwardGestureEvent(web_gesture); |
+ 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 = ui::win::ScreenToDIPPoint( |
+ gfx::Point(static_cast<short>(LOWORD(lparam)), |
+ static_cast<short>(HIWORD(lparam)))); |
+ lparam = (point.y() << 16) + point.x(); |
+ |
+ WebMouseEvent event( |
+ WebInputEventFactory::mouseEvent(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 = ui::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 (ime_input_.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 (ime_input_.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) { |
+ ime_input_.EnableIME(m_hWnd); |
+ ime_input_.SetUseCompositionWindow(!can_compose_inline_); |
+ } else { |
+ ime_input_.DisableIME(m_hWnd); |
+ } |
+} |
+ |
+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); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// RenderWidgetHostView, public: |
+ |
+// static |
+RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( |
+ RenderWidgetHost* widget) { |
+ return new RenderWidgetHostViewWin(widget); |
+} |
+ |
+// static |
+void RenderWidgetHostViewPort::GetDefaultScreenInfo( |
+ WebKit::WebScreenInfo* results) { |
+ GetScreenInfoForWindow(results, 0); |
+} |
+ |
+} // namespace content |