OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/render_widget_host_view_base.h" | 5 #include "content/browser/renderer_host/render_widget_host_view_base.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "content/browser/accessibility/browser_accessibility_manager.h" | 8 #include "content/browser/accessibility/browser_accessibility_manager.h" |
9 #include "content/browser/renderer_host/render_widget_host_impl.h" | 9 #include "content/browser/renderer_host/render_widget_host_impl.h" |
10 #include "content/port/browser/smooth_scroll_gesture.h" | 10 #include "content/port/browser/smooth_scroll_gesture.h" |
11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" | 11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" |
12 #include "ui/gfx/display.h" | 12 #include "ui/gfx/display.h" |
13 #include "ui/gfx/screen.h" | 13 #include "ui/gfx/screen.h" |
14 | 14 |
| 15 #if defined(OS_WIN) |
| 16 #include "base/command_line.h" |
| 17 #include "base/message_loop.h" |
| 18 #include "base/win/wrapped_window_proc.h" |
| 19 #include "content/browser/plugin_process_host.h" |
| 20 #include "content/public/browser/browser_thread.h" |
| 21 #include "content/public/browser/child_process_data.h" |
| 22 #include "content/public/common/content_switches.h" |
| 23 #include "ui/base/win/hwnd_util.h" |
| 24 #include "ui/gfx/gdi_util.h" |
| 25 #include "webkit/plugins/npapi/plugin_constants_win.h" |
| 26 #include "webkit/plugins/npapi/webplugin.h" |
| 27 #include "webkit/plugins/npapi/webplugin_delegate_impl.h" |
| 28 #endif |
| 29 |
15 #if defined(TOOLKIT_GTK) | 30 #if defined(TOOLKIT_GTK) |
16 #include <gdk/gdkx.h> | 31 #include <gdk/gdkx.h> |
17 #include <gtk/gtk.h> | 32 #include <gtk/gtk.h> |
18 | 33 |
19 #include "content/browser/renderer_host/gtk_window_utils.h" | 34 #include "content/browser/renderer_host/gtk_window_utils.h" |
20 #endif | 35 #endif |
21 | 36 |
22 namespace content { | 37 namespace content { |
23 | 38 |
24 // How long a smooth scroll gesture should run when it is a near scroll. | 39 // How long a smooth scroll gesture should run when it is a near scroll. |
25 static const int64 kDurationOfNearScrollGestureMs = 150; | 40 static const int64 kDurationOfNearScrollGestureMs = 150; |
26 | 41 |
27 // How long a smooth scroll gesture should run when it is a far scroll. | 42 // How long a smooth scroll gesture should run when it is a far scroll. |
28 static const int64 kDurationOfFarScrollGestureMs = 500; | 43 static const int64 kDurationOfFarScrollGestureMs = 500; |
29 | 44 |
30 // static | 45 // static |
31 RenderWidgetHostViewPort* RenderWidgetHostViewPort::FromRWHV( | 46 RenderWidgetHostViewPort* RenderWidgetHostViewPort::FromRWHV( |
32 RenderWidgetHostView* rwhv) { | 47 RenderWidgetHostView* rwhv) { |
33 return static_cast<RenderWidgetHostViewPort*>(rwhv); | 48 return static_cast<RenderWidgetHostViewPort*>(rwhv); |
34 } | 49 } |
35 | 50 |
36 // static | 51 // static |
37 RenderWidgetHostViewPort* RenderWidgetHostViewPort::CreateViewForWidget( | 52 RenderWidgetHostViewPort* RenderWidgetHostViewPort::CreateViewForWidget( |
38 content::RenderWidgetHost* widget) { | 53 content::RenderWidgetHost* widget) { |
39 return FromRWHV(RenderWidgetHostView::CreateViewForWidget(widget)); | 54 return FromRWHV(RenderWidgetHostView::CreateViewForWidget(widget)); |
40 } | 55 } |
41 | 56 |
| 57 #if defined(OS_WIN) |
| 58 |
| 59 namespace { |
| 60 |
| 61 // |window| is the plugin HWND, created and destroyed in the plugin process. |
| 62 // |parent| is the parent HWND, created and destroyed on the browser UI thread. |
| 63 void NotifyPluginProcessHostHelper(HWND window, HWND parent, int tries) { |
| 64 // How long to wait between each try. |
| 65 static const int kTryDelayMs = 200; |
| 66 |
| 67 DWORD plugin_process_id; |
| 68 bool found_starting_plugin_process = false; |
| 69 GetWindowThreadProcessId(window, &plugin_process_id); |
| 70 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) { |
| 71 if (!iter.GetData().handle) { |
| 72 found_starting_plugin_process = true; |
| 73 continue; |
| 74 } |
| 75 if (base::GetProcId(iter.GetData().handle) == plugin_process_id) { |
| 76 iter->AddWindow(parent); |
| 77 return; |
| 78 } |
| 79 } |
| 80 |
| 81 if (found_starting_plugin_process) { |
| 82 // A plugin process has started but we don't have its handle yet. Since |
| 83 // it's most likely the one for this plugin, try a few more times after a |
| 84 // delay. |
| 85 if (tries > 0) { |
| 86 MessageLoop::current()->PostDelayedTask( |
| 87 FROM_HERE, |
| 88 base::Bind(&NotifyPluginProcessHostHelper, window, parent, tries - 1), |
| 89 base::TimeDelta::FromMilliseconds(kTryDelayMs)); |
| 90 return; |
| 91 } |
| 92 } |
| 93 |
| 94 // The plugin process might have died in the time to execute the task, don't |
| 95 // leak the HWND. |
| 96 PostMessage(parent, WM_CLOSE, 0, 0); |
| 97 } |
| 98 |
| 99 // The plugin wrapper window which lives in the browser process has this proc |
| 100 // as its window procedure. We only handle the WM_PARENTNOTIFY message sent by |
| 101 // windowed plugins for mouse input. This is forwarded off to the wrappers |
| 102 // parent which is typically the RVH window which turns on user gesture. |
| 103 LRESULT CALLBACK PluginWrapperWindowProc(HWND window, unsigned int message, |
| 104 WPARAM wparam, LPARAM lparam) { |
| 105 if (message == WM_PARENTNOTIFY) { |
| 106 switch (LOWORD(wparam)) { |
| 107 case WM_LBUTTONDOWN: |
| 108 case WM_RBUTTONDOWN: |
| 109 case WM_MBUTTONDOWN: |
| 110 ::SendMessage(GetParent(window), message, wparam, lparam); |
| 111 return 0; |
| 112 default: |
| 113 break; |
| 114 } |
| 115 } |
| 116 return ::DefWindowProc(window, message, wparam, lparam); |
| 117 } |
| 118 |
| 119 // Create an intermediate window between the given HWND and its parent. |
| 120 HWND ReparentWindow(HWND window) { |
| 121 static ATOM atom = 0; |
| 122 static HMODULE instance = NULL; |
| 123 if (!atom) { |
| 124 WNDCLASSEX window_class; |
| 125 base::win::InitializeWindowClass( |
| 126 webkit::npapi::kWrapperNativeWindowClassName, |
| 127 &base::win::WrappedWindowProc<PluginWrapperWindowProc>, |
| 128 CS_DBLCLKS, |
| 129 0, |
| 130 0, |
| 131 NULL, |
| 132 // xxx reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), |
| 133 reinterpret_cast<HBRUSH>(COLOR_GRAYTEXT+1), |
| 134 NULL, |
| 135 NULL, |
| 136 NULL, |
| 137 &window_class); |
| 138 instance = window_class.hInstance; |
| 139 atom = RegisterClassEx(&window_class); |
| 140 } |
| 141 DCHECK(atom); |
| 142 |
| 143 HWND orig_parent = ::GetParent(window); |
| 144 HWND parent = CreateWindowEx( |
| 145 WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, |
| 146 MAKEINTATOM(atom), 0, |
| 147 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, |
| 148 0, 0, 0, 0, orig_parent, 0, instance, 0); |
| 149 ui::CheckWindowCreated(parent); |
| 150 // If UIPI is enabled we need to add message filters for parents with |
| 151 // children that cross process boundaries. |
| 152 if (::GetPropW(orig_parent, webkit::npapi::kNativeWindowClassFilterProp)) { |
| 153 // Process-wide message filters required on Vista must be added to: |
| 154 // chrome_content_client.cc ChromeContentClient::SandboxPlugin |
| 155 ChangeWindowMessageFilterEx(parent, WM_MOUSEWHEEL, MSGFLT_ALLOW, NULL); |
| 156 ChangeWindowMessageFilterEx(parent, WM_GESTURE, MSGFLT_ALLOW, NULL); |
| 157 ChangeWindowMessageFilterEx(parent, WM_APPCOMMAND, MSGFLT_ALLOW, NULL); |
| 158 ::RemovePropW(orig_parent, webkit::npapi::kNativeWindowClassFilterProp); |
| 159 } |
| 160 ::SetParent(window, parent); |
| 161 // How many times we try to find a PluginProcessHost whose process matches |
| 162 // the HWND. |
| 163 static const int kMaxTries = 5; |
| 164 BrowserThread::PostTask( |
| 165 BrowserThread::IO, |
| 166 FROM_HERE, |
| 167 base::Bind(&NotifyPluginProcessHostHelper, window, parent, kMaxTries)); |
| 168 return parent; |
| 169 } |
| 170 |
| 171 BOOL CALLBACK PainEnumChildProc(HWND hwnd, LPARAM lparam) { |
| 172 if (!webkit::npapi::WebPluginDelegateImpl::IsPluginDelegateWindow(hwnd)) |
| 173 return TRUE; |
| 174 |
| 175 gfx::Rect* rect = reinterpret_cast<gfx::Rect*>(lparam); |
| 176 static UINT msg = RegisterWindowMessage(webkit::npapi::kPaintMessageName); |
| 177 WPARAM wparam = rect->x() << 16 | rect->y(); |
| 178 lparam = rect->width() << 16 | rect->height(); |
| 179 |
| 180 // SendMessage gets the message across much quicker than PostMessage, since it |
| 181 // doesn't get queued. When the plugin thread calls PeekMessage or other |
| 182 // Win32 APIs, sent messages are dispatched automatically. |
| 183 SendNotifyMessage(hwnd, msg, wparam, lparam); |
| 184 |
| 185 return TRUE; |
| 186 } |
| 187 |
| 188 } // namespace |
| 189 |
| 190 // static |
| 191 void RenderWidgetHostViewBase::MovePluginWindowsHelper( |
| 192 HWND parent, |
| 193 const std::vector<webkit::npapi::WebPluginGeometry>& moves) { |
| 194 if (moves.empty()) |
| 195 return; |
| 196 |
| 197 bool oop_plugins = |
| 198 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) && |
| 199 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessPlugins); |
| 200 |
| 201 HDWP defer_window_pos_info = |
| 202 ::BeginDeferWindowPos(static_cast<int>(moves.size())); |
| 203 |
| 204 if (!defer_window_pos_info) { |
| 205 NOTREACHED(); |
| 206 return; |
| 207 } |
| 208 |
| 209 for (size_t i = 0; i < moves.size(); ++i) { |
| 210 unsigned long flags = 0; |
| 211 const webkit::npapi::WebPluginGeometry& move = moves[i]; |
| 212 HWND window = move.window; |
| 213 |
| 214 // As the plugin parent window which lives on the browser UI thread is |
| 215 // destroyed asynchronously, it is possible that we have a stale window |
| 216 // sent in by the renderer for moving around. |
| 217 // Note: get the parent before checking if the window is valid, to avoid a |
| 218 // race condition where the window is destroyed after the check but before |
| 219 // the GetParent call. |
| 220 HWND cur_parent = ::GetParent(window); |
| 221 if (!::IsWindow(window)) |
| 222 continue; |
| 223 |
| 224 if (oop_plugins) { |
| 225 if (cur_parent == parent) { |
| 226 // The plugin window is a direct child of this window, add an |
| 227 // intermediate window that lives on this thread to speed up scrolling. |
| 228 // Note this only works with out of process plugins since we depend on |
| 229 // PluginProcessHost to destroy the intermediate HWNDs. |
| 230 cur_parent = ReparentWindow(window); |
| 231 ::ShowWindow(window, SW_SHOW); // Window was created hidden. |
| 232 } else if (::GetParent(cur_parent) != parent) { |
| 233 // The renderer should only be trying to move windows that are children |
| 234 // of its render widget window. However, this may happen as a result of |
| 235 // a race condition, so we ignore it and not kill the plugin process. |
| 236 continue; |
| 237 } |
| 238 |
| 239 // We move the intermediate parent window which doesn't result in cross- |
| 240 // process synchronous Windows messages. |
| 241 window = cur_parent; |
| 242 } |
| 243 |
| 244 if (move.visible) |
| 245 flags |= SWP_SHOWWINDOW; |
| 246 else |
| 247 flags |= SWP_HIDEWINDOW; |
| 248 |
| 249 #if defined(USE_AURA) |
| 250 // Without this flag, Windows repaints the parent area uncovered by this |
| 251 // move. However it only looks at the plugin rectangle and ignores the |
| 252 // clipping region. In Aura, the browser chrome could be under the plugin, |
| 253 // and if Windows tries to paint it synchronously inside EndDeferWindowsPos |
| 254 // then it won't have the data and it will flash white. So instead we |
| 255 // manually redraw the plugin. |
| 256 // Why not do this for native Windows? Not sure if there are any performance |
| 257 // issues with this. |
| 258 flags |= SWP_NOREDRAW; |
| 259 #endif |
| 260 |
| 261 if (move.rects_valid) { |
| 262 HRGN hrgn = ::CreateRectRgn(move.clip_rect.x(), |
| 263 move.clip_rect.y(), |
| 264 move.clip_rect.right(), |
| 265 move.clip_rect.bottom()); |
| 266 gfx::SubtractRectanglesFromRegion(hrgn, move.cutout_rects); |
| 267 |
| 268 // Note: System will own the hrgn after we call SetWindowRgn, |
| 269 // so we don't need to call DeleteObject(hrgn) |
| 270 ::SetWindowRgn(window, hrgn, !move.clip_rect.IsEmpty()); |
| 271 } else { |
| 272 flags |= SWP_NOMOVE; |
| 273 flags |= SWP_NOSIZE; |
| 274 } |
| 275 |
| 276 defer_window_pos_info = ::DeferWindowPos(defer_window_pos_info, |
| 277 window, NULL, |
| 278 move.window_rect.x(), |
| 279 move.window_rect.y(), |
| 280 move.window_rect.width(), |
| 281 move.window_rect.height(), flags); |
| 282 |
| 283 if (!defer_window_pos_info) { |
| 284 DCHECK(false) << "DeferWindowPos failed, so all plugin moves ignored."; |
| 285 return; |
| 286 } |
| 287 } |
| 288 |
| 289 ::EndDeferWindowPos(defer_window_pos_info); |
| 290 |
| 291 #if defined(USE_AURA) |
| 292 for (size_t i = 0; i < moves.size(); ++i) { |
| 293 const webkit::npapi::WebPluginGeometry& move = moves[i]; |
| 294 RECT r; |
| 295 GetWindowRect(move.window, &r); |
| 296 gfx::Rect gr(r); |
| 297 PainEnumChildProc(move.window, reinterpret_cast<LPARAM>(&gr)); |
| 298 } |
| 299 #endif |
| 300 } |
| 301 |
| 302 // static |
| 303 void RenderWidgetHostViewBase::PaintPluginWindowsHelper( |
| 304 HWND parent, const gfx::Rect& damaged_screen_rect) { |
| 305 LPARAM lparam = reinterpret_cast<LPARAM>(&damaged_screen_rect); |
| 306 EnumChildWindows(parent, PainEnumChildProc, lparam); |
| 307 } |
| 308 |
| 309 #endif // OS_WIN |
| 310 |
42 RenderWidgetHostViewBase::RenderWidgetHostViewBase() | 311 RenderWidgetHostViewBase::RenderWidgetHostViewBase() |
43 : popup_type_(WebKit::WebPopupTypeNone), | 312 : popup_type_(WebKit::WebPopupTypeNone), |
44 mouse_locked_(false), | 313 mouse_locked_(false), |
45 showing_context_menu_(false), | 314 showing_context_menu_(false), |
46 selection_text_offset_(0), | 315 selection_text_offset_(0), |
47 selection_range_(ui::Range::InvalidRange()), | 316 selection_range_(ui::Range::InvalidRange()), |
48 current_device_scale_factor_(0) { | 317 current_device_scale_factor_(0) { |
49 } | 318 } |
50 | 319 |
51 RenderWidgetHostViewBase::~RenderWidgetHostViewBase() { | 320 RenderWidgetHostViewBase::~RenderWidgetHostViewBase() { |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 bool scroll_down_; | 432 bool scroll_down_; |
164 bool scroll_far_; | 433 bool scroll_far_; |
165 }; | 434 }; |
166 | 435 |
167 SmoothScrollGesture* RenderWidgetHostViewBase::CreateSmoothScrollGesture( | 436 SmoothScrollGesture* RenderWidgetHostViewBase::CreateSmoothScrollGesture( |
168 bool scroll_down, bool scroll_far) { | 437 bool scroll_down, bool scroll_far) { |
169 return new BasicMouseWheelSmoothScrollGesture(scroll_down, scroll_far); | 438 return new BasicMouseWheelSmoothScrollGesture(scroll_down, scroll_far); |
170 } | 439 } |
171 | 440 |
172 } // namespace content | 441 } // namespace content |
OLD | NEW |