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