web_contents_view_aura.cc revision bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/browser/web_contents/web_contents_view_aura.h" 6 7#include "base/auto_reset.h" 8#include "base/command_line.h" 9#include "base/metrics/histogram.h" 10#include "base/strings/utf_string_conversions.h" 11#include "content/browser/renderer_host/dip_util.h" 12#include "content/browser/renderer_host/overscroll_controller.h" 13#include "content/browser/renderer_host/render_view_host_factory.h" 14#include "content/browser/renderer_host/render_view_host_impl.h" 15#include "content/browser/renderer_host/render_widget_host_impl.h" 16#include "content/browser/renderer_host/render_widget_host_view_aura.h" 17#include "content/browser/web_contents/aura/image_window_delegate.h" 18#include "content/browser/web_contents/aura/shadow_layer_delegate.h" 19#include "content/browser/web_contents/aura/window_slider.h" 20#include "content/browser/web_contents/interstitial_page_impl.h" 21#include "content/browser/web_contents/navigation_entry_impl.h" 22#include "content/browser/web_contents/touch_editable_impl_aura.h" 23#include "content/browser/web_contents/web_contents_impl.h" 24#include "content/public/browser/notification_observer.h" 25#include "content/public/browser/notification_registrar.h" 26#include "content/public/browser/notification_source.h" 27#include "content/public/browser/notification_types.h" 28#include "content/public/browser/overscroll_configuration.h" 29#include "content/public/browser/render_view_host.h" 30#include "content/public/browser/render_widget_host.h" 31#include "content/public/browser/render_widget_host_view.h" 32#include "content/public/browser/web_contents_delegate.h" 33#include "content/public/browser/web_contents_observer.h" 34#include "content/public/browser/web_contents_view_delegate.h" 35#include "content/public/browser/web_drag_dest_delegate.h" 36#include "content/public/common/content_switches.h" 37#include "content/public/common/drop_data.h" 38#include "third_party/WebKit/public/web/WebInputEvent.h" 39#include "ui/aura/client/aura_constants.h" 40#include "ui/aura/client/drag_drop_client.h" 41#include "ui/aura/client/drag_drop_delegate.h" 42#include "ui/aura/root_window.h" 43#include "ui/aura/root_window_observer.h" 44#include "ui/aura/window.h" 45#include "ui/aura/window_observer.h" 46#include "ui/base/clipboard/clipboard.h" 47#include "ui/base/clipboard/custom_data_helper.h" 48#include "ui/base/dragdrop/drag_drop_types.h" 49#include "ui/base/dragdrop/drag_utils.h" 50#include "ui/base/dragdrop/os_exchange_data.h" 51#include "ui/base/events/event.h" 52#include "ui/base/events/event_utils.h" 53#include "ui/base/hit_test.h" 54#include "ui/compositor/layer.h" 55#include "ui/compositor/scoped_layer_animation_settings.h" 56#include "ui/gfx/canvas.h" 57#include "ui/gfx/image/image.h" 58#include "ui/gfx/image/image_png_rep.h" 59#include "ui/gfx/image/image_skia.h" 60#include "ui/gfx/screen.h" 61 62namespace content { 63WebContentsViewPort* CreateWebContentsView( 64 WebContentsImpl* web_contents, 65 WebContentsViewDelegate* delegate, 66 RenderViewHostDelegateView** render_view_host_delegate_view) { 67 WebContentsViewAura* rv = new WebContentsViewAura(web_contents, delegate); 68 *render_view_host_delegate_view = rv; 69 return rv; 70} 71 72namespace { 73 74bool IsScrollEndEffectEnabled() { 75 return CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 76 switches::kScrollEndEffect) == "1"; 77} 78 79bool ShouldNavigateForward(const NavigationController& controller, 80 OverscrollMode mode) { 81 return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) && 82 controller.CanGoForward(); 83} 84 85bool ShouldNavigateBack(const NavigationController& controller, 86 OverscrollMode mode) { 87 return mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST) && 88 controller.CanGoBack(); 89} 90 91RenderWidgetHostViewAura* ToRenderWidgetHostViewAura( 92 RenderWidgetHostView* view) { 93 if (!view || RenderViewHostFactory::has_factory()) 94 return NULL; // Can't cast to RenderWidgetHostViewAura in unit tests. 95 RenderProcessHostImpl* process = static_cast<RenderProcessHostImpl*>( 96 view->GetRenderWidgetHost()->GetProcess()); 97 if (process->IsGuest()) 98 return NULL; 99 return static_cast<RenderWidgetHostViewAura*>(view); 100} 101 102// The window delegate for the overscroll window. This redirects trackpad events 103// to the web-contents window. The delegate destroys itself when the window is 104// destroyed. 105class OverscrollWindowDelegate : public ImageWindowDelegate { 106 public: 107 OverscrollWindowDelegate(WebContentsImpl* web_contents, 108 OverscrollMode overscroll_mode) 109 : web_contents_(web_contents), 110 forward_events_(true) { 111 const NavigationControllerImpl& controller = web_contents->GetController(); 112 const NavigationEntryImpl* entry = NULL; 113 if (ShouldNavigateForward(controller, overscroll_mode)) { 114 entry = NavigationEntryImpl::FromNavigationEntry( 115 controller.GetEntryAtOffset(1)); 116 } else if (ShouldNavigateBack(controller, overscroll_mode)) { 117 entry = NavigationEntryImpl::FromNavigationEntry( 118 controller.GetEntryAtOffset(-1)); 119 } 120 121 gfx::Image image; 122 if (entry && entry->screenshot().get()) { 123 std::vector<gfx::ImagePNGRep> image_reps; 124 image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(), 125 ui::GetScaleFactorForNativeView(web_contents_window()))); 126 image = gfx::Image(image_reps); 127 } 128 SetImage(image); 129 } 130 131 void stop_forwarding_events() { forward_events_ = false; } 132 133 private: 134 virtual ~OverscrollWindowDelegate() {} 135 136 aura::Window* web_contents_window() { 137 return web_contents_->GetView()->GetContentNativeView(); 138 } 139 140 // Overridden from ui::EventHandler. 141 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE { 142 if (forward_events_ && web_contents_window()) 143 web_contents_window()->delegate()->OnScrollEvent(event); 144 } 145 146 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 147 if (forward_events_ && web_contents_window()) 148 web_contents_window()->delegate()->OnGestureEvent(event); 149 } 150 151 WebContents* web_contents_; 152 153 // The window is displayed both during the gesture, and after the gesture 154 // while the navigation is in progress. During the gesture, it is necessary to 155 // forward input events to the content page (e.g. when the overscroll window 156 // slides under the cursor and starts receiving scroll events). However, once 157 // the gesture is complete, and the window is being displayed as an overlay 158 // window during navigation, events should not be forwarded anymore. 159 bool forward_events_; 160 161 DISALLOW_COPY_AND_ASSIGN(OverscrollWindowDelegate); 162}; 163 164// Listens to all mouse drag events during a drag and drop and sends them to 165// the renderer. 166class WebDragSourceAura : public base::MessageLoopForUI::Observer, 167 public NotificationObserver { 168 public: 169 WebDragSourceAura(aura::Window* window, WebContentsImpl* contents) 170 : window_(window), 171 contents_(contents) { 172 base::MessageLoopForUI::current()->AddObserver(this); 173 registrar_.Add(this, 174 NOTIFICATION_WEB_CONTENTS_DISCONNECTED, 175 Source<WebContents>(contents)); 176 } 177 178 virtual ~WebDragSourceAura() { 179 base::MessageLoopForUI::current()->RemoveObserver(this); 180 } 181 182 // MessageLoop::Observer implementation: 183 virtual base::EventStatus WillProcessEvent( 184 const base::NativeEvent& event) OVERRIDE { 185 return base::EVENT_CONTINUE; 186 } 187 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE { 188 if (!contents_) 189 return; 190 ui::EventType type = ui::EventTypeFromNative(event); 191 RenderViewHost* rvh = NULL; 192 switch (type) { 193 case ui::ET_MOUSE_DRAGGED: 194 rvh = contents_->GetRenderViewHost(); 195 if (rvh) { 196 gfx::Point screen_loc_in_pixel = ui::EventLocationFromNative(event); 197 gfx::Point screen_loc = ConvertViewPointToDIP(rvh->GetView(), 198 screen_loc_in_pixel); 199 gfx::Point client_loc = screen_loc; 200 aura::Window* window = rvh->GetView()->GetNativeView(); 201 aura::Window::ConvertPointToTarget(window->GetRootWindow(), 202 window, &client_loc); 203 contents_->DragSourceMovedTo(client_loc.x(), client_loc.y(), 204 screen_loc.x(), screen_loc.y()); 205 } 206 break; 207 default: 208 break; 209 } 210 } 211 212 virtual void Observe(int type, 213 const NotificationSource& source, 214 const NotificationDetails& details) OVERRIDE { 215 if (type != NOTIFICATION_WEB_CONTENTS_DISCONNECTED) 216 return; 217 218 // Cancel the drag if it is still in progress. 219 aura::client::DragDropClient* dnd_client = 220 aura::client::GetDragDropClient(window_->GetRootWindow()); 221 if (dnd_client && dnd_client->IsDragDropInProgress()) 222 dnd_client->DragCancel(); 223 224 window_ = NULL; 225 contents_ = NULL; 226 } 227 228 aura::Window* window() const { return window_; } 229 230 private: 231 aura::Window* window_; 232 WebContentsImpl* contents_; 233 NotificationRegistrar registrar_; 234 235 DISALLOW_COPY_AND_ASSIGN(WebDragSourceAura); 236}; 237 238// Utility to fill a ui::OSExchangeDataProvider object from DropData. 239void PrepareDragData(const DropData& drop_data, 240 ui::OSExchangeData::Provider* provider) { 241 if (!drop_data.text.string().empty()) 242 provider->SetString(drop_data.text.string()); 243 if (drop_data.url.is_valid()) 244 provider->SetURL(drop_data.url, drop_data.url_title); 245 if (!drop_data.html.string().empty()) 246 provider->SetHtml(drop_data.html.string(), drop_data.html_base_url); 247 if (!drop_data.filenames.empty()) { 248 std::vector<ui::OSExchangeData::FileInfo> filenames; 249 for (std::vector<DropData::FileInfo>::const_iterator it = 250 drop_data.filenames.begin(); 251 it != drop_data.filenames.end(); ++it) { 252 filenames.push_back( 253 ui::OSExchangeData::FileInfo( 254 base::FilePath::FromUTF8Unsafe(UTF16ToUTF8(it->path)), 255 base::FilePath::FromUTF8Unsafe(UTF16ToUTF8(it->display_name)))); 256 } 257 provider->SetFilenames(filenames); 258 } 259 if (!drop_data.custom_data.empty()) { 260 Pickle pickle; 261 ui::WriteCustomDataToPickle(drop_data.custom_data, &pickle); 262 provider->SetPickledData(ui::Clipboard::GetWebCustomDataFormatType(), 263 pickle); 264 } 265} 266 267// Utility to fill a DropData object from ui::OSExchangeData. 268void PrepareDropData(DropData* drop_data, const ui::OSExchangeData& data) { 269 string16 plain_text; 270 data.GetString(&plain_text); 271 if (!plain_text.empty()) 272 drop_data->text = base::NullableString16(plain_text, false); 273 274 GURL url; 275 string16 url_title; 276 data.GetURLAndTitle(&url, &url_title); 277 if (url.is_valid()) { 278 drop_data->url = url; 279 drop_data->url_title = url_title; 280 } 281 282 string16 html; 283 GURL html_base_url; 284 data.GetHtml(&html, &html_base_url); 285 if (!html.empty()) 286 drop_data->html = base::NullableString16(html, false); 287 if (html_base_url.is_valid()) 288 drop_data->html_base_url = html_base_url; 289 290 std::vector<ui::OSExchangeData::FileInfo> files; 291 if (data.GetFilenames(&files) && !files.empty()) { 292 for (std::vector<ui::OSExchangeData::FileInfo>::const_iterator 293 it = files.begin(); it != files.end(); ++it) { 294 drop_data->filenames.push_back( 295 DropData::FileInfo( 296 UTF8ToUTF16(it->path.AsUTF8Unsafe()), 297 UTF8ToUTF16(it->display_name.AsUTF8Unsafe()))); 298 } 299 } 300 301 Pickle pickle; 302 if (data.GetPickledData(ui::Clipboard::GetWebCustomDataFormatType(), &pickle)) 303 ui::ReadCustomDataIntoMap( 304 pickle.data(), pickle.size(), &drop_data->custom_data); 305} 306 307// Utilities to convert between WebKit::WebDragOperationsMask and 308// ui::DragDropTypes. 309int ConvertFromWeb(WebKit::WebDragOperationsMask ops) { 310 int drag_op = ui::DragDropTypes::DRAG_NONE; 311 if (ops & WebKit::WebDragOperationCopy) 312 drag_op |= ui::DragDropTypes::DRAG_COPY; 313 if (ops & WebKit::WebDragOperationMove) 314 drag_op |= ui::DragDropTypes::DRAG_MOVE; 315 if (ops & WebKit::WebDragOperationLink) 316 drag_op |= ui::DragDropTypes::DRAG_LINK; 317 return drag_op; 318} 319 320WebKit::WebDragOperationsMask ConvertToWeb(int drag_op) { 321 int web_drag_op = WebKit::WebDragOperationNone; 322 if (drag_op & ui::DragDropTypes::DRAG_COPY) 323 web_drag_op |= WebKit::WebDragOperationCopy; 324 if (drag_op & ui::DragDropTypes::DRAG_MOVE) 325 web_drag_op |= WebKit::WebDragOperationMove; 326 if (drag_op & ui::DragDropTypes::DRAG_LINK) 327 web_drag_op |= WebKit::WebDragOperationLink; 328 return (WebKit::WebDragOperationsMask) web_drag_op; 329} 330 331int ConvertAuraEventFlagsToWebInputEventModifiers(int aura_event_flags) { 332 int web_input_event_modifiers = 0; 333 if (aura_event_flags & ui::EF_SHIFT_DOWN) 334 web_input_event_modifiers |= WebKit::WebInputEvent::ShiftKey; 335 if (aura_event_flags & ui::EF_CONTROL_DOWN) 336 web_input_event_modifiers |= WebKit::WebInputEvent::ControlKey; 337 if (aura_event_flags & ui::EF_ALT_DOWN) 338 web_input_event_modifiers |= WebKit::WebInputEvent::AltKey; 339 if (aura_event_flags & ui::EF_COMMAND_DOWN) 340 web_input_event_modifiers |= WebKit::WebInputEvent::MetaKey; 341 return web_input_event_modifiers; 342} 343 344// A LayerDelegate that paints an image for the layer. 345class ImageLayerDelegate : public ui::LayerDelegate { 346 public: 347 ImageLayerDelegate() {} 348 349 virtual ~ImageLayerDelegate() {} 350 351 void SetImage(const gfx::Image& image) { 352 image_ = image; 353 image_size_ = image.AsImageSkia().size(); 354 } 355 const gfx::Image& image() const { return image_; } 356 357 private: 358 // Overridden from ui::LayerDelegate: 359 virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { 360 if (image_.IsEmpty()) { 361 canvas->DrawColor(SK_ColorGRAY); 362 } else { 363 SkISize size = canvas->sk_canvas()->getDeviceSize(); 364 if (size.width() != image_size_.width() || 365 size.height() != image_size_.height()) { 366 canvas->DrawColor(SK_ColorWHITE); 367 } 368 canvas->DrawImageInt(image_.AsImageSkia(), 0, 0); 369 } 370 } 371 372 // Called when the layer's device scale factor has changed. 373 virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE { 374 } 375 376 // Invoked prior to the bounds changing. The returned closured is run after 377 // the bounds change. 378 virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE { 379 return base::Closure(); 380 } 381 382 gfx::Image image_; 383 gfx::Size image_size_; 384 385 DISALLOW_COPY_AND_ASSIGN(ImageLayerDelegate); 386}; 387 388} // namespace 389 390// When a history navigation is triggered at the end of an overscroll 391// navigation, it is necessary to show the history-screenshot until the page is 392// done navigating and painting. This class accomplishes this by showing the 393// screenshot window on top of the page until the page has completed loading and 394// painting. 395class OverscrollNavigationOverlay : 396 public RenderWidgetHostViewAura::PaintObserver, 397 public WindowSlider::Delegate { 398 public: 399 explicit OverscrollNavigationOverlay(WebContentsImpl* web_contents) 400 : web_contents_(web_contents), 401 image_delegate_(NULL), 402 view_(NULL), 403 loading_complete_(false), 404 received_paint_update_(false), 405 compositor_updated_(false), 406 slide_direction_(SLIDE_UNKNOWN), 407 need_paint_update_(true) { 408 } 409 410 virtual ~OverscrollNavigationOverlay() { 411 if (view_) 412 view_->set_paint_observer(NULL); 413 } 414 415 bool has_window() const { return !!window_.get(); } 416 417 void StartObservingView(RenderWidgetHostViewAura* view) { 418 if (view_) 419 view_->set_paint_observer(NULL); 420 421 loading_complete_ = false; 422 received_paint_update_ = false; 423 compositor_updated_ = false; 424 view_ = view; 425 if (view_) 426 view_->set_paint_observer(this); 427 428 // Make sure the overlay window is on top. 429 if (window_.get() && window_->parent()) 430 window_->parent()->StackChildAtTop(window_.get()); 431 } 432 433 void SetOverlayWindow(scoped_ptr<aura::Window> window, 434 ImageWindowDelegate* delegate) { 435 window_ = window.Pass(); 436 if (window_.get() && window_->parent()) 437 window_->parent()->StackChildAtTop(window_.get()); 438 image_delegate_ = delegate; 439 440 if (window_.get() && delegate->has_image()) { 441 window_slider_.reset(new WindowSlider(this, 442 window_->parent(), 443 window_.get())); 444 slide_direction_ = SLIDE_UNKNOWN; 445 } else { 446 window_slider_.reset(); 447 } 448 } 449 450 void SetupForTesting() { 451 need_paint_update_ = false; 452 } 453 454 private: 455 // Stop observing the page if the page-load has completed and the page has 456 // been painted, and a window-slide isn't in progress. 457 void StopObservingIfDone() { 458 // If there is a screenshot displayed in the overlay window, then wait for 459 // the navigated page to complete loading and some paint update before 460 // hiding the overlay. 461 // If there is no screenshot in the overlay window, then hide this view 462 // as soon as there is any new painting notification. 463 if ((need_paint_update_ && !received_paint_update_) || 464 (image_delegate_->has_image() && !loading_complete_)) { 465 return; 466 } 467 468 // If a slide is in progress, then do not destroy the window or the slide. 469 if (window_slider_.get() && window_slider_->IsSlideInProgress()) 470 return; 471 472 window_slider_.reset(); 473 window_.reset(); 474 image_delegate_ = NULL; 475 if (view_) { 476 view_->set_paint_observer(NULL); 477 view_ = NULL; 478 } 479 } 480 481 // Creates a layer to be used for window-slide. |offset| is the offset of the 482 // NavigationEntry for the screenshot image to display. 483 ui::Layer* CreateSlideLayer(int offset) { 484 const NavigationControllerImpl& controller = web_contents_->GetController(); 485 const NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry( 486 controller.GetEntryAtOffset(offset)); 487 488 gfx::Image image; 489 if (entry && entry->screenshot().get()) { 490 std::vector<gfx::ImagePNGRep> image_reps; 491 image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(), 492 ui::GetScaleFactorForNativeView(window_.get()))); 493 image = gfx::Image(image_reps); 494 } 495 layer_delegate_.SetImage(image); 496 497 ui::Layer* layer = new ui::Layer(ui::LAYER_TEXTURED); 498 layer->set_delegate(&layer_delegate_); 499 return layer; 500 } 501 502 // Overridden from WindowSlider::Delegate: 503 virtual ui::Layer* CreateBackLayer() OVERRIDE { 504 if (!web_contents_->GetController().CanGoBack()) 505 return NULL; 506 slide_direction_ = SLIDE_BACK; 507 return CreateSlideLayer(-1); 508 } 509 510 virtual ui::Layer* CreateFrontLayer() OVERRIDE { 511 if (!web_contents_->GetController().CanGoForward()) 512 return NULL; 513 slide_direction_ = SLIDE_FRONT; 514 return CreateSlideLayer(1); 515 } 516 517 virtual void OnWindowSlideComplete() OVERRIDE { 518 if (slide_direction_ == SLIDE_UNKNOWN) { 519 window_slider_.reset(); 520 StopObservingIfDone(); 521 return; 522 } 523 524 // Change the image used for the overlay window. 525 image_delegate_->SetImage(layer_delegate_.image()); 526 window_->layer()->SetTransform(gfx::Transform()); 527 window_->SchedulePaintInRect(gfx::Rect(window_->bounds().size())); 528 529 SlideDirection direction = slide_direction_; 530 slide_direction_ = SLIDE_UNKNOWN; 531 532 // Reset state and wait for the new navigation page to complete 533 // loading/painting. 534 StartObservingView(ToRenderWidgetHostViewAura( 535 web_contents_->GetRenderWidgetHostView())); 536 537 // Perform the navigation. 538 if (direction == SLIDE_BACK) 539 web_contents_->GetController().GoBack(); 540 else if (direction == SLIDE_FRONT) 541 web_contents_->GetController().GoForward(); 542 else 543 NOTREACHED(); 544 } 545 546 virtual void OnWindowSlideAborted() OVERRIDE { 547 StopObservingIfDone(); 548 } 549 550 virtual void OnWindowSliderDestroyed() OVERRIDE { 551 // The slider has just been destroyed. Release the ownership. 552 WindowSlider* slider ALLOW_UNUSED = window_slider_.release(); 553 StopObservingIfDone(); 554 } 555 556 // Overridden from RenderWidgetHostViewAura::PaintObserver: 557 virtual void OnPaintComplete() OVERRIDE { 558 received_paint_update_ = true; 559 StopObservingIfDone(); 560 } 561 562 virtual void OnCompositingComplete() OVERRIDE { 563 received_paint_update_ = compositor_updated_; 564 StopObservingIfDone(); 565 } 566 567 virtual void OnUpdateCompositorContent() OVERRIDE { 568 compositor_updated_ = true; 569 } 570 571 virtual void OnPageLoadComplete() OVERRIDE { 572 loading_complete_ = true; 573 StopObservingIfDone(); 574 } 575 576 virtual void OnViewDestroyed() OVERRIDE { 577 DCHECK(view_); 578 view_->set_paint_observer(NULL); 579 view_ = NULL; 580 } 581 582 // The WebContents which is being navigated. 583 WebContentsImpl* web_contents_; 584 585 scoped_ptr<aura::Window> window_; 586 587 // This is the WindowDelegate of |window_|. The delegate manages its own 588 // lifetime (destroys itself when |window_| is destroyed). 589 ImageWindowDelegate* image_delegate_; 590 591 RenderWidgetHostViewAura* view_; 592 bool loading_complete_; 593 bool received_paint_update_; 594 bool compositor_updated_; 595 596 enum SlideDirection { 597 SLIDE_UNKNOWN, 598 SLIDE_BACK, 599 SLIDE_FRONT 600 }; 601 602 // The |WindowSlider| that allows sliding history layers while the page is 603 // being reloaded. 604 scoped_ptr<WindowSlider> window_slider_; 605 606 // The direction of the in-progress slide (if any). 607 SlideDirection slide_direction_; 608 609 // The LayerDelegate used for the back/front layers during a slide. 610 ImageLayerDelegate layer_delegate_; 611 612 // During tests, the aura windows don't get any paint updates. So the overlay 613 // container keeps waiting for a paint update it never receives, causing a 614 // timeout. So during tests, disable the wait for paint updates. 615 bool need_paint_update_; 616 617 DISALLOW_COPY_AND_ASSIGN(OverscrollNavigationOverlay); 618}; 619 620class WebContentsViewAura::WindowObserver 621 : public aura::WindowObserver, public aura::RootWindowObserver { 622 public: 623 explicit WindowObserver(WebContentsViewAura* view) 624 : view_(view), 625 parent_(NULL) { 626 view_->window_->AddObserver(this); 627 } 628 629 virtual ~WindowObserver() { 630 view_->window_->RemoveObserver(this); 631 if (view_->window_->GetRootWindow()) 632 view_->window_->GetRootWindow()->RemoveRootWindowObserver(this); 633 if (parent_) 634 parent_->RemoveObserver(this); 635 } 636 637 // Overridden from aura::WindowObserver: 638 virtual void OnWindowParentChanged(aura::Window* window, 639 aura::Window* parent) OVERRIDE { 640 if (window == parent_) 641 return; 642 if (parent_) 643 parent_->RemoveObserver(this); 644 parent_ = parent; 645 if (parent) 646 parent->AddObserver(this); 647 } 648 649 virtual void OnWindowBoundsChanged(aura::Window* window, 650 const gfx::Rect& old_bounds, 651 const gfx::Rect& new_bounds) OVERRIDE { 652 SendScreenRects(); 653 if (view_->touch_editable_) 654 view_->touch_editable_->UpdateEditingController(); 655 } 656 657 virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE { 658 if (window != parent_) 659 window->GetRootWindow()->AddRootWindowObserver(this); 660 } 661 662 virtual void OnWindowRemovingFromRootWindow(aura::Window* window) OVERRIDE { 663 if (window != parent_) 664 window->GetRootWindow()->RemoveRootWindowObserver(this); 665 } 666 667 // Overridden RootWindowObserver: 668 virtual void OnRootWindowHostMoved(const aura::RootWindow* root, 669 const gfx::Point& new_origin) OVERRIDE { 670 // This is for the desktop case (i.e. Aura desktop). 671 SendScreenRects(); 672 } 673 674 private: 675 void SendScreenRects() { 676 RenderWidgetHostImpl::From(view_->web_contents_->GetRenderViewHost())-> 677 SendScreenRects(); 678 } 679 680 WebContentsViewAura* view_; 681 682 // We cache the old parent so that we can unregister when it's not the parent 683 // anymore. 684 aura::Window* parent_; 685 686 DISALLOW_COPY_AND_ASSIGN(WindowObserver); 687}; 688 689#if defined(OS_WIN) 690// Constrained windows are added as children of the WebContent's view which may 691// overlap with windowed NPAPI plugins. In that case, tell the RWHV so that it 692// can update the plugins' cutout rects accordingly. 693class WebContentsViewAura::ChildWindowObserver : public aura::WindowObserver, 694 public WebContentsObserver { 695 public: 696 explicit ChildWindowObserver(WebContentsViewAura* view) 697 : WebContentsObserver(view->web_contents_), 698 view_(view), 699 web_contents_destroyed_(false) { 700 view_->window_->AddObserver(this); 701 } 702 703 virtual ~ChildWindowObserver() { 704 view_->window_->RemoveObserver(this); 705 const aura::Window::Windows& children = view_->window_->children(); 706 for (size_t i = 0; i < children.size(); ++i) 707 children[i]->RemoveObserver(this); 708 } 709 710 // Overridden from aura::WindowObserver: 711 virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE { 712 // If new child windows are added to the WebContent's view, tell the RWHV. 713 // We also start watching them to know when their size is updated. Of 714 // course, ignore the shadow window that contains the RWHV and child windows 715 // of the child windows that we are watching. 716 RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura( 717 view_->web_contents_->GetRenderWidgetHostView()); 718 aura::Window* content_window = view ? view->GetNativeView() : NULL; 719 if (new_window->parent() == view_->window_ && 720 new_window != content_window) { 721 new_window->AddObserver(this); 722 UpdateConstrainedWindows(NULL); 723 } 724 } 725 726 virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE { 727 RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura( 728 view_->web_contents_->GetRenderWidgetHostView()); 729 aura::Window* content_window = view ? view->GetNativeView() : NULL; 730 if (window->parent() == view_->window_ && 731 window != content_window) { 732 window->RemoveObserver(this); 733 UpdateConstrainedWindows(window); 734 } 735 } 736 737 virtual void OnWindowBoundsChanged(aura::Window* window, 738 const gfx::Rect& old_bounds, 739 const gfx::Rect& new_bounds) OVERRIDE { 740 if (window->parent() == view_->window_ && 741 window != view_->GetContentNativeView()) { 742 UpdateConstrainedWindows(NULL); 743 } 744 } 745 746 // Overridden from WebContentsObserver: 747 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE { 748 web_contents_destroyed_ = true; 749 } 750 751 private: 752 void UpdateConstrainedWindows(aura::Window* exclude) { 753 if (web_contents_destroyed_) 754 return; 755 756 RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura( 757 view_->web_contents_->GetRenderWidgetHostView()); 758 if (!view) 759 return; 760 761 std::vector<gfx::Rect> constrained_windows; 762 const aura::Window::Windows& children = view_->window_->children(); 763 aura::Window* content = view_->GetContentNativeView(); 764 for (size_t i = 0; i < children.size(); ++i) { 765 if (children[i] != content && children[i] != exclude) 766 constrained_windows.push_back(children[i]->GetBoundsInRootWindow()); 767 } 768 769 view->UpdateConstrainedWindowRects(constrained_windows); 770 } 771 772 WebContentsViewAura* view_; 773 bool web_contents_destroyed_; 774 775 DISALLOW_COPY_AND_ASSIGN(ChildWindowObserver); 776}; 777#endif 778 779//////////////////////////////////////////////////////////////////////////////// 780// WebContentsViewAura, public: 781 782WebContentsViewAura::WebContentsViewAura( 783 WebContentsImpl* web_contents, 784 WebContentsViewDelegate* delegate) 785 : web_contents_(web_contents), 786 delegate_(delegate), 787 current_drag_op_(WebKit::WebDragOperationNone), 788 drag_dest_delegate_(NULL), 789 current_rvh_for_drag_(NULL), 790 overscroll_change_brightness_(false), 791 current_overscroll_gesture_(OVERSCROLL_NONE), 792 completed_overscroll_gesture_(OVERSCROLL_NONE), 793 touch_editable_(TouchEditableImplAura::Create()) { 794} 795 796//////////////////////////////////////////////////////////////////////////////// 797// WebContentsViewAura, private: 798 799WebContentsViewAura::~WebContentsViewAura() { 800 if (!window_) 801 return; 802 803 window_observer_.reset(); 804#if defined(OS_WIN) 805 child_window_observer_.reset(); 806#endif 807 // Window needs a valid delegate during its destructor, so we explicitly 808 // delete it here. 809 window_.reset(); 810} 811 812void WebContentsViewAura::SetupOverlayWindowForTesting() { 813 if (navigation_overlay_) 814 navigation_overlay_->SetupForTesting(); 815} 816 817void WebContentsViewAura::SetTouchEditableForTest( 818 TouchEditableImplAura* touch_editable) { 819 touch_editable_.reset(touch_editable); 820 AttachTouchEditableToRenderView(); 821} 822 823void WebContentsViewAura::SizeChangedCommon(const gfx::Size& size) { 824 if (web_contents_->GetInterstitialPage()) 825 web_contents_->GetInterstitialPage()->SetSize(size); 826 RenderWidgetHostView* rwhv = 827 web_contents_->GetRenderWidgetHostView(); 828 if (rwhv) 829 rwhv->SetSize(size); 830} 831 832void WebContentsViewAura::EndDrag(WebKit::WebDragOperationsMask ops) { 833 aura::RootWindow* root_window = GetNativeView()->GetRootWindow(); 834 gfx::Point screen_loc = 835 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 836 gfx::Point client_loc = screen_loc; 837 RenderViewHost* rvh = web_contents_->GetRenderViewHost(); 838 aura::Window* window = rvh->GetView()->GetNativeView(); 839 aura::Window::ConvertPointToTarget(root_window, window, &client_loc); 840 if (!web_contents_) 841 return; 842 web_contents_->DragSourceEndedAt(client_loc.x(), client_loc.y(), 843 screen_loc.x(), screen_loc.y(), ops); 844} 845 846void WebContentsViewAura::PrepareOverscrollWindow() { 847 // If there is an existing |overscroll_window_| which is in the middle of an 848 // animation, then destroying the window here causes the animation to be 849 // completed immidiately, which triggers |OnImplicitAnimationsCompleted()| 850 // callback, and that tries to reset |overscroll_window_| again, causing a 851 // double-free. So use a temporary variable here. 852 if (overscroll_window_) { 853 base::AutoReset<OverscrollMode> reset_state(¤t_overscroll_gesture_, 854 current_overscroll_gesture_); 855 scoped_ptr<aura::Window> reset_window(overscroll_window_.release()); 856 } 857 858 OverscrollWindowDelegate* overscroll_delegate = new OverscrollWindowDelegate( 859 web_contents_, 860 current_overscroll_gesture_); 861 overscroll_window_.reset(new aura::Window(overscroll_delegate)); 862 overscroll_window_->SetType(aura::client::WINDOW_TYPE_CONTROL); 863 overscroll_window_->SetTransparent(true); 864 overscroll_window_->Init(ui::LAYER_TEXTURED); 865 overscroll_window_->layer()->SetMasksToBounds(false); 866 overscroll_window_->SetName("OverscrollOverlay"); 867 868 overscroll_change_brightness_ = overscroll_delegate->has_image(); 869 window_->AddChild(overscroll_window_.get()); 870 871 gfx::Rect bounds = gfx::Rect(window_->bounds().size()); 872 if (ShouldNavigateForward(web_contents_->GetController(), 873 current_overscroll_gesture_)) { 874 // The overlay will be sliding in from the right edge towards the left in 875 // non-RTL, or sliding in from the left edge towards the right in RTL. 876 // So position the overlay window accordingly. 877 bounds.Offset(base::i18n::IsRTL() ? -bounds.width() : bounds.width(), 0); 878 } 879 880 aura::Window* animate_window = GetWindowToAnimateForOverscroll(); 881 if (animate_window == overscroll_window_) 882 window_->StackChildAbove(overscroll_window_.get(), GetContentNativeView()); 883 else 884 window_->StackChildBelow(overscroll_window_.get(), GetContentNativeView()); 885 886 UpdateOverscrollWindowBrightness(0.f); 887 888 overscroll_window_->SetBounds(bounds); 889 overscroll_window_->Show(); 890 891 overscroll_shadow_.reset(new ShadowLayerDelegate(animate_window->layer())); 892} 893 894void WebContentsViewAura::PrepareContentWindowForOverscroll() { 895 StopObservingImplicitAnimations(); 896 aura::Window* content = GetContentNativeView(); 897 content->layer()->GetAnimator()->AbortAllAnimations(); 898 content->SetTransform(gfx::Transform()); 899 content->layer()->SetLayerBrightness(0.f); 900} 901 902void WebContentsViewAura::ResetOverscrollTransform() { 903 if (!web_contents_->GetRenderWidgetHostView()) 904 return; 905 aura::Window* target = GetWindowToAnimateForOverscroll(); 906 if (!target) 907 return; 908 { 909 ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator()); 910 settings.SetPreemptionStrategy( 911 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 912 settings.SetTweenType(ui::Tween::EASE_OUT); 913 settings.AddObserver(this); 914 target->SetTransform(gfx::Transform()); 915 } 916 { 917 ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator()); 918 settings.SetPreemptionStrategy( 919 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 920 settings.SetTweenType(ui::Tween::EASE_OUT); 921 UpdateOverscrollWindowBrightness(0.f); 922 } 923} 924 925void WebContentsViewAura::CompleteOverscrollNavigation(OverscrollMode mode) { 926 if (!web_contents_->GetRenderWidgetHostView()) 927 return; 928 929 // Animate out the current view first. Navigate to the requested history at 930 // the end of the animation. 931 if (current_overscroll_gesture_ == OVERSCROLL_NONE) 932 return; 933 934 UMA_HISTOGRAM_ENUMERATION("Overscroll.Navigated", 935 current_overscroll_gesture_, OVERSCROLL_COUNT); 936 OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>( 937 overscroll_window_->delegate()); 938 delegate->stop_forwarding_events(); 939 940 completed_overscroll_gesture_ = mode; 941 aura::Window* target = GetWindowToAnimateForOverscroll(); 942 ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator()); 943 settings.SetPreemptionStrategy( 944 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 945 settings.SetTweenType(ui::Tween::EASE_OUT); 946 settings.AddObserver(this); 947 gfx::Transform transform; 948 int content_width = 949 web_contents_->GetRenderWidgetHostView()->GetViewBounds().width(); 950 int translate_x = mode == OVERSCROLL_WEST ? -content_width : content_width; 951 transform.Translate(translate_x, 0); 952 target->SetTransform(transform); 953 UpdateOverscrollWindowBrightness(translate_x); 954} 955 956aura::Window* WebContentsViewAura::GetWindowToAnimateForOverscroll() { 957 if (current_overscroll_gesture_ == OVERSCROLL_NONE) 958 return NULL; 959 960 return ShouldNavigateForward(web_contents_->GetController(), 961 current_overscroll_gesture_) ? 962 overscroll_window_.get() : GetContentNativeView(); 963} 964 965gfx::Vector2d WebContentsViewAura::GetTranslationForOverscroll(int delta_x, 966 int delta_y) { 967 if (current_overscroll_gesture_ == OVERSCROLL_NORTH || 968 current_overscroll_gesture_ == OVERSCROLL_SOUTH) { 969 return gfx::Vector2d(0, delta_y); 970 } 971 // For horizontal overscroll, scroll freely if a navigation is possible. Do a 972 // resistive scroll otherwise. 973 const NavigationControllerImpl& controller = web_contents_->GetController(); 974 const gfx::Rect& bounds = GetViewBounds(); 975 if (ShouldNavigateForward(controller, current_overscroll_gesture_)) 976 return gfx::Vector2d(std::max(-bounds.width(), delta_x), 0); 977 else if (ShouldNavigateBack(controller, current_overscroll_gesture_)) 978 return gfx::Vector2d(std::min(bounds.width(), delta_x), 0); 979 return gfx::Vector2d(); 980} 981 982void WebContentsViewAura::PrepareOverscrollNavigationOverlay() { 983 OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>( 984 overscroll_window_->delegate()); 985 overscroll_window_->SchedulePaintInRect( 986 gfx::Rect(overscroll_window_->bounds().size())); 987 overscroll_window_->SetBounds(gfx::Rect(window_->bounds().size())); 988 overscroll_window_->SetTransform(gfx::Transform()); 989 navigation_overlay_->SetOverlayWindow(overscroll_window_.Pass(), 990 delegate); 991 navigation_overlay_->StartObservingView(ToRenderWidgetHostViewAura( 992 web_contents_->GetRenderWidgetHostView())); 993} 994 995void WebContentsViewAura::UpdateOverscrollWindowBrightness(float delta_x) { 996 if (!overscroll_change_brightness_) 997 return; 998 999 const float kBrightnessMin = -.1f; 1000 const float kBrightnessMax = -.01f; 1001 1002 float ratio = fabs(delta_x) / GetViewBounds().width(); 1003 ratio = std::min(1.f, ratio); 1004 if (base::i18n::IsRTL()) 1005 ratio = 1.f - ratio; 1006 float brightness = current_overscroll_gesture_ == OVERSCROLL_WEST ? 1007 kBrightnessMin + ratio * (kBrightnessMax - kBrightnessMin) : 1008 kBrightnessMax - ratio * (kBrightnessMax - kBrightnessMin); 1009 brightness = std::max(kBrightnessMin, brightness); 1010 brightness = std::min(kBrightnessMax, brightness); 1011 aura::Window* window = GetWindowToAnimateForOverscroll(); 1012 window->layer()->SetLayerBrightness(brightness); 1013} 1014 1015void WebContentsViewAura::AttachTouchEditableToRenderView() { 1016 if (!touch_editable_) 1017 return; 1018 RenderWidgetHostViewAura* rwhva = ToRenderWidgetHostViewAura( 1019 web_contents_->GetRenderWidgetHostView()); 1020 touch_editable_->AttachToView(rwhva); 1021} 1022 1023void WebContentsViewAura::OverscrollUpdateForWebContentsDelegate(int delta_y) { 1024 if (web_contents_->GetDelegate() && IsScrollEndEffectEnabled()) 1025 web_contents_->GetDelegate()->OverscrollUpdate(delta_y); 1026} 1027 1028//////////////////////////////////////////////////////////////////////////////// 1029// WebContentsViewAura, WebContentsView implementation: 1030 1031gfx::NativeView WebContentsViewAura::GetNativeView() const { 1032 return window_.get(); 1033} 1034 1035gfx::NativeView WebContentsViewAura::GetContentNativeView() const { 1036 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); 1037 return rwhv ? rwhv->GetNativeView() : NULL; 1038} 1039 1040gfx::NativeWindow WebContentsViewAura::GetTopLevelNativeWindow() const { 1041 return window_->GetToplevelWindow(); 1042} 1043 1044void WebContentsViewAura::GetContainerBounds(gfx::Rect *out) const { 1045 *out = window_->GetBoundsInScreen(); 1046} 1047 1048void WebContentsViewAura::OnTabCrashed(base::TerminationStatus status, 1049 int error_code) { 1050 // Set the focus to the parent because neither the view window nor this 1051 // window can handle key events. 1052 if (window_->HasFocus() && window_->parent()) 1053 window_->parent()->Focus(); 1054} 1055 1056void WebContentsViewAura::SizeContents(const gfx::Size& size) { 1057 gfx::Rect bounds = window_->bounds(); 1058 if (bounds.size() != size) { 1059 bounds.set_size(size); 1060 window_->SetBounds(bounds); 1061 } else { 1062 // Our size matches what we want but the renderers size may not match. 1063 // Pretend we were resized so that the renderers size is updated too. 1064 SizeChangedCommon(size); 1065 } 1066} 1067 1068void WebContentsViewAura::Focus() { 1069 if (web_contents_->GetInterstitialPage()) { 1070 web_contents_->GetInterstitialPage()->Focus(); 1071 return; 1072 } 1073 1074 if (delegate_.get() && delegate_->Focus()) 1075 return; 1076 1077 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); 1078 if (rwhv) 1079 rwhv->Focus(); 1080} 1081 1082void WebContentsViewAura::SetInitialFocus() { 1083 if (web_contents_->FocusLocationBarByDefault()) 1084 web_contents_->SetFocusToLocationBar(false); 1085 else 1086 Focus(); 1087} 1088 1089void WebContentsViewAura::StoreFocus() { 1090 if (delegate_) 1091 delegate_->StoreFocus(); 1092} 1093 1094void WebContentsViewAura::RestoreFocus() { 1095 if (delegate_) 1096 delegate_->RestoreFocus(); 1097} 1098 1099DropData* WebContentsViewAura::GetDropData() const { 1100 return current_drop_data_.get(); 1101} 1102 1103gfx::Rect WebContentsViewAura::GetViewBounds() const { 1104 return window_->GetBoundsInScreen(); 1105} 1106 1107//////////////////////////////////////////////////////////////////////////////// 1108// WebContentsViewAura, WebContentsViewPort implementation: 1109 1110void WebContentsViewAura::CreateView( 1111 const gfx::Size& initial_size, gfx::NativeView context) { 1112 // NOTE: we ignore |initial_size| since in some cases it's wrong (such as 1113 // if the bookmark bar is not shown and you create a new tab). The right 1114 // value is set shortly after this, so its safe to ignore. 1115 1116 window_.reset(new aura::Window(this)); 1117 window_->set_owned_by_parent(false); 1118 window_->SetType(aura::client::WINDOW_TYPE_CONTROL); 1119 window_->SetTransparent(false); 1120 window_->Init(ui::LAYER_NOT_DRAWN); 1121 aura::RootWindow* root_window = context ? context->GetRootWindow() : NULL; 1122 if (root_window) { 1123 // There are places where there is no context currently because object 1124 // hierarchies are built before they're attached to a Widget. (See 1125 // views::WebView as an example; GetWidget() returns NULL at the point 1126 // where we are created.) 1127 // 1128 // It should be OK to not set a default parent since such users will 1129 // explicitly add this WebContentsViewAura to their tree after they create 1130 // us. 1131 if (root_window) { 1132 window_->SetDefaultParentByRootWindow( 1133 root_window, root_window->GetBoundsInScreen()); 1134 } 1135 } 1136 window_->layer()->SetMasksToBounds(true); 1137 window_->SetName("WebContentsViewAura"); 1138 1139 window_observer_.reset(new WindowObserver(this)); 1140#if defined(OS_WIN) 1141 child_window_observer_.reset(new ChildWindowObserver(this)); 1142#endif 1143 1144 // delegate_->GetDragDestDelegate() creates a new delegate on every call. 1145 // Hence, we save a reference to it locally. Similar model is used on other 1146 // platforms as well. 1147 if (delegate_) 1148 drag_dest_delegate_ = delegate_->GetDragDestDelegate(); 1149} 1150 1151RenderWidgetHostView* WebContentsViewAura::CreateViewForWidget( 1152 RenderWidgetHost* render_widget_host) { 1153 if (render_widget_host->GetView()) { 1154 // During testing, the view will already be set up in most cases to the 1155 // test view, so we don't want to clobber it with a real one. To verify that 1156 // this actually is happening (and somebody isn't accidentally creating the 1157 // view twice), we check for the RVH Factory, which will be set when we're 1158 // making special ones (which go along with the special views). 1159 DCHECK(RenderViewHostFactory::has_factory()); 1160 return render_widget_host->GetView(); 1161 } 1162 1163 RenderWidgetHostView* view = 1164 RenderWidgetHostView::CreateViewForWidget(render_widget_host); 1165 view->InitAsChild(NULL); 1166 GetNativeView()->AddChild(view->GetNativeView()); 1167 1168 if (navigation_overlay_.get() && navigation_overlay_->has_window()) { 1169 navigation_overlay_->StartObservingView(ToRenderWidgetHostViewAura(view)); 1170 } 1171 1172 view->Show(); 1173 1174 // We listen to drag drop events in the newly created view's window. 1175 aura::client::SetDragDropDelegate(view->GetNativeView(), this); 1176 1177 RenderWidgetHostImpl* host_impl = 1178 RenderWidgetHostImpl::From(render_widget_host); 1179 if (host_impl->overscroll_controller() && 1180 (!web_contents_->GetDelegate() || 1181 web_contents_->GetDelegate()->CanOverscrollContent())) { 1182 host_impl->overscroll_controller()->set_delegate(this); 1183 if (!navigation_overlay_) 1184 navigation_overlay_.reset(new OverscrollNavigationOverlay(web_contents_)); 1185 } 1186 1187 AttachTouchEditableToRenderView(); 1188 return view; 1189} 1190 1191RenderWidgetHostView* WebContentsViewAura::CreateViewForPopupWidget( 1192 RenderWidgetHost* render_widget_host) { 1193 return RenderWidgetHostViewPort::CreateViewForWidget(render_widget_host); 1194} 1195 1196void WebContentsViewAura::SetPageTitle(const string16& title) { 1197 window_->set_title(title); 1198} 1199 1200void WebContentsViewAura::RenderViewCreated(RenderViewHost* host) { 1201} 1202 1203void WebContentsViewAura::RenderViewSwappedIn(RenderViewHost* host) { 1204 if (navigation_overlay_.get() && navigation_overlay_->has_window()) { 1205 navigation_overlay_->StartObservingView( 1206 ToRenderWidgetHostViewAura(host->GetView())); 1207 } 1208 AttachTouchEditableToRenderView(); 1209} 1210 1211void WebContentsViewAura::SetOverscrollControllerEnabled(bool enabled) { 1212 RenderViewHostImpl* host = static_cast<RenderViewHostImpl*>( 1213 web_contents_->GetRenderViewHost()); 1214 if (host) { 1215 host->SetOverscrollControllerEnabled(enabled); 1216 if (enabled) 1217 host->overscroll_controller()->set_delegate(this); 1218 } 1219 1220 if (!enabled) 1221 navigation_overlay_.reset(); 1222 else if (!navigation_overlay_) 1223 navigation_overlay_.reset(new OverscrollNavigationOverlay(web_contents_)); 1224} 1225 1226//////////////////////////////////////////////////////////////////////////////// 1227// WebContentsViewAura, RenderViewHostDelegateView implementation: 1228 1229void WebContentsViewAura::ShowContextMenu(const ContextMenuParams& params) { 1230 if (delegate_) 1231 delegate_->ShowContextMenu(params); 1232 if (touch_editable_) 1233 touch_editable_->EndTouchEditing(); 1234 1235} 1236 1237void WebContentsViewAura::ShowPopupMenu(const gfx::Rect& bounds, 1238 int item_height, 1239 double item_font_size, 1240 int selected_item, 1241 const std::vector<MenuItem>& items, 1242 bool right_aligned, 1243 bool allow_multiple_selection) { 1244 // External popup menus are only used on Mac and Android. 1245 NOTIMPLEMENTED(); 1246} 1247 1248void WebContentsViewAura::StartDragging( 1249 const DropData& drop_data, 1250 WebKit::WebDragOperationsMask operations, 1251 const gfx::ImageSkia& image, 1252 const gfx::Vector2d& image_offset, 1253 const DragEventSourceInfo& event_info) { 1254 aura::RootWindow* root_window = GetNativeView()->GetRootWindow(); 1255 if (!aura::client::GetDragDropClient(root_window)) { 1256 web_contents_->SystemDragEnded(); 1257 return; 1258 } 1259 1260 if (touch_editable_) 1261 touch_editable_->EndTouchEditing(); 1262 1263 ui::OSExchangeData::Provider* provider = ui::OSExchangeData::CreateProvider(); 1264 PrepareDragData(drop_data, provider); 1265 1266 ui::OSExchangeData data(provider); // takes ownership of |provider|. 1267 1268 if (!image.isNull()) { 1269 drag_utils::SetDragImageOnDataObject(image, 1270 gfx::Size(image.width(), image.height()), image_offset, &data); 1271 } 1272 1273 scoped_ptr<WebDragSourceAura> drag_source( 1274 new WebDragSourceAura(GetNativeView(), web_contents_)); 1275 1276 // We need to enable recursive tasks on the message loop so we can get 1277 // updates while in the system DoDragDrop loop. 1278 int result_op = 0; 1279 { 1280 gfx::NativeView content_native_view = GetContentNativeView(); 1281 base::MessageLoop::ScopedNestableTaskAllower allow( 1282 base::MessageLoop::current()); 1283 result_op = aura::client::GetDragDropClient(root_window) 1284 ->StartDragAndDrop(data, 1285 root_window, 1286 content_native_view, 1287 event_info.event_location, 1288 ConvertFromWeb(operations), 1289 event_info.event_source); 1290 } 1291 1292 // Bail out immediately if the contents view window is gone. Note that it is 1293 // not safe to access any class members in this case since |this| may already 1294 // be destroyed. The local variable |drag_source| will still be valid though, 1295 // so we can use it to determine if the window is gone. 1296 if (!drag_source->window()) { 1297 // Note that in this case, we don't need to call SystemDragEnded() since the 1298 // renderer is going away. 1299 return; 1300 } 1301 1302 EndDrag(ConvertToWeb(result_op)); 1303 web_contents_->SystemDragEnded(); 1304} 1305 1306void WebContentsViewAura::UpdateDragCursor(WebKit::WebDragOperation operation) { 1307 current_drag_op_ = operation; 1308} 1309 1310void WebContentsViewAura::GotFocus() { 1311 if (web_contents_->GetDelegate()) 1312 web_contents_->GetDelegate()->WebContentsFocused(web_contents_); 1313} 1314 1315void WebContentsViewAura::TakeFocus(bool reverse) { 1316 if (web_contents_->GetDelegate() && 1317 !web_contents_->GetDelegate()->TakeFocus(web_contents_, reverse) && 1318 delegate_.get()) { 1319 delegate_->TakeFocus(reverse); 1320 } 1321} 1322 1323//////////////////////////////////////////////////////////////////////////////// 1324// WebContentsViewAura, OverscrollControllerDelegate implementation: 1325 1326void WebContentsViewAura::OnOverscrollUpdate(float delta_x, float delta_y) { 1327 if (current_overscroll_gesture_ == OVERSCROLL_NONE) 1328 return; 1329 1330 aura::Window* target = GetWindowToAnimateForOverscroll(); 1331 ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator()); 1332 settings.SetPreemptionStrategy(ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET); 1333 gfx::Vector2d translate = GetTranslationForOverscroll(delta_x, delta_y); 1334 gfx::Transform transform; 1335 1336 // Vertical overscrolls don't participate in the navigation gesture. 1337 if (current_overscroll_gesture_ != OVERSCROLL_NORTH && 1338 current_overscroll_gesture_ != OVERSCROLL_SOUTH) { 1339 transform.Translate(translate.x(), translate.y()); 1340 target->SetTransform(transform); 1341 UpdateOverscrollWindowBrightness(delta_x); 1342 } 1343 1344 OverscrollUpdateForWebContentsDelegate(translate.y()); 1345} 1346 1347void WebContentsViewAura::OnOverscrollComplete(OverscrollMode mode) { 1348 UMA_HISTOGRAM_ENUMERATION("Overscroll.Completed", mode, OVERSCROLL_COUNT); 1349 OverscrollUpdateForWebContentsDelegate(0); 1350 NavigationControllerImpl& controller = web_contents_->GetController(); 1351 if (ShouldNavigateForward(controller, mode) || 1352 ShouldNavigateBack(controller, mode)) { 1353 CompleteOverscrollNavigation(mode); 1354 return; 1355 } 1356 1357 ResetOverscrollTransform(); 1358} 1359 1360void WebContentsViewAura::OnOverscrollModeChange(OverscrollMode old_mode, 1361 OverscrollMode new_mode) { 1362 // Reset any in-progress overscroll animation first. 1363 ResetOverscrollTransform(); 1364 1365 if (new_mode == OVERSCROLL_NONE || 1366 !GetContentNativeView() || 1367 ((new_mode == OVERSCROLL_EAST || new_mode == OVERSCROLL_WEST) && 1368 navigation_overlay_.get() && navigation_overlay_->has_window())) { 1369 current_overscroll_gesture_ = OVERSCROLL_NONE; 1370 OverscrollUpdateForWebContentsDelegate(0); 1371 } else { 1372 aura::Window* target = GetWindowToAnimateForOverscroll(); 1373 if (target) { 1374 StopObservingImplicitAnimations(); 1375 target->layer()->GetAnimator()->AbortAllAnimations(); 1376 } 1377 // Cleanup state of the content window first, because that can reset the 1378 // value of |current_overscroll_gesture_|. 1379 PrepareContentWindowForOverscroll(); 1380 1381 current_overscroll_gesture_ = new_mode; 1382 if (current_overscroll_gesture_ == OVERSCROLL_EAST || 1383 current_overscroll_gesture_ == OVERSCROLL_WEST) 1384 PrepareOverscrollWindow(); 1385 1386 UMA_HISTOGRAM_ENUMERATION("Overscroll.Started", new_mode, OVERSCROLL_COUNT); 1387 } 1388 completed_overscroll_gesture_ = OVERSCROLL_NONE; 1389} 1390 1391//////////////////////////////////////////////////////////////////////////////// 1392// WebContentsViewAura, ui::ImplicitAnimationObserver implementation: 1393 1394void WebContentsViewAura::OnImplicitAnimationsCompleted() { 1395 overscroll_shadow_.reset(); 1396 1397 if (ShouldNavigateForward(web_contents_->GetController(), 1398 completed_overscroll_gesture_)) { 1399 PrepareOverscrollNavigationOverlay(); 1400 web_contents_->GetController().GoForward(); 1401 } else if (ShouldNavigateBack(web_contents_->GetController(), 1402 completed_overscroll_gesture_)) { 1403 PrepareOverscrollNavigationOverlay(); 1404 web_contents_->GetController().GoBack(); 1405 } 1406 1407 aura::Window* content = GetContentNativeView(); 1408 if (content) { 1409 content->SetTransform(gfx::Transform()); 1410 content->layer()->SetLayerBrightness(0.f); 1411 } 1412 current_overscroll_gesture_ = OVERSCROLL_NONE; 1413 completed_overscroll_gesture_ = OVERSCROLL_NONE; 1414 overscroll_window_.reset(); 1415} 1416 1417//////////////////////////////////////////////////////////////////////////////// 1418// WebContentsViewAura, aura::WindowDelegate implementation: 1419 1420gfx::Size WebContentsViewAura::GetMinimumSize() const { 1421 return gfx::Size(); 1422} 1423 1424gfx::Size WebContentsViewAura::GetMaximumSize() const { 1425 return gfx::Size(); 1426} 1427 1428void WebContentsViewAura::OnBoundsChanged(const gfx::Rect& old_bounds, 1429 const gfx::Rect& new_bounds) { 1430 SizeChangedCommon(new_bounds.size()); 1431 if (delegate_) 1432 delegate_->SizeChanged(new_bounds.size()); 1433 1434 // Constrained web dialogs, need to be kept centered over our content area. 1435 for (size_t i = 0; i < window_->children().size(); i++) { 1436 if (window_->children()[i]->GetProperty( 1437 aura::client::kConstrainedWindowKey)) { 1438 gfx::Rect bounds = window_->children()[i]->bounds(); 1439 bounds.set_origin( 1440 gfx::Point((new_bounds.width() - bounds.width()) / 2, 1441 (new_bounds.height() - bounds.height()) / 2)); 1442 window_->children()[i]->SetBounds(bounds); 1443 } 1444 } 1445} 1446 1447gfx::NativeCursor WebContentsViewAura::GetCursor(const gfx::Point& point) { 1448 return gfx::kNullCursor; 1449} 1450 1451int WebContentsViewAura::GetNonClientComponent(const gfx::Point& point) const { 1452 return HTCLIENT; 1453} 1454 1455bool WebContentsViewAura::ShouldDescendIntoChildForEventHandling( 1456 aura::Window* child, 1457 const gfx::Point& location) { 1458 return true; 1459} 1460 1461bool WebContentsViewAura::CanFocus() { 1462 // Do not take the focus if the render widget host view is gone because 1463 // neither the view window nor this window can handle key events. 1464 return web_contents_->GetRenderWidgetHostView() != NULL; 1465} 1466 1467void WebContentsViewAura::OnCaptureLost() { 1468} 1469 1470void WebContentsViewAura::OnPaint(gfx::Canvas* canvas) { 1471} 1472 1473void WebContentsViewAura::OnDeviceScaleFactorChanged( 1474 float device_scale_factor) { 1475} 1476 1477void WebContentsViewAura::OnWindowDestroying() { 1478 // This means the destructor is going to be called soon. If there is an 1479 // overscroll gesture in progress (i.e. |overscroll_window_| is not NULL), 1480 // then destroying it in the WebContentsViewAura destructor can trigger other 1481 // virtual functions to be called (e.g. OnImplicitAnimationsCompleted()). So 1482 // destroy the overscroll window here. 1483 navigation_overlay_.reset(); 1484 overscroll_window_.reset(); 1485} 1486 1487void WebContentsViewAura::OnWindowDestroyed() { 1488} 1489 1490void WebContentsViewAura::OnWindowTargetVisibilityChanged(bool visible) { 1491 if (visible) 1492 web_contents_->WasShown(); 1493 else 1494 web_contents_->WasHidden(); 1495} 1496 1497bool WebContentsViewAura::HasHitTestMask() const { 1498 return false; 1499} 1500 1501void WebContentsViewAura::GetHitTestMask(gfx::Path* mask) const { 1502} 1503 1504scoped_refptr<ui::Texture> WebContentsViewAura::CopyTexture() { 1505 // The layer we create doesn't have an external texture, so this should never 1506 // get invoked. 1507 NOTREACHED(); 1508 return scoped_refptr<ui::Texture>(); 1509} 1510 1511//////////////////////////////////////////////////////////////////////////////// 1512// WebContentsViewAura, ui::EventHandler implementation: 1513 1514void WebContentsViewAura::OnKeyEvent(ui::KeyEvent* event) { 1515} 1516 1517void WebContentsViewAura::OnMouseEvent(ui::MouseEvent* event) { 1518 if (!web_contents_->GetDelegate()) 1519 return; 1520 1521 switch (event->type()) { 1522 case ui::ET_MOUSE_PRESSED: 1523 web_contents_->GetDelegate()->ActivateContents(web_contents_); 1524 break; 1525 case ui::ET_MOUSE_MOVED: 1526 case ui::ET_MOUSE_EXITED: 1527 web_contents_->GetDelegate()->ContentsMouseEvent( 1528 web_contents_, 1529 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(), 1530 event->type() == ui::ET_MOUSE_MOVED); 1531 break; 1532 default: 1533 break; 1534 } 1535} 1536 1537//////////////////////////////////////////////////////////////////////////////// 1538// WebContentsViewAura, aura::client::DragDropDelegate implementation: 1539 1540void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) { 1541 if (drag_dest_delegate_) 1542 drag_dest_delegate_->DragInitialize(web_contents_); 1543 1544 current_drop_data_.reset(new DropData()); 1545 1546 PrepareDropData(current_drop_data_.get(), event.data()); 1547 WebKit::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); 1548 1549 gfx::Point screen_pt = 1550 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 1551 current_rvh_for_drag_ = web_contents_->GetRenderViewHost(); 1552 web_contents_->GetRenderViewHost()->DragTargetDragEnter( 1553 *current_drop_data_.get(), event.location(), screen_pt, op, 1554 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1555 1556 if (drag_dest_delegate_) { 1557 drag_dest_delegate_->OnReceiveDragData(event.data()); 1558 drag_dest_delegate_->OnDragEnter(); 1559 } 1560} 1561 1562int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) { 1563 DCHECK(current_rvh_for_drag_); 1564 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1565 OnDragEntered(event); 1566 1567 WebKit::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); 1568 gfx::Point screen_pt = 1569 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 1570 web_contents_->GetRenderViewHost()->DragTargetDragOver( 1571 event.location(), screen_pt, op, 1572 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1573 1574 if (drag_dest_delegate_) 1575 drag_dest_delegate_->OnDragOver(); 1576 1577 return ConvertFromWeb(current_drag_op_); 1578} 1579 1580void WebContentsViewAura::OnDragExited() { 1581 DCHECK(current_rvh_for_drag_); 1582 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1583 return; 1584 1585 web_contents_->GetRenderViewHost()->DragTargetDragLeave(); 1586 if (drag_dest_delegate_) 1587 drag_dest_delegate_->OnDragLeave(); 1588 1589 current_drop_data_.reset(); 1590} 1591 1592int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) { 1593 DCHECK(current_rvh_for_drag_); 1594 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1595 OnDragEntered(event); 1596 1597 web_contents_->GetRenderViewHost()->DragTargetDrop( 1598 event.location(), 1599 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(), 1600 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1601 if (drag_dest_delegate_) 1602 drag_dest_delegate_->OnDrop(); 1603 current_drop_data_.reset(); 1604 return current_drag_op_; 1605} 1606 1607} // namespace content 1608