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