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