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