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 62 namespace content { 63 WebContentsViewPort* 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 72 namespace { 73 74 bool IsScrollEndEffectEnabled() { 75 return CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 76 switches::kScrollEndEffect) == "1"; 77 } 78 79 bool ShouldNavigateForward(const NavigationController& controller, 80 OverscrollMode mode) { 81 return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) && 82 controller.CanGoForward(); 83 } 84 85 bool ShouldNavigateBack(const NavigationController& controller, 86 OverscrollMode mode) { 87 return mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST) && 88 controller.CanGoBack(); 89 } 90 91 RenderWidgetHostViewAura* 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. 105 class 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. 166 class 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. 239 void 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. 268 void 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. 309 int 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 320 WebKit::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 331 int 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. 345 class 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. 395 class 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 620 class 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. 693 class 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 782 WebContentsViewAura::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 799 WebContentsViewAura::~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 812 void WebContentsViewAura::SetupOverlayWindowForTesting() { 813 if (navigation_overlay_) 814 navigation_overlay_->SetupForTesting(); 815 } 816 817 void WebContentsViewAura::SetTouchEditableForTest( 818 TouchEditableImplAura* touch_editable) { 819 touch_editable_.reset(touch_editable); 820 AttachTouchEditableToRenderView(); 821 } 822 823 void 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 832 void 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 846 void 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 894 void 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 902 void 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 925 void 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 956 aura::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 965 gfx::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 982 void 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 995 void 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 1015 void WebContentsViewAura::AttachTouchEditableToRenderView() { 1016 if (!touch_editable_) 1017 return; 1018 RenderWidgetHostViewAura* rwhva = ToRenderWidgetHostViewAura( 1019 web_contents_->GetRenderWidgetHostView()); 1020 touch_editable_->AttachToView(rwhva); 1021 } 1022 1023 void 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 1031 gfx::NativeView WebContentsViewAura::GetNativeView() const { 1032 return window_.get(); 1033 } 1034 1035 gfx::NativeView WebContentsViewAura::GetContentNativeView() const { 1036 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); 1037 return rwhv ? rwhv->GetNativeView() : NULL; 1038 } 1039 1040 gfx::NativeWindow WebContentsViewAura::GetTopLevelNativeWindow() const { 1041 return window_->GetToplevelWindow(); 1042 } 1043 1044 void WebContentsViewAura::GetContainerBounds(gfx::Rect *out) const { 1045 *out = window_->GetBoundsInScreen(); 1046 } 1047 1048 void 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 1056 void 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 1068 void 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 1082 void WebContentsViewAura::SetInitialFocus() { 1083 if (web_contents_->FocusLocationBarByDefault()) 1084 web_contents_->SetFocusToLocationBar(false); 1085 else 1086 Focus(); 1087 } 1088 1089 void WebContentsViewAura::StoreFocus() { 1090 if (delegate_) 1091 delegate_->StoreFocus(); 1092 } 1093 1094 void WebContentsViewAura::RestoreFocus() { 1095 if (delegate_) 1096 delegate_->RestoreFocus(); 1097 } 1098 1099 DropData* WebContentsViewAura::GetDropData() const { 1100 return current_drop_data_.get(); 1101 } 1102 1103 gfx::Rect WebContentsViewAura::GetViewBounds() const { 1104 return window_->GetBoundsInScreen(); 1105 } 1106 1107 //////////////////////////////////////////////////////////////////////////////// 1108 // WebContentsViewAura, WebContentsViewPort implementation: 1109 1110 void 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 1151 RenderWidgetHostView* 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 1191 RenderWidgetHostView* WebContentsViewAura::CreateViewForPopupWidget( 1192 RenderWidgetHost* render_widget_host) { 1193 return RenderWidgetHostViewPort::CreateViewForWidget(render_widget_host); 1194 } 1195 1196 void WebContentsViewAura::SetPageTitle(const string16& title) { 1197 window_->set_title(title); 1198 } 1199 1200 void WebContentsViewAura::RenderViewCreated(RenderViewHost* host) { 1201 } 1202 1203 void 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 1211 void 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 1229 void WebContentsViewAura::ShowContextMenu(const ContextMenuParams& params) { 1230 if (delegate_) 1231 delegate_->ShowContextMenu(params); 1232 if (touch_editable_) 1233 touch_editable_->EndTouchEditing(); 1234 1235 } 1236 1237 void 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 1248 void 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 1306 void WebContentsViewAura::UpdateDragCursor(WebKit::WebDragOperation operation) { 1307 current_drag_op_ = operation; 1308 } 1309 1310 void WebContentsViewAura::GotFocus() { 1311 if (web_contents_->GetDelegate()) 1312 web_contents_->GetDelegate()->WebContentsFocused(web_contents_); 1313 } 1314 1315 void 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 1326 void 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 1347 void 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 1360 void 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 && touch_editable_) 1366 touch_editable_->OverscrollStarted(); 1367 1368 if (new_mode == OVERSCROLL_NONE || 1369 !GetContentNativeView() || 1370 ((new_mode == OVERSCROLL_EAST || new_mode == OVERSCROLL_WEST) && 1371 navigation_overlay_.get() && navigation_overlay_->has_window())) { 1372 current_overscroll_gesture_ = OVERSCROLL_NONE; 1373 OverscrollUpdateForWebContentsDelegate(0); 1374 } else { 1375 aura::Window* target = GetWindowToAnimateForOverscroll(); 1376 if (target) { 1377 StopObservingImplicitAnimations(); 1378 target->layer()->GetAnimator()->AbortAllAnimations(); 1379 } 1380 // Cleanup state of the content window first, because that can reset the 1381 // value of |current_overscroll_gesture_|. 1382 PrepareContentWindowForOverscroll(); 1383 1384 current_overscroll_gesture_ = new_mode; 1385 if (current_overscroll_gesture_ == OVERSCROLL_EAST || 1386 current_overscroll_gesture_ == OVERSCROLL_WEST) 1387 PrepareOverscrollWindow(); 1388 1389 UMA_HISTOGRAM_ENUMERATION("Overscroll.Started", new_mode, OVERSCROLL_COUNT); 1390 } 1391 completed_overscroll_gesture_ = OVERSCROLL_NONE; 1392 } 1393 1394 //////////////////////////////////////////////////////////////////////////////// 1395 // WebContentsViewAura, ui::ImplicitAnimationObserver implementation: 1396 1397 void WebContentsViewAura::OnImplicitAnimationsCompleted() { 1398 overscroll_shadow_.reset(); 1399 1400 if (ShouldNavigateForward(web_contents_->GetController(), 1401 completed_overscroll_gesture_)) { 1402 PrepareOverscrollNavigationOverlay(); 1403 web_contents_->GetController().GoForward(); 1404 } else if (ShouldNavigateBack(web_contents_->GetController(), 1405 completed_overscroll_gesture_)) { 1406 PrepareOverscrollNavigationOverlay(); 1407 web_contents_->GetController().GoBack(); 1408 } else { 1409 if (touch_editable_) 1410 touch_editable_->OverscrollCompleted(); 1411 } 1412 1413 aura::Window* content = GetContentNativeView(); 1414 if (content) { 1415 content->SetTransform(gfx::Transform()); 1416 content->layer()->SetLayerBrightness(0.f); 1417 } 1418 current_overscroll_gesture_ = OVERSCROLL_NONE; 1419 completed_overscroll_gesture_ = OVERSCROLL_NONE; 1420 overscroll_window_.reset(); 1421 } 1422 1423 //////////////////////////////////////////////////////////////////////////////// 1424 // WebContentsViewAura, aura::WindowDelegate implementation: 1425 1426 gfx::Size WebContentsViewAura::GetMinimumSize() const { 1427 return gfx::Size(); 1428 } 1429 1430 gfx::Size WebContentsViewAura::GetMaximumSize() const { 1431 return gfx::Size(); 1432 } 1433 1434 void WebContentsViewAura::OnBoundsChanged(const gfx::Rect& old_bounds, 1435 const gfx::Rect& new_bounds) { 1436 SizeChangedCommon(new_bounds.size()); 1437 if (delegate_) 1438 delegate_->SizeChanged(new_bounds.size()); 1439 1440 // Constrained web dialogs, need to be kept centered over our content area. 1441 for (size_t i = 0; i < window_->children().size(); i++) { 1442 if (window_->children()[i]->GetProperty( 1443 aura::client::kConstrainedWindowKey)) { 1444 gfx::Rect bounds = window_->children()[i]->bounds(); 1445 bounds.set_origin( 1446 gfx::Point((new_bounds.width() - bounds.width()) / 2, 1447 (new_bounds.height() - bounds.height()) / 2)); 1448 window_->children()[i]->SetBounds(bounds); 1449 } 1450 } 1451 } 1452 1453 gfx::NativeCursor WebContentsViewAura::GetCursor(const gfx::Point& point) { 1454 return gfx::kNullCursor; 1455 } 1456 1457 int WebContentsViewAura::GetNonClientComponent(const gfx::Point& point) const { 1458 return HTCLIENT; 1459 } 1460 1461 bool WebContentsViewAura::ShouldDescendIntoChildForEventHandling( 1462 aura::Window* child, 1463 const gfx::Point& location) { 1464 return true; 1465 } 1466 1467 bool WebContentsViewAura::CanFocus() { 1468 // Do not take the focus if the render widget host view is gone because 1469 // neither the view window nor this window can handle key events. 1470 return web_contents_->GetRenderWidgetHostView() != NULL; 1471 } 1472 1473 void WebContentsViewAura::OnCaptureLost() { 1474 } 1475 1476 void WebContentsViewAura::OnPaint(gfx::Canvas* canvas) { 1477 } 1478 1479 void WebContentsViewAura::OnDeviceScaleFactorChanged( 1480 float device_scale_factor) { 1481 } 1482 1483 void WebContentsViewAura::OnWindowDestroying() { 1484 // This means the destructor is going to be called soon. If there is an 1485 // overscroll gesture in progress (i.e. |overscroll_window_| is not NULL), 1486 // then destroying it in the WebContentsViewAura destructor can trigger other 1487 // virtual functions to be called (e.g. OnImplicitAnimationsCompleted()). So 1488 // destroy the overscroll window here. 1489 navigation_overlay_.reset(); 1490 overscroll_window_.reset(); 1491 } 1492 1493 void WebContentsViewAura::OnWindowDestroyed() { 1494 } 1495 1496 void WebContentsViewAura::OnWindowTargetVisibilityChanged(bool visible) { 1497 if (visible) 1498 web_contents_->WasShown(); 1499 else 1500 web_contents_->WasHidden(); 1501 } 1502 1503 bool WebContentsViewAura::HasHitTestMask() const { 1504 return false; 1505 } 1506 1507 void WebContentsViewAura::GetHitTestMask(gfx::Path* mask) const { 1508 } 1509 1510 scoped_refptr<ui::Texture> WebContentsViewAura::CopyTexture() { 1511 // The layer we create doesn't have an external texture, so this should never 1512 // get invoked. 1513 NOTREACHED(); 1514 return scoped_refptr<ui::Texture>(); 1515 } 1516 1517 //////////////////////////////////////////////////////////////////////////////// 1518 // WebContentsViewAura, ui::EventHandler implementation: 1519 1520 void WebContentsViewAura::OnKeyEvent(ui::KeyEvent* event) { 1521 } 1522 1523 void WebContentsViewAura::OnMouseEvent(ui::MouseEvent* event) { 1524 if (!web_contents_->GetDelegate()) 1525 return; 1526 1527 switch (event->type()) { 1528 case ui::ET_MOUSE_PRESSED: 1529 web_contents_->GetDelegate()->ActivateContents(web_contents_); 1530 break; 1531 case ui::ET_MOUSE_MOVED: 1532 case ui::ET_MOUSE_EXITED: 1533 web_contents_->GetDelegate()->ContentsMouseEvent( 1534 web_contents_, 1535 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(), 1536 event->type() == ui::ET_MOUSE_MOVED); 1537 break; 1538 default: 1539 break; 1540 } 1541 } 1542 1543 //////////////////////////////////////////////////////////////////////////////// 1544 // WebContentsViewAura, aura::client::DragDropDelegate implementation: 1545 1546 void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) { 1547 if (drag_dest_delegate_) 1548 drag_dest_delegate_->DragInitialize(web_contents_); 1549 1550 current_drop_data_.reset(new DropData()); 1551 1552 PrepareDropData(current_drop_data_.get(), event.data()); 1553 WebKit::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); 1554 1555 gfx::Point screen_pt = 1556 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 1557 current_rvh_for_drag_ = web_contents_->GetRenderViewHost(); 1558 web_contents_->GetRenderViewHost()->DragTargetDragEnter( 1559 *current_drop_data_.get(), event.location(), screen_pt, op, 1560 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1561 1562 if (drag_dest_delegate_) { 1563 drag_dest_delegate_->OnReceiveDragData(event.data()); 1564 drag_dest_delegate_->OnDragEnter(); 1565 } 1566 } 1567 1568 int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) { 1569 DCHECK(current_rvh_for_drag_); 1570 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1571 OnDragEntered(event); 1572 1573 WebKit::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); 1574 gfx::Point screen_pt = 1575 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 1576 web_contents_->GetRenderViewHost()->DragTargetDragOver( 1577 event.location(), screen_pt, op, 1578 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1579 1580 if (drag_dest_delegate_) 1581 drag_dest_delegate_->OnDragOver(); 1582 1583 return ConvertFromWeb(current_drag_op_); 1584 } 1585 1586 void WebContentsViewAura::OnDragExited() { 1587 DCHECK(current_rvh_for_drag_); 1588 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1589 return; 1590 1591 web_contents_->GetRenderViewHost()->DragTargetDragLeave(); 1592 if (drag_dest_delegate_) 1593 drag_dest_delegate_->OnDragLeave(); 1594 1595 current_drop_data_.reset(); 1596 } 1597 1598 int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) { 1599 DCHECK(current_rvh_for_drag_); 1600 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1601 OnDragEntered(event); 1602 1603 web_contents_->GetRenderViewHost()->DragTargetDrop( 1604 event.location(), 1605 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(), 1606 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1607 if (drag_dest_delegate_) 1608 drag_dest_delegate_->OnDrop(); 1609 current_drop_data_.reset(); 1610 return current_drag_op_; 1611 } 1612 1613 } // namespace content 1614