core_tab_helper.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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.
4
5#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
6
7#include <string>
8#include <vector>
9
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"
33
34#if defined(OS_WIN)
35#include "base/win/win_util.h"
36#endif
37
38using content::WebContents;
39
40DEFINE_WEB_CONTENTS_USER_DATA_KEY(CoreTabHelper);
41
42CoreTabHelper::CoreTabHelper(WebContents* web_contents)
43    : content::WebContentsObserver(web_contents),
44      delegate_(NULL),
45      content_restrictions_(0) {
46}
47
48CoreTabHelper::~CoreTabHelper() {
49}
50
51string16 CoreTabHelper::GetDefaultTitle() {
52  return l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE);
53}
54
55string16 CoreTabHelper::GetStatusText() const {
56  if (!web_contents()->IsLoading() ||
57      web_contents()->GetLoadState().state == net::LOAD_STATE_IDLE) {
58    return string16();
59  }
60
61  switch (web_contents()->GetLoadState().state) {
62    case net::LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL:
63    case net::LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET:
64      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_SOCKET_SLOT);
65    case net::LOAD_STATE_WAITING_FOR_DELEGATE:
66      if (!web_contents()->GetLoadState().param.empty()) {
67        return l10n_util::GetStringFUTF16(IDS_LOAD_STATE_WAITING_FOR_DELEGATE,
68                                          web_contents()->GetLoadState().param);
69      } else {
70        return l10n_util::GetStringUTF16(
71            IDS_LOAD_STATE_WAITING_FOR_DELEGATE_GENERIC);
72      }
73    case net::LOAD_STATE_WAITING_FOR_CACHE:
74      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_CACHE);
75    case net::LOAD_STATE_WAITING_FOR_APPCACHE:
76      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_APPCACHE);
77    case net::LOAD_STATE_ESTABLISHING_PROXY_TUNNEL:
78      return
79          l10n_util::GetStringUTF16(IDS_LOAD_STATE_ESTABLISHING_PROXY_TUNNEL);
80    case net::LOAD_STATE_DOWNLOADING_PROXY_SCRIPT:
81      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_DOWNLOADING_PROXY_SCRIPT);
82    case net::LOAD_STATE_RESOLVING_PROXY_FOR_URL:
83      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_PROXY_FOR_URL);
84    case net::LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT:
85      return l10n_util::GetStringUTF16(
86          IDS_LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT);
87    case net::LOAD_STATE_RESOLVING_HOST:
88      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_HOST);
89    case net::LOAD_STATE_CONNECTING:
90      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_CONNECTING);
91    case net::LOAD_STATE_SSL_HANDSHAKE:
92      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_SSL_HANDSHAKE);
93    case net::LOAD_STATE_SENDING_REQUEST:
94      if (web_contents()->GetUploadSize()) {
95        return l10n_util::GetStringFUTF16Int(
96            IDS_LOAD_STATE_SENDING_REQUEST_WITH_PROGRESS,
97            static_cast<int>((100 * web_contents()->GetUploadPosition()) /
98                web_contents()->GetUploadSize()));
99      } else {
100        return l10n_util::GetStringUTF16(IDS_LOAD_STATE_SENDING_REQUEST);
101      }
102    case net::LOAD_STATE_WAITING_FOR_RESPONSE:
103      return l10n_util::GetStringFUTF16(IDS_LOAD_STATE_WAITING_FOR_RESPONSE,
104                                        web_contents()->GetLoadStateHost());
105    // Ignore net::LOAD_STATE_READING_RESPONSE and net::LOAD_STATE_IDLE
106    case net::LOAD_STATE_IDLE:
107    case net::LOAD_STATE_READING_RESPONSE:
108      break;
109  }
110
111  return string16();
112}
113
114void CoreTabHelper::OnCloseStarted() {
115  if (close_start_time_.is_null())
116    close_start_time_ = base::TimeTicks::Now();
117}
118
119void CoreTabHelper::OnCloseCanceled() {
120  close_start_time_ = base::TimeTicks();
121  before_unload_end_time_ = base::TimeTicks();
122  unload_detached_start_time_ = base::TimeTicks();
123}
124
125void CoreTabHelper::OnUnloadStarted() {
126  before_unload_end_time_ = base::TimeTicks::Now();
127}
128
129void CoreTabHelper::OnUnloadDetachedStarted() {
130  if (unload_detached_start_time_.is_null())
131    unload_detached_start_time_ = base::TimeTicks::Now();
132}
133
134void CoreTabHelper::UpdateContentRestrictions(int content_restrictions) {
135  content_restrictions_ = content_restrictions;
136#if !defined(OS_ANDROID)
137  Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
138  if (!browser)
139    return;
140
141  browser->command_controller()->ContentRestrictionsChanged();
142#endif
143}
144
145////////////////////////////////////////////////////////////////////////////////
146// WebContentsObserver overrides
147
148void CoreTabHelper::DidStartLoading(content::RenderViewHost* render_view_host) {
149  UpdateContentRestrictions(0);
150}
151
152void CoreTabHelper::WasShown() {
153  WebCacheManager::GetInstance()->ObserveActivity(
154      web_contents()->GetRenderProcessHost()->GetID());
155}
156
157void CoreTabHelper::WebContentsDestroyed(WebContents* web_contents) {
158  // OnCloseStarted isn't called in unit tests.
159  if (!close_start_time_.is_null()) {
160    bool fast_tab_close_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
161        switches::kEnableFastUnload);
162
163    if (fast_tab_close_enabled) {
164      base::TimeTicks now = base::TimeTicks::Now();
165      base::TimeDelta close_time = now - close_start_time_;
166      UMA_HISTOGRAM_TIMES("Tab.Close", close_time);
167
168      base::TimeTicks unload_start_time = close_start_time_;
169      base::TimeTicks unload_end_time = now;
170      if (!before_unload_end_time_.is_null())
171        unload_start_time = before_unload_end_time_;
172      if (!unload_detached_start_time_.is_null())
173        unload_end_time = unload_detached_start_time_;
174      base::TimeDelta unload_time = unload_end_time - unload_start_time;
175      UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", unload_time);
176    } else {
177      base::TimeTicks now = base::TimeTicks::Now();
178      base::TimeTicks unload_start_time = close_start_time_;
179      if (!before_unload_end_time_.is_null())
180        unload_start_time = before_unload_end_time_;
181      UMA_HISTOGRAM_TIMES("Tab.Close", now - close_start_time_);
182      UMA_HISTOGRAM_TIMES("Tab.Close.UnloadTime", now - unload_start_time);
183    }
184  }
185}
186
187void CoreTabHelper::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
188  before_unload_end_time_ = proceed_time;
189}
190
191void CoreTabHelper::BeforeUnloadDialogCancelled() {
192  OnCloseCanceled();
193}
194
195bool CoreTabHelper::OnMessageReceived(const IPC::Message& message) {
196  bool handled = true;
197  IPC_BEGIN_MESSAGE_MAP(CoreTabHelper, message)
198    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FocusedNodeTouched,
199                        OnFocusedNodeTouched)
200    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestThumbnailForContextNode_ACK,
201                        OnRequestThumbnailForContextNodeACK)
202    IPC_MESSAGE_UNHANDLED(handled = false)
203  IPC_END_MESSAGE_MAP()
204  return handled;
205}
206
207void CoreTabHelper::OnFocusedNodeTouched(bool editable) {
208#if defined(OS_WIN) && defined(USE_AURA)
209  if (editable) {
210    base::win::DisplayVirtualKeyboard();
211  } else {
212    base::win::DismissVirtualKeyboard();
213  }
214#endif  // OS_WIN && USE_AURA
215}
216
217// Handles the image thumbnail for the context node, composes a image search
218// request based on the received thumbnail and opens the request in a new tab.
219void CoreTabHelper::OnRequestThumbnailForContextNodeACK(
220    const SkBitmap& bitmap,
221    const gfx::Size& original_size) {
222  if (bitmap.isNull())
223    return;
224  Profile* profile =
225      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
226
227  TemplateURLService* template_url_service =
228      TemplateURLServiceFactory::GetForProfile(profile);
229  if (!template_url_service)
230    return;
231  const TemplateURL* const default_provider =
232      template_url_service->GetDefaultSearchProvider();
233  if (!default_provider)
234    return;
235
236  const int kDefaultQualityForImageSearch = 90;
237  std::vector<unsigned char> data;
238  if (!gfx::JPEGCodec::Encode(
239      reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
240      gfx::JPEGCodec::FORMAT_SkBitmap, bitmap.width(), bitmap.height(),
241      static_cast<int>(bitmap.rowBytes()), kDefaultQualityForImageSearch,
242      &data))
243    return;
244
245  TemplateURLRef::SearchTermsArgs search_args =
246      TemplateURLRef::SearchTermsArgs(base::string16());
247  search_args.image_thumbnail_content = std::string(data.begin(), data.end());
248  // TODO(jnd): Add a method in WebContentsViewDelegate to get the image URL
249  // from the ContextMenuParams which creates current context menu.
250  search_args.image_url = GURL();
251  search_args.image_original_size = original_size;
252  TemplateURLRef::PostContent post_content;
253  GURL result(default_provider->image_url_ref().ReplaceSearchTerms(
254      search_args, &post_content));
255  if (!result.is_valid())
256    return;
257
258  content::OpenURLParams open_url_params(
259      result, content::Referrer(), NEW_FOREGROUND_TAB,
260      content::PAGE_TRANSITION_LINK, false);
261  const std::string& content_type = post_content.first;
262  std::string* post_data = &post_content.second;
263  if (!post_data->empty()) {
264    DCHECK(!content_type.empty());
265    open_url_params.uses_post = true;
266    open_url_params.browser_initiated_post_data =
267        base::RefCountedString::TakeString(post_data);
268    open_url_params.extra_headers += base::StringPrintf(
269        "%s: %s\r\n", net::HttpRequestHeaders::kContentType,
270        content_type.c_str());
271  }
272  web_contents()->OpenURL(open_url_params);
273}
274