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