1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
10 #include "base/command_line.h"
11 #include "base/metrics/histogram.h"
12 #include "base/profiler/scoped_tracker.h"
13 #include "base/strings/stringprintf.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/search_engines/template_url_service_factory.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_command_controller.h"
18 #include "chrome/browser/ui/browser_finder.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/render_messages.h"
21 #include "chrome/grit/generated_resources.h"
22 #include "components/search_engines/template_url.h"
23 #include "components/search_engines/template_url_service.h"
24 #include "components/web_cache/browser/web_cache_manager.h"
25 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/browser/web_contents.h"
28 #include "extensions/browser/guest_view/guest_view_manager.h"
29 #include "net/base/load_states.h"
30 #include "net/http/http_request_headers.h"
31 #include "ui/base/l10n/l10n_util.h"
33 using content::WebContents
;
35 DEFINE_WEB_CONTENTS_USER_DATA_KEY(CoreTabHelper
);
37 CoreTabHelper::CoreTabHelper(WebContents
* web_contents
)
38 : content::WebContentsObserver(web_contents
),
40 content_restrictions_(0) {
43 CoreTabHelper::~CoreTabHelper() {
46 base::string16
CoreTabHelper::GetDefaultTitle() {
47 return l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE
);
50 base::string16
CoreTabHelper::GetStatusText() const {
51 base::string16 status_text
;
52 GetStatusTextForWebContents(&status_text
, web_contents());
56 void CoreTabHelper::OnCloseStarted() {
57 if (close_start_time_
.is_null())
58 close_start_time_
= base::TimeTicks::Now();
61 void CoreTabHelper::OnCloseCanceled() {
62 close_start_time_
= base::TimeTicks();
63 before_unload_end_time_
= base::TimeTicks();
64 unload_detached_start_time_
= base::TimeTicks();
67 void CoreTabHelper::OnUnloadStarted() {
68 before_unload_end_time_
= base::TimeTicks::Now();
71 void CoreTabHelper::OnUnloadDetachedStarted() {
72 if (unload_detached_start_time_
.is_null())
73 unload_detached_start_time_
= base::TimeTicks::Now();
76 void CoreTabHelper::UpdateContentRestrictions(int content_restrictions
) {
77 content_restrictions_
= content_restrictions
;
78 #if !defined(OS_ANDROID)
79 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents());
83 browser
->command_controller()->ContentRestrictionsChanged();
88 bool CoreTabHelper::GetStatusTextForWebContents(
89 base::string16
* status_text
, content::WebContents
* source
) {
90 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467185 is
92 tracked_objects::ScopedTracker
tracking_profile1(
93 FROM_HERE_WITH_EXPLICIT_FUNCTION(
94 "467185 CoreTabHelper::GetStatusTextForWebContents1"));
96 extensions::GuestViewManager::FromBrowserContextIfAvailable(
97 source
->GetBrowserContext());
98 if (!source
->IsLoading() ||
99 source
->GetLoadState().state
== net::LOAD_STATE_IDLE
) {
100 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467185
102 tracked_objects::ScopedTracker
tracking_profile2(
103 FROM_HERE_WITH_EXPLICIT_FUNCTION(
104 "467185 CoreTabHelper::GetStatusTextForWebContents2"));
107 return guest_manager
->ForEachGuest(
108 source
, base::Bind(&CoreTabHelper::GetStatusTextForWebContents
,
112 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467185
114 tracked_objects::ScopedTracker
tracking_profile3(
115 FROM_HERE_WITH_EXPLICIT_FUNCTION(
116 "467185 CoreTabHelper::GetStatusTextForWebContents3"));
118 switch (source
->GetLoadState().state
) {
119 case net::LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL
:
120 case net::LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET
:
122 l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_SOCKET_SLOT
);
124 case net::LOAD_STATE_WAITING_FOR_DELEGATE
:
125 if (!source
->GetLoadState().param
.empty()) {
126 *status_text
= l10n_util::GetStringFUTF16(
127 IDS_LOAD_STATE_WAITING_FOR_DELEGATE
,
128 source
->GetLoadState().param
);
131 *status_text
= l10n_util::GetStringUTF16(
132 IDS_LOAD_STATE_WAITING_FOR_DELEGATE_GENERIC
);
135 case net::LOAD_STATE_WAITING_FOR_CACHE
:
137 l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_CACHE
);
139 case net::LOAD_STATE_WAITING_FOR_APPCACHE
:
141 l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_APPCACHE
);
143 case net::LOAD_STATE_ESTABLISHING_PROXY_TUNNEL
:
145 l10n_util::GetStringUTF16(IDS_LOAD_STATE_ESTABLISHING_PROXY_TUNNEL
);
147 case net::LOAD_STATE_DOWNLOADING_PROXY_SCRIPT
:
149 l10n_util::GetStringUTF16(IDS_LOAD_STATE_DOWNLOADING_PROXY_SCRIPT
);
151 case net::LOAD_STATE_RESOLVING_PROXY_FOR_URL
:
153 l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_PROXY_FOR_URL
);
155 case net::LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
:
156 *status_text
= l10n_util::GetStringUTF16(
157 IDS_LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
);
159 case net::LOAD_STATE_RESOLVING_HOST
:
160 *status_text
= l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_HOST
);
162 case net::LOAD_STATE_CONNECTING
:
163 *status_text
= l10n_util::GetStringUTF16(IDS_LOAD_STATE_CONNECTING
);
165 case net::LOAD_STATE_SSL_HANDSHAKE
:
166 *status_text
= l10n_util::GetStringUTF16(IDS_LOAD_STATE_SSL_HANDSHAKE
);
168 case net::LOAD_STATE_SENDING_REQUEST
:
169 if (source
->GetUploadSize()) {
170 *status_text
= l10n_util::GetStringFUTF16Int(
171 IDS_LOAD_STATE_SENDING_REQUEST_WITH_PROGRESS
,
172 static_cast<int>((100 * source
->GetUploadPosition()) /
173 source
->GetUploadSize()));
177 l10n_util::GetStringUTF16(IDS_LOAD_STATE_SENDING_REQUEST
);
180 case net::LOAD_STATE_WAITING_FOR_RESPONSE
:
182 l10n_util::GetStringFUTF16(IDS_LOAD_STATE_WAITING_FOR_RESPONSE
,
183 source
->GetLoadStateHost());
185 // Ignore net::LOAD_STATE_READING_RESPONSE and net::LOAD_STATE_IDLE
186 case net::LOAD_STATE_IDLE
:
187 case net::LOAD_STATE_READING_RESPONSE
:
193 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467185 is
195 tracked_objects::ScopedTracker
tracking_profile4(
196 FROM_HERE_WITH_EXPLICIT_FUNCTION(
197 "467185 CoreTabHelper::GetStatusTextForWebContents4"));
198 return guest_manager
->ForEachGuest(
199 source
, base::Bind(&CoreTabHelper::GetStatusTextForWebContents
,
203 ////////////////////////////////////////////////////////////////////////////////
204 // WebContentsObserver overrides
206 void CoreTabHelper::DidStartLoading() {
207 UpdateContentRestrictions(0);
210 void CoreTabHelper::WasShown() {
211 web_cache::WebCacheManager::GetInstance()->ObserveActivity(
212 web_contents()->GetRenderProcessHost()->GetID());
215 void CoreTabHelper::WebContentsDestroyed() {
216 // OnCloseStarted isn't called in unit tests.
217 if (!close_start_time_
.is_null()) {
218 bool fast_tab_close_enabled
=
219 base::CommandLine::ForCurrentProcess()->HasSwitch(
220 switches::kEnableFastUnload
);
222 if (fast_tab_close_enabled
) {
223 base::TimeTicks now
= base::TimeTicks::Now();
224 base::TimeDelta close_time
= now
- close_start_time_
;
225 UMA_HISTOGRAM_TIMES("Tab.Close", close_time
);
227 base::TimeTicks unload_start_time
= close_start_time_
;
228 base::TimeTicks unload_end_time
= now
;
229 if (!before_unload_end_time_
.is_null())
230 unload_start_time
= before_unload_end_time_
;
231 if (!unload_detached_start_time_
.is_null())
232 unload_end_time
= unload_detached_start_time_
;
233 base::TimeDelta unload_time
= unload_end_time
- unload_start_time
;
234 UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", unload_time
);
236 base::TimeTicks now
= base::TimeTicks::Now();
237 base::TimeTicks unload_start_time
= close_start_time_
;
238 if (!before_unload_end_time_
.is_null())
239 unload_start_time
= before_unload_end_time_
;
240 UMA_HISTOGRAM_TIMES("Tab.Close", now
- close_start_time_
);
241 UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", now
- unload_start_time
);
246 void CoreTabHelper::BeforeUnloadFired(const base::TimeTicks
& proceed_time
) {
247 before_unload_end_time_
= proceed_time
;
250 void CoreTabHelper::BeforeUnloadDialogCancelled() {
254 bool CoreTabHelper::OnMessageReceived(
255 const IPC::Message
& message
,
256 content::RenderFrameHost
* render_frame_host
) {
258 IPC_BEGIN_MESSAGE_MAP(CoreTabHelper
, message
)
259 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestThumbnailForContextNode_ACK
,
260 OnRequestThumbnailForContextNodeACK
)
261 IPC_MESSAGE_UNHANDLED(handled
= false)
262 IPC_END_MESSAGE_MAP()
266 // Handles the image thumbnail for the context node, composes a image search
267 // request based on the received thumbnail and opens the request in a new tab.
268 void CoreTabHelper::OnRequestThumbnailForContextNodeACK(
269 const std::string
& thumbnail_data
,
270 const gfx::Size
& original_size
) {
271 if (thumbnail_data
.empty())
275 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
277 TemplateURLService
* template_url_service
=
278 TemplateURLServiceFactory::GetForProfile(profile
);
279 if (!template_url_service
)
281 const TemplateURL
* const default_provider
=
282 template_url_service
->GetDefaultSearchProvider();
283 if (!default_provider
)
286 TemplateURLRef::SearchTermsArgs search_args
=
287 TemplateURLRef::SearchTermsArgs(base::string16());
288 search_args
.image_thumbnail_content
= thumbnail_data
;
289 // TODO(jnd): Add a method in WebContentsViewDelegate to get the image URL
290 // from the ContextMenuParams which creates current context menu.
291 search_args
.image_url
= GURL();
292 search_args
.image_original_size
= original_size
;
293 TemplateURLRef::PostContent post_content
;
294 GURL
result(default_provider
->image_url_ref().ReplaceSearchTerms(
295 search_args
, template_url_service
->search_terms_data(), &post_content
));
296 if (!result
.is_valid())
299 content::OpenURLParams
open_url_params(
300 result
, content::Referrer(), NEW_FOREGROUND_TAB
,
301 ui::PAGE_TRANSITION_LINK
, false);
302 const std::string
& content_type
= post_content
.first
;
303 std::string
* post_data
= &post_content
.second
;
304 if (!post_data
->empty()) {
305 DCHECK(!content_type
.empty());
306 open_url_params
.uses_post
= true;
307 open_url_params
.browser_initiated_post_data
=
308 base::RefCountedString::TakeString(post_data
);
309 open_url_params
.extra_headers
+= base::StringPrintf(
310 "%s: %s\r\n", net::HttpRequestHeaders::kContentType
,
311 content_type
.c_str());
313 web_contents()->OpenURL(open_url_params
);