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