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