| Index: content/browser/renderer_host/render_widget_host_view_base.cc
|
| diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
|
| index 9cdceb518eefad1e7dd47f841d32010a917e8044..bad74a425c9ed8aa55bc172d2906aab7e9f18285 100644
|
| --- a/content/browser/renderer_host/render_widget_host_view_base.cc
|
| +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
|
| @@ -21,346 +21,8 @@
|
| #include "ui/gfx/geometry/size_f.h"
|
| #include "ui/gfx/screen.h"
|
|
|
| -#if defined(OS_WIN)
|
| -#include "base/command_line.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "base/win/wrapped_window_proc.h"
|
| -#include "content/browser/plugin_process_host.h"
|
| -#include "content/browser/plugin_service_impl.h"
|
| -#include "content/common/plugin_constants_win.h"
|
| -#include "content/common/webplugin_geometry.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -#include "content/public/browser/child_process_data.h"
|
| -#include "content/public/common/content_switches.h"
|
| -#include "ui/gfx/gdi_util.h"
|
| -#include "ui/gfx/win/dpi.h"
|
| -#include "ui/gfx/win/hwnd_util.h"
|
| -#endif
|
| -
|
| namespace content {
|
|
|
| -#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) {
|
| - base::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);
|
| -}
|
| -
|
| -bool IsPluginWrapperWindow(HWND window) {
|
| - return gfx::GetClassNameW(window) ==
|
| - base::string16(kWrapperNativeWindowClassName);
|
| -}
|
| -
|
| -// Create an intermediate window between the given HWND and its parent.
|
| -HWND ReparentWindow(HWND window, HWND parent) {
|
| - static ATOM atom = 0;
|
| - static HMODULE instance = NULL;
|
| - if (!atom) {
|
| - WNDCLASSEX window_class;
|
| - base::win::InitializeWindowClass(
|
| - 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 new_parent = CreateWindowEx(
|
| - WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
|
| - MAKEINTATOM(atom), 0,
|
| - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
| - 0, 0, 0, 0, parent, 0, instance, 0);
|
| - gfx::CheckWindowCreated(new_parent);
|
| - ::SetParent(window, new_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, new_parent,
|
| - kMaxTries));
|
| - return new_parent;
|
| -}
|
| -
|
| -BOOL CALLBACK PaintEnumChildProc(HWND hwnd, LPARAM lparam) {
|
| - if (!PluginServiceImpl::GetInstance()->IsPluginWindow(hwnd))
|
| - return TRUE;
|
| -
|
| - gfx::Rect* rect = reinterpret_cast<gfx::Rect*>(lparam);
|
| - gfx::Rect rect_in_pixels = gfx::win::DIPToScreenRect(*rect);
|
| - static UINT msg = RegisterWindowMessage(kPaintMessageName);
|
| - WPARAM wparam = MAKEWPARAM(rect_in_pixels.x(), rect_in_pixels.y());
|
| - lparam = MAKELPARAM(rect_in_pixels.width(), rect_in_pixels.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;
|
| -}
|
| -
|
| -// Windows callback for OnDestroy to detach the plugin windows.
|
| -BOOL CALLBACK DetachPluginWindowsCallbackInternal(HWND window, LPARAM param) {
|
| - RenderWidgetHostViewBase::DetachPluginWindowsCallback(window);
|
| - return TRUE;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// static
|
| -void RenderWidgetHostViewBase::DetachPluginWindowsCallback(HWND window) {
|
| - if (PluginServiceImpl::GetInstance()->IsPluginWindow(window) &&
|
| - !IsHungAppWindow(window)) {
|
| - ::ShowWindow(window, SW_HIDE);
|
| - SetParent(window, NULL);
|
| - }
|
| -}
|
| -
|
| -// static
|
| -void RenderWidgetHostViewBase::MovePluginWindowsHelper(
|
| - HWND parent,
|
| - const std::vector<WebPluginGeometry>& moves) {
|
| - if (moves.empty())
|
| - return;
|
| -
|
| - bool oop_plugins = !base::CommandLine::ForCurrentProcess()->HasSwitch(
|
| - switches::kSingleProcess);
|
| -
|
| - HDWP defer_window_pos_info =
|
| - ::BeginDeferWindowPos(static_cast<int>(moves.size()));
|
| -
|
| - if (!defer_window_pos_info) {
|
| - NOTREACHED();
|
| - return;
|
| - }
|
| -
|
| -#if defined(USE_AURA)
|
| - std::vector<RECT> invalidate_rects;
|
| -#endif
|
| -
|
| - for (size_t i = 0; i < moves.size(); ++i) {
|
| - unsigned long flags = 0;
|
| - const 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 (!PluginServiceImpl::GetInstance()->IsPluginWindow(window)) {
|
| - // The renderer should only be trying to move plugin windows. However,
|
| - // this may happen as a result of a race condition (i.e. even after the
|
| - // check right above), so we ignore it.
|
| - continue;
|
| - }
|
| -
|
| - if (oop_plugins) {
|
| - if (cur_parent == GetDesktopWindow()) {
|
| - // The plugin window hasn't been parented yet, 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, parent);
|
| - ::ShowWindow(window, SW_SHOW); // Window was created hidden.
|
| - } else if (!IsPluginWrapperWindow(cur_parent)) {
|
| - continue; // Race if plugin process is shutting down.
|
| - }
|
| -
|
| - // We move the intermediate parent window which doesn't result in cross-
|
| - // process synchronous Windows messages.
|
| - window = cur_parent;
|
| - } else {
|
| - if (cur_parent == GetDesktopWindow())
|
| - SetParent(window, parent);
|
| - }
|
| -
|
| - if (move.visible)
|
| - flags |= SWP_SHOWWINDOW;
|
| - else
|
| - flags |= SWP_HIDEWINDOW;
|
| -
|
| -#if defined(USE_AURA)
|
| - if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
|
| - // Without this flag, Windows repaints the parent area uncovered by this
|
| - // move. However when software compositing is used the clipping region is
|
| - // ignored. Since in Aura the browser chrome could be under the plugin, if
|
| - // 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) {
|
| - gfx::Rect clip_rect_in_pixel = gfx::win::DIPToScreenRect(move.clip_rect);
|
| - HRGN hrgn = ::CreateRectRgn(clip_rect_in_pixel.x(),
|
| - clip_rect_in_pixel.y(),
|
| - clip_rect_in_pixel.right(),
|
| - clip_rect_in_pixel.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() && (flags & SWP_NOREDRAW) == 0);
|
| -
|
| -#if defined(USE_AURA)
|
| - // When using the software compositor, if the clipping rectangle is empty
|
| - // then DeferWindowPos won't redraw the newly uncovered area under the
|
| - // plugin.
|
| - if (clip_rect_in_pixel.IsEmpty() &&
|
| - !GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
|
| - RECT r;
|
| - GetClientRect(window, &r);
|
| - MapWindowPoints(window, parent, reinterpret_cast<POINT*>(&r), 2);
|
| - invalidate_rects.push_back(r);
|
| - }
|
| -#endif
|
| - } else {
|
| - flags |= SWP_NOMOVE;
|
| - flags |= SWP_NOSIZE;
|
| - }
|
| -
|
| - gfx::Rect window_rect_in_pixel =
|
| - gfx::win::DIPToScreenRect(move.window_rect);
|
| - defer_window_pos_info = ::DeferWindowPos(defer_window_pos_info,
|
| - window, NULL,
|
| - window_rect_in_pixel.x(),
|
| - window_rect_in_pixel.y(),
|
| - window_rect_in_pixel.width(),
|
| - window_rect_in_pixel.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)
|
| - if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
|
| - for (size_t i = 0; i < moves.size(); ++i) {
|
| - const WebPluginGeometry& move = moves[i];
|
| - RECT r;
|
| - GetWindowRect(move.window, &r);
|
| - gfx::Rect gr(r);
|
| - PaintEnumChildProc(move.window, reinterpret_cast<LPARAM>(&gr));
|
| - }
|
| - } else {
|
| - for (size_t i = 0; i < invalidate_rects.size(); ++i) {
|
| - ::RedrawWindow(
|
| - parent, &invalidate_rects[i], NULL,
|
| - // These flags are from WebPluginDelegateImpl::NativeWndProc.
|
| - RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME | RDW_UPDATENOW);
|
| - }
|
| - }
|
| -#endif
|
| -}
|
| -
|
| -// static
|
| -void RenderWidgetHostViewBase::PaintPluginWindowsHelper(
|
| - HWND parent, const gfx::Rect& damaged_screen_rect) {
|
| - LPARAM lparam = reinterpret_cast<LPARAM>(&damaged_screen_rect);
|
| - EnumChildWindows(parent, PaintEnumChildProc, lparam);
|
| -}
|
| -
|
| -// static
|
| -void RenderWidgetHostViewBase::DetachPluginsHelper(HWND parent) {
|
| - // 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(parent, DetachPluginWindowsCallbackInternal, NULL);
|
| -}
|
| -
|
| -#endif // OS_WIN
|
| -
|
| namespace {
|
|
|
| // How many microseconds apart input events should be flushed.
|
|
|