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