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/renderer_host/render_widget_host_view_aura.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/command_line.h" 10 #include "base/debug/trace_event.h" 11 #include "base/logging.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "cc/output/compositor_frame.h" 15 #include "cc/output/compositor_frame_ack.h" 16 #include "cc/output/copy_output_request.h" 17 #include "cc/output/copy_output_result.h" 18 #include "cc/resources/texture_mailbox.h" 19 #include "content/browser/accessibility/browser_accessibility_manager.h" 20 #include "content/browser/accessibility/browser_accessibility_state_impl.h" 21 #include "content/browser/renderer_host/backing_store_aura.h" 22 #include "content/browser/renderer_host/dip_util.h" 23 #include "content/browser/renderer_host/overscroll_controller.h" 24 #include "content/browser/renderer_host/render_view_host_delegate.h" 25 #include "content/browser/renderer_host/render_widget_host_impl.h" 26 #include "content/browser/renderer_host/touch_smooth_scroll_gesture_aura.h" 27 #include "content/browser/renderer_host/ui_events_helper.h" 28 #include "content/browser/renderer_host/web_input_event_aura.h" 29 #include "content/common/gpu/client/gl_helper.h" 30 #include "content/common/gpu/gpu_messages.h" 31 #include "content/common/view_messages.h" 32 #include "content/port/browser/render_widget_host_view_frame_subscriber.h" 33 #include "content/port/browser/render_widget_host_view_port.h" 34 #include "content/public/browser/browser_thread.h" 35 #include "content/public/browser/content_browser_client.h" 36 #include "content/public/browser/render_process_host.h" 37 #include "content/public/browser/render_view_host.h" 38 #include "content/public/browser/user_metrics.h" 39 #include "content/public/common/content_switches.h" 40 #include "media/base/video_util.h" 41 #include "skia/ext/image_operations.h" 42 #include "third_party/WebKit/public/web/WebCompositionUnderline.h" 43 #include "third_party/WebKit/public/web/WebInputEvent.h" 44 #include "third_party/WebKit/public/web/WebScreenInfo.h" 45 #include "ui/aura/client/activation_client.h" 46 #include "ui/aura/client/aura_constants.h" 47 #include "ui/aura/client/cursor_client.h" 48 #include "ui/aura/client/cursor_client_observer.h" 49 #include "ui/aura/client/focus_client.h" 50 #include "ui/aura/client/screen_position_client.h" 51 #include "ui/aura/client/stacking_client.h" 52 #include "ui/aura/client/tooltip_client.h" 53 #include "ui/aura/client/window_types.h" 54 #include "ui/aura/env.h" 55 #include "ui/aura/root_window.h" 56 #include "ui/aura/window.h" 57 #include "ui/aura/window_observer.h" 58 #include "ui/aura/window_tracker.h" 59 #include "ui/base/clipboard/scoped_clipboard_writer.h" 60 #include "ui/base/events/event.h" 61 #include "ui/base/events/event_utils.h" 62 #include "ui/base/gestures/gesture_recognizer.h" 63 #include "ui/base/hit_test.h" 64 #include "ui/base/ime/input_method.h" 65 #include "ui/base/ui_base_types.h" 66 #include "ui/compositor/layer.h" 67 #include "ui/gfx/canvas.h" 68 #include "ui/gfx/display.h" 69 #include "ui/gfx/rect_conversions.h" 70 #include "ui/gfx/screen.h" 71 #include "ui/gfx/size_conversions.h" 72 #include "ui/gfx/skia_util.h" 73 74 #if defined(OS_WIN) 75 #include "base/win/windows_version.h" 76 #include "content/browser/accessibility/browser_accessibility_manager_win.h" 77 #include "content/browser/accessibility/browser_accessibility_win.h" 78 #include "ui/base/win/hidden_window.h" 79 #include "ui/gfx/gdi_util.h" 80 #endif 81 82 using gfx::RectToSkIRect; 83 using gfx::SkIRectToRect; 84 85 using WebKit::WebScreenInfo; 86 using WebKit::WebTouchEvent; 87 88 namespace content { 89 90 void ReleaseMailbox(scoped_refptr<MemoryHolder> holder, 91 unsigned sync_point, 92 bool lost_resource) {} 93 94 class MemoryHolder : public base::RefCounted<MemoryHolder> { 95 public: 96 MemoryHolder(scoped_ptr<base::SharedMemory> shared_memory, 97 gfx::Size frame_size, 98 base::Callback<void()> callback) 99 : shared_memory_(shared_memory.Pass()), 100 frame_size_(frame_size), 101 callback_(callback) {} 102 103 cc::TextureMailbox GetMailbox() { 104 return cc::TextureMailbox( 105 shared_memory_.get(), 106 frame_size_, 107 base::Bind(ReleaseMailbox, make_scoped_refptr(this))); 108 } 109 110 private: 111 friend class base::RefCounted<MemoryHolder>; 112 ~MemoryHolder() { callback_.Run(); } 113 114 scoped_ptr<base::SharedMemory> shared_memory_; 115 gfx::Size frame_size_; 116 base::Callback<void()> callback_; 117 }; 118 119 namespace { 120 121 // In mouse lock mode, we need to prevent the (invisible) cursor from hitting 122 // the border of the view, in order to get valid movement information. However, 123 // forcing the cursor back to the center of the view after each mouse move 124 // doesn't work well. It reduces the frequency of useful mouse move messages 125 // significantly. Therefore, we move the cursor to the center of the view only 126 // if it approaches the border. |kMouseLockBorderPercentage| specifies the width 127 // of the border area, in percentage of the corresponding dimension. 128 const int kMouseLockBorderPercentage = 15; 129 130 // When accelerated compositing is enabled and a widget resize is pending, 131 // we delay further resizes of the UI. The following constant is the maximum 132 // length of time that we should delay further UI resizes while waiting for a 133 // resized frame from a renderer. 134 const int kResizeLockTimeoutMs = 67; 135 136 #if defined(OS_WIN) 137 // Used to associate a plugin HWND with its RenderWidgetHostViewAura instance. 138 const wchar_t kWidgetOwnerProperty[] = L"RenderWidgetHostViewAuraOwner"; 139 140 BOOL CALLBACK WindowDestroyingCallback(HWND window, LPARAM param) { 141 RenderWidgetHostViewAura* widget = 142 reinterpret_cast<RenderWidgetHostViewAura*>(param); 143 if (GetProp(window, kWidgetOwnerProperty) == widget) { 144 // Properties set on HWNDs must be removed to avoid leaks. 145 RemoveProp(window, kWidgetOwnerProperty); 146 RenderWidgetHostViewBase::DetachPluginWindowsCallback(window); 147 } 148 return TRUE; 149 } 150 151 BOOL CALLBACK HideWindowsCallback(HWND window, LPARAM param) { 152 RenderWidgetHostViewAura* widget = 153 reinterpret_cast<RenderWidgetHostViewAura*>(param); 154 if (GetProp(window, kWidgetOwnerProperty) == widget) 155 SetParent(window, ui::GetHiddenWindow()); 156 return TRUE; 157 } 158 159 BOOL CALLBACK ShowWindowsCallback(HWND window, LPARAM param) { 160 RenderWidgetHostViewAura* widget = 161 reinterpret_cast<RenderWidgetHostViewAura*>(param); 162 163 if (GetProp(window, kWidgetOwnerProperty) == widget) { 164 HWND parent = 165 widget->GetNativeView()->GetRootWindow()->GetAcceleratedWidget(); 166 SetParent(window, parent); 167 } 168 return TRUE; 169 } 170 171 struct CutoutRectsParams { 172 RenderWidgetHostViewAura* widget; 173 std::vector<gfx::Rect> cutout_rects; 174 std::map<HWND, WebPluginGeometry>* geometry; 175 }; 176 177 // Used to update the region for the windowed plugin to draw in. We start with 178 // the clip rect from the renderer, then remove the cutout rects from the 179 // renderer, and then remove the transient windows from the root window and the 180 // constrained windows from the parent window. 181 BOOL CALLBACK SetCutoutRectsCallback(HWND window, LPARAM param) { 182 CutoutRectsParams* params = reinterpret_cast<CutoutRectsParams*>(param); 183 184 if (GetProp(window, kWidgetOwnerProperty) == params->widget) { 185 // First calculate the offset of this plugin from the root window, since 186 // the cutouts are relative to the root window. 187 HWND parent = params->widget->GetNativeView()->GetRootWindow()-> 188 GetAcceleratedWidget(); 189 POINT offset; 190 offset.x = offset.y = 0; 191 MapWindowPoints(window, parent, &offset, 1); 192 193 // Now get the cached clip rect and cutouts for this plugin window that came 194 // from the renderer. 195 std::map<HWND, WebPluginGeometry>::iterator i = params->geometry->begin(); 196 while (i != params->geometry->end() && 197 i->second.window != window && 198 GetParent(i->second.window) != window) { 199 ++i; 200 } 201 202 if (i == params->geometry->end()) { 203 NOTREACHED(); 204 return TRUE; 205 } 206 207 HRGN hrgn = CreateRectRgn(i->second.clip_rect.x(), 208 i->second.clip_rect.y(), 209 i->second.clip_rect.right(), 210 i->second.clip_rect.bottom()); 211 // We start with the cutout rects that came from the renderer, then add the 212 // ones that came from transient and constrained windows. 213 std::vector<gfx::Rect> cutout_rects = i->second.cutout_rects; 214 for (size_t i = 0; i < params->cutout_rects.size(); ++i) { 215 gfx::Rect offset_cutout = params->cutout_rects[i]; 216 offset_cutout.Offset(-offset.x, -offset.y); 217 cutout_rects.push_back(offset_cutout); 218 } 219 gfx::SubtractRectanglesFromRegion(hrgn, cutout_rects); 220 SetWindowRgn(window, hrgn, TRUE); 221 } 222 return TRUE; 223 } 224 225 // A callback function for EnumThreadWindows to enumerate and dismiss 226 // any owned popup windows. 227 BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) { 228 const HWND toplevel_hwnd = reinterpret_cast<HWND>(arg); 229 230 if (::IsWindowVisible(window)) { 231 const HWND owner = ::GetWindow(window, GW_OWNER); 232 if (toplevel_hwnd == owner) { 233 ::PostMessage(window, WM_CANCELMODE, 0, 0); 234 } 235 } 236 237 return TRUE; 238 } 239 #endif 240 241 void UpdateWebTouchEventAfterDispatch(WebKit::WebTouchEvent* event, 242 WebKit::WebTouchPoint* point) { 243 if (point->state != WebKit::WebTouchPoint::StateReleased && 244 point->state != WebKit::WebTouchPoint::StateCancelled) 245 return; 246 --event->touchesLength; 247 for (unsigned i = point - event->touches; 248 i < event->touchesLength; 249 ++i) { 250 event->touches[i] = event->touches[i + 1]; 251 } 252 } 253 254 bool CanRendererHandleEvent(const ui::MouseEvent* event) { 255 if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED) 256 return false; 257 258 #if defined(OS_WIN) 259 // Renderer cannot handle WM_XBUTTON or NC events. 260 switch (event->native_event().message) { 261 case WM_XBUTTONDOWN: 262 case WM_XBUTTONUP: 263 case WM_XBUTTONDBLCLK: 264 case WM_NCMOUSELEAVE: 265 case WM_NCMOUSEMOVE: 266 case WM_NCXBUTTONDOWN: 267 case WM_NCXBUTTONUP: 268 case WM_NCXBUTTONDBLCLK: 269 return false; 270 default: 271 break; 272 } 273 #endif 274 return true; 275 } 276 277 // We don't mark these as handled so that they're sent back to the 278 // DefWindowProc so it can generate WM_APPCOMMAND as necessary. 279 bool IsXButtonUpEvent(const ui::MouseEvent* event) { 280 #if defined(OS_WIN) 281 switch (event->native_event().message) { 282 case WM_XBUTTONUP: 283 case WM_NCXBUTTONUP: 284 return true; 285 } 286 #endif 287 return false; 288 } 289 290 void GetScreenInfoForWindow(WebScreenInfo* results, aura::Window* window) { 291 const gfx::Display display = window ? 292 gfx::Screen::GetScreenFor(window)->GetDisplayNearestWindow(window) : 293 gfx::Screen::GetScreenFor(window)->GetPrimaryDisplay(); 294 results->rect = display.bounds(); 295 results->availableRect = display.work_area(); 296 // TODO(derat|oshima): Don't hardcode this. Get this from display object. 297 results->depth = 24; 298 results->depthPerComponent = 8; 299 results->deviceScaleFactor = display.device_scale_factor(); 300 } 301 302 bool ShouldSendPinchGesture() { 303 #if defined(OS_WIN) 304 if (base::win::GetVersion() >= base::win::VERSION_WIN8) 305 return true; 306 #endif 307 static bool pinch_allowed = 308 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableViewport) || 309 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePinch); 310 return pinch_allowed; 311 } 312 313 bool PointerEventActivates(const ui::Event& event) { 314 if (event.type() == ui::ET_MOUSE_PRESSED) 315 return true; 316 317 if (event.type() == ui::ET_GESTURE_BEGIN) { 318 const ui::GestureEvent& gesture = 319 static_cast<const ui::GestureEvent&>(event); 320 return gesture.details().touch_points() == 1; 321 } 322 323 return false; 324 } 325 326 // Swap ack for the renderer when kCompositeToMailbox is enabled. 327 void SendCompositorFrameAck( 328 int32 route_id, 329 uint32 output_surface_id, 330 int renderer_host_id, 331 const gpu::Mailbox& received_mailbox, 332 const gfx::Size& received_size, 333 bool skip_frame, 334 const scoped_refptr<ui::Texture>& texture_to_produce) { 335 cc::CompositorFrameAck ack; 336 ack.gl_frame_data.reset(new cc::GLFrameData()); 337 DCHECK(!texture_to_produce.get() || !skip_frame); 338 if (texture_to_produce.get()) { 339 std::string mailbox_name = texture_to_produce->Produce(); 340 std::copy(mailbox_name.data(), 341 mailbox_name.data() + mailbox_name.length(), 342 reinterpret_cast<char*>(ack.gl_frame_data->mailbox.name)); 343 ack.gl_frame_data->size = texture_to_produce->size(); 344 ack.gl_frame_data->sync_point = 345 content::ImageTransportFactory::GetInstance()->InsertSyncPoint(); 346 } else if (skip_frame) { 347 // Skip the frame, i.e. tell the producer to reuse the same buffer that 348 // we just received. 349 ack.gl_frame_data->size = received_size; 350 ack.gl_frame_data->mailbox = received_mailbox; 351 } 352 353 RenderWidgetHostImpl::SendSwapCompositorFrameAck( 354 route_id, output_surface_id, renderer_host_id, ack); 355 } 356 357 void AcknowledgeBufferForGpu( 358 int32 route_id, 359 int gpu_host_id, 360 const std::string& received_mailbox, 361 bool skip_frame, 362 const scoped_refptr<ui::Texture>& texture_to_produce) { 363 AcceleratedSurfaceMsg_BufferPresented_Params ack; 364 uint32 sync_point = 0; 365 DCHECK(!texture_to_produce.get() || !skip_frame); 366 if (texture_to_produce.get()) { 367 ack.mailbox_name = texture_to_produce->Produce(); 368 sync_point = 369 content::ImageTransportFactory::GetInstance()->InsertSyncPoint(); 370 } else if (skip_frame) { 371 ack.mailbox_name = received_mailbox; 372 ack.sync_point = 0; 373 } 374 375 ack.sync_point = sync_point; 376 RenderWidgetHostImpl::AcknowledgeBufferPresent( 377 route_id, gpu_host_id, ack); 378 } 379 380 } // namespace 381 382 // We need to watch for mouse events outside a Web Popup or its parent 383 // and dismiss the popup for certain events. 384 class RenderWidgetHostViewAura::EventFilterForPopupExit : 385 public ui::EventHandler { 386 public: 387 explicit EventFilterForPopupExit(RenderWidgetHostViewAura* rwhva) 388 : rwhva_(rwhva) { 389 DCHECK(rwhva_); 390 aura::RootWindow* root_window = rwhva_->window_->GetRootWindow(); 391 DCHECK(root_window); 392 root_window->AddPreTargetHandler(this); 393 } 394 395 virtual ~EventFilterForPopupExit() { 396 aura::RootWindow* root_window = rwhva_->window_->GetRootWindow(); 397 DCHECK(root_window); 398 root_window->RemovePreTargetHandler(this); 399 } 400 401 // Overridden from ui::EventHandler 402 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 403 rwhva_->ApplyEventFilterForPopupExit(event); 404 } 405 406 private: 407 RenderWidgetHostViewAura* rwhva_; 408 409 DISALLOW_COPY_AND_ASSIGN(EventFilterForPopupExit); 410 }; 411 412 void RenderWidgetHostViewAura::ApplyEventFilterForPopupExit( 413 ui::MouseEvent* event) { 414 if (in_shutdown_ || is_fullscreen_) 415 return; 416 417 if (event->type() != ui::ET_MOUSE_PRESSED || !event->target()) 418 return; 419 420 aura::Window* target = static_cast<aura::Window*>(event->target()); 421 if (target != window_ && 422 (!popup_parent_host_view_ || 423 target != popup_parent_host_view_->window_)) { 424 // Note: popup_parent_host_view_ may be NULL when there are multiple 425 // popup children per view. See: RenderWidgetHostViewAura::InitAsPopup(). 426 in_shutdown_ = true; 427 host_->Shutdown(); 428 } 429 } 430 431 // We have to implement the WindowObserver interface on a separate object 432 // because clang doesn't like implementing multiple interfaces that have 433 // methods with the same name. This object is owned by the 434 // RenderWidgetHostViewAura. 435 class RenderWidgetHostViewAura::WindowObserver : public aura::WindowObserver { 436 public: 437 explicit WindowObserver(RenderWidgetHostViewAura* view) 438 : view_(view) { 439 view_->window_->AddObserver(this); 440 } 441 442 virtual ~WindowObserver() { 443 view_->window_->RemoveObserver(this); 444 } 445 446 // Overridden from aura::WindowObserver: 447 virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE { 448 if (window == view_->window_) 449 view_->AddedToRootWindow(); 450 } 451 452 virtual void OnWindowRemovingFromRootWindow(aura::Window* window) OVERRIDE { 453 if (window == view_->window_) 454 view_->RemovingFromRootWindow(); 455 } 456 457 private: 458 RenderWidgetHostViewAura* view_; 459 460 DISALLOW_COPY_AND_ASSIGN(WindowObserver); 461 }; 462 463 #if defined(OS_WIN) 464 // On Windows, we need to watch the top level window for changes to transient 465 // windows because they can cover the view and we need to ensure that they're 466 // rendered on top of windowed NPAPI plugins. 467 class RenderWidgetHostViewAura::TransientWindowObserver 468 : public aura::WindowObserver { 469 public: 470 explicit TransientWindowObserver(RenderWidgetHostViewAura* view) 471 : view_(view), top_level_(NULL) { 472 view_->window_->AddObserver(this); 473 } 474 475 virtual ~TransientWindowObserver() { 476 view_->window_->RemoveObserver(this); 477 StopObserving(); 478 } 479 480 // Overridden from aura::WindowObserver: 481 virtual void OnWindowHierarchyChanged( 482 const aura::WindowObserver::HierarchyChangeParams& params) OVERRIDE { 483 aura::Window* top_level = GetToplevelWindow(); 484 if (top_level == top_level_) 485 return; 486 487 StopObserving(); 488 top_level_ = top_level; 489 if (top_level_ && top_level_ != view_->window_) 490 top_level_->AddObserver(this); 491 } 492 493 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { 494 if (window == top_level_) 495 StopObserving(); 496 } 497 498 virtual void OnWindowBoundsChanged(aura::Window* window, 499 const gfx::Rect& old_bounds, 500 const gfx::Rect& new_bounds) OVERRIDE { 501 if (window->transient_parent()) 502 SendPluginCutoutRects(); 503 } 504 505 virtual void OnWindowVisibilityChanged(aura::Window* window, 506 bool visible) OVERRIDE { 507 if (window->transient_parent()) 508 SendPluginCutoutRects(); 509 } 510 511 virtual void OnAddTransientChild(aura::Window* window, 512 aura::Window* transient) OVERRIDE { 513 transient->AddObserver(this); 514 // Just wait for the OnWindowBoundsChanged of the transient, since the size 515 // is not known now. 516 } 517 518 virtual void OnRemoveTransientChild(aura::Window* window, 519 aura::Window* transient) OVERRIDE { 520 transient->RemoveObserver(this); 521 SendPluginCutoutRects(); 522 } 523 524 aura::Window* GetToplevelWindow() { 525 aura::RootWindow* root = view_->window_->GetRootWindow(); 526 if (!root) 527 return NULL; 528 aura::client::ActivationClient* activation_client = 529 aura::client::GetActivationClient(root); 530 if (!activation_client) 531 return NULL; 532 return activation_client->GetToplevelWindow(view_->window_); 533 } 534 535 void StopObserving() { 536 if (!top_level_) 537 return; 538 539 const aura::Window::Windows& transients = top_level_->transient_children(); 540 for (size_t i = 0; i < transients.size(); ++i) 541 transients[i]->RemoveObserver(this); 542 543 if (top_level_ != view_->window_) 544 top_level_->RemoveObserver(this); 545 top_level_ = NULL; 546 } 547 548 void SendPluginCutoutRects() { 549 std::vector<gfx::Rect> cutouts; 550 if (top_level_) { 551 const aura::Window::Windows& transients = 552 top_level_->transient_children(); 553 for (size_t i = 0; i < transients.size(); ++i) { 554 if (transients[i]->IsVisible()) 555 cutouts.push_back(transients[i]->GetBoundsInRootWindow()); 556 } 557 } 558 559 view_->UpdateTransientRects(cutouts); 560 } 561 private: 562 RenderWidgetHostViewAura* view_; 563 aura::Window* top_level_; 564 565 DISALLOW_COPY_AND_ASSIGN(TransientWindowObserver); 566 }; 567 568 #endif 569 570 class RenderWidgetHostViewAura::ResizeLock { 571 public: 572 ResizeLock(aura::RootWindow* root_window, 573 const gfx::Size new_size, 574 bool defer_compositor_lock) 575 : root_window_(root_window), 576 new_size_(new_size), 577 compositor_lock_(defer_compositor_lock ? 578 NULL : 579 root_window_->compositor()->GetCompositorLock()), 580 weak_ptr_factory_(this), 581 defer_compositor_lock_(defer_compositor_lock) { 582 TRACE_EVENT_ASYNC_BEGIN2("ui", "ResizeLock", this, 583 "width", new_size_.width(), 584 "height", new_size_.height()); 585 root_window_->HoldPointerMoves(); 586 587 BrowserThread::PostDelayedTask( 588 BrowserThread::UI, FROM_HERE, 589 base::Bind(&RenderWidgetHostViewAura::ResizeLock::CancelLock, 590 weak_ptr_factory_.GetWeakPtr()), 591 base::TimeDelta::FromMilliseconds(kResizeLockTimeoutMs)); 592 } 593 594 ~ResizeLock() { 595 CancelLock(); 596 TRACE_EVENT_ASYNC_END2("ui", "ResizeLock", this, 597 "width", new_size_.width(), 598 "height", new_size_.height()); 599 } 600 601 void UnlockCompositor() { 602 defer_compositor_lock_ = false; 603 compositor_lock_ = NULL; 604 } 605 606 void CancelLock() { 607 if (!root_window_) 608 return; 609 UnlockCompositor(); 610 root_window_->ReleasePointerMoves(); 611 root_window_ = NULL; 612 } 613 614 const gfx::Size& expected_size() const { 615 return new_size_; 616 } 617 618 bool GrabDeferredLock() { 619 if (root_window_ && defer_compositor_lock_) { 620 compositor_lock_ = root_window_->compositor()->GetCompositorLock(); 621 defer_compositor_lock_ = false; 622 return true; 623 } 624 return false; 625 } 626 627 private: 628 aura::RootWindow* root_window_; 629 gfx::Size new_size_; 630 scoped_refptr<ui::CompositorLock> compositor_lock_; 631 base::WeakPtrFactory<ResizeLock> weak_ptr_factory_; 632 bool defer_compositor_lock_; 633 634 DISALLOW_COPY_AND_ASSIGN(ResizeLock); 635 }; 636 637 //////////////////////////////////////////////////////////////////////////////// 638 // RenderWidgetHostViewAura, public: 639 640 RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host) 641 : host_(RenderWidgetHostImpl::From(host)), 642 window_(new aura::Window(this)), 643 in_shutdown_(false), 644 is_fullscreen_(false), 645 popup_parent_host_view_(NULL), 646 popup_child_host_view_(NULL), 647 is_loading_(false), 648 text_input_type_(ui::TEXT_INPUT_TYPE_NONE), 649 can_compose_inline_(true), 650 has_composition_text_(false), 651 last_swapped_surface_scale_factor_(1.f), 652 paint_canvas_(NULL), 653 synthetic_move_sent_(false), 654 accelerated_compositing_state_changed_(false), 655 can_lock_compositor_(YES), 656 cursor_visibility_state_in_renderer_(UNKNOWN), 657 paint_observer_(NULL), 658 touch_editing_client_(NULL) { 659 host_->SetView(this); 660 window_observer_.reset(new WindowObserver(this)); 661 aura::client::SetTooltipText(window_, &tooltip_); 662 aura::client::SetActivationDelegate(window_, this); 663 aura::client::SetActivationChangeObserver(window_, this); 664 aura::client::SetFocusChangeObserver(window_, this); 665 gfx::Screen::GetScreenFor(window_)->AddObserver(this); 666 #if defined(OS_WIN) 667 transient_observer_.reset(new TransientWindowObserver(this)); 668 #endif 669 } 670 671 //////////////////////////////////////////////////////////////////////////////// 672 // RenderWidgetHostViewAura, RenderWidgetHostView implementation: 673 674 void RenderWidgetHostViewAura::InitAsChild( 675 gfx::NativeView parent_view) { 676 window_->Init(ui::LAYER_TEXTURED); 677 window_->SetName("RenderWidgetHostViewAura"); 678 } 679 680 void RenderWidgetHostViewAura::InitAsPopup( 681 RenderWidgetHostView* parent_host_view, 682 const gfx::Rect& bounds_in_screen) { 683 popup_parent_host_view_ = 684 static_cast<RenderWidgetHostViewAura*>(parent_host_view); 685 686 RenderWidgetHostViewAura* old_child = 687 popup_parent_host_view_->popup_child_host_view_; 688 if (old_child) { 689 // TODO(jhorwich): Allow multiple popup_child_host_view_ per view, or 690 // similar mechanism to ensure a second popup doesn't cause the first one 691 // to never get a chance to filter events. See crbug.com/160589. 692 DCHECK(old_child->popup_parent_host_view_ == popup_parent_host_view_); 693 old_child->popup_parent_host_view_ = NULL; 694 } 695 popup_parent_host_view_->popup_child_host_view_ = this; 696 window_->SetType(aura::client::WINDOW_TYPE_MENU); 697 window_->Init(ui::LAYER_TEXTURED); 698 window_->SetName("RenderWidgetHostViewAura"); 699 700 aura::RootWindow* root = popup_parent_host_view_->window_->GetRootWindow(); 701 window_->SetDefaultParentByRootWindow(root, bounds_in_screen); 702 703 // TODO(erg): While I could make sure details of the StackingClient are 704 // hidden behind aura, hiding the details of the ScreenPositionClient will 705 // take another effort. 706 aura::client::ScreenPositionClient* screen_position_client = 707 aura::client::GetScreenPositionClient(root); 708 gfx::Point origin_in_parent(bounds_in_screen.origin()); 709 if (screen_position_client) { 710 screen_position_client->ConvertPointFromScreen( 711 window_->parent(), &origin_in_parent); 712 } 713 SetBounds(gfx::Rect(origin_in_parent, bounds_in_screen.size())); 714 Show(); 715 } 716 717 void RenderWidgetHostViewAura::InitAsFullscreen( 718 RenderWidgetHostView* reference_host_view) { 719 is_fullscreen_ = true; 720 window_->SetType(aura::client::WINDOW_TYPE_NORMAL); 721 window_->Init(ui::LAYER_TEXTURED); 722 window_->SetName("RenderWidgetHostViewAura"); 723 window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); 724 725 aura::RootWindow* parent = NULL; 726 gfx::Rect bounds; 727 if (reference_host_view) { 728 aura::Window* reference_window = 729 static_cast<RenderWidgetHostViewAura*>(reference_host_view)->window_; 730 if (reference_window) { 731 host_tracker_.reset(new aura::WindowTracker); 732 host_tracker_->Add(reference_window); 733 } 734 gfx::Display display = gfx::Screen::GetScreenFor(window_)-> 735 GetDisplayNearestWindow(reference_window); 736 parent = reference_window->GetRootWindow(); 737 bounds = display.bounds(); 738 } 739 window_->SetDefaultParentByRootWindow(parent, bounds); 740 Show(); 741 Focus(); 742 } 743 744 RenderWidgetHost* RenderWidgetHostViewAura::GetRenderWidgetHost() const { 745 return host_; 746 } 747 748 void RenderWidgetHostViewAura::WasShown() { 749 if (!host_->is_hidden()) 750 return; 751 host_->WasShown(); 752 753 aura::client::CursorClient* cursor_client = 754 aura::client::GetCursorClient(window_->GetRootWindow()); 755 if (cursor_client) 756 NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible()); 757 758 if (!current_surface_.get() && host_->is_accelerated_compositing_active() && 759 !released_front_lock_.get()) { 760 released_front_lock_ = GetCompositor()->GetCompositorLock(); 761 } 762 763 #if defined(OS_WIN) 764 LPARAM lparam = reinterpret_cast<LPARAM>(this); 765 EnumChildWindows(ui::GetHiddenWindow(), ShowWindowsCallback, lparam); 766 transient_observer_->SendPluginCutoutRects(); 767 #endif 768 } 769 770 void RenderWidgetHostViewAura::WasHidden() { 771 if (host_->is_hidden()) 772 return; 773 host_->WasHidden(); 774 775 released_front_lock_ = NULL; 776 777 #if defined(OS_WIN) 778 aura::RootWindow* root_window = window_->GetRootWindow(); 779 if (root_window) { 780 HWND parent = root_window->GetAcceleratedWidget(); 781 LPARAM lparam = reinterpret_cast<LPARAM>(this); 782 783 EnumChildWindows(parent, HideWindowsCallback, lparam); 784 } 785 #endif 786 } 787 788 void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) { 789 SetBounds(gfx::Rect(window_->bounds().origin(), size)); 790 } 791 792 void RenderWidgetHostViewAura::SetBounds(const gfx::Rect& rect) { 793 if (HasDisplayPropertyChanged(window_)) 794 host_->InvalidateScreenInfo(); 795 796 window_->SetBounds(rect); 797 host_->WasResized(); 798 MaybeCreateResizeLock(); 799 if (touch_editing_client_) { 800 touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_rect_, 801 selection_focus_rect_); 802 } 803 } 804 805 void RenderWidgetHostViewAura::MaybeCreateResizeLock() { 806 gfx::Size desired_size = window_->bounds().size(); 807 if (!host_->should_auto_resize() && 808 !resize_lock_.get() && 809 desired_size != current_frame_size_ && 810 host_->is_accelerated_compositing_active()) { 811 aura::RootWindow* root_window = window_->GetRootWindow(); 812 ui::Compositor* compositor = root_window ? 813 root_window->compositor() : NULL; 814 if (root_window && compositor) { 815 // Listen to changes in the compositor lock state. 816 if (!compositor->HasObserver(this)) 817 compositor->AddObserver(this); 818 819 // On Windows while resizing, the the resize locks makes us mis-paint a white 820 // vertical strip (including the non-client area) if the content composition is 821 // lagging the UI composition. So here we disable the throttling so that the UI 822 // bits can draw ahead of the content thereby reducing the amount of whiteout. 823 // Because this causes the content to be drawn at wrong sizes while resizing 824 // we compensate by blocking the UI thread in Compositor::Draw() by issuing a 825 // FinishAllRendering() if we are resizing. 826 #if !defined (OS_WIN) 827 bool defer_compositor_lock = 828 can_lock_compositor_ == NO_PENDING_RENDERER_FRAME || 829 can_lock_compositor_ == NO_PENDING_COMMIT; 830 831 if (can_lock_compositor_ == YES) 832 can_lock_compositor_ = YES_DID_LOCK; 833 834 resize_lock_.reset(new ResizeLock(root_window, desired_size, 835 defer_compositor_lock)); 836 #endif 837 } 838 } 839 } 840 841 gfx::NativeView RenderWidgetHostViewAura::GetNativeView() const { 842 return window_; 843 } 844 845 gfx::NativeViewId RenderWidgetHostViewAura::GetNativeViewId() const { 846 #if defined(OS_WIN) 847 aura::RootWindow* root_window = window_->GetRootWindow(); 848 if (root_window) { 849 HWND window = root_window->GetAcceleratedWidget(); 850 return reinterpret_cast<gfx::NativeViewId>(window); 851 } 852 #endif 853 return static_cast<gfx::NativeViewId>(NULL); 854 } 855 856 gfx::NativeViewAccessible RenderWidgetHostViewAura::GetNativeViewAccessible() { 857 #if defined(OS_WIN) 858 aura::RootWindow* root_window = window_->GetRootWindow(); 859 if (!root_window) 860 return static_cast<gfx::NativeViewAccessible>(NULL); 861 HWND hwnd = root_window->GetAcceleratedWidget(); 862 863 BrowserAccessibilityManager* manager = 864 GetOrCreateBrowserAccessibilityManager(); 865 if (manager) 866 return manager->GetRoot()->ToBrowserAccessibilityWin(); 867 #endif 868 869 NOTIMPLEMENTED(); 870 return static_cast<gfx::NativeViewAccessible>(NULL); 871 } 872 873 BrowserAccessibilityManager* 874 RenderWidgetHostViewAura::GetOrCreateBrowserAccessibilityManager() { 875 BrowserAccessibilityManager* manager = GetBrowserAccessibilityManager(); 876 if (manager) 877 return manager; 878 879 #if defined(OS_WIN) 880 aura::RootWindow* root_window = window_->GetRootWindow(); 881 if (!root_window) 882 return NULL; 883 HWND hwnd = root_window->GetAcceleratedWidget(); 884 885 // The accessible_parent may be NULL at this point. The WebContents will pass 886 // it down to this instance (by way of the RenderViewHost and 887 // RenderWidgetHost) when it is known. This instance will then set it on its 888 // BrowserAccessibilityManager. 889 gfx::NativeViewAccessible accessible_parent = 890 host_->GetParentNativeViewAccessible(); 891 892 manager = new BrowserAccessibilityManagerWin( 893 hwnd, accessible_parent, 894 BrowserAccessibilityManagerWin::GetEmptyDocument(), this); 895 #else 896 manager = BrowserAccessibilityManager::Create( 897 BrowserAccessibilityManager::GetEmptyDocument(), this); 898 #endif 899 900 SetBrowserAccessibilityManager(manager); 901 return manager; 902 } 903 904 void RenderWidgetHostViewAura::MovePluginWindows( 905 const gfx::Vector2d& scroll_offset, 906 const std::vector<WebPluginGeometry>& plugin_window_moves) { 907 #if defined(OS_WIN) 908 // We need to clip the rectangle to the tab's viewport, otherwise we will draw 909 // over the browser UI. 910 if (!window_->GetRootWindow()) { 911 DCHECK(plugin_window_moves.empty()); 912 return; 913 } 914 HWND parent = window_->GetRootWindow()->GetAcceleratedWidget(); 915 gfx::Rect view_bounds = window_->GetBoundsInRootWindow(); 916 std::vector<WebPluginGeometry> moves = plugin_window_moves; 917 918 gfx::Rect view_port(scroll_offset.x(), scroll_offset.y(), view_bounds.width(), 919 view_bounds.height()); 920 921 for (size_t i = 0; i < moves.size(); ++i) { 922 gfx::Rect clip(moves[i].clip_rect); 923 gfx::Vector2d view_port_offset( 924 moves[i].window_rect.OffsetFromOrigin() + scroll_offset); 925 clip.Offset(view_port_offset); 926 clip.Intersect(view_port); 927 clip.Offset(-view_port_offset); 928 moves[i].clip_rect = clip; 929 930 moves[i].window_rect.Offset(view_bounds.OffsetFromOrigin()); 931 932 plugin_window_moves_[moves[i].window] = moves[i]; 933 934 // transient_rects_ and constrained_rects_ are relative to the root window. 935 // We want to convert them to be relative to the plugin window. 936 std::vector<gfx::Rect> cutout_rects; 937 cutout_rects.assign(transient_rects_.begin(), transient_rects_.end()); 938 cutout_rects.insert(cutout_rects.end(), constrained_rects_.begin(), 939 constrained_rects_.end()); 940 for (size_t j = 0; j < cutout_rects.size(); ++j) { 941 gfx::Rect offset_cutout = cutout_rects[j]; 942 offset_cutout -= moves[i].window_rect.OffsetFromOrigin(); 943 moves[i].cutout_rects.push_back(offset_cutout); 944 } 945 } 946 947 MovePluginWindowsHelper(parent, moves); 948 949 // Make sure each plugin window (or its wrapper if it exists) has a pointer to 950 // |this|. 951 for (size_t i = 0; i < moves.size(); ++i) { 952 HWND window = moves[i].window; 953 if (GetParent(window) != parent) { 954 window = GetParent(window); 955 DCHECK(GetParent(window) == parent); 956 } 957 if (!GetProp(window, kWidgetOwnerProperty)) 958 SetProp(window, kWidgetOwnerProperty, this); 959 } 960 #endif // defined(OS_WIN) 961 } 962 963 void RenderWidgetHostViewAura::Focus() { 964 // Make sure we have a FocusClient before attempting to Focus(). In some 965 // situations we may not yet be in a valid Window hierarchy (such as reloading 966 // after out of memory discarded the tab). 967 aura::client::FocusClient* client = aura::client::GetFocusClient(window_); 968 if (client) 969 window_->Focus(); 970 } 971 972 void RenderWidgetHostViewAura::Blur() { 973 window_->Blur(); 974 } 975 976 bool RenderWidgetHostViewAura::HasFocus() const { 977 return window_->HasFocus(); 978 } 979 980 bool RenderWidgetHostViewAura::IsSurfaceAvailableForCopy() const { 981 return CanCopyToBitmap() || !!host_->GetBackingStore(false); 982 } 983 984 void RenderWidgetHostViewAura::Show() { 985 window_->Show(); 986 } 987 988 void RenderWidgetHostViewAura::Hide() { 989 window_->Hide(); 990 } 991 992 bool RenderWidgetHostViewAura::IsShowing() { 993 return window_->IsVisible(); 994 } 995 996 gfx::Rect RenderWidgetHostViewAura::GetViewBounds() const { 997 // This is the size that we want the renderer to produce. While we're waiting 998 // for the correct frame (i.e. during a resize), don't change the size so that 999 // we don't pipeline more resizes than we can handle. 1000 gfx::Rect bounds(window_->GetBoundsInScreen()); 1001 if (resize_lock_.get()) 1002 return gfx::Rect(bounds.origin(), resize_lock_->expected_size()); 1003 else 1004 return bounds; 1005 } 1006 1007 void RenderWidgetHostViewAura::SetBackground(const SkBitmap& background) { 1008 RenderWidgetHostViewBase::SetBackground(background); 1009 host_->SetBackground(background); 1010 window_->layer()->SetFillsBoundsOpaquely(background.isOpaque()); 1011 } 1012 1013 #if defined(OS_WIN) 1014 gfx::NativeViewAccessible 1015 RenderWidgetHostViewAura::AccessibleObjectFromChildId(long child_id) { 1016 BrowserAccessibilityManager* manager = GetBrowserAccessibilityManager(); 1017 if (!manager) 1018 return NULL; 1019 1020 return manager->ToBrowserAccessibilityManagerWin()->GetFromUniqueIdWin( 1021 child_id); 1022 } 1023 #endif // defined(OS_WIN) 1024 1025 void RenderWidgetHostViewAura::UpdateCursor(const WebCursor& cursor) { 1026 current_cursor_ = cursor; 1027 const gfx::Display display = gfx::Screen::GetScreenFor(window_)-> 1028 GetDisplayNearestWindow(window_); 1029 current_cursor_.SetDisplayInfo(display); 1030 UpdateCursorIfOverSelf(); 1031 } 1032 1033 void RenderWidgetHostViewAura::SetIsLoading(bool is_loading) { 1034 if (is_loading_ && !is_loading && paint_observer_) 1035 paint_observer_->OnPageLoadComplete(); 1036 is_loading_ = is_loading; 1037 UpdateCursorIfOverSelf(); 1038 } 1039 1040 void RenderWidgetHostViewAura::TextInputTypeChanged( 1041 ui::TextInputType type, 1042 bool can_compose_inline, 1043 ui::TextInputMode input_mode) { 1044 if (text_input_type_ != type || 1045 can_compose_inline_ != can_compose_inline) { 1046 text_input_type_ = type; 1047 can_compose_inline_ = can_compose_inline; 1048 if (GetInputMethod()) 1049 GetInputMethod()->OnTextInputTypeChanged(this); 1050 if (touch_editing_client_) 1051 touch_editing_client_->OnTextInputTypeChanged(text_input_type_); 1052 } 1053 } 1054 1055 void RenderWidgetHostViewAura::ImeCancelComposition() { 1056 if (GetInputMethod()) 1057 GetInputMethod()->CancelComposition(this); 1058 has_composition_text_ = false; 1059 } 1060 1061 void RenderWidgetHostViewAura::ImeCompositionRangeChanged( 1062 const ui::Range& range, 1063 const std::vector<gfx::Rect>& character_bounds) { 1064 composition_character_bounds_ = character_bounds; 1065 } 1066 1067 void RenderWidgetHostViewAura::DidUpdateBackingStore( 1068 const gfx::Rect& scroll_rect, 1069 const gfx::Vector2d& scroll_delta, 1070 const std::vector<gfx::Rect>& copy_rects, 1071 const ui::LatencyInfo& latency_info) { 1072 if (accelerated_compositing_state_changed_) 1073 UpdateExternalTexture(); 1074 1075 software_latency_info_.MergeWith(latency_info); 1076 1077 // Use the state of the RenderWidgetHost and not the window as the two may 1078 // differ. In particular if the window is hidden but the renderer isn't and we 1079 // ignore the update and the window is made visible again the layer isn't 1080 // marked as dirty and we show the wrong thing. 1081 // We do this after UpdateExternalTexture() so that when we become visible 1082 // we're not drawing a stale texture. 1083 if (host_->is_hidden()) 1084 return; 1085 1086 gfx::Rect clip_rect; 1087 if (paint_canvas_) { 1088 SkRect sk_clip_rect; 1089 if (paint_canvas_->sk_canvas()->getClipBounds(&sk_clip_rect)) 1090 clip_rect = gfx::ToEnclosingRect(gfx::SkRectToRectF(sk_clip_rect)); 1091 } 1092 1093 if (!scroll_rect.IsEmpty()) 1094 SchedulePaintIfNotInClip(scroll_rect, clip_rect); 1095 1096 #if defined(OS_WIN) 1097 aura::RootWindow* root_window = window_->GetRootWindow(); 1098 #endif 1099 for (size_t i = 0; i < copy_rects.size(); ++i) { 1100 gfx::Rect rect = gfx::SubtractRects(copy_rects[i], scroll_rect); 1101 if (rect.IsEmpty()) 1102 continue; 1103 1104 SchedulePaintIfNotInClip(rect, clip_rect); 1105 1106 #if defined(OS_WIN) 1107 if (root_window) { 1108 // Send the invalid rect in screen coordinates. 1109 gfx::Rect screen_rect = GetViewBounds(); 1110 gfx::Rect invalid_screen_rect(rect); 1111 invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y()); 1112 HWND hwnd = root_window->GetAcceleratedWidget(); 1113 PaintPluginWindowsHelper(hwnd, invalid_screen_rect); 1114 } 1115 #endif // defined(OS_WIN) 1116 } 1117 } 1118 1119 void RenderWidgetHostViewAura::RenderProcessGone(base::TerminationStatus status, 1120 int error_code) { 1121 UpdateCursorIfOverSelf(); 1122 Destroy(); 1123 } 1124 1125 void RenderWidgetHostViewAura::Destroy() { 1126 // Beware, this function is not called on all destruction paths. It will 1127 // implicitly end up calling ~RenderWidgetHostViewAura though, so all 1128 // destruction/cleanup code should happen there, not here. 1129 in_shutdown_ = true; 1130 delete window_; 1131 } 1132 1133 void RenderWidgetHostViewAura::SetTooltipText(const string16& tooltip_text) { 1134 tooltip_ = tooltip_text; 1135 aura::RootWindow* root_window = window_->GetRootWindow(); 1136 aura::client::TooltipClient* tooltip_client = 1137 aura::client::GetTooltipClient(root_window); 1138 if (tooltip_client) { 1139 tooltip_client->UpdateTooltip(window_); 1140 // Content tooltips should be visible indefinitely. 1141 tooltip_client->SetTooltipShownTimeout(window_, 0); 1142 } 1143 } 1144 1145 void RenderWidgetHostViewAura::SelectionChanged(const string16& text, 1146 size_t offset, 1147 const ui::Range& range) { 1148 RenderWidgetHostViewBase::SelectionChanged(text, offset, range); 1149 1150 #if defined(USE_X11) && !defined(OS_CHROMEOS) 1151 if (text.empty() || range.is_empty()) 1152 return; 1153 1154 // Set the BUFFER_SELECTION to the ui::Clipboard. 1155 ui::ScopedClipboardWriter clipboard_writer( 1156 ui::Clipboard::GetForCurrentThread(), 1157 ui::Clipboard::BUFFER_SELECTION); 1158 clipboard_writer.WriteText(text); 1159 #endif // defined(USE_X11) && !defined(OS_CHROMEOS) 1160 } 1161 1162 void RenderWidgetHostViewAura::SelectionBoundsChanged( 1163 const ViewHostMsg_SelectionBounds_Params& params) { 1164 if (selection_anchor_rect_ == params.anchor_rect && 1165 selection_focus_rect_ == params.focus_rect) 1166 return; 1167 1168 selection_anchor_rect_ = params.anchor_rect; 1169 selection_focus_rect_ = params.focus_rect; 1170 1171 if (GetInputMethod()) 1172 GetInputMethod()->OnCaretBoundsChanged(this); 1173 1174 if (touch_editing_client_) { 1175 touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_rect_, 1176 selection_focus_rect_); 1177 } 1178 } 1179 1180 void RenderWidgetHostViewAura::ScrollOffsetChanged() { 1181 aura::RootWindow* root = window_->GetRootWindow(); 1182 if (!root) 1183 return; 1184 aura::client::CursorClient* cursor_client = 1185 aura::client::GetCursorClient(root); 1186 if (cursor_client && !cursor_client->IsCursorVisible()) 1187 cursor_client->DisableMouseEvents(); 1188 } 1189 1190 BackingStore* RenderWidgetHostViewAura::AllocBackingStore( 1191 const gfx::Size& size) { 1192 return new BackingStoreAura(host_, size); 1193 } 1194 1195 void RenderWidgetHostViewAura::CopyFromCompositingSurface( 1196 const gfx::Rect& src_subrect, 1197 const gfx::Size& dst_size, 1198 const base::Callback<void(bool, const SkBitmap&)>& callback) { 1199 if (!CanCopyToBitmap()) { 1200 callback.Run(false, SkBitmap()); 1201 return; 1202 } 1203 1204 const gfx::Size& dst_size_in_pixel = ConvertViewSizeToPixel(this, dst_size); 1205 scoped_ptr<cc::CopyOutputRequest> request = 1206 cc::CopyOutputRequest::CreateRequest(base::Bind( 1207 &RenderWidgetHostViewAura::CopyFromCompositingSurfaceHasResult, 1208 dst_size_in_pixel, 1209 callback)); 1210 gfx::Rect src_subrect_in_pixel = 1211 ConvertRectToPixel(current_device_scale_factor_, src_subrect); 1212 request->set_area(src_subrect_in_pixel); 1213 window_->layer()->RequestCopyOfOutput(request.Pass()); 1214 } 1215 1216 void RenderWidgetHostViewAura::CopyFromCompositingSurfaceToVideoFrame( 1217 const gfx::Rect& src_subrect, 1218 const scoped_refptr<media::VideoFrame>& target, 1219 const base::Callback<void(bool)>& callback) { 1220 if (!CanCopyToVideoFrame()) { 1221 callback.Run(false); 1222 return; 1223 } 1224 1225 scoped_ptr<cc::CopyOutputRequest> request = 1226 cc::CopyOutputRequest::CreateRequest(base::Bind( 1227 &RenderWidgetHostViewAura:: 1228 CopyFromCompositingSurfaceHasResultForVideo, 1229 AsWeakPtr(), // For caching the ReadbackYUVInterface on this class. 1230 target, 1231 callback)); 1232 gfx::Rect src_subrect_in_pixel = 1233 ConvertRectToPixel(current_device_scale_factor_, src_subrect); 1234 request->set_area(src_subrect_in_pixel); 1235 window_->layer()->RequestCopyOfOutput(request.Pass()); 1236 } 1237 1238 bool RenderWidgetHostViewAura::CanCopyToBitmap() const { 1239 return GetCompositor() && window_->layer()->has_external_content(); 1240 } 1241 1242 bool RenderWidgetHostViewAura::CanCopyToVideoFrame() const { 1243 return GetCompositor() && 1244 window_->layer()->has_external_content() && 1245 host_->is_accelerated_compositing_active(); 1246 } 1247 1248 bool RenderWidgetHostViewAura::CanSubscribeFrame() const { 1249 return true; 1250 } 1251 1252 void RenderWidgetHostViewAura::BeginFrameSubscription( 1253 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) { 1254 frame_subscriber_ = subscriber.Pass(); 1255 } 1256 1257 void RenderWidgetHostViewAura::EndFrameSubscription() { 1258 frame_subscriber_.reset(); 1259 } 1260 1261 1262 void RenderWidgetHostViewAura::OnAcceleratedCompositingStateChange() { 1263 // Delay processing the state change until we either get a software frame if 1264 // switching to software mode or receive a buffers swapped notification 1265 // if switching to accelerated mode. 1266 // Sometimes (e.g. on a page load) the renderer will spuriously disable then 1267 // re-enable accelerated compositing, causing us to flash. 1268 // TODO(piman): factor the enable/disable accelerated compositing message into 1269 // the UpdateRect/AcceleratedSurfaceBuffersSwapped messages so that we have 1270 // fewer inconsistent temporary states. 1271 accelerated_compositing_state_changed_ = true; 1272 } 1273 1274 bool RenderWidgetHostViewAura::ShouldSkipFrame(gfx::Size size_in_dip) const { 1275 if (can_lock_compositor_ == NO_PENDING_RENDERER_FRAME || 1276 can_lock_compositor_ == NO_PENDING_COMMIT || 1277 !resize_lock_.get()) 1278 return false; 1279 1280 return size_in_dip != resize_lock_->expected_size(); 1281 } 1282 1283 void RenderWidgetHostViewAura::CheckResizeLock() { 1284 if (!resize_lock_ || resize_lock_->expected_size() != current_frame_size_) 1285 return; 1286 1287 // Since we got the size we were looking for, unlock the compositor. But delay 1288 // the release of the lock until we've kicked a frame with the new texture, to 1289 // avoid resizing the UI before we have a chance to draw a "good" frame. 1290 resize_lock_->UnlockCompositor(); 1291 ui::Compositor* compositor = GetCompositor(); 1292 if (compositor) { 1293 if (!compositor->HasObserver(this)) 1294 compositor->AddObserver(this); 1295 } 1296 } 1297 1298 void RenderWidgetHostViewAura::UpdateExternalTexture() { 1299 // Delay processing accelerated compositing state change till here where we 1300 // act upon the state change. (Clear the external texture if switching to 1301 // software mode or set the external texture if going to accelerated mode). 1302 if (accelerated_compositing_state_changed_) 1303 accelerated_compositing_state_changed_ = false; 1304 1305 bool is_compositing_active = host_->is_accelerated_compositing_active(); 1306 if (is_compositing_active && current_surface_.get()) { 1307 window_->layer()->SetExternalTexture(current_surface_.get()); 1308 current_frame_size_ = ConvertSizeToDIP( 1309 current_surface_->device_scale_factor(), current_surface_->size()); 1310 CheckResizeLock(); 1311 } else if (is_compositing_active && framebuffer_holder_) { 1312 cc::TextureMailbox mailbox = framebuffer_holder_->GetMailbox(); 1313 window_->layer()->SetTextureMailbox(mailbox, 1314 last_swapped_surface_scale_factor_); 1315 current_frame_size_ = ConvertSizeToDIP(last_swapped_surface_scale_factor_, 1316 mailbox.shared_memory_size()); 1317 CheckResizeLock(); 1318 } else { 1319 window_->layer()->SetExternalTexture(NULL); 1320 resize_lock_.reset(); 1321 host_->WasResized(); 1322 } 1323 } 1324 1325 bool RenderWidgetHostViewAura::SwapBuffersPrepare( 1326 const gfx::Rect& surface_rect, 1327 float surface_scale_factor, 1328 const gfx::Rect& damage_rect, 1329 const std::string& mailbox_name, 1330 const BufferPresentedCallback& ack_callback) { 1331 if (last_swapped_surface_size_ != surface_rect.size()) { 1332 // The surface could have shrunk since we skipped an update, in which 1333 // case we can expect a full update. 1334 DLOG_IF(ERROR, damage_rect != surface_rect) << "Expected full damage rect"; 1335 skipped_damage_.setEmpty(); 1336 last_swapped_surface_size_ = surface_rect.size(); 1337 last_swapped_surface_scale_factor_ = surface_scale_factor; 1338 } 1339 1340 if (ShouldSkipFrame(ConvertSizeToDIP(surface_scale_factor, 1341 surface_rect.size())) || 1342 mailbox_name.empty()) { 1343 skipped_damage_.op(RectToSkIRect(damage_rect), SkRegion::kUnion_Op); 1344 ack_callback.Run(true, scoped_refptr<ui::Texture>()); 1345 return false; 1346 } 1347 1348 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 1349 current_surface_ = 1350 factory->CreateTransportClient(surface_scale_factor); 1351 if (!current_surface_.get()) { 1352 LOG(ERROR) << "Failed to create ImageTransport texture"; 1353 ack_callback.Run(true, scoped_refptr<ui::Texture>()); 1354 return false; 1355 } 1356 1357 current_surface_->Consume(mailbox_name, surface_rect.size()); 1358 released_front_lock_ = NULL; 1359 UpdateExternalTexture(); 1360 1361 return true; 1362 } 1363 1364 void RenderWidgetHostViewAura::SwapBuffersCompleted( 1365 const BufferPresentedCallback& ack_callback, 1366 const scoped_refptr<ui::Texture>& texture_to_return) { 1367 ui::Compositor* compositor = GetCompositor(); 1368 if (!compositor) { 1369 ack_callback.Run(false, texture_to_return); 1370 } else { 1371 AddOnCommitCallbackAndDisableLocks( 1372 base::Bind(ack_callback, false, texture_to_return)); 1373 } 1374 1375 DidReceiveFrameFromRenderer(); 1376 } 1377 1378 void RenderWidgetHostViewAura::DidReceiveFrameFromRenderer() { 1379 if (frame_subscriber() && CanCopyToVideoFrame()) { 1380 const base::Time present_time = base::Time::Now(); 1381 scoped_refptr<media::VideoFrame> frame; 1382 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback; 1383 if (frame_subscriber()->ShouldCaptureFrame(present_time, 1384 &frame, &callback)) { 1385 CopyFromCompositingSurfaceToVideoFrame( 1386 gfx::Rect(current_frame_size_), 1387 frame, 1388 base::Bind(callback, present_time)); 1389 } 1390 } 1391 } 1392 1393 #if defined(OS_WIN) 1394 void RenderWidgetHostViewAura::UpdateTransientRects( 1395 const std::vector<gfx::Rect>& rects) { 1396 transient_rects_ = rects; 1397 UpdateCutoutRects(); 1398 } 1399 1400 void RenderWidgetHostViewAura::UpdateConstrainedWindowRects( 1401 const std::vector<gfx::Rect>& rects) { 1402 constrained_rects_ = rects; 1403 UpdateCutoutRects(); 1404 } 1405 1406 void RenderWidgetHostViewAura::UpdateCutoutRects() { 1407 if (!window_->GetRootWindow()) 1408 return; 1409 HWND parent = window_->GetRootWindow()->GetAcceleratedWidget(); 1410 CutoutRectsParams params; 1411 params.widget = this; 1412 params.cutout_rects.assign(transient_rects_.begin(), transient_rects_.end()); 1413 params.cutout_rects.insert(params.cutout_rects.end(), 1414 constrained_rects_.begin(), 1415 constrained_rects_.end()); 1416 params.geometry = &plugin_window_moves_; 1417 LPARAM lparam = reinterpret_cast<LPARAM>(¶ms); 1418 EnumChildWindows(parent, SetCutoutRectsCallback, lparam); 1419 } 1420 #endif 1421 1422 void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( 1423 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel, 1424 int gpu_host_id) { 1425 BufferPresentedCallback ack_callback = base::Bind( 1426 &AcknowledgeBufferForGpu, 1427 params_in_pixel.route_id, 1428 gpu_host_id, 1429 params_in_pixel.mailbox_name); 1430 BuffersSwapped(params_in_pixel.size, 1431 gfx::Rect(params_in_pixel.size), 1432 params_in_pixel.scale_factor, 1433 params_in_pixel.mailbox_name, 1434 params_in_pixel.latency_info, 1435 ack_callback); 1436 } 1437 1438 void RenderWidgetHostViewAura::SwapDelegatedFrame( 1439 uint32 output_surface_id, 1440 scoped_ptr<cc::DelegatedFrameData> frame_data, 1441 float frame_device_scale_factor, 1442 const ui::LatencyInfo& latency_info) { 1443 gfx::Size frame_size_in_dip; 1444 if (!frame_data->render_pass_list.empty()) { 1445 frame_size_in_dip = gfx::ToFlooredSize(gfx::ScaleSize( 1446 frame_data->render_pass_list.back()->output_rect.size(), 1447 1.f/frame_device_scale_factor)); 1448 } 1449 if (ShouldSkipFrame(frame_size_in_dip)) { 1450 cc::CompositorFrameAck ack; 1451 ack.resources.swap(frame_data->resource_list); 1452 RenderWidgetHostImpl::SendSwapCompositorFrameAck( 1453 host_->GetRoutingID(), output_surface_id, 1454 host_->GetProcess()->GetID(), ack); 1455 return; 1456 } 1457 window_->layer()->SetDelegatedFrame(frame_data.Pass(), frame_size_in_dip); 1458 released_front_lock_ = NULL; 1459 current_frame_size_ = frame_size_in_dip; 1460 CheckResizeLock(); 1461 1462 if (paint_observer_) 1463 paint_observer_->OnUpdateCompositorContent(); 1464 1465 ui::Compositor* compositor = GetCompositor(); 1466 if (!compositor) { 1467 SendDelegatedFrameAck(output_surface_id); 1468 } else { 1469 compositor->SetLatencyInfo(latency_info); 1470 AddOnCommitCallbackAndDisableLocks( 1471 base::Bind(&RenderWidgetHostViewAura::SendDelegatedFrameAck, 1472 AsWeakPtr(), 1473 output_surface_id)); 1474 } 1475 DidReceiveFrameFromRenderer(); 1476 } 1477 1478 void RenderWidgetHostViewAura::SendDelegatedFrameAck(uint32 output_surface_id) { 1479 cc::CompositorFrameAck ack; 1480 window_->layer()->TakeUnusedResourcesForChildCompositor(&ack.resources); 1481 RenderWidgetHostImpl::SendSwapCompositorFrameAck( 1482 host_->GetRoutingID(), output_surface_id, 1483 host_->GetProcess()->GetID(), ack); 1484 } 1485 1486 void RenderWidgetHostViewAura::SwapSoftwareFrame( 1487 uint32 output_surface_id, 1488 scoped_ptr<cc::SoftwareFrameData> frame_data, 1489 float frame_device_scale_factor, 1490 const ui::LatencyInfo& latency_info) { 1491 const gfx::Size& frame_size = frame_data->size; 1492 const gfx::Rect& damage_rect = frame_data->damage_rect; 1493 gfx::Size frame_size_in_dip = 1494 ConvertSizeToDIP(frame_device_scale_factor, frame_size); 1495 if (ShouldSkipFrame(frame_size_in_dip)) { 1496 SendSoftwareFrameAck(output_surface_id, frame_data->id); 1497 return; 1498 } 1499 1500 const size_t size_in_bytes = 4 * frame_size.GetArea(); 1501 #ifdef OS_WIN 1502 scoped_ptr<base::SharedMemory> shared_memory( 1503 new base::SharedMemory(frame_data->handle, true, 1504 host_->GetProcess()->GetHandle())); 1505 #else 1506 scoped_ptr<base::SharedMemory> shared_memory( 1507 new base::SharedMemory(frame_data->handle, true)); 1508 #endif 1509 1510 if (!shared_memory->Map(size_in_bytes)) { 1511 host_->GetProcess()->ReceivedBadMessage(); 1512 return; 1513 } 1514 1515 if (last_swapped_surface_size_ != frame_size) { 1516 DLOG_IF(ERROR, damage_rect != gfx::Rect(frame_size)) 1517 << "Expected full damage rect"; 1518 } 1519 last_swapped_surface_size_ = frame_size; 1520 last_swapped_surface_scale_factor_ = frame_device_scale_factor; 1521 1522 scoped_refptr<MemoryHolder> holder(new MemoryHolder( 1523 shared_memory.Pass(), 1524 frame_size, 1525 base::Bind(&RenderWidgetHostViewAura::SendSoftwareFrameAck, 1526 AsWeakPtr(), 1527 output_surface_id, 1528 frame_data->id))); 1529 framebuffer_holder_.swap(holder); 1530 cc::TextureMailbox mailbox = framebuffer_holder_->GetMailbox(); 1531 DCHECK(mailbox.IsSharedMemory()); 1532 current_frame_size_ = frame_size_in_dip; 1533 1534 released_front_lock_ = NULL; 1535 CheckResizeLock(); 1536 window_->layer()->SetTextureMailbox(mailbox, frame_device_scale_factor); 1537 window_->SchedulePaintInRect( 1538 ConvertRectToDIP(frame_device_scale_factor, damage_rect)); 1539 1540 ui::Compositor* compositor = GetCompositor(); 1541 if (compositor) 1542 compositor->SetLatencyInfo(latency_info); 1543 if (paint_observer_) 1544 paint_observer_->OnUpdateCompositorContent(); 1545 DidReceiveFrameFromRenderer(); 1546 } 1547 1548 void RenderWidgetHostViewAura::SendSoftwareFrameAck( 1549 uint32 output_surface_id, unsigned software_frame_id) { 1550 cc::CompositorFrameAck ack; 1551 ack.last_software_frame_id = software_frame_id; 1552 RenderWidgetHostImpl::SendSwapCompositorFrameAck( 1553 host_->GetRoutingID(), output_surface_id, 1554 host_->GetProcess()->GetID(), ack); 1555 } 1556 1557 void RenderWidgetHostViewAura::OnSwapCompositorFrame( 1558 uint32 output_surface_id, 1559 scoped_ptr<cc::CompositorFrame> frame) { 1560 if (frame->delegated_frame_data) { 1561 SwapDelegatedFrame(output_surface_id, 1562 frame->delegated_frame_data.Pass(), 1563 frame->metadata.device_scale_factor, 1564 frame->metadata.latency_info); 1565 return; 1566 } 1567 1568 if (frame->software_frame_data) { 1569 SwapSoftwareFrame(output_surface_id, 1570 frame->software_frame_data.Pass(), 1571 frame->metadata.device_scale_factor, 1572 frame->metadata.latency_info); 1573 return; 1574 } 1575 1576 if (!frame->gl_frame_data || frame->gl_frame_data->mailbox.IsZero()) 1577 return; 1578 1579 BufferPresentedCallback ack_callback = base::Bind( 1580 &SendCompositorFrameAck, 1581 host_->GetRoutingID(), output_surface_id, host_->GetProcess()->GetID(), 1582 frame->gl_frame_data->mailbox, frame->gl_frame_data->size); 1583 1584 if (!frame->gl_frame_data->sync_point) { 1585 LOG(ERROR) << "CompositorFrame without sync point. Skipping frame..."; 1586 ack_callback.Run(true, scoped_refptr<ui::Texture>()); 1587 return; 1588 } 1589 1590 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 1591 factory->WaitSyncPoint(frame->gl_frame_data->sync_point); 1592 1593 std::string mailbox_name( 1594 reinterpret_cast<const char*>(frame->gl_frame_data->mailbox.name), 1595 sizeof(frame->gl_frame_data->mailbox.name)); 1596 BuffersSwapped(frame->gl_frame_data->size, 1597 frame->gl_frame_data->sub_buffer_rect, 1598 frame->metadata.device_scale_factor, 1599 mailbox_name, 1600 frame->metadata.latency_info, 1601 ack_callback); 1602 } 1603 1604 #if defined(OS_WIN) 1605 void RenderWidgetHostViewAura::SetParentNativeViewAccessible( 1606 gfx::NativeViewAccessible accessible_parent) { 1607 if (GetBrowserAccessibilityManager()) { 1608 GetBrowserAccessibilityManager()->ToBrowserAccessibilityManagerWin() 1609 ->set_parent_iaccessible(accessible_parent); 1610 } 1611 } 1612 #endif 1613 1614 void RenderWidgetHostViewAura::BuffersSwapped( 1615 const gfx::Size& surface_size, 1616 const gfx::Rect& damage_rect, 1617 float surface_scale_factor, 1618 const std::string& mailbox_name, 1619 const ui::LatencyInfo& latency_info, 1620 const BufferPresentedCallback& ack_callback) { 1621 scoped_refptr<ui::Texture> previous_texture(current_surface_); 1622 const gfx::Rect surface_rect = gfx::Rect(surface_size); 1623 1624 if (!SwapBuffersPrepare(surface_rect, 1625 surface_scale_factor, 1626 damage_rect, 1627 mailbox_name, 1628 ack_callback)) { 1629 return; 1630 } 1631 1632 SkRegion damage(RectToSkIRect(damage_rect)); 1633 if (!skipped_damage_.isEmpty()) { 1634 damage.op(skipped_damage_, SkRegion::kUnion_Op); 1635 skipped_damage_.setEmpty(); 1636 } 1637 1638 DCHECK(surface_rect.Contains(SkIRectToRect(damage.getBounds()))); 1639 ui::Texture* current_texture = current_surface_.get(); 1640 1641 const gfx::Size surface_size_in_pixel = surface_size; 1642 DLOG_IF(ERROR, previous_texture.get() && 1643 previous_texture->size() != current_texture->size() && 1644 SkIRectToRect(damage.getBounds()) != surface_rect) << 1645 "Expected full damage rect after size change"; 1646 if (previous_texture.get() && !previous_damage_.isEmpty() && 1647 previous_texture->size() == current_texture->size()) { 1648 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 1649 GLHelper* gl_helper = factory->GetGLHelper(); 1650 gl_helper->CopySubBufferDamage( 1651 current_texture->PrepareTexture(), 1652 previous_texture->PrepareTexture(), 1653 damage, 1654 previous_damage_); 1655 } 1656 previous_damage_ = damage; 1657 1658 ui::Compositor* compositor = GetCompositor(); 1659 if (compositor) { 1660 // Co-ordinates come in OpenGL co-ordinate space. 1661 // We need to convert to layer space. 1662 gfx::Rect rect_to_paint = 1663 ConvertRectToDIP(surface_scale_factor, 1664 gfx::Rect(damage_rect.x(), 1665 surface_size_in_pixel.height() - 1666 damage_rect.y() - damage_rect.height(), 1667 damage_rect.width(), 1668 damage_rect.height())); 1669 1670 // Damage may not have been DIP aligned, so inflate damage to compensate 1671 // for any round-off error. 1672 rect_to_paint.Inset(-1, -1); 1673 rect_to_paint.Intersect(window_->bounds()); 1674 1675 if (paint_observer_) 1676 paint_observer_->OnUpdateCompositorContent(); 1677 window_->SchedulePaintInRect(rect_to_paint); 1678 compositor->SetLatencyInfo(latency_info); 1679 } 1680 1681 SwapBuffersCompleted(ack_callback, previous_texture); 1682 } 1683 1684 void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( 1685 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel, 1686 int gpu_host_id) { 1687 gfx::Rect damage_rect(params_in_pixel.x, 1688 params_in_pixel.y, 1689 params_in_pixel.width, 1690 params_in_pixel.height); 1691 BufferPresentedCallback ack_callback = 1692 base::Bind(&AcknowledgeBufferForGpu, 1693 params_in_pixel.route_id, 1694 gpu_host_id, 1695 params_in_pixel.mailbox_name); 1696 BuffersSwapped(params_in_pixel.surface_size, 1697 damage_rect, 1698 params_in_pixel.surface_scale_factor, 1699 params_in_pixel.mailbox_name, 1700 params_in_pixel.latency_info, 1701 ack_callback); 1702 } 1703 1704 void RenderWidgetHostViewAura::AcceleratedSurfaceSuspend() { 1705 } 1706 1707 void RenderWidgetHostViewAura::AcceleratedSurfaceRelease() { 1708 // This really tells us to release the frontbuffer. 1709 if (current_surface_.get()) { 1710 ui::Compositor* compositor = GetCompositor(); 1711 if (compositor) { 1712 // We need to wait for a commit to clear to guarantee that all we 1713 // will not issue any more GL referencing the previous surface. 1714 AddOnCommitCallbackAndDisableLocks( 1715 base::Bind(&RenderWidgetHostViewAura:: 1716 SetSurfaceNotInUseByCompositor, 1717 AsWeakPtr(), 1718 current_surface_)); // Hold a ref so the texture will not 1719 // get deleted until after commit. 1720 } 1721 current_surface_ = NULL; 1722 UpdateExternalTexture(); 1723 } 1724 } 1725 1726 bool RenderWidgetHostViewAura::HasAcceleratedSurface( 1727 const gfx::Size& desired_size) { 1728 // Aura doesn't use GetBackingStore for accelerated pages, so it doesn't 1729 // matter what is returned here as GetBackingStore is the only caller of this 1730 // method. TODO(jbates) implement this if other Aura code needs it. 1731 return false; 1732 } 1733 1734 void RenderWidgetHostViewAura::SetSurfaceNotInUseByCompositor( 1735 scoped_refptr<ui::Texture>) { 1736 } 1737 1738 // static 1739 void RenderWidgetHostViewAura::CopyFromCompositingSurfaceHasResult( 1740 const gfx::Size& dst_size_in_pixel, 1741 const base::Callback<void(bool, const SkBitmap&)>& callback, 1742 scoped_ptr<cc::CopyOutputResult> result) { 1743 if (result->IsEmpty() || result->size().IsEmpty()) { 1744 callback.Run(false, SkBitmap()); 1745 return; 1746 } 1747 1748 if (result->HasTexture()) { 1749 PrepareTextureCopyOutputResult(dst_size_in_pixel, callback, result.Pass()); 1750 return; 1751 } 1752 1753 DCHECK(result->HasBitmap()); 1754 PrepareBitmapCopyOutputResult(dst_size_in_pixel, callback, result.Pass()); 1755 } 1756 1757 static void CopyFromCompositingSurfaceFinished( 1758 const base::Callback<void(bool, const SkBitmap&)>& callback, 1759 const cc::TextureMailbox::ReleaseCallback& release_callback, 1760 scoped_ptr<SkBitmap> bitmap, 1761 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock, 1762 bool result) { 1763 bitmap_pixels_lock.reset(); 1764 release_callback.Run(0, false); 1765 callback.Run(result, *bitmap); 1766 } 1767 1768 // static 1769 void RenderWidgetHostViewAura::PrepareTextureCopyOutputResult( 1770 const gfx::Size& dst_size_in_pixel, 1771 const base::Callback<void(bool, const SkBitmap&)>& callback, 1772 scoped_ptr<cc::CopyOutputResult> result) { 1773 base::ScopedClosureRunner scoped_callback_runner( 1774 base::Bind(callback, false, SkBitmap())); 1775 1776 DCHECK(result->HasTexture()); 1777 if (!result->HasTexture()) 1778 return; 1779 1780 scoped_ptr<SkBitmap> bitmap(new SkBitmap); 1781 bitmap->setConfig(SkBitmap::kARGB_8888_Config, 1782 dst_size_in_pixel.width(), dst_size_in_pixel.height()); 1783 if (!bitmap->allocPixels()) 1784 return; 1785 bitmap->setIsOpaque(true); 1786 1787 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 1788 GLHelper* gl_helper = factory->GetGLHelper(); 1789 if (!gl_helper) 1790 return; 1791 1792 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock( 1793 new SkAutoLockPixels(*bitmap)); 1794 uint8* pixels = static_cast<uint8*>(bitmap->getPixels()); 1795 1796 scoped_ptr<cc::TextureMailbox> texture_mailbox = result->TakeTexture(); 1797 DCHECK(texture_mailbox->IsTexture()); 1798 if (!texture_mailbox->IsTexture()) 1799 return; 1800 1801 scoped_callback_runner.Release(); 1802 1803 gl_helper->CropScaleReadbackAndCleanMailbox( 1804 texture_mailbox->name(), 1805 texture_mailbox->sync_point(), 1806 result->size(), 1807 gfx::Rect(result->size()), 1808 dst_size_in_pixel, 1809 pixels, 1810 base::Bind(&CopyFromCompositingSurfaceFinished, 1811 callback, 1812 texture_mailbox->callback(), 1813 base::Passed(&bitmap), 1814 base::Passed(&bitmap_pixels_lock))); 1815 } 1816 1817 // static 1818 void RenderWidgetHostViewAura::PrepareBitmapCopyOutputResult( 1819 const gfx::Size& dst_size_in_pixel, 1820 const base::Callback<void(bool, const SkBitmap&)>& callback, 1821 scoped_ptr<cc::CopyOutputResult> result) { 1822 DCHECK(result->HasBitmap()); 1823 1824 base::ScopedClosureRunner scoped_callback_runner( 1825 base::Bind(callback, false, SkBitmap())); 1826 if (!result->HasBitmap()) 1827 return; 1828 1829 scoped_ptr<SkBitmap> source = result->TakeBitmap(); 1830 DCHECK(source); 1831 if (!source) 1832 return; 1833 1834 scoped_callback_runner.Release(); 1835 1836 SkBitmap bitmap = skia::ImageOperations::Resize( 1837 *source, 1838 skia::ImageOperations::RESIZE_BEST, 1839 dst_size_in_pixel.width(), 1840 dst_size_in_pixel.height()); 1841 callback.Run(true, bitmap); 1842 } 1843 1844 static void CopyFromCompositingSurfaceFinishedForVideo( 1845 const base::Callback<void(bool)>& callback, 1846 const cc::TextureMailbox::ReleaseCallback& release_callback, 1847 bool result) { 1848 release_callback.Run(0, false); 1849 callback.Run(result); 1850 } 1851 1852 // static 1853 void RenderWidgetHostViewAura::CopyFromCompositingSurfaceHasResultForVideo( 1854 base::WeakPtr<RenderWidgetHostViewAura> rwhva, 1855 scoped_refptr<media::VideoFrame> video_frame, 1856 const base::Callback<void(bool)>& callback, 1857 scoped_ptr<cc::CopyOutputResult> result) { 1858 base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false)); 1859 1860 if (!rwhva) 1861 return; 1862 1863 if (result->IsEmpty()) 1864 return; 1865 if (result->size().IsEmpty()) 1866 return; 1867 1868 // Compute the dest size we want after the letterboxing resize. Make the 1869 // coordinates and sizes even because we letterbox in YUV space 1870 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to 1871 // line up correctly. 1872 // The video frame's coded_size() and the result's size() are both physical 1873 // pixels. 1874 gfx::Rect region_in_frame = 1875 media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()), 1876 result->size()); 1877 region_in_frame = gfx::Rect(region_in_frame.x() & ~1, 1878 region_in_frame.y() & ~1, 1879 region_in_frame.width() & ~1, 1880 region_in_frame.height() & ~1); 1881 if (region_in_frame.IsEmpty()) 1882 return; 1883 1884 // We only handle texture readbacks for now. If the compositor is in software 1885 // mode, we could produce a software-backed VideoFrame here as well. 1886 if (!result->HasTexture()) { 1887 DCHECK(result->HasBitmap()); 1888 scoped_ptr<SkBitmap> bitmap = result->TakeBitmap(); 1889 // Scale the bitmap to the required size, if necessary. 1890 SkBitmap scaled_bitmap; 1891 if (result->size().width() != region_in_frame.width() || 1892 result->size().height() != region_in_frame.height()) { 1893 skia::ImageOperations::ResizeMethod method = 1894 skia::ImageOperations::RESIZE_GOOD; 1895 scaled_bitmap = skia::ImageOperations::Resize(*bitmap.get(), method, 1896 region_in_frame.width(), 1897 region_in_frame.height()); 1898 } else { 1899 scaled_bitmap = *bitmap.get(); 1900 } 1901 1902 { 1903 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap); 1904 1905 media::CopyRGBToVideoFrame( 1906 reinterpret_cast<uint8*>(scaled_bitmap.getPixels()), 1907 scaled_bitmap.rowBytes(), 1908 region_in_frame, 1909 video_frame.get()); 1910 } 1911 scoped_callback_runner.Release(); 1912 callback.Run(true); 1913 return; 1914 } 1915 1916 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 1917 GLHelper* gl_helper = factory->GetGLHelper(); 1918 if (!gl_helper) 1919 return; 1920 1921 scoped_ptr<cc::TextureMailbox> texture_mailbox = result->TakeTexture(); 1922 DCHECK(texture_mailbox->IsTexture()); 1923 if (!texture_mailbox->IsTexture()) 1924 return; 1925 1926 gfx::Rect result_rect(result->size()); 1927 1928 content::ReadbackYUVInterface* yuv_readback_pipeline = 1929 rwhva->yuv_readback_pipeline_.get(); 1930 if (yuv_readback_pipeline == NULL || 1931 yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() || 1932 yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect || 1933 yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) { 1934 GLHelper::ScalerQuality quality = GLHelper::SCALER_QUALITY_FAST; 1935 std::string quality_switch = switches::kTabCaptureDownscaleQuality; 1936 // If we're scaling up, we can use the "best" quality. 1937 if (result_rect.size().width() < region_in_frame.size().width() && 1938 result_rect.size().height() < region_in_frame.size().height()) 1939 quality_switch = switches::kTabCaptureUpscaleQuality; 1940 1941 std::string switch_value = 1942 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(quality_switch); 1943 if (switch_value == "fast") 1944 quality = GLHelper::SCALER_QUALITY_FAST; 1945 else if (switch_value == "good") 1946 quality = GLHelper::SCALER_QUALITY_GOOD; 1947 else if (switch_value == "best") 1948 quality = GLHelper::SCALER_QUALITY_BEST; 1949 1950 rwhva->yuv_readback_pipeline_.reset( 1951 gl_helper->CreateReadbackPipelineYUV(quality, 1952 result_rect.size(), 1953 result_rect, 1954 video_frame->coded_size(), 1955 region_in_frame, 1956 true, 1957 false)); 1958 yuv_readback_pipeline = rwhva->yuv_readback_pipeline_.get(); 1959 } 1960 1961 scoped_callback_runner.Release(); 1962 base::Callback<void(bool result)> finished_callback = base::Bind( 1963 &CopyFromCompositingSurfaceFinishedForVideo, 1964 callback, 1965 texture_mailbox->callback()); 1966 yuv_readback_pipeline->ReadbackYUV( 1967 texture_mailbox->name(), 1968 texture_mailbox->sync_point(), 1969 video_frame.get(), 1970 finished_callback); 1971 } 1972 1973 void RenderWidgetHostViewAura::GetScreenInfo(WebScreenInfo* results) { 1974 GetScreenInfoForWindow(results, window_->GetRootWindow() ? window_ : NULL); 1975 } 1976 1977 gfx::Rect RenderWidgetHostViewAura::GetBoundsInRootWindow() { 1978 return window_->GetToplevelWindow()->GetBoundsInScreen(); 1979 } 1980 1981 void RenderWidgetHostViewAura::GestureEventAck(int gesture_event_type, 1982 InputEventAckState ack_result) { 1983 if (touch_editing_client_) 1984 touch_editing_client_->GestureEventAck(gesture_event_type); 1985 } 1986 1987 void RenderWidgetHostViewAura::ProcessAckedTouchEvent( 1988 const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) { 1989 ScopedVector<ui::TouchEvent> events; 1990 if (!MakeUITouchEventsFromWebTouchEvents(touch, &events, 1991 SCREEN_COORDINATES)) 1992 return; 1993 1994 aura::RootWindow* root = window_->GetRootWindow(); 1995 // |root| is NULL during tests. 1996 if (!root) 1997 return; 1998 1999 ui::EventResult result = (ack_result == 2000 INPUT_EVENT_ACK_STATE_CONSUMED) ? ui::ER_HANDLED : ui::ER_UNHANDLED; 2001 for (ScopedVector<ui::TouchEvent>::iterator iter = events.begin(), 2002 end = events.end(); iter != end; ++iter) { 2003 root->ProcessedTouchEvent((*iter), window_, result); 2004 } 2005 } 2006 2007 SmoothScrollGesture* RenderWidgetHostViewAura::CreateSmoothScrollGesture( 2008 bool scroll_down, 2009 int pixels_to_scroll, 2010 int mouse_event_x, 2011 int mouse_event_y) { 2012 return new TouchSmoothScrollGestureAura(scroll_down, 2013 pixels_to_scroll, 2014 mouse_event_x, 2015 mouse_event_y, 2016 window_); 2017 } 2018 2019 void RenderWidgetHostViewAura::SetHasHorizontalScrollbar( 2020 bool has_horizontal_scrollbar) { 2021 // Not needed. Mac-only. 2022 } 2023 2024 void RenderWidgetHostViewAura::SetScrollOffsetPinning( 2025 bool is_pinned_to_left, bool is_pinned_to_right) { 2026 // Not needed. Mac-only. 2027 } 2028 2029 void RenderWidgetHostViewAura::OnAccessibilityNotifications( 2030 const std::vector<AccessibilityHostMsg_NotificationParams>& params) { 2031 BrowserAccessibilityManager* manager = 2032 GetOrCreateBrowserAccessibilityManager(); 2033 if (manager) 2034 manager->OnAccessibilityNotifications(params); 2035 } 2036 2037 gfx::GLSurfaceHandle RenderWidgetHostViewAura::GetCompositingSurface() { 2038 if (shared_surface_handle_.is_null()) { 2039 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 2040 shared_surface_handle_ = factory->CreateSharedSurfaceHandle(); 2041 if (!shared_surface_handle_.is_null()) 2042 factory->AddObserver(this); 2043 } 2044 return shared_surface_handle_; 2045 } 2046 2047 bool RenderWidgetHostViewAura::LockMouse() { 2048 aura::RootWindow* root_window = window_->GetRootWindow(); 2049 if (!root_window) 2050 return false; 2051 2052 if (mouse_locked_) 2053 return true; 2054 2055 mouse_locked_ = true; 2056 window_->SetCapture(); 2057 aura::client::CursorClient* cursor_client = 2058 aura::client::GetCursorClient(root_window); 2059 if (cursor_client) { 2060 cursor_client->HideCursor(); 2061 cursor_client->LockCursor(); 2062 } 2063 2064 if (ShouldMoveToCenter()) { 2065 synthetic_move_sent_ = true; 2066 window_->MoveCursorTo(gfx::Rect(window_->bounds().size()).CenterPoint()); 2067 } 2068 if (aura::client::GetTooltipClient(root_window)) 2069 aura::client::GetTooltipClient(root_window)->SetTooltipsEnabled(false); 2070 return true; 2071 } 2072 2073 void RenderWidgetHostViewAura::UnlockMouse() { 2074 aura::RootWindow* root_window = window_->GetRootWindow(); 2075 if (!mouse_locked_ || !root_window) 2076 return; 2077 2078 mouse_locked_ = false; 2079 2080 window_->ReleaseCapture(); 2081 window_->MoveCursorTo(unlocked_mouse_position_); 2082 aura::client::CursorClient* cursor_client = 2083 aura::client::GetCursorClient(root_window); 2084 if (cursor_client) { 2085 cursor_client->UnlockCursor(); 2086 cursor_client->ShowCursor(); 2087 } 2088 2089 if (aura::client::GetTooltipClient(root_window)) 2090 aura::client::GetTooltipClient(root_window)->SetTooltipsEnabled(true); 2091 2092 host_->LostMouseLock(); 2093 } 2094 2095 //////////////////////////////////////////////////////////////////////////////// 2096 // RenderWidgetHostViewAura, ui::TextInputClient implementation: 2097 void RenderWidgetHostViewAura::SetCompositionText( 2098 const ui::CompositionText& composition) { 2099 if (!host_) 2100 return; 2101 2102 // ui::CompositionUnderline should be identical to 2103 // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely. 2104 COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == 2105 sizeof(WebKit::WebCompositionUnderline), 2106 ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff); 2107 2108 // TODO(suzhe): convert both renderer_host and renderer to use 2109 // ui::CompositionText. 2110 const std::vector<WebKit::WebCompositionUnderline>& underlines = 2111 reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>( 2112 composition.underlines); 2113 2114 // TODO(suzhe): due to a bug of webkit, we can't use selection range with 2115 // composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788 2116 host_->ImeSetComposition(composition.text, underlines, 2117 composition.selection.end(), 2118 composition.selection.end()); 2119 2120 has_composition_text_ = !composition.text.empty(); 2121 } 2122 2123 void RenderWidgetHostViewAura::ConfirmCompositionText() { 2124 if (host_ && has_composition_text_) 2125 host_->ImeConfirmComposition(string16(), ui::Range::InvalidRange(), false); 2126 has_composition_text_ = false; 2127 } 2128 2129 void RenderWidgetHostViewAura::ClearCompositionText() { 2130 if (host_ && has_composition_text_) 2131 host_->ImeCancelComposition(); 2132 has_composition_text_ = false; 2133 } 2134 2135 void RenderWidgetHostViewAura::InsertText(const string16& text) { 2136 DCHECK(text_input_type_ != ui::TEXT_INPUT_TYPE_NONE); 2137 if (host_) 2138 host_->ImeConfirmComposition(text, ui::Range::InvalidRange(), false); 2139 has_composition_text_ = false; 2140 } 2141 2142 void RenderWidgetHostViewAura::InsertChar(char16 ch, int flags) { 2143 if (popup_child_host_view_ && popup_child_host_view_->NeedsInputGrab()) { 2144 popup_child_host_view_->InsertChar(ch, flags); 2145 return; 2146 } 2147 2148 if (host_) { 2149 double now = ui::EventTimeForNow().InSecondsF(); 2150 // Send a WebKit::WebInputEvent::Char event to |host_|. 2151 NativeWebKeyboardEvent webkit_event(ui::ET_KEY_PRESSED, 2152 true /* is_char */, 2153 ch, 2154 flags, 2155 now); 2156 host_->ForwardKeyboardEvent(webkit_event); 2157 } 2158 } 2159 2160 gfx::NativeWindow RenderWidgetHostViewAura::GetAttachedWindow() const { 2161 return window_; 2162 } 2163 2164 ui::TextInputType RenderWidgetHostViewAura::GetTextInputType() const { 2165 return text_input_type_; 2166 } 2167 2168 ui::TextInputMode RenderWidgetHostViewAura::GetTextInputMode() const { 2169 return ui::TEXT_INPUT_MODE_DEFAULT; 2170 } 2171 2172 bool RenderWidgetHostViewAura::CanComposeInline() const { 2173 return can_compose_inline_; 2174 } 2175 2176 gfx::Rect RenderWidgetHostViewAura::ConvertRectToScreen(const gfx::Rect& rect) { 2177 gfx::Point origin = rect.origin(); 2178 gfx::Point end = gfx::Point(rect.right(), rect.bottom()); 2179 2180 aura::RootWindow* root_window = window_->GetRootWindow(); 2181 if (root_window) { 2182 aura::client::ScreenPositionClient* screen_position_client = 2183 aura::client::GetScreenPositionClient(root_window); 2184 screen_position_client->ConvertPointToScreen(window_, &origin); 2185 screen_position_client->ConvertPointToScreen(window_, &end); 2186 return gfx::Rect(origin.x(), 2187 origin.y(), 2188 end.x() - origin.x(), 2189 end.y() - origin.y()); 2190 } 2191 2192 return rect; 2193 } 2194 2195 gfx::Rect RenderWidgetHostViewAura::ConvertRectFromScreen( 2196 const gfx::Rect& rect) { 2197 gfx::Point origin = rect.origin(); 2198 gfx::Point end = gfx::Point(rect.right(), rect.bottom()); 2199 2200 aura::RootWindow* root_window = window_->GetRootWindow(); 2201 if (root_window) { 2202 aura::client::ScreenPositionClient* screen_position_client = 2203 aura::client::GetScreenPositionClient(root_window); 2204 screen_position_client->ConvertPointFromScreen(window_, &origin); 2205 screen_position_client->ConvertPointFromScreen(window_, &end); 2206 return gfx::Rect(origin.x(), 2207 origin.y(), 2208 end.x() - origin.x(), 2209 end.y() - origin.y()); 2210 } 2211 2212 return rect; 2213 } 2214 2215 gfx::Rect RenderWidgetHostViewAura::GetCaretBounds() { 2216 const gfx::Rect rect = 2217 gfx::UnionRects(selection_anchor_rect_, selection_focus_rect_); 2218 return ConvertRectToScreen(rect); 2219 } 2220 2221 bool RenderWidgetHostViewAura::GetCompositionCharacterBounds(uint32 index, 2222 gfx::Rect* rect) { 2223 DCHECK(rect); 2224 if (index >= composition_character_bounds_.size()) 2225 return false; 2226 *rect = ConvertRectToScreen(composition_character_bounds_[index]); 2227 return true; 2228 } 2229 2230 bool RenderWidgetHostViewAura::HasCompositionText() { 2231 return has_composition_text_; 2232 } 2233 2234 bool RenderWidgetHostViewAura::GetTextRange(ui::Range* range) { 2235 range->set_start(selection_text_offset_); 2236 range->set_end(selection_text_offset_ + selection_text_.length()); 2237 return true; 2238 } 2239 2240 bool RenderWidgetHostViewAura::GetCompositionTextRange(ui::Range* range) { 2241 // TODO(suzhe): implement this method when fixing http://crbug.com/55130. 2242 NOTIMPLEMENTED(); 2243 return false; 2244 } 2245 2246 bool RenderWidgetHostViewAura::GetSelectionRange(ui::Range* range) { 2247 range->set_start(selection_range_.start()); 2248 range->set_end(selection_range_.end()); 2249 return true; 2250 } 2251 2252 bool RenderWidgetHostViewAura::SetSelectionRange(const ui::Range& range) { 2253 // TODO(suzhe): implement this method when fixing http://crbug.com/55130. 2254 NOTIMPLEMENTED(); 2255 return false; 2256 } 2257 2258 bool RenderWidgetHostViewAura::DeleteRange(const ui::Range& range) { 2259 // TODO(suzhe): implement this method when fixing http://crbug.com/55130. 2260 NOTIMPLEMENTED(); 2261 return false; 2262 } 2263 2264 bool RenderWidgetHostViewAura::GetTextFromRange( 2265 const ui::Range& range, 2266 string16* text) { 2267 ui::Range selection_text_range(selection_text_offset_, 2268 selection_text_offset_ + selection_text_.length()); 2269 2270 if (!selection_text_range.Contains(range)) { 2271 text->clear(); 2272 return false; 2273 } 2274 if (selection_text_range.EqualsIgnoringDirection(range)) { 2275 // Avoid calling substr whose performance is low. 2276 *text = selection_text_; 2277 } else { 2278 *text = selection_text_.substr( 2279 range.GetMin() - selection_text_offset_, 2280 range.length()); 2281 } 2282 return true; 2283 } 2284 2285 void RenderWidgetHostViewAura::OnInputMethodChanged() { 2286 if (!host_) 2287 return; 2288 2289 if (GetInputMethod()) 2290 host_->SetInputMethodActive(GetInputMethod()->IsActive()); 2291 2292 // TODO(suzhe): implement the newly added locale property of HTML DOM 2293 // TextEvent. 2294 } 2295 2296 bool RenderWidgetHostViewAura::ChangeTextDirectionAndLayoutAlignment( 2297 base::i18n::TextDirection direction) { 2298 if (!host_) 2299 return false; 2300 host_->UpdateTextDirection( 2301 direction == base::i18n::RIGHT_TO_LEFT ? 2302 WebKit::WebTextDirectionRightToLeft : 2303 WebKit::WebTextDirectionLeftToRight); 2304 host_->NotifyTextDirection(); 2305 return true; 2306 } 2307 2308 void RenderWidgetHostViewAura::ExtendSelectionAndDelete( 2309 size_t before, size_t after) { 2310 if (host_) 2311 host_->ExtendSelectionAndDelete(before, after); 2312 } 2313 2314 void RenderWidgetHostViewAura::EnsureCaretInRect(const gfx::Rect& rect) { 2315 gfx::Rect intersected_rect( 2316 gfx::IntersectRects(rect, window_->GetBoundsInScreen())); 2317 2318 if (intersected_rect.IsEmpty()) 2319 return; 2320 2321 host_->ScrollFocusedEditableNodeIntoRect( 2322 ConvertRectFromScreen(intersected_rect)); 2323 } 2324 2325 //////////////////////////////////////////////////////////////////////////////// 2326 // RenderWidgetHostViewAura, gfx::DisplayObserver implementation: 2327 2328 void RenderWidgetHostViewAura::OnDisplayBoundsChanged( 2329 const gfx::Display& display) { 2330 gfx::Screen* screen = gfx::Screen::GetScreenFor(window_); 2331 if (display.id() == screen->GetDisplayNearestWindow(window_).id()) { 2332 UpdateScreenInfo(window_); 2333 current_cursor_.SetDisplayInfo(display); 2334 UpdateCursorIfOverSelf(); 2335 } 2336 } 2337 2338 void RenderWidgetHostViewAura::OnDisplayAdded( 2339 const gfx::Display& new_display) { 2340 } 2341 2342 void RenderWidgetHostViewAura::OnDisplayRemoved( 2343 const gfx::Display& old_display) { 2344 } 2345 2346 //////////////////////////////////////////////////////////////////////////////// 2347 // RenderWidgetHostViewAura, aura::WindowDelegate implementation: 2348 2349 gfx::Size RenderWidgetHostViewAura::GetMinimumSize() const { 2350 return gfx::Size(); 2351 } 2352 2353 gfx::Size RenderWidgetHostViewAura::GetMaximumSize() const { 2354 return gfx::Size(); 2355 } 2356 2357 void RenderWidgetHostViewAura::OnBoundsChanged(const gfx::Rect& old_bounds, 2358 const gfx::Rect& new_bounds) { 2359 // We care about this only in fullscreen mode, where there is no 2360 // WebContentsViewAura. We are sized via SetSize() or SetBounds() by 2361 // WebContentsViewAura in other cases. 2362 if (is_fullscreen_) 2363 SetSize(new_bounds.size()); 2364 } 2365 2366 gfx::NativeCursor RenderWidgetHostViewAura::GetCursor(const gfx::Point& point) { 2367 if (mouse_locked_) 2368 return ui::kCursorNone; 2369 return current_cursor_.GetNativeCursor(); 2370 } 2371 2372 int RenderWidgetHostViewAura::GetNonClientComponent( 2373 const gfx::Point& point) const { 2374 return HTCLIENT; 2375 } 2376 2377 bool RenderWidgetHostViewAura::ShouldDescendIntoChildForEventHandling( 2378 aura::Window* child, 2379 const gfx::Point& location) { 2380 return true; 2381 } 2382 2383 bool RenderWidgetHostViewAura::CanFocus() { 2384 return popup_type_ == WebKit::WebPopupTypeNone; 2385 } 2386 2387 void RenderWidgetHostViewAura::OnCaptureLost() { 2388 host_->LostCapture(); 2389 if (touch_editing_client_) 2390 touch_editing_client_->EndTouchEditing(); 2391 } 2392 2393 void RenderWidgetHostViewAura::OnPaint(gfx::Canvas* canvas) { 2394 bool has_backing_store = !!host_->GetBackingStore(false); 2395 if (has_backing_store) { 2396 paint_canvas_ = canvas; 2397 BackingStoreAura* backing_store = static_cast<BackingStoreAura*>( 2398 host_->GetBackingStore(true)); 2399 paint_canvas_ = NULL; 2400 backing_store->SkiaShowRect(gfx::Point(), canvas); 2401 2402 if (paint_observer_) 2403 paint_observer_->OnPaintComplete(); 2404 ui::Compositor* compositor = GetCompositor(); 2405 if (compositor) { 2406 compositor->SetLatencyInfo(software_latency_info_); 2407 software_latency_info_.Clear(); 2408 } 2409 } else { 2410 // For non-opaque windows, we don't draw anything, since we depend on the 2411 // canvas coming from the compositor to already be initialized as 2412 // transparent. 2413 if (window_->layer()->fills_bounds_opaquely()) 2414 canvas->DrawColor(SK_ColorWHITE); 2415 } 2416 } 2417 2418 void RenderWidgetHostViewAura::OnDeviceScaleFactorChanged( 2419 float device_scale_factor) { 2420 if (!host_) 2421 return; 2422 2423 BackingStoreAura* backing_store = static_cast<BackingStoreAura*>( 2424 host_->GetBackingStore(false)); 2425 if (backing_store) // NULL in hardware path. 2426 backing_store->ScaleFactorChanged(device_scale_factor); 2427 2428 UpdateScreenInfo(window_); 2429 2430 const gfx::Display display = gfx::Screen::GetScreenFor(window_)-> 2431 GetDisplayNearestWindow(window_); 2432 DCHECK_EQ(device_scale_factor, display.device_scale_factor()); 2433 current_cursor_.SetDisplayInfo(display); 2434 } 2435 2436 void RenderWidgetHostViewAura::OnWindowDestroying() { 2437 #if defined(OS_WIN) 2438 HWND parent = NULL; 2439 // If the tab was hidden and it's closed, host_->is_hidden would have been 2440 // reset to false in RenderWidgetHostImpl::RendererExited. 2441 if (!window_->GetRootWindow() || host_->is_hidden()) { 2442 parent = ui::GetHiddenWindow(); 2443 } else { 2444 parent = window_->GetRootWindow()->GetAcceleratedWidget(); 2445 } 2446 LPARAM lparam = reinterpret_cast<LPARAM>(this); 2447 EnumChildWindows(parent, WindowDestroyingCallback, lparam); 2448 #endif 2449 } 2450 2451 void RenderWidgetHostViewAura::OnWindowDestroyed() { 2452 host_->ViewDestroyed(); 2453 delete this; 2454 } 2455 2456 void RenderWidgetHostViewAura::OnWindowTargetVisibilityChanged(bool visible) { 2457 } 2458 2459 bool RenderWidgetHostViewAura::HasHitTestMask() const { 2460 return false; 2461 } 2462 2463 void RenderWidgetHostViewAura::GetHitTestMask(gfx::Path* mask) const { 2464 } 2465 2466 scoped_refptr<ui::Texture> RenderWidgetHostViewAura::CopyTexture() { 2467 if (!host_->is_accelerated_compositing_active()) 2468 return scoped_refptr<ui::Texture>(); 2469 2470 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 2471 GLHelper* gl_helper = factory->GetGLHelper(); 2472 if (!gl_helper) 2473 return scoped_refptr<ui::Texture>(); 2474 2475 if (!current_surface_.get()) 2476 return scoped_refptr<ui::Texture>(); 2477 2478 WebKit::WebGLId texture_id = 2479 gl_helper->CopyTexture(current_surface_->PrepareTexture(), 2480 current_surface_->size()); 2481 if (!texture_id) 2482 return scoped_refptr<ui::Texture>(); 2483 2484 return scoped_refptr<ui::Texture>( 2485 factory->CreateOwnedTexture( 2486 current_surface_->size(), 2487 current_surface_->device_scale_factor(), texture_id)); 2488 } 2489 2490 //////////////////////////////////////////////////////////////////////////////// 2491 // RenderWidgetHostViewAura, ui::EventHandler implementation: 2492 2493 void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) { 2494 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnKeyEvent"); 2495 if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event)) 2496 return; 2497 2498 if (popup_child_host_view_ && popup_child_host_view_->NeedsInputGrab()) { 2499 popup_child_host_view_->OnKeyEvent(event); 2500 if (event->handled()) 2501 return; 2502 } 2503 2504 // We need to handle the Escape key for Pepper Flash. 2505 if (is_fullscreen_ && event->key_code() == ui::VKEY_ESCAPE) { 2506 // Focus the window we were created from. 2507 if (host_tracker_.get() && !host_tracker_->windows().empty()) { 2508 aura::Window* host = *(host_tracker_->windows().begin()); 2509 aura::client::FocusClient* client = aura::client::GetFocusClient(host); 2510 if (client) { 2511 // Calling host->Focus() may delete |this|. We create a local observer 2512 // for that. In that case we exit without further access to any members. 2513 aura::WindowTracker tracker; 2514 aura::Window* window = window_; 2515 tracker.Add(window); 2516 host->Focus(); 2517 if (!tracker.Contains(window)) { 2518 event->SetHandled(); 2519 return; 2520 } 2521 } 2522 } 2523 if (!in_shutdown_) { 2524 in_shutdown_ = true; 2525 host_->Shutdown(); 2526 } 2527 } else { 2528 // We don't have to communicate with an input method here. 2529 if (!event->HasNativeEvent()) { 2530 NativeWebKeyboardEvent webkit_event( 2531 event->type(), 2532 event->is_char(), 2533 event->is_char() ? event->GetCharacter() : event->key_code(), 2534 event->flags(), 2535 ui::EventTimeForNow().InSecondsF()); 2536 host_->ForwardKeyboardEvent(webkit_event); 2537 } else { 2538 NativeWebKeyboardEvent webkit_event(event); 2539 host_->ForwardKeyboardEvent(webkit_event); 2540 } 2541 } 2542 event->SetHandled(); 2543 } 2544 2545 void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) { 2546 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnMouseEvent"); 2547 2548 if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event)) 2549 return; 2550 2551 if (mouse_locked_) { 2552 aura::client::CursorClient* cursor_client = 2553 aura::client::GetCursorClient(window_->GetRootWindow()); 2554 DCHECK(!cursor_client || !cursor_client->IsCursorVisible()); 2555 2556 if (event->type() == ui::ET_MOUSEWHEEL) { 2557 WebKit::WebMouseWheelEvent mouse_wheel_event = 2558 MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent*>(event)); 2559 if (mouse_wheel_event.deltaX != 0 || mouse_wheel_event.deltaY != 0) 2560 host_->ForwardWheelEvent(mouse_wheel_event); 2561 return; 2562 } 2563 2564 WebKit::WebMouseEvent mouse_event = MakeWebMouseEvent(event); 2565 gfx::Point center(gfx::Rect(window_->bounds().size()).CenterPoint()); 2566 2567 bool is_move_to_center_event = (event->type() == ui::ET_MOUSE_MOVED || 2568 event->type() == ui::ET_MOUSE_DRAGGED) && 2569 mouse_event.x == center.x() && mouse_event.y == center.y(); 2570 2571 ModifyEventMovementAndCoords(&mouse_event); 2572 2573 bool should_not_forward = is_move_to_center_event && synthetic_move_sent_; 2574 if (should_not_forward) { 2575 synthetic_move_sent_ = false; 2576 } else { 2577 // Check if the mouse has reached the border and needs to be centered. 2578 if (ShouldMoveToCenter()) { 2579 synthetic_move_sent_ = true; 2580 window_->MoveCursorTo(center); 2581 } 2582 // Forward event to renderer. 2583 if (CanRendererHandleEvent(event) && 2584 !(event->flags() & ui::EF_FROM_TOUCH)) 2585 host_->ForwardMouseEvent(mouse_event); 2586 } 2587 return; 2588 } 2589 2590 // As the overscroll is handled during scroll events from the trackpad, the 2591 // RWHVA window is transformed by the overscroll controller. This transform 2592 // triggers a synthetic mouse-move event to be generated (by the aura 2593 // RootWindow). But this event interferes with the overscroll gesture. So, 2594 // ignore such synthetic mouse-move events if an overscroll gesture is in 2595 // progress. 2596 if (host_->overscroll_controller() && 2597 host_->overscroll_controller()->overscroll_mode() != OVERSCROLL_NONE && 2598 event->flags() & ui::EF_IS_SYNTHESIZED && 2599 (event->type() == ui::ET_MOUSE_ENTERED || 2600 event->type() == ui::ET_MOUSE_EXITED || 2601 event->type() == ui::ET_MOUSE_MOVED)) { 2602 event->StopPropagation(); 2603 return; 2604 } 2605 2606 if (event->type() == ui::ET_MOUSEWHEEL) { 2607 #if defined(OS_WIN) 2608 // We get mouse wheel/scroll messages even if we are not in the foreground. 2609 // So here we check if we have any owned popup windows in the foreground and 2610 // dismiss them. 2611 aura::RootWindow* root_window = window_->GetRootWindow(); 2612 if (root_window) { 2613 HWND parent = root_window->GetAcceleratedWidget(); 2614 HWND toplevel_hwnd = ::GetAncestor(parent, GA_ROOT); 2615 EnumThreadWindows(GetCurrentThreadId(), 2616 DismissOwnedPopups, 2617 reinterpret_cast<LPARAM>(toplevel_hwnd)); 2618 } 2619 #endif 2620 WebKit::WebMouseWheelEvent mouse_wheel_event = 2621 MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent*>(event)); 2622 if (mouse_wheel_event.deltaX != 0 || mouse_wheel_event.deltaY != 0) 2623 host_->ForwardWheelEvent(mouse_wheel_event); 2624 } else if (CanRendererHandleEvent(event) && 2625 !(event->flags() & ui::EF_FROM_TOUCH)) { 2626 WebKit::WebMouseEvent mouse_event = MakeWebMouseEvent(event); 2627 ModifyEventMovementAndCoords(&mouse_event); 2628 host_->ForwardMouseEvent(mouse_event); 2629 } 2630 2631 switch (event->type()) { 2632 case ui::ET_MOUSE_PRESSED: 2633 window_->SetCapture(); 2634 // Confirm existing composition text on mouse click events, to make sure 2635 // the input caret won't be moved with an ongoing composition text. 2636 FinishImeCompositionSession(); 2637 break; 2638 case ui::ET_MOUSE_RELEASED: 2639 window_->ReleaseCapture(); 2640 break; 2641 default: 2642 break; 2643 } 2644 2645 // Needed to propagate mouse event to native_tab_contents_view_aura. 2646 // TODO(pkotwicz): Find a better way of doing this. 2647 // In fullscreen mode which is typically used by flash, don't forward 2648 // the mouse events to the parent. The renderer and the plugin process 2649 // handle these events. 2650 if (!is_fullscreen_ && window_->parent()->delegate() && 2651 !(event->flags() & ui::EF_FROM_TOUCH)) 2652 window_->parent()->delegate()->OnMouseEvent(event); 2653 2654 if (!IsXButtonUpEvent(event)) 2655 event->SetHandled(); 2656 } 2657 2658 void RenderWidgetHostViewAura::OnScrollEvent(ui::ScrollEvent* event) { 2659 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnScrollEvent"); 2660 if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event)) 2661 return; 2662 2663 if (event->type() == ui::ET_SCROLL) { 2664 if (event->finger_count() != 2) 2665 return; 2666 WebKit::WebGestureEvent gesture_event = 2667 MakeWebGestureEventFlingCancel(); 2668 host_->ForwardGestureEvent(gesture_event); 2669 WebKit::WebMouseWheelEvent mouse_wheel_event = 2670 MakeWebMouseWheelEvent(event); 2671 host_->ForwardWheelEvent(mouse_wheel_event); 2672 RecordAction(UserMetricsAction("TrackpadScroll")); 2673 } else if (event->type() == ui::ET_SCROLL_FLING_START || 2674 event->type() == ui::ET_SCROLL_FLING_CANCEL) { 2675 WebKit::WebGestureEvent gesture_event = 2676 MakeWebGestureEvent(event); 2677 host_->ForwardGestureEvent(gesture_event); 2678 if (event->type() == ui::ET_SCROLL_FLING_START) 2679 RecordAction(UserMetricsAction("TrackpadScrollFling")); 2680 } 2681 2682 event->SetHandled(); 2683 } 2684 2685 void RenderWidgetHostViewAura::OnTouchEvent(ui::TouchEvent* event) { 2686 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnTouchEvent"); 2687 if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event)) 2688 return; 2689 2690 // Update the touch event first. 2691 WebKit::WebTouchPoint* point = UpdateWebTouchEventFromUIEvent(*event, 2692 &touch_event_); 2693 2694 // Forward the touch event only if a touch point was updated, and there's a 2695 // touch-event handler in the page, and no other touch-event is in the queue. 2696 // It is important to always consume the event if there is a touch-event 2697 // handler in the page, or some touch-event is already in the queue, even if 2698 // no point has been updated, to make sure that this event does not get 2699 // processed by the gesture recognizer before the events in the queue. 2700 if (host_->ShouldForwardTouchEvent()) 2701 event->StopPropagation(); 2702 2703 if (point) { 2704 if (host_->ShouldForwardTouchEvent()) 2705 host_->ForwardTouchEventWithLatencyInfo(touch_event_, *event->latency()); 2706 UpdateWebTouchEventAfterDispatch(&touch_event_, point); 2707 } 2708 } 2709 2710 void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) { 2711 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnGestureEvent"); 2712 // Pinch gestures are currently disabled by default. See crbug.com/128477. 2713 if ((event->type() == ui::ET_GESTURE_PINCH_BEGIN || 2714 event->type() == ui::ET_GESTURE_PINCH_UPDATE || 2715 event->type() == ui::ET_GESTURE_PINCH_END) && !ShouldSendPinchGesture()) { 2716 event->SetHandled(); 2717 return; 2718 } 2719 2720 if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event)) 2721 return; 2722 2723 RenderViewHostDelegate* delegate = NULL; 2724 if (popup_type_ == WebKit::WebPopupTypeNone && !is_fullscreen_) 2725 delegate = RenderViewHost::From(host_)->GetDelegate(); 2726 2727 if (delegate && event->type() == ui::ET_GESTURE_BEGIN && 2728 event->details().touch_points() == 1) { 2729 delegate->HandleGestureBegin(); 2730 } 2731 2732 WebKit::WebGestureEvent gesture = MakeWebGestureEvent(event); 2733 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { 2734 // Webkit does not stop a fling-scroll on tap-down. So explicitly send an 2735 // event to stop any in-progress flings. 2736 WebKit::WebGestureEvent fling_cancel = gesture; 2737 fling_cancel.type = WebKit::WebInputEvent::GestureFlingCancel; 2738 fling_cancel.sourceDevice = WebKit::WebGestureEvent::Touchscreen; 2739 host_->ForwardGestureEvent(fling_cancel); 2740 } 2741 2742 if (gesture.type != WebKit::WebInputEvent::Undefined) { 2743 host_->ForwardGestureEventWithLatencyInfo(gesture, *event->latency()); 2744 2745 if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || 2746 event->type() == ui::ET_GESTURE_SCROLL_UPDATE || 2747 event->type() == ui::ET_GESTURE_SCROLL_END) { 2748 RecordAction(UserMetricsAction("TouchscreenScroll")); 2749 } else if (event->type() == ui::ET_SCROLL_FLING_START) { 2750 RecordAction(UserMetricsAction("TouchscreenScrollFling")); 2751 } 2752 } 2753 2754 if (delegate && event->type() == ui::ET_GESTURE_END && 2755 event->details().touch_points() == 1) { 2756 delegate->HandleGestureEnd(); 2757 } 2758 2759 // If a gesture is not processed by the webpage, then WebKit processes it 2760 // (e.g. generates synthetic mouse events). 2761 event->SetHandled(); 2762 } 2763 2764 //////////////////////////////////////////////////////////////////////////////// 2765 // RenderWidgetHostViewAura, aura::client::ActivationDelegate implementation: 2766 2767 bool RenderWidgetHostViewAura::ShouldActivate() const { 2768 aura::RootWindow* root_window = window_->GetRootWindow(); 2769 if (!root_window) 2770 return true; 2771 const ui::Event* event = root_window->current_event(); 2772 if (!event) 2773 return true; 2774 return is_fullscreen_; 2775 } 2776 2777 //////////////////////////////////////////////////////////////////////////////// 2778 // RenderWidgetHostViewAura, 2779 // aura::client::ActivationChangeObserver implementation: 2780 2781 void RenderWidgetHostViewAura::OnWindowActivated(aura::Window* gained_active, 2782 aura::Window* lost_active) { 2783 DCHECK(window_ == gained_active || window_ == lost_active); 2784 if (window_ == gained_active) { 2785 const ui::Event* event = window_->GetRootWindow()->current_event(); 2786 if (event && PointerEventActivates(*event)) 2787 host_->OnPointerEventActivate(); 2788 } 2789 } 2790 2791 //////////////////////////////////////////////////////////////////////////////// 2792 // RenderWidgetHostViewAura, aura::client::CursorClientObserver implementation: 2793 2794 void RenderWidgetHostViewAura::OnCursorVisibilityChanged(bool is_visible) { 2795 NotifyRendererOfCursorVisibilityState(is_visible); 2796 } 2797 2798 //////////////////////////////////////////////////////////////////////////////// 2799 // RenderWidgetHostViewAura, aura::client::FocusChangeObserver implementation: 2800 2801 void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus, 2802 aura::Window* lost_focus) { 2803 DCHECK(window_ == gained_focus || window_ == lost_focus); 2804 if (window_ == gained_focus) { 2805 // We need to honor input bypass if the associated tab is does not want 2806 // input. This gives the current focused window a chance to be the text 2807 // input client and handle events. 2808 if (host_->ignore_input_events()) 2809 return; 2810 2811 host_->GotFocus(); 2812 host_->SetActive(true); 2813 2814 ui::InputMethod* input_method = GetInputMethod(); 2815 if (input_method) { 2816 // Ask the system-wide IME to send all TextInputClient messages to |this| 2817 // object. 2818 input_method->SetFocusedTextInputClient(this); 2819 host_->SetInputMethodActive(input_method->IsActive()); 2820 2821 // Often the application can set focus to the view in response to a key 2822 // down. However the following char event shouldn't be sent to the web 2823 // page. 2824 host_->SuppressNextCharEvents(); 2825 } else { 2826 host_->SetInputMethodActive(false); 2827 } 2828 } else if (window_ == lost_focus) { 2829 host_->SetActive(false); 2830 host_->Blur(); 2831 2832 DetachFromInputMethod(); 2833 host_->SetInputMethodActive(false); 2834 2835 if (touch_editing_client_) 2836 touch_editing_client_->EndTouchEditing(); 2837 2838 // If we lose the focus while fullscreen, close the window; Pepper Flash 2839 // won't do it for us (unlike NPAPI Flash). However, we do not close the 2840 // window if we lose the focus to a window on another display. 2841 gfx::Screen* screen = gfx::Screen::GetScreenFor(window_); 2842 bool focusing_other_display = 2843 gained_focus && screen->GetNumDisplays() > 1 && 2844 (screen->GetDisplayNearestWindow(window_).id() != 2845 screen->GetDisplayNearestWindow(gained_focus).id()); 2846 if (is_fullscreen_ && !in_shutdown_ && !focusing_other_display) { 2847 in_shutdown_ = true; 2848 host_->Shutdown(); 2849 } 2850 } 2851 } 2852 2853 //////////////////////////////////////////////////////////////////////////////// 2854 // RenderWidgetHostViewAura, aura::RootWindowObserver implementation: 2855 2856 void RenderWidgetHostViewAura::OnRootWindowHostMoved( 2857 const aura::RootWindow* root, 2858 const gfx::Point& new_origin) { 2859 UpdateScreenInfo(window_); 2860 } 2861 2862 //////////////////////////////////////////////////////////////////////////////// 2863 // RenderWidgetHostViewAura, ui::CompositorObserver implementation: 2864 2865 void RenderWidgetHostViewAura::OnCompositingDidCommit( 2866 ui::Compositor* compositor) { 2867 if (can_lock_compositor_ == NO_PENDING_COMMIT) { 2868 can_lock_compositor_ = YES; 2869 if (resize_lock_.get() && resize_lock_->GrabDeferredLock()) 2870 can_lock_compositor_ = YES_DID_LOCK; 2871 } 2872 RunOnCommitCallbacks(); 2873 if (resize_lock_ && resize_lock_->expected_size() == current_frame_size_) { 2874 resize_lock_.reset(); 2875 host_->WasResized(); 2876 // We may have had a resize while we had the lock (e.g. if the lock expired, 2877 // or if the UI still gave us some resizes), so make sure we grab a new lock 2878 // if necessary. 2879 MaybeCreateResizeLock(); 2880 } 2881 } 2882 2883 void RenderWidgetHostViewAura::OnCompositingStarted( 2884 ui::Compositor* compositor, base::TimeTicks start_time) { 2885 last_draw_ended_ = start_time; 2886 } 2887 2888 void RenderWidgetHostViewAura::OnCompositingEnded( 2889 ui::Compositor* compositor) { 2890 if (paint_observer_) 2891 paint_observer_->OnCompositingComplete(); 2892 } 2893 2894 void RenderWidgetHostViewAura::OnCompositingAborted( 2895 ui::Compositor* compositor) { 2896 } 2897 2898 void RenderWidgetHostViewAura::OnCompositingLockStateChanged( 2899 ui::Compositor* compositor) { 2900 // A compositor lock that is part of a resize lock timed out. We 2901 // should display a renderer frame. 2902 if (!compositor->IsLocked() && can_lock_compositor_ == YES_DID_LOCK) { 2903 can_lock_compositor_ = NO_PENDING_RENDERER_FRAME; 2904 } 2905 } 2906 2907 void RenderWidgetHostViewAura::OnUpdateVSyncParameters( 2908 ui::Compositor* compositor, 2909 base::TimeTicks timebase, 2910 base::TimeDelta interval) { 2911 if (IsShowing() && !last_draw_ended_.is_null()) 2912 host_->UpdateVSyncParameters(last_draw_ended_, interval); 2913 } 2914 2915 //////////////////////////////////////////////////////////////////////////////// 2916 // RenderWidgetHostViewAura, BrowserAccessibilityDelegate implementation: 2917 2918 void RenderWidgetHostViewAura::SetAccessibilityFocus(int acc_obj_id) { 2919 if (!host_) 2920 return; 2921 2922 host_->AccessibilitySetFocus(acc_obj_id); 2923 } 2924 2925 void RenderWidgetHostViewAura::AccessibilityDoDefaultAction(int acc_obj_id) { 2926 if (!host_) 2927 return; 2928 2929 host_->AccessibilityDoDefaultAction(acc_obj_id); 2930 } 2931 2932 void RenderWidgetHostViewAura::AccessibilityScrollToMakeVisible( 2933 int acc_obj_id, gfx::Rect subfocus) { 2934 if (!host_) 2935 return; 2936 2937 host_->AccessibilityScrollToMakeVisible(acc_obj_id, subfocus); 2938 } 2939 2940 void RenderWidgetHostViewAura::AccessibilityScrollToPoint( 2941 int acc_obj_id, gfx::Point point) { 2942 if (!host_) 2943 return; 2944 2945 host_->AccessibilityScrollToPoint(acc_obj_id, point); 2946 } 2947 2948 void RenderWidgetHostViewAura::AccessibilitySetTextSelection( 2949 int acc_obj_id, int start_offset, int end_offset) { 2950 if (!host_) 2951 return; 2952 2953 host_->AccessibilitySetTextSelection( 2954 acc_obj_id, start_offset, end_offset); 2955 } 2956 2957 gfx::Point RenderWidgetHostViewAura::GetLastTouchEventLocation() const { 2958 // Only needed for Win 8 non-aura. 2959 return gfx::Point(); 2960 } 2961 2962 void RenderWidgetHostViewAura::FatalAccessibilityTreeError() { 2963 host_->FatalAccessibilityTreeError(); 2964 SetBrowserAccessibilityManager(NULL); 2965 } 2966 2967 //////////////////////////////////////////////////////////////////////////////// 2968 // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation: 2969 2970 void RenderWidgetHostViewAura::OnLostResources() { 2971 current_surface_ = NULL; 2972 UpdateExternalTexture(); 2973 2974 // Make sure all ImageTransportClients are deleted now that the context those 2975 // are using is becoming invalid. This sends pending ACKs and needs to happen 2976 // after calling UpdateExternalTexture() which syncs with the impl thread. 2977 RunOnCommitCallbacks(); 2978 2979 DCHECK(!shared_surface_handle_.is_null()); 2980 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 2981 factory->DestroySharedSurfaceHandle(shared_surface_handle_); 2982 shared_surface_handle_ = factory->CreateSharedSurfaceHandle(); 2983 host_->CompositingSurfaceUpdated(); 2984 host_->ScheduleComposite(); 2985 } 2986 2987 //////////////////////////////////////////////////////////////////////////////// 2988 // RenderWidgetHostViewAura, private: 2989 2990 RenderWidgetHostViewAura::~RenderWidgetHostViewAura() { 2991 if (paint_observer_) 2992 paint_observer_->OnViewDestroyed(); 2993 if (touch_editing_client_) 2994 touch_editing_client_->OnViewDestroyed(); 2995 if (!shared_surface_handle_.is_null()) { 2996 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 2997 factory->DestroySharedSurfaceHandle(shared_surface_handle_); 2998 factory->RemoveObserver(this); 2999 } 3000 window_observer_.reset(); 3001 #if defined(OS_WIN) 3002 transient_observer_.reset(); 3003 #endif 3004 if (window_->GetRootWindow()) 3005 window_->GetRootWindow()->RemoveRootWindowObserver(this); 3006 UnlockMouse(); 3007 if (popup_type_ != WebKit::WebPopupTypeNone && popup_parent_host_view_) { 3008 DCHECK(popup_parent_host_view_->popup_child_host_view_ == NULL || 3009 popup_parent_host_view_->popup_child_host_view_ == this); 3010 popup_parent_host_view_->popup_child_host_view_ = NULL; 3011 } 3012 if (popup_child_host_view_) { 3013 DCHECK(popup_child_host_view_->popup_parent_host_view_ == NULL || 3014 popup_child_host_view_->popup_parent_host_view_ == this); 3015 popup_child_host_view_->popup_parent_host_view_ = NULL; 3016 } 3017 aura::client::SetTooltipText(window_, NULL); 3018 gfx::Screen::GetScreenFor(window_)->RemoveObserver(this); 3019 3020 // This call is usually no-op since |this| object is already removed from the 3021 // Aura root window and we don't have a way to get an input method object 3022 // associated with the window, but just in case. 3023 DetachFromInputMethod(); 3024 } 3025 3026 void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() { 3027 const gfx::Point screen_point = 3028 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 3029 aura::RootWindow* root_window = window_->GetRootWindow(); 3030 if (!root_window) 3031 return; 3032 3033 gfx::Rect screen_rect = GetViewBounds(); 3034 gfx::Point local_point = screen_point; 3035 local_point.Offset(-screen_rect.x(), -screen_rect.y()); 3036 3037 if (root_window->GetEventHandlerForPoint(local_point) != window_) 3038 return; 3039 3040 gfx::NativeCursor cursor = current_cursor_.GetNativeCursor(); 3041 // Do not show loading cursor when the cursor is currently hidden. 3042 if (is_loading_ && cursor != ui::kCursorNone) 3043 cursor = ui::kCursorPointer; 3044 3045 aura::client::CursorClient* cursor_client = 3046 aura::client::GetCursorClient(root_window); 3047 if (cursor_client) { 3048 cursor_client->SetCursor(cursor); 3049 } 3050 } 3051 3052 ui::InputMethod* RenderWidgetHostViewAura::GetInputMethod() const { 3053 aura::RootWindow* root_window = window_->GetRootWindow(); 3054 if (!root_window) 3055 return NULL; 3056 return root_window->GetProperty(aura::client::kRootWindowInputMethodKey); 3057 } 3058 3059 bool RenderWidgetHostViewAura::NeedsInputGrab() { 3060 return popup_type_ == WebKit::WebPopupTypeSelect; 3061 } 3062 3063 void RenderWidgetHostViewAura::FinishImeCompositionSession() { 3064 if (!has_composition_text_) 3065 return; 3066 if (host_) 3067 host_->ImeConfirmComposition(string16(), ui::Range::InvalidRange(), false); 3068 ImeCancelComposition(); 3069 } 3070 3071 void RenderWidgetHostViewAura::ModifyEventMovementAndCoords( 3072 WebKit::WebMouseEvent* event) { 3073 // If the mouse has just entered, we must report zero movementX/Y. Hence we 3074 // reset any global_mouse_position set previously. 3075 if (event->type == WebKit::WebInputEvent::MouseEnter || 3076 event->type == WebKit::WebInputEvent::MouseLeave) 3077 global_mouse_position_.SetPoint(event->globalX, event->globalY); 3078 3079 // Movement is computed by taking the difference of the new cursor position 3080 // and the previous. Under mouse lock the cursor will be warped back to the 3081 // center so that we are not limited by clipping boundaries. 3082 // We do not measure movement as the delta from cursor to center because 3083 // we may receive more mouse movement events before our warp has taken 3084 // effect. 3085 event->movementX = event->globalX - global_mouse_position_.x(); 3086 event->movementY = event->globalY - global_mouse_position_.y(); 3087 3088 global_mouse_position_.SetPoint(event->globalX, event->globalY); 3089 3090 // Under mouse lock, coordinates of mouse are locked to what they were when 3091 // mouse lock was entered. 3092 if (mouse_locked_) { 3093 event->x = unlocked_mouse_position_.x(); 3094 event->y = unlocked_mouse_position_.y(); 3095 event->windowX = unlocked_mouse_position_.x(); 3096 event->windowY = unlocked_mouse_position_.y(); 3097 event->globalX = unlocked_global_mouse_position_.x(); 3098 event->globalY = unlocked_global_mouse_position_.y(); 3099 } else { 3100 unlocked_mouse_position_.SetPoint(event->windowX, event->windowY); 3101 unlocked_global_mouse_position_.SetPoint(event->globalX, event->globalY); 3102 } 3103 } 3104 3105 void RenderWidgetHostViewAura::NotifyRendererOfCursorVisibilityState( 3106 bool is_visible) { 3107 if (host_->is_hidden() || 3108 (cursor_visibility_state_in_renderer_ == VISIBLE && is_visible) || 3109 (cursor_visibility_state_in_renderer_ == NOT_VISIBLE && !is_visible)) 3110 return; 3111 3112 cursor_visibility_state_in_renderer_ = is_visible ? VISIBLE : NOT_VISIBLE; 3113 host_->SendCursorVisibilityState(is_visible); 3114 } 3115 3116 void RenderWidgetHostViewAura::SchedulePaintIfNotInClip( 3117 const gfx::Rect& rect, 3118 const gfx::Rect& clip) { 3119 if (!clip.IsEmpty()) { 3120 gfx::Rect to_paint = gfx::SubtractRects(rect, clip); 3121 if (!to_paint.IsEmpty()) 3122 window_->SchedulePaintInRect(to_paint); 3123 } else { 3124 window_->SchedulePaintInRect(rect); 3125 } 3126 } 3127 3128 bool RenderWidgetHostViewAura::ShouldMoveToCenter() { 3129 gfx::Rect rect = window_->bounds(); 3130 rect = ConvertRectToScreen(rect); 3131 int border_x = rect.width() * kMouseLockBorderPercentage / 100; 3132 int border_y = rect.height() * kMouseLockBorderPercentage / 100; 3133 3134 return global_mouse_position_.x() < rect.x() + border_x || 3135 global_mouse_position_.x() > rect.right() - border_x || 3136 global_mouse_position_.y() < rect.y() + border_y || 3137 global_mouse_position_.y() > rect.bottom() - border_y; 3138 } 3139 3140 void RenderWidgetHostViewAura::RunOnCommitCallbacks() { 3141 for (std::vector<base::Closure>::const_iterator 3142 it = on_compositing_did_commit_callbacks_.begin(); 3143 it != on_compositing_did_commit_callbacks_.end(); ++it) { 3144 it->Run(); 3145 } 3146 on_compositing_did_commit_callbacks_.clear(); 3147 } 3148 3149 void RenderWidgetHostViewAura::AddOnCommitCallbackAndDisableLocks( 3150 const base::Closure& callback) { 3151 ui::Compositor* compositor = GetCompositor(); 3152 DCHECK(compositor); 3153 3154 if (!compositor->HasObserver(this)) 3155 compositor->AddObserver(this); 3156 3157 can_lock_compositor_ = NO_PENDING_COMMIT; 3158 on_compositing_did_commit_callbacks_.push_back(callback); 3159 } 3160 3161 void RenderWidgetHostViewAura::AddedToRootWindow() { 3162 window_->GetRootWindow()->AddRootWindowObserver(this); 3163 host_->ParentChanged(GetNativeViewId()); 3164 UpdateScreenInfo(window_); 3165 if (popup_type_ != WebKit::WebPopupTypeNone) 3166 event_filter_for_popup_exit_.reset(new EventFilterForPopupExit(this)); 3167 3168 aura::client::CursorClient* cursor_client = 3169 aura::client::GetCursorClient(window_->GetRootWindow()); 3170 if (cursor_client) { 3171 cursor_client->AddObserver(this); 3172 NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible()); 3173 } 3174 UpdateExternalTexture(); 3175 } 3176 3177 void RenderWidgetHostViewAura::RemovingFromRootWindow() { 3178 aura::client::CursorClient* cursor_client = 3179 aura::client::GetCursorClient(window_->GetRootWindow()); 3180 if (cursor_client) 3181 cursor_client->RemoveObserver(this); 3182 3183 event_filter_for_popup_exit_.reset(); 3184 window_->GetRootWindow()->RemoveRootWindowObserver(this); 3185 host_->ParentChanged(0); 3186 ui::Compositor* compositor = GetCompositor(); 3187 // We can't get notification for commits after this point, which would 3188 // guarantee that the compositor isn't using an old texture any more, so 3189 // instead we force the texture to NULL which synchronizes with the compositor 3190 // thread, and makes it safe to run the callback. 3191 window_->layer()->SetExternalTexture(NULL); 3192 RunOnCommitCallbacks(); 3193 resize_lock_.reset(); 3194 host_->WasResized(); 3195 if (compositor && compositor->HasObserver(this)) 3196 compositor->RemoveObserver(this); 3197 } 3198 3199 ui::Compositor* RenderWidgetHostViewAura::GetCompositor() const { 3200 aura::RootWindow* root_window = window_->GetRootWindow(); 3201 return root_window ? root_window->compositor() : NULL; 3202 } 3203 3204 void RenderWidgetHostViewAura::DetachFromInputMethod() { 3205 ui::InputMethod* input_method = GetInputMethod(); 3206 if (input_method && input_method->GetTextInputClient() == this) 3207 input_method->SetFocusedTextInputClient(NULL); 3208 } 3209 3210 //////////////////////////////////////////////////////////////////////////////// 3211 // RenderWidgetHostView, public: 3212 3213 // static 3214 RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( 3215 RenderWidgetHost* widget) { 3216 return new RenderWidgetHostViewAura(widget); 3217 } 3218 3219 // static 3220 void RenderWidgetHostViewPort::GetDefaultScreenInfo(WebScreenInfo* results) { 3221 GetScreenInfoForWindow(results, NULL); 3222 } 3223 3224 } // namespace content 3225