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