// 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. #include "chrome/browser/renderer_host/render_widget_host_view_win.h" #include #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 "chrome/browser/browser_trial.h" #include "chrome/browser/renderer_host/render_widget_host_view_views.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/render_messages.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/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/native_web_keyboard_event.h" #include "content/common/notification_service.h" #include "content/common/plugin_messages.h" #include "content/common/view_messages.h" #include "grit/webkit_resources.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/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 "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(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(*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); } } // namespace // RenderWidgetHostView -------------------------------------------------------- // static RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( RenderWidgetHost* widget) { if (views::Widget::IsPureViews()) return new RenderWidgetHostViewViews(widget); return new RenderWidgetHostViewWin(widget); } /////////////////////////////////////////////////////////////////////////////// // 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) { 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) { parent_hwnd_ = parent_host_view->GetNativeView(); close_on_deactivate_ = true; Create(parent_hwnd_, NULL, NULL, WS_POPUP, WS_EX_TOOLWINDOW); MoveWindow(pos.x(), pos.y(), pos.width(), pos.height(), TRUE); // To show tooltip on popup window.(e.g. title in