web_contents_view_aura.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 87 switches::kScrollEndEffect) == "1"; 88} 89 90bool ShouldNavigateForward(const NavigationController& controller, 91 OverscrollMode mode) { 92 return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) && 93 controller.CanGoForward(); 94} 95 96bool ShouldNavigateBack(const NavigationController& controller, 97 OverscrollMode mode) { 98 return mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST) && 99 controller.CanGoBack(); 100} 101 102RenderWidgetHostViewAura* ToRenderWidgetHostViewAura( 103 RenderWidgetHostView* view) { 104 if (!view || RenderViewHostFactory::has_factory()) 105 return NULL; // Can't cast to RenderWidgetHostViewAura in unit tests. 106 107 RenderViewHost* rvh = RenderViewHost::From(view->GetRenderWidgetHost()); 108 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( 109 rvh ? WebContents::FromRenderViewHost(rvh) : NULL); 110 if (BrowserPluginGuest::IsGuest(web_contents)) 111 return NULL; 112 return static_cast<RenderWidgetHostViewAura*>(view); 113} 114 115// The window delegate for the overscroll window. This redirects trackpad events 116// to the web-contents window. The delegate destroys itself when the window is 117// destroyed. 118class OverscrollWindowDelegate : public ImageWindowDelegate { 119 public: 120 OverscrollWindowDelegate(WebContentsImpl* web_contents, 121 OverscrollMode overscroll_mode) 122 : web_contents_(web_contents), 123 forward_events_(true) { 124 const NavigationControllerImpl& controller = web_contents->GetController(); 125 const NavigationEntryImpl* entry = NULL; 126 if (ShouldNavigateForward(controller, overscroll_mode)) { 127 entry = NavigationEntryImpl::FromNavigationEntry( 128 controller.GetEntryAtOffset(1)); 129 } else if (ShouldNavigateBack(controller, overscroll_mode)) { 130 entry = NavigationEntryImpl::FromNavigationEntry( 131 controller.GetEntryAtOffset(-1)); 132 } 133 134 gfx::Image image; 135 if (entry && entry->screenshot().get()) { 136 std::vector<gfx::ImagePNGRep> image_reps; 137 image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(), 138 ui::GetScaleFactorForNativeView(web_contents_window()))); 139 image = gfx::Image(image_reps); 140 } 141 SetImage(image); 142 } 143 144 void stop_forwarding_events() { forward_events_ = false; } 145 146 private: 147 virtual ~OverscrollWindowDelegate() {} 148 149 aura::Window* web_contents_window() { 150 return web_contents_->GetView()->GetContentNativeView(); 151 } 152 153 // Overridden from ui::EventHandler. 154 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE { 155 if (forward_events_ && web_contents_window()) 156 web_contents_window()->delegate()->OnScrollEvent(event); 157 } 158 159 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 160 if (forward_events_ && web_contents_window()) 161 web_contents_window()->delegate()->OnGestureEvent(event); 162 } 163 164 WebContentsImpl* web_contents_; 165 166 // The window is displayed both during the gesture, and after the gesture 167 // while the navigation is in progress. During the gesture, it is necessary to 168 // forward input events to the content page (e.g. when the overscroll window 169 // slides under the cursor and starts receiving scroll events). However, once 170 // the gesture is complete, and the window is being displayed as an overlay 171 // window during navigation, events should not be forwarded anymore. 172 bool forward_events_; 173 174 DISALLOW_COPY_AND_ASSIGN(OverscrollWindowDelegate); 175}; 176 177// Listens to all mouse drag events during a drag and drop and sends them to 178// the renderer. 179class WebDragSourceAura : public NotificationObserver { 180 public: 181 WebDragSourceAura(aura::Window* window, WebContentsImpl* contents) 182 : window_(window), 183 contents_(contents) { 184 registrar_.Add(this, 185 NOTIFICATION_WEB_CONTENTS_DISCONNECTED, 186 Source<WebContents>(contents)); 187 } 188 189 virtual ~WebDragSourceAura() { 190 } 191 192 // NotificationObserver: 193 virtual void Observe(int type, 194 const NotificationSource& source, 195 const NotificationDetails& details) OVERRIDE { 196 if (type != NOTIFICATION_WEB_CONTENTS_DISCONNECTED) 197 return; 198 199 // Cancel the drag if it is still in progress. 200 aura::client::DragDropClient* dnd_client = 201 aura::client::GetDragDropClient(window_->GetRootWindow()); 202 if (dnd_client && dnd_client->IsDragDropInProgress()) 203 dnd_client->DragCancel(); 204 205 window_ = NULL; 206 contents_ = NULL; 207 } 208 209 aura::Window* window() const { return window_; } 210 211 private: 212 aura::Window* window_; 213 WebContentsImpl* contents_; 214 NotificationRegistrar registrar_; 215 216 DISALLOW_COPY_AND_ASSIGN(WebDragSourceAura); 217}; 218 219#if (!defined(OS_CHROMEOS) && defined(USE_X11)) || defined(OS_WIN) 220// Fill out the OSExchangeData with a file contents, synthesizing a name if 221// necessary. 222void PrepareDragForFileContents(const DropData& drop_data, 223 ui::OSExchangeData::Provider* provider) { 224 base::FilePath file_name = 225 base::FilePath::FromUTF16Unsafe(drop_data.file_description_filename); 226 // Images without ALT text will only have a file extension so we need to 227 // synthesize one from the provided extension and URL. 228 if (file_name.BaseName().RemoveExtension().empty()) { 229 const base::FilePath::StringType extension = file_name.Extension(); 230 // Retrieve the name from the URL. 231 file_name = net::GenerateFileName(drop_data.url, "", "", "", "", "") 232 .ReplaceExtension(extension); 233 } 234 provider->SetFileContents(file_name, drop_data.file_contents); 235} 236#endif 237 238#if defined(OS_WIN) 239void PrepareDragForDownload( 240 const DropData& drop_data, 241 ui::OSExchangeData::Provider* provider, 242 WebContentsImpl* web_contents) { 243 const GURL& page_url = web_contents->GetLastCommittedURL(); 244 const std::string& page_encoding = web_contents->GetEncoding(); 245 246 // Parse the download metadata. 247 base::string16 mime_type; 248 base::FilePath file_name; 249 GURL download_url; 250 if (!ParseDownloadMetadata(drop_data.download_metadata, 251 &mime_type, 252 &file_name, 253 &download_url)) 254 return; 255 256 // Generate the file name based on both mime type and proposed file name. 257 std::string default_name = 258 GetContentClient()->browser()->GetDefaultDownloadName(); 259 base::FilePath generated_download_file_name = 260 net::GenerateFileName(download_url, 261 std::string(), 262 std::string(), 263 base::UTF16ToUTF8(file_name.value()), 264 base::UTF16ToUTF8(mime_type), 265 default_name); 266 267 // http://crbug.com/332579 268 base::ThreadRestrictions::ScopedAllowIO allow_file_operations; 269 270 base::FilePath temp_dir_path; 271 if (!base::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome_drag"), 272 &temp_dir_path)) 273 return; 274 275 base::FilePath download_path = 276 temp_dir_path.Append(generated_download_file_name); 277 278 // We cannot know when the target application will be done using the temporary 279 // file, so schedule it to be deleted after rebooting. 280 base::DeleteFileAfterReboot(download_path); 281 base::DeleteFileAfterReboot(temp_dir_path); 282 283 // Provide the data as file (CF_HDROP). A temporary download file with the 284 // Zone.Identifier ADS (Alternate Data Stream) attached will be created. 285 scoped_refptr<DragDownloadFile> download_file = 286 new DragDownloadFile( 287 download_path, 288 base::File(), 289 download_url, 290 Referrer(page_url, drop_data.referrer_policy), 291 page_encoding, 292 web_contents); 293 ui::OSExchangeData::DownloadFileInfo file_download(base::FilePath(), 294 download_file.get()); 295 provider->SetDownloadFileInfo(file_download); 296} 297#endif // defined(OS_WIN) 298 299// Returns the CustomFormat to store file system files. 300const ui::OSExchangeData::CustomFormat& GetFileSystemFileCustomFormat() { 301 static const char kFormatString[] = "chromium/x-file-system-files"; 302 CR_DEFINE_STATIC_LOCAL(ui::OSExchangeData::CustomFormat, 303 format, 304 (ui::Clipboard::GetFormatType(kFormatString))); 305 return format; 306} 307 308// Writes file system files to the pickle. 309void WriteFileSystemFilesToPickle( 310 const std::vector<DropData::FileSystemFileInfo>& file_system_files, 311 Pickle* pickle) { 312 pickle->WriteUInt64(file_system_files.size()); 313 for (size_t i = 0; i < file_system_files.size(); ++i) { 314 pickle->WriteString(file_system_files[i].url.spec()); 315 pickle->WriteInt64(file_system_files[i].size); 316 } 317} 318 319// Reads file system files from the pickle. 320bool ReadFileSystemFilesFromPickle( 321 const Pickle& pickle, 322 std::vector<DropData::FileSystemFileInfo>* file_system_files) { 323 PickleIterator iter(pickle); 324 325 uint64 num_files = 0; 326 if (!pickle.ReadUInt64(&iter, &num_files)) 327 return false; 328 file_system_files->resize(num_files); 329 330 for (uint64 i = 0; i < num_files; ++i) { 331 std::string url_string; 332 int64 size = 0; 333 if (!pickle.ReadString(&iter, &url_string) || 334 !pickle.ReadInt64(&iter, &size)) 335 return false; 336 337 GURL url(url_string); 338 if (!url.is_valid()) 339 return false; 340 341 (*file_system_files)[i].url = url; 342 (*file_system_files)[i].size = size; 343 } 344 return true; 345} 346 347// Utility to fill a ui::OSExchangeDataProvider object from DropData. 348void PrepareDragData(const DropData& drop_data, 349 ui::OSExchangeData::Provider* provider, 350 WebContentsImpl* web_contents) { 351 provider->MarkOriginatedFromRenderer(); 352#if defined(OS_WIN) 353 // Put download before file contents to prefer the download of a image over 354 // its thumbnail link. 355 if (!drop_data.download_metadata.empty()) 356 PrepareDragForDownload(drop_data, provider, web_contents); 357#endif 358#if (!defined(OS_CHROMEOS) && defined(USE_X11)) || defined(OS_WIN) 359 // We set the file contents before the URL because the URL also sets file 360 // contents (to a .URL shortcut). We want to prefer file content data over 361 // a shortcut so we add it first. 362 if (!drop_data.file_contents.empty()) 363 PrepareDragForFileContents(drop_data, provider); 364#endif 365 // Call SetString() before SetURL() when we actually have a custom string. 366 // SetURL() will itself do SetString() when a string hasn't been set yet, 367 // but we want to prefer drop_data.text.string() over the URL string if it 368 // exists. 369 if (!drop_data.text.string().empty()) 370 provider->SetString(drop_data.text.string()); 371 if (drop_data.url.is_valid()) 372 provider->SetURL(drop_data.url, drop_data.url_title); 373 if (!drop_data.html.string().empty()) 374 provider->SetHtml(drop_data.html.string(), drop_data.html_base_url); 375 if (!drop_data.filenames.empty()) 376 provider->SetFilenames(drop_data.filenames); 377 if (!drop_data.file_system_files.empty()) { 378 Pickle pickle; 379 WriteFileSystemFilesToPickle(drop_data.file_system_files, &pickle); 380 provider->SetPickledData(GetFileSystemFileCustomFormat(), pickle); 381 } 382 if (!drop_data.custom_data.empty()) { 383 Pickle pickle; 384 ui::WriteCustomDataToPickle(drop_data.custom_data, &pickle); 385 provider->SetPickledData(ui::Clipboard::GetWebCustomDataFormatType(), 386 pickle); 387 } 388} 389 390// Utility to fill a DropData object from ui::OSExchangeData. 391void PrepareDropData(DropData* drop_data, const ui::OSExchangeData& data) { 392 drop_data->did_originate_from_renderer = data.DidOriginateFromRenderer(); 393 394 base::string16 plain_text; 395 data.GetString(&plain_text); 396 if (!plain_text.empty()) 397 drop_data->text = base::NullableString16(plain_text, false); 398 399 GURL url; 400 base::string16 url_title; 401 data.GetURLAndTitle( 402 ui::OSExchangeData::DO_NOT_CONVERT_FILENAMES, &url, &url_title); 403 if (url.is_valid()) { 404 drop_data->url = url; 405 drop_data->url_title = url_title; 406 } 407 408 base::string16 html; 409 GURL html_base_url; 410 data.GetHtml(&html, &html_base_url); 411 if (!html.empty()) 412 drop_data->html = base::NullableString16(html, false); 413 if (html_base_url.is_valid()) 414 drop_data->html_base_url = html_base_url; 415 416 data.GetFilenames(&drop_data->filenames); 417 418 Pickle pickle; 419 std::vector<DropData::FileSystemFileInfo> file_system_files; 420 if (data.GetPickledData(GetFileSystemFileCustomFormat(), &pickle) && 421 ReadFileSystemFilesFromPickle(pickle, &file_system_files)) 422 drop_data->file_system_files = file_system_files; 423 424 if (data.GetPickledData(ui::Clipboard::GetWebCustomDataFormatType(), &pickle)) 425 ui::ReadCustomDataIntoMap( 426 pickle.data(), pickle.size(), &drop_data->custom_data); 427} 428 429// Utilities to convert between blink::WebDragOperationsMask and 430// ui::DragDropTypes. 431int ConvertFromWeb(blink::WebDragOperationsMask ops) { 432 int drag_op = ui::DragDropTypes::DRAG_NONE; 433 if (ops & blink::WebDragOperationCopy) 434 drag_op |= ui::DragDropTypes::DRAG_COPY; 435 if (ops & blink::WebDragOperationMove) 436 drag_op |= ui::DragDropTypes::DRAG_MOVE; 437 if (ops & blink::WebDragOperationLink) 438 drag_op |= ui::DragDropTypes::DRAG_LINK; 439 return drag_op; 440} 441 442blink::WebDragOperationsMask ConvertToWeb(int drag_op) { 443 int web_drag_op = blink::WebDragOperationNone; 444 if (drag_op & ui::DragDropTypes::DRAG_COPY) 445 web_drag_op |= blink::WebDragOperationCopy; 446 if (drag_op & ui::DragDropTypes::DRAG_MOVE) 447 web_drag_op |= blink::WebDragOperationMove; 448 if (drag_op & ui::DragDropTypes::DRAG_LINK) 449 web_drag_op |= blink::WebDragOperationLink; 450 return (blink::WebDragOperationsMask) web_drag_op; 451} 452 453int ConvertAuraEventFlagsToWebInputEventModifiers(int aura_event_flags) { 454 int web_input_event_modifiers = 0; 455 if (aura_event_flags & ui::EF_SHIFT_DOWN) 456 web_input_event_modifiers |= blink::WebInputEvent::ShiftKey; 457 if (aura_event_flags & ui::EF_CONTROL_DOWN) 458 web_input_event_modifiers |= blink::WebInputEvent::ControlKey; 459 if (aura_event_flags & ui::EF_ALT_DOWN) 460 web_input_event_modifiers |= blink::WebInputEvent::AltKey; 461 if (aura_event_flags & ui::EF_COMMAND_DOWN) 462 web_input_event_modifiers |= blink::WebInputEvent::MetaKey; 463 return web_input_event_modifiers; 464} 465 466} // namespace 467 468class WebContentsViewAura::WindowObserver 469 : public aura::WindowObserver, public aura::WindowTreeHostObserver { 470 public: 471 explicit WindowObserver(WebContentsViewAura* view) 472 : view_(view), 473 host_window_(NULL) { 474 view_->window_->AddObserver(this); 475 476#if defined(OS_WIN) 477 if (view_->window_->GetRootWindow()) 478 view_->window_->GetRootWindow()->AddObserver(this); 479#endif 480 } 481 482 virtual ~WindowObserver() { 483 view_->window_->RemoveObserver(this); 484 if (view_->window_->GetHost()) 485 view_->window_->GetHost()->RemoveObserver(this); 486 if (host_window_) 487 host_window_->RemoveObserver(this); 488#if defined(OS_WIN) 489 if (host_window_) { 490 const aura::Window::Windows& children = host_window_->children(); 491 for (size_t i = 0; i < children.size(); ++i) 492 children[i]->RemoveObserver(this); 493 } 494 495 aura::Window* root_window = view_->window_->GetRootWindow(); 496 if (root_window) { 497 root_window->RemoveObserver(this); 498 const aura::Window::Windows& root_children = root_window->children(); 499 for (size_t i = 0; i < root_children.size(); ++i) 500 root_children[i]->RemoveObserver(this); 501 } 502#endif 503 } 504 505 // Overridden from aura::WindowObserver: 506 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 732WebContentsViewAura::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 750WebContentsViewAura::~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 762void WebContentsViewAura::SetTouchEditableForTest( 763 TouchEditableImplAura* touch_editable) { 764 touch_editable_.reset(touch_editable); 765 AttachTouchEditableToRenderView(); 766} 767 768void 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 777void 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 791void 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 811void 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 immidiately, 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 859void 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 867void 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 890void 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 921aura::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 930gfx::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 947void 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 959void 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 979void WebContentsViewAura::AttachTouchEditableToRenderView() { 980 if (!touch_editable_) 981 return; 982 RenderWidgetHostViewAura* rwhva = ToRenderWidgetHostViewAura( 983 web_contents_->GetRenderWidgetHostView()); 984 touch_editable_->AttachToView(rwhva); 985} 986 987void 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 995gfx::NativeView WebContentsViewAura::GetNativeView() const { 996 return window_.get(); 997} 998 999gfx::NativeView WebContentsViewAura::GetContentNativeView() const { 1000 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); 1001 return rwhv ? rwhv->GetNativeView() : NULL; 1002} 1003 1004gfx::NativeWindow WebContentsViewAura::GetTopLevelNativeWindow() const { 1005 return window_->GetToplevelWindow(); 1006} 1007 1008void WebContentsViewAura::GetContainerBounds(gfx::Rect *out) const { 1009 *out = window_->GetBoundsInScreen(); 1010} 1011 1012void 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 1024void 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 1038void WebContentsViewAura::SetInitialFocus() { 1039 if (web_contents_->FocusLocationBarByDefault()) 1040 web_contents_->SetFocusToLocationBar(false); 1041 else 1042 Focus(); 1043} 1044 1045void WebContentsViewAura::StoreFocus() { 1046 if (delegate_) 1047 delegate_->StoreFocus(); 1048} 1049 1050void WebContentsViewAura::RestoreFocus() { 1051 if (delegate_) 1052 delegate_->RestoreFocus(); 1053} 1054 1055DropData* WebContentsViewAura::GetDropData() const { 1056 return current_drop_data_.get(); 1057} 1058 1059gfx::Rect WebContentsViewAura::GetViewBounds() const { 1060 return window_->GetBoundsInScreen(); 1061} 1062 1063//////////////////////////////////////////////////////////////////////////////// 1064// WebContentsViewAura, WebContentsView implementation: 1065 1066void 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 1112RenderWidgetHostViewBase* 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 1153RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForPopupWidget( 1154 RenderWidgetHost* render_widget_host) { 1155 return new RenderWidgetHostViewAura(render_widget_host); 1156} 1157 1158void WebContentsViewAura::SetPageTitle(const base::string16& title) { 1159 window_->SetTitle(title); 1160} 1161 1162void WebContentsViewAura::RenderViewCreated(RenderViewHost* host) { 1163} 1164 1165void WebContentsViewAura::RenderViewSwappedIn(RenderViewHost* host) { 1166 if (navigation_overlay_.get() && navigation_overlay_->has_window()) 1167 navigation_overlay_->StartObserving(); 1168 AttachTouchEditableToRenderView(); 1169} 1170 1171void 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 1189void 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 1200void 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 1256void WebContentsViewAura::UpdateDragCursor(blink::WebDragOperation operation) { 1257 current_drag_op_ = operation; 1258} 1259 1260void WebContentsViewAura::GotFocus() { 1261 if (web_contents_->GetDelegate()) 1262 web_contents_->GetDelegate()->WebContentsFocused(web_contents_); 1263} 1264 1265void 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//////////////////////////////////////////////////////////////////////////////// 1274// WebContentsViewAura, OverscrollControllerDelegate implementation: 1275 1276gfx::Rect WebContentsViewAura::GetVisibleBounds() const { 1277 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); 1278 if (!rwhv || !rwhv->IsShowing()) 1279 return gfx::Rect(); 1280 1281 return rwhv->GetViewBounds(); 1282} 1283 1284bool WebContentsViewAura::OnOverscrollUpdate(float delta_x, float delta_y) { 1285 if (current_overscroll_gesture_ == OVERSCROLL_NONE) 1286 return false; 1287 1288 aura::Window* target = GetWindowToAnimateForOverscroll(); 1289 gfx::Vector2d translate = GetTranslationForOverscroll(delta_x, delta_y); 1290 gfx::Transform transform; 1291 1292 // Vertical overscrolls don't participate in the navigation gesture. 1293 if (current_overscroll_gesture_ != OVERSCROLL_NORTH && 1294 current_overscroll_gesture_ != OVERSCROLL_SOUTH) { 1295 transform.Translate(translate.x(), translate.y()); 1296 target->SetTransform(transform); 1297 UpdateOverscrollWindowBrightness(delta_x); 1298 } 1299 1300 OverscrollUpdateForWebContentsDelegate(translate.y()); 1301 return !translate.IsZero(); 1302} 1303 1304void WebContentsViewAura::OnOverscrollComplete(OverscrollMode mode) { 1305 UMA_HISTOGRAM_ENUMERATION("Overscroll.Completed", mode, OVERSCROLL_COUNT); 1306 OverscrollUpdateForWebContentsDelegate(0); 1307 NavigationControllerImpl& controller = web_contents_->GetController(); 1308 if (ShouldNavigateForward(controller, mode) || 1309 ShouldNavigateBack(controller, mode)) { 1310 CompleteOverscrollNavigation(mode); 1311 return; 1312 } 1313 1314 ResetOverscrollTransform(); 1315} 1316 1317void WebContentsViewAura::OnOverscrollModeChange(OverscrollMode old_mode, 1318 OverscrollMode new_mode) { 1319 // Reset any in-progress overscroll animation first. 1320 ResetOverscrollTransform(); 1321 1322 if (new_mode != OVERSCROLL_NONE && touch_editable_) 1323 touch_editable_->OverscrollStarted(); 1324 1325 if (new_mode == OVERSCROLL_NONE || 1326 !GetContentNativeView() || 1327 ((new_mode == OVERSCROLL_EAST || new_mode == OVERSCROLL_WEST) && 1328 navigation_overlay_.get() && navigation_overlay_->has_window())) { 1329 current_overscroll_gesture_ = OVERSCROLL_NONE; 1330 OverscrollUpdateForWebContentsDelegate(0); 1331 } else { 1332 aura::Window* target = GetWindowToAnimateForOverscroll(); 1333 if (target) { 1334 StopObservingImplicitAnimations(); 1335 target->layer()->GetAnimator()->AbortAllAnimations(); 1336 } 1337 // Cleanup state of the content window first, because that can reset the 1338 // value of |current_overscroll_gesture_|. 1339 PrepareContentWindowForOverscroll(); 1340 1341 current_overscroll_gesture_ = new_mode; 1342 if (current_overscroll_gesture_ == OVERSCROLL_EAST || 1343 current_overscroll_gesture_ == OVERSCROLL_WEST) 1344 PrepareOverscrollWindow(); 1345 1346 UMA_HISTOGRAM_ENUMERATION("Overscroll.Started", new_mode, OVERSCROLL_COUNT); 1347 } 1348 completed_overscroll_gesture_ = OVERSCROLL_NONE; 1349} 1350 1351//////////////////////////////////////////////////////////////////////////////// 1352// WebContentsViewAura, ui::ImplicitAnimationObserver implementation: 1353 1354void WebContentsViewAura::OnImplicitAnimationsCompleted() { 1355 overscroll_shadow_.reset(); 1356 1357 if (ShouldNavigateForward(web_contents_->GetController(), 1358 completed_overscroll_gesture_)) { 1359 web_contents_->GetController().GoForward(); 1360 PrepareOverscrollNavigationOverlay(); 1361 } else if (ShouldNavigateBack(web_contents_->GetController(), 1362 completed_overscroll_gesture_)) { 1363 web_contents_->GetController().GoBack(); 1364 PrepareOverscrollNavigationOverlay(); 1365 } else { 1366 if (touch_editable_) 1367 touch_editable_->OverscrollCompleted(); 1368 } 1369 1370 aura::Window* content = GetContentNativeView(); 1371 if (content) { 1372 content->SetTransform(gfx::Transform()); 1373 content->layer()->SetLayerBrightness(0.f); 1374 } 1375 current_overscroll_gesture_ = OVERSCROLL_NONE; 1376 completed_overscroll_gesture_ = OVERSCROLL_NONE; 1377 overscroll_window_.reset(); 1378} 1379 1380//////////////////////////////////////////////////////////////////////////////// 1381// WebContentsViewAura, aura::WindowDelegate implementation: 1382 1383gfx::Size WebContentsViewAura::GetMinimumSize() const { 1384 return gfx::Size(); 1385} 1386 1387gfx::Size WebContentsViewAura::GetMaximumSize() const { 1388 return gfx::Size(); 1389} 1390 1391void WebContentsViewAura::OnBoundsChanged(const gfx::Rect& old_bounds, 1392 const gfx::Rect& new_bounds) { 1393 SizeChangedCommon(new_bounds.size()); 1394 if (delegate_) 1395 delegate_->SizeChanged(new_bounds.size()); 1396 1397 // Constrained web dialogs, need to be kept centered over our content area. 1398 for (size_t i = 0; i < window_->children().size(); i++) { 1399 if (window_->children()[i]->GetProperty( 1400 aura::client::kConstrainedWindowKey)) { 1401 gfx::Rect bounds = window_->children()[i]->bounds(); 1402 bounds.set_origin( 1403 gfx::Point((new_bounds.width() - bounds.width()) / 2, 1404 (new_bounds.height() - bounds.height()) / 2)); 1405 window_->children()[i]->SetBounds(bounds); 1406 } 1407 } 1408} 1409 1410gfx::NativeCursor WebContentsViewAura::GetCursor(const gfx::Point& point) { 1411 return gfx::kNullCursor; 1412} 1413 1414int WebContentsViewAura::GetNonClientComponent(const gfx::Point& point) const { 1415 return HTCLIENT; 1416} 1417 1418bool WebContentsViewAura::ShouldDescendIntoChildForEventHandling( 1419 aura::Window* child, 1420 const gfx::Point& location) { 1421 return true; 1422} 1423 1424bool WebContentsViewAura::CanFocus() { 1425 // Do not take the focus if the render widget host view aura is gone or 1426 // is in the process of shutting down because neither the view window nor 1427 // this window can handle key events. 1428 RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura( 1429 web_contents_->GetRenderWidgetHostView()); 1430 if (view != NULL && !view->IsClosing()) 1431 return true; 1432 1433 return false; 1434} 1435 1436void WebContentsViewAura::OnCaptureLost() { 1437} 1438 1439void WebContentsViewAura::OnPaint(gfx::Canvas* canvas) { 1440} 1441 1442void WebContentsViewAura::OnDeviceScaleFactorChanged( 1443 float device_scale_factor) { 1444} 1445 1446void WebContentsViewAura::OnWindowDestroying(aura::Window* window) { 1447 // This means the destructor is going to be called soon. If there is an 1448 // overscroll gesture in progress (i.e. |overscroll_window_| is not NULL), 1449 // then destroying it in the WebContentsViewAura destructor can trigger other 1450 // virtual functions to be called (e.g. OnImplicitAnimationsCompleted()). So 1451 // destroy the overscroll window here. 1452 navigation_overlay_.reset(); 1453 overscroll_window_.reset(); 1454} 1455 1456void WebContentsViewAura::OnWindowDestroyed(aura::Window* window) { 1457} 1458 1459void WebContentsViewAura::OnWindowTargetVisibilityChanged(bool visible) { 1460} 1461 1462bool WebContentsViewAura::HasHitTestMask() const { 1463 return false; 1464} 1465 1466void WebContentsViewAura::GetHitTestMask(gfx::Path* mask) const { 1467} 1468 1469//////////////////////////////////////////////////////////////////////////////// 1470// WebContentsViewAura, ui::EventHandler implementation: 1471 1472void WebContentsViewAura::OnKeyEvent(ui::KeyEvent* event) { 1473} 1474 1475void WebContentsViewAura::OnMouseEvent(ui::MouseEvent* event) { 1476 if (!web_contents_->GetDelegate()) 1477 return; 1478 1479 switch (event->type()) { 1480 case ui::ET_MOUSE_PRESSED: 1481 web_contents_->GetDelegate()->ActivateContents(web_contents_); 1482 break; 1483 case ui::ET_MOUSE_MOVED: 1484 case ui::ET_MOUSE_EXITED: 1485 web_contents_->GetDelegate()->ContentsMouseEvent( 1486 web_contents_, 1487 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(), 1488 event->type() == ui::ET_MOUSE_MOVED); 1489 break; 1490 default: 1491 break; 1492 } 1493} 1494 1495//////////////////////////////////////////////////////////////////////////////// 1496// WebContentsViewAura, aura::client::DragDropDelegate implementation: 1497 1498void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) { 1499 current_rvh_for_drag_ = web_contents_->GetRenderViewHost(); 1500 current_drop_data_.reset(new DropData()); 1501 1502 PrepareDropData(current_drop_data_.get(), event.data()); 1503 blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); 1504 1505 // Give the delegate an opportunity to cancel the drag. 1506 if (web_contents_->GetDelegate() && 1507 !web_contents_->GetDelegate()->CanDragEnter( 1508 web_contents_, *current_drop_data_.get(), op)) { 1509 current_drop_data_.reset(NULL); 1510 return; 1511 } 1512 1513 if (drag_dest_delegate_) 1514 drag_dest_delegate_->DragInitialize(web_contents_); 1515 1516 gfx::Point screen_pt = 1517 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 1518 web_contents_->GetRenderViewHost()->DragTargetDragEnter( 1519 *current_drop_data_.get(), event.location(), screen_pt, op, 1520 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1521 1522 if (drag_dest_delegate_) { 1523 drag_dest_delegate_->OnReceiveDragData(event.data()); 1524 drag_dest_delegate_->OnDragEnter(); 1525 } 1526} 1527 1528int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) { 1529 DCHECK(current_rvh_for_drag_); 1530 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1531 OnDragEntered(event); 1532 1533 if (!current_drop_data_) 1534 return ui::DragDropTypes::DRAG_NONE; 1535 1536 blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); 1537 gfx::Point screen_pt = 1538 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(); 1539 web_contents_->GetRenderViewHost()->DragTargetDragOver( 1540 event.location(), screen_pt, op, 1541 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1542 1543 if (drag_dest_delegate_) 1544 drag_dest_delegate_->OnDragOver(); 1545 1546 return ConvertFromWeb(current_drag_op_); 1547} 1548 1549void WebContentsViewAura::OnDragExited() { 1550 DCHECK(current_rvh_for_drag_); 1551 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1552 return; 1553 1554 if (!current_drop_data_) 1555 return; 1556 1557 web_contents_->GetRenderViewHost()->DragTargetDragLeave(); 1558 if (drag_dest_delegate_) 1559 drag_dest_delegate_->OnDragLeave(); 1560 1561 current_drop_data_.reset(); 1562} 1563 1564int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) { 1565 DCHECK(current_rvh_for_drag_); 1566 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost()) 1567 OnDragEntered(event); 1568 1569 if (!current_drop_data_) 1570 return ui::DragDropTypes::DRAG_NONE; 1571 1572 web_contents_->GetRenderViewHost()->DragTargetDrop( 1573 event.location(), 1574 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(), 1575 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); 1576 if (drag_dest_delegate_) 1577 drag_dest_delegate_->OnDrop(); 1578 current_drop_data_.reset(); 1579 return ConvertFromWeb(current_drag_op_); 1580} 1581 1582void WebContentsViewAura::OnWindowParentChanged(aura::Window* window, 1583 aura::Window* parent) { 1584 // Ignore any visibility changes in the hierarchy below. 1585 if (window != window_.get() && window_->Contains(window)) 1586 return; 1587 1588 // On Windows we will get called with a parent of NULL as part of the shut 1589 // down process. As such we do only change the visibility when a parent gets 1590 // set. 1591 if (parent) 1592 UpdateWebContentsVisibility(window->IsVisible()); 1593} 1594 1595void WebContentsViewAura::OnWindowVisibilityChanged(aura::Window* window, 1596 bool visible) { 1597 // Ignore any visibility changes in the hierarchy below. 1598 if (window != window_.get() && window_->Contains(window)) 1599 return; 1600 1601 UpdateWebContentsVisibility(visible); 1602} 1603 1604void WebContentsViewAura::UpdateWebContentsVisibility(bool visible) { 1605 if (!is_or_was_visible_) { 1606 // We should not hide the web contents before it was shown the first time, 1607 // since resources would immediately be destroyed and only re-created after 1608 // content got loaded. In this state the window content is undefined and can 1609 // show garbage. 1610 // However - the page load mechanism requires an activation call through a 1611 // visibility call to (re)load. 1612 if (visible) { 1613 is_or_was_visible_ = true; 1614 web_contents_->WasShown(); 1615 } 1616 return; 1617 } 1618 if (visible) { 1619 if (!web_contents_->should_normally_be_visible()) 1620 web_contents_->WasShown(); 1621 } else { 1622 if (web_contents_->should_normally_be_visible()) 1623 web_contents_->WasHidden(); 1624 } 1625} 1626 1627} // namespace content 1628