| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 "chrome/browser/tab_contents/tab_contents.h" | |
| 6 | |
| 7 #include <cmath> | |
| 8 | |
| 9 #include "base/auto_reset.h" | |
| 10 #include "base/metrics/histogram.h" | |
| 11 #include "base/metrics/stats_counters.h" | |
| 12 #include "base/string16.h" | |
| 13 #include "base/string_util.h" | |
| 14 #include "base/time.h" | |
| 15 #include "base/utf_string_conversions.h" | |
| 16 #include "chrome/browser/autocomplete_history_manager.h" | |
| 17 #include "chrome/browser/autofill/autofill_manager.h" | |
| 18 #include "chrome/browser/blocked_content_container.h" | |
| 19 #include "chrome/browser/browser_process.h" | |
| 20 #include "chrome/browser/browser_shutdown.h" | |
| 21 #include "chrome/browser/character_encoding.h" | |
| 22 #include "chrome/browser/child_process_security_policy.h" | |
| 23 #include "chrome/browser/content_settings/content_settings_details.h" | |
| 24 #include "chrome/browser/content_settings/host_content_settings_map.h" | |
| 25 #include "chrome/browser/debugger/devtools_manager.h" | |
| 26 #include "chrome/browser/defaults.h" | |
| 27 #include "chrome/browser/desktop_notification_handler.h" | |
| 28 #include "chrome/browser/dom_operation_notification_details.h" | |
| 29 #include "chrome/browser/dom_ui/web_ui.h" | |
| 30 #include "chrome/browser/download/download_item_model.h" | |
| 31 #include "chrome/browser/download/download_manager.h" | |
| 32 #include "chrome/browser/download/download_request_limiter.h" | |
| 33 #include "chrome/browser/extensions/extension_service.h" | |
| 34 #include "chrome/browser/external_protocol_handler.h" | |
| 35 #include "chrome/browser/favicon_service.h" | |
| 36 #include "chrome/browser/file_select_helper.h" | |
| 37 #include "chrome/browser/google/google_util.h" | |
| 38 #include "chrome/browser/history/history.h" | |
| 39 #include "chrome/browser/history/history_types.h" | |
| 40 #include "chrome/browser/history/top_sites.h" | |
| 41 #include "chrome/browser/host_zoom_map.h" | |
| 42 #include "chrome/browser/hung_renderer_dialog.h" | |
| 43 #include "chrome/browser/in_process_webkit/session_storage_namespace.h" | |
| 44 #include "chrome/browser/load_from_memory_cache_details.h" | |
| 45 #include "chrome/browser/load_notification_details.h" | |
| 46 #include "chrome/browser/metrics/metric_event_duration_details.h" | |
| 47 #include "chrome/browser/metrics/user_metrics.h" | |
| 48 #include "chrome/browser/modal_html_dialog_delegate.h" | |
| 49 #include "chrome/browser/omnibox_search_hint.h" | |
| 50 #include "chrome/browser/pdf_unsupported_feature.h" | |
| 51 #include "chrome/browser/platform_util.h" | |
| 52 #include "chrome/browser/plugin_observer.h" | |
| 53 #include "chrome/browser/prefs/pref_service.h" | |
| 54 #include "chrome/browser/prerender/prerender_manager.h" | |
| 55 #include "chrome/browser/prerender/prerender_plt_recorder.h" | |
| 56 #include "chrome/browser/printing/print_preview_message_handler.h" | |
| 57 #include "chrome/browser/printing/print_preview_tab_controller.h" | |
| 58 #include "chrome/browser/printing/print_view_manager.h" | |
| 59 #include "chrome/browser/profiles/profile.h" | |
| 60 #include "chrome/browser/renderer_host/render_process_host.h" | |
| 61 #include "chrome/browser/renderer_host/render_view_host.h" | |
| 62 #include "chrome/browser/renderer_host/render_widget_host_view.h" | |
| 63 #include "chrome/browser/renderer_host/resource_request_details.h" | |
| 64 #include "chrome/browser/renderer_host/site_instance.h" | |
| 65 #include "chrome/browser/renderer_host/web_cache_manager.h" | |
| 66 #include "chrome/browser/renderer_preferences_util.h" | |
| 67 #include "chrome/browser/safe_browsing/client_side_detection_host.h" | |
| 68 #include "chrome/browser/sessions/session_types.h" | |
| 69 #include "chrome/browser/tab_contents/infobar_delegate.h" | |
| 70 #include "chrome/browser/tab_contents/interstitial_page.h" | |
| 71 #include "chrome/browser/tab_contents/navigation_entry.h" | |
| 72 #include "chrome/browser/tab_contents/provisional_load_details.h" | |
| 73 #include "chrome/browser/tab_contents/tab_contents_delegate.h" | |
| 74 #include "chrome/browser/tab_contents/tab_contents_observer.h" | |
| 75 #include "chrome/browser/tab_contents/tab_contents_ssl_helper.h" | |
| 76 #include "chrome/browser/tab_contents/tab_contents_view.h" | |
| 77 #include "chrome/browser/tab_contents/thumbnail_generator.h" | |
| 78 #include "chrome/browser/translate/page_translated_details.h" | |
| 79 #include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h" | |
| 80 #include "chrome/common/bindings_policy.h" | |
| 81 #include "chrome/common/chrome_switches.h" | |
| 82 #include "chrome/common/content_restriction.h" | |
| 83 #include "chrome/common/extensions/extension.h" | |
| 84 #include "chrome/common/extensions/extension_action.h" | |
| 85 #include "chrome/common/extensions/extension_icon_set.h" | |
| 86 #include "chrome/common/extensions/extension_resource.h" | |
| 87 #include "chrome/common/extensions/url_pattern.h" | |
| 88 #include "chrome/common/navigation_types.h" | |
| 89 #include "chrome/common/net/url_request_context_getter.h" | |
| 90 #include "chrome/common/notification_service.h" | |
| 91 #include "chrome/common/pref_names.h" | |
| 92 #include "chrome/common/render_messages.h" | |
| 93 #include "chrome/common/render_messages_params.h" | |
| 94 #include "chrome/common/url_constants.h" | |
| 95 #include "grit/chromium_strings.h" | |
| 96 #include "grit/generated_resources.h" | |
| 97 #include "grit/locale_settings.h" | |
| 98 #include "grit/platform_locale_settings.h" | |
| 99 #include "grit/theme_resources.h" | |
| 100 #include "net/base/net_util.h" | |
| 101 #include "net/base/registry_controlled_domain.h" | |
| 102 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
| 103 #include "ui/base/l10n/l10n_util.h" | |
| 104 #include "ui/base/resource/resource_bundle.h" | |
| 105 #include "ui/gfx/codec/png_codec.h" | |
| 106 #include "webkit/glue/password_form.h" | |
| 107 #include "webkit/glue/webpreferences.h" | |
| 108 | |
| 109 #if defined(OS_MACOSX) | |
| 110 #include "app/surface/io_surface_support_mac.h" | |
| 111 #endif // defined(OS_MACOSX) | |
| 112 | |
| 113 #if defined(OS_CHROMEOS) | |
| 114 #include "chrome/browser/chromeos/locale_change_guard.h" | |
| 115 #endif // defined(OS_CHROMEOS) | |
| 116 | |
| 117 // Cross-Site Navigations | |
| 118 // | |
| 119 // If a TabContents is told to navigate to a different web site (as determined | |
| 120 // by SiteInstance), it will replace its current RenderViewHost with a new | |
| 121 // RenderViewHost dedicated to the new SiteInstance. This works as follows: | |
| 122 // | |
| 123 // - Navigate determines whether the destination is cross-site, and if so, | |
| 124 // it creates a pending_render_view_host_ and moves into the PENDING | |
| 125 // RendererState. | |
| 126 // - The pending RVH is "suspended," so that no navigation messages are sent to | |
| 127 // its renderer until the onbeforeunload JavaScript handler has a chance to | |
| 128 // run in the current RVH. | |
| 129 // - The pending RVH tells CrossSiteRequestManager (a thread-safe singleton) | |
| 130 // that it has a pending cross-site request. ResourceDispatcherHost will | |
| 131 // check for this when the response arrives. | |
| 132 // - The current RVH runs its onbeforeunload handler. If it returns false, we | |
| 133 // cancel all the pending logic and go back to NORMAL. Otherwise we allow | |
| 134 // the pending RVH to send the navigation request to its renderer. | |
| 135 // - ResourceDispatcherHost receives a ResourceRequest on the IO thread. It | |
| 136 // checks CrossSiteRequestManager to see that the RVH responsible has a | |
| 137 // pending cross-site request, and then installs a CrossSiteEventHandler. | |
| 138 // - When RDH receives a response, the BufferedEventHandler determines whether | |
| 139 // it is a download. If so, it sends a message to the new renderer causing | |
| 140 // it to cancel the request, and the download proceeds in the download | |
| 141 // thread. For now, we stay in a PENDING state (with a pending RVH) until | |
| 142 // the next DidNavigate event for this TabContents. This isn't ideal, but it | |
| 143 // doesn't affect any functionality. | |
| 144 // - After RDH receives a response and determines that it is safe and not a | |
| 145 // download, it pauses the response to first run the old page's onunload | |
| 146 // handler. It does this by asynchronously calling the OnCrossSiteResponse | |
| 147 // method of TabContents on the UI thread, which sends a ClosePage message | |
| 148 // to the current RVH. | |
| 149 // - Once the onunload handler is finished, a ClosePage_ACK message is sent to | |
| 150 // the ResourceDispatcherHost, who unpauses the response. Data is then sent | |
| 151 // to the pending RVH. | |
| 152 // - The pending renderer sends a FrameNavigate message that invokes the | |
| 153 // DidNavigate method. This replaces the current RVH with the | |
| 154 // pending RVH and goes back to the NORMAL RendererState. | |
| 155 | |
| 156 namespace { | |
| 157 | |
| 158 // Amount of time we wait between when a key event is received and the renderer | |
| 159 // is queried for its state and pushed to the NavigationEntry. | |
| 160 const int kQueryStateDelay = 5000; | |
| 161 | |
| 162 const int kSyncWaitDelay = 40; | |
| 163 | |
| 164 // If another javascript message box is displayed within | |
| 165 // kJavascriptMessageExpectedDelay of a previous javascript message box being | |
| 166 // dismissed, display an option to suppress future message boxes from this | |
| 167 // contents. | |
| 168 const int kJavascriptMessageExpectedDelay = 1000; | |
| 169 | |
| 170 // The list of prefs we want to observe. | |
| 171 const char* kPrefsToObserve[] = { | |
| 172 prefs::kAlternateErrorPagesEnabled, | |
| 173 prefs::kDefaultZoomLevel, | |
| 174 prefs::kWebKitJavaEnabled, | |
| 175 prefs::kWebKitJavascriptEnabled, | |
| 176 prefs::kWebKitLoadsImagesAutomatically, | |
| 177 prefs::kWebKitPluginsEnabled, | |
| 178 prefs::kWebKitUsesUniversalDetector, | |
| 179 prefs::kWebKitSerifFontFamily, | |
| 180 prefs::kWebKitSansSerifFontFamily, | |
| 181 prefs::kWebKitFixedFontFamily, | |
| 182 prefs::kWebKitDefaultFontSize, | |
| 183 prefs::kWebKitDefaultFixedFontSize, | |
| 184 prefs::kWebKitMinimumFontSize, | |
| 185 prefs::kWebKitMinimumLogicalFontSize, | |
| 186 prefs::kWebkitTabsToLinks, | |
| 187 prefs::kDefaultCharset | |
| 188 // kWebKitStandardFontIsSerif needs to be added | |
| 189 // if we let users pick which font to use, serif or sans-serif when | |
| 190 // no font is specified or a CSS generic family (serif or sans-serif) | |
| 191 // is not specified. | |
| 192 }; | |
| 193 | |
| 194 const int kPrefsToObserveLength = arraysize(kPrefsToObserve); | |
| 195 | |
| 196 #if defined(OS_WIN) | |
| 197 | |
| 198 BOOL CALLBACK InvalidateWindow(HWND hwnd, LPARAM lparam) { | |
| 199 // Note: erase is required to properly paint some widgets borders. This can | |
| 200 // be seen with textfields. | |
| 201 InvalidateRect(hwnd, NULL, TRUE); | |
| 202 return TRUE; | |
| 203 } | |
| 204 #endif | |
| 205 | |
| 206 ViewMsg_Navigate_Params::NavigationType GetNavigationType( | |
| 207 Profile* profile, const NavigationEntry& entry, | |
| 208 NavigationController::ReloadType reload_type) { | |
| 209 switch (reload_type) { | |
| 210 case NavigationController::RELOAD: | |
| 211 return ViewMsg_Navigate_Params::RELOAD; | |
| 212 case NavigationController::RELOAD_IGNORING_CACHE: | |
| 213 return ViewMsg_Navigate_Params::RELOAD_IGNORING_CACHE; | |
| 214 case NavigationController::NO_RELOAD: | |
| 215 break; // Fall through to rest of function. | |
| 216 } | |
| 217 | |
| 218 if (entry.restore_type() == NavigationEntry::RESTORE_LAST_SESSION && | |
| 219 profile->DidLastSessionExitCleanly()) | |
| 220 return ViewMsg_Navigate_Params::RESTORE; | |
| 221 | |
| 222 return ViewMsg_Navigate_Params::NORMAL; | |
| 223 } | |
| 224 | |
| 225 void MakeNavigateParams(const NavigationEntry& entry, | |
| 226 const NavigationController& controller, | |
| 227 NavigationController::ReloadType reload_type, | |
| 228 ViewMsg_Navigate_Params* params) { | |
| 229 params->page_id = entry.page_id(); | |
| 230 params->pending_history_list_offset = controller.GetIndexOfEntry(&entry); | |
| 231 params->current_history_list_offset = controller.last_committed_entry_index(); | |
| 232 params->current_history_list_length = controller.entry_count(); | |
| 233 params->url = entry.url(); | |
| 234 params->referrer = entry.referrer(); | |
| 235 params->transition = entry.transition_type(); | |
| 236 params->state = entry.content_state(); | |
| 237 params->navigation_type = | |
| 238 GetNavigationType(controller.profile(), entry, reload_type); | |
| 239 params->request_time = base::Time::Now(); | |
| 240 } | |
| 241 | |
| 242 } // namespace | |
| 243 | |
| 244 | |
| 245 // TabContents ---------------------------------------------------------------- | |
| 246 | |
| 247 TabContents::TabContents(Profile* profile, | |
| 248 SiteInstance* site_instance, | |
| 249 int routing_id, | |
| 250 const TabContents* base_tab_contents, | |
| 251 SessionStorageNamespace* session_storage_namespace) | |
| 252 : delegate_(NULL), | |
| 253 ALLOW_THIS_IN_INITIALIZER_LIST(controller_( | |
| 254 this, profile, session_storage_namespace)), | |
| 255 ALLOW_THIS_IN_INITIALIZER_LIST(view_( | |
| 256 TabContentsView::Create(this))), | |
| 257 ALLOW_THIS_IN_INITIALIZER_LIST(render_manager_(this, this)), | |
| 258 bookmark_drag_(NULL), | |
| 259 is_loading_(false), | |
| 260 crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING), | |
| 261 crashed_error_code_(0), | |
| 262 waiting_for_response_(false), | |
| 263 max_page_id_(-1), | |
| 264 load_state_(net::LOAD_STATE_IDLE), | |
| 265 upload_size_(0), | |
| 266 upload_position_(0), | |
| 267 received_page_title_(false), | |
| 268 blocked_contents_(NULL), | |
| 269 all_contents_blocked_(false), | |
| 270 dont_notify_render_view_(false), | |
| 271 displayed_insecure_content_(false), | |
| 272 extension_app_(NULL), | |
| 273 capturing_contents_(false), | |
| 274 is_being_destroyed_(false), | |
| 275 notify_disconnection_(false), | |
| 276 #if defined(OS_WIN) | |
| 277 message_box_active_(CreateEvent(NULL, TRUE, FALSE, NULL)), | |
| 278 #endif | |
| 279 suppress_javascript_messages_(false), | |
| 280 is_showing_before_unload_dialog_(false), | |
| 281 opener_web_ui_type_(WebUIFactory::kNoWebUI), | |
| 282 language_state_(&controller_), | |
| 283 closed_by_user_gesture_(false), | |
| 284 minimum_zoom_percent_( | |
| 285 static_cast<int>(WebKit::WebView::minTextSizeMultiplier * 100)), | |
| 286 maximum_zoom_percent_( | |
| 287 static_cast<int>(WebKit::WebView::maxTextSizeMultiplier * 100)), | |
| 288 temporary_zoom_settings_(false), | |
| 289 content_restrictions_(0) { | |
| 290 renderer_preferences_util::UpdateFromSystemSettings( | |
| 291 &renderer_preferences_, profile); | |
| 292 | |
| 293 content_settings_delegate_.reset( | |
| 294 new TabSpecificContentSettings(this, profile)); | |
| 295 | |
| 296 render_manager_.Init(profile, site_instance, routing_id); | |
| 297 | |
| 298 // We have the initial size of the view be based on the size of the passed in | |
| 299 // tab contents (normally a tab from the same window). | |
| 300 view_->CreateView(base_tab_contents ? | |
| 301 base_tab_contents->view()->GetContainerSize() : gfx::Size()); | |
| 302 | |
| 303 // Register for notifications about all interested prefs change. | |
| 304 PrefService* prefs = profile->GetPrefs(); | |
| 305 pref_change_registrar_.Init(prefs); | |
| 306 if (prefs) { | |
| 307 for (int i = 0; i < kPrefsToObserveLength; ++i) | |
| 308 pref_change_registrar_.Add(kPrefsToObserve[i], this); | |
| 309 } | |
| 310 | |
| 311 registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DESTROYED, | |
| 312 NotificationService::AllSources()); | |
| 313 #if defined(OS_LINUX) | |
| 314 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, | |
| 315 NotificationService::AllSources()); | |
| 316 #endif | |
| 317 | |
| 318 registrar_.Add(this, NotificationType::USER_STYLE_SHEET_UPDATED, | |
| 319 NotificationService::AllSources()); | |
| 320 | |
| 321 // Register for notifications about content setting changes. | |
| 322 registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED, | |
| 323 NotificationService::AllSources()); | |
| 324 | |
| 325 // Listen for extension changes so we can update extension_for_current_page_. | |
| 326 registrar_.Add(this, NotificationType::EXTENSION_LOADED, | |
| 327 NotificationService::AllSources()); | |
| 328 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | |
| 329 NotificationService::AllSources()); | |
| 330 | |
| 331 // Listen for Google URL changes | |
| 332 registrar_.Add(this, NotificationType::GOOGLE_URL_UPDATED, | |
| 333 NotificationService::AllSources()); | |
| 334 | |
| 335 // Set-up the showing of the omnibox search infobar if applicable. | |
| 336 if (OmniboxSearchHint::IsEnabled(profile)) | |
| 337 omnibox_search_hint_.reset(new OmniboxSearchHint(this)); | |
| 338 | |
| 339 // Can only add observers after render_manager_.Init() is called, since that's | |
| 340 // what sets up the render_view_host which TabContentObserver's constructor | |
| 341 // uses to get the routing_id. | |
| 342 AddObservers(); | |
| 343 } | |
| 344 | |
| 345 TabContents::~TabContents() { | |
| 346 is_being_destroyed_ = true; | |
| 347 | |
| 348 // We don't want any notifications while we're running our destructor. | |
| 349 registrar_.RemoveAll(); | |
| 350 pref_change_registrar_.RemoveAll(); | |
| 351 | |
| 352 NotifyDisconnected(); | |
| 353 hung_renderer_dialog::HideForTabContents(this); | |
| 354 | |
| 355 // First cleanly close all child windows. | |
| 356 // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked | |
| 357 // some of these to close. CloseWindows is async, so it might get called | |
| 358 // twice before it runs. | |
| 359 CloseConstrainedWindows(); | |
| 360 | |
| 361 // Close all blocked contents. | |
| 362 if (blocked_contents_) | |
| 363 blocked_contents_->Destroy(); | |
| 364 | |
| 365 // Notify any observer that have a reference on this tab contents. | |
| 366 NotificationService::current()->Notify( | |
| 367 NotificationType::TAB_CONTENTS_DESTROYED, | |
| 368 Source<TabContents>(this), | |
| 369 NotificationService::NoDetails()); | |
| 370 | |
| 371 // Notify any lasting InfobarDelegates that have not yet been removed that | |
| 372 // whatever infobar they were handling in this TabContents has closed, | |
| 373 // because the TabContents is going away entirely. | |
| 374 // This must happen after the TAB_CONTENTS_DESTROYED notification as the | |
| 375 // notification may trigger infobars calls that access their delegate. (and | |
| 376 // some implementations of InfoBarDelegate do delete themselves on | |
| 377 // InfoBarClosed()). | |
| 378 for (size_t i = 0; i < infobar_count(); ++i) { | |
| 379 InfoBarDelegate* delegate = GetInfoBarDelegateAt(i); | |
| 380 delegate->InfoBarClosed(); | |
| 381 } | |
| 382 infobar_delegates_.clear(); | |
| 383 | |
| 384 // TODO(brettw) this should be moved to the view. | |
| 385 #if defined(OS_WIN) | |
| 386 // If we still have a window handle, destroy it. GetNativeView can return | |
| 387 // NULL if this contents was part of a window that closed. | |
| 388 if (GetNativeView()) { | |
| 389 RenderViewHost* host = render_view_host(); | |
| 390 if (host && host->view()) { | |
| 391 host->view()->WillWmDestroy(); | |
| 392 } | |
| 393 ::DestroyWindow(GetNativeView()); | |
| 394 } | |
| 395 #endif | |
| 396 | |
| 397 // OnCloseStarted isn't called in unit tests. | |
| 398 if (!tab_close_start_time_.is_null()) { | |
| 399 UMA_HISTOGRAM_TIMES("Tab.Close", | |
| 400 base::TimeTicks::Now() - tab_close_start_time_); | |
| 401 } | |
| 402 | |
| 403 FOR_EACH_OBSERVER(TabContentsObserver, observers_, set_tab_contents(NULL)); | |
| 404 } | |
| 405 | |
| 406 void TabContents::AddObservers() { | |
| 407 printing_.reset(new printing::PrintViewManager(this)); | |
| 408 print_preview_.reset(new printing::PrintPreviewMessageHandler(this)); | |
| 409 fav_icon_helper_.reset(new FavIconHelper(this)); | |
| 410 autofill_manager_.reset(new AutoFillManager(this)); | |
| 411 autocomplete_history_manager_.reset(new AutocompleteHistoryManager(this)); | |
| 412 prerender_plt_recorder_.reset(new prerender::PrerenderPLTRecorder(this)); | |
| 413 desktop_notification_handler_.reset( | |
| 414 new DesktopNotificationHandlerForTC(this, GetRenderProcessHost())); | |
| 415 plugin_observer_.reset(new PluginObserver(this)); | |
| 416 safebrowsing_detection_host_.reset(new safe_browsing::ClientSideDetectionHost( | |
| 417 this)); | |
| 418 } | |
| 419 | |
| 420 // static | |
| 421 void TabContents::RegisterUserPrefs(PrefService* prefs) { | |
| 422 prefs->RegisterBooleanPref(prefs::kAlternateErrorPagesEnabled, true); | |
| 423 | |
| 424 WebPreferences pref_defaults; | |
| 425 prefs->RegisterBooleanPref(prefs::kWebKitJavascriptEnabled, | |
| 426 pref_defaults.javascript_enabled); | |
| 427 prefs->RegisterBooleanPref(prefs::kWebKitWebSecurityEnabled, | |
| 428 pref_defaults.web_security_enabled); | |
| 429 prefs->RegisterBooleanPref( | |
| 430 prefs::kWebKitJavascriptCanOpenWindowsAutomatically, true); | |
| 431 prefs->RegisterBooleanPref(prefs::kWebKitLoadsImagesAutomatically, | |
| 432 pref_defaults.loads_images_automatically); | |
| 433 prefs->RegisterBooleanPref(prefs::kWebKitPluginsEnabled, | |
| 434 pref_defaults.plugins_enabled); | |
| 435 prefs->RegisterBooleanPref(prefs::kWebKitDomPasteEnabled, | |
| 436 pref_defaults.dom_paste_enabled); | |
| 437 prefs->RegisterBooleanPref(prefs::kWebKitShrinksStandaloneImagesToFit, | |
| 438 pref_defaults.shrinks_standalone_images_to_fit); | |
| 439 prefs->RegisterDictionaryPref(prefs::kWebKitInspectorSettings); | |
| 440 prefs->RegisterBooleanPref(prefs::kWebKitTextAreasAreResizable, | |
| 441 pref_defaults.text_areas_are_resizable); | |
| 442 prefs->RegisterBooleanPref(prefs::kWebKitJavaEnabled, | |
| 443 pref_defaults.java_enabled); | |
| 444 prefs->RegisterBooleanPref(prefs::kWebkitTabsToLinks, | |
| 445 pref_defaults.tabs_to_links); | |
| 446 | |
| 447 prefs->RegisterLocalizedStringPref(prefs::kAcceptLanguages, | |
| 448 IDS_ACCEPT_LANGUAGES); | |
| 449 prefs->RegisterLocalizedStringPref(prefs::kDefaultCharset, | |
| 450 IDS_DEFAULT_ENCODING); | |
| 451 prefs->RegisterLocalizedBooleanPref(prefs::kWebKitStandardFontIsSerif, | |
| 452 IDS_STANDARD_FONT_IS_SERIF); | |
| 453 prefs->RegisterLocalizedStringPref(prefs::kWebKitFixedFontFamily, | |
| 454 IDS_FIXED_FONT_FAMILY); | |
| 455 prefs->RegisterLocalizedStringPref(prefs::kWebKitSerifFontFamily, | |
| 456 IDS_SERIF_FONT_FAMILY); | |
| 457 prefs->RegisterLocalizedStringPref(prefs::kWebKitSansSerifFontFamily, | |
| 458 IDS_SANS_SERIF_FONT_FAMILY); | |
| 459 prefs->RegisterLocalizedStringPref(prefs::kWebKitCursiveFontFamily, | |
| 460 IDS_CURSIVE_FONT_FAMILY); | |
| 461 prefs->RegisterLocalizedStringPref(prefs::kWebKitFantasyFontFamily, | |
| 462 IDS_FANTASY_FONT_FAMILY); | |
| 463 prefs->RegisterLocalizedIntegerPref(prefs::kWebKitDefaultFontSize, | |
| 464 IDS_DEFAULT_FONT_SIZE); | |
| 465 prefs->RegisterLocalizedIntegerPref(prefs::kWebKitDefaultFixedFontSize, | |
| 466 IDS_DEFAULT_FIXED_FONT_SIZE); | |
| 467 prefs->RegisterLocalizedIntegerPref(prefs::kWebKitMinimumFontSize, | |
| 468 IDS_MINIMUM_FONT_SIZE); | |
| 469 prefs->RegisterLocalizedIntegerPref(prefs::kWebKitMinimumLogicalFontSize, | |
| 470 IDS_MINIMUM_LOGICAL_FONT_SIZE); | |
| 471 prefs->RegisterLocalizedBooleanPref(prefs::kWebKitUsesUniversalDetector, | |
| 472 IDS_USES_UNIVERSAL_DETECTOR); | |
| 473 prefs->RegisterLocalizedStringPref(prefs::kStaticEncodings, | |
| 474 IDS_STATIC_ENCODING_LIST); | |
| 475 } | |
| 476 | |
| 477 bool TabContents::OnMessageReceived(const IPC::Message& message) { | |
| 478 ObserverListBase<TabContentsObserver>::Iterator it(observers_); | |
| 479 TabContentsObserver* observer; | |
| 480 while ((observer = it.GetNext()) != NULL) | |
| 481 if (observer->OnMessageReceived(message)) | |
| 482 return true; | |
| 483 | |
| 484 bool handled = true; | |
| 485 bool message_is_ok = true; | |
| 486 IPC_BEGIN_MESSAGE_MAP_EX(TabContents, message, message_is_ok) | |
| 487 IPC_MESSAGE_HANDLER(ViewHostMsg_DidStartProvisionalLoadForFrame, | |
| 488 OnDidStartProvisionalLoadForFrame) | |
| 489 IPC_MESSAGE_HANDLER(ViewHostMsg_DidRedirectProvisionalLoad, | |
| 490 OnDidRedirectProvisionalLoad) | |
| 491 IPC_MESSAGE_HANDLER(ViewHostMsg_DidFailProvisionalLoadWithError, | |
| 492 OnDidFailProvisionalLoadWithError) | |
| 493 IPC_MESSAGE_HANDLER(ViewHostMsg_DidLoadResourceFromMemoryCache, | |
| 494 OnDidLoadResourceFromMemoryCache) | |
| 495 IPC_MESSAGE_HANDLER(ViewHostMsg_DidDisplayInsecureContent, | |
| 496 OnDidDisplayInsecureContent) | |
| 497 IPC_MESSAGE_HANDLER(ViewHostMsg_DidRunInsecureContent, | |
| 498 OnDidRunInsecureContent) | |
| 499 IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentLoadedInFrame, | |
| 500 OnDocumentLoadedInFrame) | |
| 501 IPC_MESSAGE_HANDLER(ViewHostMsg_DidFinishLoad, OnDidFinishLoad) | |
| 502 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateContentRestrictions, | |
| 503 OnUpdateContentRestrictions) | |
| 504 IPC_MESSAGE_HANDLER(ViewHostMsg_PDFHasUnsupportedFeature, | |
| 505 OnPDFHasUnsupportedFeature) | |
| 506 IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset) | |
| 507 IPC_MESSAGE_HANDLER(ViewHostMsg_DidGetApplicationInfo, | |
| 508 OnDidGetApplicationInfo) | |
| 509 IPC_MESSAGE_HANDLER(ViewHostMsg_InstallApplication, | |
| 510 OnInstallApplication) | |
| 511 IPC_MESSAGE_HANDLER(ViewHostMsg_PageContents, OnPageContents) | |
| 512 IPC_MESSAGE_HANDLER(ViewHostMsg_PageTranslated, OnPageTranslated) | |
| 513 IPC_MESSAGE_HANDLER(ViewHostMsg_SetSuggestions, OnSetSuggestions) | |
| 514 IPC_MESSAGE_HANDLER(ViewHostMsg_InstantSupportDetermined, | |
| 515 OnInstantSupportDetermined) | |
| 516 IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser) | |
| 517 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 518 IPC_END_MESSAGE_MAP_EX() | |
| 519 | |
| 520 if (!message_is_ok) { | |
| 521 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RVD")); | |
| 522 GetRenderProcessHost()->ReceivedBadMessage(); | |
| 523 } | |
| 524 | |
| 525 return handled; | |
| 526 } | |
| 527 | |
| 528 // Returns true if contains content rendered by an extension. | |
| 529 bool TabContents::HostsExtension() const { | |
| 530 return GetURL().SchemeIs(chrome::kExtensionScheme); | |
| 531 } | |
| 532 | |
| 533 TabContentsSSLHelper* TabContents::GetSSLHelper() { | |
| 534 if (ssl_helper_.get() == NULL) | |
| 535 ssl_helper_.reset(new TabContentsSSLHelper(this)); | |
| 536 return ssl_helper_.get(); | |
| 537 } | |
| 538 | |
| 539 RenderProcessHost* TabContents::GetRenderProcessHost() const { | |
| 540 return render_manager_.current_host()->process(); | |
| 541 } | |
| 542 | |
| 543 void TabContents::SetExtensionApp(const Extension* extension) { | |
| 544 DCHECK(!extension || extension->GetFullLaunchURL().is_valid()); | |
| 545 extension_app_ = extension; | |
| 546 | |
| 547 UpdateExtensionAppIcon(extension_app_); | |
| 548 | |
| 549 NotificationService::current()->Notify( | |
| 550 NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, | |
| 551 Source<TabContents>(this), | |
| 552 NotificationService::NoDetails()); | |
| 553 } | |
| 554 | |
| 555 void TabContents::SetExtensionAppById(const std::string& extension_app_id) { | |
| 556 if (extension_app_id.empty()) | |
| 557 return; | |
| 558 | |
| 559 ExtensionService* extension_service = profile()->GetExtensionService(); | |
| 560 if (!extension_service || !extension_service->is_ready()) | |
| 561 return; | |
| 562 | |
| 563 const Extension* extension = | |
| 564 extension_service->GetExtensionById(extension_app_id, false); | |
| 565 if (extension) | |
| 566 SetExtensionApp(extension); | |
| 567 } | |
| 568 | |
| 569 SkBitmap* TabContents::GetExtensionAppIcon() { | |
| 570 if (extension_app_icon_.empty()) | |
| 571 return NULL; | |
| 572 | |
| 573 return &extension_app_icon_; | |
| 574 } | |
| 575 | |
| 576 const GURL& TabContents::GetURL() const { | |
| 577 // We may not have a navigation entry yet | |
| 578 NavigationEntry* entry = controller_.GetActiveEntry(); | |
| 579 return entry ? entry->virtual_url() : GURL::EmptyGURL(); | |
| 580 } | |
| 581 | |
| 582 const string16& TabContents::GetTitle() const { | |
| 583 // Transient entries take precedence. They are used for interstitial pages | |
| 584 // that are shown on top of existing pages. | |
| 585 NavigationEntry* entry = controller_.GetTransientEntry(); | |
| 586 if (entry) { | |
| 587 return entry->GetTitleForDisplay(profile()->GetPrefs()-> | |
| 588 GetString(prefs::kAcceptLanguages)); | |
| 589 } | |
| 590 WebUI* our_web_ui = render_manager_.pending_web_ui() ? | |
| 591 render_manager_.pending_web_ui() : render_manager_.web_ui(); | |
| 592 if (our_web_ui) { | |
| 593 // Don't override the title in view source mode. | |
| 594 entry = controller_.GetActiveEntry(); | |
| 595 if (!(entry && entry->IsViewSourceMode())) { | |
| 596 // Give the Web UI the chance to override our title. | |
| 597 const string16& title = our_web_ui->overridden_title(); | |
| 598 if (!title.empty()) | |
| 599 return title; | |
| 600 } | |
| 601 } | |
| 602 | |
| 603 // We use the title for the last committed entry rather than a pending | |
| 604 // navigation entry. For example, when the user types in a URL, we want to | |
| 605 // keep the old page's title until the new load has committed and we get a new | |
| 606 // title. | |
| 607 entry = controller_.GetLastCommittedEntry(); | |
| 608 if (entry) { | |
| 609 return entry->GetTitleForDisplay(profile()->GetPrefs()-> | |
| 610 GetString(prefs::kAcceptLanguages)); | |
| 611 } | |
| 612 return EmptyString16(); | |
| 613 } | |
| 614 | |
| 615 // static | |
| 616 string16 TabContents::GetDefaultTitle() { | |
| 617 return l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); | |
| 618 } | |
| 619 | |
| 620 int32 TabContents::GetMaxPageID() { | |
| 621 if (GetSiteInstance()) | |
| 622 return GetSiteInstance()->max_page_id(); | |
| 623 else | |
| 624 return max_page_id_; | |
| 625 } | |
| 626 | |
| 627 void TabContents::UpdateMaxPageID(int32 page_id) { | |
| 628 // Ensure both the SiteInstance and RenderProcessHost update their max page | |
| 629 // IDs in sync. Only TabContents will also have site instances, except during | |
| 630 // testing. | |
| 631 if (GetSiteInstance()) | |
| 632 GetSiteInstance()->UpdateMaxPageID(page_id); | |
| 633 GetRenderProcessHost()->UpdateMaxPageID(page_id); | |
| 634 } | |
| 635 | |
| 636 SiteInstance* TabContents::GetSiteInstance() const { | |
| 637 return render_manager_.current_host()->site_instance(); | |
| 638 } | |
| 639 | |
| 640 bool TabContents::ShouldDisplayURL() { | |
| 641 // Don't hide the url in view source mode and with interstitials. | |
| 642 NavigationEntry* entry = controller_.GetActiveEntry(); | |
| 643 if (entry && (entry->IsViewSourceMode() || | |
| 644 entry->page_type() == INTERSTITIAL_PAGE)) { | |
| 645 return true; | |
| 646 } | |
| 647 | |
| 648 // We always display the URL for non-WebUI URLs to prevent spoofing. | |
| 649 if (entry && !WebUIFactory::HasWebUIScheme(entry->url())) | |
| 650 return true; | |
| 651 | |
| 652 WebUI* web_ui = GetWebUIForCurrentState(); | |
| 653 if (web_ui) | |
| 654 return !web_ui->should_hide_url(); | |
| 655 return true; | |
| 656 } | |
| 657 | |
| 658 SkBitmap TabContents::GetFavIcon() const { | |
| 659 // Like GetTitle(), we also want to use the favicon for the last committed | |
| 660 // entry rather than a pending navigation entry. | |
| 661 NavigationEntry* entry = controller_.GetTransientEntry(); | |
| 662 if (entry) | |
| 663 return entry->favicon().bitmap(); | |
| 664 | |
| 665 entry = controller_.GetLastCommittedEntry(); | |
| 666 if (entry) | |
| 667 return entry->favicon().bitmap(); | |
| 668 return SkBitmap(); | |
| 669 } | |
| 670 | |
| 671 bool TabContents::FavIconIsValid() const { | |
| 672 NavigationEntry* entry = controller_.GetTransientEntry(); | |
| 673 if (entry) | |
| 674 return entry->favicon().is_valid(); | |
| 675 | |
| 676 entry = controller_.GetLastCommittedEntry(); | |
| 677 if (entry) | |
| 678 return entry->favicon().is_valid(); | |
| 679 | |
| 680 return false; | |
| 681 } | |
| 682 | |
| 683 bool TabContents::ShouldDisplayFavIcon() { | |
| 684 // Always display a throbber during pending loads. | |
| 685 if (controller_.GetLastCommittedEntry() && controller_.pending_entry()) | |
| 686 return true; | |
| 687 | |
| 688 WebUI* web_ui = GetWebUIForCurrentState(); | |
| 689 if (web_ui) | |
| 690 return !web_ui->hide_favicon(); | |
| 691 return true; | |
| 692 } | |
| 693 | |
| 694 string16 TabContents::GetStatusText() const { | |
| 695 if (!is_loading() || load_state_ == net::LOAD_STATE_IDLE) | |
| 696 return string16(); | |
| 697 | |
| 698 switch (load_state_) { | |
| 699 case net::LOAD_STATE_WAITING_FOR_CACHE: | |
| 700 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_CACHE); | |
| 701 case net::LOAD_STATE_ESTABLISHING_PROXY_TUNNEL: | |
| 702 return | |
| 703 l10n_util::GetStringUTF16(IDS_LOAD_STATE_ESTABLISHING_PROXY_TUNNEL); | |
| 704 case net::LOAD_STATE_RESOLVING_PROXY_FOR_URL: | |
| 705 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_PROXY_FOR_URL); | |
| 706 case net::LOAD_STATE_RESOLVING_HOST: | |
| 707 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_HOST); | |
| 708 case net::LOAD_STATE_CONNECTING: | |
| 709 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_CONNECTING); | |
| 710 case net::LOAD_STATE_SSL_HANDSHAKE: | |
| 711 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_SSL_HANDSHAKE); | |
| 712 case net::LOAD_STATE_SENDING_REQUEST: | |
| 713 if (upload_size_) | |
| 714 return l10n_util::GetStringFUTF16Int( | |
| 715 IDS_LOAD_STATE_SENDING_REQUEST_WITH_PROGRESS, | |
| 716 static_cast<int>((100 * upload_position_) / upload_size_)); | |
| 717 else | |
| 718 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_SENDING_REQUEST); | |
| 719 case net::LOAD_STATE_WAITING_FOR_RESPONSE: | |
| 720 return l10n_util::GetStringFUTF16(IDS_LOAD_STATE_WAITING_FOR_RESPONSE, | |
| 721 load_state_host_); | |
| 722 // Ignore net::LOAD_STATE_READING_RESPONSE and net::LOAD_STATE_IDLE | |
| 723 case net::LOAD_STATE_IDLE: | |
| 724 case net::LOAD_STATE_READING_RESPONSE: | |
| 725 break; | |
| 726 } | |
| 727 | |
| 728 return string16(); | |
| 729 } | |
| 730 | |
| 731 void TabContents::AddObserver(TabContentsObserver* observer) { | |
| 732 observers_.AddObserver(observer); | |
| 733 } | |
| 734 | |
| 735 void TabContents::RemoveObserver(TabContentsObserver* observer) { | |
| 736 observers_.RemoveObserver(observer); | |
| 737 } | |
| 738 | |
| 739 void TabContents::SetIsCrashed(base::TerminationStatus status, int error_code) { | |
| 740 if (status == crashed_status_) | |
| 741 return; | |
| 742 | |
| 743 crashed_status_ = status; | |
| 744 crashed_error_code_ = error_code; | |
| 745 NotifyNavigationStateChanged(INVALIDATE_TAB); | |
| 746 } | |
| 747 | |
| 748 void TabContents::PageActionStateChanged() { | |
| 749 NotifyNavigationStateChanged(TabContents::INVALIDATE_PAGE_ACTIONS); | |
| 750 } | |
| 751 | |
| 752 void TabContents::NotifyNavigationStateChanged(unsigned changed_flags) { | |
| 753 if (delegate_) | |
| 754 delegate_->NavigationStateChanged(this, changed_flags); | |
| 755 } | |
| 756 | |
| 757 void TabContents::DidBecomeSelected() { | |
| 758 controller_.SetActive(true); | |
| 759 RenderWidgetHostView* rwhv = GetRenderWidgetHostView(); | |
| 760 if (rwhv) { | |
| 761 rwhv->DidBecomeSelected(); | |
| 762 #if defined(OS_MACOSX) | |
| 763 rwhv->SetActive(true); | |
| 764 #endif | |
| 765 } | |
| 766 | |
| 767 WebCacheManager::GetInstance()->ObserveActivity(GetRenderProcessHost()->id()); | |
| 768 last_selected_time_ = base::TimeTicks::Now(); | |
| 769 #if defined(OS_CHROMEOS) | |
| 770 chromeos::LocaleChangeGuard::Check(this); | |
| 771 #endif | |
| 772 } | |
| 773 | |
| 774 void TabContents::FadeForInstant(bool animate) { | |
| 775 RenderWidgetHostView* rwhv = GetRenderWidgetHostView(); | |
| 776 SkColor whitish = SkColorSetARGB(192, 255, 255, 255); | |
| 777 if (rwhv) | |
| 778 rwhv->SetVisuallyDeemphasized(&whitish, animate); | |
| 779 } | |
| 780 | |
| 781 void TabContents::CancelInstantFade() { | |
| 782 RenderWidgetHostView* rwhv = GetRenderWidgetHostView(); | |
| 783 if (rwhv) | |
| 784 rwhv->SetVisuallyDeemphasized(NULL, false); | |
| 785 } | |
| 786 | |
| 787 void TabContents::WasHidden() { | |
| 788 if (!capturing_contents()) { | |
| 789 // |render_view_host()| can be NULL if the user middle clicks a link to open | |
| 790 // a tab in then background, then closes the tab before selecting it. This | |
| 791 // is because closing the tab calls TabContents::Destroy(), which removes | |
| 792 // the |render_view_host()|; then when we actually destroy the window, | |
| 793 // OnWindowPosChanged() notices and calls HideContents() (which calls us). | |
| 794 RenderWidgetHostView* rwhv = GetRenderWidgetHostView(); | |
| 795 if (rwhv) | |
| 796 rwhv->WasHidden(); | |
| 797 } | |
| 798 | |
| 799 NotificationService::current()->Notify( | |
| 800 NotificationType::TAB_CONTENTS_HIDDEN, | |
| 801 Source<TabContents>(this), | |
| 802 NotificationService::NoDetails()); | |
| 803 } | |
| 804 | |
| 805 void TabContents::Activate() { | |
| 806 if (delegate_) | |
| 807 delegate_->ActivateContents(this); | |
| 808 } | |
| 809 | |
| 810 void TabContents::Deactivate() { | |
| 811 if (delegate_) | |
| 812 delegate_->DeactivateContents(this); | |
| 813 } | |
| 814 | |
| 815 void TabContents::ShowContents() { | |
| 816 RenderWidgetHostView* rwhv = GetRenderWidgetHostView(); | |
| 817 if (rwhv) | |
| 818 rwhv->DidBecomeSelected(); | |
| 819 } | |
| 820 | |
| 821 void TabContents::HideContents() { | |
| 822 // TODO(pkasting): http://b/1239839 Right now we purposefully don't call | |
| 823 // our superclass HideContents(), because some callers want to be very picky | |
| 824 // about the order in which these get called. In addition to making the code | |
| 825 // here practically impossible to understand, this also means we end up | |
| 826 // calling TabContents::WasHidden() twice if callers call both versions of | |
| 827 // HideContents() on a TabContents. | |
| 828 WasHidden(); | |
| 829 } | |
| 830 | |
| 831 bool TabContents::NeedToFireBeforeUnload() { | |
| 832 // TODO(creis): Should we fire even for interstitial pages? | |
| 833 return notify_disconnection() && | |
| 834 !showing_interstitial_page() && | |
| 835 !render_view_host()->SuddenTerminationAllowed(); | |
| 836 } | |
| 837 | |
| 838 void TabContents::OpenURL(const GURL& url, const GURL& referrer, | |
| 839 WindowOpenDisposition disposition, | |
| 840 PageTransition::Type transition) { | |
| 841 if (delegate_) | |
| 842 delegate_->OpenURLFromTab(this, url, referrer, disposition, transition); | |
| 843 } | |
| 844 | |
| 845 bool TabContents::NavigateToPendingEntry( | |
| 846 NavigationController::ReloadType reload_type) { | |
| 847 return NavigateToEntry(*controller_.pending_entry(), reload_type); | |
| 848 } | |
| 849 | |
| 850 bool TabContents::NavigateToEntry( | |
| 851 const NavigationEntry& entry, | |
| 852 NavigationController::ReloadType reload_type) { | |
| 853 RenderViewHost* dest_render_view_host = render_manager_.Navigate(entry); | |
| 854 if (!dest_render_view_host) | |
| 855 return false; // Unable to create the desired render view host. | |
| 856 | |
| 857 if (delegate_ && delegate_->ShouldEnablePreferredSizeNotifications()) { | |
| 858 dest_render_view_host->EnablePreferredSizeChangedMode( | |
| 859 kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); | |
| 860 } | |
| 861 | |
| 862 // For security, we should never send non-Web-UI URLs to a Web UI renderer. | |
| 863 // Double check that here. | |
| 864 int enabled_bindings = dest_render_view_host->enabled_bindings(); | |
| 865 bool is_allowed_in_web_ui_renderer = | |
| 866 WebUIFactory::IsURLAcceptableForWebUI(profile(), entry.url()); | |
| 867 CHECK(!BindingsPolicy::is_web_ui_enabled(enabled_bindings) || | |
| 868 is_allowed_in_web_ui_renderer); | |
| 869 | |
| 870 // Tell DevTools agent that it is attached prior to the navigation. | |
| 871 DevToolsManager* devtools_manager = DevToolsManager::GetInstance(); | |
| 872 if (devtools_manager) { // NULL in unit tests. | |
| 873 devtools_manager->OnNavigatingToPendingEntry(render_view_host(), | |
| 874 dest_render_view_host, | |
| 875 entry.url()); | |
| 876 } | |
| 877 | |
| 878 // Used for page load time metrics. | |
| 879 current_load_start_ = base::TimeTicks::Now(); | |
| 880 | |
| 881 // Navigate in the desired RenderViewHost. | |
| 882 ViewMsg_Navigate_Params navigate_params; | |
| 883 MakeNavigateParams(entry, controller_, reload_type, &navigate_params); | |
| 884 if (delegate_) { | |
| 885 navigate_params.extra_headers = | |
| 886 delegate_->GetNavigationHeaders(navigate_params.url); | |
| 887 } | |
| 888 dest_render_view_host->Navigate(navigate_params); | |
| 889 | |
| 890 if (entry.page_id() == -1) { | |
| 891 // HACK!! This code suppresses javascript: URLs from being added to | |
| 892 // session history, which is what we want to do for javascript: URLs that | |
| 893 // do not generate content. What we really need is a message from the | |
| 894 // renderer telling us that a new page was not created. The same message | |
| 895 // could be used for mailto: URLs and the like. | |
| 896 if (entry.url().SchemeIs(chrome::kJavaScriptScheme)) | |
| 897 return false; | |
| 898 } | |
| 899 | |
| 900 // Notify observers about navigation. | |
| 901 FOR_EACH_OBSERVER(TabContentsObserver, observers_, NavigateToPendingEntry()); | |
| 902 | |
| 903 if (reload_type != NavigationController::NO_RELOAD && | |
| 904 !profile()->IsOffTheRecord()) { | |
| 905 FaviconService* favicon_service = | |
| 906 profile()->GetFaviconService(Profile::IMPLICIT_ACCESS); | |
| 907 if (favicon_service) | |
| 908 favicon_service->SetFaviconOutOfDateForPage(entry.url()); | |
| 909 } | |
| 910 | |
| 911 return true; | |
| 912 } | |
| 913 | |
| 914 void TabContents::Stop() { | |
| 915 render_manager_.Stop(); | |
| 916 printing_->Stop(); | |
| 917 } | |
| 918 | |
| 919 void TabContents::DisassociateFromPopupCount() { | |
| 920 render_view_host()->DisassociateFromPopupCount(); | |
| 921 } | |
| 922 | |
| 923 TabContents* TabContents::Clone() { | |
| 924 // We create a new SiteInstance so that the new tab won't share processes | |
| 925 // with the old one. This can be changed in the future if we need it to share | |
| 926 // processes for some reason. | |
| 927 TabContents* tc = new TabContents(profile(), | |
| 928 SiteInstance::CreateSiteInstance(profile()), | |
| 929 MSG_ROUTING_NONE, this, NULL); | |
| 930 tc->controller().CopyStateFrom(controller_); | |
| 931 tc->extension_app_ = extension_app_; | |
| 932 tc->extension_app_icon_ = extension_app_icon_; | |
| 933 return tc; | |
| 934 } | |
| 935 | |
| 936 void TabContents::ShowPageInfo(const GURL& url, | |
| 937 const NavigationEntry::SSLStatus& ssl, | |
| 938 bool show_history) { | |
| 939 if (!delegate_) | |
| 940 return; | |
| 941 | |
| 942 delegate_->ShowPageInfo(profile(), url, ssl, show_history); | |
| 943 } | |
| 944 | |
| 945 void TabContents::SaveFavicon() { | |
| 946 NavigationEntry* entry = controller_.GetActiveEntry(); | |
| 947 if (!entry || entry->url().is_empty()) | |
| 948 return; | |
| 949 | |
| 950 // Make sure the page is in history, otherwise adding the favicon does | |
| 951 // nothing. | |
| 952 HistoryService* history = profile()->GetOriginalProfile()->GetHistoryService( | |
| 953 Profile::IMPLICIT_ACCESS); | |
| 954 if (!history) | |
| 955 return; | |
| 956 history->AddPageNoVisitForBookmark(entry->url()); | |
| 957 | |
| 958 FaviconService* service = profile()->GetOriginalProfile()->GetFaviconService( | |
| 959 Profile::IMPLICIT_ACCESS); | |
| 960 if (!service) | |
| 961 return; | |
| 962 const NavigationEntry::FaviconStatus& favicon(entry->favicon()); | |
| 963 if (!favicon.is_valid() || favicon.url().is_empty() || | |
| 964 favicon.bitmap().empty()) { | |
| 965 return; | |
| 966 } | |
| 967 std::vector<unsigned char> image_data; | |
| 968 gfx::PNGCodec::EncodeBGRASkBitmap(favicon.bitmap(), false, &image_data); | |
| 969 service->SetFavicon(entry->url(), favicon.url(), image_data); | |
| 970 } | |
| 971 | |
| 972 ConstrainedWindow* TabContents::CreateConstrainedDialog( | |
| 973 ConstrainedWindowDelegate* delegate) { | |
| 974 ConstrainedWindow* window = | |
| 975 ConstrainedWindow::CreateConstrainedDialog(this, delegate); | |
| 976 child_windows_.push_back(window); | |
| 977 | |
| 978 if (child_windows_.size() == 1) { | |
| 979 window->ShowConstrainedWindow(); | |
| 980 BlockTabContent(true); | |
| 981 } | |
| 982 | |
| 983 return window; | |
| 984 } | |
| 985 | |
| 986 void TabContents::BlockTabContent(bool blocked) { | |
| 987 RenderWidgetHostView* rwhv = GetRenderWidgetHostView(); | |
| 988 // 70% opaque grey. | |
| 989 SkColor greyish = SkColorSetARGB(178, 0, 0, 0); | |
| 990 if (rwhv) | |
| 991 rwhv->SetVisuallyDeemphasized(blocked ? &greyish : NULL, false); | |
| 992 render_view_host()->set_ignore_input_events(blocked); | |
| 993 if (delegate_) | |
| 994 delegate_->SetTabContentBlocked(this, blocked); | |
| 995 } | |
| 996 | |
| 997 void TabContents::AddNewContents(TabContents* new_contents, | |
| 998 WindowOpenDisposition disposition, | |
| 999 const gfx::Rect& initial_pos, | |
| 1000 bool user_gesture) { | |
| 1001 if (all_contents_blocked_) { | |
| 1002 if (!blocked_contents_) | |
| 1003 blocked_contents_ = new BlockedContentContainer(this); | |
| 1004 blocked_contents_->AddTabContents( | |
| 1005 new_contents, disposition, initial_pos, user_gesture); | |
| 1006 return; | |
| 1007 } | |
| 1008 | |
| 1009 if (!delegate_) | |
| 1010 return; | |
| 1011 | |
| 1012 if ((disposition == NEW_POPUP) && !user_gesture && | |
| 1013 !CommandLine::ForCurrentProcess()->HasSwitch( | |
| 1014 switches::kDisablePopupBlocking)) { | |
| 1015 // Unrequested popups from normal pages are constrained unless they're in | |
| 1016 // the whitelist. The popup owner will handle checking this. | |
| 1017 delegate_->GetConstrainingContents(this)->AddPopup( | |
| 1018 new_contents, initial_pos); | |
| 1019 } else { | |
| 1020 new_contents->DisassociateFromPopupCount(); | |
| 1021 delegate_->AddNewContents(this, new_contents, disposition, initial_pos, | |
| 1022 user_gesture); | |
| 1023 NotificationService::current()->Notify( | |
| 1024 NotificationType::TAB_ADDED, | |
| 1025 Source<TabContentsDelegate>(delegate_), | |
| 1026 Details<TabContents>(this)); | |
| 1027 } | |
| 1028 | |
| 1029 // TODO(pkasting): Why is this necessary? | |
| 1030 PopupNotificationVisibilityChanged(blocked_contents_ != NULL); | |
| 1031 } | |
| 1032 | |
| 1033 bool TabContents::ExecuteCode(int request_id, const std::string& extension_id, | |
| 1034 bool is_js_code, const std::string& code_string, | |
| 1035 bool all_frames) { | |
| 1036 RenderViewHost* host = render_view_host(); | |
| 1037 if (!host) | |
| 1038 return false; | |
| 1039 | |
| 1040 return host->Send(new ViewMsg_ExecuteCode(host->routing_id(), | |
| 1041 ViewMsg_ExecuteCode_Params(request_id, extension_id, | |
| 1042 is_js_code, code_string, all_frames))); | |
| 1043 } | |
| 1044 | |
| 1045 void TabContents::PopupNotificationVisibilityChanged(bool visible) { | |
| 1046 if (is_being_destroyed_) | |
| 1047 return; | |
| 1048 content_settings_delegate_->SetPopupsBlocked(visible); | |
| 1049 if (!dont_notify_render_view_) | |
| 1050 render_view_host()->AllowScriptToClose(!visible); | |
| 1051 } | |
| 1052 | |
| 1053 gfx::NativeView TabContents::GetContentNativeView() const { | |
| 1054 return view_->GetContentNativeView(); | |
| 1055 } | |
| 1056 | |
| 1057 gfx::NativeView TabContents::GetNativeView() const { | |
| 1058 return view_->GetNativeView(); | |
| 1059 } | |
| 1060 | |
| 1061 void TabContents::GetContainerBounds(gfx::Rect *out) const { | |
| 1062 view_->GetContainerBounds(out); | |
| 1063 } | |
| 1064 | |
| 1065 void TabContents::Focus() { | |
| 1066 view_->Focus(); | |
| 1067 } | |
| 1068 | |
| 1069 void TabContents::FocusThroughTabTraversal(bool reverse) { | |
| 1070 if (showing_interstitial_page()) { | |
| 1071 render_manager_.interstitial_page()->FocusThroughTabTraversal(reverse); | |
| 1072 return; | |
| 1073 } | |
| 1074 render_view_host()->SetInitialFocus(reverse); | |
| 1075 } | |
| 1076 | |
| 1077 bool TabContents::FocusLocationBarByDefault() { | |
| 1078 WebUI* web_ui = GetWebUIForCurrentState(); | |
| 1079 if (web_ui) | |
| 1080 return web_ui->focus_location_bar_by_default(); | |
| 1081 NavigationEntry* entry = controller_.GetActiveEntry(); | |
| 1082 if (entry && entry->url() == GURL(chrome::kAboutBlankURL)) | |
| 1083 return true; | |
| 1084 return false; | |
| 1085 } | |
| 1086 | |
| 1087 void TabContents::SetFocusToLocationBar(bool select_all) { | |
| 1088 if (delegate()) | |
| 1089 delegate()->SetFocusToLocationBar(select_all); | |
| 1090 } | |
| 1091 | |
| 1092 void TabContents::AddInfoBar(InfoBarDelegate* delegate) { | |
| 1093 if (delegate_ && !delegate_->infobars_enabled()) { | |
| 1094 delegate->InfoBarClosed(); | |
| 1095 return; | |
| 1096 } | |
| 1097 | |
| 1098 // Look through the existing InfoBarDelegates we have for a match. If we've | |
| 1099 // already got one that matches, then we don't add the new one. | |
| 1100 for (size_t i = 0; i < infobar_count(); ++i) { | |
| 1101 if (GetInfoBarDelegateAt(i)->EqualsDelegate(delegate)) { | |
| 1102 // Tell the new infobar to close so that it can clean itself up. | |
| 1103 delegate->InfoBarClosed(); | |
| 1104 return; | |
| 1105 } | |
| 1106 } | |
| 1107 | |
| 1108 infobar_delegates_.push_back(delegate); | |
| 1109 NotificationService::current()->Notify( | |
| 1110 NotificationType::TAB_CONTENTS_INFOBAR_ADDED, Source<TabContents>(this), | |
| 1111 Details<InfoBarDelegate>(delegate)); | |
| 1112 | |
| 1113 // Add ourselves as an observer for navigations the first time a delegate is | |
| 1114 // added. We use this notification to expire InfoBars that need to expire on | |
| 1115 // page transitions. | |
| 1116 if (infobar_delegates_.size() == 1) { | |
| 1117 registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, | |
| 1118 Source<NavigationController>(&controller_)); | |
| 1119 } | |
| 1120 } | |
| 1121 | |
| 1122 void TabContents::RemoveInfoBar(InfoBarDelegate* delegate) { | |
| 1123 if (delegate_ && !delegate_->infobars_enabled()) { | |
| 1124 return; | |
| 1125 } | |
| 1126 | |
| 1127 std::vector<InfoBarDelegate*>::iterator it = | |
| 1128 find(infobar_delegates_.begin(), infobar_delegates_.end(), delegate); | |
| 1129 if (it != infobar_delegates_.end()) { | |
| 1130 InfoBarDelegate* delegate = *it; | |
| 1131 NotificationService::current()->Notify( | |
| 1132 NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, | |
| 1133 Source<TabContents>(this), | |
| 1134 Details<InfoBarDelegate>(delegate)); | |
| 1135 | |
| 1136 infobar_delegates_.erase(it); | |
| 1137 // Remove ourselves as an observer if we are tracking no more InfoBars. | |
| 1138 if (infobar_delegates_.empty()) { | |
| 1139 registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED, | |
| 1140 Source<NavigationController>(&controller_)); | |
| 1141 } | |
| 1142 } | |
| 1143 } | |
| 1144 | |
| 1145 void TabContents::ReplaceInfoBar(InfoBarDelegate* old_delegate, | |
| 1146 InfoBarDelegate* new_delegate) { | |
| 1147 if (delegate_ && !delegate_->infobars_enabled()) { | |
| 1148 new_delegate->InfoBarClosed(); | |
| 1149 return; | |
| 1150 } | |
| 1151 | |
| 1152 std::vector<InfoBarDelegate*>::iterator it = | |
| 1153 find(infobar_delegates_.begin(), infobar_delegates_.end(), old_delegate); | |
| 1154 DCHECK(it != infobar_delegates_.end()); | |
| 1155 | |
| 1156 // Notify the container about the change of plans. | |
| 1157 scoped_ptr<std::pair<InfoBarDelegate*, InfoBarDelegate*> > details( | |
| 1158 new std::pair<InfoBarDelegate*, InfoBarDelegate*>( | |
| 1159 old_delegate, new_delegate)); | |
| 1160 NotificationService::current()->Notify( | |
| 1161 NotificationType::TAB_CONTENTS_INFOBAR_REPLACED, | |
| 1162 Source<TabContents>(this), | |
| 1163 Details<std::pair<InfoBarDelegate*, InfoBarDelegate*> >(details.get())); | |
| 1164 | |
| 1165 // Remove the old one. | |
| 1166 infobar_delegates_.erase(it); | |
| 1167 | |
| 1168 // Add the new one. | |
| 1169 DCHECK(find(infobar_delegates_.begin(), | |
| 1170 infobar_delegates_.end(), new_delegate) == | |
| 1171 infobar_delegates_.end()); | |
| 1172 infobar_delegates_.push_back(new_delegate); | |
| 1173 } | |
| 1174 | |
| 1175 bool TabContents::ShouldShowBookmarkBar() { | |
| 1176 if (showing_interstitial_page()) | |
| 1177 return false; | |
| 1178 | |
| 1179 // Do not show bookmarks bar if bookmarks aren't enabled. | |
| 1180 if (!browser_defaults::bookmarks_enabled) | |
| 1181 return false; | |
| 1182 | |
| 1183 // See GetWebUIForCurrentState() comment for more info. This case is very | |
| 1184 // similar, but for non-first loads, we want to use the committed entry. This | |
| 1185 // is so the bookmarks bar disappears at the same time the page does. | |
| 1186 if (controller_.GetLastCommittedEntry()) { | |
| 1187 // Not the first load, always use the committed Web UI. | |
| 1188 return (render_manager_.web_ui() == NULL) ? | |
| 1189 false : render_manager_.web_ui()->force_bookmark_bar_visible(); | |
| 1190 } | |
| 1191 | |
| 1192 // When it's the first load, we know either the pending one or the committed | |
| 1193 // one will have the Web UI in it (see GetWebUIForCurrentState), and only one | |
| 1194 // of them will be valid, so we can just check both. | |
| 1195 if (render_manager_.pending_web_ui()) | |
| 1196 return render_manager_.pending_web_ui()->force_bookmark_bar_visible(); | |
| 1197 return (render_manager_.web_ui() == NULL) ? | |
| 1198 false : render_manager_.web_ui()->force_bookmark_bar_visible(); | |
| 1199 } | |
| 1200 | |
| 1201 void TabContents::ToolbarSizeChanged(bool is_animating) { | |
| 1202 TabContentsDelegate* d = delegate(); | |
| 1203 if (d) | |
| 1204 d->ToolbarSizeChanged(this, is_animating); | |
| 1205 } | |
| 1206 | |
| 1207 bool TabContents::CanDownload(int request_id) { | |
| 1208 TabContentsDelegate* d = delegate(); | |
| 1209 if (d) | |
| 1210 return d->CanDownload(request_id); | |
| 1211 return true; | |
| 1212 } | |
| 1213 | |
| 1214 void TabContents::OnStartDownload(DownloadItem* download) { | |
| 1215 DCHECK(download); | |
| 1216 | |
| 1217 // Download in a constrained popup is shown in the tab that opened it. | |
| 1218 TabContents* tab_contents = delegate()->GetConstrainingContents(this); | |
| 1219 | |
| 1220 if (tab_contents && tab_contents->delegate()) | |
| 1221 tab_contents->delegate()->OnStartDownload(download, this); | |
| 1222 } | |
| 1223 | |
| 1224 void TabContents::WillClose(ConstrainedWindow* window) { | |
| 1225 ConstrainedWindowList::iterator i( | |
| 1226 std::find(child_windows_.begin(), child_windows_.end(), window)); | |
| 1227 bool removed_topmost_window = i == child_windows_.begin(); | |
| 1228 if (i != child_windows_.end()) | |
| 1229 child_windows_.erase(i); | |
| 1230 if (child_windows_.empty()) { | |
| 1231 BlockTabContent(false); | |
| 1232 } else { | |
| 1233 if (removed_topmost_window) | |
| 1234 child_windows_[0]->ShowConstrainedWindow(); | |
| 1235 BlockTabContent(true); | |
| 1236 } | |
| 1237 } | |
| 1238 | |
| 1239 void TabContents::WillCloseBlockedContentContainer( | |
| 1240 BlockedContentContainer* container) { | |
| 1241 DCHECK(blocked_contents_ == container); | |
| 1242 blocked_contents_ = NULL; | |
| 1243 PopupNotificationVisibilityChanged(false); | |
| 1244 } | |
| 1245 | |
| 1246 void TabContents::DidMoveOrResize(ConstrainedWindow* window) { | |
| 1247 #if defined(OS_WIN) | |
| 1248 UpdateWindow(GetNativeView()); | |
| 1249 #endif | |
| 1250 } | |
| 1251 | |
| 1252 void TabContents::OnSavePage() { | |
| 1253 // If we can not save the page, try to download it. | |
| 1254 if (!SavePackage::IsSavableContents(contents_mime_type())) { | |
| 1255 DownloadManager* dlm = profile()->GetDownloadManager(); | |
| 1256 const GURL& current_page_url = GetURL(); | |
| 1257 if (dlm && current_page_url.is_valid()) | |
| 1258 dlm->DownloadUrl(current_page_url, GURL(), "", this); | |
| 1259 return; | |
| 1260 } | |
| 1261 | |
| 1262 Stop(); | |
| 1263 | |
| 1264 // Create the save package and possibly prompt the user for the name to save | |
| 1265 // the page as. The user prompt is an asynchronous operation that runs on | |
| 1266 // another thread. | |
| 1267 save_package_ = new SavePackage(this); | |
| 1268 save_package_->GetSaveInfo(); | |
| 1269 } | |
| 1270 | |
| 1271 // Used in automated testing to bypass prompting the user for file names. | |
| 1272 // Instead, the names and paths are hard coded rather than running them through | |
| 1273 // file name sanitation and extension / mime checking. | |
| 1274 bool TabContents::SavePage(const FilePath& main_file, const FilePath& dir_path, | |
| 1275 SavePackage::SavePackageType save_type) { | |
| 1276 // Stop the page from navigating. | |
| 1277 Stop(); | |
| 1278 | |
| 1279 save_package_ = new SavePackage(this, save_type, main_file, dir_path); | |
| 1280 return save_package_->Init(); | |
| 1281 } | |
| 1282 | |
| 1283 void TabContents::EmailPageLocation() { | |
| 1284 std::string title = EscapeQueryParamValue(UTF16ToUTF8(GetTitle()), false); | |
| 1285 std::string page_url = EscapeQueryParamValue(GetURL().spec(), false); | |
| 1286 std::string mailto = std::string("mailto:?subject=Fwd:%20") + | |
| 1287 title + "&body=%0A%0A" + page_url; | |
| 1288 platform_util::OpenExternal(GURL(mailto)); | |
| 1289 } | |
| 1290 | |
| 1291 void TabContents::PrintPreview() { | |
| 1292 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 1293 switches::kEnablePrintPreview)) { | |
| 1294 if (showing_interstitial_page()) | |
| 1295 return; | |
| 1296 | |
| 1297 printing::PrintPreviewTabController* tab_controller = | |
| 1298 printing::PrintPreviewTabController::GetInstance(); | |
| 1299 if (!tab_controller) | |
| 1300 return; | |
| 1301 tab_controller->GetOrCreatePreviewTab(this, controller().window_id().id()); | |
| 1302 | |
| 1303 render_view_host()->PrintPreview(); | |
| 1304 } else { | |
| 1305 PrintNow(); | |
| 1306 } | |
| 1307 } | |
| 1308 | |
| 1309 bool TabContents::PrintNow() { | |
| 1310 // We can't print interstitial page for now. | |
| 1311 if (showing_interstitial_page()) | |
| 1312 return false; | |
| 1313 | |
| 1314 return render_view_host()->PrintPages(); | |
| 1315 } | |
| 1316 | |
| 1317 void TabContents::PrintingDone(int document_cookie, bool success) { | |
| 1318 render_view_host()->PrintingDone(document_cookie, success); | |
| 1319 } | |
| 1320 | |
| 1321 bool TabContents::IsActiveEntry(int32 page_id) { | |
| 1322 NavigationEntry* active_entry = controller_.GetActiveEntry(); | |
| 1323 return (active_entry != NULL && | |
| 1324 active_entry->site_instance() == GetSiteInstance() && | |
| 1325 active_entry->page_id() == page_id); | |
| 1326 } | |
| 1327 | |
| 1328 void TabContents::SetOverrideEncoding(const std::string& encoding) { | |
| 1329 set_encoding(encoding); | |
| 1330 render_view_host()->SetPageEncoding(encoding); | |
| 1331 } | |
| 1332 | |
| 1333 void TabContents::ResetOverrideEncoding() { | |
| 1334 reset_encoding(); | |
| 1335 render_view_host()->ResetPageEncodingToDefault(); | |
| 1336 } | |
| 1337 | |
| 1338 void TabContents::WindowMoveOrResizeStarted() { | |
| 1339 render_view_host()->WindowMoveOrResizeStarted(); | |
| 1340 } | |
| 1341 | |
| 1342 void TabContents::SetAllContentsBlocked(bool value) { | |
| 1343 if (all_contents_blocked_ == value) | |
| 1344 return; | |
| 1345 | |
| 1346 all_contents_blocked_ = value; | |
| 1347 if (!all_contents_blocked_ && blocked_contents_) { | |
| 1348 std::vector<TabContents*> blocked; | |
| 1349 blocked_contents_->GetBlockedContents(&blocked); | |
| 1350 for (size_t i = 0; i < blocked.size(); ++i) | |
| 1351 blocked_contents_->LaunchForContents(blocked[i]); | |
| 1352 } | |
| 1353 } | |
| 1354 | |
| 1355 void TabContents::LogNewTabTime(const std::string& event_name) { | |
| 1356 // Not all new tab pages get timed. In those cases, we don't have a | |
| 1357 // new_tab_start_time_. | |
| 1358 if (new_tab_start_time_.is_null()) | |
| 1359 return; | |
| 1360 | |
| 1361 base::TimeDelta duration = base::TimeTicks::Now() - new_tab_start_time_; | |
| 1362 MetricEventDurationDetails details(event_name, | |
| 1363 static_cast<int>(duration.InMilliseconds())); | |
| 1364 | |
| 1365 if (event_name == "Tab.NewTabScriptStart") { | |
| 1366 UMA_HISTOGRAM_TIMES("Tab.NewTabScriptStart", duration); | |
| 1367 } else if (event_name == "Tab.NewTabDOMContentLoaded") { | |
| 1368 UMA_HISTOGRAM_TIMES("Tab.NewTabDOMContentLoaded", duration); | |
| 1369 } else if (event_name == "Tab.NewTabOnload") { | |
| 1370 UMA_HISTOGRAM_TIMES("Tab.NewTabOnload", duration); | |
| 1371 // The new tab page has finished loading; reset it. | |
| 1372 new_tab_start_time_ = base::TimeTicks(); | |
| 1373 } else { | |
| 1374 NOTREACHED(); | |
| 1375 } | |
| 1376 NotificationService::current()->Notify( | |
| 1377 NotificationType::METRIC_EVENT_DURATION, | |
| 1378 Source<TabContents>(this), | |
| 1379 Details<MetricEventDurationDetails>(&details)); | |
| 1380 } | |
| 1381 | |
| 1382 void TabContents::OnCloseStarted() { | |
| 1383 if (tab_close_start_time_.is_null()) | |
| 1384 tab_close_start_time_ = base::TimeTicks::Now(); | |
| 1385 } | |
| 1386 | |
| 1387 bool TabContents::ShouldAcceptDragAndDrop() const { | |
| 1388 #if defined(OS_CHROMEOS) | |
| 1389 // ChromeOS panels (pop-ups) do not take drag-n-drop. | |
| 1390 // See http://crosbug.com/2413 | |
| 1391 if (delegate() && delegate()->IsPopup(this)) | |
| 1392 return false; | |
| 1393 return true; | |
| 1394 #else | |
| 1395 return true; | |
| 1396 #endif | |
| 1397 } | |
| 1398 | |
| 1399 void TabContents::SystemDragEnded() { | |
| 1400 if (render_view_host()) | |
| 1401 render_view_host()->DragSourceSystemDragEnded(); | |
| 1402 if (delegate()) | |
| 1403 delegate()->DragEnded(); | |
| 1404 } | |
| 1405 | |
| 1406 void TabContents::UpdateHistoryForNavigation( | |
| 1407 scoped_refptr<history::HistoryAddPageArgs> add_page_args) { | |
| 1408 if (profile()->IsOffTheRecord()) | |
| 1409 return; | |
| 1410 | |
| 1411 // Add to history service. | |
| 1412 HistoryService* hs = profile()->GetHistoryService(Profile::IMPLICIT_ACCESS); | |
| 1413 if (hs) | |
| 1414 hs->AddPage(*add_page_args); | |
| 1415 } | |
| 1416 | |
| 1417 void TabContents::UpdateHistoryPageTitle(const NavigationEntry& entry) { | |
| 1418 if (profile()->IsOffTheRecord()) | |
| 1419 return; | |
| 1420 | |
| 1421 HistoryService* hs = profile()->GetHistoryService(Profile::IMPLICIT_ACCESS); | |
| 1422 if (hs) | |
| 1423 hs->SetPageTitle(entry.virtual_url(), entry.title()); | |
| 1424 } | |
| 1425 | |
| 1426 double TabContents::GetZoomLevel() const { | |
| 1427 HostZoomMap* zoom_map = profile()->GetHostZoomMap(); | |
| 1428 if (!zoom_map) | |
| 1429 return 0; | |
| 1430 | |
| 1431 double zoom_level; | |
| 1432 if (temporary_zoom_settings_) { | |
| 1433 zoom_level = zoom_map->GetTemporaryZoomLevel( | |
| 1434 GetRenderProcessHost()->id(), render_view_host()->routing_id()); | |
| 1435 } else { | |
| 1436 zoom_level = zoom_map->GetZoomLevel(GetURL()); | |
| 1437 } | |
| 1438 return zoom_level; | |
| 1439 } | |
| 1440 | |
| 1441 int TabContents::GetZoomPercent(bool* enable_increment, | |
| 1442 bool* enable_decrement) { | |
| 1443 *enable_decrement = *enable_increment = false; | |
| 1444 int percent = static_cast<int>( | |
| 1445 WebKit::WebView::zoomLevelToZoomFactor(GetZoomLevel()) * 100); | |
| 1446 *enable_decrement = percent > minimum_zoom_percent_; | |
| 1447 *enable_increment = percent < maximum_zoom_percent_; | |
| 1448 return percent; | |
| 1449 } | |
| 1450 | |
| 1451 void TabContents::ViewSource() { | |
| 1452 if (!delegate_) | |
| 1453 return; | |
| 1454 | |
| 1455 NavigationEntry* active_entry = controller().GetActiveEntry(); | |
| 1456 if (!active_entry) | |
| 1457 return; | |
| 1458 | |
| 1459 delegate_->ViewSourceForTab(this, active_entry->url()); | |
| 1460 } | |
| 1461 | |
| 1462 void TabContents::OnDidStartProvisionalLoadForFrame(int64 frame_id, | |
| 1463 bool is_main_frame, | |
| 1464 const GURL& url) { | |
| 1465 bool is_error_page = (url.spec() == chrome::kUnreachableWebDataURL); | |
| 1466 GURL validated_url(url); | |
| 1467 render_view_host()->FilterURL(ChildProcessSecurityPolicy::GetInstance(), | |
| 1468 GetRenderProcessHost()->id(), &validated_url); | |
| 1469 | |
| 1470 ProvisionalLoadDetails details( | |
| 1471 is_main_frame, | |
| 1472 controller_.IsURLInPageNavigation(validated_url), | |
| 1473 validated_url, std::string(), false, is_error_page, frame_id); | |
| 1474 NotificationService::current()->Notify( | |
| 1475 NotificationType::FRAME_PROVISIONAL_LOAD_START, | |
| 1476 Source<NavigationController>(&controller_), | |
| 1477 Details<ProvisionalLoadDetails>(&details)); | |
| 1478 if (is_main_frame) { | |
| 1479 // If we're displaying a network error page do not reset the content | |
| 1480 // settings delegate's cookies so the user has a chance to modify cookie | |
| 1481 // settings. | |
| 1482 if (!is_error_page) | |
| 1483 content_settings_delegate_->ClearCookieSpecificContentSettings(); | |
| 1484 content_settings_delegate_->ClearGeolocationContentSettings(); | |
| 1485 | |
| 1486 // Check if the URL we are about to load has been prerendered by any chance, | |
| 1487 // and use it if possible. | |
| 1488 MaybeUsePreloadedPage(url); | |
| 1489 } | |
| 1490 } | |
| 1491 | |
| 1492 void TabContents::OnDidRedirectProvisionalLoad(int32 page_id, | |
| 1493 const GURL& source_url, | |
| 1494 const GURL& target_url) { | |
| 1495 NavigationEntry* entry; | |
| 1496 if (page_id == -1) | |
| 1497 entry = controller_.pending_entry(); | |
| 1498 else | |
| 1499 entry = controller_.GetEntryWithPageID(GetSiteInstance(), page_id); | |
| 1500 if (!entry || entry->url() != source_url) | |
| 1501 return; | |
| 1502 entry->set_url(target_url); | |
| 1503 | |
| 1504 // Check if the URL we are about to load has been prerendered by any chance, | |
| 1505 // and use it if possible. | |
| 1506 MaybeUsePreloadedPage(target_url); | |
| 1507 } | |
| 1508 | |
| 1509 void TabContents::OnDidFailProvisionalLoadWithError( | |
| 1510 int64 frame_id, | |
| 1511 bool is_main_frame, | |
| 1512 int error_code, | |
| 1513 const GURL& url, | |
| 1514 bool showing_repost_interstitial) { | |
| 1515 VLOG(1) << "Failed Provisional Load: " << url.possibly_invalid_spec() | |
| 1516 << ", error_code: " << error_code | |
| 1517 << " is_main_frame: " << is_main_frame | |
| 1518 << " showing_repost_interstitial: " << showing_repost_interstitial | |
| 1519 << " frame_id: " << frame_id; | |
| 1520 GURL validated_url(url); | |
| 1521 render_view_host()->FilterURL(ChildProcessSecurityPolicy::GetInstance(), | |
| 1522 GetRenderProcessHost()->id(), &validated_url); | |
| 1523 | |
| 1524 if (net::ERR_ABORTED == error_code) { | |
| 1525 // EVIL HACK ALERT! Ignore failed loads when we're showing interstitials. | |
| 1526 // This means that the interstitial won't be torn down properly, which is | |
| 1527 // bad. But if we have an interstitial, go back to another tab type, and | |
| 1528 // then load the same interstitial again, we could end up getting the first | |
| 1529 // interstitial's "failed" message (as a result of the cancel) when we're on | |
| 1530 // the second one. | |
| 1531 // | |
| 1532 // We can't tell this apart, so we think we're tearing down the current page | |
| 1533 // which will cause a crash later one. There is also some code in | |
| 1534 // RenderViewHostManager::RendererAbortedProvisionalLoad that is commented | |
| 1535 // out because of this problem. | |
| 1536 // | |
| 1537 // http://code.google.com/p/chromium/issues/detail?id=2855 | |
| 1538 // Because this will not tear down the interstitial properly, if "back" is | |
| 1539 // back to another tab type, the interstitial will still be somewhat alive | |
| 1540 // in the previous tab type. If you navigate somewhere that activates the | |
| 1541 // tab with the interstitial again, you'll see a flash before the new load | |
| 1542 // commits of the interstitial page. | |
| 1543 if (showing_interstitial_page()) { | |
| 1544 LOG(WARNING) << "Discarding message during interstitial."; | |
| 1545 return; | |
| 1546 } | |
| 1547 | |
| 1548 // This will discard our pending entry if we cancelled the load (e.g., if we | |
| 1549 // decided to download the file instead of load it). Only discard the | |
| 1550 // pending entry if the URLs match, otherwise the user initiated a navigate | |
| 1551 // before the page loaded so that the discard would discard the wrong entry. | |
| 1552 NavigationEntry* pending_entry = controller_.pending_entry(); | |
| 1553 if (pending_entry && pending_entry->url() == validated_url) { | |
| 1554 controller_.DiscardNonCommittedEntries(); | |
| 1555 // Update the URL display. | |
| 1556 NotifyNavigationStateChanged(TabContents::INVALIDATE_URL); | |
| 1557 } | |
| 1558 | |
| 1559 render_manager_.RendererAbortedProvisionalLoad(render_view_host()); | |
| 1560 } | |
| 1561 | |
| 1562 // Send out a notification that we failed a provisional load with an error. | |
| 1563 ProvisionalLoadDetails details( | |
| 1564 is_main_frame, controller_.IsURLInPageNavigation(validated_url), | |
| 1565 validated_url, std::string(), false, false, frame_id); | |
| 1566 details.set_error_code(error_code); | |
| 1567 | |
| 1568 NotificationService::current()->Notify( | |
| 1569 NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR, | |
| 1570 Source<NavigationController>(&controller_), | |
| 1571 Details<ProvisionalLoadDetails>(&details)); | |
| 1572 } | |
| 1573 | |
| 1574 void TabContents::OnDidLoadResourceFromMemoryCache( | |
| 1575 const GURL& url, | |
| 1576 const std::string& security_info) { | |
| 1577 static base::StatsCounter cache("WebKit.CacheHit"); | |
| 1578 cache.Increment(); | |
| 1579 | |
| 1580 // Send out a notification that we loaded a resource from our memory cache. | |
| 1581 int cert_id = 0, cert_status = 0, security_bits = -1, connection_status = 0; | |
| 1582 SSLManager::DeserializeSecurityInfo(security_info, | |
| 1583 &cert_id, &cert_status, | |
| 1584 &security_bits, | |
| 1585 &connection_status); | |
| 1586 LoadFromMemoryCacheDetails details(url, GetRenderProcessHost()->id(), | |
| 1587 cert_id, cert_status); | |
| 1588 | |
| 1589 NotificationService::current()->Notify( | |
| 1590 NotificationType::LOAD_FROM_MEMORY_CACHE, | |
| 1591 Source<NavigationController>(&controller_), | |
| 1592 Details<LoadFromMemoryCacheDetails>(&details)); | |
| 1593 } | |
| 1594 | |
| 1595 void TabContents::OnDidDisplayInsecureContent() { | |
| 1596 displayed_insecure_content_ = true; | |
| 1597 SSLManager::NotifySSLInternalStateChanged(); | |
| 1598 } | |
| 1599 | |
| 1600 void TabContents::OnDidRunInsecureContent( | |
| 1601 const std::string& security_origin, const GURL& target_url) { | |
| 1602 LOG(INFO) << security_origin << " ran insecure content from " | |
| 1603 << target_url.possibly_invalid_spec(); | |
| 1604 controller_.ssl_manager()->DidRunInsecureContent(security_origin); | |
| 1605 } | |
| 1606 | |
| 1607 void TabContents::OnDocumentLoadedInFrame(int64 frame_id) { | |
| 1608 controller_.DocumentLoadedInFrame(); | |
| 1609 NotificationService::current()->Notify( | |
| 1610 NotificationType::FRAME_DOM_CONTENT_LOADED, | |
| 1611 Source<NavigationController>(&controller_), | |
| 1612 Details<int64>(&frame_id)); | |
| 1613 } | |
| 1614 | |
| 1615 void TabContents::OnDidFinishLoad(int64 frame_id) { | |
| 1616 NotificationService::current()->Notify( | |
| 1617 NotificationType::FRAME_DID_FINISH_LOAD, | |
| 1618 Source<NavigationController>(&controller_), | |
| 1619 Details<int64>(&frame_id)); | |
| 1620 } | |
| 1621 | |
| 1622 void TabContents::OnUpdateContentRestrictions(int restrictions) { | |
| 1623 content_restrictions_ = restrictions; | |
| 1624 delegate()->ContentRestrictionsChanged(this); | |
| 1625 } | |
| 1626 | |
| 1627 void TabContents::OnPDFHasUnsupportedFeature() { | |
| 1628 PDFHasUnsupportedFeature(this); | |
| 1629 } | |
| 1630 | |
| 1631 // Notifies the RenderWidgetHost instance about the fact that the page is | |
| 1632 // loading, or done loading and calls the base implementation. | |
| 1633 void TabContents::SetIsLoading(bool is_loading, | |
| 1634 LoadNotificationDetails* details) { | |
| 1635 if (is_loading == is_loading_) | |
| 1636 return; | |
| 1637 | |
| 1638 if (!is_loading) { | |
| 1639 load_state_ = net::LOAD_STATE_IDLE; | |
| 1640 load_state_host_.clear(); | |
| 1641 upload_size_ = 0; | |
| 1642 upload_position_ = 0; | |
| 1643 } | |
| 1644 | |
| 1645 render_manager_.SetIsLoading(is_loading); | |
| 1646 | |
| 1647 is_loading_ = is_loading; | |
| 1648 waiting_for_response_ = is_loading; | |
| 1649 | |
| 1650 if (delegate_) | |
| 1651 delegate_->LoadingStateChanged(this); | |
| 1652 NotifyNavigationStateChanged(INVALIDATE_LOAD); | |
| 1653 | |
| 1654 NotificationType type = is_loading ? NotificationType::LOAD_START : | |
| 1655 NotificationType::LOAD_STOP; | |
| 1656 NotificationDetails det = NotificationService::NoDetails(); | |
| 1657 if (details) | |
| 1658 det = Details<LoadNotificationDetails>(details); | |
| 1659 NotificationService::current()->Notify(type, | |
| 1660 Source<NavigationController>(&controller_), | |
| 1661 det); | |
| 1662 } | |
| 1663 | |
| 1664 void TabContents::AddPopup(TabContents* new_contents, | |
| 1665 const gfx::Rect& initial_pos) { | |
| 1666 // A page can't spawn popups (or do anything else, either) until its load | |
| 1667 // commits, so when we reach here, the popup was spawned by the | |
| 1668 // NavigationController's last committed entry, not the active entry. For | |
| 1669 // example, if a page opens a popup in an onunload() handler, then the active | |
| 1670 // entry is the page to be loaded as we navigate away from the unloading | |
| 1671 // page. For this reason, we can't use GetURL() to get the opener URL, | |
| 1672 // because it returns the active entry. | |
| 1673 NavigationEntry* entry = controller_.GetLastCommittedEntry(); | |
| 1674 GURL creator = entry ? entry->virtual_url() : GURL::EmptyGURL(); | |
| 1675 | |
| 1676 if (creator.is_valid() && | |
| 1677 profile()->GetHostContentSettingsMap()->GetContentSetting( | |
| 1678 creator, CONTENT_SETTINGS_TYPE_POPUPS, "") == CONTENT_SETTING_ALLOW) { | |
| 1679 AddNewContents(new_contents, NEW_POPUP, initial_pos, true); | |
| 1680 } else { | |
| 1681 if (!blocked_contents_) | |
| 1682 blocked_contents_ = new BlockedContentContainer(this); | |
| 1683 blocked_contents_->AddTabContents(new_contents, NEW_POPUP, initial_pos, | |
| 1684 true); | |
| 1685 content_settings_delegate_->OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS, | |
| 1686 std::string()); | |
| 1687 } | |
| 1688 } | |
| 1689 | |
| 1690 void TabContents::ExpireInfoBars( | |
| 1691 const NavigationController::LoadCommittedDetails& details) { | |
| 1692 // Only hide InfoBars when the user has done something that makes the main | |
| 1693 // frame load. We don't want various automatic or subframe navigations making | |
| 1694 // it disappear. | |
| 1695 if (!details.is_user_initiated_main_frame_load()) | |
| 1696 return; | |
| 1697 | |
| 1698 // NOTE: It is not safe to change the following code to count upwards or use | |
| 1699 // iterators, as the RemoveInfoBar() call synchronously modifies our delegate | |
| 1700 // list. | |
| 1701 for (size_t i = infobar_count(); i > 0; --i) { | |
| 1702 InfoBarDelegate* delegate = GetInfoBarDelegateAt(i - 1); | |
| 1703 if (delegate->ShouldExpire(details)) | |
| 1704 RemoveInfoBar(delegate); | |
| 1705 } | |
| 1706 } | |
| 1707 | |
| 1708 WebUI* TabContents::GetWebUIForCurrentState() { | |
| 1709 // When there is a pending navigation entry, we want to use the pending WebUI | |
| 1710 // that goes along with it to control the basic flags. For example, we want to | |
| 1711 // show the pending URL in the URL bar, so we want the display_url flag to | |
| 1712 // be from the pending entry. | |
| 1713 // | |
| 1714 // The confusion comes because there are multiple possibilities for the | |
| 1715 // initial load in a tab as a side effect of the way the RenderViewHostManager | |
| 1716 // works. | |
| 1717 // | |
| 1718 // - For the very first tab the load looks "normal". The new tab Web UI is | |
| 1719 // the pending one, and we want it to apply here. | |
| 1720 // | |
| 1721 // - For subsequent new tabs, they'll get a new SiteInstance which will then | |
| 1722 // get switched to the one previously associated with the new tab pages. | |
| 1723 // This switching will cause the manager to commit the RVH/WebUI. So we'll | |
| 1724 // have a committed Web UI in this case. | |
| 1725 // | |
| 1726 // This condition handles all of these cases: | |
| 1727 // | |
| 1728 // - First load in first tab: no committed nav entry + pending nav entry + | |
| 1729 // pending dom ui: | |
| 1730 // -> Use pending Web UI if any. | |
| 1731 // | |
| 1732 // - First load in second tab: no committed nav entry + pending nav entry + | |
| 1733 // no pending Web UI: | |
| 1734 // -> Use the committed Web UI if any. | |
| 1735 // | |
| 1736 // - Second navigation in any tab: committed nav entry + pending nav entry: | |
| 1737 // -> Use pending Web UI if any. | |
| 1738 // | |
| 1739 // - Normal state with no load: committed nav entry + no pending nav entry: | |
| 1740 // -> Use committed Web UI. | |
| 1741 if (controller_.pending_entry() && | |
| 1742 (controller_.GetLastCommittedEntry() || | |
| 1743 render_manager_.pending_web_ui())) | |
| 1744 return render_manager_.pending_web_ui(); | |
| 1745 return render_manager_.web_ui(); | |
| 1746 } | |
| 1747 | |
| 1748 void TabContents::DidNavigateMainFramePostCommit( | |
| 1749 const NavigationController::LoadCommittedDetails& details, | |
| 1750 const ViewHostMsg_FrameNavigate_Params& params) { | |
| 1751 if (opener_web_ui_type_ != WebUIFactory::kNoWebUI) { | |
| 1752 // If this is a window.open navigation, use the same WebUI as the renderer | |
| 1753 // that opened the window, as long as both renderers have the same | |
| 1754 // privileges. | |
| 1755 if (opener_web_ui_type_ == | |
| 1756 WebUIFactory::GetWebUIType(profile(), GetURL())) { | |
| 1757 WebUI* web_ui = WebUIFactory::CreateWebUIForURL(this, GetURL()); | |
| 1758 // web_ui might be NULL if the URL refers to a non-existent extension. | |
| 1759 if (web_ui) { | |
| 1760 render_manager_.SetWebUIPostCommit(web_ui); | |
| 1761 web_ui->RenderViewCreated(render_view_host()); | |
| 1762 } | |
| 1763 } | |
| 1764 opener_web_ui_type_ = WebUIFactory::kNoWebUI; | |
| 1765 } | |
| 1766 | |
| 1767 if (details.is_user_initiated_main_frame_load()) { | |
| 1768 // Clear the status bubble. This is a workaround for a bug where WebKit | |
| 1769 // doesn't let us know that the cursor left an element during a | |
| 1770 // transition (this is also why the mouse cursor remains as a hand after | |
| 1771 // clicking on a link); see bugs 1184641 and 980803. We don't want to | |
| 1772 // clear the bubble when a user navigates to a named anchor in the same | |
| 1773 // page. | |
| 1774 UpdateTargetURL(details.entry->page_id(), GURL()); | |
| 1775 } | |
| 1776 | |
| 1777 // Allow the new page to set the title again. | |
| 1778 received_page_title_ = false; | |
| 1779 | |
| 1780 // Get the favicon, either from history or request it from the net. | |
| 1781 fav_icon_helper_->FetchFavIcon(details.entry->url()); | |
| 1782 | |
| 1783 // Clear all page actions, blocked content notifications and browser actions | |
| 1784 // for this tab, unless this is an in-page navigation. | |
| 1785 if (!details.is_in_page) { | |
| 1786 ExtensionService* service = profile()->GetExtensionService(); | |
| 1787 if (service) { | |
| 1788 for (size_t i = 0; i < service->extensions()->size(); ++i) { | |
| 1789 ExtensionAction* browser_action = | |
| 1790 service->extensions()->at(i)->browser_action(); | |
| 1791 if (browser_action) { | |
| 1792 browser_action->ClearAllValuesForTab(controller().session_id().id()); | |
| 1793 NotificationService::current()->Notify( | |
| 1794 NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, | |
| 1795 Source<ExtensionAction>(browser_action), | |
| 1796 NotificationService::NoDetails()); | |
| 1797 } | |
| 1798 | |
| 1799 ExtensionAction* page_action = | |
| 1800 service->extensions()->at(i)->page_action(); | |
| 1801 if (page_action) { | |
| 1802 page_action->ClearAllValuesForTab(controller().session_id().id()); | |
| 1803 PageActionStateChanged(); | |
| 1804 } | |
| 1805 } | |
| 1806 } | |
| 1807 | |
| 1808 // Close blocked popups. | |
| 1809 if (blocked_contents_) { | |
| 1810 AutoReset<bool> auto_reset(&dont_notify_render_view_, true); | |
| 1811 blocked_contents_->Destroy(); | |
| 1812 blocked_contents_ = NULL; | |
| 1813 } | |
| 1814 | |
| 1815 // Clear "blocked" flags. | |
| 1816 content_settings_delegate_->ClearBlockedContentSettingsExceptForCookies(); | |
| 1817 content_settings_delegate_->GeolocationDidNavigate(details); | |
| 1818 | |
| 1819 // Once the main frame is navigated, we're no longer considered to have | |
| 1820 // displayed insecure content. | |
| 1821 displayed_insecure_content_ = false; | |
| 1822 } | |
| 1823 | |
| 1824 // Close constrained windows if necessary. | |
| 1825 if (!net::RegistryControlledDomainService::SameDomainOrHost( | |
| 1826 details.previous_url, details.entry->url())) | |
| 1827 CloseConstrainedWindows(); | |
| 1828 | |
| 1829 // Notify observers about navigation. | |
| 1830 FOR_EACH_OBSERVER(TabContentsObserver, observers_, | |
| 1831 DidNavigateMainFramePostCommit(details, params)); | |
| 1832 } | |
| 1833 | |
| 1834 void TabContents::DidNavigateAnyFramePostCommit( | |
| 1835 RenderViewHost* render_view_host, | |
| 1836 const NavigationController::LoadCommittedDetails& details, | |
| 1837 const ViewHostMsg_FrameNavigate_Params& params) { | |
| 1838 // If we navigate, start showing messages again. This does nothing to prevent | |
| 1839 // a malicious script from spamming messages, since the script could just | |
| 1840 // reload the page to stop blocking. | |
| 1841 suppress_javascript_messages_ = false; | |
| 1842 | |
| 1843 // Notify observers about navigation. | |
| 1844 FOR_EACH_OBSERVER(TabContentsObserver, observers_, | |
| 1845 DidNavigateAnyFramePostCommit(details, params)); | |
| 1846 | |
| 1847 // Let the LanguageState clear its state. | |
| 1848 language_state_.DidNavigate(details); | |
| 1849 } | |
| 1850 | |
| 1851 void TabContents::CloseConstrainedWindows() { | |
| 1852 // Clear out any constrained windows since we are leaving this page entirely. | |
| 1853 // We use indices instead of iterators in case CloseWindow does something | |
| 1854 // that may invalidate an iterator. | |
| 1855 for (size_t i = 0; i < child_windows_.size(); ++i) { | |
| 1856 ConstrainedWindow* window = child_windows_[child_windows_.size() - 1 - i]; | |
| 1857 if (window) { | |
| 1858 window->CloseConstrainedWindow(); | |
| 1859 BlockTabContent(false); | |
| 1860 } | |
| 1861 } | |
| 1862 } | |
| 1863 | |
| 1864 void TabContents::UpdateAlternateErrorPageURL() { | |
| 1865 GURL url = GetAlternateErrorPageURL(); | |
| 1866 render_view_host()->SetAlternateErrorPageURL(url); | |
| 1867 } | |
| 1868 | |
| 1869 void TabContents::UpdateWebPreferences() { | |
| 1870 render_view_host()->UpdateWebPreferences(GetWebkitPrefs()); | |
| 1871 } | |
| 1872 | |
| 1873 void TabContents::UpdateZoomLevel() { | |
| 1874 render_view_host()->SetZoomLevel(GetZoomLevel()); | |
| 1875 } | |
| 1876 | |
| 1877 void TabContents::UpdateMaxPageIDIfNecessary(SiteInstance* site_instance, | |
| 1878 RenderViewHost* rvh) { | |
| 1879 // If we are creating a RVH for a restored controller, then we might | |
| 1880 // have more page IDs than the SiteInstance's current max page ID. We must | |
| 1881 // make sure that the max page ID is larger than any restored page ID. | |
| 1882 // Note that it is ok for conflicting page IDs to exist in another tab | |
| 1883 // (i.e., NavigationController), but if any page ID is larger than the max, | |
| 1884 // the back/forward list will get confused. | |
| 1885 int max_restored_page_id = controller_.max_restored_page_id(); | |
| 1886 if (max_restored_page_id > 0) { | |
| 1887 int curr_max_page_id = site_instance->max_page_id(); | |
| 1888 if (max_restored_page_id > curr_max_page_id) { | |
| 1889 // Need to update the site instance immediately. | |
| 1890 site_instance->UpdateMaxPageID(max_restored_page_id); | |
| 1891 | |
| 1892 // Also tell the renderer to update its internal representation. We | |
| 1893 // need to reserve enough IDs to make all restored page IDs less than | |
| 1894 // the max. | |
| 1895 if (curr_max_page_id < 0) | |
| 1896 curr_max_page_id = 0; | |
| 1897 rvh->ReservePageIDRange(max_restored_page_id - curr_max_page_id); | |
| 1898 } | |
| 1899 } | |
| 1900 } | |
| 1901 | |
| 1902 scoped_refptr<history::HistoryAddPageArgs> | |
| 1903 TabContents::CreateHistoryAddPageArgs( | |
| 1904 const GURL& virtual_url, | |
| 1905 const NavigationController::LoadCommittedDetails& details, | |
| 1906 const ViewHostMsg_FrameNavigate_Params& params) { | |
| 1907 scoped_refptr<history::HistoryAddPageArgs> add_page_args( | |
| 1908 new history::HistoryAddPageArgs( | |
| 1909 params.url, base::Time::Now(), this, params.page_id, params.referrer, | |
| 1910 params.redirects, params.transition, history::SOURCE_BROWSED, | |
| 1911 details.did_replace_entry)); | |
| 1912 if (PageTransition::IsMainFrame(params.transition) && | |
| 1913 virtual_url != params.url) { | |
| 1914 // Hack on the "virtual" URL so that it will appear in history. For some | |
| 1915 // types of URLs, we will display a magic URL that is different from where | |
| 1916 // the page is actually navigated. We want the user to see in history what | |
| 1917 // they saw in the URL bar, so we add the virtual URL as a redirect. This | |
| 1918 // only applies to the main frame, as the virtual URL doesn't apply to | |
| 1919 // sub-frames. | |
| 1920 add_page_args->url = virtual_url; | |
| 1921 if (!add_page_args->redirects.empty()) | |
| 1922 add_page_args->redirects.back() = virtual_url; | |
| 1923 } | |
| 1924 return add_page_args; | |
| 1925 } | |
| 1926 | |
| 1927 bool TabContents::UpdateTitleForEntry(NavigationEntry* entry, | |
| 1928 const std::wstring& title) { | |
| 1929 // For file URLs without a title, use the pathname instead. In the case of a | |
| 1930 // synthesized title, we don't want the update to count toward the "one set | |
| 1931 // per page of the title to history." | |
| 1932 string16 final_title; | |
| 1933 bool explicit_set; | |
| 1934 if (entry->url().SchemeIsFile() && title.empty()) { | |
| 1935 final_title = UTF8ToUTF16(entry->url().ExtractFileName()); | |
| 1936 explicit_set = false; // Don't count synthetic titles toward the set limit. | |
| 1937 } else { | |
| 1938 TrimWhitespace(WideToUTF16Hack(title), TRIM_ALL, &final_title); | |
| 1939 explicit_set = true; | |
| 1940 } | |
| 1941 | |
| 1942 if (final_title == entry->title()) | |
| 1943 return false; // Nothing changed, don't bother. | |
| 1944 | |
| 1945 entry->set_title(final_title); | |
| 1946 | |
| 1947 if (!received_page_title_) { | |
| 1948 UpdateHistoryPageTitle(*entry); | |
| 1949 received_page_title_ = explicit_set; | |
| 1950 } | |
| 1951 | |
| 1952 // Lastly, set the title for the view. | |
| 1953 view_->SetPageTitle(UTF16ToWideHack(final_title)); | |
| 1954 | |
| 1955 NotificationService::current()->Notify( | |
| 1956 NotificationType::TAB_CONTENTS_TITLE_UPDATED, | |
| 1957 Source<TabContents>(this), | |
| 1958 NotificationService::NoDetails()); | |
| 1959 | |
| 1960 return true; | |
| 1961 } | |
| 1962 | |
| 1963 void TabContents::NotifySwapped() { | |
| 1964 // After sending out a swap notification, we need to send a disconnect | |
| 1965 // notification so that clients that pick up a pointer to |this| can NULL the | |
| 1966 // pointer. See Bug 1230284. | |
| 1967 notify_disconnection_ = true; | |
| 1968 NotificationService::current()->Notify( | |
| 1969 NotificationType::TAB_CONTENTS_SWAPPED, | |
| 1970 Source<TabContents>(this), | |
| 1971 NotificationService::NoDetails()); | |
| 1972 } | |
| 1973 | |
| 1974 void TabContents::NotifyConnected() { | |
| 1975 notify_disconnection_ = true; | |
| 1976 NotificationService::current()->Notify( | |
| 1977 NotificationType::TAB_CONTENTS_CONNECTED, | |
| 1978 Source<TabContents>(this), | |
| 1979 NotificationService::NoDetails()); | |
| 1980 } | |
| 1981 | |
| 1982 void TabContents::NotifyDisconnected() { | |
| 1983 if (!notify_disconnection_) | |
| 1984 return; | |
| 1985 | |
| 1986 notify_disconnection_ = false; | |
| 1987 NotificationService::current()->Notify( | |
| 1988 NotificationType::TAB_CONTENTS_DISCONNECTED, | |
| 1989 Source<TabContents>(this), | |
| 1990 NotificationService::NoDetails()); | |
| 1991 } | |
| 1992 | |
| 1993 void TabContents::OnGoToEntryAtOffset(int offset) { | |
| 1994 if (!delegate_ || delegate_->OnGoToEntryOffset(offset)) { | |
| 1995 NavigationEntry* entry = controller_.GetEntryAtOffset(offset); | |
| 1996 if (!entry) | |
| 1997 return; | |
| 1998 // Note that we don't call NavigationController::GotToOffset() as we don't | |
| 1999 // want to create a pending navigation entry (it might end up lingering | |
| 2000 // http://crbug.com/51680). | |
| 2001 entry->set_transition_type(entry->transition_type() | | |
| 2002 PageTransition::FORWARD_BACK); | |
| 2003 NavigateToEntry(*entry, NavigationController::NO_RELOAD); | |
| 2004 } | |
| 2005 } | |
| 2006 | |
| 2007 void TabContents::OnDidGetApplicationInfo(int32 page_id, | |
| 2008 const WebApplicationInfo& info) { | |
| 2009 web_app_info_ = info; | |
| 2010 | |
| 2011 if (delegate()) | |
| 2012 delegate()->OnDidGetApplicationInfo(this, page_id); | |
| 2013 } | |
| 2014 | |
| 2015 void TabContents::OnInstallApplication(const WebApplicationInfo& info) { | |
| 2016 if (delegate()) | |
| 2017 delegate()->OnInstallApplication(this, info); | |
| 2018 } | |
| 2019 | |
| 2020 void TabContents::OnPageContents(const GURL& url, | |
| 2021 int32 page_id, | |
| 2022 const string16& contents, | |
| 2023 const std::string& language, | |
| 2024 bool page_translatable) { | |
| 2025 // Don't index any https pages. People generally don't want their bank | |
| 2026 // accounts, etc. indexed on their computer, especially since some of these | |
| 2027 // things are not marked cachable. | |
| 2028 // TODO(brettw) we may want to consider more elaborate heuristics such as | |
| 2029 // the cachability of the page. We may also want to consider subframes (this | |
| 2030 // test will still index subframes if the subframe is SSL). | |
| 2031 // TODO(zelidrag) bug chromium-os:2808 - figure out if we want to reenable | |
| 2032 // content indexing for chromeos in some future releases. | |
| 2033 #if !defined(OS_CHROMEOS) | |
| 2034 if (!url.SchemeIsSecure()) { | |
| 2035 Profile* p = profile(); | |
| 2036 if (p && !p->IsOffTheRecord()) { | |
| 2037 HistoryService* hs = p->GetHistoryService(Profile::IMPLICIT_ACCESS); | |
| 2038 if (hs) | |
| 2039 hs->SetPageContents(url, contents); | |
| 2040 } | |
| 2041 } | |
| 2042 #endif | |
| 2043 | |
| 2044 language_state_.LanguageDetermined(language, page_translatable); | |
| 2045 | |
| 2046 std::string lang = language; | |
| 2047 NotificationService::current()->Notify( | |
| 2048 NotificationType::TAB_LANGUAGE_DETERMINED, | |
| 2049 Source<TabContents>(this), | |
| 2050 Details<std::string>(&lang)); | |
| 2051 | |
| 2052 // Generate the thumbnail here if the in-browser thumbnailing is enabled. | |
| 2053 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 2054 switches::kEnableInBrowserThumbnailing)) { | |
| 2055 ThumbnailGenerator::UpdateThumbnailIfNecessary(this, url); | |
| 2056 } | |
| 2057 } | |
| 2058 | |
| 2059 void TabContents::OnPageTranslated(int32 page_id, | |
| 2060 const std::string& original_lang, | |
| 2061 const std::string& translated_lang, | |
| 2062 TranslateErrors::Type error_type) { | |
| 2063 language_state_.set_current_language(translated_lang); | |
| 2064 language_state_.set_translation_pending(false); | |
| 2065 PageTranslatedDetails details(original_lang, translated_lang, error_type); | |
| 2066 NotificationService::current()->Notify( | |
| 2067 NotificationType::PAGE_TRANSLATED, | |
| 2068 Source<TabContents>(this), | |
| 2069 Details<PageTranslatedDetails>(&details)); | |
| 2070 } | |
| 2071 | |
| 2072 void TabContents::OnSetSuggestions( | |
| 2073 int32 page_id, | |
| 2074 const std::vector<std::string>& suggestions) { | |
| 2075 if (delegate()) | |
| 2076 delegate()->OnSetSuggestions(page_id, suggestions); | |
| 2077 } | |
| 2078 | |
| 2079 void TabContents::OnInstantSupportDetermined(int32 page_id, bool result) { | |
| 2080 if (delegate()) | |
| 2081 delegate()->OnInstantSupportDetermined(page_id, result); | |
| 2082 } | |
| 2083 | |
| 2084 void TabContents::OnRunFileChooser( | |
| 2085 const ViewHostMsg_RunFileChooser_Params& params) { | |
| 2086 if (file_select_helper_.get() == NULL) | |
| 2087 file_select_helper_.reset(new FileSelectHelper(profile())); | |
| 2088 file_select_helper_->RunFileChooser(render_view_host(), params); | |
| 2089 } | |
| 2090 | |
| 2091 | |
| 2092 void TabContents::OnContentSettingsAccessed(bool content_was_blocked) { | |
| 2093 if (delegate_) | |
| 2094 delegate_->OnContentSettingsChange(this); | |
| 2095 } | |
| 2096 | |
| 2097 RenderViewHostDelegate::View* TabContents::GetViewDelegate() { | |
| 2098 return view_.get(); | |
| 2099 } | |
| 2100 | |
| 2101 RenderViewHostDelegate::RendererManagement* | |
| 2102 TabContents::GetRendererManagementDelegate() { | |
| 2103 return &render_manager_; | |
| 2104 } | |
| 2105 | |
| 2106 RenderViewHostDelegate::ContentSettings* | |
| 2107 TabContents::GetContentSettingsDelegate() { | |
| 2108 return content_settings_delegate_.get(); | |
| 2109 } | |
| 2110 | |
| 2111 RenderViewHostDelegate::SSL* TabContents::GetSSLDelegate() { | |
| 2112 return GetSSLHelper(); | |
| 2113 } | |
| 2114 | |
| 2115 AutomationResourceRoutingDelegate* | |
| 2116 TabContents::GetAutomationResourceRoutingDelegate() { | |
| 2117 return delegate(); | |
| 2118 } | |
| 2119 | |
| 2120 RenderViewHostDelegate::BookmarkDrag* TabContents::GetBookmarkDragDelegate() { | |
| 2121 return bookmark_drag_; | |
| 2122 } | |
| 2123 | |
| 2124 void TabContents::SetBookmarkDragDelegate( | |
| 2125 RenderViewHostDelegate::BookmarkDrag* bookmark_drag) { | |
| 2126 bookmark_drag_ = bookmark_drag; | |
| 2127 } | |
| 2128 | |
| 2129 TabSpecificContentSettings* TabContents::GetTabSpecificContentSettings() const { | |
| 2130 return content_settings_delegate_.get(); | |
| 2131 } | |
| 2132 | |
| 2133 RendererPreferences TabContents::GetRendererPrefs(Profile* profile) const { | |
| 2134 return renderer_preferences_; | |
| 2135 } | |
| 2136 | |
| 2137 TabContents* TabContents::GetAsTabContents() { | |
| 2138 return this; | |
| 2139 } | |
| 2140 | |
| 2141 ViewType::Type TabContents::GetRenderViewType() const { | |
| 2142 return ViewType::TAB_CONTENTS; | |
| 2143 } | |
| 2144 | |
| 2145 int TabContents::GetBrowserWindowID() const { | |
| 2146 return controller().window_id().id(); | |
| 2147 } | |
| 2148 | |
| 2149 void TabContents::RenderViewCreated(RenderViewHost* render_view_host) { | |
| 2150 NotificationService::current()->Notify( | |
| 2151 NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB, | |
| 2152 Source<TabContents>(this), | |
| 2153 Details<RenderViewHost>(render_view_host)); | |
| 2154 NavigationEntry* entry = controller_.GetActiveEntry(); | |
| 2155 if (!entry) | |
| 2156 return; | |
| 2157 | |
| 2158 // When we're creating views, we're still doing initial setup, so we always | |
| 2159 // use the pending Web UI rather than any possibly existing committed one. | |
| 2160 if (render_manager_.pending_web_ui()) { | |
| 2161 render_manager_.pending_web_ui()->RenderViewCreated(render_view_host); | |
| 2162 } | |
| 2163 | |
| 2164 if (entry->IsViewSourceMode()) { | |
| 2165 // Put the renderer in view source mode. | |
| 2166 render_view_host->Send( | |
| 2167 new ViewMsg_EnableViewSourceMode(render_view_host->routing_id())); | |
| 2168 } | |
| 2169 | |
| 2170 view()->RenderViewCreated(render_view_host); | |
| 2171 } | |
| 2172 | |
| 2173 void TabContents::RenderViewReady(RenderViewHost* rvh) { | |
| 2174 if (rvh != render_view_host()) { | |
| 2175 // Don't notify the world, since this came from a renderer in the | |
| 2176 // background. | |
| 2177 return; | |
| 2178 } | |
| 2179 | |
| 2180 NotifyConnected(); | |
| 2181 bool was_crashed = is_crashed(); | |
| 2182 SetIsCrashed(base::TERMINATION_STATUS_STILL_RUNNING, 0); | |
| 2183 | |
| 2184 // Restore the focus to the tab (otherwise the focus will be on the top | |
| 2185 // window). | |
| 2186 if (was_crashed && !FocusLocationBarByDefault() && | |
| 2187 (!delegate_ || delegate_->ShouldFocusPageAfterCrash())) { | |
| 2188 Focus(); | |
| 2189 } | |
| 2190 } | |
| 2191 | |
| 2192 void TabContents::RenderViewGone(RenderViewHost* rvh, | |
| 2193 base::TerminationStatus status, | |
| 2194 int error_code) { | |
| 2195 // Ask the print preview if this renderer was valuable. | |
| 2196 if (!printing_->OnRenderViewGone(rvh)) | |
| 2197 return; | |
| 2198 if (rvh != render_view_host()) { | |
| 2199 // The pending page's RenderViewHost is gone. | |
| 2200 return; | |
| 2201 } | |
| 2202 | |
| 2203 SetIsLoading(false, NULL); | |
| 2204 NotifyDisconnected(); | |
| 2205 SetIsCrashed(status, error_code); | |
| 2206 | |
| 2207 // Remove all infobars. | |
| 2208 while (!infobar_delegates_.empty()) | |
| 2209 RemoveInfoBar(GetInfoBarDelegateAt(infobar_count() - 1)); | |
| 2210 | |
| 2211 // Tell the view that we've crashed so it can prepare the sad tab page. | |
| 2212 // Only do this if we're not in browser shutdown, so that TabContents | |
| 2213 // objects that are not in a browser (e.g., HTML dialogs) and thus are | |
| 2214 // visible do not flash a sad tab page. | |
| 2215 if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID) | |
| 2216 view_->OnTabCrashed(status, error_code); | |
| 2217 | |
| 2218 // Hide any visible hung renderer warning for this web contents' process. | |
| 2219 hung_renderer_dialog::HideForTabContents(this); | |
| 2220 } | |
| 2221 | |
| 2222 void TabContents::RenderViewDeleted(RenderViewHost* rvh) { | |
| 2223 NotificationService::current()->Notify( | |
| 2224 NotificationType::RENDER_VIEW_HOST_DELETED, | |
| 2225 Source<TabContents>(this), | |
| 2226 Details<RenderViewHost>(rvh)); | |
| 2227 render_manager_.RenderViewDeleted(rvh); | |
| 2228 } | |
| 2229 | |
| 2230 void TabContents::DidNavigate(RenderViewHost* rvh, | |
| 2231 const ViewHostMsg_FrameNavigate_Params& params) { | |
| 2232 int extra_invalidate_flags = 0; | |
| 2233 | |
| 2234 if (PageTransition::IsMainFrame(params.transition)) { | |
| 2235 if (MaybeUsePreloadedPage(params.url)) { | |
| 2236 return; | |
| 2237 } | |
| 2238 | |
| 2239 bool was_bookmark_bar_visible = ShouldShowBookmarkBar(); | |
| 2240 | |
| 2241 render_manager_.DidNavigateMainFrame(rvh); | |
| 2242 | |
| 2243 if (was_bookmark_bar_visible != ShouldShowBookmarkBar()) | |
| 2244 extra_invalidate_flags |= INVALIDATE_BOOKMARK_BAR; | |
| 2245 } | |
| 2246 | |
| 2247 // Update the site of the SiteInstance if it doesn't have one yet. | |
| 2248 if (!GetSiteInstance()->has_site()) | |
| 2249 GetSiteInstance()->SetSite(params.url); | |
| 2250 | |
| 2251 // Need to update MIME type here because it's referred to in | |
| 2252 // UpdateNavigationCommands() called by RendererDidNavigate() to | |
| 2253 // determine whether or not to enable the encoding menu. | |
| 2254 // It's updated only for the main frame. For a subframe, | |
| 2255 // RenderView::UpdateURL does not set params.contents_mime_type. | |
| 2256 // (see http://code.google.com/p/chromium/issues/detail?id=2929 ) | |
| 2257 // TODO(jungshik): Add a test for the encoding menu to avoid | |
| 2258 // regressing it again. | |
| 2259 if (PageTransition::IsMainFrame(params.transition)) | |
| 2260 contents_mime_type_ = params.contents_mime_type; | |
| 2261 | |
| 2262 NavigationController::LoadCommittedDetails details; | |
| 2263 bool did_navigate = controller_.RendererDidNavigate( | |
| 2264 params, extra_invalidate_flags, &details); | |
| 2265 | |
| 2266 // Send notification about committed provisional loads. This notification is | |
| 2267 // different from the NAV_ENTRY_COMMITTED notification which doesn't include | |
| 2268 // the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations. | |
| 2269 if (details.type != NavigationType::NAV_IGNORE) { | |
| 2270 // For AUTO_SUBFRAME navigations, an event for the main frame is generated | |
| 2271 // that is not recorded in the navigation history. For the purpose of | |
| 2272 // tracking navigation events, we treat this event as a sub frame navigation | |
| 2273 // event. | |
| 2274 bool is_main_frame = did_navigate ? details.is_main_frame : false; | |
| 2275 ProvisionalLoadDetails load_details( | |
| 2276 is_main_frame, details.is_in_page, params.url, std::string(), false, | |
| 2277 false, params.frame_id); | |
| 2278 load_details.set_transition_type(params.transition); | |
| 2279 // Whether or not a page transition was triggered by going backward or | |
| 2280 // forward in the history is only stored in the navigation controller's | |
| 2281 // entry list. | |
| 2282 if (did_navigate && | |
| 2283 (controller_.GetActiveEntry()->transition_type() & | |
| 2284 PageTransition::FORWARD_BACK)) { | |
| 2285 load_details.set_transition_type( | |
| 2286 params.transition | PageTransition::FORWARD_BACK); | |
| 2287 } | |
| 2288 NotificationService::current()->Notify( | |
| 2289 NotificationType::FRAME_PROVISIONAL_LOAD_COMMITTED, | |
| 2290 Source<NavigationController>(&controller_), | |
| 2291 Details<ProvisionalLoadDetails>(&load_details)); | |
| 2292 } | |
| 2293 | |
| 2294 // Update history. Note that this needs to happen after the entry is complete, | |
| 2295 // which WillNavigate[Main,Sub]Frame will do before this function is called. | |
| 2296 if (params.should_update_history) { | |
| 2297 // Most of the time, the displayURL matches the loaded URL, but for about: | |
| 2298 // URLs, we use a data: URL as the real value. We actually want to save the | |
| 2299 // about: URL to the history db and keep the data: URL hidden. This is what | |
| 2300 // the TabContents' URL getter does. | |
| 2301 scoped_refptr<history::HistoryAddPageArgs> add_page_args( | |
| 2302 CreateHistoryAddPageArgs(GetURL(), details, params)); | |
| 2303 if (!delegate() || | |
| 2304 delegate()->ShouldAddNavigationToHistory(*add_page_args, | |
| 2305 details.type)) { | |
| 2306 UpdateHistoryForNavigation(add_page_args); | |
| 2307 } | |
| 2308 } | |
| 2309 | |
| 2310 if (!did_navigate) | |
| 2311 return; // No navigation happened. | |
| 2312 | |
| 2313 // DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen | |
| 2314 // for the appropriate notification (best) or you can add it to | |
| 2315 // DidNavigateMainFramePostCommit / DidNavigateAnyFramePostCommit (only if | |
| 2316 // necessary, please). | |
| 2317 | |
| 2318 // Run post-commit tasks. | |
| 2319 if (details.is_main_frame) | |
| 2320 DidNavigateMainFramePostCommit(details, params); | |
| 2321 DidNavigateAnyFramePostCommit(rvh, details, params); | |
| 2322 } | |
| 2323 | |
| 2324 void TabContents::UpdateState(RenderViewHost* rvh, | |
| 2325 int32 page_id, | |
| 2326 const std::string& state) { | |
| 2327 DCHECK(rvh == render_view_host()); | |
| 2328 | |
| 2329 // We must be prepared to handle state updates for any page, these occur | |
| 2330 // when the user is scrolling and entering form data, as well as when we're | |
| 2331 // leaving a page, in which case our state may have already been moved to | |
| 2332 // the next page. The navigation controller will look up the appropriate | |
| 2333 // NavigationEntry and update it when it is notified via the delegate. | |
| 2334 | |
| 2335 int entry_index = controller_.GetEntryIndexWithPageID( | |
| 2336 GetSiteInstance(), page_id); | |
| 2337 if (entry_index < 0) | |
| 2338 return; | |
| 2339 NavigationEntry* entry = controller_.GetEntryAtIndex(entry_index); | |
| 2340 | |
| 2341 if (state == entry->content_state()) | |
| 2342 return; // Nothing to update. | |
| 2343 entry->set_content_state(state); | |
| 2344 controller_.NotifyEntryChanged(entry, entry_index); | |
| 2345 } | |
| 2346 | |
| 2347 void TabContents::UpdateTitle(RenderViewHost* rvh, | |
| 2348 int32 page_id, const std::wstring& title) { | |
| 2349 // If we have a title, that's a pretty good indication that we've started | |
| 2350 // getting useful data. | |
| 2351 SetNotWaitingForResponse(); | |
| 2352 | |
| 2353 DCHECK(rvh == render_view_host()); | |
| 2354 NavigationEntry* entry = controller_.GetEntryWithPageID(rvh->site_instance(), | |
| 2355 page_id); | |
| 2356 if (!entry || !UpdateTitleForEntry(entry, title)) | |
| 2357 return; | |
| 2358 | |
| 2359 // Broadcast notifications when the UI should be updated. | |
| 2360 if (entry == controller_.GetEntryAtOffset(0)) | |
| 2361 NotifyNavigationStateChanged(INVALIDATE_TITLE); | |
| 2362 } | |
| 2363 | |
| 2364 void TabContents::UpdateEncoding(RenderViewHost* render_view_host, | |
| 2365 const std::string& encoding) { | |
| 2366 set_encoding(encoding); | |
| 2367 } | |
| 2368 | |
| 2369 void TabContents::UpdateTargetURL(int32 page_id, const GURL& url) { | |
| 2370 if (delegate()) | |
| 2371 delegate()->UpdateTargetURL(this, url); | |
| 2372 } | |
| 2373 | |
| 2374 void TabContents::UpdateThumbnail(const GURL& url, | |
| 2375 const SkBitmap& bitmap, | |
| 2376 const ThumbnailScore& score) { | |
| 2377 if (profile()->IsOffTheRecord()) | |
| 2378 return; | |
| 2379 | |
| 2380 // Tell History about this thumbnail | |
| 2381 history::TopSites* ts = profile()->GetTopSites(); | |
| 2382 if (ts) | |
| 2383 ts->SetPageThumbnail(url, bitmap, score); | |
| 2384 } | |
| 2385 | |
| 2386 void TabContents::UpdateInspectorSetting(const std::string& key, | |
| 2387 const std::string& value) { | |
| 2388 RenderViewHostDelegateHelper::UpdateInspectorSetting(profile(), key, value); | |
| 2389 } | |
| 2390 | |
| 2391 void TabContents::ClearInspectorSettings() { | |
| 2392 RenderViewHostDelegateHelper::ClearInspectorSettings(profile()); | |
| 2393 } | |
| 2394 | |
| 2395 void TabContents::Close(RenderViewHost* rvh) { | |
| 2396 // The UI may be in an event-tracking loop, such as between the | |
| 2397 // mouse-down and mouse-up in text selection or a button click. | |
| 2398 // Defer the close until after tracking is complete, so that we | |
| 2399 // don't free objects out from under the UI. | |
| 2400 // TODO(shess): This could probably be integrated with the | |
| 2401 // IsDoingDrag() test below. Punting for now because I need more | |
| 2402 // research to understand how this impacts platforms other than Mac. | |
| 2403 // TODO(shess): This could get more fine-grained. For instance, | |
| 2404 // closing a tab in another window while selecting text in the | |
| 2405 // current window's Omnibox should be just fine. | |
| 2406 if (view()->IsEventTracking()) { | |
| 2407 view()->CloseTabAfterEventTracking(); | |
| 2408 return; | |
| 2409 } | |
| 2410 | |
| 2411 // If we close the tab while we're in the middle of a drag, we'll crash. | |
| 2412 // Instead, cancel the drag and close it as soon as the drag ends. | |
| 2413 if (view()->IsDoingDrag()) { | |
| 2414 view()->CancelDragAndCloseTab(); | |
| 2415 return; | |
| 2416 } | |
| 2417 | |
| 2418 // Ignore this if it comes from a RenderViewHost that we aren't showing. | |
| 2419 if (delegate() && rvh == render_view_host()) | |
| 2420 delegate()->CloseContents(this); | |
| 2421 } | |
| 2422 | |
| 2423 void TabContents::RequestMove(const gfx::Rect& new_bounds) { | |
| 2424 if (delegate() && delegate()->IsPopup(this)) | |
| 2425 delegate()->MoveContents(this, new_bounds); | |
| 2426 } | |
| 2427 | |
| 2428 void TabContents::DidStartLoading() { | |
| 2429 SetIsLoading(true, NULL); | |
| 2430 | |
| 2431 if (delegate()) { | |
| 2432 bool is_print_preview_tab = | |
| 2433 printing::PrintPreviewTabController::IsPrintPreviewTab(this); | |
| 2434 if (content_restrictions_ || is_print_preview_tab) { | |
| 2435 content_restrictions_= is_print_preview_tab ? | |
| 2436 CONTENT_RESTRICTION_PRINT : 0; | |
| 2437 delegate()->ContentRestrictionsChanged(this); | |
| 2438 } | |
| 2439 } | |
| 2440 | |
| 2441 // Notify observers about navigation. | |
| 2442 FOR_EACH_OBSERVER(TabContentsObserver, observers_, DidStartLoading()); | |
| 2443 } | |
| 2444 | |
| 2445 void TabContents::DidStopLoading() { | |
| 2446 scoped_ptr<LoadNotificationDetails> details; | |
| 2447 | |
| 2448 NavigationEntry* entry = controller_.GetActiveEntry(); | |
| 2449 // An entry may not exist for a stop when loading an initial blank page or | |
| 2450 // if an iframe injected by script into a blank page finishes loading. | |
| 2451 if (entry) { | |
| 2452 base::TimeDelta elapsed = base::TimeTicks::Now() - current_load_start_; | |
| 2453 | |
| 2454 details.reset(new LoadNotificationDetails( | |
| 2455 entry->virtual_url(), | |
| 2456 entry->transition_type(), | |
| 2457 elapsed, | |
| 2458 &controller_, | |
| 2459 controller_.GetCurrentEntryIndex())); | |
| 2460 } | |
| 2461 | |
| 2462 SetIsLoading(false, details.get()); | |
| 2463 | |
| 2464 // Notify observers about navigation. | |
| 2465 FOR_EACH_OBSERVER(TabContentsObserver, observers_, DidStopLoading()); | |
| 2466 } | |
| 2467 | |
| 2468 void TabContents::DidChangeLoadProgress(double progress) { | |
| 2469 if (delegate()) | |
| 2470 delegate()->LoadProgressChanged(progress); | |
| 2471 } | |
| 2472 | |
| 2473 void TabContents::DocumentOnLoadCompletedInMainFrame( | |
| 2474 RenderViewHost* render_view_host, | |
| 2475 int32 page_id) { | |
| 2476 NotificationService::current()->Notify( | |
| 2477 NotificationType::LOAD_COMPLETED_MAIN_FRAME, | |
| 2478 Source<TabContents>(this), | |
| 2479 Details<int>(&page_id)); | |
| 2480 } | |
| 2481 | |
| 2482 void TabContents::RequestOpenURL(const GURL& url, const GURL& referrer, | |
| 2483 WindowOpenDisposition disposition) { | |
| 2484 if (render_manager_.web_ui()) { | |
| 2485 // When we're a Web UI, it will provide a page transition type for us (this | |
| 2486 // is so the new tab page can specify AUTO_BOOKMARK for automatically | |
| 2487 // generated suggestions). | |
| 2488 // | |
| 2489 // Note also that we hide the referrer for Web UI pages. We don't really | |
| 2490 // want web sites to see a referrer of "chrome://blah" (and some | |
| 2491 // chrome: URLs might have search terms or other stuff we don't want to | |
| 2492 // send to the site), so we send no referrer. | |
| 2493 OpenURL(url, GURL(), disposition, | |
| 2494 render_manager_.web_ui()->link_transition_type()); | |
| 2495 } else { | |
| 2496 OpenURL(url, referrer, disposition, PageTransition::LINK); | |
| 2497 } | |
| 2498 } | |
| 2499 | |
| 2500 void TabContents::DomOperationResponse(const std::string& json_string, | |
| 2501 int automation_id) { | |
| 2502 } | |
| 2503 | |
| 2504 void TabContents::ProcessWebUIMessage( | |
| 2505 const ViewHostMsg_DomMessage_Params& params) { | |
| 2506 if (!render_manager_.web_ui()) { | |
| 2507 // This can happen if someone uses window.open() to open an extension URL | |
| 2508 // from a non-extension context. | |
| 2509 render_view_host()->BlockExtensionRequest(params.request_id); | |
| 2510 return; | |
| 2511 } | |
| 2512 render_manager_.web_ui()->ProcessWebUIMessage(params); | |
| 2513 } | |
| 2514 | |
| 2515 void TabContents::ProcessExternalHostMessage(const std::string& message, | |
| 2516 const std::string& origin, | |
| 2517 const std::string& target) { | |
| 2518 if (delegate()) | |
| 2519 delegate()->ForwardMessageToExternalHost(message, origin, target); | |
| 2520 } | |
| 2521 | |
| 2522 void TabContents::RunJavaScriptMessage( | |
| 2523 const std::wstring& message, | |
| 2524 const std::wstring& default_prompt, | |
| 2525 const GURL& frame_url, | |
| 2526 const int flags, | |
| 2527 IPC::Message* reply_msg, | |
| 2528 bool* did_suppress_message) { | |
| 2529 // Suppress javascript messages when requested and when inside a constrained | |
| 2530 // popup window (because that activates them and breaks them out of the | |
| 2531 // constrained window jail). | |
| 2532 // Also suppress messages when showing an interstitial. The interstitial is | |
| 2533 // shown over the previous page, we don't want the hidden page dialogs to | |
| 2534 // interfere with the interstitial. | |
| 2535 bool suppress_this_message = | |
| 2536 suppress_javascript_messages_ || | |
| 2537 showing_interstitial_page() || | |
| 2538 (delegate() && delegate()->ShouldSuppressDialogs()); | |
| 2539 if (delegate()) | |
| 2540 suppress_this_message |= | |
| 2541 (delegate()->GetConstrainingContents(this) != this); | |
| 2542 | |
| 2543 *did_suppress_message = suppress_this_message; | |
| 2544 | |
| 2545 if (!suppress_this_message) { | |
| 2546 base::TimeDelta time_since_last_message( | |
| 2547 base::TimeTicks::Now() - last_javascript_message_dismissal_); | |
| 2548 bool show_suppress_checkbox = false; | |
| 2549 // Show a checkbox offering to suppress further messages if this message is | |
| 2550 // being displayed within kJavascriptMessageExpectedDelay of the last one. | |
| 2551 if (time_since_last_message < | |
| 2552 base::TimeDelta::FromMilliseconds(kJavascriptMessageExpectedDelay)) | |
| 2553 show_suppress_checkbox = true; | |
| 2554 | |
| 2555 RunJavascriptMessageBox(profile(), this, frame_url, flags, message, | |
| 2556 default_prompt, show_suppress_checkbox, reply_msg); | |
| 2557 } else { | |
| 2558 // If we are suppressing messages, just reply as is if the user immediately | |
| 2559 // pressed "Cancel". | |
| 2560 OnMessageBoxClosed(reply_msg, false, std::wstring()); | |
| 2561 } | |
| 2562 } | |
| 2563 | |
| 2564 void TabContents::RunBeforeUnloadConfirm(const std::wstring& message, | |
| 2565 IPC::Message* reply_msg) { | |
| 2566 if (delegate()) | |
| 2567 delegate()->WillRunBeforeUnloadConfirm(); | |
| 2568 if (delegate() && delegate()->ShouldSuppressDialogs()) { | |
| 2569 render_view_host()->JavaScriptMessageBoxClosed(reply_msg, true, | |
| 2570 std::wstring()); | |
| 2571 return; | |
| 2572 } | |
| 2573 is_showing_before_unload_dialog_ = true; | |
| 2574 RunBeforeUnloadDialog(this, message, reply_msg); | |
| 2575 } | |
| 2576 | |
| 2577 void TabContents::ShowModalHTMLDialog(const GURL& url, int width, int height, | |
| 2578 const std::string& json_arguments, | |
| 2579 IPC::Message* reply_msg) { | |
| 2580 if (delegate()) { | |
| 2581 HtmlDialogUIDelegate* dialog_delegate = | |
| 2582 new ModalHtmlDialogDelegate(url, width, height, json_arguments, | |
| 2583 reply_msg, this); | |
| 2584 delegate()->ShowHtmlDialog(dialog_delegate, NULL); | |
| 2585 } | |
| 2586 } | |
| 2587 | |
| 2588 GURL TabContents::GetAlternateErrorPageURL() const { | |
| 2589 GURL url; | |
| 2590 // Disable alternate error pages when in OffTheRecord/Incognito mode. | |
| 2591 if (profile()->IsOffTheRecord()) | |
| 2592 return url; | |
| 2593 | |
| 2594 PrefService* prefs = profile()->GetPrefs(); | |
| 2595 DCHECK(prefs); | |
| 2596 if (prefs->GetBoolean(prefs::kAlternateErrorPagesEnabled)) { | |
| 2597 url = google_util::AppendGoogleLocaleParam( | |
| 2598 GURL(google_util::kLinkDoctorBaseURL)); | |
| 2599 url = google_util::AppendGoogleTLDParam(url); | |
| 2600 } | |
| 2601 return url; | |
| 2602 } | |
| 2603 | |
| 2604 WebPreferences TabContents::GetWebkitPrefs() { | |
| 2605 Profile* profile = render_view_host()->process()->profile(); | |
| 2606 bool is_web_ui = false; | |
| 2607 WebPreferences web_prefs = | |
| 2608 RenderViewHostDelegateHelper::GetWebkitPrefs(profile, is_web_ui); | |
| 2609 | |
| 2610 // Force accelerated compositing and 2d canvas off for chrome: and | |
| 2611 // chrome-extension: pages. | |
| 2612 if (GetURL().SchemeIs(chrome::kChromeDevToolsScheme) || | |
| 2613 GetURL().SchemeIs(chrome::kChromeUIScheme)) { | |
| 2614 web_prefs.accelerated_compositing_enabled = false; | |
| 2615 web_prefs.accelerated_2d_canvas_enabled = false; | |
| 2616 } | |
| 2617 | |
| 2618 #if defined(OS_MACOSX) | |
| 2619 // Disable accelerated compositing if IOSurface's are not supported, | |
| 2620 // as is the case in 10.5. | |
| 2621 if (!IOSurfaceSupport::Initialize()) | |
| 2622 web_prefs.accelerated_compositing_enabled = false; | |
| 2623 #endif | |
| 2624 | |
| 2625 return web_prefs; | |
| 2626 } | |
| 2627 | |
| 2628 void TabContents::OnUserGesture() { | |
| 2629 // See comment in RenderViewHostDelegate::OnUserGesture as to why we do this. | |
| 2630 DownloadRequestLimiter* limiter = | |
| 2631 g_browser_process->download_request_limiter(); | |
| 2632 if (limiter) | |
| 2633 limiter->OnUserGesture(this); | |
| 2634 ExternalProtocolHandler::PermitLaunchUrl(); | |
| 2635 } | |
| 2636 | |
| 2637 void TabContents::OnIgnoredUIEvent() { | |
| 2638 if (constrained_window_count()) { | |
| 2639 ConstrainedWindow* window = *constrained_window_begin(); | |
| 2640 window->FocusConstrainedWindow(); | |
| 2641 } | |
| 2642 } | |
| 2643 | |
| 2644 void TabContents::OnJSOutOfMemory() { | |
| 2645 AddInfoBar(new SimpleAlertInfoBarDelegate(this, NULL, | |
| 2646 l10n_util::GetStringUTF16(IDS_JS_OUT_OF_MEMORY_PROMPT), true)); | |
| 2647 } | |
| 2648 | |
| 2649 void TabContents::OnCrossSiteResponse(int new_render_process_host_id, | |
| 2650 int new_request_id) { | |
| 2651 // Allows the TabContents to react when a cross-site response is ready to be | |
| 2652 // delivered to a pending RenderViewHost. We must first run the onunload | |
| 2653 // handler of the old RenderViewHost before we can allow it to proceed. | |
| 2654 render_manager_.OnCrossSiteResponse(new_render_process_host_id, | |
| 2655 new_request_id); | |
| 2656 } | |
| 2657 | |
| 2658 void TabContents::RendererUnresponsive(RenderViewHost* rvh, | |
| 2659 bool is_during_unload) { | |
| 2660 if (is_during_unload) { | |
| 2661 // Hang occurred while firing the beforeunload/unload handler. | |
| 2662 // Pretend the handler fired so tab closing continues as if it had. | |
| 2663 rvh->set_sudden_termination_allowed(true); | |
| 2664 | |
| 2665 if (!render_manager_.ShouldCloseTabOnUnresponsiveRenderer()) | |
| 2666 return; | |
| 2667 | |
| 2668 // If the tab hangs in the beforeunload/unload handler there's really | |
| 2669 // nothing we can do to recover. Pretend the unload listeners have | |
| 2670 // all fired and close the tab. If the hang is in the beforeunload handler | |
| 2671 // then the user will not have the option of cancelling the close. | |
| 2672 Close(rvh); | |
| 2673 return; | |
| 2674 } | |
| 2675 | |
| 2676 if (render_view_host() && render_view_host()->IsRenderViewLive() && | |
| 2677 (!delegate() || delegate()->ShouldShowHungRendererDialog())) { | |
| 2678 hung_renderer_dialog::ShowForTabContents(this); | |
| 2679 } | |
| 2680 } | |
| 2681 | |
| 2682 void TabContents::RendererResponsive(RenderViewHost* render_view_host) { | |
| 2683 hung_renderer_dialog::HideForTabContents(this); | |
| 2684 } | |
| 2685 | |
| 2686 void TabContents::LoadStateChanged(const GURL& url, | |
| 2687 net::LoadState load_state, | |
| 2688 uint64 upload_position, | |
| 2689 uint64 upload_size) { | |
| 2690 load_state_ = load_state; | |
| 2691 upload_position_ = upload_position; | |
| 2692 upload_size_ = upload_size; | |
| 2693 std::wstring languages = | |
| 2694 UTF8ToWide(profile()->GetPrefs()->GetString(prefs::kAcceptLanguages)); | |
| 2695 std::string host = url.host(); | |
| 2696 load_state_host_ = WideToUTF16Hack( | |
| 2697 net::IDNToUnicode(host.c_str(), host.size(), languages, NULL)); | |
| 2698 if (load_state_ == net::LOAD_STATE_READING_RESPONSE) | |
| 2699 SetNotWaitingForResponse(); | |
| 2700 if (is_loading()) | |
| 2701 NotifyNavigationStateChanged(INVALIDATE_LOAD | INVALIDATE_TAB); | |
| 2702 } | |
| 2703 | |
| 2704 bool TabContents::IsExternalTabContainer() const { | |
| 2705 if (!delegate()) | |
| 2706 return false; | |
| 2707 | |
| 2708 return delegate()->IsExternalTabContainer(); | |
| 2709 } | |
| 2710 | |
| 2711 void TabContents::DidInsertCSS() { | |
| 2712 // This RVHDelegate function is used for extensions and not us. | |
| 2713 } | |
| 2714 | |
| 2715 void TabContents::FocusedNodeChanged(bool is_editable_node) { | |
| 2716 NotificationService::current()->Notify( | |
| 2717 NotificationType::FOCUS_CHANGED_IN_PAGE, | |
| 2718 Source<TabContents>(this), | |
| 2719 Details<const bool>(&is_editable_node)); | |
| 2720 } | |
| 2721 | |
| 2722 void TabContents::UpdateZoomLimits(int minimum_percent, | |
| 2723 int maximum_percent, | |
| 2724 bool remember) { | |
| 2725 minimum_zoom_percent_ = minimum_percent; | |
| 2726 maximum_zoom_percent_ = maximum_percent; | |
| 2727 temporary_zoom_settings_ = !remember; | |
| 2728 } | |
| 2729 | |
| 2730 void TabContents::WorkerCrashed() { | |
| 2731 AddInfoBar(new SimpleAlertInfoBarDelegate(this, NULL, | |
| 2732 l10n_util::GetStringUTF16(IDS_WEBWORKER_CRASHED_PROMPT), true)); | |
| 2733 } | |
| 2734 | |
| 2735 void TabContents::BeforeUnloadFiredFromRenderManager( | |
| 2736 bool proceed, | |
| 2737 bool* proceed_to_fire_unload) { | |
| 2738 if (delegate()) | |
| 2739 delegate()->BeforeUnloadFired(this, proceed, proceed_to_fire_unload); | |
| 2740 } | |
| 2741 | |
| 2742 void TabContents::DidStartLoadingFromRenderManager( | |
| 2743 RenderViewHost* render_view_host) { | |
| 2744 DidStartLoading(); | |
| 2745 } | |
| 2746 | |
| 2747 void TabContents::RenderViewGoneFromRenderManager( | |
| 2748 RenderViewHost* render_view_host) { | |
| 2749 DCHECK(crashed_status_ != base::TERMINATION_STATUS_STILL_RUNNING); | |
| 2750 RenderViewGone(render_view_host, crashed_status_, crashed_error_code_); | |
| 2751 } | |
| 2752 | |
| 2753 void TabContents::UpdateRenderViewSizeForRenderManager() { | |
| 2754 // TODO(brettw) this is a hack. See TabContentsView::SizeContents. | |
| 2755 gfx::Size size = view_->GetContainerSize(); | |
| 2756 // 0x0 isn't a valid window size (minimal window size is 1x1) but it may be | |
| 2757 // here during container initialization and normal window size will be set | |
| 2758 // later. In case of tab duplication this resizing to 0x0 prevents setting | |
| 2759 // normal size later so just ignore it. | |
| 2760 if (!size.IsEmpty()) | |
| 2761 view_->SizeContents(size); | |
| 2762 } | |
| 2763 | |
| 2764 void TabContents::NotifySwappedFromRenderManager() { | |
| 2765 NotifySwapped(); | |
| 2766 } | |
| 2767 | |
| 2768 NavigationController& TabContents::GetControllerForRenderManager() { | |
| 2769 return controller(); | |
| 2770 } | |
| 2771 | |
| 2772 WebUI* TabContents::CreateWebUIForRenderManager(const GURL& url) { | |
| 2773 return WebUIFactory::CreateWebUIForURL(this, url); | |
| 2774 } | |
| 2775 | |
| 2776 NavigationEntry* | |
| 2777 TabContents::GetLastCommittedNavigationEntryForRenderManager() { | |
| 2778 return controller_.GetLastCommittedEntry(); | |
| 2779 } | |
| 2780 | |
| 2781 bool TabContents::CreateRenderViewForRenderManager( | |
| 2782 RenderViewHost* render_view_host) { | |
| 2783 RenderWidgetHostView* rwh_view = view_->CreateViewForWidget(render_view_host); | |
| 2784 | |
| 2785 if (!render_view_host->CreateRenderView(string16())) | |
| 2786 return false; | |
| 2787 | |
| 2788 // Now that the RenderView has been created, we need to tell it its size. | |
| 2789 rwh_view->SetSize(view_->GetContainerSize()); | |
| 2790 | |
| 2791 UpdateMaxPageIDIfNecessary(render_view_host->site_instance(), | |
| 2792 render_view_host); | |
| 2793 return true; | |
| 2794 } | |
| 2795 | |
| 2796 void TabContents::Observe(NotificationType type, | |
| 2797 const NotificationSource& source, | |
| 2798 const NotificationDetails& details) { | |
| 2799 switch (type.value) { | |
| 2800 case NotificationType::PREF_CHANGED: { | |
| 2801 std::string* pref_name_in = Details<std::string>(details).ptr(); | |
| 2802 DCHECK(Source<PrefService>(source).ptr() == profile()->GetPrefs()); | |
| 2803 if (*pref_name_in == prefs::kAlternateErrorPagesEnabled) { | |
| 2804 UpdateAlternateErrorPageURL(); | |
| 2805 } else if ((*pref_name_in == prefs::kDefaultCharset) || | |
| 2806 StartsWithASCII(*pref_name_in, "webkit.webprefs.", true)) { | |
| 2807 UpdateWebPreferences(); | |
| 2808 } else if (*pref_name_in == prefs::kDefaultZoomLevel) { | |
| 2809 UpdateZoomLevel(); | |
| 2810 } else { | |
| 2811 NOTREACHED() << "unexpected pref change notification" << *pref_name_in; | |
| 2812 } | |
| 2813 break; | |
| 2814 } | |
| 2815 case NotificationType::RENDER_WIDGET_HOST_DESTROYED: | |
| 2816 view_->RenderWidgetHostDestroyed(Source<RenderWidgetHost>(source).ptr()); | |
| 2817 break; | |
| 2818 | |
| 2819 case NotificationType::NAV_ENTRY_COMMITTED: { | |
| 2820 DCHECK(&controller_ == Source<NavigationController>(source).ptr()); | |
| 2821 | |
| 2822 NavigationController::LoadCommittedDetails& committed_details = | |
| 2823 *(Details<NavigationController::LoadCommittedDetails>(details).ptr()); | |
| 2824 ExpireInfoBars(committed_details); | |
| 2825 break; | |
| 2826 } | |
| 2827 | |
| 2828 #if defined(OS_LINUX) | |
| 2829 case NotificationType::BROWSER_THEME_CHANGED: { | |
| 2830 renderer_preferences_util::UpdateFromSystemSettings( | |
| 2831 &renderer_preferences_, profile()); | |
| 2832 render_view_host()->SyncRendererPrefs(); | |
| 2833 break; | |
| 2834 } | |
| 2835 #endif | |
| 2836 | |
| 2837 case NotificationType::USER_STYLE_SHEET_UPDATED: | |
| 2838 UpdateWebPreferences(); | |
| 2839 break; | |
| 2840 | |
| 2841 case NotificationType::CONTENT_SETTINGS_CHANGED: { | |
| 2842 Details<const ContentSettingsDetails> settings_details(details); | |
| 2843 NavigationEntry* entry = controller_.GetActiveEntry(); | |
| 2844 GURL entry_url; | |
| 2845 if (entry) | |
| 2846 entry_url = entry->url(); | |
| 2847 if (settings_details.ptr()->update_all() || | |
| 2848 settings_details.ptr()->pattern().Matches(entry_url)) { | |
| 2849 render_view_host()->SendContentSettings(entry_url, | |
| 2850 profile()->GetHostContentSettingsMap()-> | |
| 2851 GetContentSettings(entry_url)); | |
| 2852 } | |
| 2853 break; | |
| 2854 } | |
| 2855 | |
| 2856 case NotificationType::EXTENSION_LOADED: | |
| 2857 break; | |
| 2858 | |
| 2859 case NotificationType::EXTENSION_UNLOADED: | |
| 2860 break; | |
| 2861 | |
| 2862 case NotificationType::GOOGLE_URL_UPDATED: | |
| 2863 UpdateAlternateErrorPageURL(); | |
| 2864 break; | |
| 2865 | |
| 2866 default: | |
| 2867 NOTREACHED(); | |
| 2868 } | |
| 2869 } | |
| 2870 | |
| 2871 void TabContents::UpdateExtensionAppIcon(const Extension* extension) { | |
| 2872 extension_app_icon_.reset(); | |
| 2873 | |
| 2874 if (extension) { | |
| 2875 extension_app_image_loader_.reset(new ImageLoadingTracker(this)); | |
| 2876 extension_app_image_loader_->LoadImage( | |
| 2877 extension, | |
| 2878 extension->GetIconResource(Extension::EXTENSION_ICON_SMALLISH, | |
| 2879 ExtensionIconSet::MATCH_EXACTLY), | |
| 2880 gfx::Size(Extension::EXTENSION_ICON_SMALLISH, | |
| 2881 Extension::EXTENSION_ICON_SMALLISH), | |
| 2882 ImageLoadingTracker::CACHE); | |
| 2883 } else { | |
| 2884 extension_app_image_loader_.reset(NULL); | |
| 2885 } | |
| 2886 } | |
| 2887 | |
| 2888 const Extension* TabContents::GetExtensionContaining(const GURL& url) { | |
| 2889 ExtensionService* extensions_service = profile()->GetExtensionService(); | |
| 2890 if (!extensions_service) | |
| 2891 return NULL; | |
| 2892 | |
| 2893 const Extension* extension = extensions_service->GetExtensionByURL(url); | |
| 2894 return extension ? | |
| 2895 extension : extensions_service->GetExtensionByWebExtent(url); | |
| 2896 } | |
| 2897 | |
| 2898 void TabContents::OnImageLoaded(SkBitmap* image, ExtensionResource resource, | |
| 2899 int index) { | |
| 2900 if (image) { | |
| 2901 extension_app_icon_ = *image; | |
| 2902 NotifyNavigationStateChanged(INVALIDATE_TAB); | |
| 2903 } | |
| 2904 } | |
| 2905 | |
| 2906 gfx::NativeWindow TabContents::GetMessageBoxRootWindow() { | |
| 2907 return view_->GetTopLevelNativeWindow(); | |
| 2908 } | |
| 2909 | |
| 2910 void TabContents::OnMessageBoxClosed(IPC::Message* reply_msg, | |
| 2911 bool success, | |
| 2912 const std::wstring& prompt) { | |
| 2913 last_javascript_message_dismissal_ = base::TimeTicks::Now(); | |
| 2914 if (is_showing_before_unload_dialog_ && !success) { | |
| 2915 // If a beforeunload dialog is canceled, we need to stop the throbber from | |
| 2916 // spinning, since we forced it to start spinning in Navigate. | |
| 2917 DidStopLoading(); | |
| 2918 | |
| 2919 tab_close_start_time_ = base::TimeTicks(); | |
| 2920 } | |
| 2921 is_showing_before_unload_dialog_ = false; | |
| 2922 render_view_host()->JavaScriptMessageBoxClosed(reply_msg, success, prompt); | |
| 2923 } | |
| 2924 | |
| 2925 void TabContents::SetSuppressMessageBoxes(bool suppress_message_boxes) { | |
| 2926 set_suppress_javascript_messages(suppress_message_boxes); | |
| 2927 } | |
| 2928 | |
| 2929 TabContents* TabContents::AsTabContents() { | |
| 2930 return this; | |
| 2931 } | |
| 2932 | |
| 2933 ExtensionHost* TabContents::AsExtensionHost() { | |
| 2934 return NULL; | |
| 2935 } | |
| 2936 | |
| 2937 void TabContents::set_encoding(const std::string& encoding) { | |
| 2938 encoding_ = CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding); | |
| 2939 } | |
| 2940 | |
| 2941 void TabContents::SetAppIcon(const SkBitmap& app_icon) { | |
| 2942 app_icon_ = app_icon; | |
| 2943 NotifyNavigationStateChanged(INVALIDATE_TITLE); | |
| 2944 } | |
| 2945 | |
| 2946 void TabContents::SwapInRenderViewHost(RenderViewHost* rvh) { | |
| 2947 render_manager_.SwapInRenderViewHost(rvh); | |
| 2948 } | |
| 2949 | |
| 2950 void TabContents::CreateViewAndSetSizeForRVH(RenderViewHost* rvh) { | |
| 2951 RenderWidgetHostView* rwh_view = view()->CreateViewForWidget(rvh); | |
| 2952 rwh_view->SetSize(view()->GetContainerSize()); | |
| 2953 } | |
| 2954 | |
| 2955 bool TabContents::MaybeUsePreloadedPage(const GURL& url) { | |
| 2956 prerender::PrerenderManager* pm = profile()->GetPrerenderManager(); | |
| 2957 if (pm != NULL) { | |
| 2958 if (pm->MaybeUsePreloadedPage(this, url)) | |
| 2959 return true; | |
| 2960 } | |
| 2961 return false; | |
| 2962 } | |
| OLD | NEW |