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