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/interstitial_page_impl.h" 6 7 #include <vector> 8 9 #include "base/bind.h" 10 #include "base/compiler_specific.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/strings/string_util.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "base/threading/thread.h" 15 #include "content/browser/dom_storage/dom_storage_context_wrapper.h" 16 #include "content/browser/dom_storage/session_storage_namespace_impl.h" 17 #include "content/browser/loader/resource_dispatcher_host_impl.h" 18 #include "content/browser/renderer_host/render_process_host_impl.h" 19 #include "content/browser/renderer_host/render_view_host_impl.h" 20 #include "content/browser/site_instance_impl.h" 21 #include "content/browser/web_contents/navigation_controller_impl.h" 22 #include "content/browser/web_contents/navigation_entry_impl.h" 23 #include "content/browser/web_contents/web_contents_impl.h" 24 #include "content/common/view_messages.h" 25 #include "content/port/browser/render_view_host_delegate_view.h" 26 #include "content/port/browser/render_widget_host_view_port.h" 27 #include "content/port/browser/web_contents_view_port.h" 28 #include "content/public/browser/browser_context.h" 29 #include "content/public/browser/browser_thread.h" 30 #include "content/public/browser/content_browser_client.h" 31 #include "content/public/browser/dom_operation_notification_details.h" 32 #include "content/public/browser/interstitial_page_delegate.h" 33 #include "content/public/browser/invalidate_type.h" 34 #include "content/public/browser/notification_service.h" 35 #include "content/public/browser/notification_source.h" 36 #include "content/public/browser/storage_partition.h" 37 #include "content/public/browser/web_contents_delegate.h" 38 #include "content/public/common/bindings_policy.h" 39 #include "content/public/common/page_transition_types.h" 40 #include "net/base/escape.h" 41 #include "net/url_request/url_request_context_getter.h" 42 43 using WebKit::WebDragOperation; 44 using WebKit::WebDragOperationsMask; 45 46 namespace content { 47 namespace { 48 49 void ResourceRequestHelper(ResourceDispatcherHostImpl* rdh, 50 int process_id, 51 int render_view_host_id, 52 ResourceRequestAction action) { 53 switch (action) { 54 case BLOCK: 55 rdh->BlockRequestsForRoute(process_id, render_view_host_id); 56 break; 57 case RESUME: 58 rdh->ResumeBlockedRequestsForRoute(process_id, render_view_host_id); 59 break; 60 case CANCEL: 61 rdh->CancelBlockedRequestsForRoute(process_id, render_view_host_id); 62 break; 63 default: 64 NOTREACHED(); 65 } 66 } 67 68 } // namespace 69 70 class InterstitialPageImpl::InterstitialPageRVHDelegateView 71 : public RenderViewHostDelegateView { 72 public: 73 explicit InterstitialPageRVHDelegateView(InterstitialPageImpl* page); 74 75 // RenderViewHostDelegateView implementation: 76 virtual void ShowPopupMenu(const gfx::Rect& bounds, 77 int item_height, 78 double item_font_size, 79 int selected_item, 80 const std::vector<MenuItem>& items, 81 bool right_aligned, 82 bool allow_multiple_selection) OVERRIDE; 83 virtual void StartDragging(const DropData& drop_data, 84 WebDragOperationsMask operations_allowed, 85 const gfx::ImageSkia& image, 86 const gfx::Vector2d& image_offset, 87 const DragEventSourceInfo& event_info) OVERRIDE; 88 virtual void UpdateDragCursor(WebDragOperation operation) OVERRIDE; 89 virtual void GotFocus() OVERRIDE; 90 virtual void TakeFocus(bool reverse) OVERRIDE; 91 virtual void OnFindReply(int request_id, 92 int number_of_matches, 93 const gfx::Rect& selection_rect, 94 int active_match_ordinal, 95 bool final_update); 96 97 private: 98 InterstitialPageImpl* interstitial_page_; 99 100 DISALLOW_COPY_AND_ASSIGN(InterstitialPageRVHDelegateView); 101 }; 102 103 104 // We keep a map of the various blocking pages shown as the UI tests need to 105 // be able to retrieve them. 106 typedef std::map<WebContents*, InterstitialPageImpl*> InterstitialPageMap; 107 static InterstitialPageMap* g_web_contents_to_interstitial_page; 108 109 // Initializes g_web_contents_to_interstitial_page in a thread-safe manner. 110 // Should be called before accessing g_web_contents_to_interstitial_page. 111 static void InitInterstitialPageMap() { 112 if (!g_web_contents_to_interstitial_page) 113 g_web_contents_to_interstitial_page = new InterstitialPageMap; 114 } 115 116 InterstitialPage* InterstitialPage::Create(WebContents* web_contents, 117 bool new_navigation, 118 const GURL& url, 119 InterstitialPageDelegate* delegate) { 120 return new InterstitialPageImpl(web_contents, new_navigation, url, delegate); 121 } 122 123 InterstitialPage* InterstitialPage::GetInterstitialPage( 124 WebContents* web_contents) { 125 InitInterstitialPageMap(); 126 InterstitialPageMap::const_iterator iter = 127 g_web_contents_to_interstitial_page->find(web_contents); 128 if (iter == g_web_contents_to_interstitial_page->end()) 129 return NULL; 130 131 return iter->second; 132 } 133 134 InterstitialPageImpl::InterstitialPageImpl(WebContents* web_contents, 135 bool new_navigation, 136 const GURL& url, 137 InterstitialPageDelegate* delegate) 138 : WebContentsObserver(web_contents), 139 web_contents_(static_cast<WebContentsImpl*>(web_contents)), 140 url_(url), 141 new_navigation_(new_navigation), 142 should_discard_pending_nav_entry_(new_navigation), 143 reload_on_dont_proceed_(false), 144 enabled_(true), 145 action_taken_(NO_ACTION), 146 render_view_host_(NULL), 147 original_child_id_(web_contents->GetRenderProcessHost()->GetID()), 148 original_rvh_id_(web_contents->GetRenderViewHost()->GetRoutingID()), 149 should_revert_web_contents_title_(false), 150 web_contents_was_loading_(false), 151 resource_dispatcher_host_notified_(false), 152 rvh_delegate_view_(new InterstitialPageRVHDelegateView(this)), 153 create_view_(true), 154 delegate_(delegate), 155 weak_ptr_factory_(this) { 156 InitInterstitialPageMap(); 157 // It would be inconsistent to create an interstitial with no new navigation 158 // (which is the case when the interstitial was triggered by a sub-resource on 159 // a page) when we have a pending entry (in the process of loading a new top 160 // frame). 161 DCHECK(new_navigation || !web_contents->GetController().GetPendingEntry()); 162 } 163 164 InterstitialPageImpl::~InterstitialPageImpl() { 165 } 166 167 void InterstitialPageImpl::Show() { 168 if (!enabled()) 169 return; 170 171 // If an interstitial is already showing or about to be shown, close it before 172 // showing the new one. 173 // Be careful not to take an action on the old interstitial more than once. 174 InterstitialPageMap::const_iterator iter = 175 g_web_contents_to_interstitial_page->find(web_contents_); 176 if (iter != g_web_contents_to_interstitial_page->end()) { 177 InterstitialPageImpl* interstitial = iter->second; 178 if (interstitial->action_taken_ != NO_ACTION) { 179 interstitial->Hide(); 180 } else { 181 // If we are currently showing an interstitial page for which we created 182 // a transient entry and a new interstitial is shown as the result of a 183 // new browser initiated navigation, then that transient entry has already 184 // been discarded and a new pending navigation entry created. 185 // So we should not discard that new pending navigation entry. 186 // See http://crbug.com/9791 187 if (new_navigation_ && interstitial->new_navigation_) 188 interstitial->should_discard_pending_nav_entry_= false; 189 interstitial->DontProceed(); 190 } 191 } 192 193 // Block the resource requests for the render view host while it is hidden. 194 TakeActionOnResourceDispatcher(BLOCK); 195 // We need to be notified when the RenderViewHost is destroyed so we can 196 // cancel the blocked requests. We cannot do that on 197 // NOTIFY_WEB_CONTENTS_DESTROYED as at that point the RenderViewHost has 198 // already been destroyed. 199 notification_registrar_.Add( 200 this, NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, 201 Source<RenderWidgetHost>(web_contents_->GetRenderViewHost())); 202 203 // Update the g_web_contents_to_interstitial_page map. 204 iter = g_web_contents_to_interstitial_page->find(web_contents_); 205 DCHECK(iter == g_web_contents_to_interstitial_page->end()); 206 (*g_web_contents_to_interstitial_page)[web_contents_] = this; 207 208 if (new_navigation_) { 209 NavigationEntryImpl* entry = new NavigationEntryImpl; 210 entry->SetURL(url_); 211 entry->SetVirtualURL(url_); 212 entry->set_page_type(PAGE_TYPE_INTERSTITIAL); 213 214 // Give delegates a chance to set some states on the navigation entry. 215 delegate_->OverrideEntry(entry); 216 217 web_contents_->GetController().SetTransientEntry(entry); 218 } 219 220 DCHECK(!render_view_host_); 221 render_view_host_ = static_cast<RenderViewHostImpl*>(CreateRenderViewHost()); 222 CreateWebContentsView(); 223 224 std::string data_url = "data:text/html;charset=utf-8," + 225 net::EscapePath(delegate_->GetHTMLContents()); 226 render_view_host_->NavigateToURL(GURL(data_url)); 227 228 notification_registrar_.Add(this, NOTIFICATION_NAV_ENTRY_PENDING, 229 Source<NavigationController>(&web_contents_->GetController())); 230 notification_registrar_.Add( 231 this, NOTIFICATION_DOM_OPERATION_RESPONSE, 232 Source<RenderViewHost>(render_view_host_)); 233 } 234 235 void InterstitialPageImpl::Hide() { 236 // We may have already been hidden, and are just waiting to be deleted. 237 // We can't check for enabled() here, because some callers have already 238 // called Disable. 239 if (!render_view_host_) 240 return; 241 242 Disable(); 243 244 RenderWidgetHostView* old_view = 245 web_contents_->GetRenderViewHost()->GetView(); 246 if (web_contents_->GetInterstitialPage() == this && 247 old_view && !old_view->IsShowing()) { 248 // Show the original RVH since we're going away. Note it might not exist if 249 // the renderer crashed while the interstitial was showing. 250 // Note that it is important that we don't call Show() if the view is 251 // already showing. That would result in bad things (unparented HWND on 252 // Windows for example) happening. 253 old_view->Show(); 254 } 255 256 // If the focus was on the interstitial, let's keep it to the page. 257 // (Note that in unit-tests the RVH may not have a view). 258 if (render_view_host_->GetView() && 259 render_view_host_->GetView()->HasFocus() && 260 web_contents_->GetRenderViewHost()->GetView()) { 261 RenderWidgetHostViewPort::FromRWHV( 262 web_contents_->GetRenderViewHost()->GetView())->Focus(); 263 } 264 265 // Shutdown the RVH asynchronously, as we may have been called from a RVH 266 // delegate method, and we can't delete the RVH out from under itself. 267 base::MessageLoop::current()->PostNonNestableTask( 268 FROM_HERE, 269 base::Bind(&InterstitialPageImpl::Shutdown, 270 weak_ptr_factory_.GetWeakPtr(), 271 render_view_host_)); 272 render_view_host_ = NULL; 273 web_contents_->DetachInterstitialPage(); 274 // Let's revert to the original title if necessary. 275 NavigationEntry* entry = web_contents_->GetController().GetActiveEntry(); 276 if (!new_navigation_ && should_revert_web_contents_title_) { 277 entry->SetTitle(original_web_contents_title_); 278 web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TITLE); 279 } 280 281 InterstitialPageMap::iterator iter = 282 g_web_contents_to_interstitial_page->find(web_contents_); 283 DCHECK(iter != g_web_contents_to_interstitial_page->end()); 284 if (iter != g_web_contents_to_interstitial_page->end()) 285 g_web_contents_to_interstitial_page->erase(iter); 286 287 // Clear the WebContents pointer, because it may now be deleted. 288 // This signifies that we are in the process of shutting down. 289 web_contents_ = NULL; 290 } 291 292 void InterstitialPageImpl::Observe( 293 int type, 294 const NotificationSource& source, 295 const NotificationDetails& details) { 296 switch (type) { 297 case NOTIFICATION_NAV_ENTRY_PENDING: 298 // We are navigating away from the interstitial (the user has typed a URL 299 // in the location bar or clicked a bookmark). Make sure clicking on the 300 // interstitial will have no effect. Also cancel any blocked requests 301 // on the ResourceDispatcherHost. Note that when we get this notification 302 // the RenderViewHost has not yet navigated so we'll unblock the 303 // RenderViewHost before the resource request for the new page we are 304 // navigating arrives in the ResourceDispatcherHost. This ensures that 305 // request won't be blocked if the same RenderViewHost was used for the 306 // new navigation. 307 Disable(); 308 TakeActionOnResourceDispatcher(CANCEL); 309 break; 310 case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: 311 if (action_taken_ == NO_ACTION) { 312 // The RenderViewHost is being destroyed (as part of the tab being 313 // closed); make sure we clear the blocked requests. 314 RenderViewHost* rvh = static_cast<RenderViewHost*>( 315 static_cast<RenderViewHostImpl*>( 316 RenderWidgetHostImpl::From( 317 Source<RenderWidgetHost>(source).ptr()))); 318 DCHECK(rvh->GetProcess()->GetID() == original_child_id_ && 319 rvh->GetRoutingID() == original_rvh_id_); 320 TakeActionOnResourceDispatcher(CANCEL); 321 } 322 break; 323 case NOTIFICATION_DOM_OPERATION_RESPONSE: 324 if (enabled()) { 325 Details<DomOperationNotificationDetails> dom_op_details( 326 details); 327 delegate_->CommandReceived(dom_op_details->json); 328 } 329 break; 330 default: 331 NOTREACHED(); 332 } 333 } 334 335 void InterstitialPageImpl::NavigationEntryCommitted( 336 const LoadCommittedDetails& load_details) { 337 OnNavigatingAwayOrTabClosing(); 338 } 339 340 void InterstitialPageImpl::WebContentsDestroyed(WebContents* web_contents) { 341 OnNavigatingAwayOrTabClosing(); 342 } 343 344 RenderViewHostDelegateView* InterstitialPageImpl::GetDelegateView() { 345 return rvh_delegate_view_.get(); 346 } 347 348 const GURL& InterstitialPageImpl::GetURL() const { 349 return url_; 350 } 351 352 void InterstitialPageImpl::RenderViewTerminated( 353 RenderViewHost* render_view_host, 354 base::TerminationStatus status, 355 int error_code) { 356 // Our renderer died. This should not happen in normal cases. 357 // If we haven't already started shutdown, just dismiss the interstitial. 358 // We cannot check for enabled() here, because we may have called Disable 359 // without calling Hide. 360 if (render_view_host_) 361 DontProceed(); 362 } 363 364 void InterstitialPageImpl::DidNavigate( 365 RenderViewHost* render_view_host, 366 const ViewHostMsg_FrameNavigate_Params& params) { 367 // A fast user could have navigated away from the page that triggered the 368 // interstitial while the interstitial was loading, that would have disabled 369 // us. In that case we can dismiss ourselves. 370 if (!enabled()) { 371 DontProceed(); 372 return; 373 } 374 if (PageTransitionCoreTypeIs(params.transition, 375 PAGE_TRANSITION_AUTO_SUBFRAME)) { 376 // No need to handle navigate message from iframe in the interstitial page. 377 return; 378 } 379 380 // The RenderViewHost has loaded its contents, we can show it now. 381 render_view_host_->GetView()->Show(); 382 web_contents_->AttachInterstitialPage(this); 383 384 RenderWidgetHostView* rwh_view = 385 web_contents_->GetRenderViewHost()->GetView(); 386 387 // The RenderViewHost may already have crashed before we even get here. 388 if (rwh_view) { 389 // If the page has focus, focus the interstitial. 390 if (rwh_view->HasFocus()) 391 Focus(); 392 393 // Hide the original RVH since we're showing the interstitial instead. 394 rwh_view->Hide(); 395 } 396 397 // Notify the tab we are not loading so the throbber is stopped. It also 398 // causes a NOTIFY_LOAD_STOP notification, that the AutomationProvider (used 399 // by the UI tests) expects to consider a navigation as complete. Without 400 // this, navigating in a UI test to a URL that triggers an interstitial would 401 // hang. 402 web_contents_was_loading_ = web_contents_->IsLoading(); 403 web_contents_->SetIsLoading(false, NULL); 404 } 405 406 void InterstitialPageImpl::UpdateTitle( 407 RenderViewHost* render_view_host, 408 int32 page_id, 409 const string16& title, 410 base::i18n::TextDirection title_direction) { 411 if (!enabled()) 412 return; 413 414 DCHECK(render_view_host == render_view_host_); 415 NavigationEntry* entry = web_contents_->GetController().GetActiveEntry(); 416 if (!entry) { 417 // Crash reports from the field indicate this can be NULL. 418 // This is unexpected as InterstitialPages constructed with the 419 // new_navigation flag set to true create a transient navigation entry 420 // (that is returned as the active entry). And the only case so far of 421 // interstitial created with that flag set to false is with the 422 // SafeBrowsingBlockingPage, when the resource triggering the interstitial 423 // is a sub-resource, meaning the main page has already been loaded and a 424 // navigation entry should have been created. 425 NOTREACHED(); 426 return; 427 } 428 429 // If this interstitial is shown on an existing navigation entry, we'll need 430 // to remember its title so we can revert to it when hidden. 431 if (!new_navigation_ && !should_revert_web_contents_title_) { 432 original_web_contents_title_ = entry->GetTitle(); 433 should_revert_web_contents_title_ = true; 434 } 435 // TODO(evan): make use of title_direction. 436 // http://code.google.com/p/chromium/issues/detail?id=27094 437 entry->SetTitle(title); 438 web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TITLE); 439 } 440 441 RendererPreferences InterstitialPageImpl::GetRendererPrefs( 442 BrowserContext* browser_context) const { 443 delegate_->OverrideRendererPrefs(&renderer_preferences_); 444 return renderer_preferences_; 445 } 446 447 WebPreferences InterstitialPageImpl::GetWebkitPrefs() { 448 if (!enabled()) 449 return WebPreferences(); 450 451 return WebContentsImpl::GetWebkitPrefs(render_view_host_, url_); 452 } 453 454 void InterstitialPageImpl::RenderWidgetDeleted( 455 RenderWidgetHostImpl* render_widget_host) { 456 delete this; 457 } 458 459 bool InterstitialPageImpl::PreHandleKeyboardEvent( 460 const NativeWebKeyboardEvent& event, 461 bool* is_keyboard_shortcut) { 462 if (!enabled()) 463 return false; 464 return web_contents_->PreHandleKeyboardEvent(event, is_keyboard_shortcut); 465 } 466 467 void InterstitialPageImpl::HandleKeyboardEvent( 468 const NativeWebKeyboardEvent& event) { 469 if (enabled()) 470 web_contents_->HandleKeyboardEvent(event); 471 } 472 473 #if defined(OS_WIN) && defined(USE_AURA) 474 gfx::NativeViewAccessible 475 InterstitialPageImpl::GetParentNativeViewAccessible() { 476 return web_contents_->GetParentNativeViewAccessible(); 477 } 478 #endif 479 480 WebContents* InterstitialPageImpl::web_contents() const { 481 return web_contents_; 482 } 483 484 RenderViewHost* InterstitialPageImpl::CreateRenderViewHost() { 485 if (!enabled()) 486 return NULL; 487 488 // Interstitial pages don't want to share the session storage so we mint a 489 // new one. 490 BrowserContext* browser_context = web_contents()->GetBrowserContext(); 491 scoped_refptr<SiteInstance> site_instance = 492 SiteInstance::Create(browser_context); 493 DOMStorageContextWrapper* dom_storage_context = 494 static_cast<DOMStorageContextWrapper*>( 495 BrowserContext::GetStoragePartition( 496 browser_context, site_instance.get())->GetDOMStorageContext()); 497 session_storage_namespace_ = 498 new SessionStorageNamespaceImpl(dom_storage_context); 499 500 RenderViewHostImpl* render_view_host = 501 new RenderViewHostImpl(site_instance.get(), 502 this, 503 this, 504 MSG_ROUTING_NONE, 505 MSG_ROUTING_NONE, 506 false); 507 web_contents_->RenderViewForInterstitialPageCreated(render_view_host); 508 return render_view_host; 509 } 510 511 WebContentsView* InterstitialPageImpl::CreateWebContentsView() { 512 if (!enabled() || !create_view_) 513 return NULL; 514 WebContentsView* web_contents_view = web_contents()->GetView(); 515 WebContentsViewPort* web_contents_view_port = 516 static_cast<WebContentsViewPort*>(web_contents_view); 517 RenderWidgetHostView* view = 518 web_contents_view_port->CreateViewForWidget(render_view_host_); 519 render_view_host_->SetView(view); 520 render_view_host_->AllowBindings(BINDINGS_POLICY_DOM_AUTOMATION); 521 522 int32 max_page_id = web_contents()-> 523 GetMaxPageIDForSiteInstance(render_view_host_->GetSiteInstance()); 524 render_view_host_->CreateRenderView(string16(), 525 MSG_ROUTING_NONE, 526 max_page_id); 527 view->SetSize(web_contents_view->GetContainerSize()); 528 // Don't show the interstitial until we have navigated to it. 529 view->Hide(); 530 return web_contents_view; 531 } 532 533 void InterstitialPageImpl::Proceed() { 534 // Don't repeat this if we are already shutting down. We cannot check for 535 // enabled() here, because we may have called Disable without calling Hide. 536 if (!render_view_host_) 537 return; 538 539 if (action_taken_ != NO_ACTION) { 540 NOTREACHED(); 541 return; 542 } 543 Disable(); 544 action_taken_ = PROCEED_ACTION; 545 546 // Resumes the throbber, if applicable. 547 if (web_contents_was_loading_) 548 web_contents_->SetIsLoading(true, NULL); 549 550 // If this is a new navigation, the old page is going away, so we cancel any 551 // blocked requests for it. If it is not a new navigation, then it means the 552 // interstitial was shown as a result of a resource loading in the page. 553 // Since the user wants to proceed, we'll let any blocked request go through. 554 if (new_navigation_) 555 TakeActionOnResourceDispatcher(CANCEL); 556 else 557 TakeActionOnResourceDispatcher(RESUME); 558 559 // No need to hide if we are a new navigation, we'll get hidden when the 560 // navigation is committed. 561 if (!new_navigation_) { 562 Hide(); 563 delegate_->OnProceed(); 564 return; 565 } 566 567 delegate_->OnProceed(); 568 } 569 570 void InterstitialPageImpl::DontProceed() { 571 // Don't repeat this if we are already shutting down. We cannot check for 572 // enabled() here, because we may have called Disable without calling Hide. 573 if (!render_view_host_) 574 return; 575 DCHECK(action_taken_ != DONT_PROCEED_ACTION); 576 577 Disable(); 578 action_taken_ = DONT_PROCEED_ACTION; 579 580 // If this is a new navigation, we are returning to the original page, so we 581 // resume blocked requests for it. If it is not a new navigation, then it 582 // means the interstitial was shown as a result of a resource loading in the 583 // page and we won't return to the original page, so we cancel blocked 584 // requests in that case. 585 if (new_navigation_) 586 TakeActionOnResourceDispatcher(RESUME); 587 else 588 TakeActionOnResourceDispatcher(CANCEL); 589 590 if (should_discard_pending_nav_entry_) { 591 // Since no navigation happens we have to discard the transient entry 592 // explicitely. Note that by calling DiscardNonCommittedEntries() we also 593 // discard the pending entry, which is what we want, since the navigation is 594 // cancelled. 595 web_contents_->GetController().DiscardNonCommittedEntries(); 596 } 597 598 if (reload_on_dont_proceed_) 599 web_contents_->GetController().Reload(true); 600 601 Hide(); 602 delegate_->OnDontProceed(); 603 } 604 605 void InterstitialPageImpl::CancelForNavigation() { 606 // The user is trying to navigate away. We should unblock the renderer and 607 // disable the interstitial, but keep it visible until the navigation 608 // completes. 609 Disable(); 610 // If this interstitial was shown for a new navigation, allow any navigations 611 // on the original page to resume (e.g., subresource requests, XHRs, etc). 612 // Otherwise, cancel the pending, possibly dangerous navigations. 613 if (new_navigation_) 614 TakeActionOnResourceDispatcher(RESUME); 615 else 616 TakeActionOnResourceDispatcher(CANCEL); 617 } 618 619 void InterstitialPageImpl::SetSize(const gfx::Size& size) { 620 if (!enabled()) 621 return; 622 #if !defined(OS_MACOSX) 623 // When a tab is closed, we might be resized after our view was NULLed 624 // (typically if there was an info-bar). 625 if (render_view_host_->GetView()) 626 render_view_host_->GetView()->SetSize(size); 627 #else 628 // TODO(port): Does Mac need to SetSize? 629 NOTIMPLEMENTED(); 630 #endif 631 } 632 633 void InterstitialPageImpl::Focus() { 634 // Focus the native window. 635 if (!enabled()) 636 return; 637 RenderWidgetHostViewPort::FromRWHV(render_view_host_->GetView())->Focus(); 638 } 639 640 void InterstitialPageImpl::FocusThroughTabTraversal(bool reverse) { 641 if (!enabled()) 642 return; 643 render_view_host_->SetInitialFocus(reverse); 644 } 645 646 RenderWidgetHostView* InterstitialPageImpl::GetView() { 647 return render_view_host_->GetView(); 648 } 649 650 RenderViewHost* InterstitialPageImpl::GetRenderViewHostForTesting() const { 651 return render_view_host_; 652 } 653 654 #if defined(OS_ANDROID) 655 RenderViewHost* InterstitialPageImpl::GetRenderViewHost() const { 656 return render_view_host_; 657 } 658 #endif 659 660 InterstitialPageDelegate* InterstitialPageImpl::GetDelegateForTesting() { 661 return delegate_.get(); 662 } 663 664 void InterstitialPageImpl::DontCreateViewForTesting() { 665 create_view_ = false; 666 } 667 668 gfx::Rect InterstitialPageImpl::GetRootWindowResizerRect() const { 669 return gfx::Rect(); 670 } 671 672 void InterstitialPageImpl::CreateNewWindow( 673 int route_id, 674 int main_frame_route_id, 675 const ViewHostMsg_CreateWindow_Params& params, 676 SessionStorageNamespace* session_storage_namespace) { 677 NOTREACHED() << "InterstitialPage does not support showing popups yet."; 678 } 679 680 void InterstitialPageImpl::CreateNewWidget(int route_id, 681 WebKit::WebPopupType popup_type) { 682 NOTREACHED() << "InterstitialPage does not support showing drop-downs yet."; 683 } 684 685 void InterstitialPageImpl::CreateNewFullscreenWidget(int route_id) { 686 NOTREACHED() 687 << "InterstitialPage does not support showing full screen popups."; 688 } 689 690 void InterstitialPageImpl::ShowCreatedWindow(int route_id, 691 WindowOpenDisposition disposition, 692 const gfx::Rect& initial_pos, 693 bool user_gesture) { 694 NOTREACHED() << "InterstitialPage does not support showing popups yet."; 695 } 696 697 void InterstitialPageImpl::ShowCreatedWidget(int route_id, 698 const gfx::Rect& initial_pos) { 699 NOTREACHED() << "InterstitialPage does not support showing drop-downs yet."; 700 } 701 702 void InterstitialPageImpl::ShowCreatedFullscreenWidget(int route_id) { 703 NOTREACHED() 704 << "InterstitialPage does not support showing full screen popups."; 705 } 706 707 SessionStorageNamespace* InterstitialPageImpl::GetSessionStorageNamespace( 708 SiteInstance* instance) { 709 return session_storage_namespace_.get(); 710 } 711 712 void InterstitialPageImpl::Disable() { 713 enabled_ = false; 714 } 715 716 void InterstitialPageImpl::Shutdown(RenderViewHostImpl* render_view_host) { 717 render_view_host->Shutdown(); 718 // We are deleted now. 719 } 720 721 void InterstitialPageImpl::OnNavigatingAwayOrTabClosing() { 722 if (action_taken_ == NO_ACTION) { 723 // We are navigating away from the interstitial or closing a tab with an 724 // interstitial. Default to DontProceed(). We don't just call Hide as 725 // subclasses will almost certainly override DontProceed to do some work 726 // (ex: close pending connections). 727 DontProceed(); 728 } else { 729 // User decided to proceed and either the navigation was committed or 730 // the tab was closed before that. 731 Hide(); 732 } 733 } 734 735 void InterstitialPageImpl::TakeActionOnResourceDispatcher( 736 ResourceRequestAction action) { 737 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) << 738 "TakeActionOnResourceDispatcher should be called on the main thread."; 739 740 if (action == CANCEL || action == RESUME) { 741 if (resource_dispatcher_host_notified_) 742 return; 743 resource_dispatcher_host_notified_ = true; 744 } 745 746 // The tab might not have a render_view_host if it was closed (in which case, 747 // we have taken care of the blocked requests when processing 748 // NOTIFY_RENDER_WIDGET_HOST_DESTROYED. 749 // Also we need to test there is a ResourceDispatcherHostImpl, as when unit- 750 // tests we don't have one. 751 RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(original_child_id_, 752 original_rvh_id_); 753 if (!rvh || !ResourceDispatcherHostImpl::Get()) 754 return; 755 756 BrowserThread::PostTask( 757 BrowserThread::IO, 758 FROM_HERE, 759 base::Bind( 760 &ResourceRequestHelper, 761 ResourceDispatcherHostImpl::Get(), 762 original_child_id_, 763 original_rvh_id_, 764 action)); 765 } 766 767 InterstitialPageImpl::InterstitialPageRVHDelegateView:: 768 InterstitialPageRVHDelegateView(InterstitialPageImpl* page) 769 : interstitial_page_(page) { 770 } 771 772 void InterstitialPageImpl::InterstitialPageRVHDelegateView::ShowPopupMenu( 773 const gfx::Rect& bounds, 774 int item_height, 775 double item_font_size, 776 int selected_item, 777 const std::vector<MenuItem>& items, 778 bool right_aligned, 779 bool allow_multiple_selection) { 780 NOTREACHED() << "InterstitialPage does not support showing popup menus."; 781 } 782 783 void InterstitialPageImpl::InterstitialPageRVHDelegateView::StartDragging( 784 const DropData& drop_data, 785 WebDragOperationsMask allowed_operations, 786 const gfx::ImageSkia& image, 787 const gfx::Vector2d& image_offset, 788 const DragEventSourceInfo& event_info) { 789 NOTREACHED() << "InterstitialPage does not support dragging yet."; 790 } 791 792 void InterstitialPageImpl::InterstitialPageRVHDelegateView::UpdateDragCursor( 793 WebDragOperation) { 794 NOTREACHED() << "InterstitialPage does not support dragging yet."; 795 } 796 797 void InterstitialPageImpl::InterstitialPageRVHDelegateView::GotFocus() { 798 WebContents* web_contents = interstitial_page_->web_contents(); 799 if (web_contents && web_contents->GetDelegate()) 800 web_contents->GetDelegate()->WebContentsFocused(web_contents); 801 } 802 803 void InterstitialPageImpl::InterstitialPageRVHDelegateView::TakeFocus( 804 bool reverse) { 805 if (!interstitial_page_->web_contents()) 806 return; 807 WebContentsImpl* web_contents = 808 static_cast<WebContentsImpl*>(interstitial_page_->web_contents()); 809 if (!web_contents->GetDelegateView()) 810 return; 811 812 web_contents->GetDelegateView()->TakeFocus(reverse); 813 } 814 815 void InterstitialPageImpl::InterstitialPageRVHDelegateView::OnFindReply( 816 int request_id, int number_of_matches, const gfx::Rect& selection_rect, 817 int active_match_ordinal, bool final_update) { 818 } 819 820 } // namespace content 821