Index: chrome/browser/renderer_host/render_widget_host_view_win.cc |
=================================================================== |
--- chrome/browser/renderer_host/render_widget_host_view_win.cc (revision 98240) |
+++ chrome/browser/renderer_host/render_widget_host_view_win.cc (working copy) |
@@ -1,1865 +0,0 @@ |
-// Copyright (c) 2011 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. |
- |
-// Need Win 7 headers for WM_GESTURE and ChangeWindowMessageFilterEx |
-// TODO(jschuh): See crbug.com/92941 for longterm fix. |
-#undef WINVER |
-#define WINVER _WIN32_WINNT_WIN7 |
-#undef _WIN32_WINNT |
-#define _WIN32_WINNT _WIN32_WINNT_WIN7 |
-#include <windows.h> |
- |
-#include "chrome/browser/renderer_host/render_widget_host_view_win.h" |
- |
-#include <algorithm> |
- |
-#include "base/command_line.h" |
-#include "base/i18n/rtl.h" |
-#include "base/metrics/histogram.h" |
-#include "base/process_util.h" |
-#include "base/threading/thread.h" |
-#include "base/win/scoped_comptr.h" |
-#include "base/win/scoped_gdi_object.h" |
-#include "base/win/wrapped_window_proc.h" |
-#include "content/browser/accessibility/browser_accessibility_manager.h" |
-#include "content/browser/accessibility/browser_accessibility_state.h" |
-#include "content/browser/accessibility/browser_accessibility_win.h" |
-#include "content/browser/browser_thread.h" |
-#include "content/browser/content_browser_client.h" |
-#include "content/browser/plugin_process_host.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.h" |
-#include "content/browser/renderer_host/render_widget_host.h" |
-#include "content/common/content_switches.h" |
-#include "content/common/native_web_keyboard_event.h" |
-#include "content/common/notification_service.h" |
-#include "content/common/plugin_messages.h" |
-#include "content/common/view_messages.h" |
-#include "skia/ext/skia_utils_win.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 "ui/base/ime/composition_text.h" |
-#include "ui/base/l10n/l10n_util.h" |
-#include "ui/base/l10n/l10n_util_win.h" |
-#include "ui/base/resource/resource_bundle.h" |
-#include "ui/base/text/text_elider.h" |
-#include "ui/base/view_prop.h" |
-#include "ui/base/win/hwnd_util.h" |
-#include "ui/gfx/canvas.h" |
-#include "ui/gfx/canvas_skia.h" |
-#include "ui/gfx/gdi_util.h" |
-#include "ui/gfx/rect.h" |
-#include "ui/gfx/screen.h" |
-#include "views/accessibility/native_view_accessibility_win.h" |
-#include "views/focus/focus_manager.h" |
-#include "views/focus/focus_util_win.h" |
-// Included for views::kReflectedMessage - TODO(beng): move this to win_util.h! |
-#include "views/widget/native_widget_win.h" |
-#include "webkit/glue/webaccessibility.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" |
- |
-using base::TimeDelta; |
-using base::TimeTicks; |
-using ui::ViewProp; |
-using WebKit::WebInputEvent; |
-using WebKit::WebInputEventFactory; |
-using WebKit::WebMouseEvent; |
-using WebKit::WebTextDirection; |
-using webkit::npapi::WebPluginGeometry; |
- |
-const wchar_t kRenderWidgetHostHWNDClass[] = L"Chrome_RenderWidgetHostHWND"; |
- |
-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; |
- |
-const char* const kRenderWidgetHostViewKey = "__RENDER_WIDGET_HOST_VIEW__"; |
- |
-// A callback function for EnumThreadWindows to enumerate and dismiss |
-// any owned popop 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; |
-} |
- |
-class NotifyPluginProcessHostTask : public Task { |
- public: |
- NotifyPluginProcessHostTask(HWND window, HWND parent) |
- : window_(window), parent_(parent), tries_(kMaxTries) { } |
- |
- private: |
- void Run() { |
- DWORD plugin_process_id; |
- bool found_starting_plugin_process = false; |
- GetWindowThreadProcessId(window_, &plugin_process_id); |
- for (BrowserChildProcessHost::Iterator iter( |
- ChildProcessInfo::PLUGIN_PROCESS); |
- !iter.Done(); ++iter) { |
- PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter); |
- if (!plugin->handle()) { |
- found_starting_plugin_process = true; |
- continue; |
- } |
- if (base::GetProcId(plugin->handle()) == plugin_process_id) { |
- plugin->AddWindow(parent_); |
- return; |
- } |
- } |
- |
- if (found_starting_plugin_process) { |
- // A plugin process has started but we don't have its handle yet. Since |
- // it's most likely the one for this plugin, try a few more times after a |
- // delay. |
- if (tries_--) { |
- MessageLoop::current()->PostDelayedTask(FROM_HERE, this, kTryDelayMs); |
- return; |
- } |
- } |
- |
- // The plugin process might have died in the time to execute the task, don't |
- // leak the HWND. |
- PostMessage(parent_, WM_CLOSE, 0, 0); |
- } |
- |
- HWND window_; // Plugin HWND, created and destroyed in the plugin process. |
- HWND parent_; // Parent HWND, created and destroyed on the browser UI thread. |
- |
- int tries_; |
- |
- // How many times we try to find a PluginProcessHost whose process matches |
- // the HWND. |
- static const int kMaxTries = 5; |
- // How long to wait between each try. |
- static const int kTryDelayMs = 200; |
-}; |
- |
-// Windows callback for OnDestroy to detach the plugin windows. |
-BOOL CALLBACK DetachPluginWindowsCallback(HWND window, LPARAM param) { |
- if (webkit::npapi::WebPluginDelegateImpl::IsPluginDelegateWindow(window) && |
- !IsHungAppWindow(window)) { |
- ::ShowWindow(window, SW_HIDE); |
- SetParent(window, NULL); |
- } |
- return TRUE; |
-} |
- |
-// Draw the contents of |backing_store_dc| onto |paint_rect| with a 70% grey |
-// filter. |
-void DrawDeemphasized(const SkColor& color, |
- const gfx::Rect& paint_rect, |
- HDC backing_store_dc, |
- HDC paint_dc) { |
- gfx::CanvasSkia canvas(paint_rect.width(), paint_rect.height(), true); |
- { |
- skia::ScopedPlatformPaint scoped_platform_paint(&canvas); |
- HDC dc = scoped_platform_paint.GetPlatformSurface(); |
- BitBlt(dc, |
- 0, |
- 0, |
- paint_rect.width(), |
- paint_rect.height(), |
- backing_store_dc, |
- paint_rect.x(), |
- paint_rect.y(), |
- SRCCOPY); |
- } |
- canvas.FillRectInt(color, 0, 0, paint_rect.width(), paint_rect.height()); |
- skia::DrawToNativeContext(&canvas, paint_dc, paint_rect.x(), |
- paint_rect.y(), NULL); |
-} |
- |
-// The plugin wrapper window which lives in the browser process has this proc |
-// as its window procedure. We only handle the WM_PARENTNOTIFY message sent by |
-// windowed plugins for mouse input. This is forwarded off to the wrappers |
-// parent which is typically the RVH window which turns on user gesture. |
-LRESULT CALLBACK PluginWrapperWindowProc(HWND window, unsigned int message, |
- WPARAM wparam, LPARAM lparam) { |
- if (message == WM_PARENTNOTIFY) { |
- switch (LOWORD(wparam)) { |
- case WM_LBUTTONDOWN: |
- case WM_RBUTTONDOWN: |
- case WM_MBUTTONDOWN: |
- ::SendMessage(GetParent(window), message, wparam, lparam); |
- return 0; |
- default: |
- break; |
- } |
- } |
- return ::DefWindowProc(window, message, wparam, lparam); |
-} |
- |
-// Must be dynamically loaded to avoid startup failures on Win XP. |
-typedef BOOL (WINAPI *ChangeWindowMessageFilterExFunction)( |
- HWND hwnd, |
- UINT message, |
- DWORD action, |
- PCHANGEFILTERSTRUCT change_filter_struct); |
-ChangeWindowMessageFilterExFunction g_ChangeWindowMessageFilterEx; |
- |
-} // namespace |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// RenderWidgetHostViewWin, public: |
- |
-RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget) |
- : render_widget_host_(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), |
- shutdown_factory_(this), |
- parent_hwnd_(NULL), |
- is_loading_(false), |
- overlay_color_(0), |
- text_input_type_(ui::TEXT_INPUT_TYPE_NONE), |
- is_fullscreen_(false) { |
- render_widget_host_->SetView(this); |
- registrar_.Add(this, |
- content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
- NotificationService::AllSources()); |
-} |
- |
-RenderWidgetHostViewWin::~RenderWidgetHostViewWin() { |
- ResetTooltip(); |
-} |
- |
-void RenderWidgetHostViewWin::CreateWnd(HWND parent) { |
- Create(parent); // ATL function to create the window. |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// RenderWidgetHostViewWin, RenderWidgetHostView implementation: |
- |
-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::GetMonitorAreaNearestWindow( |
- reference_host_view->GetNativeView()); |
- is_fullscreen_ = true; |
- DoPopupOrFullscreenInit(GetDesktopWindow(), pos, 0); |
-} |
- |
-RenderWidgetHost* RenderWidgetHostViewWin::GetRenderWidgetHost() const { |
- return render_widget_host_; |
-} |
- |
-void RenderWidgetHostViewWin::DidBecomeSelected() { |
- if (!is_hidden_) |
- return; |
- |
- if (tab_switch_paint_time_.is_null()) |
- tab_switch_paint_time_ = TimeTicks::Now(); |
- is_hidden_ = false; |
- EnsureTooltip(); |
- render_widget_host_->WasRestored(); |
-} |
- |
-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. |
- render_widget_host_->WasHidden(); |
- |
- // TODO(darin): what about constrained windows? it doesn't look like they |
- // see a message when their parent is hidden. maybe there is something more |
- // generic we can do at the TabContents API level instead of relying on |
- // Windows messages. |
-} |
- |
-void RenderWidgetHostViewWin::SetSize(const gfx::Size& size) { |
- SetBounds(gfx::Rect(GetViewBounds().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(); |
- EnsureTooltip(); |
-} |
- |
-gfx::NativeView RenderWidgetHostViewWin::GetNativeView() const { |
- return m_hWnd; |
-} |
- |
-gfx::NativeViewId RenderWidgetHostViewWin::GetNativeViewId() const { |
- return reinterpret_cast<gfx::NativeViewId>(m_hWnd); |
-} |
- |
-void RenderWidgetHostViewWin::MovePluginWindows( |
- const std::vector<WebPluginGeometry>& plugin_window_moves) { |
- if (plugin_window_moves.empty()) |
- return; |
- |
- bool oop_plugins = |
- !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) && |
- !CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessPlugins); |
- |
- HDWP defer_window_pos_info = |
- ::BeginDeferWindowPos(static_cast<int>(plugin_window_moves.size())); |
- |
- if (!defer_window_pos_info) { |
- NOTREACHED(); |
- return; |
- } |
- |
- for (size_t i = 0; i < plugin_window_moves.size(); ++i) { |
- unsigned long flags = 0; |
- const WebPluginGeometry& move = plugin_window_moves[i]; |
- HWND window = move.window; |
- |
- // As the plugin parent window which lives on the browser UI thread is |
- // destroyed asynchronously, it is possible that we have a stale window |
- // sent in by the renderer for moving around. |
- // Note: get the parent before checking if the window is valid, to avoid a |
- // race condition where the window is destroyed after the check but before |
- // the GetParent call. |
- HWND parent = ::GetParent(window); |
- if (!::IsWindow(window)) |
- continue; |
- |
- if (oop_plugins) { |
- if (parent == m_hWnd) { |
- // The plugin window is a direct child of this window, add an |
- // intermediate window that lives on this thread to speed up scrolling. |
- // Note this only works with out of process plugins since we depend on |
- // PluginProcessHost to destroy the intermediate HWNDs. |
- parent = ReparentWindow(window); |
- ::ShowWindow(window, SW_SHOW); // Window was created hidden. |
- } else if (::GetParent(parent) != m_hWnd) { |
- // The renderer should only be trying to move windows that are children |
- // of its render widget window. However, this may happen as a result of |
- // a race condition, so we ignore it and not kill the plugin process. |
- continue; |
- } |
- |
- // We move the intermediate parent window which doesn't result in cross- |
- // process synchronous Windows messages. |
- window = parent; |
- } |
- |
- if (move.visible) |
- flags |= SWP_SHOWWINDOW; |
- else |
- flags |= SWP_HIDEWINDOW; |
- |
- if (move.rects_valid) { |
- HRGN hrgn = ::CreateRectRgn(move.clip_rect.x(), |
- move.clip_rect.y(), |
- move.clip_rect.right(), |
- move.clip_rect.bottom()); |
- gfx::SubtractRectanglesFromRegion(hrgn, move.cutout_rects); |
- |
- // Note: System will own the hrgn after we call SetWindowRgn, |
- // so we don't need to call DeleteObject(hrgn) |
- ::SetWindowRgn(window, hrgn, !move.clip_rect.IsEmpty()); |
- } else { |
- flags |= SWP_NOMOVE; |
- flags |= SWP_NOSIZE; |
- } |
- |
- defer_window_pos_info = ::DeferWindowPos(defer_window_pos_info, |
- window, NULL, |
- move.window_rect.x(), |
- move.window_rect.y(), |
- move.window_rect.width(), |
- move.window_rect.height(), flags); |
- if (!defer_window_pos_info) { |
- DCHECK(false) << "DeferWindowPos failed, so all plugin moves ignored."; |
- return; |
- } |
- } |
- |
- ::EndDeferWindowPos(defer_window_pos_info); |
-} |
- |
-HWND RenderWidgetHostViewWin::ReparentWindow(HWND window) { |
- static ATOM window_class = 0; |
- if (!window_class) { |
- WNDCLASSEX wcex; |
- wcex.cbSize = sizeof(WNDCLASSEX); |
- wcex.style = CS_DBLCLKS; |
- wcex.lpfnWndProc = base::win::WrappedWindowProc<PluginWrapperWindowProc>; |
- wcex.cbClsExtra = 0; |
- wcex.cbWndExtra = 0; |
- wcex.hInstance = GetModuleHandle(NULL); |
- wcex.hIcon = 0; |
- wcex.hCursor = 0; |
- wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1); |
- wcex.lpszMenuName = 0; |
- wcex.lpszClassName = webkit::npapi::kWrapperNativeWindowClassName; |
- wcex.hIconSm = 0; |
- window_class = RegisterClassEx(&wcex); |
- } |
- DCHECK(window_class); |
- |
- HWND orig_parent = ::GetParent(window); |
- HWND parent = CreateWindowEx( |
- WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, |
- MAKEINTATOM(window_class), 0, |
- WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, |
- 0, 0, 0, 0, orig_parent, 0, GetModuleHandle(NULL), 0); |
- ui::CheckWindowCreated(parent); |
- // If UIPI is enabled we need to add message filters for parents with |
- // children that cross process boundaries. |
- if (::GetPropW(orig_parent, webkit::npapi::kNativeWindowClassFilterProp)) { |
- // Process-wide message filters required on Vista must be added to: |
- // chrome_content_client.cc ChromeContentClient::SandboxPlugin |
- if (!g_ChangeWindowMessageFilterEx) { |
- g_ChangeWindowMessageFilterEx = |
- reinterpret_cast<ChangeWindowMessageFilterExFunction>( |
- ::GetProcAddress(::GetModuleHandle(L"user32.dll"), |
- "ChangeWindowMessageFilterEx")); |
- } |
- // Process-wide message filters required on Vista must be added to: |
- // chrome_content_client.cc ChromeContentClient::SandboxPlugin |
- g_ChangeWindowMessageFilterEx(parent, WM_MOUSEWHEEL, MSGFLT_ALLOW, NULL); |
- g_ChangeWindowMessageFilterEx(parent, WM_GESTURE, MSGFLT_ALLOW, NULL); |
- ::SetPropW(orig_parent, webkit::npapi::kNativeWindowClassFilterProp, NULL); |
- } |
- ::SetParent(window, parent); |
- BrowserThread::PostTask( |
- BrowserThread::IO, FROM_HERE, |
- new NotifyPluginProcessHostTask(window, parent)); |
- return parent; |
-} |
- |
-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, |
- NewRunnableFunction(::DestroyWindow, compositor_host_window_), |
- 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() { |
- views::Widget* widget = views::Widget::GetTopLevelWidgetForNativeView(m_hWnd); |
- if (widget) { |
- views::FocusManager* focus_manager = widget->GetFocusManager(); |
- // We don't have a FocusManager if we are hidden. |
- if (focus_manager) |
- focus_manager->ClearFocus(); |
- } |
-} |
- |
-bool RenderWidgetHostViewWin::HasFocus() { |
- return ::GetFocus() == m_hWnd; |
-} |
- |
-void RenderWidgetHostViewWin::Show() { |
- if (!is_fullscreen_) { |
- DCHECK(parent_hwnd_); |
- DCHECK(parent_hwnd_ != GetDesktopWindow()); |
- SetParent(parent_hwnd_); |
- } |
- ShowWindow(SW_SHOW); |
- |
- DidBecomeSelected(); |
-} |
- |
-void RenderWidgetHostViewWin::Hide() { |
- if (!is_fullscreen_ && GetParent() == GetDesktopWindow()) { |
- LOG(WARNING) << "Hide() called twice in a row: " << this << ":" << |
- parent_hwnd_ << ":" << GetParent(); |
- return; |
- } |
- |
- if (::GetFocus() == m_hWnd) |
- ::SetFocus(NULL); |
- ShowWindow(SW_HIDE); |
- |
- if (!is_fullscreen_) { |
- // Cache the old parent, then orphan the window so we stop receiving |
- // messages. |
- parent_hwnd_ = GetParent(); |
- SetParent(NULL); |
- } |
- |
- WasHidden(); |
-} |
- |
-bool RenderWidgetHostViewWin::IsShowing() { |
- return !!IsWindowVisible(); |
-} |
- |
-gfx::Rect RenderWidgetHostViewWin::GetViewBounds() 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( |
- content::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) { |
- BOOL result = ::ScreenToClient(m_hWnd, &pt); |
- DCHECK(result); |
- // 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::ImeUpdateTextInputState( |
- ui::TextInputType type, |
- bool can_compose_inline, |
- const gfx::Rect& caret_rect) { |
- // TODO(kinaba): currently, can_compose_inline is ignored and always treated |
- // as true. We need to support "can_compose_inline=false" for PPAPI plugins |
- // that may want to avoid drawing composition-text by themselves and pass |
- // the responsibility to the browser. |
- bool is_enabled = (type != ui::TEXT_INPUT_TYPE_NONE && |
- type != ui::TEXT_INPUT_TYPE_PASSWORD); |
- if (text_input_type_ != type) { |
- text_input_type_ = type; |
- if (is_enabled) |
- ime_input_.EnableIME(m_hWnd); |
- else |
- ime_input_.DisableIME(m_hWnd); |
- } |
- |
- // Only update caret position if the input method is enabled. |
- if (is_enabled) |
- ime_input_.UpdateCaretRect(m_hWnd, caret_rect); |
-} |
- |
-void RenderWidgetHostViewWin::ImeCancelComposition() { |
- ime_input_.CancelIME(m_hWnd); |
-} |
- |
-BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lparam) { |
- if (!webkit::npapi::WebPluginDelegateImpl::IsPluginDelegateWindow(hwnd)) |
- return TRUE; |
- |
- gfx::Rect* rect = reinterpret_cast<gfx::Rect*>(lparam); |
- static UINT msg = RegisterWindowMessage(webkit::npapi::kPaintMessageName); |
- WPARAM wparam = rect->x() << 16 | rect->y(); |
- lparam = rect->width() << 16 | rect->height(); |
- |
- // SendMessage gets the message across much quicker than PostMessage, since it |
- // doesn't get queued. When the plugin thread calls PeekMessage or other |
- // Win32 APIs, sent messages are dispatched automatically. |
- SendNotifyMessage(hwnd, msg, wparam, lparam); |
- |
- return TRUE; |
-} |
- |
-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 screen_rect = GetViewBounds(); |
- gfx::Rect invalid_screen_rect(damage_bounds); |
- invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y()); |
- |
- LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect); |
- EnumChildWindows(m_hWnd, EnumChildProc, lparam); |
-} |
- |
-void RenderWidgetHostViewWin::DidUpdateBackingStore( |
- const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, |
- 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) |
- InvalidateRect(©_rects[i].ToRECT(), false); |
- |
- if (!scroll_rect.IsEmpty()) { |
- RECT clip_rect = scroll_rect.ToRECT(); |
- ScrollWindowEx(scroll_dx, scroll_dy, NULL, &clip_rect, NULL, NULL, |
- SW_INVALIDATE); |
- } |
- |
- if (!about_to_validate_and_paint_) |
- Redraw(); |
-} |
- |
-void RenderWidgetHostViewWin::RenderViewGone(base::TerminationStatus status, |
- int error_code) { |
- // TODO(darin): keep this around, and draw sad-tab into it. |
- UpdateCursorIfOverSelf(); |
- being_destroyed_ = true; |
- CleanupCompositorWindow(); |
- DestroyWindow(); |
-} |
- |
-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(); |
- DestroyWindow(); |
-} |
- |
-void RenderWidgetHostViewWin::SetTooltipText(const std::wstring& tooltip_text) { |
- // 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 std::wstring& 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::SetBackground(const SkBitmap& background) { |
- RenderWidgetHostView::SetBackground(background); |
- Send(new ViewMsg_SetBackground(render_widget_host_->routing_id(), |
- background)); |
-} |
- |
-void RenderWidgetHostViewWin::SetVisuallyDeemphasized(const SkColor* color, |
- bool animate) { |
- // |animate| is not yet implemented, and currently isn't used. |
- CHECK(!animate); |
- |
- SkColor overlay_color = color ? *color : 0; |
- if (overlay_color_ == overlay_color) |
- return; |
- overlay_color_ = overlay_color; |
- |
- InvalidateRect(NULL, FALSE); |
-} |
- |
-void RenderWidgetHostViewWin::UnhandledWheelEvent( |
- const WebKit::WebMouseWheelEvent& event) { |
-} |
- |
-void RenderWidgetHostViewWin::SetHasHorizontalScrollbar( |
- bool has_horizontal_scrollbar) { |
-} |
- |
-void RenderWidgetHostViewWin::SetScrollOffsetPinning( |
- bool is_pinned_to_left, bool is_pinned_to_right) { |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// RenderWidgetHostViewWin, private: |
- |
-LRESULT RenderWidgetHostViewWin::OnCreate(CREATESTRUCT* create_struct) { |
- // 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(views::SetWindowSupportsRerouteMouseWheel(m_hWnd)); |
- props_.push_back(new ViewProp(m_hWnd, kRenderWidgetHostViewKey, |
- static_cast<RenderWidgetHostView*>(this))); |
- |
- return 0; |
-} |
- |
-void RenderWidgetHostViewWin::OnActivate(UINT action, BOOL minimized, |
- HWND window) { |
- // 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() { |
- // When a tab is closed all its child plugin windows are destroyed |
- // automatically. This happens before plugins get any notification that its |
- // instances are tearing down. |
- // |
- // Plugins like Quicktime assume that their windows will remain valid as long |
- // as they have plugin instances active. Quicktime crashes in this case |
- // because its windowing code cleans up an internal data structure that the |
- // handler for NPP_DestroyStream relies on. |
- // |
- // The fix is to detach plugin windows from web contents when it is going |
- // away. This will prevent the plugin windows from getting destroyed |
- // automatically. The detached plugin windows will get cleaned up in proper |
- // sequence as part of the usual cleanup when the plugin instance goes away. |
- EnumChildWindows(m_hWnd, DetachPluginWindowsCallback, NULL); |
- |
- props_.reset(); |
- |
- CleanupCompositorWindow(); |
- |
- ResetTooltip(); |
- TrackMouseLeave(false); |
-} |
- |
-void RenderWidgetHostViewWin::OnPaint(HDC unused_dc) { |
- if (!render_widget_host_) |
- return; |
- |
- DCHECK(render_widget_host_->process()->HasConnection()); |
- |
- // If the GPU process is rendering directly into the View, compositing is |
- // already triggered by damage to compositor_host_window_, so all we need to |
- // do here is clear borders during resize. |
- if (render_widget_host_->is_accelerated_compositing_active()) { |
- // We initialize paint_dc here so that BeginPaint()/EndPaint() |
- // get called to validate the region. |
- CPaintDC paint_dc(m_hWnd); |
- 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; |
- } |
- |
- 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; |
- |
- // 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); |
- |
- if (hide_compositor_window_at_next_paint_) { |
- ::ShowWindow(compositor_host_window_, SW_HIDE); |
- hide_compositor_window_at_next_paint_ = false; |
- } |
- |
- CPaintDC paint_dc(m_hWnd); |
- |
- gfx::Rect damaged_rect(paint_dc.m_ps.rcPaint); |
- if (damaged_rect.IsEmpty()) |
- return; |
- |
- if (backing_store) { |
- gfx::Rect bitmap_rect(gfx::Point(), 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(new char[data_size]); |
- RGNDATA* region_data = reinterpret_cast<RGNDATA*>(region_data_buf.get()); |
- GetRegionData(damage_region, data_size, region_data); |
- |
- RECT* region_rects = reinterpret_cast<RECT*>(region_data->Buffer); |
- for (DWORD i = 0; i < region_data->rdh.nCount; ++i) { |
- gfx::Rect paint_rect = bitmap_rect.Intersect(gfx::Rect(region_rects[i])); |
- if (!paint_rect.IsEmpty()) { |
- if (SkColorGetA(overlay_color_) > 0) { |
- DrawDeemphasized(overlay_color_, |
- paint_rect, |
- backing_store->hdc(), |
- paint_dc.m_hDC); |
- } else { |
- 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 (!tab_switch_paint_time_.is_null()) { |
- TimeDelta tab_switch_paint_duration = TimeTicks::Now() - |
- tab_switch_paint_time_; |
- UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", |
- tab_switch_paint_duration); |
- // Reset tab_switch_paint_time_ to 0 so future tab selections are |
- // recorded. |
- tab_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::CanvasSkia canvas(dirty_rect.right - dirty_rect.left, |
- dirty_rect.bottom - dirty_rect.top, |
- true); // opaque |
- canvas.TranslateInt(-dirty_rect.left, -dirty_rect.top); |
- |
- const RECT& dc_rect = dc->m_ps.rcPaint; |
- canvas.TileImageInt(background_, 0, 0, |
- dc_rect.right - dc_rect.left, |
- dc_rect.bottom - dc_rect.top); |
- |
- skia::DrawToNativeContext(&canvas, *dc, dirty_rect.left, dirty_rect.top, |
- NULL); |
- } else { |
- HBRUSH white_brush = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); |
- dc->FillRect(&dirty_rect, white_brush); |
- } |
-} |
- |
-void RenderWidgetHostViewWin::OnNCPaint(HRGN update_region) { |
- // Do nothing. This suppresses the resize corner that Windows would |
- // otherwise draw for us. |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnEraseBkgnd(HDC dc) { |
- return 1; |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnSetCursor(HWND window, UINT hittest_code, |
- UINT mouse_message_id) { |
- UpdateCursorIfOverSelf(); |
- return 0; |
-} |
- |
-void RenderWidgetHostViewWin::OnSetFocus(HWND window) { |
- views::FocusManager::GetWidgetFocusManager()->OnWidgetFocusEvent(window, |
- m_hWnd); |
- if (browser_accessibility_manager_.get()) |
- browser_accessibility_manager_->GotFocus(); |
- if (render_widget_host_) |
- render_widget_host_->GotFocus(); |
-} |
- |
-void RenderWidgetHostViewWin::OnKillFocus(HWND window) { |
- views::FocusManager::GetWidgetFocusManager()->OnWidgetFocusEvent(m_hWnd, |
- window); |
- |
- if (render_widget_host_) |
- render_widget_host_->Blur(); |
-} |
- |
-void RenderWidgetHostViewWin::OnCaptureChanged(HWND window) { |
- if (render_widget_host_) |
- render_widget_host_->LostCapture(); |
-} |
- |
-void RenderWidgetHostViewWin::OnCancelMode() { |
- if (render_widget_host_) |
- render_widget_host_->LostCapture(); |
- |
- if ((is_fullscreen_ || close_on_deactivate_) && |
- shutdown_factory_.empty()) { |
- // 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, |
- shutdown_factory_.NewRunnableMethod( |
- &RenderWidgetHostViewWin::ShutdownHost)); |
- } |
-} |
- |
-void RenderWidgetHostViewWin::OnInputLangChange(DWORD character_set, |
- HKL input_language_id) { |
- // 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; |
- } |
- } |
-} |
- |
-void RenderWidgetHostViewWin::OnThemeChanged() { |
- if (!render_widget_host_) |
- return; |
- render_widget_host_->Send(new ViewMsg_ThemeChanged( |
- render_widget_host_->routing_id())); |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnNotify(int w_param, NMHDR* header) { |
- 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_t*>(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_showing_ = true; |
- SetMsgHandled(TRUE); |
- break; |
- } |
- return 0; |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnImeSetContext( |
- UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { |
- 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) { |
- if (!render_widget_host_) |
- return 0; |
- |
- // Reset the composition status and create IME windows. |
- ime_input_.CreateImeWindow(m_hWnd); |
- ime_input_.ResetComposition(m_hWnd); |
- // We have to prevent WTL from calling ::DefWindowProc() because the function |
- // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to |
- // over-write the position of IME windows. |
- handled = TRUE; |
- return 0; |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnImeComposition( |
- UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { |
- 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; |
- return 0; |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnImeEndComposition( |
- UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { |
- 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::OnMouseEvent(UINT message, WPARAM wparam, |
- LPARAM lparam, BOOL& handled) { |
- handled = TRUE; |
- |
- 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 |
- // TabContents first in the case of popups. If we do, we would need to |
- // convert the click from the popup window coordinates to the TabContents' |
- // 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 TabContents 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. |
- ime_input_.CleanupComposition(m_hWnd); |
- // Fall through. |
- case WM_MOUSEMOVE: |
- case WM_MOUSELEAVE: { |
- // Give the TabContents 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) |
- return 1; |
- } |
- } |
- } |
- |
- ForwardMouseEventToRenderer(message, wparam, lparam); |
- return 0; |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnKeyEvent(UINT message, WPARAM wparam, |
- LPARAM lparam, BOOL& handled) { |
- handled = TRUE; |
- |
- // Force fullscreen windows to close on Escape. |
- if (is_fullscreen_ && (message == WM_KEYDOWN || message == WM_KEYUP) && |
- wparam == VK_ESCAPE) { |
- 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'))) { |
- DCHECK(parent_hwnd_); |
- // First close the pop-up. |
- SendMessage(WM_CANCELMODE); |
- // Then move the focus by forwarding the tab key to the parent. |
- return ::SendMessage(parent_hwnd_, 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) { |
- render_widget_host_->ForwardKeyboardEvent( |
- NativeWebKeyboardEvent(m_hWnd, message, wparam, lparam)); |
- } |
- return 0; |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnWheelEvent(UINT message, WPARAM wparam, |
- LPARAM lparam, BOOL& handled) { |
- // Forward the mouse-wheel message to the window under the mouse if it belongs |
- // to us. |
- if (message == WM_MOUSEWHEEL && |
- views::RerouteMouseWheel(m_hWnd, wparam, lparam)) { |
- handled = TRUE; |
- return 0; |
- } |
- |
- // Workaround for Thinkpad mousewheel driver. 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)); |
- } |
- |
- // This is a bit of a hack, but will work for now since we don't want to |
- // pollute this object with TabContents-specific functionality... |
- bool handled_by_TabContents = false; |
- if (!is_fullscreen_ && GetParent()) { |
- // Use a special reflected message to break recursion. If we send |
- // WM_MOUSEWHEEL, the focus manager subclass of web contents will |
- // route it back here. |
- MSG new_message = {0}; |
- new_message.hwnd = m_hWnd; |
- new_message.message = message; |
- new_message.wParam = wparam; |
- new_message.lParam = lparam; |
- |
- handled_by_TabContents = |
- !!::SendMessage(GetParent(), views::kReflectedMessage, 0, |
- reinterpret_cast<LPARAM>(&new_message)); |
- } |
- |
- if (!handled_by_TabContents && render_widget_host_) { |
- render_widget_host_->ForwardWheelEvent( |
- WebInputEventFactory::mouseWheelEvent(m_hWnd, message, wparam, |
- lparam)); |
- } |
- handled = TRUE; |
- return 0; |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnMouseActivate(UINT message, |
- WPARAM wparam, |
- LPARAM lparam, |
- BOOL& handled) { |
- 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_->OnMouseActivate(); |
- return MA_ACTIVATE; |
-} |
- |
-void RenderWidgetHostViewWin::OnAccessibilityNotifications( |
- const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) { |
- if (!browser_accessibility_manager_.get()) { |
- browser_accessibility_manager_.reset( |
- BrowserAccessibilityManager::CreateEmptyDocument( |
- m_hWnd, static_cast<WebAccessibility::State>(0), this)); |
- } |
- browser_accessibility_manager_->OnAccessibilityNotifications(params); |
-} |
- |
-void RenderWidgetHostViewWin::Observe(int type, |
- const NotificationSource& source, |
- const NotificationDetails& details) { |
- DCHECK(type == content::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_->process()) |
- 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. |
- browser_accessibility_manager_.reset(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->ScheduleComposite(); |
- |
- 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::ScheduleComposite() { |
- if (render_widget_host_) |
- render_widget_host_->ScheduleComposite(); |
-} |
- |
-// 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::PluginWindowHandle RenderWidgetHostViewWin::GetCompositingSurface() { |
- // If the window has been created, don't recreate it a second time |
- if (compositor_host_window_) |
- return compositor_host_window_; |
- |
- static ATOM window_class = 0; |
- if (!window_class) { |
- WNDCLASSEX wcex; |
- wcex.cbSize = sizeof(WNDCLASSEX); |
- wcex.style = 0; |
- wcex.lpfnWndProc = |
- base::win::WrappedWindowProc<CompositorHostWindowProc>; |
- wcex.cbClsExtra = 0; |
- wcex.cbWndExtra = 0; |
- wcex.hInstance = GetModuleHandle(NULL); |
- wcex.hIcon = 0; |
- wcex.hCursor = 0; |
- wcex.hbrBackground = NULL; |
- wcex.lpszMenuName = 0; |
- wcex.lpszClassName = L"CompositorHostWindowClass"; |
- wcex.hIconSm = 0; |
- window_class = RegisterClassEx(&wcex); |
- DCHECK(window_class); |
- } |
- |
- 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(window_class), 0, |
- WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED, |
- 0, 0, width, height, m_hWnd, 0, GetModuleHandle(NULL), 0); |
- ui::CheckWindowCreated(compositor_host_window_); |
- |
- ui::SetWindowUserData(compositor_host_window_, this); |
- |
- return static_cast<gfx::PluginWindowHandle>(compositor_host_window_); |
-} |
- |
-void RenderWidgetHostViewWin::ShowCompositorHostWindow(bool show) { |
- // 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 { |
- hide_compositor_window_at_next_paint_ = true; |
- } |
-} |
- |
-void RenderWidgetHostViewWin::SetAccessibilityFocus(int acc_obj_id) { |
- if (!render_widget_host_) |
- return; |
- |
- render_widget_host_->Send(new ViewMsg_SetAccessibilityFocus( |
- render_widget_host_->routing_id(), acc_obj_id)); |
-} |
- |
-void RenderWidgetHostViewWin::AccessibilityDoDefaultAction(int acc_obj_id) { |
- if (!render_widget_host_) |
- return; |
- |
- render_widget_host_->Send(new ViewMsg_AccessibilityDoDefaultAction( |
- render_widget_host_->routing_id(), acc_obj_id)); |
-} |
- |
-IAccessible* RenderWidgetHostViewWin::GetIAccessible() { |
- if (render_widget_host_ && !render_widget_host_->renderer_accessible()) { |
- // Attempt to detect screen readers by sending an event with our custom id. |
- NotifyWinEvent(EVENT_SYSTEM_ALERT, m_hWnd, kIdCustom, CHILDID_SELF); |
- } |
- |
- if (!browser_accessibility_manager_.get()) { |
- // Return busy document tree while renderer accessibility tree loads. |
- WebAccessibility::State busy_state = |
- static_cast<WebAccessibility::State>(1 << WebAccessibility::STATE_BUSY); |
- browser_accessibility_manager_.reset( |
- BrowserAccessibilityManager::CreateEmptyDocument( |
- m_hWnd, busy_state, this)); |
- } |
- |
- return browser_accessibility_manager_->GetRoot()->toBrowserAccessibilityWin(); |
-} |
- |
-LRESULT RenderWidgetHostViewWin::OnGetObject(UINT message, WPARAM wparam, |
- LPARAM lparam, BOOL& handled) { |
- 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_->EnableRendererAccessibility(); |
- |
- // Return with failure. |
- return static_cast<LRESULT>(0L); |
- } |
- |
- if (lparam != OBJID_CLIENT) { |
- handled = false; |
- return static_cast<LRESULT>(0L); |
- } |
- |
- IAccessible* iaccessible = GetIAccessible(); |
- 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) { |
- 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) { |
- // 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; |
-} |
- |
-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; |
- 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; |
-} |
- |
-void RenderWidgetHostViewWin::ForwardMouseEventToRenderer(UINT message, |
- WPARAM wparam, |
- LPARAM lparam) { |
- if (!render_widget_host_) |
- return; |
- |
- WebMouseEvent event( |
- WebInputEventFactory::mouseEvent(m_hWnd, message, wparam, lparam)); |
- |
- // 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() { |
- shutdown_factory_.RevokeAll(); |
- 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) { |
- parent_hwnd_ = parent_hwnd; |
- Create(parent_hwnd_, NULL, NULL, WS_POPUP, ex_style); |
- MoveWindow(pos.x(), pos.y(), pos.width(), pos.height(), TRUE); |
- // To show tooltip on popup window.(e.g. title in <select>) |
- // Popups default to showing, which means |DidBecomeSelected()| isn't invoked. |
- // Ensure the tooltip is created otherwise tooltips are never shown. |
- EnsureTooltip(); |
- ShowWindow(IsActivatable() ? SW_SHOW : SW_SHOWNA); |
-} |