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/guest_view/browser/guest_view_manager.h"
23 #include "components/search_engines/template_url.h"
24 #include "components/search_engines/template_url_service.h"
25 #include "components/web_cache/browser/web_cache_manager.h"
26 #include "content/public/browser/render_process_host.h"
27 #include "content/public/browser/render_view_host.h"
28 #include "content/public/browser/web_contents.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"));
95 auto guest_manager
= guest_view::GuestViewManager::FromBrowserContext(
96 source
->GetBrowserContext());
97 if (!source
->IsLoading() ||
98 source
->GetLoadState().state
== net::LOAD_STATE_IDLE
) {
99 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467185
101 tracked_objects::ScopedTracker
tracking_profile2(
102 FROM_HERE_WITH_EXPLICIT_FUNCTION(
103 "467185 CoreTabHelper::GetStatusTextForWebContents2"));
106 return guest_manager
->ForEachGuest(
107 source
, base::Bind(&CoreTabHelper::GetStatusTextForWebContents
,
111 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467185
113 tracked_objects::ScopedTracker
tracking_profile3(
114 FROM_HERE_WITH_EXPLICIT_FUNCTION(
115 "467185 CoreTabHelper::GetStatusTextForWebContents3"));
117 switch (source
->GetLoadState().state
) {
118 case net::LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL
:
119 case net::LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET
:
121 l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_SOCKET_SLOT
);
123 case net::LOAD_STATE_WAITING_FOR_DELEGATE
:
124 if (!source
->GetLoadState().param
.empty()) {
125 *status_text
= l10n_util::GetStringFUTF16(
126 IDS_LOAD_STATE_WAITING_FOR_DELEGATE
,
127 source
->GetLoadState().param
);
130 *status_text
= l10n_util::GetStringUTF16(
131 IDS_LOAD_STATE_WAITING_FOR_DELEGATE_GENERIC
);
134 case net::LOAD_STATE_WAITING_FOR_CACHE
:
136 l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_CACHE
);
138 case net::LOAD_STATE_WAITING_FOR_APPCACHE
:
140 l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_APPCACHE
);
142 case net::LOAD_STATE_ESTABLISHING_PROXY_TUNNEL
:
144 l10n_util::GetStringUTF16(IDS_LOAD_STATE_ESTABLISHING_PROXY_TUNNEL
);
146 case net::LOAD_STATE_DOWNLOADING_PROXY_SCRIPT
:
148 l10n_util::GetStringUTF16(IDS_LOAD_STATE_DOWNLOADING_PROXY_SCRIPT
);
150 case net::LOAD_STATE_RESOLVING_PROXY_FOR_URL
:
152 l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_PROXY_FOR_URL
);
154 case net::LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
:
155 *status_text
= l10n_util::GetStringUTF16(
156 IDS_LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
);
158 case net::LOAD_STATE_RESOLVING_HOST
:
159 *status_text
= l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_HOST
);
161 case net::LOAD_STATE_CONNECTING
:
162 *status_text
= l10n_util::GetStringUTF16(IDS_LOAD_STATE_CONNECTING
);
164 case net::LOAD_STATE_SSL_HANDSHAKE
:
165 *status_text
= l10n_util::GetStringUTF16(IDS_LOAD_STATE_SSL_HANDSHAKE
);
167 case net::LOAD_STATE_SENDING_REQUEST
:
168 if (source
->GetUploadSize()) {
169 *status_text
= l10n_util::GetStringFUTF16Int(
170 IDS_LOAD_STATE_SENDING_REQUEST_WITH_PROGRESS
,
171 static_cast<int>((100 * source
->GetUploadPosition()) /
172 source
->GetUploadSize()));
176 l10n_util::GetStringUTF16(IDS_LOAD_STATE_SENDING_REQUEST
);
179 case net::LOAD_STATE_WAITING_FOR_RESPONSE
:
181 l10n_util::GetStringFUTF16(IDS_LOAD_STATE_WAITING_FOR_RESPONSE
,
182 source
->GetLoadStateHost());
184 // Ignore net::LOAD_STATE_READING_RESPONSE and net::LOAD_STATE_IDLE
185 case net::LOAD_STATE_IDLE
:
186 case net::LOAD_STATE_READING_RESPONSE
:
192 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467185 is
194 tracked_objects::ScopedTracker
tracking_profile4(
195 FROM_HERE_WITH_EXPLICIT_FUNCTION(
196 "467185 CoreTabHelper::GetStatusTextForWebContents4"));
197 return guest_manager
->ForEachGuest(
198 source
, base::Bind(&CoreTabHelper::GetStatusTextForWebContents
,
202 ////////////////////////////////////////////////////////////////////////////////
203 // WebContentsObserver overrides
205 void CoreTabHelper::DidStartLoading() {
206 UpdateContentRestrictions(0);
209 void CoreTabHelper::WasShown() {
210 web_cache::WebCacheManager::GetInstance()->ObserveActivity(
211 web_contents()->GetRenderProcessHost()->GetID());
214 void CoreTabHelper::WebContentsDestroyed() {
215 // OnCloseStarted isn't called in unit tests.
216 if (!close_start_time_
.is_null()) {
217 bool fast_tab_close_enabled
=
218 base::CommandLine::ForCurrentProcess()->HasSwitch(
219 switches::kEnableFastUnload
);
221 if (fast_tab_close_enabled
) {
222 base::TimeTicks now
= base::TimeTicks::Now();
223 base::TimeDelta close_time
= now
- close_start_time_
;
224 UMA_HISTOGRAM_TIMES("Tab.Close", close_time
);
226 base::TimeTicks unload_start_time
= close_start_time_
;
227 base::TimeTicks unload_end_time
= now
;
228 if (!before_unload_end_time_
.is_null())
229 unload_start_time
= before_unload_end_time_
;
230 if (!unload_detached_start_time_
.is_null())
231 unload_end_time
= unload_detached_start_time_
;
232 base::TimeDelta unload_time
= unload_end_time
- unload_start_time
;
233 UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", unload_time
);
235 base::TimeTicks now
= base::TimeTicks::Now();
236 base::TimeTicks unload_start_time
= close_start_time_
;
237 if (!before_unload_end_time_
.is_null())
238 unload_start_time
= before_unload_end_time_
;
239 UMA_HISTOGRAM_TIMES("Tab.Close", now
- close_start_time_
);
240 UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", now
- unload_start_time
);
245 void CoreTabHelper::BeforeUnloadFired(const base::TimeTicks
& proceed_time
) {
246 before_unload_end_time_
= proceed_time
;
249 void CoreTabHelper::BeforeUnloadDialogCancelled() {
253 bool CoreTabHelper::OnMessageReceived(
254 const IPC::Message
& message
,
255 content::RenderFrameHost
* render_frame_host
) {
257 IPC_BEGIN_MESSAGE_MAP(CoreTabHelper
, message
)
258 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestThumbnailForContextNode_ACK
,
259 OnRequestThumbnailForContextNodeACK
)
260 IPC_MESSAGE_UNHANDLED(handled
= false)
261 IPC_END_MESSAGE_MAP()
265 // Handles the image thumbnail for the context node, composes a image search
266 // request based on the received thumbnail and opens the request in a new tab.
267 void CoreTabHelper::OnRequestThumbnailForContextNodeACK(
268 const std::string
& thumbnail_data
,
269 const gfx::Size
& original_size
) {
270 if (thumbnail_data
.empty())
274 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
276 TemplateURLService
* template_url_service
=
277 TemplateURLServiceFactory::GetForProfile(profile
);
278 if (!template_url_service
)
280 const TemplateURL
* const default_provider
=
281 template_url_service
->GetDefaultSearchProvider();
282 if (!default_provider
)
285 TemplateURLRef::SearchTermsArgs search_args
=
286 TemplateURLRef::SearchTermsArgs(base::string16());
287 search_args
.image_thumbnail_content
= thumbnail_data
;
288 // TODO(jnd): Add a method in WebContentsViewDelegate to get the image URL
289 // from the ContextMenuParams which creates current context menu.
290 search_args
.image_url
= GURL();
291 search_args
.image_original_size
= original_size
;
292 TemplateURLRef::PostContent post_content
;
293 GURL
result(default_provider
->image_url_ref().ReplaceSearchTerms(
294 search_args
, template_url_service
->search_terms_data(), &post_content
));
295 if (!result
.is_valid())
298 content::OpenURLParams
open_url_params(
299 result
, content::Referrer(), NEW_FOREGROUND_TAB
,
300 ui::PAGE_TRANSITION_LINK
, false);
301 const std::string
& content_type
= post_content
.first
;
302 std::string
* post_data
= &post_content
.second
;
303 if (!post_data
->empty()) {
304 DCHECK(!content_type
.empty());
305 open_url_params
.uses_post
= true;
306 open_url_params
.browser_initiated_post_data
=
307 base::RefCountedString::TakeString(post_data
);
308 open_url_params
.extra_headers
+= base::StringPrintf(
309 "%s: %s\r\n", net::HttpRequestHeaders::kContentType
,
310 content_type
.c_str());
312 web_contents()->OpenURL(open_url_params
);