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