blob: 82ec6f02bd584d8c0a094f57599f90a2e5b764bd [file] [log] [blame]
[email protected]7e7414ae2010-01-26 20:19:291// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]f3ec7742009-01-15 00:59:165#include "chrome/browser/tab_contents/tab_contents.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]beb440c2009-11-06 04:08:547#include "app/gfx/text_elider.h"
[email protected]a92b8642009-05-05 23:38:568#include "app/l10n_util.h"
[email protected]9929da92009-05-05 02:05:119#include "app/resource_bundle.h"
[email protected]8cc8d492010-02-02 10:40:4910#include "base/auto_reset.h"
[email protected]420ae012009-04-24 05:16:3211#include "base/file_version_info.h"
12#include "base/process_util.h"
[email protected]96d185d2009-04-24 03:28:5413#include "base/string16.h"
[email protected]996fd702009-09-04 19:12:3714#include "base/string_util.h"
[email protected]96d185d2009-04-24 03:28:5415#include "base/time.h"
[email protected]21674df2009-10-28 19:51:2116#include "chrome/browser/autofill/autofill_manager.h"
[email protected]66ba4932009-06-04 19:22:1317#include "chrome/browser/blocked_popup_container.h"
[email protected]420ae012009-04-24 05:16:3218#include "chrome/browser/bookmarks/bookmark_model.h"
[email protected]96d185d2009-04-24 03:28:5419#include "chrome/browser/browser_process.h"
[email protected]cf68b092010-01-15 20:05:5520#include "chrome/browser/browser_shutdown.h"
initial.commit09911bf2008-07-26 23:55:2921#include "chrome/browser/cert_store.h"
[email protected]aacd7cc2009-09-02 14:51:1022#include "chrome/browser/character_encoding.h"
[email protected]96d185d2009-04-24 03:28:5423#include "chrome/browser/debugger/devtools_manager.h"
[email protected]420ae012009-04-24 05:16:3224#include "chrome/browser/dom_operation_notification_details.h"
[email protected]96d185d2009-04-24 03:28:5425#include "chrome/browser/dom_ui/dom_ui.h"
26#include "chrome/browser/dom_ui/dom_ui_factory.h"
[email protected]bcef0dc02009-02-28 00:35:0227#include "chrome/browser/download/download_item_model.h"
[email protected]420ae012009-04-24 05:16:3228#include "chrome/browser/download/download_manager.h"
29#include "chrome/browser/download/download_request_manager.h"
[email protected]e7eaedde2009-09-25 20:09:4930#include "chrome/browser/external_protocol_handler.h"
[email protected]92c6f9b92009-10-24 04:35:0831#include "chrome/browser/extensions/extensions_service.h"
[email protected]0189bc722009-08-28 21:56:4832#include "chrome/browser/favicon_service.h"
[email protected]19289d02009-10-21 21:47:0033#include "chrome/browser/form_field_history_manager.h"
[email protected]420ae012009-04-24 05:16:3234#include "chrome/browser/google_util.h"
[email protected]79580c62010-02-02 02:36:2535#include "chrome/browser/host_content_settings_map.h"
[email protected]8897c382009-05-06 17:53:2636#include "chrome/browser/hung_renderer_dialog.h"
[email protected]12f74a92010-02-05 22:32:1437#include "chrome/browser/message_box_handler.h"
[email protected]420ae012009-04-24 05:16:3238#include "chrome/browser/load_from_memory_cache_details.h"
39#include "chrome/browser/load_notification_details.h"
[email protected]84abba62009-10-07 17:01:4440#include "chrome/browser/metrics/metric_event_duration_details.h"
[email protected]ea0e80892009-08-22 00:36:0541#include "chrome/browser/modal_html_dialog_delegate.h"
[email protected]c8865482009-07-23 20:40:1042#include "chrome/browser/omnibox_search_hint.h"
[email protected]fdd61c62009-04-22 19:22:5743#include "chrome/browser/password_manager/password_manager.h"
44#include "chrome/browser/plugin_installer.h"
[email protected]052313b2010-02-19 09:43:0845#include "chrome/browser/pref_service.h"
[email protected]ce560f82009-06-03 09:39:4446#include "chrome/browser/profile.h"
[email protected]1db6ff152009-10-12 15:32:0747#include "chrome/browser/renderer_host/render_process_host.h"
[email protected]8cb5d5b2010-02-09 11:36:1648#include "chrome/browser/renderer_host/render_view_host.h"
[email protected]96d185d2009-04-24 03:28:5449#include "chrome/browser/renderer_host/render_widget_host_view.h"
[email protected]fd694982009-07-03 17:32:3750#include "chrome/browser/renderer_host/resource_request_details.h"
[email protected]1db6ff152009-10-12 15:32:0751#include "chrome/browser/renderer_host/site_instance.h"
[email protected]d4a00a72010-01-29 01:44:4252#include "chrome/browser/renderer_host/translation_service.h"
[email protected]96d185d2009-04-24 03:28:5453#include "chrome/browser/renderer_host/web_cache_manager.h"
[email protected]93623c5d2009-12-10 21:40:3254#include "chrome/browser/renderer_preferences_util.h"
[email protected]c37e3b62010-01-22 00:15:1755#include "chrome/browser/sessions/session_types.h"
[email protected]bd1ad682009-05-15 22:19:1756#include "chrome/browser/tab_contents/infobar_delegate.h"
[email protected]7e383692009-06-12 19:14:5457#include "chrome/browser/tab_contents/interstitial_page.h"
[email protected]f3ec7742009-01-15 00:59:1658#include "chrome/browser/tab_contents/navigation_entry.h"
[email protected]de34a962009-06-26 23:22:4359#include "chrome/browser/tab_contents/provisional_load_details.h"
[email protected]f3ec7742009-01-15 00:59:1660#include "chrome/browser/tab_contents/tab_contents_delegate.h"
[email protected]fdd61c62009-04-22 19:22:5761#include "chrome/browser/tab_contents/tab_contents_view.h"
[email protected]58dca552009-06-17 00:35:0262#include "chrome/browser/tab_contents/thumbnail_generator.h"
[email protected]449478302009-06-09 20:04:2863#include "chrome/browser/thumbnail_store.h"
[email protected]420ae012009-04-24 05:16:3264#include "chrome/browser/search_engines/template_url_fetcher.h"
65#include "chrome/browser/search_engines/template_url_model.h"
[email protected]35f7d212009-04-29 21:19:2766#include "chrome/common/chrome_switches.h"
[email protected]3b355642010-02-05 16:01:4967#include "chrome/common/extensions/extension.h"
[email protected]5d246db22009-10-27 06:17:5768#include "chrome/common/extensions/extension_action.h"
[email protected]bfd04a62009-02-01 18:16:5669#include "chrome/common/notification_service.h"
[email protected]89d6e6e2009-12-03 23:06:5170#include "chrome/common/platform_util.h"
initial.commit09911bf2008-07-26 23:55:2971#include "chrome/common/pref_names.h"
[email protected]420ae012009-04-24 05:16:3272#include "chrome/common/render_messages.h"
[email protected]1ee614862009-07-06 20:29:1873#include "chrome/common/renderer_preferences.h"
[email protected]96d185d2009-04-24 03:28:5474#include "chrome/common/url_constants.h"
[email protected]8897c382009-05-06 17:53:2675#include "grit/generated_resources.h"
[email protected]420ae012009-04-24 05:16:3276#include "grit/locale_settings.h"
[email protected]fd626782010-01-22 05:26:0677#include "grit/platform_locale_settings.h"
[email protected]420ae012009-04-24 05:16:3278#include "net/base/mime_util.h"
79#include "net/base/net_errors.h"
[email protected]d686e812009-06-03 19:10:2980#include "net/base/net_util.h"
[email protected]420ae012009-04-24 05:16:3281#include "net/base/registry_controlled_domain.h"
[email protected]1ee614862009-07-06 20:29:1882#include "webkit/glue/password_form.h"
83#include "webkit/glue/webpreferences.h"
[email protected]3e45ba92009-02-20 21:09:0084
[email protected]304f8792009-08-19 21:28:0985#if defined(OS_CHROMEOS)
86// For GdkScreen
87#include <gdk/gdk.h>
[email protected]0ba5c5e2009-08-20 16:47:1388#endif // defined(OS_CHROMEOS)
89
[email protected]420ae012009-04-24 05:16:3290// Cross-Site Navigations
91//
92// If a TabContents is told to navigate to a different web site (as determined
93// by SiteInstance), it will replace its current RenderViewHost with a new
94// RenderViewHost dedicated to the new SiteInstance. This works as follows:
95//
96// - Navigate determines whether the destination is cross-site, and if so,
97// it creates a pending_render_view_host_ and moves into the PENDING
98// RendererState.
99// - The pending RVH is "suspended," so that no navigation messages are sent to
100// its renderer until the onbeforeunload JavaScript handler has a chance to
101// run in the current RVH.
102// - The pending RVH tells CrossSiteRequestManager (a thread-safe singleton)
103// that it has a pending cross-site request. ResourceDispatcherHost will
104// check for this when the response arrives.
105// - The current RVH runs its onbeforeunload handler. If it returns false, we
106// cancel all the pending logic and go back to NORMAL. Otherwise we allow
107// the pending RVH to send the navigation request to its renderer.
108// - ResourceDispatcherHost receives a ResourceRequest on the IO thread. It
109// checks CrossSiteRequestManager to see that the RVH responsible has a
110// pending cross-site request, and then installs a CrossSiteEventHandler.
111// - When RDH receives a response, the BufferedEventHandler determines whether
112// it is a download. If so, it sends a message to the new renderer causing
113// it to cancel the request, and the download proceeds in the download
114// thread. For now, we stay in a PENDING state (with a pending RVH) until
[email protected]57c6a652009-05-04 07:58:34115// the next DidNavigate event for this TabContents. This isn't ideal, but it
[email protected]420ae012009-04-24 05:16:32116// doesn't affect any functionality.
117// - After RDH receives a response and determines that it is safe and not a
118// download, it pauses the response to first run the old page's onunload
119// handler. It does this by asynchronously calling the OnCrossSiteResponse
[email protected]57c6a652009-05-04 07:58:34120// method of TabContents on the UI thread, which sends a ClosePage message
[email protected]420ae012009-04-24 05:16:32121// to the current RVH.
122// - Once the onunload handler is finished, a ClosePage_ACK message is sent to
123// the ResourceDispatcherHost, who unpauses the response. Data is then sent
124// to the pending RVH.
125// - The pending renderer sends a FrameNavigate message that invokes the
126// DidNavigate method. This replaces the current RVH with the
127// pending RVH and goes back to the NORMAL RendererState.
128
129namespace {
130
131// Amount of time we wait between when a key event is received and the renderer
132// is queried for its state and pushed to the NavigationEntry.
133const int kQueryStateDelay = 5000;
134
135const int kSyncWaitDelay = 40;
136
[email protected]304f8792009-08-19 21:28:09137#if defined(OS_CHROMEOS)
138// If a popup window is bigger than this fraction of the screen on chrome os,
139// turn it into a tab
140const float kMaxWidthFactor = 0.5;
141const float kMaxHeightFactor = 0.6;
142#endif
143
[email protected]420ae012009-04-24 05:16:32144// If another javascript message box is displayed within
145// kJavascriptMessageExpectedDelay of a previous javascript message box being
146// dismissed, display an option to suppress future message boxes from this
147// contents.
148const int kJavascriptMessageExpectedDelay = 1000;
149
[email protected]420ae012009-04-24 05:16:32150// The list of prefs we want to observe.
151const wchar_t* kPrefsToObserve[] = {
152 prefs::kAlternateErrorPagesEnabled,
153 prefs::kWebKitJavaEnabled,
154 prefs::kWebKitJavascriptEnabled,
155 prefs::kWebKitLoadsImagesAutomatically,
156 prefs::kWebKitPluginsEnabled,
157 prefs::kWebKitUsesUniversalDetector,
158 prefs::kWebKitSerifFontFamily,
159 prefs::kWebKitSansSerifFontFamily,
160 prefs::kWebKitFixedFontFamily,
161 prefs::kWebKitDefaultFontSize,
162 prefs::kWebKitDefaultFixedFontSize,
163 prefs::kDefaultCharset
164 // kWebKitStandardFontIsSerif needs to be added
165 // if we let users pick which font to use, serif or sans-serif when
166 // no font is specified or a CSS generic family (serif or sans-serif)
167 // is not specified.
168};
169
170const int kPrefsToObserveLength = arraysize(kPrefsToObserve);
171
[email protected]420ae012009-04-24 05:16:32172// Returns true if the entry's transition type is FORM_SUBMIT.
173bool IsFormSubmit(const NavigationEntry* entry) {
174 return (PageTransition::StripQualifier(entry->transition_type()) ==
175 PageTransition::FORM_SUBMIT);
176}
177
178#if defined(OS_WIN)
179
180BOOL CALLBACK InvalidateWindow(HWND hwnd, LPARAM lparam) {
181 // Note: erase is required to properly paint some widgets borders. This can
182 // be seen with textfields.
183 InvalidateRect(hwnd, NULL, TRUE);
184 return TRUE;
185}
186#endif
187
[email protected]5e369672009-11-03 23:48:30188ViewMsg_Navigate_Params::NavigationType GetNavigationType(
[email protected]1ccb3568d2010-02-19 10:51:16189 Profile* profile, const NavigationEntry& entry,
190 NavigationController::ReloadType reload_type) {
191 switch (reload_type) {
192 case NavigationController::RELOAD:
193 return ViewMsg_Navigate_Params::RELOAD;
194 case NavigationController::RELOAD_IGNORING_CACHE:
195 return ViewMsg_Navigate_Params::RELOAD_IGNORING_CACHE;
196 case NavigationController::NO_RELOAD:
197 break; // Fall through to rest of function.
198 }
[email protected]5e369672009-11-03 23:48:30199
200 if (entry.restore_type() == NavigationEntry::RESTORE_LAST_SESSION &&
201 profile->DidLastSessionExitCleanly())
202 return ViewMsg_Navigate_Params::RESTORE;
203
204 return ViewMsg_Navigate_Params::NORMAL;
205}
206
207void MakeNavigateParams(Profile* profile, const NavigationEntry& entry,
[email protected]1ccb3568d2010-02-19 10:51:16208 NavigationController::ReloadType reload_type,
209 ViewMsg_Navigate_Params* params) {
[email protected]056de2d2009-06-26 16:41:34210 params->page_id = entry.page_id();
211 params->url = entry.url();
212 params->referrer = entry.referrer();
213 params->transition = entry.transition_type();
214 params->state = entry.content_state();
[email protected]1ccb3568d2010-02-19 10:51:16215 params->navigation_type = GetNavigationType(profile, entry, reload_type);
[email protected]056de2d2009-06-26 16:41:34216 params->request_time = base::Time::Now();
217}
218
[email protected]420ae012009-04-24 05:16:32219} // namespace
220
221// -----------------------------------------------------------------------------
222
[email protected]fdd61c62009-04-22 19:22:57223// static
224int TabContents::find_request_id_counter_ = -1;
225
[email protected]420ae012009-04-24 05:16:32226
[email protected]420ae012009-04-24 05:16:32227TabContents::TabContents(Profile* profile,
228 SiteInstance* site_instance,
229 int routing_id,
[email protected]34ac70502009-09-25 17:07:23230 const TabContents* base_tab_contents)
[email protected]b680ad22009-04-15 23:19:42231 : delegate_(NULL),
[email protected]66ba4932009-06-04 19:22:13232 ALLOW_THIS_IN_INITIALIZER_LIST(controller_(this, profile)),
233 ALLOW_THIS_IN_INITIALIZER_LIST(view_(
[email protected]d82ed61e2009-06-16 02:46:22234 TabContentsView::Create(this))),
235 ALLOW_THIS_IN_INITIALIZER_LIST(render_manager_(this, this)),
[email protected]fdd61c62009-04-22 19:22:57236 property_bag_(),
237 registrar_(),
[email protected]d82ed61e2009-06-16 02:46:22238 ALLOW_THIS_IN_INITIALIZER_LIST(printing_(*this)),
[email protected]fdd61c62009-04-22 19:22:57239 save_package_(),
[email protected]19289d02009-10-21 21:47:00240 form_field_history_manager_(),
[email protected]21674df2009-10-28 19:51:21241 autofill_manager_(),
[email protected]fdd61c62009-04-22 19:22:57242 password_manager_(),
243 plugin_installer_(),
[email protected]d82ed61e2009-06-16 02:46:22244 ALLOW_THIS_IN_INITIALIZER_LIST(fav_icon_helper_(this)),
[email protected]fdd61c62009-04-22 19:22:57245 select_file_dialog_(),
[email protected]d5f942ba2008-09-26 19:30:34246 is_loading_(false),
initial.commit09911bf2008-07-26 23:55:29247 is_crashed_(false),
[email protected]d5f942ba2008-09-26 19:30:34248 waiting_for_response_(false),
[email protected]d5f942ba2008-09-26 19:30:34249 max_page_id_(-1),
[email protected]fdd61c62009-04-22 19:22:57250 current_load_start_(),
251 load_state_(net::LOAD_STATE_IDLE),
252 load_state_host_(),
[email protected]094e5b22009-09-25 04:23:56253 upload_size_(0),
254 upload_position_(0),
[email protected]fdd61c62009-04-22 19:22:57255 received_page_title_(false),
256 is_starred_(false),
257 contents_mime_type_(),
258 encoding_(),
[email protected]332af7732009-03-11 13:21:35259 blocked_popups_(NULL),
[email protected]8cc8d492010-02-02 10:40:49260 dont_notify_render_view_(false),
[email protected]fdd61c62009-04-22 19:22:57261 infobar_delegates_(),
[email protected]fdd61c62009-04-22 19:22:57262 find_ui_active_(false),
263 find_op_aborted_(false),
264 current_find_request_id_(find_request_id_counter_++),
[email protected]e491f1c2009-05-22 20:28:12265 last_search_case_sensitive_(false),
266 last_search_prepopulate_text_(NULL),
267 last_search_result_(),
[email protected]fdd61c62009-04-22 19:22:57268 capturing_contents_(false),
269 is_being_destroyed_(false),
270 notify_disconnection_(false),
271 history_requests_(),
272#if defined(OS_WIN)
273 message_box_active_(CreateEvent(NULL, TRUE, FALSE, NULL)),
274#endif
275 last_javascript_message_dismissal_(),
[email protected]c2e74fe82009-09-03 17:57:44276 suppress_javascript_messages_(false),
[email protected]7ab1e7d62009-10-14 23:32:01277 is_showing_before_unload_dialog_(false),
[email protected]7ff431e2010-01-07 18:18:54278 renderer_preferences_(),
[email protected]1a242c32010-02-02 21:20:54279 opener_dom_ui_type_(DOMUIFactory::kNoDOMUI),
[email protected]3b1c1812010-02-12 21:53:55280 app_extension_(NULL),
281 language_state_(&controller_) {
[email protected]0de80162010-02-03 04:52:35282 ClearBlockedContentSettings();
[email protected]7ff431e2010-01-07 18:18:54283 renderer_preferences_util::UpdateFromSystemSettings(
284 &renderer_preferences_, profile);
285
[email protected]16779842009-07-08 23:45:29286#if defined(OS_CHROMEOS)
[email protected]58dca552009-06-17 00:35:02287 // Make sure the thumbnailer is started before starting the render manager.
288 // The thumbnailer will want to listen for RVH creations, one of which will
289 // happen in RVHManager::Init.
290 ThumbnailGenerator* generator = g_browser_process->GetThumbnailGenerator();
291 if (generator)
292 generator->StartThumbnailing();
293#endif
294
[email protected]12636df2009-09-28 22:32:21295 render_manager_.Init(profile, site_instance, routing_id);
[email protected]420ae012009-04-24 05:16:32296
[email protected]34ac70502009-09-25 17:07:23297 // We have the initial size of the view be based on the size of the passed in
298 // tab contents (normally a tab from the same window).
299 view_->CreateView(base_tab_contents ?
300 base_tab_contents->view()->GetContainerSize() : gfx::Size());
[email protected]420ae012009-04-24 05:16:32301
302 // Register for notifications about all interested prefs change.
303 PrefService* prefs = profile->GetPrefs();
304 if (prefs) {
305 for (int i = 0; i < kPrefsToObserveLength; ++i)
306 prefs->AddPrefObserver(kPrefsToObserve[i], this);
307 }
308
309 // Register for notifications about URL starredness changing on any profile.
310 registrar_.Add(this, NotificationType::URLS_STARRED,
311 NotificationService::AllSources());
312 registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
313 NotificationService::AllSources());
314 registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DESTROYED,
315 NotificationService::AllSources());
[email protected]d3ba77272009-09-03 00:06:09316#if defined(OS_LINUX)
317 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
318 NotificationService::AllSources());
319#endif
[email protected]420ae012009-04-24 05:16:32320
[email protected]79580c62010-02-02 02:36:25321 // Register for notifications about content setting changes.
322 registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
323 NotificationService::AllSources());
324
[email protected]420ae012009-04-24 05:16:32325 // Keep a global copy of the previous search string (if any).
326 static string16 global_last_search = string16();
[email protected]e491f1c2009-05-22 20:28:12327 last_search_prepopulate_text_ = &global_last_search;
[email protected]840b1512009-07-21 16:53:46328
[email protected]c8865482009-07-23 20:40:10329 // Set-up the showing of the omnibox search infobar if applicable.
330 if (OmniboxSearchHint::IsEnabled(profile))
331 omnibox_search_hint_.reset(new OmniboxSearchHint(this));
[email protected]332af7732009-03-11 13:21:35332}
initial.commit09911bf2008-07-26 23:55:29333
334TabContents::~TabContents() {
[email protected]420ae012009-04-24 05:16:32335 is_being_destroyed_ = true;
336
[email protected]bfe4c1582009-10-02 18:11:09337 // We don't want any notifications while we're running our destructor.
[email protected]420ae012009-04-24 05:16:32338 registrar_.RemoveAll();
339
340 // Unregister the notifications of all observed prefs change.
341 PrefService* prefs = profile()->GetPrefs();
342 if (prefs) {
343 for (int i = 0; i < kPrefsToObserveLength; ++i)
344 prefs->RemovePrefObserver(kPrefsToObserve[i], this);
345 }
346
[email protected]420ae012009-04-24 05:16:32347 NotifyDisconnected();
[email protected]e7b8d832009-11-20 22:41:00348 hung_renderer_dialog::HideForTabContents(this);
[email protected]420ae012009-04-24 05:16:32349
[email protected]420ae012009-04-24 05:16:32350 // First cleanly close all child windows.
351 // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
352 // some of these to close. CloseWindows is async, so it might get called
353 // twice before it runs.
[email protected]8cc8d492010-02-02 10:40:49354 CloseConstrainedWindows();
[email protected]420ae012009-04-24 05:16:32355
[email protected]8cc8d492010-02-02 10:40:49356 // Close all blocked popups.
[email protected]66ba4932009-06-04 19:22:13357 if (blocked_popups_)
358 blocked_popups_->Destroy();
359
[email protected]420ae012009-04-24 05:16:32360 // Notify any observer that have a reference on this tab contents.
361 NotificationService::current()->Notify(
362 NotificationType::TAB_CONTENTS_DESTROYED,
363 Source<TabContents>(this),
364 NotificationService::NoDetails());
365
[email protected]1e5e74f2009-05-27 20:55:12366 // Notify any lasting InfobarDelegates that have not yet been removed that
367 // whatever infobar they were handling in this TabContents has closed,
368 // because the TabContents is going away entirely.
369 // This must happen after the TAB_CONTENTS_DESTROYED notification as the
370 // notification may trigger infobars calls that access their delegate. (and
371 // some implementations of InfoBarDelegate do delete themselves on
372 // InfoBarClosed()).
373 for (int i = 0; i < infobar_delegate_count(); ++i) {
374 InfoBarDelegate* delegate = GetInfoBarDelegateAt(i);
375 delegate->InfoBarClosed();
376 }
377 infobar_delegates_.clear();
378
[email protected]420ae012009-04-24 05:16:32379 // TODO(brettw) this should be moved to the view.
380#if defined(OS_WIN)
381 // If we still have a window handle, destroy it. GetNativeView can return
382 // NULL if this contents was part of a window that closed.
383 if (GetNativeView())
384 ::DestroyWindow(GetNativeView());
385#endif
[email protected]7ab1e7d62009-10-14 23:32:01386
387 // OnCloseStarted isn't called in unit tests.
388 if (!tab_close_start_time_.is_null()) {
389 UMA_HISTOGRAM_TIMES("Tab.Close",
390 base::TimeTicks::Now() - tab_close_start_time_);
391 }
initial.commit09911bf2008-07-26 23:55:29392}
393
[email protected]d5f942ba2008-09-26 19:30:34394// static
395void TabContents::RegisterUserPrefs(PrefService* prefs) {
[email protected]420ae012009-04-24 05:16:32396 prefs->RegisterBooleanPref(prefs::kAlternateErrorPagesEnabled, true);
397
398 WebPreferences pref_defaults;
399 prefs->RegisterBooleanPref(prefs::kWebKitJavascriptEnabled,
400 pref_defaults.javascript_enabled);
401 prefs->RegisterBooleanPref(prefs::kWebKitWebSecurityEnabled,
402 pref_defaults.web_security_enabled);
403 prefs->RegisterBooleanPref(
404 prefs::kWebKitJavascriptCanOpenWindowsAutomatically, true);
405 prefs->RegisterBooleanPref(prefs::kWebKitLoadsImagesAutomatically,
406 pref_defaults.loads_images_automatically);
407 prefs->RegisterBooleanPref(prefs::kWebKitPluginsEnabled,
408 pref_defaults.plugins_enabled);
409 prefs->RegisterBooleanPref(prefs::kWebKitDomPasteEnabled,
410 pref_defaults.dom_paste_enabled);
411 prefs->RegisterBooleanPref(prefs::kWebKitShrinksStandaloneImagesToFit,
412 pref_defaults.shrinks_standalone_images_to_fit);
[email protected]0df30122009-06-03 12:13:08413 prefs->RegisterStringPref(prefs::kWebKitInspectorSettings,
[email protected]8922e1f2009-10-03 05:01:26414 UTF8ToWide(pref_defaults.inspector_settings));
[email protected]420ae012009-04-24 05:16:32415 prefs->RegisterBooleanPref(prefs::kWebKitTextAreasAreResizable,
416 pref_defaults.text_areas_are_resizable);
417 prefs->RegisterBooleanPref(prefs::kWebKitJavaEnabled,
418 pref_defaults.java_enabled);
419
420 prefs->RegisterLocalizedStringPref(prefs::kAcceptLanguages,
421 IDS_ACCEPT_LANGUAGES);
422 prefs->RegisterLocalizedStringPref(prefs::kDefaultCharset,
423 IDS_DEFAULT_ENCODING);
424 prefs->RegisterLocalizedBooleanPref(prefs::kWebKitStandardFontIsSerif,
425 IDS_STANDARD_FONT_IS_SERIF);
426 prefs->RegisterLocalizedStringPref(prefs::kWebKitFixedFontFamily,
427 IDS_FIXED_FONT_FAMILY);
428 prefs->RegisterLocalizedStringPref(prefs::kWebKitSerifFontFamily,
429 IDS_SERIF_FONT_FAMILY);
430 prefs->RegisterLocalizedStringPref(prefs::kWebKitSansSerifFontFamily,
431 IDS_SANS_SERIF_FONT_FAMILY);
432 prefs->RegisterLocalizedStringPref(prefs::kWebKitCursiveFontFamily,
433 IDS_CURSIVE_FONT_FAMILY);
434 prefs->RegisterLocalizedStringPref(prefs::kWebKitFantasyFontFamily,
435 IDS_FANTASY_FONT_FAMILY);
436 prefs->RegisterLocalizedIntegerPref(prefs::kWebKitDefaultFontSize,
437 IDS_DEFAULT_FONT_SIZE);
438 prefs->RegisterLocalizedIntegerPref(prefs::kWebKitDefaultFixedFontSize,
439 IDS_DEFAULT_FIXED_FONT_SIZE);
440 prefs->RegisterLocalizedIntegerPref(prefs::kWebKitMinimumFontSize,
441 IDS_MINIMUM_FONT_SIZE);
442 prefs->RegisterLocalizedIntegerPref(prefs::kWebKitMinimumLogicalFontSize,
443 IDS_MINIMUM_LOGICAL_FONT_SIZE);
444 prefs->RegisterLocalizedBooleanPref(prefs::kWebKitUsesUniversalDetector,
445 IDS_USES_UNIVERSAL_DETECTOR);
446 prefs->RegisterLocalizedStringPref(prefs::kStaticEncodings,
447 IDS_STATIC_ENCODING_LIST);
initial.commit09911bf2008-07-26 23:55:29448}
449
[email protected]13367f72009-07-08 16:39:02450// Returns true if contains content rendered by an extension.
451bool TabContents::HostsExtension() const {
452 return GetURL().SchemeIs(chrome::kExtensionScheme);
[email protected]d5f942ba2008-09-26 19:30:34453}
454
[email protected]6e95706d2009-04-23 22:55:01455PasswordManager* TabContents::GetPasswordManager() {
456 if (password_manager_.get() == NULL)
457 password_manager_.reset(new PasswordManager(this));
458 return password_manager_.get();
459}
460
461PluginInstaller* TabContents::GetPluginInstaller() {
462 if (plugin_installer_.get() == NULL)
463 plugin_installer_.reset(new PluginInstaller(this));
464 return plugin_installer_.get();
465}
466
[email protected]8cb5d5b2010-02-09 11:36:16467RenderProcessHost* TabContents::GetRenderProcessHost() const {
468 return render_manager_.current_host()->process();
469}
470
[email protected]3b355642010-02-05 16:01:49471void TabContents::SetAppExtension(Extension* extension) {
472 DCHECK(!extension || extension->IsApp());
473 app_extension_ = extension;
[email protected]fca656c2010-02-10 20:30:10474
475 NotificationService::current()->Notify(
476 NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
477 Source<TabContents>(this),
478 NotificationService::NoDetails());
[email protected]3b355642010-02-05 16:01:49479}
480
[email protected]d5f942ba2008-09-26 19:30:34481const GURL& TabContents::GetURL() const {
482 // We may not have a navigation entry yet
[email protected]ce3fa3c2009-04-20 19:55:57483 NavigationEntry* entry = controller_.GetActiveEntry();
[email protected]ebe89e062009-08-13 23:16:54484 return entry ? entry->virtual_url() : GURL::EmptyGURL();
[email protected]d5f942ba2008-09-26 19:30:34485}
486
[email protected]96d185d2009-04-24 03:28:54487const string16& TabContents::GetTitle() const {
[email protected]4c6092c5b2009-06-06 00:23:55488 // Transient entries take precedence. They are used for interstitial pages
489 // that are shown on top of existing pages.
490 NavigationEntry* entry = controller_.GetTransientEntry();
491 if (entry)
492 return entry->GetTitleForDisplay(&controller_);
493
[email protected]96d185d2009-04-24 03:28:54494 DOMUI* our_dom_ui = render_manager_.pending_dom_ui() ?
495 render_manager_.pending_dom_ui() : render_manager_.dom_ui();
496 if (our_dom_ui) {
497 // Don't override the title in view source mode.
[email protected]4c6092c5b2009-06-06 00:23:55498 entry = controller_.GetActiveEntry();
[email protected]96d185d2009-04-24 03:28:54499 if (!(entry && entry->IsViewSourceMode())) {
500 // Give the DOM UI the chance to override our title.
501 const string16& title = our_dom_ui->overridden_title();
502 if (!title.empty())
503 return title;
504 }
505 }
506
507 // We use the title for the last committed entry rather than a pending
508 // navigation entry. For example, when the user types in a URL, we want to
509 // keep the old page's title until the new load has committed and we get a new
510 // title.
[email protected]96d185d2009-04-24 03:28:54511 entry = controller_.GetLastCommittedEntry();
512 if (entry)
513 return entry->GetTitleForDisplay(&controller_);
[email protected]96d185d2009-04-24 03:28:54514 return EmptyString16();
515}
516
[email protected]bbbc1ef2010-02-12 18:03:41517// static
518string16 TabContents::GetDefaultTitle() {
519 return l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE);
520}
521
[email protected]d5f942ba2008-09-26 19:30:34522int32 TabContents::GetMaxPageID() {
523 if (GetSiteInstance())
524 return GetSiteInstance()->max_page_id();
525 else
526 return max_page_id_;
527}
528
529void TabContents::UpdateMaxPageID(int32 page_id) {
530 // Ensure both the SiteInstance and RenderProcessHost update their max page
[email protected]57c6a652009-05-04 07:58:34531 // IDs in sync. Only TabContents will also have site instances, except during
[email protected]d5f942ba2008-09-26 19:30:34532 // testing.
533 if (GetSiteInstance())
534 GetSiteInstance()->UpdateMaxPageID(page_id);
[email protected]8cb5d5b2010-02-09 11:36:16535 GetRenderProcessHost()->UpdateMaxPageID(page_id);
[email protected]d5f942ba2008-09-26 19:30:34536}
537
[email protected]96d185d2009-04-24 03:28:54538SiteInstance* TabContents::GetSiteInstance() const {
539 return render_manager_.current_host()->site_instance();
540}
541
[email protected]96d185d2009-04-24 03:28:54542bool TabContents::ShouldDisplayURL() {
[email protected]8ab24cc2009-11-13 20:56:15543 // Don't hide the url in view source mode and with interstitials.
[email protected]96d185d2009-04-24 03:28:54544 NavigationEntry* entry = controller_.GetActiveEntry();
[email protected]8ab24cc2009-11-13 20:56:15545 if (entry && (entry->IsViewSourceMode() ||
546 entry->page_type() == NavigationEntry::INTERSTITIAL_PAGE)) {
[email protected]96d185d2009-04-24 03:28:54547 return true;
[email protected]8ab24cc2009-11-13 20:56:15548 }
[email protected]83e3895b2009-06-11 00:07:16549
[email protected]96d185d2009-04-24 03:28:54550 DOMUI* dom_ui = GetDOMUIForCurrentState();
551 if (dom_ui)
552 return !dom_ui->should_hide_url();
553 return true;
554}
555
[email protected]d5f942ba2008-09-26 19:30:34556SkBitmap TabContents::GetFavIcon() const {
557 // Like GetTitle(), we also want to use the favicon for the last committed
558 // entry rather than a pending navigation entry.
[email protected]ce3fa3c2009-04-20 19:55:57559 NavigationEntry* entry = controller_.GetTransientEntry();
[email protected]cbab76d2008-10-13 22:42:47560 if (entry)
561 return entry->favicon().bitmap();
562
[email protected]ce3fa3c2009-04-20 19:55:57563 entry = controller_.GetLastCommittedEntry();
[email protected]d5f942ba2008-09-26 19:30:34564 if (entry)
565 return entry->favicon().bitmap();
[email protected]d5f942ba2008-09-26 19:30:34566 return SkBitmap();
567}
568
[email protected]0b303cc2009-09-28 22:35:15569bool TabContents::FavIconIsValid() const {
570 NavigationEntry* entry = controller_.GetTransientEntry();
571 if (entry)
572 return entry->favicon().is_valid();
573
574 entry = controller_.GetLastCommittedEntry();
575 if (entry)
576 return entry->favicon().is_valid();
577
578 return false;
579}
580
[email protected]96d185d2009-04-24 03:28:54581bool TabContents::ShouldDisplayFavIcon() {
582 // Always display a throbber during pending loads.
583 if (controller_.GetLastCommittedEntry() && controller_.pending_entry())
584 return true;
585
586 DOMUI* dom_ui = GetDOMUIForCurrentState();
587 if (dom_ui)
588 return !dom_ui->hide_favicon();
589 return true;
590}
591
[email protected]2d5a3592010-01-30 04:29:52592bool TabContents::IsContentBlocked(ContentSettingsType content_type) const {
[email protected]8cc8d492010-02-02 10:40:49593 if (content_type == CONTENT_SETTINGS_TYPE_POPUPS)
594 return blocked_popups_ != NULL;
595
[email protected]0de80162010-02-03 04:52:35596 if (content_type == CONTENT_SETTINGS_TYPE_IMAGES ||
597 content_type == CONTENT_SETTINGS_TYPE_JAVASCRIPT ||
[email protected]3dbb80b2010-02-09 22:41:20598 content_type == CONTENT_SETTINGS_TYPE_PLUGINS ||
599 content_type == CONTENT_SETTINGS_TYPE_COOKIES)
[email protected]0de80162010-02-03 04:52:35600 return content_blocked_[content_type];
601
[email protected]3dbb80b2010-02-09 22:41:20602 NOTREACHED();
[email protected]2d5a3592010-01-30 04:29:52603 return false;
604}
605
[email protected]96d185d2009-04-24 03:28:54606std::wstring TabContents::GetStatusText() const {
607 if (!is_loading() || load_state_ == net::LOAD_STATE_IDLE)
608 return std::wstring();
609
610 switch (load_state_) {
611 case net::LOAD_STATE_WAITING_FOR_CACHE:
612 return l10n_util::GetString(IDS_LOAD_STATE_WAITING_FOR_CACHE);
613 case net::LOAD_STATE_RESOLVING_PROXY_FOR_URL:
614 return l10n_util::GetString(IDS_LOAD_STATE_RESOLVING_PROXY_FOR_URL);
615 case net::LOAD_STATE_RESOLVING_HOST:
616 return l10n_util::GetString(IDS_LOAD_STATE_RESOLVING_HOST);
617 case net::LOAD_STATE_CONNECTING:
618 return l10n_util::GetString(IDS_LOAD_STATE_CONNECTING);
619 case net::LOAD_STATE_SENDING_REQUEST:
[email protected]094e5b22009-09-25 04:23:56620 if (upload_size_)
621 return l10n_util::GetStringF(
622 IDS_LOAD_STATE_SENDING_REQUEST_WITH_PROGRESS,
623 static_cast<int>((100 * upload_position_) / upload_size_));
624 else
625 return l10n_util::GetString(IDS_LOAD_STATE_SENDING_REQUEST);
[email protected]96d185d2009-04-24 03:28:54626 case net::LOAD_STATE_WAITING_FOR_RESPONSE:
627 return l10n_util::GetStringF(IDS_LOAD_STATE_WAITING_FOR_RESPONSE,
628 load_state_host_);
629 // Ignore net::LOAD_STATE_READING_RESPONSE and net::LOAD_STATE_IDLE
630 case net::LOAD_STATE_IDLE:
631 case net::LOAD_STATE_READING_RESPONSE:
632 break;
633 }
634
635 return std::wstring();
636}
637
[email protected]d5f942ba2008-09-26 19:30:34638void TabContents::SetIsCrashed(bool state) {
639 if (state == is_crashed_)
640 return;
641
642 is_crashed_ = state;
[email protected]c9cd2222009-05-06 05:16:50643 NotifyNavigationStateChanged(INVALIDATE_TAB);
[email protected]d5f942ba2008-09-26 19:30:34644}
645
[email protected]744ef172009-10-16 21:53:46646void TabContents::PageActionStateChanged() {
647 NotifyNavigationStateChanged(TabContents::INVALIDATE_PAGE_ACTIONS);
[email protected]d7eaf572009-07-01 21:57:00648}
[email protected]ce5c4502009-05-06 16:46:11649
[email protected]d5f942ba2008-09-26 19:30:34650void TabContents::NotifyNavigationStateChanged(unsigned changed_flags) {
651 if (delegate_)
652 delegate_->NavigationStateChanged(this, changed_flags);
653}
654
[email protected]96d185d2009-04-24 03:28:54655void TabContents::DidBecomeSelected() {
656 controller_.SetActive(true);
[email protected]8cb5d5b2010-02-09 11:36:16657 RenderWidgetHostView* rwhv = GetRenderWidgetHostView();
658 if (rwhv) {
659 rwhv->DidBecomeSelected();
[email protected]789e9152009-08-04 21:59:43660#if defined(OS_MACOSX)
[email protected]8cb5d5b2010-02-09 11:36:16661 rwhv->SetActive(true);
[email protected]789e9152009-08-04 21:59:43662#endif
663 }
[email protected]96d185d2009-04-24 03:28:54664
[email protected]8cb5d5b2010-02-09 11:36:16665 WebCacheManager::GetInstance()->ObserveActivity(GetRenderProcessHost()->id());
[email protected]96d185d2009-04-24 03:28:54666}
667
668void TabContents::WasHidden() {
669 if (!capturing_contents()) {
670 // |render_view_host()| can be NULL if the user middle clicks a link to open
671 // a tab in then background, then closes the tab before selecting it. This
672 // is because closing the tab calls TabContents::Destroy(), which removes
673 // the |render_view_host()|; then when we actually destroy the window,
674 // OnWindowPosChanged() notices and calls HideContents() (which calls us).
[email protected]8cb5d5b2010-02-09 11:36:16675 RenderWidgetHostView* rwhv = GetRenderWidgetHostView();
676 if (rwhv)
677 rwhv->WasHidden();
[email protected]96d185d2009-04-24 03:28:54678 }
679
680 NotificationService::current()->Notify(
681 NotificationType::TAB_CONTENTS_HIDDEN,
682 Source<TabContents>(this),
683 NotificationService::NoDetails());
684}
685
[email protected]d5f942ba2008-09-26 19:30:34686void TabContents::Activate() {
687 if (delegate_)
688 delegate_->ActivateContents(this);
689}
690
[email protected]96d185d2009-04-24 03:28:54691void TabContents::ShowContents() {
[email protected]8cb5d5b2010-02-09 11:36:16692 RenderWidgetHostView* rwhv = GetRenderWidgetHostView();
693 if (rwhv)
694 rwhv->DidBecomeSelected();
[email protected]96d185d2009-04-24 03:28:54695}
696
697void TabContents::HideContents() {
698 // TODO(pkasting): http://b/1239839 Right now we purposefully don't call
699 // our superclass HideContents(), because some callers want to be very picky
700 // about the order in which these get called. In addition to making the code
701 // here practically impossible to understand, this also means we end up
702 // calling TabContents::WasHidden() twice if callers call both versions of
[email protected]57c6a652009-05-04 07:58:34703 // HideContents() on a TabContents.
[email protected]96d185d2009-04-24 03:28:54704 WasHidden();
705}
706
[email protected]c0588052008-10-27 23:01:50707void TabContents::OpenURL(const GURL& url, const GURL& referrer,
[email protected]d5f942ba2008-09-26 19:30:34708 WindowOpenDisposition disposition,
709 PageTransition::Type transition) {
710 if (delegate_)
[email protected]c0588052008-10-27 23:01:50711 delegate_->OpenURLFromTab(this, url, referrer, disposition, transition);
[email protected]d5f942ba2008-09-26 19:30:34712}
713
[email protected]1ccb3568d2010-02-19 10:51:16714bool TabContents::NavigateToPendingEntry(
715 NavigationController::ReloadType reload_type) {
[email protected]96d185d2009-04-24 03:28:54716 const NavigationEntry& entry = *controller_.pending_entry();
717
718 RenderViewHost* dest_render_view_host = render_manager_.Navigate(entry);
719 if (!dest_render_view_host)
720 return false; // Unable to create the desired render view host.
721
722 // Tell DevTools agent that it is attached prior to the navigation.
[email protected]d9f9b792009-06-24 13:17:12723 DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
[email protected]7e8e6b62009-05-08 11:28:32724 if (devtools_manager) { // NULL in unit tests.
[email protected]684b4ba22009-05-07 06:27:41725 devtools_manager->OnNavigatingToPendingEntry(
726 render_view_host(),
727 dest_render_view_host,
728 controller_.pending_entry()->url());
[email protected]7e8e6b62009-05-08 11:28:32729 }
[email protected]96d185d2009-04-24 03:28:54730
731 // Used for page load time metrics.
732 current_load_start_ = base::TimeTicks::Now();
733
734 // Navigate in the desired RenderViewHost.
[email protected]056de2d2009-06-26 16:41:34735 ViewMsg_Navigate_Params navigate_params;
[email protected]1ccb3568d2010-02-19 10:51:16736 MakeNavigateParams(profile(), entry, reload_type, &navigate_params);
[email protected]056de2d2009-06-26 16:41:34737 dest_render_view_host->Navigate(navigate_params);
[email protected]96d185d2009-04-24 03:28:54738
739 if (entry.page_id() == -1) {
740 // HACK!! This code suppresses javascript: URLs from being added to
741 // session history, which is what we want to do for javascript: URLs that
742 // do not generate content. What we really need is a message from the
743 // renderer telling us that a new page was not created. The same message
744 // could be used for mailto: URLs and the like.
745 if (entry.url().SchemeIs(chrome::kJavaScriptScheme))
746 return false;
747 }
748
749 // Clear any provisional password saves - this stops password infobars
750 // showing up on pages the user navigates to while the right page is
751 // loading.
752 GetPasswordManager()->ClearProvisionalSave();
753
[email protected]1ccb3568d2010-02-19 10:51:16754 if (reload_type != NavigationController::NO_RELOAD &&
755 !profile()->IsOffTheRecord()) {
[email protected]0189bc722009-08-28 21:56:48756 FaviconService* favicon_service =
757 profile()->GetFaviconService(Profile::IMPLICIT_ACCESS);
758 if (favicon_service)
759 favicon_service->SetFaviconOutOfDateForPage(entry.url());
[email protected]96d185d2009-04-24 03:28:54760 }
761
[email protected]d5f942ba2008-09-26 19:30:34762 return true;
763}
764
[email protected]96d185d2009-04-24 03:28:54765void TabContents::Stop() {
766 render_manager_.Stop();
767 printing_.Stop();
768}
769
770void TabContents::Cut() {
771 render_view_host()->Cut();
772}
773
774void TabContents::Copy() {
775 render_view_host()->Copy();
776}
777
[email protected]c0cc3092009-09-12 08:27:27778#if defined(OS_MACOSX)
[email protected]a954bf72009-09-12 07:30:35779void TabContents::CopyToFindPboard() {
780 render_view_host()->CopyToFindPboard();
781}
[email protected]c0cc3092009-09-12 08:27:27782#endif
[email protected]a954bf72009-09-12 07:30:35783
[email protected]96d185d2009-04-24 03:28:54784void TabContents::Paste() {
785 render_view_host()->Paste();
786}
787
[email protected]7e786822009-11-07 00:00:27788#if defined(OS_MACOSX)
789void TabContents::PasteAndMatchStyle() {
790 render_view_host()->ForwardEditCommand("PasteAndMatchStyle", "");
791}
792#endif
793
[email protected]96d185d2009-04-24 03:28:54794void TabContents::DisassociateFromPopupCount() {
795 render_view_host()->DisassociateFromPopupCount();
796}
797
798TabContents* TabContents::Clone() {
799 // We create a new SiteInstance so that the new tab won't share processes
800 // with the old one. This can be changed in the future if we need it to share
801 // processes for some reason.
[email protected]420ae012009-04-24 05:16:32802 TabContents* tc = new TabContents(profile(),
[email protected]96d185d2009-04-24 03:28:54803 SiteInstance::CreateSiteInstance(profile()),
[email protected]12636df2009-09-28 22:32:21804 MSG_ROUTING_NONE, this);
[email protected]96d185d2009-04-24 03:28:54805 tc->controller().CopyStateFrom(controller_);
806 return tc;
807}
808
[email protected]4d677202009-07-19 07:37:12809void TabContents::ShowPageInfo(const GURL& url,
810 const NavigationEntry::SSLStatus& ssl,
811 bool show_history) {
812 if (!delegate_)
813 return;
814
[email protected]bb678332009-07-21 00:15:50815 delegate_->ShowPageInfo(profile(), url, ssl, show_history);
[email protected]4d677202009-07-19 07:37:12816}
817
[email protected]7e0831b2010-02-01 08:45:15818void TabContents::TranslatePage(const std::string& source_lang,
819 const std::string& target_lang) {
820 NavigationEntry* entry = controller_.GetActiveEntry();
821 if (!entry) {
822 NOTREACHED();
823 return;
824 }
[email protected]3b1c1812010-02-12 21:53:55825 language_state_.set_translation_pending(true);
[email protected]7e0831b2010-02-01 08:45:15826 render_view_host()->TranslatePage(entry->page_id(), source_lang, target_lang);
827}
828
initial.commit09911bf2008-07-26 23:55:29829ConstrainedWindow* TabContents::CreateConstrainedDialog(
[email protected]e8382172009-06-19 22:16:28830 ConstrainedWindowDelegate* delegate) {
initial.commit09911bf2008-07-26 23:55:29831 ConstrainedWindow* window =
[email protected]e8382172009-06-19 22:16:28832 ConstrainedWindow::CreateConstrainedDialog(this, delegate);
initial.commit09911bf2008-07-26 23:55:29833 child_windows_.push_back(window);
[email protected]fa1cf0b82010-01-15 21:49:44834
835 if (child_windows_.size() == 1) {
836 window->ShowConstrainedWindow();
837 BlockTabContent(true);
838 }
839
initial.commit09911bf2008-07-26 23:55:29840 return window;
841}
842
[email protected]fa1cf0b82010-01-15 21:49:44843void TabContents::BlockTabContent(bool blocked) {
844 render_view_host()->set_ignore_input_events(blocked);
845 if (delegate_)
846 delegate_->SetTabContentBlocked(this, blocked);
847}
848
initial.commit09911bf2008-07-26 23:55:29849void TabContents::AddNewContents(TabContents* new_contents,
850 WindowOpenDisposition disposition,
851 const gfx::Rect& initial_pos,
[email protected]7e7414ae2010-01-26 20:19:29852 bool user_gesture) {
initial.commit09911bf2008-07-26 23:55:29853 if (!delegate_)
854 return;
855
[email protected]35f7d212009-04-29 21:19:27856 if ((disposition == NEW_POPUP) && !user_gesture &&
857 !CommandLine::ForCurrentProcess()->HasSwitch(
858 switches::kDisablePopupBlocking)) {
[email protected]2c4410d2009-05-06 23:46:22859 // Unrequested popups from normal pages are constrained unless they're in
[email protected]b6c874582009-05-08 19:38:31860 // the whitelist. The popup owner will handle checking this.
[email protected]7e7414ae2010-01-26 20:19:29861 delegate_->GetConstrainingContents(this)->AddPopup(
862 new_contents, initial_pos);
[email protected]b6c874582009-05-08 19:38:31863 } else {
[email protected]304f8792009-08-19 21:28:09864#if defined(OS_CHROMEOS)
865 if (disposition == NEW_POPUP) {
866 // If the popup is bigger than a given factor of the screen, then
867 // turn it into a foreground tab (on chrome os only)
868 GdkScreen* screen = gdk_screen_get_default();
869 int max_width = gdk_screen_get_width(screen) * kMaxWidthFactor;
870 int max_height = gdk_screen_get_height(screen) * kMaxHeightFactor;
871 if (initial_pos.width() > max_width ||
872 initial_pos.height() > max_height) {
873 disposition = NEW_FOREGROUND_TAB;
874 }
875 }
876#endif
877
[email protected]0aa55312008-10-17 21:53:08878 new_contents->DisassociateFromPopupCount();
initial.commit09911bf2008-07-26 23:55:29879 delegate_->AddNewContents(this, new_contents, disposition, initial_pos,
880 user_gesture);
[email protected]7f37dd92009-09-15 16:35:49881 NotificationService::current()->Notify(
882 NotificationType::TAB_ADDED,
883 Source<TabContentsDelegate>(delegate_),
884 Details<TabContents>(this));
initial.commit09911bf2008-07-26 23:55:29885 }
initial.commit09911bf2008-07-26 23:55:29886
[email protected]8cc8d492010-02-02 10:40:49887 // TODO(pkasting): Why is this necessary?
888 PopupNotificationVisibilityChanged(blocked_popups_ != NULL);
initial.commit09911bf2008-07-26 23:55:29889}
890
[email protected]bcd9dc42010-01-23 16:38:18891bool TabContents::ExecuteCode(int request_id, const std::string& extension_id,
[email protected]61f5a7b2009-12-22 22:21:20892 const std::vector<URLPattern>& host_permissions,
[email protected]20ad2692009-11-20 18:27:20893 bool is_js_code, const std::string& code_string,
894 bool all_frames) {
[email protected]ebd0eae72010-02-16 23:50:51895 RenderViewHost* host = render_view_host();
896 if (!host)
897 return false;
898
899 return host->Send(new ViewMsg_ExecuteCode(host->routing_id(),
900 ViewMsg_ExecuteCode_Params(request_id, extension_id, host_permissions,
901 is_js_code, code_string, all_frames)));
[email protected]912256b32009-09-18 09:47:35902}
903
[email protected]96d185d2009-04-24 03:28:54904void TabContents::PopupNotificationVisibilityChanged(bool visible) {
[email protected]8cc8d492010-02-02 10:40:49905 if (is_being_destroyed_)
906 return;
907 if (!dont_notify_render_view_)
908 render_view_host()->PopupNotificationVisibilityChanged(visible);
[email protected]0de80162010-02-03 04:52:35909 if (delegate_)
910 delegate_->OnBlockedContentChange(this);
[email protected]96d185d2009-04-24 03:28:54911}
912
[email protected]5c9e97a2009-09-09 23:48:30913gfx::NativeView TabContents::GetContentNativeView() const {
[email protected]96d185d2009-04-24 03:28:54914 return view_->GetContentNativeView();
915}
916
917gfx::NativeView TabContents::GetNativeView() const {
918 return view_->GetNativeView();
919}
920
921void TabContents::GetContainerBounds(gfx::Rect *out) const {
922 view_->GetContainerBounds(out);
923}
924
925void TabContents::Focus() {
926 view_->Focus();
927}
928
[email protected]90daadb42009-06-08 21:27:28929void TabContents::FocusThroughTabTraversal(bool reverse) {
[email protected]7e383692009-06-12 19:14:54930 if (showing_interstitial_page()) {
931 render_manager_.interstitial_page()->FocusThroughTabTraversal(reverse);
932 return;
933 }
[email protected]96d185d2009-04-24 03:28:54934 render_view_host()->SetInitialFocus(reverse);
935}
936
937bool TabContents::FocusLocationBarByDefault() {
938 DOMUI* dom_ui = GetDOMUIForCurrentState();
939 if (dom_ui)
940 return dom_ui->focus_location_bar_by_default();
[email protected]3e3f0eb2009-06-22 18:33:43941 NavigationEntry* entry = controller_.GetActiveEntry();
[email protected]e0d481582009-09-15 21:06:25942 if (entry && entry->url() == GURL(chrome::kAboutBlankURL))
[email protected]3e3f0eb2009-06-22 18:33:43943 return true;
[email protected]96d185d2009-04-24 03:28:54944 return false;
945}
946
[email protected]616ed5a2008-11-21 22:27:24947void TabContents::AddInfoBar(InfoBarDelegate* delegate) {
948 // Look through the existing InfoBarDelegates we have for a match. If we've
949 // already got one that matches, then we don't add the new one.
[email protected]f86a07022008-11-25 01:06:05950 for (int i = 0; i < infobar_delegate_count(); ++i) {
[email protected]6d27a7b2009-12-18 23:25:45951 if (GetInfoBarDelegateAt(i)->EqualsDelegate(delegate)) {
952 // Tell the new infobar to close so that it can clean itself up.
953 delegate->InfoBarClosed();
[email protected]616ed5a2008-11-21 22:27:24954 return;
[email protected]6d27a7b2009-12-18 23:25:45955 }
[email protected]616ed5a2008-11-21 22:27:24956 }
957
958 infobar_delegates_.push_back(delegate);
[email protected]bfd04a62009-02-01 18:16:56959 NotificationService::current()->Notify(
960 NotificationType::TAB_CONTENTS_INFOBAR_ADDED,
961 Source<TabContents>(this),
962 Details<InfoBarDelegate>(delegate));
[email protected]616ed5a2008-11-21 22:27:24963
964 // Add ourselves as an observer for navigations the first time a delegate is
965 // added. We use this notification to expire InfoBars that need to expire on
966 // page transitions.
967 if (infobar_delegates_.size() == 1) {
[email protected]bfd04a62009-02-01 18:16:56968 registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
[email protected]ce3fa3c2009-04-20 19:55:57969 Source<NavigationController>(&controller_));
[email protected]616ed5a2008-11-21 22:27:24970 }
971}
972
973void TabContents::RemoveInfoBar(InfoBarDelegate* delegate) {
974 std::vector<InfoBarDelegate*>::iterator it =
975 find(infobar_delegates_.begin(), infobar_delegates_.end(), delegate);
976 if (it != infobar_delegates_.end()) {
977 InfoBarDelegate* delegate = *it;
[email protected]bfd04a62009-02-01 18:16:56978 NotificationService::current()->Notify(
979 NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
980 Source<TabContents>(this),
981 Details<InfoBarDelegate>(delegate));
[email protected]f86a07022008-11-25 01:06:05982 infobar_delegates_.erase(it);
[email protected]616ed5a2008-11-21 22:27:24983
[email protected]6a02963e2009-01-06 16:58:03984 // Remove ourselves as an observer if we are tracking no more InfoBars.
985 if (infobar_delegates_.empty()) {
[email protected]bfd04a62009-02-01 18:16:56986 registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
[email protected]ce3fa3c2009-04-20 19:55:57987 Source<NavigationController>(&controller_));
[email protected]6a02963e2009-01-06 16:58:03988 }
[email protected]616ed5a2008-11-21 22:27:24989 }
990}
[email protected]3edd9522009-03-04 22:19:41991
[email protected]f81821c2009-08-07 01:29:47992void TabContents::ReplaceInfoBar(InfoBarDelegate* old_delegate,
993 InfoBarDelegate* new_delegate) {
994 std::vector<InfoBarDelegate*>::iterator it =
995 find(infobar_delegates_.begin(), infobar_delegates_.end(), old_delegate);
996 DCHECK(it != infobar_delegates_.end());
997
998 // Notify the container about the change of plans.
999 scoped_ptr<std::pair<InfoBarDelegate*, InfoBarDelegate*> > details(
1000 new std::pair<InfoBarDelegate*, InfoBarDelegate*>(
1001 old_delegate, new_delegate));
1002 NotificationService::current()->Notify(
1003 NotificationType::TAB_CONTENTS_INFOBAR_REPLACED,
1004 Source<TabContents>(this),
1005 Details<std::pair<InfoBarDelegate*, InfoBarDelegate*> >(details.get()));
1006
1007 // Remove the old one.
1008 infobar_delegates_.erase(it);
1009
1010 // Add the new one.
1011 infobar_delegates_.push_back(new_delegate);
1012}
1013
[email protected]20ede072009-10-06 00:28:351014bool TabContents::ShouldShowBookmarkBar() {
[email protected]aa9196f2009-10-22 16:20:271015 if (showing_interstitial_page())
1016 return false;
1017
[email protected]96d185d2009-04-24 03:28:541018 // See GetDOMUIForCurrentState() comment for more info. This case is very
1019 // similar, but for non-first loads, we want to use the committed entry. This
1020 // is so the bookmarks bar disappears at the same time the page does.
1021 if (controller_.GetLastCommittedEntry()) {
1022 // Not the first load, always use the committed DOM UI.
1023 if (render_manager_.dom_ui())
1024 return render_manager_.dom_ui()->force_bookmark_bar_visible();
1025 return false; // Default.
1026 }
1027
1028 // When it's the first load, we know either the pending one or the committed
1029 // one will have the DOM UI in it (see GetDOMUIForCurrentState), and only one
1030 // of them will be valid, so we can just check both.
1031 if (render_manager_.pending_dom_ui())
1032 return render_manager_.pending_dom_ui()->force_bookmark_bar_visible();
1033 if (render_manager_.dom_ui())
1034 return render_manager_.dom_ui()->force_bookmark_bar_visible();
1035 return false; // Default.
1036}
1037
[email protected]d8f16ae2009-08-30 03:47:261038bool TabContents::IsExtensionShelfAlwaysVisible() {
1039 // See GetDOMUIForCurrentState() comment for more info. This case is very
1040 // similar, but for non-first loads, we want to use the committed entry. This
1041 // is so the bookmarks bar disappears at the same time the page does.
1042 if (controller_.GetLastCommittedEntry()) {
1043 // Not the first load, always use the committed DOM UI.
1044 if (render_manager_.dom_ui())
1045 return render_manager_.dom_ui()->force_extension_shelf_visible();
1046 return false; // Default.
1047 }
1048
1049 // When it's the first load, we know either the pending one or the committed
1050 // one will have the DOM UI in it (see GetDOMUIForCurrentState), and only one
1051 // of them will be valid, so we can just check both.
1052 if (render_manager_.pending_dom_ui())
1053 return render_manager_.pending_dom_ui()->force_extension_shelf_visible();
1054 if (render_manager_.dom_ui())
1055 return render_manager_.dom_ui()->force_extension_shelf_visible();
1056 return false; // Default.
1057}
1058
[email protected]3edd9522009-03-04 22:19:411059void TabContents::ToolbarSizeChanged(bool is_animating) {
1060 TabContentsDelegate* d = delegate();
1061 if (d)
1062 d->ToolbarSizeChanged(this, is_animating);
1063}
[email protected]616ed5a2008-11-21 22:27:241064
[email protected]fc6fb7fb2009-11-07 02:35:041065bool TabContents::CanDownload(int request_id) {
1066 TabContentsDelegate* d = delegate();
1067 if (d)
1068 return d->CanDownload(request_id);
1069 return true;
1070}
1071
[email protected]d5f942ba2008-09-26 19:30:341072void TabContents::OnStartDownload(DownloadItem* download) {
1073 DCHECK(download);
[email protected]d5f942ba2008-09-26 19:30:341074
1075 // Download in a constrained popup is shown in the tab that opened it.
[email protected]b6c874582009-05-08 19:38:311076 TabContents* tab_contents = delegate()->GetConstrainingContents(this);
[email protected]d5f942ba2008-09-26 19:30:341077
[email protected]59560e0b2009-06-04 03:30:221078 if (tab_contents && tab_contents->delegate())
1079 tab_contents->delegate()->OnStartDownload(download);
[email protected]3edd9522009-03-04 22:19:411080}
[email protected]3edd9522009-03-04 22:19:411081
[email protected]d5f942ba2008-09-26 19:30:341082void TabContents::WillClose(ConstrainedWindow* window) {
1083 ConstrainedWindowList::iterator it =
1084 find(child_windows_.begin(), child_windows_.end(), window);
[email protected]fa1cf0b82010-01-15 21:49:441085 bool removed_topmost_window = it == child_windows_.begin();
[email protected]d5f942ba2008-09-26 19:30:341086 if (it != child_windows_.end())
1087 child_windows_.erase(it);
[email protected]fa1cf0b82010-01-15 21:49:441088 if (removed_topmost_window && child_windows_.size() > 0) {
1089 child_windows_[0]->ShowConstrainedWindow();
1090 BlockTabContent(true);
1091 } else {
1092 BlockTabContent(false);
1093 }
[email protected]66ba4932009-06-04 19:22:131094}
[email protected]d5f942ba2008-09-26 19:30:341095
[email protected]66ba4932009-06-04 19:22:131096void TabContents::WillCloseBlockedPopupContainer(
1097 BlockedPopupContainer* container) {
1098 DCHECK(blocked_popups_ == container);
1099 blocked_popups_ = NULL;
[email protected]8cc8d492010-02-02 10:40:491100 PopupNotificationVisibilityChanged(false);
[email protected]d5f942ba2008-09-26 19:30:341101}
1102
[email protected]d5f942ba2008-09-26 19:30:341103void TabContents::DidMoveOrResize(ConstrainedWindow* window) {
[email protected]332af7732009-03-11 13:21:351104#if defined(OS_WIN)
[email protected]92edc472009-02-10 20:32:061105 UpdateWindow(GetNativeView());
[email protected]332af7732009-03-11 13:21:351106#endif
[email protected]d5f942ba2008-09-26 19:30:341107}
1108
[email protected]c1dc9f132009-11-20 23:13:211109void TabContents::StartFinding(string16 search_string,
[email protected]e491f1c2009-05-22 20:28:121110 bool forward_direction,
1111 bool case_sensitive) {
[email protected]c1dc9f132009-11-20 23:13:211112 // If search_string is empty, it means FindNext was pressed with a keyboard
[email protected]6e95706d2009-04-23 22:55:011113 // shortcut so unless we have something to search for we return early.
[email protected]c1dc9f132009-11-20 23:13:211114 if (search_string.empty() && find_text_.empty()) {
[email protected]87fae512009-12-11 02:20:211115 // Try the last thing we searched for on this tab, then the last thing
1116 // searched for on any tab.
1117 if (!previous_find_text_.empty())
1118 search_string = previous_find_text_;
1119 else if (!last_search_prepopulate_text_->empty())
1120 search_string = *last_search_prepopulate_text_;
1121 else
[email protected]e491f1c2009-05-22 20:28:121122 return;
[email protected]e491f1c2009-05-22 20:28:121123 }
[email protected]6e95706d2009-04-23 22:55:011124
[email protected]101c90e2009-10-26 21:14:441125 // Keep track of the previous search.
1126 previous_find_text_ = find_text_;
1127
[email protected]6e95706d2009-04-23 22:55:011128 // This is a FindNext operation if we are searching for the same text again,
1129 // or if the passed in search text is empty (FindNext keyboard shortcut). The
1130 // exception to this is if the Find was aborted (then we don't want FindNext
1131 // because the highlighting has been cleared and we need it to reappear). We
1132 // therefore treat FindNext after an aborted Find operation as a full fledged
1133 // Find.
[email protected]c1dc9f132009-11-20 23:13:211134 bool find_next = (find_text_ == search_string || search_string.empty()) &&
[email protected]e491f1c2009-05-22 20:28:121135 (last_search_case_sensitive_ == case_sensitive) &&
[email protected]6e95706d2009-04-23 22:55:011136 !find_op_aborted_;
1137 if (!find_next)
1138 current_find_request_id_ = find_request_id_counter_++;
1139
[email protected]c1dc9f132009-11-20 23:13:211140 if (!search_string.empty())
1141 find_text_ = search_string;
[email protected]e491f1c2009-05-22 20:28:121142 last_search_case_sensitive_ = case_sensitive;
[email protected]6e95706d2009-04-23 22:55:011143
1144 find_op_aborted_ = false;
1145
1146 // Keep track of what the last search was across the tabs.
[email protected]c1dc9f132009-11-20 23:13:211147 *last_search_prepopulate_text_ = find_text_;
[email protected]6e95706d2009-04-23 22:55:011148 render_view_host()->StartFinding(current_find_request_id_,
1149 find_text_,
1150 forward_direction,
[email protected]e491f1c2009-05-22 20:28:121151 case_sensitive,
[email protected]6e95706d2009-04-23 22:55:011152 find_next);
1153}
1154
1155void TabContents::StopFinding(bool clear_selection) {
[email protected]2d2dffc2009-06-09 21:41:001156 // When |clear_selection| is true, it means the find string has been cleared
1157 // by the user, but the UI has not been dismissed.
1158 if (!clear_selection)
1159 find_ui_active_ = false;
[email protected]87fae512009-12-11 02:20:211160 previous_find_text_ = find_text_;
[email protected]101c90e2009-10-26 21:14:441161 find_text_.clear();
[email protected]6e95706d2009-04-23 22:55:011162 find_op_aborted_ = true;
[email protected]e491f1c2009-05-22 20:28:121163 last_search_result_ = FindNotificationDetails();
[email protected]6e95706d2009-04-23 22:55:011164 render_view_host()->StopFinding(clear_selection);
1165}
1166
[email protected]420ae012009-04-24 05:16:321167void TabContents::OnSavePage() {
1168 // If we can not save the page, try to download it.
1169 if (!SavePackage::IsSavableContents(contents_mime_type())) {
1170 DownloadManager* dlm = profile()->GetDownloadManager();
1171 const GURL& current_page_url = GetURL();
1172 if (dlm && current_page_url.is_valid())
[email protected]d82ed61e2009-06-16 02:46:221173 dlm->DownloadUrl(current_page_url, GURL(), "", this);
[email protected]420ae012009-04-24 05:16:321174 return;
1175 }
1176
1177 Stop();
1178
1179 // Create the save package and possibly prompt the user for the name to save
1180 // the page as. The user prompt is an asynchronous operation that runs on
1181 // another thread.
[email protected]d82ed61e2009-06-16 02:46:221182 save_package_ = new SavePackage(this);
[email protected]420ae012009-04-24 05:16:321183 save_package_->GetSaveInfo();
1184}
1185
1186// Used in automated testing to bypass prompting the user for file names.
1187// Instead, the names and paths are hard coded rather than running them through
1188// file name sanitation and extension / mime checking.
[email protected]828cabe2009-09-26 22:47:111189bool TabContents::SavePage(const FilePath& main_file, const FilePath& dir_path,
[email protected]420ae012009-04-24 05:16:321190 SavePackage::SavePackageType save_type) {
1191 // Stop the page from navigating.
1192 Stop();
1193
[email protected]828cabe2009-09-26 22:47:111194 save_package_ = new SavePackage(this, save_type, main_file, dir_path);
[email protected]cdf6cc82009-08-04 21:48:591195 return save_package_->Init();
[email protected]420ae012009-04-24 05:16:321196}
1197
[email protected]89d6e6e2009-12-03 23:06:511198void TabContents::EmailPageLocation() {
1199 std::string title = EscapeQueryParamValue(UTF16ToUTF8(GetTitle()), false);
1200 std::string page_url = EscapeQueryParamValue(GetURL().spec(), false);
1201 std::string mailto = std::string("mailto:?subject=Fwd:%20") +
1202 title + "&body=%0A%0A" + page_url;
1203 platform_util::OpenExternal(GURL(mailto));
1204}
1205
[email protected]420ae012009-04-24 05:16:321206void TabContents::PrintPreview() {
1207 // We don't show the print preview yet, only the print dialog.
1208 PrintNow();
1209}
1210
1211bool TabContents::PrintNow() {
1212 // We can't print interstitial page for now.
1213 if (showing_interstitial_page())
1214 return false;
1215
1216 return render_view_host()->PrintPages();
1217}
1218
[email protected]82270452009-06-19 15:58:011219void TabContents::PrintingDone(int document_cookie, bool success) {
1220 render_view_host()->PrintingDone(document_cookie, success);
1221}
1222
[email protected]420ae012009-04-24 05:16:321223bool TabContents::IsActiveEntry(int32 page_id) {
1224 NavigationEntry* active_entry = controller_.GetActiveEntry();
1225 return (active_entry != NULL &&
1226 active_entry->site_instance() == GetSiteInstance() &&
1227 active_entry->page_id() == page_id);
1228}
1229
[email protected]b2fe07d12010-02-09 14:38:081230void TabContents::SetOverrideEncoding(const std::string& encoding) {
[email protected]8cb5d5b2010-02-09 11:36:161231 set_encoding(encoding);
1232 render_view_host()->SetPageEncoding(encoding);
1233}
1234
[email protected]b2fe07d12010-02-09 14:38:081235void TabContents::ResetOverrideEncoding() {
[email protected]8cb5d5b2010-02-09 11:36:161236 reset_encoding();
1237 render_view_host()->ResetPageEncodingToDefault();
1238}
1239
1240void TabContents::WindowMoveOrResizeStarted() {
1241 render_view_host()->WindowMoveOrResizeStarted();
1242}
1243
[email protected]3f8eb7f2009-10-02 23:58:051244void TabContents::LogNewTabTime(const std::string& event_name) {
1245 // Not all new tab pages get timed. In those cases, we don't have a
1246 // new_tab_start_time_.
1247 if (new_tab_start_time_.is_null())
1248 return;
1249
1250 base::TimeDelta duration = base::TimeTicks::Now() - new_tab_start_time_;
[email protected]84abba62009-10-07 17:01:441251 MetricEventDurationDetails details(event_name,
1252 static_cast<int>(duration.InMilliseconds()));
1253
[email protected]7ab1e7d62009-10-14 23:32:011254 if (event_name == "Tab.NewTabScriptStart") {
1255 UMA_HISTOGRAM_TIMES("Tab.NewTabScriptStart", duration);
1256 } else if (event_name == "Tab.NewTabDOMContentLoaded") {
1257 UMA_HISTOGRAM_TIMES("Tab.NewTabDOMContentLoaded", duration);
1258 } else if (event_name == "Tab.NewTabOnload") {
1259 UMA_HISTOGRAM_TIMES("Tab.NewTabOnload", duration);
[email protected]3f8eb7f2009-10-02 23:58:051260 // The new tab page has finished loading; reset it.
1261 new_tab_start_time_ = base::TimeTicks();
[email protected]84abba62009-10-07 17:01:441262 } else {
1263 NOTREACHED();
[email protected]3f8eb7f2009-10-02 23:58:051264 }
[email protected]84abba62009-10-07 17:01:441265 NotificationService::current()->Notify(
1266 NotificationType::METRIC_EVENT_DURATION,
1267 Source<TabContents>(this),
1268 Details<MetricEventDurationDetails>(&details));
[email protected]3f8eb7f2009-10-02 23:58:051269}
1270
[email protected]7ab1e7d62009-10-14 23:32:011271void TabContents::OnCloseStarted() {
1272 if (tab_close_start_time_.is_null())
1273 tab_close_start_time_ = base::TimeTicks::Now();
1274}
1275
[email protected]c37e3b62010-01-22 00:15:171276TabContents* TabContents::CloneAndMakePhantom() {
[email protected]c37e3b62010-01-22 00:15:171277 TabNavigation tab_nav;
[email protected]df72ac72010-02-06 00:43:161278
1279 NavigationEntry* entry = controller().GetActiveEntry();
1280 if (app_extension_)
1281 tab_nav.set_url(app_extension_->app_launch_url());
1282 else if (entry)
1283 tab_nav.SetFromNavigationEntry(*entry);
1284
[email protected]c37e3b62010-01-22 00:15:171285 std::vector<TabNavigation> navigations;
1286 navigations.push_back(tab_nav);
1287
1288 TabContents* new_contents =
1289 new TabContents(profile(), NULL, MSG_ROUTING_NONE, NULL);
[email protected]3b355642010-02-05 16:01:491290 new_contents->SetAppExtension(app_extension_);
[email protected]c37e3b62010-01-22 00:15:171291 new_contents->controller().RestoreFromState(navigations, 0, false);
[email protected]c37e3b62010-01-22 00:15:171292
[email protected]df72ac72010-02-06 00:43:161293 if (!app_extension_ && entry)
1294 new_contents->controller().GetActiveEntry()->favicon() = entry->favicon();
1295
[email protected]c37e3b62010-01-22 00:15:171296 return new_contents;
1297}
1298
[email protected]0de80162010-02-03 04:52:351299// Resets the |content_blocked_| array.
1300void TabContents::ClearBlockedContentSettings() {
[email protected]15cf526b2010-02-12 06:33:491301 for (size_t i = 0; i < arraysize(content_blocked_); ++i)
[email protected]0de80162010-02-03 04:52:351302 content_blocked_[i] = false;
1303}
1304
[email protected]96d185d2009-04-24 03:28:541305// Notifies the RenderWidgetHost instance about the fact that the page is
1306// loading, or done loading and calls the base implementation.
1307void TabContents::SetIsLoading(bool is_loading,
1308 LoadNotificationDetails* details) {
1309 if (is_loading == is_loading_)
1310 return;
1311
1312 if (!is_loading) {
1313 load_state_ = net::LOAD_STATE_IDLE;
1314 load_state_host_.clear();
[email protected]094e5b22009-09-25 04:23:561315 upload_size_ = 0;
1316 upload_position_ = 0;
[email protected]96d185d2009-04-24 03:28:541317 }
1318
1319 render_manager_.SetIsLoading(is_loading);
1320
1321 is_loading_ = is_loading;
1322 waiting_for_response_ = is_loading;
1323
1324 if (delegate_)
1325 delegate_->LoadingStateChanged(this);
[email protected]329581b2009-04-28 06:52:351326 NotifyNavigationStateChanged(INVALIDATE_LOAD);
[email protected]96d185d2009-04-24 03:28:541327
1328 NotificationType type = is_loading ? NotificationType::LOAD_START :
1329 NotificationType::LOAD_STOP;
[email protected]ce5c4502009-05-06 16:46:111330 NotificationDetails det = NotificationService::NoDetails();
[email protected]96d185d2009-04-24 03:28:541331 if (details)
1332 det = Details<LoadNotificationDetails>(details);
1333 NotificationService::current()->Notify(type,
1334 Source<NavigationController>(&controller_),
1335 det);
1336}
1337
[email protected]b6c874582009-05-08 19:38:311338void TabContents::AddPopup(TabContents* new_contents,
[email protected]7e7414ae2010-01-26 20:19:291339 const gfx::Rect& initial_pos) {
[email protected]8cc8d492010-02-02 10:40:491340 GURL url(GetURL());
1341 if (url.is_valid() &&
1342 profile()->GetHostContentSettingsMap()->GetContentSetting(
[email protected]da0c8e92010-02-09 23:25:491343 url, CONTENT_SETTINGS_TYPE_POPUPS) == CONTENT_SETTING_ALLOW) {
[email protected]8cc8d492010-02-02 10:40:491344 AddNewContents(new_contents, NEW_POPUP, initial_pos, true);
1345 } else {
1346 if (!blocked_popups_)
1347 blocked_popups_ = new BlockedPopupContainer(this);
1348 blocked_popups_->AddTabContents(new_contents, initial_pos);
1349 }
[email protected]b9681312008-11-07 00:08:261350}
[email protected]616ed5a2008-11-21 22:27:241351
1352namespace {
1353bool TransitionIsReload(PageTransition::Type transition) {
1354 return PageTransition::StripQualifier(transition) == PageTransition::RELOAD;
1355}
1356}
1357
1358void TabContents::ExpireInfoBars(
1359 const NavigationController::LoadCommittedDetails& details) {
1360 // Only hide InfoBars when the user has done something that makes the main
1361 // frame load. We don't want various automatic or subframe navigations making
1362 // it disappear.
1363 if (!details.is_user_initiated_main_frame_load())
1364 return;
1365
[email protected]f86a07022008-11-25 01:06:051366 for (int i = infobar_delegate_count() - 1; i >= 0; --i) {
[email protected]616ed5a2008-11-21 22:27:241367 InfoBarDelegate* delegate = GetInfoBarDelegateAt(i);
[email protected]f86a07022008-11-25 01:06:051368 if (delegate->ShouldExpire(details))
[email protected]616ed5a2008-11-21 22:27:241369 RemoveInfoBar(delegate);
[email protected]616ed5a2008-11-21 22:27:241370 }
1371}
[email protected]fdd61c62009-04-22 19:22:571372
[email protected]96d185d2009-04-24 03:28:541373DOMUI* TabContents::GetDOMUIForCurrentState() {
1374 // When there is a pending navigation entry, we want to use the pending DOMUI
1375 // that goes along with it to control the basic flags. For example, we want to
1376 // show the pending URL in the URL bar, so we want the display_url flag to
1377 // be from the pending entry.
1378 //
1379 // The confusion comes because there are multiple possibilities for the
1380 // initial load in a tab as a side effect of the way the RenderViewHostManager
1381 // works.
1382 //
1383 // - For the very first tab the load looks "normal". The new tab DOM UI is
1384 // the pending one, and we want it to apply here.
1385 //
1386 // - For subsequent new tabs, they'll get a new SiteInstance which will then
1387 // get switched to the one previously associated with the new tab pages.
1388 // This switching will cause the manager to commit the RVH/DOMUI. So we'll
1389 // have a committed DOM UI in this case.
1390 //
1391 // This condition handles all of these cases:
1392 //
1393 // - First load in first tab: no committed nav entry + pending nav entry +
1394 // pending dom ui:
1395 // -> Use pending DOM UI if any.
1396 //
1397 // - First load in second tab: no committed nav entry + pending nav entry +
1398 // no pending DOM UI:
1399 // -> Use the committed DOM UI if any.
1400 //
1401 // - Second navigation in any tab: committed nav entry + pending nav entry:
1402 // -> Use pending DOM UI if any.
1403 //
1404 // - Normal state with no load: committed nav entry + no pending nav entry:
1405 // -> Use committed DOM UI.
1406 if (controller_.pending_entry() &&
1407 (controller_.GetLastCommittedEntry() ||
1408 render_manager_.pending_dom_ui()))
1409 return render_manager_.pending_dom_ui();
1410 return render_manager_.dom_ui();
1411}
[email protected]420ae012009-04-24 05:16:321412
1413void TabContents::DidNavigateMainFramePostCommit(
1414 const NavigationController::LoadCommittedDetails& details,
1415 const ViewHostMsg_FrameNavigate_Params& params) {
[email protected]c2e74fe82009-09-03 17:57:441416 if (opener_dom_ui_type_ != DOMUIFactory::kNoDOMUI) {
1417 // If this is a window.open navigation, use the same DOMUI as the renderer
1418 // that opened the window, as long as both renderers have the same
1419 // privileges.
1420 if (opener_dom_ui_type_ == DOMUIFactory::GetDOMUIType(GetURL())) {
1421 DOMUI* dom_ui = DOMUIFactory::CreateDOMUIForURL(this, GetURL());
1422 // dom_ui might be NULL if the URL refers to a non-existent extension.
1423 if (dom_ui) {
1424 render_manager_.SetDOMUIPostCommit(dom_ui);
1425 dom_ui->RenderViewCreated(render_view_host());
1426 }
1427 }
1428 opener_dom_ui_type_ = DOMUIFactory::kNoDOMUI;
1429 }
1430
[email protected]420ae012009-04-24 05:16:321431 if (details.is_user_initiated_main_frame_load()) {
1432 // Clear the status bubble. This is a workaround for a bug where WebKit
1433 // doesn't let us know that the cursor left an element during a
1434 // transition (this is also why the mouse cursor remains as a hand after
1435 // clicking on a link); see bugs 1184641 and 980803. We don't want to
1436 // clear the bubble when a user navigates to a named anchor in the same
1437 // page.
1438 UpdateTargetURL(details.entry->page_id(), GURL());
1439
1440 // UpdateHelpersForDidNavigate will handle the case where the password_form
1441 // origin is valid.
1442 // TODO(brettw) bug 1343111: Password manager stuff in here needs to be
1443 // cleaned up and covered by tests.
1444 if (!params.password_form.origin.is_valid())
1445 GetPasswordManager()->DidNavigate();
1446 }
1447
1448 // The keyword generator uses the navigation entries, so must be called after
1449 // the commit.
1450 GenerateKeywordIfNecessary(params);
1451
1452 // Allow the new page to set the title again.
1453 received_page_title_ = false;
1454
1455 // Get the favicon, either from history or request it from the net.
1456 fav_icon_helper_.FetchFavIcon(details.entry->url());
1457
[email protected]0de80162010-02-03 04:52:351458 // Clear all page actions, blocked content notifications and browser actions
1459 // for this tab, unless this is an in-page navigation.
[email protected]92c6f9b92009-10-24 04:35:081460 url_canon::Replacements<char> replacements;
1461 replacements.ClearRef();
1462 if (params.url.ReplaceComponents(replacements) !=
1463 params.referrer.ReplaceComponents(replacements)) {
[email protected]92c6f9b92009-10-24 04:35:081464 ExtensionsService* service = profile()->GetExtensionsService();
1465 if (service) {
1466 for (size_t i = 0; i < service->extensions()->size(); ++i) {
[email protected]5d246db22009-10-27 06:17:571467 ExtensionAction* browser_action =
[email protected]92c6f9b92009-10-24 04:35:081468 service->extensions()->at(i)->browser_action();
[email protected]56ce6e52009-10-27 00:10:521469 if (browser_action) {
1470 browser_action->ClearAllValuesForTab(controller().session_id().id());
1471 NotificationService::current()->Notify(
1472 NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
[email protected]5d246db22009-10-27 06:17:571473 Source<ExtensionAction>(browser_action),
[email protected]56ce6e52009-10-27 00:10:521474 NotificationService::NoDetails());
1475 }
[email protected]92c6f9b92009-10-24 04:35:081476
[email protected]5d246db22009-10-27 06:17:571477 ExtensionAction* page_action =
[email protected]56ce6e52009-10-27 00:10:521478 service->extensions()->at(i)->page_action();
1479 if (page_action) {
1480 page_action->ClearAllValuesForTab(controller().session_id().id());
1481 PageActionStateChanged();
1482 }
[email protected]92c6f9b92009-10-24 04:35:081483 }
[email protected]aece2c7f2009-08-27 20:43:171484 }
[email protected]0de80162010-02-03 04:52:351485
1486 // Close blocked popups.
1487 if (blocked_popups_) {
1488 AutoReset auto_reset(&dont_notify_render_view_, true);
1489 blocked_popups_->Destroy();
1490 }
1491
1492 // Clear "blocked" flags.
1493 ClearBlockedContentSettings();
1494 if (delegate_)
1495 delegate_->OnBlockedContentChange(this);
[email protected]aece2c7f2009-08-27 20:43:171496 }
[email protected]ce5c4502009-05-06 16:46:111497
[email protected]8cc8d492010-02-02 10:40:491498 // Close constrained windows if necessary.
1499 if (!net::RegistryControlledDomainService::SameDomainOrHost(
1500 details.previous_url, details.entry->url()))
1501 CloseConstrainedWindows();
1502
[email protected]420ae012009-04-24 05:16:321503 // Update the starred state.
1504 UpdateStarredStateForCurrentURL();
1505}
1506
1507void TabContents::DidNavigateAnyFramePostCommit(
1508 RenderViewHost* render_view_host,
1509 const NavigationController::LoadCommittedDetails& details,
1510 const ViewHostMsg_FrameNavigate_Params& params) {
1511 // If we navigate, start showing messages again. This does nothing to prevent
1512 // a malicious script from spamming messages, since the script could just
1513 // reload the page to stop blocking.
1514 suppress_javascript_messages_ = false;
1515
[email protected]420ae012009-04-24 05:16:321516 // Notify the password manager of the navigation or form submit.
1517 // TODO(brettw) bug 1343111: Password manager stuff in here needs to be
1518 // cleaned up and covered by tests.
1519 if (params.password_form.origin.is_valid())
1520 GetPasswordManager()->ProvisionallySavePassword(params.password_form);
[email protected]3b1c1812010-02-12 21:53:551521
1522 // Let the LanguageState clear its state.
[email protected]575c4e172010-02-16 18:46:561523 language_state_.DidNavigate(details.entry->transition_type() ==
1524 PageTransition::RELOAD);
[email protected]420ae012009-04-24 05:16:321525}
1526
[email protected]8cc8d492010-02-02 10:40:491527void TabContents::CloseConstrainedWindows() {
1528 // Clear out any constrained windows since we are leaving this page entirely.
[email protected]420ae012009-04-24 05:16:321529 // We use indices instead of iterators in case CloseWindow does something
1530 // that may invalidate an iterator.
1531 int size = static_cast<int>(child_windows_.size());
1532 for (int i = size - 1; i >= 0; --i) {
1533 ConstrainedWindow* window = child_windows_[i];
[email protected]fa1cf0b82010-01-15 21:49:441534 if (window) {
[email protected]420ae012009-04-24 05:16:321535 window->CloseConstrainedWindow();
[email protected]fa1cf0b82010-01-15 21:49:441536 BlockTabContent(false);
1537 }
[email protected]420ae012009-04-24 05:16:321538 }
1539}
1540
1541void TabContents::UpdateStarredStateForCurrentURL() {
1542 BookmarkModel* model = profile()->GetBookmarkModel();
1543 const bool old_state = is_starred_;
1544 is_starred_ = (model && model->IsBookmarked(GetURL()));
1545
1546 if (is_starred_ != old_state && delegate())
1547 delegate()->URLStarredChanged(this, is_starred_);
1548}
1549
1550void TabContents::UpdateAlternateErrorPageURL() {
1551 GURL url = GetAlternateErrorPageURL();
1552 render_view_host()->SetAlternateErrorPageURL(url);
1553}
1554
1555void TabContents::UpdateWebPreferences() {
1556 render_view_host()->UpdateWebPreferences(GetWebkitPrefs());
1557}
1558
1559void TabContents::UpdateMaxPageIDIfNecessary(SiteInstance* site_instance,
1560 RenderViewHost* rvh) {
1561 // If we are creating a RVH for a restored controller, then we might
1562 // have more page IDs than the SiteInstance's current max page ID. We must
1563 // make sure that the max page ID is larger than any restored page ID.
1564 // Note that it is ok for conflicting page IDs to exist in another tab
1565 // (i.e., NavigationController), but if any page ID is larger than the max,
1566 // the back/forward list will get confused.
1567 int max_restored_page_id = controller_.max_restored_page_id();
1568 if (max_restored_page_id > 0) {
1569 int curr_max_page_id = site_instance->max_page_id();
1570 if (max_restored_page_id > curr_max_page_id) {
1571 // Need to update the site instance immediately.
1572 site_instance->UpdateMaxPageID(max_restored_page_id);
1573
1574 // Also tell the renderer to update its internal representation. We
1575 // need to reserve enough IDs to make all restored page IDs less than
1576 // the max.
1577 if (curr_max_page_id < 0)
1578 curr_max_page_id = 0;
1579 rvh->ReservePageIDRange(max_restored_page_id - curr_max_page_id);
1580 }
1581 }
1582}
1583
1584void TabContents::UpdateHistoryForNavigation(
[email protected]ebe89e062009-08-13 23:16:541585 const GURL& virtual_url,
[email protected]befd8d822009-07-01 04:51:471586 const NavigationController::LoadCommittedDetails& details,
[email protected]420ae012009-04-24 05:16:321587 const ViewHostMsg_FrameNavigate_Params& params) {
1588 if (profile()->IsOffTheRecord())
1589 return;
1590
1591 // Add to history service.
1592 HistoryService* hs = profile()->GetHistoryService(Profile::IMPLICIT_ACCESS);
1593 if (hs) {
1594 if (PageTransition::IsMainFrame(params.transition) &&
[email protected]ebe89e062009-08-13 23:16:541595 virtual_url != params.url) {
1596 // Hack on the "virtual" URL so that it will appear in history. For some
[email protected]420ae012009-04-24 05:16:321597 // types of URLs, we will display a magic URL that is different from where
1598 // the page is actually navigated. We want the user to see in history
[email protected]ebe89e062009-08-13 23:16:541599 // what they saw in the URL bar, so we add the virtual URL as a redirect.
1600 // This only applies to the main frame, as the virtual URL doesn't apply
[email protected]420ae012009-04-24 05:16:321601 // to sub-frames.
1602 std::vector<GURL> redirects = params.redirects;
1603 if (!redirects.empty())
[email protected]ebe89e062009-08-13 23:16:541604 redirects.back() = virtual_url;
1605 hs->AddPage(virtual_url, this, params.page_id, params.referrer,
[email protected]befd8d822009-07-01 04:51:471606 params.transition, redirects, details.did_replace_entry);
[email protected]420ae012009-04-24 05:16:321607 } else {
1608 hs->AddPage(params.url, this, params.page_id, params.referrer,
[email protected]befd8d822009-07-01 04:51:471609 params.transition, params.redirects,
1610 details.did_replace_entry);
[email protected]420ae012009-04-24 05:16:321611 }
1612 }
1613}
1614
1615bool TabContents::UpdateTitleForEntry(NavigationEntry* entry,
1616 const std::wstring& title) {
1617 // For file URLs without a title, use the pathname instead. In the case of a
1618 // synthesized title, we don't want the update to count toward the "one set
1619 // per page of the title to history."
1620 std::wstring final_title;
1621 bool explicit_set;
1622 if (entry->url().SchemeIsFile() && title.empty()) {
1623 final_title = UTF8ToWide(entry->url().ExtractFileName());
1624 explicit_set = false; // Don't count synthetic titles toward the set limit.
1625 } else {
1626 TrimWhitespace(title, TRIM_ALL, &final_title);
1627 explicit_set = true;
1628 }
1629
1630 if (final_title == UTF16ToWideHack(entry->title()))
1631 return false; // Nothing changed, don't bother.
1632
1633 entry->set_title(WideToUTF16Hack(final_title));
1634
1635 // Update the history system for this page.
1636 if (!profile()->IsOffTheRecord() && !received_page_title_) {
1637 HistoryService* hs =
1638 profile()->GetHistoryService(Profile::IMPLICIT_ACCESS);
1639 if (hs)
[email protected]ebe89e062009-08-13 23:16:541640 hs->SetPageTitle(entry->virtual_url(), final_title);
[email protected]420ae012009-04-24 05:16:321641
1642 // Don't allow the title to be saved again for explicitly set ones.
1643 received_page_title_ = explicit_set;
1644 }
1645
1646 // Lastly, set the title for the view.
1647 view_->SetPageTitle(final_title);
1648
1649 return true;
1650}
1651
1652void TabContents::NotifySwapped() {
1653 // After sending out a swap notification, we need to send a disconnect
1654 // notification so that clients that pick up a pointer to |this| can NULL the
1655 // pointer. See Bug 1230284.
1656 notify_disconnection_ = true;
1657 NotificationService::current()->Notify(
[email protected]57c6a652009-05-04 07:58:341658 NotificationType::TAB_CONTENTS_SWAPPED,
[email protected]d82ed61e2009-06-16 02:46:221659 Source<TabContents>(this),
[email protected]420ae012009-04-24 05:16:321660 NotificationService::NoDetails());
1661}
1662
1663void TabContents::NotifyConnected() {
1664 notify_disconnection_ = true;
1665 NotificationService::current()->Notify(
[email protected]57c6a652009-05-04 07:58:341666 NotificationType::TAB_CONTENTS_CONNECTED,
[email protected]d82ed61e2009-06-16 02:46:221667 Source<TabContents>(this),
[email protected]420ae012009-04-24 05:16:321668 NotificationService::NoDetails());
1669}
1670
1671void TabContents::NotifyDisconnected() {
1672 if (!notify_disconnection_)
1673 return;
1674
1675 notify_disconnection_ = false;
1676 NotificationService::current()->Notify(
[email protected]57c6a652009-05-04 07:58:341677 NotificationType::TAB_CONTENTS_DISCONNECTED,
[email protected]d82ed61e2009-06-16 02:46:221678 Source<TabContents>(this),
[email protected]420ae012009-04-24 05:16:321679 NotificationService::NoDetails());
1680}
1681
1682void TabContents::GenerateKeywordIfNecessary(
1683 const ViewHostMsg_FrameNavigate_Params& params) {
1684 if (!params.searchable_form_url.is_valid())
1685 return;
1686
1687 if (profile()->IsOffTheRecord())
1688 return;
1689
1690 int last_index = controller_.last_committed_entry_index();
1691 // When there was no previous page, the last index will be 0. This is
1692 // normally due to a form submit that opened in a new tab.
1693 // TODO(brettw) bug 916126: we should support keywords when form submits
1694 // happen in new tabs.
1695 if (last_index <= 0)
1696 return;
1697 const NavigationEntry* previous_entry =
1698 controller_.GetEntryAtIndex(last_index - 1);
1699 if (IsFormSubmit(previous_entry)) {
1700 // Only generate a keyword if the previous page wasn't itself a form
1701 // submit.
1702 return;
1703 }
1704
1705 GURL keyword_url = previous_entry->user_typed_url().is_valid() ?
1706 previous_entry->user_typed_url() : previous_entry->url();
1707 std::wstring keyword =
1708 TemplateURLModel::GenerateKeyword(keyword_url, true); // autodetected
1709 if (keyword.empty())
1710 return;
1711
1712 TemplateURLModel* url_model = profile()->GetTemplateURLModel();
1713 if (!url_model)
1714 return;
1715
1716 if (!url_model->loaded()) {
1717 url_model->Load();
1718 return;
1719 }
1720
1721 const TemplateURL* current_url;
1722 std::wstring url = UTF8ToWide(params.searchable_form_url.spec());
1723 if (!url_model->CanReplaceKeyword(keyword, url, &current_url))
1724 return;
1725
1726 if (current_url) {
1727 if (current_url->originating_url().is_valid()) {
1728 // The existing keyword was generated from an OpenSearch description
1729 // document, don't regenerate.
1730 return;
1731 }
1732 url_model->Remove(current_url);
1733 }
1734 TemplateURL* new_url = new TemplateURL();
1735 new_url->set_keyword(keyword);
1736 new_url->set_short_name(keyword);
1737 new_url->SetURL(url, 0, 0);
1738 new_url->add_input_encoding(params.searchable_form_encoding);
1739 DCHECK(controller_.GetLastCommittedEntry());
1740 const GURL& favicon_url =
1741 controller_.GetLastCommittedEntry()->favicon().url();
1742 if (favicon_url.is_valid()) {
1743 new_url->SetFavIconURL(favicon_url);
1744 } else {
1745 // The favicon url isn't valid. This means there really isn't a favicon,
1746 // or the favicon url wasn't obtained before the load started. This assumes
1747 // the later.
1748 // TODO(sky): Need a way to set the favicon that doesn't involve generating
1749 // its url.
1750 new_url->SetFavIconURL(TemplateURL::GenerateFaviconURL(params.referrer));
1751 }
1752 new_url->set_safe_for_autoreplace(true);
1753 url_model->Add(new_url);
1754}
1755
[email protected]bf5c2ff392009-07-08 16:24:331756void TabContents::OnUserGesture() {
1757 // See comment in RenderViewHostDelegate::OnUserGesture as to why we do this.
1758 DownloadRequestManager* drm = g_browser_process->download_request_manager();
1759 if (drm)
1760 drm->OnUserGesture(this);
[email protected]e7eaedde2009-09-25 20:09:491761 ExternalProtocolHandler::OnUserGesture();
[email protected]bf5c2ff392009-07-08 16:24:331762 controller_.OnUserGesture();
1763}
1764
1765void TabContents::OnFindReply(int request_id,
1766 int number_of_matches,
1767 const gfx::Rect& selection_rect,
1768 int active_match_ordinal,
1769 bool final_update) {
[email protected]3ce7ced2009-07-24 18:52:421770 // Ignore responses for requests that have been aborted.
1771 if (find_op_aborted_)
1772 return;
1773
[email protected]bf5c2ff392009-07-08 16:24:331774 // Ignore responses for requests other than the one we have most recently
1775 // issued. That way we won't act on stale results when the user has
1776 // already typed in another query.
1777 if (request_id != current_find_request_id_)
1778 return;
1779
1780 if (number_of_matches == -1)
1781 number_of_matches = last_search_result_.number_of_matches();
1782 if (active_match_ordinal == -1)
1783 active_match_ordinal = last_search_result_.active_match_ordinal();
1784
1785 gfx::Rect selection = selection_rect;
1786 if (selection.IsEmpty())
1787 selection = last_search_result_.selection_rect();
1788
1789 // Notify the UI, automation and any other observers that a find result was
1790 // found.
1791 last_search_result_ = FindNotificationDetails(request_id, number_of_matches,
1792 selection, active_match_ordinal,
1793 final_update);
1794 NotificationService::current()->Notify(
1795 NotificationType::FIND_RESULT_AVAILABLE,
1796 Source<TabContents>(this),
1797 Details<FindNotificationDetails>(&last_search_result_));
1798}
1799
1800void TabContents::GoToEntryAtOffset(int offset) {
[email protected]f9cc4c452009-10-13 14:56:381801 if (!delegate_ || delegate_->OnGoToEntryOffset(offset))
1802 controller_.GoToOffset(offset);
[email protected]bf5c2ff392009-07-08 16:24:331803}
1804
1805void TabContents::GetHistoryListCount(int* back_list_count,
1806 int* forward_list_count) {
1807 int current_index = controller_.last_committed_entry_index();
1808 *back_list_count = current_index;
1809 *forward_list_count = controller_.entry_count() - current_index - 1;
1810}
1811
1812void TabContents::OnMissingPluginStatus(int status) {
1813#if defined(OS_WIN)
1814// TODO(PORT): pull in when plug-ins work
1815 GetPluginInstaller()->OnMissingPluginStatus(status);
1816#endif
1817}
1818
1819void TabContents::OnCrashedPlugin(const FilePath& plugin_path) {
[email protected]bf5c2ff392009-07-08 16:24:331820 DCHECK(!plugin_path.value().empty());
1821
1822 std::wstring plugin_name = plugin_path.ToWStringHack();
[email protected]d32d46182009-07-23 00:09:351823#if defined(OS_WIN) || defined(OS_MACOSX)
[email protected]bf5c2ff392009-07-08 16:24:331824 scoped_ptr<FileVersionInfo> version_info(
1825 FileVersionInfo::CreateFileVersionInfo(plugin_path));
1826 if (version_info.get()) {
1827 const std::wstring& product_name = version_info->product_name();
[email protected]996fd702009-09-04 19:12:371828 if (!product_name.empty()) {
[email protected]bf5c2ff392009-07-08 16:24:331829 plugin_name = product_name;
[email protected]996fd702009-09-04 19:12:371830#if defined(OS_MACOSX)
1831 // Many plugins on the Mac have .plugin in the actual name, which looks
1832 // terrible, so look for that and strip it off if present.
1833 const std::wstring plugin_extension(L".plugin");
1834 if (EndsWith(plugin_name, plugin_extension, true))
1835 plugin_name.erase(plugin_name.length() - plugin_extension.length());
1836#endif // OS_MACOSX
1837 }
[email protected]bf5c2ff392009-07-08 16:24:331838 }
[email protected]4a560ed2009-07-13 23:35:261839#else
1840 NOTIMPLEMENTED() << " convert plugin path to plugin name";
1841#endif
[email protected]bf5c2ff392009-07-08 16:24:331842 AddInfoBar(new SimpleAlertInfoBarDelegate(
1843 this, l10n_util::GetStringF(IDS_PLUGIN_CRASHED_PROMPT, plugin_name),
1844 NULL));
[email protected]bf5c2ff392009-07-08 16:24:331845}
1846
1847void TabContents::OnCrashedWorker() {
1848 AddInfoBar(new SimpleAlertInfoBarDelegate(
1849 this, l10n_util::GetString(IDS_WEBWORKER_CRASHED_PROMPT),
1850 NULL));
1851}
1852
1853void TabContents::OnDidGetApplicationInfo(
1854 int32 page_id,
1855 const webkit_glue::WebApplicationInfo& info) {
[email protected]ed5431872009-11-17 08:39:511856 web_app_info_ = info;
[email protected]bf5c2ff392009-07-08 16:24:331857
[email protected]ed5431872009-11-17 08:39:511858 if (delegate())
1859 delegate()->OnDidGetApplicationInfo(this, page_id);
[email protected]bf5c2ff392009-07-08 16:24:331860}
1861
[email protected]a2cf65eb2010-01-18 08:20:381862void TabContents::OnPageContents(const GURL& url,
1863 int renderer_process_id,
1864 int32 page_id,
[email protected]a8a81292010-01-21 00:32:451865 const std::wstring& contents,
1866 const std::string& language) {
[email protected]a2cf65eb2010-01-18 08:20:381867 // Don't index any https pages. People generally don't want their bank
1868 // accounts, etc. indexed on their computer, especially since some of these
1869 // things are not marked cachable.
1870 // TODO(brettw) we may want to consider more elaborate heuristics such as
1871 // the cachability of the page. We may also want to consider subframes (this
1872 // test will still index subframes if the subframe is SSL).
1873 if (!url.SchemeIsSecure()) {
1874 Profile* p = profile();
1875 if (p && !p->IsOffTheRecord()) {
1876 HistoryService* hs = p->GetHistoryService(Profile::IMPLICIT_ACCESS);
1877 if (hs)
1878 hs->SetPageContents(url, contents);
1879 }
1880 }
[email protected]a8a81292010-01-21 00:32:451881
[email protected]3b1c1812010-02-12 21:53:551882 language_state_.LanguageDetermined(language);
[email protected]a8a81292010-01-21 00:32:451883
1884 std::string lang = language;
1885 NotificationService::current()->Notify(
1886 NotificationType::TAB_LANGUAGE_DETERMINED,
[email protected]7e0831b2010-02-01 08:45:151887 Source<TabContents>(this),
[email protected]a8a81292010-01-21 00:32:451888 Details<std::string>(&lang));
[email protected]a2cf65eb2010-01-18 08:20:381889}
1890
[email protected]7e0831b2010-02-01 08:45:151891void TabContents::OnPageTranslated(int32 page_id,
1892 const std::string& original_lang,
1893 const std::string& translated_lang) {
[email protected]3b1c1812010-02-12 21:53:551894 language_state_.set_current_language(translated_lang);
1895 language_state_.set_translation_pending(false);
[email protected]7e0831b2010-02-01 08:45:151896 std::pair<std::string, std::string> lang_pair =
1897 std::make_pair(original_lang, translated_lang);
1898 NotificationService::current()->Notify(
1899 NotificationType::PAGE_TRANSLATED,
1900 Source<TabContents>(this),
1901 Details<std::pair<std::string, std::string> >(&lang_pair));
1902}
1903
[email protected]bf5c2ff392009-07-08 16:24:331904void TabContents::DidStartProvisionalLoadForFrame(
1905 RenderViewHost* render_view_host,
1906 bool is_main_frame,
1907 const GURL& url) {
1908 ProvisionalLoadDetails details(is_main_frame,
1909 controller_.IsURLInPageNavigation(url),
1910 url, std::string(), false);
1911 NotificationService::current()->Notify(
1912 NotificationType::FRAME_PROVISIONAL_LOAD_START,
1913 Source<NavigationController>(&controller_),
1914 Details<ProvisionalLoadDetails>(&details));
1915}
1916
1917void TabContents::DidStartReceivingResourceResponse(
[email protected]3dbb80b2010-02-09 22:41:201918 const ResourceRequestDetails& details) {
[email protected]bf5c2ff392009-07-08 16:24:331919 NotificationService::current()->Notify(
1920 NotificationType::RESOURCE_RESPONSE_STARTED,
1921 Source<NavigationController>(&controller()),
[email protected]3dbb80b2010-02-09 22:41:201922 Details<const ResourceRequestDetails>(&details));
[email protected]bf5c2ff392009-07-08 16:24:331923}
1924
[email protected]3dbb80b2010-02-09 22:41:201925void TabContents::DidRedirectResource(
1926 const ResourceRedirectDetails& details) {
[email protected]bf5c2ff392009-07-08 16:24:331927 NotificationService::current()->Notify(
1928 NotificationType::RESOURCE_RECEIVED_REDIRECT,
1929 Source<NavigationController>(&controller()),
[email protected]3dbb80b2010-02-09 22:41:201930 Details<const ResourceRequestDetails>(&details));
[email protected]bf5c2ff392009-07-08 16:24:331931}
1932
1933void TabContents::DidLoadResourceFromMemoryCache(
1934 const GURL& url,
1935 const std::string& frame_origin,
1936 const std::string& main_frame_origin,
1937 const std::string& security_info) {
1938 // Send out a notification that we loaded a resource from our memory cache.
1939 int cert_id = 0, cert_status = 0, security_bits = 0;
1940 SSLManager::DeserializeSecurityInfo(security_info,
1941 &cert_id, &cert_status,
1942 &security_bits);
1943 LoadFromMemoryCacheDetails details(url, frame_origin, main_frame_origin,
[email protected]8cb5d5b2010-02-09 11:36:161944 GetRenderProcessHost()->id(), cert_id,
1945 cert_status);
[email protected]bf5c2ff392009-07-08 16:24:331946
1947 NotificationService::current()->Notify(
1948 NotificationType::LOAD_FROM_MEMORY_CACHE,
1949 Source<NavigationController>(&controller_),
1950 Details<LoadFromMemoryCacheDetails>(&details));
1951}
1952
[email protected]e3d60e5d2009-09-25 21:08:291953void TabContents::DidDisplayInsecureContent() {
[email protected]09843b5f2009-09-26 08:30:591954 controller_.ssl_manager()->DidDisplayInsecureContent();
[email protected]e3d60e5d2009-09-25 21:08:291955}
1956
1957void TabContents::DidRunInsecureContent(const std::string& security_origin) {
[email protected]09843b5f2009-09-26 08:30:591958 controller_.ssl_manager()->DidRunInsecureContent(security_origin);
[email protected]e3d60e5d2009-09-25 21:08:291959}
1960
[email protected]bf5c2ff392009-07-08 16:24:331961void TabContents::DidFailProvisionalLoadWithError(
1962 RenderViewHost* render_view_host,
1963 bool is_main_frame,
1964 int error_code,
1965 const GURL& url,
1966 bool showing_repost_interstitial) {
1967 if (net::ERR_ABORTED == error_code) {
1968 // EVIL HACK ALERT! Ignore failed loads when we're showing interstitials.
1969 // This means that the interstitial won't be torn down properly, which is
1970 // bad. But if we have an interstitial, go back to another tab type, and
1971 // then load the same interstitial again, we could end up getting the first
1972 // interstitial's "failed" message (as a result of the cancel) when we're on
1973 // the second one.
1974 //
1975 // We can't tell this apart, so we think we're tearing down the current page
1976 // which will cause a crash later one. There is also some code in
1977 // RenderViewHostManager::RendererAbortedProvisionalLoad that is commented
1978 // out because of this problem.
1979 //
1980 // http://code.google.com/p/chromium/issues/detail?id=2855
1981 // Because this will not tear down the interstitial properly, if "back" is
1982 // back to another tab type, the interstitial will still be somewhat alive
1983 // in the previous tab type. If you navigate somewhere that activates the
1984 // tab with the interstitial again, you'll see a flash before the new load
1985 // commits of the interstitial page.
1986 if (showing_interstitial_page()) {
1987 LOG(WARNING) << "Discarding message during interstitial.";
1988 return;
1989 }
1990
1991 // This will discard our pending entry if we cancelled the load (e.g., if we
1992 // decided to download the file instead of load it). Only discard the
1993 // pending entry if the URLs match, otherwise the user initiated a navigate
1994 // before the page loaded so that the discard would discard the wrong entry.
1995 NavigationEntry* pending_entry = controller_.pending_entry();
1996 if (pending_entry && pending_entry->url() == url) {
1997 controller_.DiscardNonCommittedEntries();
1998 // Update the URL display.
1999 NotifyNavigationStateChanged(TabContents::INVALIDATE_URL);
2000 }
2001
2002 render_manager_.RendererAbortedProvisionalLoad(render_view_host);
2003 }
2004
2005 // Send out a notification that we failed a provisional load with an error.
2006 ProvisionalLoadDetails details(is_main_frame,
2007 controller_.IsURLInPageNavigation(url),
2008 url, std::string(), false);
2009 details.set_error_code(error_code);
2010
2011 NotificationService::current()->Notify(
2012 NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR,
2013 Source<NavigationController>(&controller_),
2014 Details<ProvisionalLoadDetails>(&details));
2015}
2016
2017void TabContents::DocumentLoadedInFrame() {
2018 controller_.DocumentLoadedInFrame();
2019}
2020
[email protected]0de80162010-02-03 04:52:352021void TabContents::OnContentBlocked(ContentSettingsType type) {
2022 content_blocked_[type] = true;
2023 if (delegate_)
2024 delegate_->OnBlockedContentChange(this);
2025}
2026
[email protected]8d3347f2009-07-09 22:00:212027RenderViewHostDelegate::View* TabContents::GetViewDelegate() {
[email protected]420ae012009-04-24 05:16:322028 return view_.get();
2029}
2030
[email protected]8d3347f2009-07-09 22:00:212031RenderViewHostDelegate::RendererManagement*
2032TabContents::GetRendererManagementDelegate() {
2033 return &render_manager_;
2034}
2035
[email protected]bf5c2ff392009-07-08 16:24:332036RenderViewHostDelegate::BrowserIntegration*
[email protected]8d3347f2009-07-09 22:00:212037 TabContents::GetBrowserIntegrationDelegate() {
2038 return this;
[email protected]bf5c2ff392009-07-08 16:24:332039}
2040
[email protected]8d3347f2009-07-09 22:00:212041RenderViewHostDelegate::Resource* TabContents::GetResourceDelegate() {
2042 return this;
[email protected]bf5c2ff392009-07-08 16:24:332043}
2044
[email protected]8d3347f2009-07-09 22:00:212045RenderViewHostDelegate::Save* TabContents::GetSaveDelegate() {
[email protected]420ae012009-04-24 05:16:322046 return save_package_.get(); // May be NULL, but we can return NULL.
2047}
2048
[email protected]8d3347f2009-07-09 22:00:212049RenderViewHostDelegate::Printing* TabContents::GetPrintingDelegate() {
2050 return &printing_;
2051}
2052
2053RenderViewHostDelegate::FavIcon* TabContents::GetFavIconDelegate() {
2054 return &fav_icon_helper_;
2055}
2056
[email protected]c54d269e2009-10-21 18:07:382057RenderViewHostDelegate::FormFieldHistory*
2058TabContents::GetFormFieldHistoryDelegate() {
[email protected]19289d02009-10-21 21:47:002059 if (form_field_history_manager_.get() == NULL)
2060 form_field_history_manager_.reset(new FormFieldHistoryManager(this));
2061 return form_field_history_manager_.get();
[email protected]bf5c2ff392009-07-08 16:24:332062}
2063
[email protected]21674df2009-10-28 19:51:212064RenderViewHostDelegate::AutoFill* TabContents::GetAutoFillDelegate() {
2065 if (autofill_manager_.get() == NULL)
2066 autofill_manager_.reset(new AutoFillManager(this));
2067 return autofill_manager_.get();
2068}
2069
[email protected]93623c5d2009-12-10 21:40:322070RendererPreferences TabContents::GetRendererPrefs(Profile* profile) const {
[email protected]840b1512009-07-21 16:53:462071 return renderer_preferences_;
[email protected]80d96fa2009-06-10 22:34:512072}
2073
[email protected]57c6a652009-05-04 07:58:342074TabContents* TabContents::GetAsTabContents() {
2075 return this;
2076}
2077
[email protected]7b291f92009-08-14 05:43:532078ViewType::Type TabContents::GetRenderViewType() const {
2079 return ViewType::TAB_CONTENTS;
2080}
2081
2082int TabContents::GetBrowserWindowID() const {
2083 return controller().window_id().id();
2084}
2085
[email protected]420ae012009-04-24 05:16:322086void TabContents::RenderViewCreated(RenderViewHost* render_view_host) {
[email protected]2e4633c2009-07-09 16:58:062087 NotificationService::current()->Notify(
2088 NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB,
2089 Source<TabContents>(this),
2090 Details<RenderViewHost>(render_view_host));
[email protected]420ae012009-04-24 05:16:322091 NavigationEntry* entry = controller_.GetActiveEntry();
2092 if (!entry)
2093 return;
2094
2095 // When we're creating views, we're still doing initial setup, so we always
2096 // use the pending DOM UI rather than any possibly existing committed one.
2097 if (render_manager_.pending_dom_ui()) {
2098 render_manager_.pending_dom_ui()->RenderViewCreated(render_view_host);
2099 }
2100
2101 if (entry->IsViewSourceMode()) {
2102 // Put the renderer in view source mode.
2103 render_view_host->Send(
2104 new ViewMsg_EnableViewSourceMode(render_view_host->routing_id()));
2105 }
[email protected]0666aef2009-05-13 19:48:082106
2107 view()->RenderViewCreated(render_view_host);
[email protected]420ae012009-04-24 05:16:322108}
2109
2110void TabContents::RenderViewReady(RenderViewHost* rvh) {
2111 if (rvh != render_view_host()) {
2112 // Don't notify the world, since this came from a renderer in the
2113 // background.
2114 return;
2115 }
2116
2117 NotifyConnected();
[email protected]9d8a4642009-07-29 17:25:302118 bool was_crashed = is_crashed();
[email protected]420ae012009-04-24 05:16:322119 SetIsCrashed(false);
[email protected]9d8a4642009-07-29 17:25:302120
2121 // Restore the focus to the tab (otherwise the focus will be on the top
2122 // window).
2123 if (was_crashed && !FocusLocationBarByDefault())
2124 Focus();
[email protected]420ae012009-04-24 05:16:322125}
2126
2127void TabContents::RenderViewGone(RenderViewHost* rvh) {
2128 // Ask the print preview if this renderer was valuable.
2129 if (!printing_.OnRenderViewGone(rvh))
2130 return;
2131 if (rvh != render_view_host()) {
2132 // The pending page's RenderViewHost is gone.
2133 return;
2134 }
2135
2136 SetIsLoading(false, NULL);
2137 NotifyDisconnected();
2138 SetIsCrashed(true);
2139
[email protected]ff9efc62010-02-18 22:10:542140 // Remove all infobars.
[email protected]e5430c92010-02-18 22:39:212141 for (int i = infobar_delegate_count() - 1; i >=0 ; --i)
[email protected]ff9efc62010-02-18 22:10:542142 RemoveInfoBar(GetInfoBarDelegateAt(i));
2143
[email protected]8e537302009-06-10 21:19:582144 // Tell the view that we've crashed so it can prepare the sad tab page.
[email protected]cf68b092010-01-15 20:05:552145 // Only do this if we're not in browser shutdown, so that TabContents
2146 // objects that are not in a browser (e.g., HTML dialogs) and thus are
2147 // visible do not flash a sad tab page.
2148 if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID)
2149 view_->OnTabCrashed();
[email protected]420ae012009-04-24 05:16:322150
2151 // Hide any visible hung renderer warning for this web contents' process.
[email protected]e7b8d832009-11-20 22:41:002152 hung_renderer_dialog::HideForTabContents(this);
[email protected]420ae012009-04-24 05:16:322153}
2154
[email protected]2e4633c2009-07-09 16:58:062155void TabContents::RenderViewDeleted(RenderViewHost* rvh) {
2156 NotificationService::current()->Notify(
2157 NotificationType::RENDER_VIEW_HOST_DELETED,
2158 Source<TabContents>(this),
2159 Details<RenderViewHost>(rvh));
[email protected]fb7b79f72009-11-06 18:00:482160 render_manager_.RenderViewDeleted(rvh);
[email protected]2e4633c2009-07-09 16:58:062161}
2162
[email protected]420ae012009-04-24 05:16:322163void TabContents::DidNavigate(RenderViewHost* rvh,
2164 const ViewHostMsg_FrameNavigate_Params& params) {
[email protected]8030f012009-09-25 18:09:372165 int extra_invalidate_flags = 0;
2166
2167 if (PageTransition::IsMainFrame(params.transition)) {
[email protected]20ede072009-10-06 00:28:352168 bool was_bookmark_bar_visible = ShouldShowBookmarkBar();
[email protected]8030f012009-09-25 18:09:372169 bool was_extension_shelf_visible = IsExtensionShelfAlwaysVisible();
2170
[email protected]420ae012009-04-24 05:16:322171 render_manager_.DidNavigateMainFrame(rvh);
2172
[email protected]20ede072009-10-06 00:28:352173 if (was_bookmark_bar_visible != ShouldShowBookmarkBar())
[email protected]8030f012009-09-25 18:09:372174 extra_invalidate_flags |= INVALIDATE_BOOKMARK_BAR;
2175 if (was_extension_shelf_visible != IsExtensionShelfAlwaysVisible())
2176 extra_invalidate_flags |= INVALIDATE_EXTENSION_SHELF;
2177 }
2178
[email protected]420ae012009-04-24 05:16:322179 // Update the site of the SiteInstance if it doesn't have one yet.
2180 if (!GetSiteInstance()->has_site())
2181 GetSiteInstance()->SetSite(params.url);
2182
2183 // Need to update MIME type here because it's referred to in
2184 // UpdateNavigationCommands() called by RendererDidNavigate() to
2185 // determine whether or not to enable the encoding menu.
2186 // It's updated only for the main frame. For a subframe,
2187 // RenderView::UpdateURL does not set params.contents_mime_type.
2188 // (see http://code.google.com/p/chromium/issues/detail?id=2929 )
2189 // TODO(jungshik): Add a test for the encoding menu to avoid
2190 // regressing it again.
2191 if (PageTransition::IsMainFrame(params.transition))
2192 contents_mime_type_ = params.contents_mime_type;
2193
2194 NavigationController::LoadCommittedDetails details;
[email protected]8030f012009-09-25 18:09:372195 bool did_navigate = controller_.RendererDidNavigate(
2196 params, extra_invalidate_flags, &details);
[email protected]3e90d4a2009-07-03 17:38:392197
2198 // Update history. Note that this needs to happen after the entry is complete,
2199 // which WillNavigate[Main,Sub]Frame will do before this function is called.
[email protected]2e29d922009-10-22 22:13:352200 if (params.should_update_history &&
2201 (!delegate() || delegate()->ShouldAddNavigationsToHistory())) {
[email protected]3e90d4a2009-07-03 17:38:392202 // Most of the time, the displayURL matches the loaded URL, but for about:
2203 // URLs, we use a data: URL as the real value. We actually want to save
2204 // the about: URL to the history db and keep the data: URL hidden. This is
2205 // what the TabContents' URL getter does.
2206 UpdateHistoryForNavigation(GetURL(), details, params);
2207 }
2208
[email protected]76543b92009-08-31 17:27:452209 if (!did_navigate)
2210 return; // No navigation happened.
[email protected]420ae012009-04-24 05:16:322211
2212 // DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen
2213 // for the appropriate notification (best) or you can add it to
2214 // DidNavigateMainFramePostCommit / DidNavigateAnyFramePostCommit (only if
2215 // necessary, please).
2216
2217 // Run post-commit tasks.
2218 if (details.is_main_frame)
2219 DidNavigateMainFramePostCommit(details, params);
2220 DidNavigateAnyFramePostCommit(rvh, details, params);
2221}
2222
2223void TabContents::UpdateState(RenderViewHost* rvh,
2224 int32 page_id,
2225 const std::string& state) {
2226 DCHECK(rvh == render_view_host());
2227
2228 // We must be prepared to handle state updates for any page, these occur
2229 // when the user is scrolling and entering form data, as well as when we're
2230 // leaving a page, in which case our state may have already been moved to
2231 // the next page. The navigation controller will look up the appropriate
2232 // NavigationEntry and update it when it is notified via the delegate.
2233
2234 int entry_index = controller_.GetEntryIndexWithPageID(
2235 GetSiteInstance(), page_id);
2236 if (entry_index < 0)
2237 return;
2238 NavigationEntry* entry = controller_.GetEntryAtIndex(entry_index);
2239
2240 if (state == entry->content_state())
2241 return; // Nothing to update.
2242 entry->set_content_state(state);
2243 controller_.NotifyEntryChanged(entry, entry_index);
2244}
2245
2246void TabContents::UpdateTitle(RenderViewHost* rvh,
2247 int32 page_id, const std::wstring& title) {
2248 // If we have a title, that's a pretty good indication that we've started
2249 // getting useful data.
2250 SetNotWaitingForResponse();
2251
2252 DCHECK(rvh == render_view_host());
2253 NavigationEntry* entry = controller_.GetEntryWithPageID(GetSiteInstance(),
2254 page_id);
2255 if (!entry || !UpdateTitleForEntry(entry, title))
2256 return;
2257
2258 // Broadcast notifications when the UI should be updated.
2259 if (entry == controller_.GetEntryAtOffset(0))
[email protected]f1cd5e82009-10-23 17:19:032260 NotifyNavigationStateChanged(INVALIDATE_TITLE);
[email protected]420ae012009-04-24 05:16:322261}
2262
[email protected]420ae012009-04-24 05:16:322263void TabContents::UpdateEncoding(RenderViewHost* render_view_host,
[email protected]41fc0322009-09-04 22:23:402264 const std::string& encoding) {
[email protected]420ae012009-04-24 05:16:322265 set_encoding(encoding);
2266}
2267
2268void TabContents::UpdateTargetURL(int32 page_id, const GURL& url) {
2269 if (delegate())
2270 delegate()->UpdateTargetURL(this, url);
2271}
2272
2273void TabContents::UpdateThumbnail(const GURL& url,
2274 const SkBitmap& bitmap,
2275 const ThumbnailScore& score) {
2276 // Tell History about this thumbnail
[email protected]449478302009-06-09 20:04:282277 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kThumbnailStore)) {
[email protected]72d0fc72009-07-09 17:30:492278 if (!profile()->IsOffTheRecord())
[email protected]42339402009-07-17 17:27:192279 profile()->GetThumbnailStore()->SetPageThumbnail(url, bitmap,
2280 score, true);
[email protected]449478302009-06-09 20:04:282281 } else {
2282 HistoryService* hs;
2283 if (!profile()->IsOffTheRecord() &&
2284 (hs = profile()->GetHistoryService(Profile::IMPLICIT_ACCESS))) {
2285 hs->SetPageThumbnail(url, bitmap, score);
2286 }
[email protected]420ae012009-04-24 05:16:322287 }
2288}
2289
[email protected]8922e1f2009-10-03 05:01:262290void TabContents::UpdateInspectorSettings(const std::string& raw_settings) {
[email protected]0df30122009-06-03 12:13:082291 profile()->GetPrefs()->SetString(prefs::kWebKitInspectorSettings,
[email protected]8922e1f2009-10-03 05:01:262292 UTF8ToWide(raw_settings));
[email protected]0df30122009-06-03 12:13:082293}
2294
[email protected]420ae012009-04-24 05:16:322295void TabContents::Close(RenderViewHost* rvh) {
[email protected]07707302009-11-06 00:50:292296 // The UI may be in an event-tracking loop, such as between the
2297 // mouse-down and mouse-up in text selection or a button click.
2298 // Defer the close until after tracking is complete, so that we
2299 // don't free objects out from under the UI.
2300 // TODO(shess): This could probably be integrated with the
2301 // IsDoingDrag() test below. Punting for now because I need more
2302 // research to understand how this impacts platforms other than Mac.
2303 // TODO(shess): This could get more fine-grained. For instance,
2304 // closing a tab in another window while selecting text in the
2305 // current window's Omnibox should be just fine.
2306 if (view()->IsEventTracking()) {
2307 view()->CloseTabAfterEventTracking();
2308 return;
2309 }
2310
[email protected]24a4d1062009-07-10 23:10:422311 // If we close the tab while we're in the middle of a drag, we'll crash.
2312 // Instead, cancel the drag and close it as soon as the drag ends.
2313 if (view()->IsDoingDrag()) {
2314 view()->CancelDragAndCloseTab();
2315 return;
2316 }
2317
[email protected]420ae012009-04-24 05:16:322318 // Ignore this if it comes from a RenderViewHost that we aren't showing.
2319 if (delegate() && rvh == render_view_host())
2320 delegate()->CloseContents(this);
2321}
2322
2323void TabContents::RequestMove(const gfx::Rect& new_bounds) {
2324 if (delegate() && delegate()->IsPopup(this))
2325 delegate()->MoveContents(this, new_bounds);
2326}
2327
[email protected]7ab1e7d62009-10-14 23:32:012328void TabContents::DidStartLoading() {
[email protected]420ae012009-04-24 05:16:322329 SetIsLoading(true, NULL);
2330}
2331
[email protected]7ab1e7d62009-10-14 23:32:012332void TabContents::DidStopLoading() {
[email protected]420ae012009-04-24 05:16:322333 scoped_ptr<LoadNotificationDetails> details;
2334
2335 NavigationEntry* entry = controller_.GetActiveEntry();
2336 // An entry may not exist for a stop when loading an initial blank page or
2337 // if an iframe injected by script into a blank page finishes loading.
2338 if (entry) {
[email protected]420ae012009-04-24 05:16:322339 base::TimeDelta elapsed = base::TimeTicks::Now() - current_load_start_;
2340
2341 details.reset(new LoadNotificationDetails(
[email protected]ebe89e062009-08-13 23:16:542342 entry->virtual_url(),
[email protected]420ae012009-04-24 05:16:322343 entry->transition_type(),
2344 elapsed,
2345 &controller_,
2346 controller_.GetCurrentEntryIndex()));
2347 }
2348
2349 // Tell PasswordManager we've finished a page load, which serves as a
2350 // green light to save pending passwords and reset itself.
2351 GetPasswordManager()->DidStopLoading();
2352
2353 SetIsLoading(false, details.get());
2354}
2355
[email protected]420ae012009-04-24 05:16:322356void TabContents::DidRedirectProvisionalLoad(int32 page_id,
2357 const GURL& source_url,
2358 const GURL& target_url) {
2359 NavigationEntry* entry;
2360 if (page_id == -1)
2361 entry = controller_.pending_entry();
2362 else
2363 entry = controller_.GetEntryWithPageID(GetSiteInstance(), page_id);
2364 if (!entry || entry->url() != source_url)
2365 return;
2366 entry->set_url(target_url);
2367}
2368
[email protected]420ae012009-04-24 05:16:322369void TabContents::RequestOpenURL(const GURL& url, const GURL& referrer,
2370 WindowOpenDisposition disposition) {
2371 if (render_manager_.dom_ui()) {
2372 // When we're a DOM UI, it will provide a page transition type for us (this
2373 // is so the new tab page can specify AUTO_BOOKMARK for automatically
2374 // generated suggestions).
2375 //
2376 // Note also that we hide the referrer for DOM UI pages. We don't really
[email protected]60e448982009-05-06 04:21:162377 // want web sites to see a referrer of "chrome://blah" (and some
2378 // chrome: URLs might have search terms or other stuff we don't want to
[email protected]420ae012009-04-24 05:16:322379 // send to the site), so we send no referrer.
2380 OpenURL(url, GURL(), disposition,
2381 render_manager_.dom_ui()->link_transition_type());
2382 } else {
2383 OpenURL(url, referrer, disposition, PageTransition::LINK);
2384 }
2385}
2386
[email protected]1ee614862009-07-06 20:29:182387void TabContents::DomOperationResponse(const std::string& json_string,
2388 int automation_id) {
2389}
2390
[email protected]420ae012009-04-24 05:16:322391void TabContents::ProcessDOMUIMessage(const std::string& message,
[email protected]e4dad9fb2009-10-06 18:15:582392 const Value* content,
[email protected]811bfe32009-07-01 08:46:252393 int request_id,
2394 bool has_callback) {
[email protected]420ae012009-04-24 05:16:322395 if (!render_manager_.dom_ui()) {
[email protected]c2e74fe82009-09-03 17:57:442396 // This can happen if someone uses window.open() to open an extension URL
2397 // from a non-extension context.
2398 render_view_host()->BlockExtensionRequest(request_id);
[email protected]420ae012009-04-24 05:16:322399 return;
2400 }
[email protected]811bfe32009-07-01 08:46:252401 render_manager_.dom_ui()->ProcessDOMUIMessage(message, content, request_id,
2402 has_callback);
[email protected]420ae012009-04-24 05:16:322403}
2404
2405void TabContents::ProcessExternalHostMessage(const std::string& message,
2406 const std::string& origin,
2407 const std::string& target) {
2408 if (delegate())
2409 delegate()->ForwardMessageToExternalHost(message, origin, target);
2410}
2411
[email protected]420ae012009-04-24 05:16:322412void TabContents::RunFileChooser(bool multiple_files,
2413 const string16& title,
2414 const FilePath& default_file) {
2415 if (!select_file_dialog_.get())
2416 select_file_dialog_ = SelectFileDialog::Create(this);
2417 SelectFileDialog::Type dialog_type =
2418 multiple_files ? SelectFileDialog::SELECT_OPEN_MULTI_FILE :
2419 SelectFileDialog::SELECT_OPEN_FILE;
2420 select_file_dialog_->SelectFile(dialog_type, title, default_file,
2421 NULL, 0, FILE_PATH_LITERAL(""),
2422 view_->GetTopLevelNativeWindow(), NULL);
2423}
2424
2425void TabContents::RunJavaScriptMessage(
2426 const std::wstring& message,
2427 const std::wstring& default_prompt,
2428 const GURL& frame_url,
2429 const int flags,
2430 IPC::Message* reply_msg,
2431 bool* did_suppress_message) {
2432 // Suppress javascript messages when requested and when inside a constrained
2433 // popup window (because that activates them and breaks them out of the
2434 // constrained window jail).
[email protected]91ed49a2009-07-07 21:29:552435 // Also suppress messages when showing an interstitial. The interstitial is
2436 // shown over the previous page, we don't want the hidden page dialogs to
2437 // interfere with the interstitial.
2438 bool suppress_this_message = suppress_javascript_messages_ ||
2439 showing_interstitial_page();
[email protected]420ae012009-04-24 05:16:322440 if (delegate())
2441 suppress_this_message |=
[email protected]b6c874582009-05-08 19:38:312442 (delegate()->GetConstrainingContents(this) != this);
[email protected]420ae012009-04-24 05:16:322443
2444 *did_suppress_message = suppress_this_message;
2445
2446 if (!suppress_this_message) {
2447 base::TimeDelta time_since_last_message(
2448 base::TimeTicks::Now() - last_javascript_message_dismissal_);
2449 bool show_suppress_checkbox = false;
2450 // Show a checkbox offering to suppress further messages if this message is
2451 // being displayed within kJavascriptMessageExpectedDelay of the last one.
2452 if (time_since_last_message <
2453 base::TimeDelta::FromMilliseconds(kJavascriptMessageExpectedDelay))
2454 show_suppress_checkbox = true;
2455
[email protected]d82ed61e2009-06-16 02:46:222456 RunJavascriptMessageBox(this, frame_url, flags, message, default_prompt,
[email protected]420ae012009-04-24 05:16:322457 show_suppress_checkbox, reply_msg);
2458 } else {
2459 // If we are suppressing messages, just reply as is if the user immediately
2460 // pressed "Cancel".
[email protected]beb440c2009-11-06 04:08:542461 OnMessageBoxClosed(reply_msg, false, std::wstring());
[email protected]420ae012009-04-24 05:16:322462 }
2463}
2464
2465void TabContents::RunBeforeUnloadConfirm(const std::wstring& message,
2466 IPC::Message* reply_msg) {
[email protected]7ab1e7d62009-10-14 23:32:012467 is_showing_before_unload_dialog_ = true;
[email protected]d82ed61e2009-06-16 02:46:222468 RunBeforeUnloadDialog(this, message, reply_msg);
[email protected]420ae012009-04-24 05:16:322469}
2470
2471void TabContents::ShowModalHTMLDialog(const GURL& url, int width, int height,
2472 const std::string& json_arguments,
2473 IPC::Message* reply_msg) {
2474 if (delegate()) {
2475 HtmlDialogUIDelegate* dialog_delegate =
2476 new ModalHtmlDialogDelegate(url, width, height, json_arguments,
[email protected]d82ed61e2009-06-16 02:46:222477 reply_msg, this);
[email protected]420ae012009-04-24 05:16:322478 delegate()->ShowHtmlDialog(dialog_delegate, NULL);
2479 }
2480}
2481
2482void TabContents::PasswordFormsSeen(
[email protected]ed3fb032009-06-16 19:50:562483 const std::vector<webkit_glue::PasswordForm>& forms) {
[email protected]420ae012009-04-24 05:16:322484 GetPasswordManager()->PasswordFormsSeen(forms);
2485}
2486
[email protected]420ae012009-04-24 05:16:322487// Checks to see if we should generate a keyword based on the OSDD, and if
2488// necessary uses TemplateURLFetcher to download the OSDD and create a keyword.
2489void TabContents::PageHasOSDD(RenderViewHost* render_view_host,
2490 int32 page_id, const GURL& url,
2491 bool autodetected) {
2492 // Make sure page_id is the current page, and the TemplateURLModel is loaded.
2493 DCHECK(url.is_valid());
2494 if (!IsActiveEntry(page_id))
2495 return;
2496 TemplateURLModel* url_model = profile()->GetTemplateURLModel();
2497 if (!url_model)
2498 return;
2499 if (!url_model->loaded()) {
2500 url_model->Load();
2501 return;
2502 }
2503 if (!profile()->GetTemplateURLFetcher())
2504 return;
2505
2506 if (profile()->IsOffTheRecord())
2507 return;
2508
2509 const NavigationEntry* entry = controller_.GetLastCommittedEntry();
2510 DCHECK(entry);
2511
2512 const NavigationEntry* base_entry = entry;
2513 if (IsFormSubmit(base_entry)) {
2514 // If the current page is a form submit, find the last page that was not
2515 // a form submit and use its url to generate the keyword from.
2516 int index = controller_.last_committed_entry_index() - 1;
2517 while (index >= 0 && IsFormSubmit(controller_.GetEntryAtIndex(index)))
2518 index--;
2519 if (index >= 0)
2520 base_entry = controller_.GetEntryAtIndex(index);
2521 else
2522 base_entry = NULL;
2523 }
2524
2525 // We want to use the user typed URL if available since that represents what
2526 // the user typed to get here, and fall back on the regular URL if not.
2527 if (!base_entry)
2528 return;
2529 GURL keyword_url = base_entry->user_typed_url().is_valid() ?
2530 base_entry->user_typed_url() : base_entry->url();
2531 if (!keyword_url.is_valid())
2532 return;
2533 std::wstring keyword = TemplateURLModel::GenerateKeyword(keyword_url,
2534 autodetected);
[email protected]a88dbdd52010-01-15 19:25:532535
2536 // For JS added OSDD empty keyword is OK because we will generate keyword
2537 // later from OSDD content.
2538 if (autodetected && keyword.empty())
[email protected]420ae012009-04-24 05:16:322539 return;
2540 const TemplateURL* template_url =
2541 url_model->GetTemplateURLForKeyword(keyword);
2542 if (template_url && (!template_url->safe_for_autoreplace() ||
2543 template_url->originating_url() == url)) {
2544 // Either there is a user created TemplateURL for this keyword, or the
2545 // keyword has the same OSDD url and we've parsed it.
2546 return;
2547 }
2548
2549 // Download the OpenSearch description document. If this is successful a
2550 // new keyword will be created when done.
[email protected]420ae012009-04-24 05:16:322551 profile()->GetTemplateURLFetcher()->ScheduleDownload(
2552 keyword,
2553 url,
2554 base_entry->favicon().url(),
[email protected]d0cc9fb52009-06-23 02:26:162555 this,
[email protected]420ae012009-04-24 05:16:322556 autodetected);
2557}
2558
[email protected]420ae012009-04-24 05:16:322559GURL TabContents::GetAlternateErrorPageURL() const {
2560 GURL url;
2561 // Disable alternate error pages when in OffTheRecord/Incognito mode.
2562 if (profile()->IsOffTheRecord())
2563 return url;
2564
2565 PrefService* prefs = profile()->GetPrefs();
2566 DCHECK(prefs);
2567 if (prefs->GetBoolean(prefs::kAlternateErrorPagesEnabled)) {
[email protected]a33457b82009-09-21 23:07:152568 url = google_util::AppendGoogleLocaleParam(
2569 GURL(google_util::kLinkDoctorBaseURL));
[email protected]420ae012009-04-24 05:16:322570 url = google_util::AppendGoogleTLDParam(url);
2571 }
2572 return url;
2573}
2574
2575WebPreferences TabContents::GetWebkitPrefs() {
2576 PrefService* prefs = render_view_host()->process()->profile()->GetPrefs();
[email protected]7ccddb8c2009-08-04 17:36:552577 bool is_dom_ui = false;
2578 return RenderViewHostDelegateHelper::GetWebkitPrefs(prefs, is_dom_ui);
[email protected]420ae012009-04-24 05:16:322579}
2580
[email protected]fa1cf0b82010-01-15 21:49:442581void TabContents::OnIgnoredUIEvent() {
2582 if (constrained_window_count()) {
2583 ConstrainedWindow* window = *constrained_window_begin();
2584 window->FocusConstrainedWindow();
2585 }
2586}
2587
[email protected]420ae012009-04-24 05:16:322588void TabContents::OnJSOutOfMemory() {
2589 AddInfoBar(new SimpleAlertInfoBarDelegate(
2590 this, l10n_util::GetString(IDS_JS_OUT_OF_MEMORY_PROMPT), NULL));
2591}
2592
[email protected]420ae012009-04-24 05:16:322593void TabContents::OnCrossSiteResponse(int new_render_process_host_id,
2594 int new_request_id) {
[email protected]57c6a652009-05-04 07:58:342595 // Allows the TabContents to react when a cross-site response is ready to be
[email protected]420ae012009-04-24 05:16:322596 // delivered to a pending RenderViewHost. We must first run the onunload
2597 // handler of the old RenderViewHost before we can allow it to proceed.
2598 render_manager_.OnCrossSiteResponse(new_render_process_host_id,
2599 new_request_id);
2600}
2601
2602bool TabContents::CanBlur() const {
2603 return delegate() ? delegate()->CanBlur() : true;
2604}
2605
2606gfx::Rect TabContents::GetRootWindowResizerRect() const {
2607 if (delegate())
2608 return delegate()->GetRootWindowResizerRect();
2609 return gfx::Rect();
2610}
2611
2612void TabContents::RendererUnresponsive(RenderViewHost* rvh,
2613 bool is_during_unload) {
2614 if (is_during_unload) {
2615 // Hang occurred while firing the beforeunload/unload handler.
2616 // Pretend the handler fired so tab closing continues as if it had.
[email protected]829e7612009-04-25 01:15:112617 rvh->set_sudden_termination_allowed(true);
[email protected]420ae012009-04-24 05:16:322618
2619 if (!render_manager_.ShouldCloseTabOnUnresponsiveRenderer())
2620 return;
2621
2622 // If the tab hangs in the beforeunload/unload handler there's really
2623 // nothing we can do to recover. Pretend the unload listeners have
2624 // all fired and close the tab. If the hang is in the beforeunload handler
2625 // then the user will not have the option of cancelling the close.
2626 Close(rvh);
2627 return;
2628 }
2629
2630 if (render_view_host() && render_view_host()->IsRenderViewLive())
[email protected]e7b8d832009-11-20 22:41:002631 hung_renderer_dialog::ShowForTabContents(this);
[email protected]420ae012009-04-24 05:16:322632}
2633
2634void TabContents::RendererResponsive(RenderViewHost* render_view_host) {
[email protected]e7b8d832009-11-20 22:41:002635 hung_renderer_dialog::HideForTabContents(this);
[email protected]420ae012009-04-24 05:16:322636}
2637
2638void TabContents::LoadStateChanged(const GURL& url,
[email protected]094e5b22009-09-25 04:23:562639 net::LoadState load_state,
2640 uint64 upload_position,
2641 uint64 upload_size) {
[email protected]420ae012009-04-24 05:16:322642 load_state_ = load_state;
[email protected]094e5b22009-09-25 04:23:562643 upload_position_ = upload_position;
2644 upload_size_ = upload_size;
[email protected]d686e812009-06-03 19:10:292645 std::wstring languages =
2646 profile()->GetPrefs()->GetString(prefs::kAcceptLanguages);
[email protected]d686e812009-06-03 19:10:292647 std::string host = url.host();
[email protected]ce85f602009-11-07 01:34:532648 load_state_host_ =
2649 net::IDNToUnicode(host.c_str(), host.size(), languages, NULL);
[email protected]420ae012009-04-24 05:16:322650 if (load_state_ == net::LOAD_STATE_READING_RESPONSE)
2651 SetNotWaitingForResponse();
2652 if (is_loading())
[email protected]c9cd2222009-05-06 05:16:502653 NotifyNavigationStateChanged(INVALIDATE_LOAD | INVALIDATE_TAB);
[email protected]420ae012009-04-24 05:16:322654}
2655
[email protected]1ee614862009-07-06 20:29:182656bool TabContents::IsExternalTabContainer() const {
2657 if (!delegate())
2658 return false;
2659
2660 return delegate()->IsExternalTabContainer();
2661}
2662
[email protected]1ee614862009-07-06 20:29:182663void TabContents::DidInsertCSS() {
2664 // This RVHDelegate function is used for extensions and not us.
[email protected]420ae012009-04-24 05:16:322665}
2666
[email protected]130efb02009-09-18 18:54:352667void TabContents::FocusedNodeChanged() {
2668 NotificationService::current()->Notify(
2669 NotificationType::FOCUS_CHANGED_IN_PAGE,
2670 Source<RenderViewHost>(render_view_host()),
2671 NotificationService::NoDetails());
2672}
2673
[email protected]420ae012009-04-24 05:16:322674void TabContents::FileSelected(const FilePath& path,
2675 int index, void* params) {
2676 render_view_host()->FileSelected(path);
2677}
2678
2679void TabContents::MultiFilesSelected(const std::vector<FilePath>& files,
2680 void* params) {
2681 render_view_host()->MultiFilesSelected(files);
2682}
2683
2684void TabContents::FileSelectionCanceled(void* params) {
2685 // If the user cancels choosing a file to upload we pass back an
2686 // empty vector.
2687 render_view_host()->MultiFilesSelected(std::vector<FilePath>());
2688}
2689
2690void TabContents::BeforeUnloadFiredFromRenderManager(
2691 bool proceed,
2692 bool* proceed_to_fire_unload) {
2693 if (delegate())
2694 delegate()->BeforeUnloadFired(this, proceed, proceed_to_fire_unload);
2695}
2696
2697void TabContents::UpdateRenderViewSizeForRenderManager() {
2698 // TODO(brettw) this is a hack. See TabContentsView::SizeContents.
[email protected]0323ee42010-02-17 22:03:262699 gfx::Size size = view_->GetContainerSize();
2700 // 0x0 isn't a valid window size (minimal window size is 1x1) but it may be
2701 // here during container initialization and normal window size will be set
2702 // later. In case of tab duplication this resizing to 0x0 prevents setting
2703 // normal size later so just ignore it.
2704 if (!size.IsEmpty())
2705 view_->SizeContents(size);
[email protected]420ae012009-04-24 05:16:322706}
2707
2708DOMUI* TabContents::CreateDOMUIForRenderManager(const GURL& url) {
[email protected]d82ed61e2009-06-16 02:46:222709 return DOMUIFactory::CreateDOMUIForURL(this, url);
[email protected]420ae012009-04-24 05:16:322710}
2711
2712NavigationEntry*
2713TabContents::GetLastCommittedNavigationEntryForRenderManager() {
2714 return controller_.GetLastCommittedEntry();
2715}
2716
2717bool TabContents::CreateRenderViewForRenderManager(
2718 RenderViewHost* render_view_host) {
[email protected]811bfe32009-07-01 08:46:252719 // If the pending navigation is to a DOMUI, tell the RenderView about any
2720 // bindings it will need enabled.
[email protected]420ae012009-04-24 05:16:322721 if (render_manager_.pending_dom_ui())
[email protected]811bfe32009-07-01 08:46:252722 render_view_host->AllowBindings(
2723 render_manager_.pending_dom_ui()->bindings());
[email protected]1adff062009-06-02 18:39:552724
[email protected]420ae012009-04-24 05:16:322725 RenderWidgetHostView* rwh_view = view_->CreateViewForWidget(render_view_host);
[email protected]1a98a932009-11-17 00:12:522726
2727 scoped_refptr<URLRequestContextGetter> request_context = request_context_;
2728 if (!request_context.get())
2729 request_context = profile()->GetRequestContext();
2730
2731 if (!render_view_host->CreateRenderView(request_context))
[email protected]420ae012009-04-24 05:16:322732 return false;
2733
2734 // Now that the RenderView has been created, we need to tell it its size.
2735 rwh_view->SetSize(view_->GetContainerSize());
2736
2737 UpdateMaxPageIDIfNecessary(render_view_host->site_instance(),
2738 render_view_host);
2739 return true;
2740}
2741
2742void TabContents::Observe(NotificationType type,
2743 const NotificationSource& source,
2744 const NotificationDetails& details) {
2745 switch (type.value) {
2746 case NotificationType::BOOKMARK_MODEL_LOADED:
2747 // BookmarkModel finished loading, fall through to update starred state.
2748 case NotificationType::URLS_STARRED: {
2749 // Somewhere, a URL has been starred.
2750 // Ignore notifications for profiles other than our current one.
2751 Profile* source_profile = Source<Profile>(source).ptr();
2752 if (!source_profile || !source_profile->IsSameProfile(profile()))
2753 return;
2754
2755 UpdateStarredStateForCurrentURL();
2756 break;
2757 }
2758 case NotificationType::PREF_CHANGED: {
2759 std::wstring* pref_name_in = Details<std::wstring>(details).ptr();
2760 DCHECK(Source<PrefService>(source).ptr() == profile()->GetPrefs());
2761 if (*pref_name_in == prefs::kAlternateErrorPagesEnabled) {
2762 UpdateAlternateErrorPageURL();
2763 } else if (*pref_name_in == prefs::kDefaultCharset ||
2764 StartsWithASCII(WideToUTF8(*pref_name_in), "webkit.webprefs.", true)
2765 ) {
2766 UpdateWebPreferences();
2767 } else {
2768 NOTREACHED() << "unexpected pref change notification" << *pref_name_in;
2769 }
2770 break;
2771 }
2772 case NotificationType::RENDER_WIDGET_HOST_DESTROYED:
2773 view_->RenderWidgetHostDestroyed(Source<RenderWidgetHost>(source).ptr());
2774 break;
2775
2776 case NotificationType::NAV_ENTRY_COMMITTED: {
2777 DCHECK(&controller_ == Source<NavigationController>(source).ptr());
2778
2779 NavigationController::LoadCommittedDetails& committed_details =
2780 *(Details<NavigationController::LoadCommittedDetails>(details).ptr());
2781 ExpireInfoBars(committed_details);
2782 break;
2783 }
2784
[email protected]d3ba77272009-09-03 00:06:092785#if defined(OS_LINUX)
2786 case NotificationType::BROWSER_THEME_CHANGED: {
[email protected]7ff431e2010-01-07 18:18:542787 renderer_preferences_util::UpdateFromSystemSettings(
2788 &renderer_preferences_, profile());
[email protected]d3ba77272009-09-03 00:06:092789 render_view_host()->SyncRendererPrefs();
2790 break;
2791 }
2792#endif
2793
[email protected]79580c62010-02-02 02:36:252794 case NotificationType::CONTENT_SETTINGS_CHANGED: {
2795 Details<HostContentSettingsMap::ContentSettingsDetails>
2796 settings_details(details);
[email protected]79580c62010-02-02 02:36:252797 NavigationEntry* entry = controller_.GetActiveEntry();
[email protected]da0c8e92010-02-09 23:25:492798 GURL entry_url;
2799 std::string host;
2800 if (entry) {
2801 entry_url = entry->url();
2802 host = entry_url.host();
2803 }
[email protected]79580c62010-02-02 02:36:252804 Source<HostContentSettingsMap> content_settings(source);
2805 if (settings_details.ptr()->host().empty() ||
2806 settings_details.ptr()->host() == host) {
2807 render_view_host()->SendContentSettings(host,
[email protected]da0c8e92010-02-09 23:25:492808 content_settings.ptr()->GetContentSettings(entry_url));
[email protected]79580c62010-02-02 02:36:252809 }
2810 break;
2811 }
2812
[email protected]420ae012009-04-24 05:16:322813 default:
2814 NOTREACHED();
2815 }
2816}
[email protected]aacd7cc2009-09-02 14:51:102817
[email protected]beb440c2009-11-06 04:08:542818std::wstring TabContents::GetMessageBoxTitle(const GURL& frame_url,
2819 bool is_alert) {
2820 if (!frame_url.has_host())
2821 return l10n_util::GetString(
2822 is_alert ? IDS_JAVASCRIPT_ALERT_DEFAULT_TITLE
2823 : IDS_JAVASCRIPT_MESSAGEBOX_DEFAULT_TITLE);
2824
2825 // We really only want the scheme, hostname, and port.
2826 GURL::Replacements replacements;
2827 replacements.ClearUsername();
2828 replacements.ClearPassword();
2829 replacements.ClearPath();
2830 replacements.ClearQuery();
2831 replacements.ClearRef();
2832 GURL clean_url = frame_url.ReplaceComponents(replacements);
2833
2834 // TODO(brettw) it should be easier than this to do the correct language
2835 // handling without getting the accept language from the profile.
2836 std::wstring base_address = gfx::ElideUrl(clean_url, gfx::Font(), 0,
2837 profile()->GetPrefs()->GetString(prefs::kAcceptLanguages));
2838 // Force URL to have LTR directionality.
2839 if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
2840 l10n_util::WrapStringWithLTRFormatting(&base_address);
2841
2842 return l10n_util::GetStringF(
2843 is_alert ? IDS_JAVASCRIPT_ALERT_TITLE : IDS_JAVASCRIPT_MESSAGEBOX_TITLE,
2844 base_address);
2845}
2846
2847gfx::NativeWindow TabContents::GetMessageBoxRootWindow() {
2848 return view_->GetTopLevelNativeWindow();
2849}
2850
2851void TabContents::OnMessageBoxClosed(IPC::Message* reply_msg,
2852 bool success,
2853 const std::wstring& prompt) {
2854 last_javascript_message_dismissal_ = base::TimeTicks::Now();
2855 if (is_showing_before_unload_dialog_ && !success) {
2856 // If a beforeunload dialog is canceled, we need to stop the throbber from
2857 // spinning, since we forced it to start spinning in Navigate.
2858 DidStopLoading();
2859
2860 tab_close_start_time_ = base::TimeTicks();
2861 }
2862 is_showing_before_unload_dialog_ = false;
2863 render_view_host()->JavaScriptMessageBoxClosed(reply_msg, success, prompt);
2864}
2865
2866void TabContents::SetSuppressMessageBoxes(bool suppress_message_boxes) {
2867 set_suppress_javascript_messages(suppress_message_boxes);
2868}
2869
[email protected]41fc0322009-09-04 22:23:402870void TabContents::set_encoding(const std::string& encoding) {
[email protected]aacd7cc2009-09-02 14:51:102871 encoding_ = CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding);
2872}