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/files/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/renderer_host/web_input_event_aura.h" 23 #include "content/browser/web_contents/aura/gesture_nav_simple.h" 24 #include "content/browser/web_contents/aura/image_window_delegate.h" 25 #include "content/browser/web_contents/aura/overscroll_navigation_overlay.h" 26 #include "content/browser/web_contents/aura/shadow_layer_delegate.h" 27 #include "content/browser/web_contents/aura/window_slider.h" 28 #include "content/browser/web_contents/touch_editable_impl_aura.h" 29 #include "content/browser/web_contents/web_contents_impl.h" 30 #include "content/public/browser/content_browser_client.h" 31 #include "content/public/browser/notification_observer.h" 32 #include "content/public/browser/notification_registrar.h" 33 #include "content/public/browser/notification_source.h" 34 #include "content/public/browser/notification_types.h" 35 #include "content/public/browser/overscroll_configuration.h" 36 #include "content/public/browser/render_view_host.h" 37 #include "content/public/browser/render_widget_host.h" 38 #include "content/public/browser/render_widget_host_view.h" 39 #include "content/public/browser/web_contents_delegate.h" 40 #include "content/public/browser/web_contents_observer.h" 41 #include "content/public/browser/web_contents_view_delegate.h" 42 #include "content/public/browser/web_drag_dest_delegate.h" 43 #include "content/public/common/content_client.h" 44 #include "content/public/common/content_switches.h" 45 #include "content/public/common/drop_data.h" 46 #include "net/base/filename_util.h" 47 #include "third_party/WebKit/public/web/WebInputEvent.h" 48 #include "ui/aura/client/aura_constants.h" 49 #include "ui/aura/client/window_tree_client.h" 50 #include "ui/aura/env.h" 51 #include "ui/aura/window.h" 52 #include "ui/aura/window_observer.h" 53 #include "ui/aura/window_tree_host.h" 54 #include "ui/aura/window_tree_host_observer.h" 55 #include "ui/base/clipboard/clipboard.h" 56 #include "ui/base/clipboard/custom_data_helper.h" 57 #include "ui/base/dragdrop/drag_drop_types.h" 58 #include "ui/base/dragdrop/drag_utils.h" 59 #include "ui/base/dragdrop/drop_target_event.h" 60 #include "ui/base/dragdrop/os_exchange_data.h" 61 #include "ui/base/hit_test.h" 62 #include "ui/compositor/layer.h" 63 #include "ui/compositor/scoped_layer_animation_settings.h" 64 #include "ui/events/event.h" 65 #include "ui/events/event_utils.h" 66 #include "ui/gfx/canvas.h" 67 #include "ui/gfx/image/image.h" 68 #include "ui/gfx/image/image_png_rep.h" 69 #include "ui/gfx/image/image_skia.h" 70 #include "ui/gfx/screen.h" 71 #include "ui/wm/public/drag_drop_client.h" 72 #include "ui/wm/public/drag_drop_delegate.h" 73 74 namespace content { 75 WebContentsView* CreateWebContentsView( 76 WebContentsImpl* web_contents, 77 WebContentsViewDelegate* delegate, 78 RenderViewHostDelegateView** render_view_host_delegate_view) { 79 WebContentsViewAura* rv = new WebContentsViewAura(web_contents, delegate); 80 *render_view_host_delegate_view = rv; 81 return rv; 82 } 83 84 namespace { 85 86 bool IsScrollEndEffectEnabled() { 87 return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 88 switches::kScrollEndEffect) == "1"; 89 } 90 91 bool ShouldNavigateForward(const NavigationController& controller, 92 OverscrollMode mode) { 93 return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) && 94 controller.CanGoForward(); 95 } 96 97 bool ShouldNavigateBack(const NavigationController& controller, 98 OverscrollMode mode) { 99 return mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST) && 100 controller.CanGoBack(); 101 } 102 103 RenderWidgetHostViewAura* ToRenderWidgetHostViewAura( 104 RenderWidgetHostView* view) { 105 if (!view || RenderViewHostFactory::has_factory()) 106 return NULL; // Can't cast to RenderWidgetHostViewAura in unit tests. 107 108 RenderViewHost* rvh = RenderViewHost::From(view->GetRenderWidgetHost()); 109 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( 110 rvh ? WebContents::FromRenderViewHost(rvh) : NULL); 111 if (BrowserPluginGuest::IsGuest(web_contents)) 112 return NULL; 113 return static_cast<RenderWidgetHostViewAura*>(view); 114 } 115 116 // The window delegate for the overscroll window. This redirects trackpad events 117 // to the web-contents window. The delegate destroys itself when the window is 118 // destroyed. 119 class OverscrollWindowDelegate : public ImageWindowDelegate { 120 public: 121 OverscrollWindowDelegate(WebContentsImpl* web_contents, 122 OverscrollMode overscroll_mode) 123 : web_contents_(web_contents), 124 forward_events_(true) { 125 const NavigationControllerImpl& controller = web_contents->GetController(); 126 const NavigationEntryImpl* entry = NULL; 127 if (ShouldNavigateForward(controller, overscroll_mode)) { 128 entry = NavigationEntryImpl::FromNavigationEntry( 129 controller.GetEntryAtOffset(1)); 130 } else if (ShouldNavigateBack(controller, overscroll_mode)) { 131 entry = NavigationEntryImpl::FromNavigationEntry( 132 controller.GetEntryAtOffset(-1)); 133 } 134 135 gfx::Image image; 136 if (entry && entry->screenshot().get()) { 137 std::vector<gfx::ImagePNGRep> image_reps; 138 image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(), 1.0f)); 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. 179 class 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. 222 void 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) 239 void 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. 300 const 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. 309 void 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. 320 bool 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. 348 void 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. 391 void 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. 431 int 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 442 blink::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 453 int 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 468 class 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 virtual void OnWindowHierarchyChanged( 507 const aura::WindowObserver::HierarchyChangeParams& params) OVERRIDE { 508 if (params.receiver != view_->window_.get() || 509 !params.target->Contains(view_->window_.get())) { 510 return; 511 } 512 513 // Use the new parent's root window for calculating HiDPI subpixel offset. 514 RenderWidgetHostViewAura* rwhv = ToRenderWidgetHostViewAura( 515 view_->web_contents_->GetRenderWidgetHostView()); 516 if (rwhv) 517 rwhv->SnapToPhysicalPixelBoundary(); 518 } 519 520 #if defined(OS_WIN) 521 // Constrained windows are added as children of the parent's parent's view 522 // which may overlap with windowed NPAPI plugins. In that case, tell the RWHV 523 // so that it can update the plugins' cutout rects accordingly. 524 // Note: this is hard coding how Chrome layer adds its dialogs. Since NPAPI is 525 // going to be deprecated in a year, this is ok for now. The test for this is 526 // PrintPreviewTest.WindowedNPAPIPluginHidden. 527 virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE { 528 if (!new_window->Contains(view_->window_.get())) { 529 // Skip the case when the parent moves to the root window. 530 if (new_window != host_window_) { 531 // Observe sibling windows of the WebContents, or children of the root 532 // window. 533 if (new_window->parent() == host_window_ || 534 new_window->parent() == view_->window_->GetRootWindow()) { 535 new_window->AddObserver(this); 536 } 537 } 538 } 539 540 if (new_window->parent() == host_window_) { 541 UpdateConstrainedWindows(NULL); 542 } 543 } 544 545 virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE { 546 if (window == view_->window_) 547 return; 548 549 window->RemoveObserver(this); 550 UpdateConstrainedWindows(window); 551 } 552 553 virtual void OnWindowVisibilityChanged(aura::Window* window, 554 bool visible) OVERRIDE { 555 if (window == view_->window_ || 556 window->parent() == host_window_ || 557 window->parent() == view_->window_->GetRootWindow()) { 558 UpdateConstrainedWindows(NULL); 559 } 560 } 561 #endif 562 563 virtual void OnWindowParentChanged(aura::Window* window, 564 aura::Window* parent) OVERRIDE { 565 if (window != view_->window_) 566 return; 567 568 aura::Window* host_window = 569 window->GetProperty(aura::client::kHostWindowKey); 570 if (!host_window) 571 host_window = parent; 572 573 if (host_window_) 574 host_window_->RemoveObserver(this); 575 576 #if defined(OS_WIN) 577 if (host_window_) { 578 const aura::Window::Windows& children = host_window_->children(); 579 for (size_t i = 0; i < children.size(); ++i) 580 children[i]->RemoveObserver(this); 581 RenderWidgetHostViewAura* rwhv = ToRenderWidgetHostViewAura( 582 view_->web_contents_->GetRenderWidgetHostView()); 583 if (rwhv) 584 rwhv->UpdateConstrainedWindowRects(std::vector<gfx::Rect>()); 585 } 586 587 // When we get parented to the root window, the code below will watch the 588 // host window, aka root window. Since we already watch the root window on 589 // Windows, unregister first so that the debug check doesn't fire. 590 if (host_window && host_window == window->GetRootWindow()) 591 host_window->RemoveObserver(this); 592 593 // We need to undo the above if we were parented to the root window and then 594 // got parented to another window. At that point, the code before the ifdef 595 // would have stopped watching the root window. 596 if (window->GetRootWindow() && 597 host_window != window->GetRootWindow() && 598 !window->GetRootWindow()->HasObserver(this)) { 599 window->GetRootWindow()->AddObserver(this); 600 } 601 #endif 602 603 host_window_ = host_window; 604 if (host_window) { 605 host_window->AddObserver(this); 606 #if defined(OS_WIN) 607 if (host_window != window->GetRootWindow()) { 608 const aura::Window::Windows& children = host_window->children(); 609 for (size_t i = 0; i < children.size(); ++i) { 610 if (!children[i]->Contains(view_->window_.get())) 611 children[i]->AddObserver(this); 612 } 613 } 614 #endif 615 } 616 } 617 618 virtual void OnWindowBoundsChanged(aura::Window* window, 619 const gfx::Rect& old_bounds, 620 const gfx::Rect& new_bounds) OVERRIDE { 621 if (window == host_window_ || window == view_->window_) { 622 SendScreenRects(); 623 if (view_->touch_editable_) 624 view_->touch_editable_->UpdateEditingController(); 625 #if defined(OS_WIN) 626 } else { 627 UpdateConstrainedWindows(NULL); 628 #endif 629 } 630 } 631 632 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { 633 if (window == host_window_) { 634 host_window_->RemoveObserver(this); 635 host_window_ = NULL; 636 } 637 } 638 639 virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE { 640 if (window == view_->window_) { 641 window->GetHost()->AddObserver(this); 642 #if defined(OS_WIN) 643 if (!window->GetRootWindow()->HasObserver(this)) 644 window->GetRootWindow()->AddObserver(this); 645 #endif 646 } 647 } 648 649 virtual void OnWindowRemovingFromRootWindow(aura::Window* window, 650 aura::Window* new_root) OVERRIDE { 651 if (window == view_->window_) { 652 window->GetHost()->RemoveObserver(this); 653 #if defined(OS_WIN) 654 window->GetRootWindow()->RemoveObserver(this); 655 656 const aura::Window::Windows& root_children = 657 window->GetRootWindow()->children(); 658 for (size_t i = 0; i < root_children.size(); ++i) { 659 if (root_children[i] != view_->window_ && 660 root_children[i] != host_window_) { 661 root_children[i]->RemoveObserver(this); 662 } 663 } 664 #endif 665 } 666 } 667 668 // Overridden WindowTreeHostObserver: 669 virtual void OnHostMoved(const aura::WindowTreeHost* host, 670 const gfx::Point& new_origin) OVERRIDE { 671 TRACE_EVENT1("ui", 672 "WebContentsViewAura::WindowObserver::OnHostMoved", 673 "new_origin", new_origin.ToString()); 674 675 // This is for the desktop case (i.e. Aura desktop). 676 SendScreenRects(); 677 } 678 679 private: 680 void SendScreenRects() { 681 RenderWidgetHostImpl::From(view_->web_contents_->GetRenderViewHost())-> 682 SendScreenRects(); 683 } 684 685 #if defined(OS_WIN) 686 void UpdateConstrainedWindows(aura::Window* exclude) { 687 RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura( 688 view_->web_contents_->GetRenderWidgetHostView()); 689 if (!view) 690 return; 691 692 std::vector<gfx::Rect> constrained_windows; 693 if (host_window_) { 694 const aura::Window::Windows& children = host_window_->children(); 695 for (size_t i = 0; i < children.size(); ++i) { 696 if (!children[i]->Contains(view_->window_.get()) && 697 children[i] != exclude && 698 children[i]->IsVisible()) { 699 constrained_windows.push_back(children[i]->GetBoundsInRootWindow()); 700 } 701 } 702 } 703 704 aura::Window* root_window = view_->window_->GetRootWindow(); 705 const aura::Window::Windows& root_children = root_window->children(); 706 if (root_window) { 707 for (size_t i = 0; i < root_children.size(); ++i) { 708 if (root_children[i]->IsVisible() && 709 !root_children[i]->Contains(view_->window_.get())) { 710 constrained_windows.push_back( 711 root_children[i]->GetBoundsInRootWindow()); 712 } 713 } 714 } 715 716 view->UpdateConstrainedWindowRects(constrained_windows); 717 } 718 #endif 719 720 WebContentsViewAura* view_; 721 722 // The parent window that hosts the constrained windows. We cache the old host 723 // view so that we can unregister when it's not the parent anymore. 724 aura::Window* host_window_; 725 726 DISALLOW_COPY_AND_ASSIGN(WindowObserver); 727 }; 728 729 //////////////////////////////////////////////////////////////////////////////// 730 // WebContentsViewAura, public: 731 732 WebContentsViewAura::WebContentsViewAura( 733 WebContentsImpl* web_contents, 734 WebContentsViewDelegate* delegate) 735 : web_contents_(web_contents), 736 delegate_(delegate), 737 current_drag_op_(blink::WebDragOperationNone), 738 drag_dest_delegate_(NULL), 739 current_rvh_for_drag_(NULL), 740 overscroll_change_brightness_(false), 741 current_overscroll_gesture_(OVERSCROLL_NONE), 742 completed_overscroll_gesture_(OVERSCROLL_NONE), 743 touch_editable_(TouchEditableImplAura::Create()), 744 is_or_was_visible_(false) { 745 } 746 747 //////////////////////////////////////////////////////////////////////////////// 748 // WebContentsViewAura, private: 749 750 WebContentsViewAura::~WebContentsViewAura() { 751 if (!window_) 752 return; 753 754 window_observer_.reset(); 755 window_->RemoveObserver(this); 756 757 // Window needs a valid delegate during its destructor, so we explicitly 758 // delete it here. 759 window_.reset(); 760 } 761 762 void WebContentsViewAura::SetTouchEditableForTest( 763 TouchEditableImplAura* touch_editable) { 764 touch_editable_.reset(touch_editable); 765 AttachTouchEditableToRenderView(); 766 } 767 768 void WebContentsViewAura::SizeChangedCommon(const gfx::Size& size) { 769 if (web_contents_->GetInterstitialPage()) 770 web_contents_->GetInterstitialPage()->SetSize(size); 771 RenderWidgetHostView* rwhv = 772 web_contents_->GetRenderWidgetHostView(); 773 if (rwhv) 774 rwhv->SetSize(size); 775 } 776 777 void WebContentsViewAura::EndDrag(blink::WebDragOperationsMask ops) { 778 aura::Window* root_window = GetNativeView()->GetRootWindow(); 779 gfx::Point screen_loc = 780 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 781 gfx::Point client_loc = screen_loc; 782 RenderViewHost* rvh = web_contents_->GetRenderViewHost(); 783 aura::Window* window = rvh->GetView()->GetNativeView(); 784 aura::Window::ConvertPointToTarget(root_window, window, &client_loc); 785 if (!web_contents_) 786 return; 787 web_contents_->DragSourceEndedAt(client_loc.x(), client_loc.y(), 788 screen_loc.x(), screen_loc.y(), ops); 789 } 790 791 void WebContentsViewAura::InstallOverscrollControllerDelegate( 792 RenderWidgetHostViewAura* view) { 793 const std::string value = base::CommandLine::ForCurrentProcess()-> 794 GetSwitchValueASCII(switches::kOverscrollHistoryNavigation); 795 if (value == "0") { 796 navigation_overlay_.reset(); 797 return; 798 } 799 if (value == "2") { 800 navigation_overlay_.reset(); 801 if (!gesture_nav_simple_) 802 gesture_nav_simple_.reset(new GestureNavSimple(web_contents_)); 803 view->overscroll_controller()->set_delegate(gesture_nav_simple_.get()); 804 return; 805 } 806 view->overscroll_controller()->set_delegate(this); 807 if (!navigation_overlay_) 808 navigation_overlay_.reset(new OverscrollNavigationOverlay(web_contents_)); 809 } 810 811 void WebContentsViewAura::PrepareOverscrollWindow() { 812 // If there is an existing |overscroll_window_| which is in the middle of an 813 // animation, then destroying the window here causes the animation to be 814 // completed immediately, which triggers |OnImplicitAnimationsCompleted()| 815 // callback, and that tries to reset |overscroll_window_| again, causing a 816 // double-free. So use a temporary variable here. 817 if (overscroll_window_) { 818 base::AutoReset<OverscrollMode> reset_state(¤t_overscroll_gesture_, 819 current_overscroll_gesture_); 820 scoped_ptr<aura::Window> reset_window(overscroll_window_.release()); 821 } 822 823 OverscrollWindowDelegate* overscroll_delegate = new OverscrollWindowDelegate( 824 web_contents_, 825 current_overscroll_gesture_); 826 overscroll_window_.reset(new aura::Window(overscroll_delegate)); 827 overscroll_window_->SetType(ui::wm::WINDOW_TYPE_CONTROL); 828 overscroll_window_->SetTransparent(true); 829 overscroll_window_->Init(aura::WINDOW_LAYER_TEXTURED); 830 overscroll_window_->layer()->SetMasksToBounds(false); 831 overscroll_window_->SetName("OverscrollOverlay"); 832 833 overscroll_change_brightness_ = overscroll_delegate->has_image(); 834 window_->AddChild(overscroll_window_.get()); 835 836 gfx::Rect bounds = gfx::Rect(window_->bounds().size()); 837 if (ShouldNavigateForward(web_contents_->GetController(), 838 current_overscroll_gesture_)) { 839 // The overlay will be sliding in from the right edge towards the left in 840 // non-RTL, or sliding in from the left edge towards the right in RTL. 841 // So position the overlay window accordingly. 842 bounds.Offset(base::i18n::IsRTL() ? -bounds.width() : bounds.width(), 0); 843 } 844 845 aura::Window* animate_window = GetWindowToAnimateForOverscroll(); 846 if (animate_window == overscroll_window_) 847 window_->StackChildAbove(overscroll_window_.get(), GetContentNativeView()); 848 else 849 window_->StackChildBelow(overscroll_window_.get(), GetContentNativeView()); 850 851 UpdateOverscrollWindowBrightness(0.f); 852 853 overscroll_window_->SetBounds(bounds); 854 overscroll_window_->Show(); 855 856 overscroll_shadow_.reset(new ShadowLayerDelegate(animate_window->layer())); 857 } 858 859 void WebContentsViewAura::PrepareContentWindowForOverscroll() { 860 StopObservingImplicitAnimations(); 861 aura::Window* content = GetContentNativeView(); 862 content->layer()->GetAnimator()->AbortAllAnimations(); 863 content->SetTransform(gfx::Transform()); 864 content->layer()->SetLayerBrightness(0.f); 865 } 866 867 void WebContentsViewAura::ResetOverscrollTransform() { 868 if (!web_contents_->GetRenderWidgetHostView()) 869 return; 870 aura::Window* target = GetWindowToAnimateForOverscroll(); 871 if (!target) 872 return; 873 { 874 ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator()); 875 settings.SetPreemptionStrategy( 876 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 877 settings.SetTweenType(gfx::Tween::EASE_OUT); 878 settings.AddObserver(this); 879 target->SetTransform(gfx::Transform()); 880 } 881 { 882 ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator()); 883 settings.SetPreemptionStrategy( 884 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 885 settings.SetTweenType(gfx::Tween::EASE_OUT); 886 UpdateOverscrollWindowBrightness(0.f); 887 } 888 } 889 890 void WebContentsViewAura::CompleteOverscrollNavigation(OverscrollMode mode) { 891 if (!web_contents_->GetRenderWidgetHostView()) 892 return; 893 894 // Animate out the current view first. Navigate to the requested history at 895 // the end of the animation. 896 if (current_overscroll_gesture_ == OVERSCROLL_NONE) 897 return; 898 899 UMA_HISTOGRAM_ENUMERATION("Overscroll.Navigated", 900 current_overscroll_gesture_, OVERSCROLL_COUNT); 901 OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>( 902 overscroll_window_->delegate()); 903 delegate->stop_forwarding_events(); 904 905 completed_overscroll_gesture_ = mode; 906 aura::Window* target = GetWindowToAnimateForOverscroll(); 907 ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator()); 908 settings.SetPreemptionStrategy( 909 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 910 settings.SetTweenType(gfx::Tween::EASE_OUT); 911 settings.AddObserver(this); 912 gfx::Transform transform; 913 int content_width = 914 web_contents_->GetRenderWidgetHostView()->GetViewBounds().width(); 915 int translate_x = mode == OVERSCROLL_WEST ? -content_width : content_width; 916 transform.Translate(translate_x, 0); 917 target->SetTransform(transform); 918 UpdateOverscrollWindowBrightness(translate_x); 919 } 920 921 aura::Window* WebContentsViewAura::GetWindowToAnimateForOverscroll() { 922 if (current_overscroll_gesture_ == OVERSCROLL_NONE) 923 return NULL; 924 925 return ShouldNavigateForward(web_contents_->GetController(), 926 current_overscroll_gesture_) ? 927 overscroll_window_.get() : GetContentNativeView(); 928 } 929 930 gfx::Vector2d WebContentsViewAura::GetTranslationForOverscroll(int delta_x, 931 int delta_y) { 932 if (current_overscroll_gesture_ == OVERSCROLL_NORTH || 933 current_overscroll_gesture_ == OVERSCROLL_SOUTH) { 934 return gfx::Vector2d(0, delta_y); 935 } 936 // For horizontal overscroll, scroll freely if a navigation is possible. Do a 937 // resistive scroll otherwise. 938 const NavigationControllerImpl& controller = web_contents_->GetController(); 939 const gfx::Rect& bounds = GetViewBounds(); 940 if (ShouldNavigateForward(controller, current_overscroll_gesture_)) 941 return gfx::Vector2d(std::max(-bounds.width(), delta_x), 0); 942 else if (ShouldNavigateBack(controller, current_overscroll_gesture_)) 943 return gfx::Vector2d(std::min(bounds.width(), delta_x), 0); 944 return gfx::Vector2d(); 945 } 946 947 void WebContentsViewAura::PrepareOverscrollNavigationOverlay() { 948 OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>( 949 overscroll_window_->delegate()); 950 overscroll_window_->SchedulePaintInRect( 951 gfx::Rect(overscroll_window_->bounds().size())); 952 overscroll_window_->SetBounds(gfx::Rect(window_->bounds().size())); 953 overscroll_window_->SetTransform(gfx::Transform()); 954 navigation_overlay_->SetOverlayWindow(overscroll_window_.Pass(), 955 delegate); 956 navigation_overlay_->StartObserving(); 957 } 958 959 void WebContentsViewAura::UpdateOverscrollWindowBrightness(float delta_x) { 960 if (!overscroll_change_brightness_) 961 return; 962 963 const float kBrightnessMin = -.1f; 964 const float kBrightnessMax = -.01f; 965 966 float ratio = fabs(delta_x) / GetViewBounds().width(); 967 ratio = std::min(1.f, ratio); 968 if (base::i18n::IsRTL()) 969 ratio = 1.f - ratio; 970 float brightness = current_overscroll_gesture_ == OVERSCROLL_WEST ? 971 kBrightnessMin + ratio * (kBrightnessMax - kBrightnessMin) : 972 kBrightnessMax - ratio * (kBrightnessMax - kBrightnessMin); 973 brightness = std::max(kBrightnessMin, brightness); 974 brightness = std::min(kBrightnessMax, brightness); 975 aura::Window* window = GetWindowToAnimateForOverscroll(); 976 window->layer()->SetLayerBrightness(brightness); 977 } 978 979 void WebContentsViewAura::AttachTouchEditableToRenderView() { 980 if (!touch_editable_) 981 return; 982 RenderWidgetHostViewAura* rwhva = ToRenderWidgetHostViewAura( 983 web_contents_->GetRenderWidgetHostView()); 984 touch_editable_->AttachToView(rwhva); 985 } 986 987 void WebContentsViewAura::OverscrollUpdateForWebContentsDelegate(int delta_y) { 988 if (web_contents_->GetDelegate() && IsScrollEndEffectEnabled()) 989 web_contents_->GetDelegate()->OverscrollUpdate(delta_y); 990 } 991 992 //////////////////////////////////////////////////////////////////////////////// 993 // WebContentsViewAura, WebContentsView implementation: 994 995 gfx::NativeView WebContentsViewAura::GetNativeView() const { 996 return window_.get(); 997 } 998 999 gfx::NativeView WebContentsViewAura::GetContentNativeView() const { 1000 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); 1001 return rwhv ? rwhv->GetNativeView() : NULL; 1002 } 1003 1004 gfx::NativeWindow WebContentsViewAura::GetTopLevelNativeWindow() const { 1005 return window_->GetToplevelWindow(); 1006 } 1007 1008 void WebContentsViewAura::GetContainerBounds(gfx::Rect *out) const { 1009 *out = window_->GetBoundsInScreen(); 1010 } 1011 1012 void WebContentsViewAura::SizeContents(const gfx::Size& size) { 1013 gfx::Rect bounds = window_->bounds(); 1014 if (bounds.size() != size) { 1015 bounds.set_size(size); 1016 window_->SetBounds(bounds); 1017 } else { 1018 // Our size matches what we want but the renderers size may not match. 1019 // Pretend we were resized so that the renderers size is updated too. 1020 SizeChangedCommon(size); 1021 } 1022 } 1023 1024 void WebContentsViewAura::Focus() { 1025 if (web_contents_->GetInterstitialPage()) { 1026 web_contents_->GetInterstitialPage()->Focus(); 1027 return; 1028 } 1029 1030 if (delegate_.get() && delegate_->Focus()) 1031 return; 1032 1033 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); 1034 if (rwhv) 1035 rwhv->Focus(); 1036 } 1037 1038 void WebContentsViewAura::SetInitialFocus() { 1039 if (web_contents_->FocusLocationBarByDefault()) 1040 web_contents_->SetFocusToLocationBar(false); 1041 else 1042 Focus(); 1043 } 1044 1045 void WebContentsViewAura::StoreFocus() { 1046 if (delegate_) 1047 delegate_->StoreFocus(); 1048 } 1049 1050 void WebContentsViewAura::RestoreFocus() { 1051 if (delegate_) 1052 delegate_->RestoreFocus(); 1053 } 1054 1055 DropData* WebContentsViewAura::GetDropData() const { 1056 return current_drop_data_.get(); 1057 } 1058 1059 gfx::Rect WebContentsViewAura::GetViewBounds() const { 1060 return window_->GetBoundsInScreen(); 1061 } 1062 1063 //////////////////////////////////////////////////////////////////////////////// 1064 // WebContentsViewAura, WebContentsView implementation: 1065 1066 void WebContentsViewAura::CreateView( 1067 const gfx::Size& initial_size, gfx::NativeView context) { 1068 // NOTE: we ignore |initial_size| since in some cases it's wrong (such as 1069 // if the bookmark bar is not shown and you create a new tab). The right 1070 // value is set shortly after this, so its safe to ignore. 1071 1072 aura::Env::CreateInstance(true); 1073 window_.reset(new aura::Window(this)); 1074 window_->set_owned_by_parent(false); 1075 window_->SetType(ui::wm::WINDOW_TYPE_CONTROL); 1076 window_->SetTransparent(false); 1077 window_->Init(aura::WINDOW_LAYER_NOT_DRAWN); 1078 window_->AddObserver(this); 1079 aura::Window* root_window = context ? context->GetRootWindow() : NULL; 1080 if (root_window) { 1081 // There are places where there is no context currently because object 1082 // hierarchies are built before they're attached to a Widget. (See 1083 // views::WebView as an example; GetWidget() returns NULL at the point 1084 // where we are created.) 1085 // 1086 // It should be OK to not set a default parent since such users will 1087 // explicitly add this WebContentsViewAura to their tree after they create 1088 // us. 1089 if (root_window) { 1090 aura::client::ParentWindowWithContext( 1091 window_.get(), root_window, root_window->GetBoundsInScreen()); 1092 } 1093 } 1094 window_->layer()->SetMasksToBounds(true); 1095 window_->SetName("WebContentsViewAura"); 1096 1097 // WindowObserver is not interesting and is problematic for Browser Plugin 1098 // guests. 1099 // The use cases for WindowObserver do not apply to Browser Plugins: 1100 // 1) guests do not support NPAPI plugins. 1101 // 2) guests' window bounds are supposed to come from its embedder. 1102 if (!BrowserPluginGuest::IsGuest(web_contents_)) 1103 window_observer_.reset(new WindowObserver(this)); 1104 1105 // delegate_->GetDragDestDelegate() creates a new delegate on every call. 1106 // Hence, we save a reference to it locally. Similar model is used on other 1107 // platforms as well. 1108 if (delegate_) 1109 drag_dest_delegate_ = delegate_->GetDragDestDelegate(); 1110 } 1111 1112 RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForWidget( 1113 RenderWidgetHost* render_widget_host) { 1114 if (render_widget_host->GetView()) { 1115 // During testing, the view will already be set up in most cases to the 1116 // test view, so we don't want to clobber it with a real one. To verify that 1117 // this actually is happening (and somebody isn't accidentally creating the 1118 // view twice), we check for the RVH Factory, which will be set when we're 1119 // making special ones (which go along with the special views). 1120 DCHECK(RenderViewHostFactory::has_factory()); 1121 return static_cast<RenderWidgetHostViewBase*>( 1122 render_widget_host->GetView()); 1123 } 1124 1125 RenderWidgetHostViewAura* view = 1126 new RenderWidgetHostViewAura(render_widget_host); 1127 view->InitAsChild(NULL); 1128 GetNativeView()->AddChild(view->GetNativeView()); 1129 1130 if (navigation_overlay_.get() && navigation_overlay_->has_window()) { 1131 navigation_overlay_->StartObserving(); 1132 } 1133 1134 RenderWidgetHostImpl* host_impl = 1135 RenderWidgetHostImpl::From(render_widget_host); 1136 1137 if (!host_impl->is_hidden()) 1138 view->Show(); 1139 1140 // We listen to drag drop events in the newly created view's window. 1141 aura::client::SetDragDropDelegate(view->GetNativeView(), this); 1142 1143 if (view->overscroll_controller() && 1144 (!web_contents_->GetDelegate() || 1145 web_contents_->GetDelegate()->CanOverscrollContent())) { 1146 InstallOverscrollControllerDelegate(view); 1147 } 1148 1149 AttachTouchEditableToRenderView(); 1150 return view; 1151 } 1152 1153 RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForPopupWidget( 1154 RenderWidgetHost* render_widget_host) { 1155 return new RenderWidgetHostViewAura(render_widget_host); 1156 } 1157 1158 void WebContentsViewAura::SetPageTitle(const base::string16& title) { 1159 window_->SetTitle(title); 1160 } 1161 1162 void WebContentsViewAura::RenderViewCreated(RenderViewHost* host) { 1163 } 1164 1165 void WebContentsViewAura::RenderViewSwappedIn(RenderViewHost* host) { 1166 if (navigation_overlay_.get() && navigation_overlay_->has_window()) 1167 navigation_overlay_->StartObserving(); 1168 AttachTouchEditableToRenderView(); 1169 } 1170 1171 void WebContentsViewAura::SetOverscrollControllerEnabled(bool enabled) { 1172 RenderWidgetHostViewAura* view = 1173 ToRenderWidgetHostViewAura(web_contents_->GetRenderWidgetHostView()); 1174 if (view) { 1175 view->SetOverscrollControllerEnabled(enabled); 1176 if (enabled) 1177 InstallOverscrollControllerDelegate(view); 1178 } 1179 1180 if (!enabled) 1181 navigation_overlay_.reset(); 1182 else if (!navigation_overlay_) 1183 navigation_overlay_.reset(new OverscrollNavigationOverlay(web_contents_)); 1184 } 1185 1186 //////////////////////////////////////////////////////////////////////////////// 1187 // WebContentsViewAura, RenderViewHostDelegateView implementation: 1188 1189 void WebContentsViewAura::ShowContextMenu(RenderFrameHost* render_frame_host, 1190 const ContextMenuParams& params) { 1191 if (touch_editable_) { 1192 touch_editable_->EndTouchEditing(false); 1193 } 1194 if (delegate_) { 1195 delegate_->ShowContextMenu(render_frame_host, params); 1196 // WARNING: we may have been deleted during the call to ShowContextMenu(). 1197 } 1198 } 1199 1200 void WebContentsViewAura::StartDragging( 1201 const DropData& drop_data, 1202 blink::WebDragOperationsMask operations, 1203 const gfx::ImageSkia& image, 1204 const gfx::Vector2d& image_offset, 1205 const DragEventSourceInfo& event_info) { 1206 aura::Window* root_window = GetNativeView()->GetRootWindow(); 1207 if (!aura::client::GetDragDropClient(root_window)) { 1208 web_contents_->SystemDragEnded(); 1209 return; 1210 } 1211 1212 if (touch_editable_) 1213 touch_editable_->EndTouchEditing(false); 1214 1215 ui::OSExchangeData::Provider* provider = ui::OSExchangeData::CreateProvider(); 1216 PrepareDragData(drop_data, provider, web_contents_); 1217 1218 ui::OSExchangeData data(provider); // takes ownership of |provider|. 1219 1220 if (!image.isNull()) 1221 drag_utils::SetDragImageOnDataObject(image, image_offset, &data); 1222 1223 scoped_ptr<WebDragSourceAura> drag_source( 1224 new WebDragSourceAura(GetNativeView(), web_contents_)); 1225 1226 // We need to enable recursive tasks on the message loop so we can get 1227 // updates while in the system DoDragDrop loop. 1228 int result_op = 0; 1229 { 1230 gfx::NativeView content_native_view = GetContentNativeView(); 1231 base::MessageLoop::ScopedNestableTaskAllower allow( 1232 base::MessageLoop::current()); 1233 result_op = aura::client::GetDragDropClient(root_window) 1234 ->StartDragAndDrop(data, 1235 root_window, 1236 content_native_view, 1237 event_info.event_location, 1238 ConvertFromWeb(operations), 1239 event_info.event_source); 1240 } 1241 1242 // Bail out immediately if the contents view window is gone. Note that it is 1243 // not safe to access any class members in this case since |this| may already 1244 // be destroyed. The local variable |drag_source| will still be valid though, 1245 // so we can use it to determine if the window is gone. 1246 if (!drag_source->window()) { 1247 // Note that in this case, we don't need to call SystemDragEnded() since the 1248 // renderer is going away. 1249 return; 1250 } 1251 1252 EndDrag(ConvertToWeb(result_op)); 1253 web_contents_->SystemDragEnded(); 1254 } 1255 1256 void WebContentsViewAura::UpdateDragCursor(blink::WebDragOperation operation) { 1257 current_drag_op_ = operation; 1258 } 1259 1260 void WebContentsViewAura::GotFocus() { 1261 if (web_contents_->GetDelegate()) 1262 web_contents_->GetDelegate()->WebContentsFocused(web_contents_); 1263 } 1264 1265 void WebContentsViewAura::TakeFocus(bool reverse) { 1266 if (web_contents_->GetDelegate() && 1267 !web_contents_->GetDelegate()->TakeFocus(web_contents_, reverse) && 1268 delegate_.get()) { 1269 delegate_->TakeFocus(reverse); 1270 } 1271 } 1272 1273 void WebContentsViewAura::ShowDisambiguationPopup( 1274 const gfx::Rect& target_rect, 1275 const SkBitmap& zoomed_bitmap, 1276 const base::Callback<void(ui::GestureEvent*)>& gesture_cb, 1277 const base::Callback<void(ui::MouseEvent*)>& mouse_cb) { 1278 if (delegate_) { 1279 delegate_->ShowDisambiguationPopup(target_rect, zoomed_bitmap, 1280 window_.get(), gesture_cb, mouse_cb); 1281 } 1282 } 1283 1284 void WebContentsViewAura::HideDisambiguationPopup() { 1285 if (delegate_) 1286 delegate_->HideDisambiguationPopup(); 1287 } 1288 1289 //////////////////////////////////////////////////////////////////////////////// 1290 // WebContentsViewAura, OverscrollControllerDelegate implementation: 1291 1292 gfx::Rect WebContentsViewAura::GetVisibleBounds() const { 1293 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); 1294 if (!rwhv || !rwhv->IsShowing()) 1295 return gfx::Rect(); 1296 1297 return rwhv->GetViewBounds(); 1298 } 1299 1300 bool WebContentsViewAura::OnOverscrollUpdate(float delta_x, float delta_y) { 1301 if (current_overscroll_gesture_ == OVERSCROLL_NONE) 1302 return false; 1303 1304 aura::Window* target = GetWindowToAnimateForOverscroll(); 1305 gfx::Vector2d translate = GetTranslationForOverscroll(delta_x, delta_y); 1306 gfx::Transform transform; 1307 1308 if (current_overscroll_gesture_ == OVERSCROLL_NORTH || 1309 current_overscroll_gesture_ == OVERSCROLL_SOUTH) { 1310 OverscrollUpdateForWebContentsDelegate(translate.y()); 1311 } else { 1312 // Only horizontal overscrolls participate in the navigation gesture. 1313 transform.Translate(translate.x(), translate.y()); 1314 target->SetTransform(transform); 1315 UpdateOverscrollWindowBrightness(delta_x); 1316 } 1317 1318 return !translate.IsZero(); 1319 } 1320 1321 void WebContentsViewAura::OnOverscrollComplete(OverscrollMode mode) { 1322 UMA_HISTOGRAM_ENUMERATION("Overscroll.Completed", mode, OVERSCROLL_COUNT); 1323 if (web_contents_->GetDelegate() && 1324 IsScrollEndEffectEnabled() && 1325 (mode == OVERSCROLL_NORTH || mode == OVERSCROLL_SOUTH)) { 1326 web_contents_->GetDelegate()->OverscrollComplete(); 1327 } 1328 NavigationControllerImpl& controller = web_contents_->GetController(); 1329 if (ShouldNavigateForward(controller, mode) || 1330 ShouldNavigateBack(controller, mode)) { 1331 CompleteOverscrollNavigation(mode); 1332 return; 1333 } 1334 1335 ResetOverscrollTransform(); 1336 } 1337 1338 void WebContentsViewAura::OnOverscrollModeChange(OverscrollMode old_mode, 1339 OverscrollMode new_mode) { 1340 // Reset any in-progress overscroll animation first. 1341 ResetOverscrollTransform(); 1342 1343 if (old_mode == OVERSCROLL_NORTH || old_mode == OVERSCROLL_SOUTH) 1344 OverscrollUpdateForWebContentsDelegate(0); 1345 1346 if (new_mode != OVERSCROLL_NONE && touch_editable_) 1347 touch_editable_->OverscrollStarted(); 1348 1349 if (new_mode == OVERSCROLL_NONE || 1350 !GetContentNativeView() || 1351 ((new_mode == OVERSCROLL_EAST || new_mode == OVERSCROLL_WEST) && 1352 navigation_overlay_.get() && navigation_overlay_->has_window())) { 1353 current_overscroll_gesture_ = OVERSCROLL_NONE; 1354 } else { 1355 aura::Window* target = GetWindowToAnimateForOverscroll(); 1356 if (target) { 1357 StopObservingImplicitAnimations(); 1358 target->layer()->GetAnimator()->AbortAllAnimations(); 1359 } 1360 // Cleanup state of the content window first, because that can reset the 1361 // value of |current_overscroll_gesture_|. 1362 PrepareContentWindowForOverscroll(); 1363 1364 current_overscroll_gesture_ = new_mode; 1365 if (current_overscroll_gesture_ == OVERSCROLL_EAST || 1366 current_overscroll_gesture_ == OVERSCROLL_WEST) 1367 PrepareOverscrollWindow(); 1368 1369 UMA_HISTOGRAM_ENUMERATION("Overscroll.Started", new_mode, OVERSCROLL_COUNT); 1370 } 1371 completed_overscroll_gesture_ = OVERSCROLL_NONE; 1372 } 1373 1374 //////////////////////////////////////////////////////////////////////////////// 1375 // WebContentsViewAura, ui::ImplicitAnimationObserver implementation: 1376 1377 void WebContentsViewAura::OnImplicitAnimationsCompleted() { 1378 overscroll_shadow_.reset(); 1379 1380 if (ShouldNavigateForward(web_contents_->GetController(), 1381 completed_overscroll_gesture_)) { 1382 web_contents_->GetController().GoForward(); 1383 PrepareOverscrollNavigationOverlay(); 1384 } else if (ShouldNavigateBack(web_contents_->GetController(), 1385 completed_overscroll_gesture_)) { 1386 web_contents_->GetController().GoBack(); 1387 PrepareOverscrollNavigationOverlay(); 1388 } else { 1389 if (touch_editable_) 1390 touch_editable_->OverscrollCompleted(); 1391 } 1392 1393 aura::Window* content = GetContentNativeView(); 1394 if (content) { 1395 content->SetTransform(gfx::Transform()); 1396 content->layer()->SetLayerBrightness(0.f); 1397 } 1398 current_overscroll_gesture_ = OVERSCROLL_NONE; 1399 completed_overscroll_gesture_ = OVERSCROLL_NONE; 1400 overscroll_window_.reset(); 1401 } 1402 1403 //////////////////////////////////////////////////////////////////////////////// 1404 // WebContentsViewAura, aura::WindowDelegate implementation: 1405 1406 gfx::Size WebContentsViewAura::GetMinimumSize() const { 1407 return gfx::Size(); 1408 } 1409 1410 gfx::Size WebContentsViewAura::GetMaximumSize() const { 1411 return gfx::Size(); 1412 } 1413 1414 void WebContentsViewAura::OnBoundsChanged(const gfx::Rect& old_bounds, 1415 const gfx::Rect& new_bounds) { 1416 SizeChangedCommon(new_bounds.size()); 1417 if (delegate_) 1418 delegate_->SizeChanged(new_bounds.size()); 1419 1420 // Constrained web dialogs, need to be kept centered over our content area. 1421 for (size_t i = 0; i < window_->children().size(); i++) { 1422 if (window_->children()[i]->GetProperty( 1423 aura::client::kConstrainedWindowKey)) { 1424 gfx::Rect bounds = window_->children()[i]->bounds(); 1425 bounds.set_origin( 1426 gfx::Point((new_bounds.width() - bounds.width()) / 2, 1427 (new_bounds.height() - bounds.height()) / 2)); 1428 window_->children()[i]->SetBounds(bounds); 1429 } 1430 } 1431 } 1432 1433 gfx::NativeCursor WebContentsViewAura::GetCursor(const gfx::Point& point) { 1434 return gfx::kNullCursor; 1435 } 1436 1437 int WebContentsViewAura::GetNonClientComponent(const gfx::Point& point) const { 1438 return HTCLIENT; 1439 } 1440 1441 bool WebContentsViewAura::ShouldDescendIntoChildForEventHandling( 1442 aura::Window* child, 1443 const gfx::Point& location) { 1444 return true; 1445 } 1446 1447 bool WebContentsViewAura::CanFocus() { 1448 // Do not take the focus if the render widget host view aura is gone or 1449 // is in the process of shutting down because neither the view window nor 1450 // this window can handle key events. 1451 RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura( 1452 web_contents_->GetRenderWidgetHostView()); 1453 if (view != NULL && !view->IsClosing()) 1454 return true; 1455 1456 return false; 1457 } 1458 1459 void WebContentsViewAura::OnCaptureLost() { 1460 } 1461 1462 void WebContentsViewAura::OnPaint(gfx::Canvas* canvas) { 1463 } 1464 1465 void WebContentsViewAura::OnDeviceScaleFactorChanged( 1466 float device_scale_factor) { 1467 } 1468 1469 void WebContentsViewAura::OnWindowDestroying(aura::Window* window) { 1470 // This means the destructor is going to be called soon. If there is an 1471 // overscroll gesture in progress (i.e. |overscroll_window_| is not NULL), 1472 // then destroying it in the WebContentsViewAura destructor can trigger other 1473 // virtual functions to be called (e.g. OnImplicitAnimationsCompleted()). So 1474 // destroy the overscroll window here. 1475 navigation_overlay_.reset(); 1476 overscroll_window_.reset(); 1477 } 1478 1479 void WebContentsViewAura::OnWindowDestroyed(aura::Window* window) { 1480 } 1481 1482 void WebContentsViewAura::OnWindowTargetVisibilityChanged(bool visible) { 1483 } 1484 1485 bool WebContentsViewAura::HasHitTestMask() const { 1486 return false; 1487 } 1488 1489 void WebContentsViewAura::GetHitTestMask(gfx::Path* mask) const { 1490 } 1491 1492 //////////////////////////////////////////////////////////////////////////////// 1493 // WebContentsViewAura, ui::EventHandler implementation: 1494 1495 void WebContentsViewAura::OnKeyEvent(ui::KeyEvent* event) { 1496 } 1497 1498 void WebContentsViewAura::OnMouseEvent(ui::MouseEvent* event) { 1499 if (!web_contents_->GetDelegate()) 1500 return; 1501 1502 switch (event->type()) { 1503 case ui::ET_MOUSE_PRESSED: 1504 web_contents_->GetDelegate()->ActivateContents(web_contents_); 1505 break; 1506 case ui::ET_MOUSE_MOVED: 1507 case ui::ET_MOUSE_EXITED: 1508 web_contents_->GetDelegate()->ContentsMouseEvent( 1509 web_contents_, 1510 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(), 1511 event->type() == ui::ET_MOUSE_MOVED); 1512 break; 1513 default: 1514 break; 1515 } 1516 } 1517 1518 //////////////////////////////////////////////////////////////////////////////// 1519 // WebContentsViewAura, aura::client::DragDropDelegate implementation: 1520 1521 void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) { 1522 current_rvh_for_drag_ = web_contents_->GetRenderViewHost(); 1523 current_drop_data_.reset(new DropData()); 1524 1525 PrepareDropData(current_drop_data_.get(), event.data()); 1526 blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); 1527 1528 // Give the delegate an opportunity to cancel the drag. 1529 if (web_contents_->GetDelegate() && 1530 !web_contents_->GetDelegate()->CanDragEnter( 1531 web_contents_, *current_drop_data_.get(), op)) { 1532 current_drop_data_.reset(NULL); 1533 return; 1534 } 1535 1536 if (drag_dest_delegate_) 1537 drag_dest_delegate_->DragInitialize(web_contents_); 1538 1539 gfx::Point screen_pt = 1540 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 1541 web_contents_->GetRenderViewHost()->DragTargetDragEnter( 1542 *current_drop_data_.get(), event.location(), screen_pt, op, 1543 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1544 1545 if (drag_dest_delegate_) { 1546 drag_dest_delegate_->OnReceiveDragData(event.data()); 1547 drag_dest_delegate_->OnDragEnter(); 1548 } 1549 } 1550 1551 int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) { 1552 DCHECK(current_rvh_for_drag_); 1553 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1554 OnDragEntered(event); 1555 1556 if (!current_drop_data_) 1557 return ui::DragDropTypes::DRAG_NONE; 1558 1559 blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); 1560 gfx::Point screen_pt = 1561 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 1562 web_contents_->GetRenderViewHost()->DragTargetDragOver( 1563 event.location(), screen_pt, op, 1564 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1565 1566 if (drag_dest_delegate_) 1567 drag_dest_delegate_->OnDragOver(); 1568 1569 return ConvertFromWeb(current_drag_op_); 1570 } 1571 1572 void WebContentsViewAura::OnDragExited() { 1573 DCHECK(current_rvh_for_drag_); 1574 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1575 return; 1576 1577 if (!current_drop_data_) 1578 return; 1579 1580 web_contents_->GetRenderViewHost()->DragTargetDragLeave(); 1581 if (drag_dest_delegate_) 1582 drag_dest_delegate_->OnDragLeave(); 1583 1584 current_drop_data_.reset(); 1585 } 1586 1587 int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) { 1588 DCHECK(current_rvh_for_drag_); 1589 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1590 OnDragEntered(event); 1591 1592 if (!current_drop_data_) 1593 return ui::DragDropTypes::DRAG_NONE; 1594 1595 web_contents_->GetRenderViewHost()->DragTargetDrop( 1596 event.location(), 1597 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(), 1598 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1599 if (drag_dest_delegate_) 1600 drag_dest_delegate_->OnDrop(); 1601 current_drop_data_.reset(); 1602 return ConvertFromWeb(current_drag_op_); 1603 } 1604 1605 void WebContentsViewAura::OnWindowVisibilityChanged(aura::Window* window, 1606 bool visible) { 1607 // Ignore any visibility changes in the hierarchy below. 1608 if (window != window_.get() && window_->Contains(window)) 1609 return; 1610 1611 UpdateWebContentsVisibility(visible); 1612 } 1613 1614 void WebContentsViewAura::UpdateWebContentsVisibility(bool visible) { 1615 if (!is_or_was_visible_) { 1616 // We should not hide the web contents before it was shown the first time, 1617 // since resources would immediately be destroyed and only re-created after 1618 // content got loaded. In this state the window content is undefined and can 1619 // show garbage. 1620 // However - the page load mechanism requires an activation call through a 1621 // visibility call to (re)load. 1622 if (visible) { 1623 is_or_was_visible_ = true; 1624 web_contents_->WasShown(); 1625 } 1626 return; 1627 } 1628 if (visible) { 1629 if (!web_contents_->should_normally_be_visible()) 1630 web_contents_->WasShown(); 1631 } else { 1632 if (web_contents_->should_normally_be_visible()) 1633 web_contents_->WasHidden(); 1634 } 1635 } 1636 1637 } // namespace content 1638