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