Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Unified Diff: content/browser/renderer_host/render_widget_host_view_base.cc

Issue 10905122: Initial NPAPI plugin support in Win Aura. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: sync Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/render_widget_host_view_base.cc
===================================================================
--- content/browser/renderer_host/render_widget_host_view_base.cc (revision 156019)
+++ content/browser/renderer_host/render_widget_host_view_base.cc (working copy)
@@ -12,6 +12,21 @@
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
+#if defined(OS_WIN)
+#include "base/command_line.h"
+#include "base/message_loop.h"
+#include "base/win/wrapped_window_proc.h"
+#include "content/browser/plugin_process_host.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_data.h"
+#include "content/public/common/content_switches.h"
+#include "ui/base/win/hwnd_util.h"
+#include "ui/gfx/gdi_util.h"
+#include "webkit/plugins/npapi/plugin_constants_win.h"
+#include "webkit/plugins/npapi/webplugin.h"
+#include "webkit/plugins/npapi/webplugin_delegate_impl.h"
+#endif
+
#if defined(TOOLKIT_GTK)
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
@@ -39,6 +54,260 @@
return FromRWHV(RenderWidgetHostView::CreateViewForWidget(widget));
}
+#if defined(OS_WIN)
+
+namespace {
+
+// |window| is the plugin HWND, created and destroyed in the plugin process.
+// |parent| is the parent HWND, created and destroyed on the browser UI thread.
+void NotifyPluginProcessHostHelper(HWND window, HWND parent, int tries) {
+ // How long to wait between each try.
+ static const int kTryDelayMs = 200;
+
+ DWORD plugin_process_id;
+ bool found_starting_plugin_process = false;
+ GetWindowThreadProcessId(window, &plugin_process_id);
+ for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
+ if (!iter.GetData().handle) {
+ found_starting_plugin_process = true;
+ continue;
+ }
+ if (base::GetProcId(iter.GetData().handle) == plugin_process_id) {
+ iter->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 > 0) {
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&NotifyPluginProcessHostHelper, window, parent, tries - 1),
+ base::TimeDelta::FromMilliseconds(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);
+}
+
+// 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);
+}
+
+// Create an intermediate window between the given HWND and its parent.
+HWND ReparentWindow(HWND window) {
+ static ATOM atom = 0;
+ static HMODULE instance = NULL;
+ if (!atom) {
+ WNDCLASSEX window_class;
+ base::win::InitializeWindowClass(
+ webkit::npapi::kWrapperNativeWindowClassName,
+ &base::win::WrappedWindowProc<PluginWrapperWindowProc>,
+ CS_DBLCLKS,
+ 0,
+ 0,
+ NULL,
+ // xxx reinterpret_cast<HBRUSH>(COLOR_WINDOW+1),
+ reinterpret_cast<HBRUSH>(COLOR_GRAYTEXT+1),
+ NULL,
+ NULL,
+ NULL,
+ &window_class);
+ instance = window_class.hInstance;
+ atom = RegisterClassEx(&window_class);
+ }
+ DCHECK(atom);
+
+ HWND orig_parent = ::GetParent(window);
+ HWND parent = CreateWindowEx(
+ WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
+ MAKEINTATOM(atom), 0,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ 0, 0, 0, 0, orig_parent, 0, instance, 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
+ ChangeWindowMessageFilterEx(parent, WM_MOUSEWHEEL, MSGFLT_ALLOW, NULL);
+ ChangeWindowMessageFilterEx(parent, WM_GESTURE, MSGFLT_ALLOW, NULL);
+ ChangeWindowMessageFilterEx(parent, WM_APPCOMMAND, MSGFLT_ALLOW, NULL);
+ ::RemovePropW(orig_parent, webkit::npapi::kNativeWindowClassFilterProp);
+ }
+ ::SetParent(window, parent);
+ // How many times we try to find a PluginProcessHost whose process matches
+ // the HWND.
+ static const int kMaxTries = 5;
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&NotifyPluginProcessHostHelper, window, parent, kMaxTries));
+ return parent;
+}
+
+BOOL CALLBACK PainEnumChildProc(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;
+}
+
+} // namespace
+
+// static
+void RenderWidgetHostViewBase::MovePluginWindowsHelper(
+ HWND parent,
+ const std::vector<webkit::npapi::WebPluginGeometry>& moves) {
+ if (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>(moves.size()));
+
+ if (!defer_window_pos_info) {
+ NOTREACHED();
+ return;
+ }
+
+ for (size_t i = 0; i < moves.size(); ++i) {
+ unsigned long flags = 0;
+ const webkit::npapi::WebPluginGeometry& move = 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 cur_parent = ::GetParent(window);
+ if (!::IsWindow(window))
+ continue;
+
+ if (oop_plugins) {
+ if (cur_parent == parent) {
+ // 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.
+ cur_parent = ReparentWindow(window);
+ ::ShowWindow(window, SW_SHOW); // Window was created hidden.
+ } else if (::GetParent(cur_parent) != parent) {
+ // 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 = cur_parent;
+ }
+
+ if (move.visible)
+ flags |= SWP_SHOWWINDOW;
+ else
+ flags |= SWP_HIDEWINDOW;
+
+#if defined(USE_AURA)
+ // Without this flag, Windows repaints the parent area uncovered by this
+ // move. However it only looks at the plugin rectangle and ignores the
+ // clipping region. In Aura, the browser chrome could be under the plugin,
+ // and if Windows tries to paint it synchronously inside EndDeferWindowsPos
+ // then it won't have the data and it will flash white. So instead we
+ // manually redraw the plugin.
+ // Why not do this for native Windows? Not sure if there are any performance
+ // issues with this.
+ flags |= SWP_NOREDRAW;
+#endif
+
+ 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);
+
+#if defined(USE_AURA)
+ for (size_t i = 0; i < moves.size(); ++i) {
+ const webkit::npapi::WebPluginGeometry& move = moves[i];
+ RECT r;
+ GetWindowRect(move.window, &r);
+ gfx::Rect gr(r);
+ PainEnumChildProc(move.window, reinterpret_cast<LPARAM>(&gr));
+ }
+#endif
+}
+
+// static
+void RenderWidgetHostViewBase::PaintPluginWindowsHelper(
+ HWND parent, const gfx::Rect& damaged_screen_rect) {
+ LPARAM lparam = reinterpret_cast<LPARAM>(&damaged_screen_rect);
+ EnumChildWindows(parent, PainEnumChildProc, lparam);
+}
+
+#endif // OS_WIN
+
RenderWidgetHostViewBase::RenderWidgetHostViewBase()
: popup_type_(WebKit::WebPopupTypeNone),
mouse_locked_(false),

Powered by Google App Engine
This is Rietveld 408576698