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