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/strings/stringprintf.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/renderer_host/web_cache_manager.h"
15 #include "chrome/browser/search_engines/search_terms_data.h"
16 #include "chrome/browser/search_engines/template_url.h"
17 #include "chrome/browser/search_engines/template_url_service.h"
18 #include "chrome/browser/search_engines/template_url_service_factory.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_command_controller.h"
21 #include "chrome/browser/ui/browser_finder.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/render_messages.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/render_view_host.h"
26 #include "content/public/browser/web_contents.h"
27 #include "grit/generated_resources.h"
28 #include "net/base/load_states.h"
29 #include "net/http/http_request_headers.h"
30 #include "third_party/skia/include/core/SkBitmap.h"
31 #include "ui/base/l10n/l10n_util.h"
32 #include "ui/gfx/codec/jpeg_codec.h"
34 using content::WebContents
;
36 DEFINE_WEB_CONTENTS_USER_DATA_KEY(CoreTabHelper
);
38 CoreTabHelper::CoreTabHelper(WebContents
* web_contents
)
39 : content::WebContentsObserver(web_contents
),
41 content_restrictions_(0) {
44 CoreTabHelper::~CoreTabHelper() {
47 base::string16
CoreTabHelper::GetDefaultTitle() {
48 return l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE
);
51 base::string16
CoreTabHelper::GetStatusText() const {
52 if (!web_contents()->IsLoading() ||
53 web_contents()->GetLoadState().state
== net::LOAD_STATE_IDLE
) {
54 return base::string16();
57 switch (web_contents()->GetLoadState().state
) {
58 case net::LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL
:
59 case net::LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET
:
60 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_SOCKET_SLOT
);
61 case net::LOAD_STATE_WAITING_FOR_DELEGATE
:
62 if (!web_contents()->GetLoadState().param
.empty()) {
63 return l10n_util::GetStringFUTF16(IDS_LOAD_STATE_WAITING_FOR_DELEGATE
,
64 web_contents()->GetLoadState().param
);
66 return l10n_util::GetStringUTF16(
67 IDS_LOAD_STATE_WAITING_FOR_DELEGATE_GENERIC
);
69 case net::LOAD_STATE_WAITING_FOR_CACHE
:
70 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_CACHE
);
71 case net::LOAD_STATE_WAITING_FOR_APPCACHE
:
72 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_APPCACHE
);
73 case net::LOAD_STATE_ESTABLISHING_PROXY_TUNNEL
:
75 l10n_util::GetStringUTF16(IDS_LOAD_STATE_ESTABLISHING_PROXY_TUNNEL
);
76 case net::LOAD_STATE_DOWNLOADING_PROXY_SCRIPT
:
77 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_DOWNLOADING_PROXY_SCRIPT
);
78 case net::LOAD_STATE_RESOLVING_PROXY_FOR_URL
:
79 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_PROXY_FOR_URL
);
80 case net::LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
:
81 return l10n_util::GetStringUTF16(
82 IDS_LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
);
83 case net::LOAD_STATE_RESOLVING_HOST
:
84 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_HOST
);
85 case net::LOAD_STATE_CONNECTING
:
86 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_CONNECTING
);
87 case net::LOAD_STATE_SSL_HANDSHAKE
:
88 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_SSL_HANDSHAKE
);
89 case net::LOAD_STATE_SENDING_REQUEST
:
90 if (web_contents()->GetUploadSize()) {
91 return l10n_util::GetStringFUTF16Int(
92 IDS_LOAD_STATE_SENDING_REQUEST_WITH_PROGRESS
,
93 static_cast<int>((100 * web_contents()->GetUploadPosition()) /
94 web_contents()->GetUploadSize()));
96 return l10n_util::GetStringUTF16(IDS_LOAD_STATE_SENDING_REQUEST
);
98 case net::LOAD_STATE_WAITING_FOR_RESPONSE
:
99 return l10n_util::GetStringFUTF16(IDS_LOAD_STATE_WAITING_FOR_RESPONSE
,
100 web_contents()->GetLoadStateHost());
101 // Ignore net::LOAD_STATE_READING_RESPONSE and net::LOAD_STATE_IDLE
102 case net::LOAD_STATE_IDLE
:
103 case net::LOAD_STATE_READING_RESPONSE
:
107 return base::string16();
110 void CoreTabHelper::OnCloseStarted() {
111 if (close_start_time_
.is_null())
112 close_start_time_
= base::TimeTicks::Now();
115 void CoreTabHelper::OnCloseCanceled() {
116 close_start_time_
= base::TimeTicks();
117 before_unload_end_time_
= base::TimeTicks();
118 unload_detached_start_time_
= base::TimeTicks();
121 void CoreTabHelper::OnUnloadStarted() {
122 before_unload_end_time_
= base::TimeTicks::Now();
125 void CoreTabHelper::OnUnloadDetachedStarted() {
126 if (unload_detached_start_time_
.is_null())
127 unload_detached_start_time_
= base::TimeTicks::Now();
130 void CoreTabHelper::UpdateContentRestrictions(int content_restrictions
) {
131 content_restrictions_
= content_restrictions
;
132 #if !defined(OS_ANDROID)
133 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents());
137 browser
->command_controller()->ContentRestrictionsChanged();
141 ////////////////////////////////////////////////////////////////////////////////
142 // WebContentsObserver overrides
144 void CoreTabHelper::DidStartLoading(content::RenderViewHost
* render_view_host
) {
145 UpdateContentRestrictions(0);
148 void CoreTabHelper::WasShown() {
149 WebCacheManager::GetInstance()->ObserveActivity(
150 web_contents()->GetRenderProcessHost()->GetID());
153 void CoreTabHelper::WebContentsDestroyed(WebContents
* web_contents
) {
154 // OnCloseStarted isn't called in unit tests.
155 if (!close_start_time_
.is_null()) {
156 bool fast_tab_close_enabled
= CommandLine::ForCurrentProcess()->HasSwitch(
157 switches::kEnableFastUnload
);
159 if (fast_tab_close_enabled
) {
160 base::TimeTicks now
= base::TimeTicks::Now();
161 base::TimeDelta close_time
= now
- close_start_time_
;
162 UMA_HISTOGRAM_TIMES("Tab.Close", close_time
);
164 base::TimeTicks unload_start_time
= close_start_time_
;
165 base::TimeTicks unload_end_time
= now
;
166 if (!before_unload_end_time_
.is_null())
167 unload_start_time
= before_unload_end_time_
;
168 if (!unload_detached_start_time_
.is_null())
169 unload_end_time
= unload_detached_start_time_
;
170 base::TimeDelta unload_time
= unload_end_time
- unload_start_time
;
171 UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", unload_time
);
173 base::TimeTicks now
= base::TimeTicks::Now();
174 base::TimeTicks unload_start_time
= close_start_time_
;
175 if (!before_unload_end_time_
.is_null())
176 unload_start_time
= before_unload_end_time_
;
177 UMA_HISTOGRAM_TIMES("Tab.Close", now
- close_start_time_
);
178 UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", now
- unload_start_time
);
183 void CoreTabHelper::BeforeUnloadFired(const base::TimeTicks
& proceed_time
) {
184 before_unload_end_time_
= proceed_time
;
187 void CoreTabHelper::BeforeUnloadDialogCancelled() {
191 bool CoreTabHelper::OnMessageReceived(const IPC::Message
& message
) {
193 IPC_BEGIN_MESSAGE_MAP(CoreTabHelper
, message
)
194 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestThumbnailForContextNode_ACK
,
195 OnRequestThumbnailForContextNodeACK
)
196 IPC_MESSAGE_UNHANDLED(handled
= false)
197 IPC_END_MESSAGE_MAP()
201 // Handles the image thumbnail for the context node, composes a image search
202 // request based on the received thumbnail and opens the request in a new tab.
203 void CoreTabHelper::OnRequestThumbnailForContextNodeACK(
204 const SkBitmap
& bitmap
,
205 const gfx::Size
& original_size
) {
209 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
211 TemplateURLService
* template_url_service
=
212 TemplateURLServiceFactory::GetForProfile(profile
);
213 if (!template_url_service
)
215 const TemplateURL
* const default_provider
=
216 template_url_service
->GetDefaultSearchProvider();
217 if (!default_provider
)
220 const int kDefaultQualityForImageSearch
= 90;
221 std::vector
<unsigned char> data
;
222 if (!gfx::JPEGCodec::Encode(
223 reinterpret_cast<unsigned char*>(bitmap
.getAddr32(0, 0)),
224 gfx::JPEGCodec::FORMAT_SkBitmap
, bitmap
.width(), bitmap
.height(),
225 static_cast<int>(bitmap
.rowBytes()), kDefaultQualityForImageSearch
,
229 TemplateURLRef::SearchTermsArgs search_args
=
230 TemplateURLRef::SearchTermsArgs(base::string16());
231 search_args
.image_thumbnail_content
= std::string(data
.begin(), data
.end());
232 // TODO(jnd): Add a method in WebContentsViewDelegate to get the image URL
233 // from the ContextMenuParams which creates current context menu.
234 search_args
.image_url
= GURL();
235 search_args
.image_original_size
= original_size
;
236 TemplateURLRef::PostContent post_content
;
237 GURL
result(default_provider
->image_url_ref().ReplaceSearchTerms(
238 search_args
, &post_content
));
239 if (!result
.is_valid())
242 content::OpenURLParams
open_url_params(
243 result
, content::Referrer(), NEW_FOREGROUND_TAB
,
244 content::PAGE_TRANSITION_LINK
, false);
245 const std::string
& content_type
= post_content
.first
;
246 std::string
* post_data
= &post_content
.second
;
247 if (!post_data
->empty()) {
248 DCHECK(!content_type
.empty());
249 open_url_params
.uses_post
= true;
250 open_url_params
.browser_initiated_post_data
=
251 base::RefCountedString::TakeString(post_data
);
252 open_url_params
.extra_headers
+= base::StringPrintf(
253 "%s: %s\r\n", net::HttpRequestHeaders::kContentType
,
254 content_type
.c_str());
256 web_contents()->OpenURL(open_url_params
);