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