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