| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/web_contents/web_contents_view_win.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/memory/scoped_vector.h" | |
| 9 #include "content/browser/frame_host/interstitial_page_impl.h" | |
| 10 #include "content/browser/renderer_host/render_view_host_factory.h" | |
| 11 #include "content/browser/renderer_host/render_view_host_impl.h" | |
| 12 #include "content/browser/renderer_host/render_widget_host_view_win.h" | |
| 13 #include "content/browser/web_contents/web_contents_drag_win.h" | |
| 14 #include "content/browser/web_contents/web_contents_impl.h" | |
| 15 #include "content/browser/web_contents/web_drag_dest_win.h" | |
| 16 #include "content/public/browser/web_contents_delegate.h" | |
| 17 #include "content/public/browser/web_contents_view_delegate.h" | |
| 18 #include "ui/base/win/hidden_window.h" | |
| 19 #include "ui/base/win/hwnd_subclass.h" | |
| 20 #include "ui/gfx/screen.h" | |
| 21 | |
| 22 namespace content { | |
| 23 WebContentsViewPort* CreateWebContentsView( | |
| 24 WebContentsImpl* web_contents, | |
| 25 WebContentsViewDelegate* delegate, | |
| 26 RenderViewHostDelegateView** render_view_host_delegate_view) { | |
| 27 WebContentsViewWin* rv = new WebContentsViewWin(web_contents, delegate); | |
| 28 *render_view_host_delegate_view = rv; | |
| 29 return rv; | |
| 30 } | |
| 31 | |
| 32 namespace { | |
| 33 | |
| 34 typedef std::map<HWND, WebContentsViewWin*> HwndToWcvMap; | |
| 35 HwndToWcvMap hwnd_to_wcv_map; | |
| 36 | |
| 37 void RemoveHwndToWcvMapEntry(WebContentsViewWin* wcv) { | |
| 38 HwndToWcvMap::iterator it; | |
| 39 for (it = hwnd_to_wcv_map.begin(); it != hwnd_to_wcv_map.end();) { | |
| 40 if (it->second == wcv) | |
| 41 hwnd_to_wcv_map.erase(it++); | |
| 42 else | |
| 43 ++it; | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) { | |
| 48 HwndToWcvMap::iterator it = hwnd_to_wcv_map.find(hwnd); | |
| 49 if (it == hwnd_to_wcv_map.end()) | |
| 50 return TRUE; // must return TRUE to continue enumeration. | |
| 51 WebContentsViewWin* wcv = it->second; | |
| 52 RenderWidgetHostViewWin* rwhv = static_cast<RenderWidgetHostViewWin*>( | |
| 53 wcv->web_contents()->GetRenderWidgetHostView()); | |
| 54 if (rwhv) | |
| 55 rwhv->UpdateScreenInfo(rwhv->GetNativeView()); | |
| 56 | |
| 57 return TRUE; // must return TRUE to continue enumeration. | |
| 58 } | |
| 59 | |
| 60 class PositionChangedMessageFilter : public ui::HWNDMessageFilter { | |
| 61 public: | |
| 62 PositionChangedMessageFilter() {} | |
| 63 | |
| 64 private: | |
| 65 // Overridden from ui::HWNDMessageFilter: | |
| 66 virtual bool FilterMessage(HWND hwnd, | |
| 67 UINT message, | |
| 68 WPARAM w_param, | |
| 69 LPARAM l_param, | |
| 70 LRESULT* l_result) OVERRIDE { | |
| 71 if (message == WM_WINDOWPOSCHANGED || message == WM_SETTINGCHANGE) | |
| 72 EnumChildWindows(hwnd, EnumChildProc, 0); | |
| 73 | |
| 74 return false; | |
| 75 } | |
| 76 | |
| 77 DISALLOW_COPY_AND_ASSIGN(PositionChangedMessageFilter); | |
| 78 }; | |
| 79 | |
| 80 void AddFilterToParentHwndSubclass(HWND hwnd, ui::HWNDMessageFilter* filter) { | |
| 81 HWND parent = ::GetAncestor(hwnd, GA_ROOT); | |
| 82 if (parent) { | |
| 83 ui::HWNDSubclass::RemoveFilterFromAllTargets(filter); | |
| 84 ui::HWNDSubclass::AddFilterToTarget(parent, filter); | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 } // namespace namespace | |
| 89 | |
| 90 WebContentsViewWin::WebContentsViewWin(WebContentsImpl* web_contents, | |
| 91 WebContentsViewDelegate* delegate) | |
| 92 : web_contents_(web_contents), | |
| 93 delegate_(delegate), | |
| 94 hwnd_message_filter_(new PositionChangedMessageFilter) { | |
| 95 } | |
| 96 | |
| 97 WebContentsViewWin::~WebContentsViewWin() { | |
| 98 RemoveHwndToWcvMapEntry(this); | |
| 99 | |
| 100 if (IsWindow(hwnd())) | |
| 101 DestroyWindow(hwnd()); | |
| 102 } | |
| 103 | |
| 104 gfx::NativeView WebContentsViewWin::GetNativeView() const { | |
| 105 return hwnd(); | |
| 106 } | |
| 107 | |
| 108 gfx::NativeView WebContentsViewWin::GetContentNativeView() const { | |
| 109 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); | |
| 110 return rwhv ? rwhv->GetNativeView() : NULL; | |
| 111 } | |
| 112 | |
| 113 gfx::NativeWindow WebContentsViewWin::GetTopLevelNativeWindow() const { | |
| 114 return ::GetAncestor(GetNativeView(), GA_ROOT); | |
| 115 } | |
| 116 | |
| 117 void WebContentsViewWin::GetContainerBounds(gfx::Rect *out) const { | |
| 118 // Copied from NativeWidgetWin::GetClientAreaScreenBounds(). | |
| 119 RECT r; | |
| 120 GetClientRect(hwnd(), &r); | |
| 121 POINT point = { r.left, r.top }; | |
| 122 ClientToScreen(hwnd(), &point); | |
| 123 *out = gfx::Rect(point.x, point.y, r.right - r.left, r.bottom - r.top); | |
| 124 } | |
| 125 | |
| 126 void WebContentsViewWin::OnTabCrashed(base::TerminationStatus status, | |
| 127 int error_code) { | |
| 128 } | |
| 129 | |
| 130 void WebContentsViewWin::SizeContents(const gfx::Size& size) { | |
| 131 gfx::Rect bounds; | |
| 132 GetContainerBounds(&bounds); | |
| 133 if (bounds.size() != size) { | |
| 134 SetWindowPos(hwnd(), NULL, 0, 0, size.width(), size.height(), | |
| 135 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); | |
| 136 } else { | |
| 137 // Our size matches what we want but the renderers size may not match. | |
| 138 // Pretend we were resized so that the renderers size is updated too. | |
| 139 if (web_contents_->GetInterstitialPage()) | |
| 140 web_contents_->GetInterstitialPage()->SetSize(size); | |
| 141 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); | |
| 142 if (rwhv) | |
| 143 rwhv->SetSize(size); | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 void WebContentsViewWin::CreateView( | |
| 148 const gfx::Size& initial_size, gfx::NativeView context) { | |
| 149 initial_size_ = initial_size; | |
| 150 | |
| 151 set_window_style(WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); | |
| 152 | |
| 153 Init(ui::GetHiddenWindow(), gfx::Rect(initial_size_)); | |
| 154 | |
| 155 // Remove the root view drop target so we can register our own. | |
| 156 RevokeDragDrop(GetNativeView()); | |
| 157 drag_dest_ = new WebDragDest(hwnd(), web_contents_); | |
| 158 if (delegate_) { | |
| 159 WebDragDestDelegate* delegate = delegate_->GetDragDestDelegate(); | |
| 160 if (delegate) | |
| 161 drag_dest_->set_delegate(delegate); | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 void WebContentsViewWin::Focus() { | |
| 166 if (web_contents_->GetInterstitialPage()) { | |
| 167 web_contents_->GetInterstitialPage()->Focus(); | |
| 168 return; | |
| 169 } | |
| 170 | |
| 171 if (delegate_.get() && delegate_->Focus()) | |
| 172 return; | |
| 173 | |
| 174 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); | |
| 175 if (rwhv) | |
| 176 rwhv->Focus(); | |
| 177 } | |
| 178 | |
| 179 void WebContentsViewWin::SetInitialFocus() { | |
| 180 if (web_contents_->FocusLocationBarByDefault()) | |
| 181 web_contents_->SetFocusToLocationBar(false); | |
| 182 else | |
| 183 Focus(); | |
| 184 } | |
| 185 | |
| 186 void WebContentsViewWin::StoreFocus() { | |
| 187 if (delegate_) | |
| 188 delegate_->StoreFocus(); | |
| 189 } | |
| 190 | |
| 191 void WebContentsViewWin::RestoreFocus() { | |
| 192 if (delegate_) | |
| 193 delegate_->RestoreFocus(); | |
| 194 } | |
| 195 | |
| 196 DropData* WebContentsViewWin::GetDropData() const { | |
| 197 return drag_dest_->current_drop_data(); | |
| 198 } | |
| 199 | |
| 200 gfx::Rect WebContentsViewWin::GetViewBounds() const { | |
| 201 RECT r; | |
| 202 GetWindowRect(hwnd(), &r); | |
| 203 return gfx::Rect(r); | |
| 204 } | |
| 205 | |
| 206 RenderWidgetHostView* WebContentsViewWin::CreateViewForWidget( | |
| 207 RenderWidgetHost* render_widget_host) { | |
| 208 if (render_widget_host->GetView()) { | |
| 209 // During testing, the view will already be set up in most cases to the | |
| 210 // test view, so we don't want to clobber it with a real one. To verify that | |
| 211 // this actually is happening (and somebody isn't accidentally creating the | |
| 212 // view twice), we check for the RVH Factory, which will be set when we're | |
| 213 // making special ones (which go along with the special views). | |
| 214 DCHECK(RenderViewHostFactory::has_factory()); | |
| 215 return render_widget_host->GetView(); | |
| 216 } | |
| 217 | |
| 218 RenderWidgetHostViewWin* view = static_cast<RenderWidgetHostViewWin*>( | |
| 219 RenderWidgetHostView::CreateViewForWidget(render_widget_host)); | |
| 220 view->CreateWnd(GetNativeView()); | |
| 221 view->ShowWindow(SW_SHOW); | |
| 222 view->SetSize(initial_size_); | |
| 223 return view; | |
| 224 } | |
| 225 | |
| 226 RenderWidgetHostView* WebContentsViewWin::CreateViewForPopupWidget( | |
| 227 RenderWidgetHost* render_widget_host) { | |
| 228 return RenderWidgetHostViewPort::CreateViewForWidget(render_widget_host); | |
| 229 } | |
| 230 | |
| 231 void WebContentsViewWin::SetPageTitle(const base::string16& title) { | |
| 232 // It's possible to get this after the hwnd has been destroyed. | |
| 233 if (GetNativeView()) | |
| 234 ::SetWindowText(GetNativeView(), title.c_str()); | |
| 235 } | |
| 236 | |
| 237 void WebContentsViewWin::RenderViewCreated(RenderViewHost* host) { | |
| 238 } | |
| 239 | |
| 240 void WebContentsViewWin::RenderViewSwappedIn(RenderViewHost* host) { | |
| 241 } | |
| 242 | |
| 243 void WebContentsViewWin::SetOverscrollControllerEnabled(bool enabled) { | |
| 244 } | |
| 245 | |
| 246 void WebContentsViewWin::ShowContextMenu(const ContextMenuParams& params) { | |
| 247 if (delegate_) | |
| 248 delegate_->ShowContextMenu(params); | |
| 249 // WARNING: this may have been deleted. | |
| 250 } | |
| 251 | |
| 252 void WebContentsViewWin::ShowPopupMenu(const gfx::Rect& bounds, | |
| 253 int item_height, | |
| 254 double item_font_size, | |
| 255 int selected_item, | |
| 256 const std::vector<MenuItem>& items, | |
| 257 bool right_aligned, | |
| 258 bool allow_multiple_selection) { | |
| 259 // External popup menus are only used on Mac and Android. | |
| 260 NOTIMPLEMENTED(); | |
| 261 } | |
| 262 | |
| 263 void WebContentsViewWin::StartDragging(const DropData& drop_data, | |
| 264 blink::WebDragOperationsMask operations, | |
| 265 const gfx::ImageSkia& image, | |
| 266 const gfx::Vector2d& image_offset, | |
| 267 const DragEventSourceInfo& event_info) { | |
| 268 drag_handler_ = new WebContentsDragWin( | |
| 269 GetNativeView(), | |
| 270 web_contents_, | |
| 271 drag_dest_, | |
| 272 base::Bind(&WebContentsViewWin::EndDragging, base::Unretained(this))); | |
| 273 drag_handler_->StartDragging(drop_data, operations, image, image_offset); | |
| 274 } | |
| 275 | |
| 276 void WebContentsViewWin::UpdateDragCursor(blink::WebDragOperation operation) { | |
| 277 drag_dest_->set_drag_cursor(operation); | |
| 278 } | |
| 279 | |
| 280 void WebContentsViewWin::GotFocus() { | |
| 281 if (web_contents_->GetDelegate()) | |
| 282 web_contents_->GetDelegate()->WebContentsFocused(web_contents_); | |
| 283 } | |
| 284 | |
| 285 void WebContentsViewWin::TakeFocus(bool reverse) { | |
| 286 if (web_contents_->GetDelegate() && | |
| 287 !web_contents_->GetDelegate()->TakeFocus(web_contents_, reverse) && | |
| 288 delegate_.get()) { | |
| 289 delegate_->TakeFocus(reverse); | |
| 290 } | |
| 291 } | |
| 292 | |
| 293 void WebContentsViewWin::EndDragging() { | |
| 294 drag_handler_ = NULL; | |
| 295 web_contents_->SystemDragEnded(); | |
| 296 } | |
| 297 | |
| 298 void WebContentsViewWin::CloseTab() { | |
| 299 RenderViewHost* rvh = web_contents_->GetRenderViewHost(); | |
| 300 rvh->GetDelegate()->Close(rvh); | |
| 301 } | |
| 302 | |
| 303 LRESULT WebContentsViewWin::OnCreate( | |
| 304 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | |
| 305 hwnd_to_wcv_map.insert(std::make_pair(hwnd(), this)); | |
| 306 AddFilterToParentHwndSubclass(hwnd(), hwnd_message_filter_.get()); | |
| 307 return 0; | |
| 308 } | |
| 309 | |
| 310 LRESULT WebContentsViewWin::OnDestroy( | |
| 311 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | |
| 312 if (drag_dest_) { | |
| 313 RevokeDragDrop(GetNativeView()); | |
| 314 drag_dest_ = NULL; | |
| 315 } | |
| 316 if (drag_handler_) { | |
| 317 drag_handler_->CancelDrag(); | |
| 318 drag_handler_ = NULL; | |
| 319 } | |
| 320 return 0; | |
| 321 } | |
| 322 | |
| 323 LRESULT WebContentsViewWin::OnWindowPosChanged( | |
| 324 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | |
| 325 | |
| 326 // Our parent might have changed. So we re-install our hwnd message filter. | |
| 327 AddFilterToParentHwndSubclass(hwnd(), hwnd_message_filter_.get()); | |
| 328 | |
| 329 WINDOWPOS* window_pos = reinterpret_cast<WINDOWPOS*>(lparam); | |
| 330 if (window_pos->flags & SWP_HIDEWINDOW) { | |
| 331 web_contents_->WasHidden(); | |
| 332 return 0; | |
| 333 } | |
| 334 | |
| 335 // The WebContents was shown by a means other than the user selecting a | |
| 336 // Tab, e.g. the window was minimized then restored. | |
| 337 if (window_pos->flags & SWP_SHOWWINDOW) | |
| 338 web_contents_->WasShown(); | |
| 339 | |
| 340 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); | |
| 341 if (rwhv) { | |
| 342 RenderWidgetHostViewWin* view = static_cast<RenderWidgetHostViewWin*>(rwhv); | |
| 343 view->UpdateScreenInfo(view->GetNativeView()); | |
| 344 } | |
| 345 | |
| 346 // Unless we were specifically told not to size, cause the renderer to be | |
| 347 // sized to the new bounds, which forces a repaint. Not required for the | |
| 348 // simple minimize-restore case described above, for example, since the | |
| 349 // size hasn't changed. | |
| 350 if (window_pos->flags & SWP_NOSIZE) | |
| 351 return 0; | |
| 352 | |
| 353 gfx::Size size(window_pos->cx, window_pos->cy); | |
| 354 if (web_contents_->GetInterstitialPage()) | |
| 355 web_contents_->GetInterstitialPage()->SetSize(size); | |
| 356 if (rwhv) | |
| 357 rwhv->SetSize(size); | |
| 358 | |
| 359 if (delegate_) | |
| 360 delegate_->SizeChanged(size); | |
| 361 | |
| 362 return 0; | |
| 363 } | |
| 364 | |
| 365 LRESULT WebContentsViewWin::OnMouseDown( | |
| 366 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | |
| 367 // Make sure this WebContents is activated when it is clicked on. | |
| 368 if (web_contents_->GetDelegate()) | |
| 369 web_contents_->GetDelegate()->ActivateContents(web_contents_); | |
| 370 return 0; | |
| 371 } | |
| 372 | |
| 373 LRESULT WebContentsViewWin::OnMouseMove( | |
| 374 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | |
| 375 // Let our delegate know that the mouse moved (useful for resetting status | |
| 376 // bubble state). | |
| 377 if (web_contents_->GetDelegate()) { | |
| 378 web_contents_->GetDelegate()->ContentsMouseEvent( | |
| 379 web_contents_, | |
| 380 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(), | |
| 381 true); | |
| 382 } | |
| 383 return 0; | |
| 384 } | |
| 385 | |
| 386 LRESULT WebContentsViewWin::OnNCCalcSize( | |
| 387 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | |
| 388 // Hack for ThinkPad mouse wheel driver. We have set the fake scroll bars | |
| 389 // to receive scroll messages from ThinkPad touch-pad driver. Suppress | |
| 390 // painting of scrollbars by returning 0 size for them. | |
| 391 return 0; | |
| 392 } | |
| 393 | |
| 394 LRESULT WebContentsViewWin::OnNCHitTest( | |
| 395 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | |
| 396 return HTTRANSPARENT; | |
| 397 } | |
| 398 | |
| 399 LRESULT WebContentsViewWin::OnScroll( | |
| 400 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | |
| 401 int scroll_type = LOWORD(wparam); | |
| 402 short position = HIWORD(wparam); | |
| 403 HWND scrollbar = reinterpret_cast<HWND>(lparam); | |
| 404 // This window can receive scroll events as a result of the ThinkPad's | |
| 405 // touch-pad scroll wheel emulation. | |
| 406 // If ctrl is held, zoom the UI. There are three issues with this: | |
| 407 // 1) Should the event be eaten or forwarded to content? We eat the event, | |
| 408 // which is like Firefox and unlike IE. | |
| 409 // 2) Should wheel up zoom in or out? We zoom in (increase font size), which | |
| 410 // is like IE and Google maps, but unlike Firefox. | |
| 411 // 3) Should the mouse have to be over the content area? We zoom as long as | |
| 412 // content has focus, although FF and IE require that the mouse is over | |
| 413 // content. This is because all events get forwarded when content has | |
| 414 // focus. | |
| 415 if (GetAsyncKeyState(VK_CONTROL) & 0x8000) { | |
| 416 int distance = 0; | |
| 417 switch (scroll_type) { | |
| 418 case SB_LINEUP: | |
| 419 distance = WHEEL_DELTA; | |
| 420 break; | |
| 421 case SB_LINEDOWN: | |
| 422 distance = -WHEEL_DELTA; | |
| 423 break; | |
| 424 // TODO(joshia): Handle SB_PAGEUP, SB_PAGEDOWN, SB_THUMBPOSITION, | |
| 425 // and SB_THUMBTRACK for completeness | |
| 426 default: | |
| 427 break; | |
| 428 } | |
| 429 | |
| 430 web_contents_->GetDelegate()->ContentsZoomChange(distance > 0); | |
| 431 return 0; | |
| 432 } | |
| 433 | |
| 434 // Reflect scroll message to the view() to give it a chance | |
| 435 // to process scrolling. | |
| 436 SendMessage(GetContentNativeView(), message, wparam, lparam); | |
| 437 return 0; | |
| 438 } | |
| 439 | |
| 440 LRESULT WebContentsViewWin::OnSize( | |
| 441 UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { | |
| 442 // NOTE: Because we handle OnWindowPosChanged without calling DefWindowProc, | |
| 443 // OnSize is NOT called on window resize. This handler is called only once | |
| 444 // when the window is created. | |
| 445 // Don't call base class OnSize to avoid useless layout for 0x0 size. | |
| 446 // We will get OnWindowPosChanged later and layout root view in WasSized. | |
| 447 | |
| 448 // Hack for ThinkPad touch-pad driver. | |
| 449 // Set fake scrollbars so that we can get scroll messages, | |
| 450 SCROLLINFO si = {0}; | |
| 451 si.cbSize = sizeof(si); | |
| 452 si.fMask = SIF_ALL; | |
| 453 | |
| 454 si.nMin = 1; | |
| 455 si.nMax = 100; | |
| 456 si.nPage = 10; | |
| 457 si.nPos = 50; | |
| 458 | |
| 459 ::SetScrollInfo(hwnd(), SB_HORZ, &si, FALSE); | |
| 460 ::SetScrollInfo(hwnd(), SB_VERT, &si, FALSE); | |
| 461 | |
| 462 return 1; | |
| 463 } | |
| 464 | |
| 465 } // namespace content | |
| OLD | NEW |