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 8a4e0ed3bc16025a8c8c722ff7180b08ac7fd2ae..d3dd8d044042810403ef4b6b09daf0ed6f1532c9 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. |