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/ui/tab_contents/tab_contents_wrapper.h"
6
7#include "base/lazy_instance.h"
8#include "chrome/browser/autocomplete_history_manager.h"
9#include "chrome/browser/autofill/autofill_manager.h"
10#include "chrome/browser/automation/automation_tab_helper.h"
11#include "chrome/browser/bookmarks/bookmark_model.h"
12#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
13#include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h"
14#include "chrome/browser/extensions/extension_tab_helper.h"
15#include "chrome/browser/extensions/extension_webnavigation_api.h"
16#include "chrome/browser/file_select_helper.h"
17#include "chrome/browser/history/history.h"
18#include "chrome/browser/history/top_sites.h"
19#include "chrome/browser/password_manager/password_manager.h"
20#include "chrome/browser/password_manager_delegate_impl.h"
21#include "chrome/browser/prefs/pref_service.h"
22#include "chrome/browser/prerender/prerender_observer.h"
23#include "chrome/browser/printing/print_preview_message_handler.h"
24#include "chrome/browser/profiles/profile.h"
25#include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h"
26#include "chrome/browser/translate/translate_tab_helper.h"
27#include "chrome/browser/ui/download/download_tab_helper.h"
28#include "chrome/browser/ui/find_bar/find_tab_helper.h"
29#include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
30#include "chrome/browser/ui/tab_contents/tab_contents_wrapper_delegate.h"
31#include "chrome/common/pref_names.h"
32#include "chrome/common/render_messages.h"
33#include "content/browser/tab_contents/tab_contents.h"
34#include "content/common/notification_service.h"
35#include "content/common/view_messages.h"
36#include "grit/generated_resources.h"
37#include "grit/locale_settings.h"
38#include "grit/platform_locale_settings.h"
39#include "ui/base/l10n/l10n_util.h"
40#include "webkit/glue/webpreferences.h"
41
42static base::LazyInstance<PropertyAccessor<TabContentsWrapper*> >
43    g_tab_contents_wrapper_property_accessor(base::LINKER_INITIALIZED);
44
45////////////////////////////////////////////////////////////////////////////////
46// TabContentsWrapper, public:
47
48TabContentsWrapper::TabContentsWrapper(TabContents* contents)
49    : TabContentsObserver(contents),
50      delegate_(NULL),
51      is_starred_(false),
52      tab_contents_(contents) {
53  DCHECK(contents);
54  // Stash this in the property bag so it can be retrieved without having to
55  // go to a Browser.
56  property_accessor()->SetProperty(contents->property_bag(), this);
57
58  // Create the tab helpers.
59  autocomplete_history_manager_.reset(new AutocompleteHistoryManager(contents));
60  autofill_manager_.reset(new AutofillManager(contents));
61  automation_tab_helper_.reset(new AutomationTabHelper(contents));
62  download_tab_helper_.reset(new DownloadTabHelper(contents));
63  extension_tab_helper_.reset(new ExtensionTabHelper(this));
64  find_tab_helper_.reset(new FindTabHelper(contents));
65  password_manager_delegate_.reset(new PasswordManagerDelegateImpl(contents));
66  password_manager_.reset(
67      new PasswordManager(contents, password_manager_delegate_.get()));
68  search_engine_tab_helper_.reset(new SearchEngineTabHelper(contents));
69  translate_tab_helper_.reset(new TranslateTabHelper(contents));
70  print_view_manager_.reset(new printing::PrintViewManager(contents));
71
72  // Register for notifications about URL starredness changing on any profile.
73  registrar_.Add(this, NotificationType::URLS_STARRED,
74                 NotificationService::AllSources());
75  registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
76                 NotificationService::AllSources());
77
78  // Create the per-tab observers.
79  file_select_observer_.reset(new FileSelectObserver(contents));
80  prerender_observer_.reset(new prerender::PrerenderObserver(contents));
81  print_preview_.reset(new printing::PrintPreviewMessageHandler(contents));
82  webnavigation_observer_.reset(
83      new ExtensionWebNavigationTabObserver(contents));
84}
85
86TabContentsWrapper::~TabContentsWrapper() {
87  // We don't want any notifications while we're running our destructor.
88  registrar_.RemoveAll();
89}
90
91PropertyAccessor<TabContentsWrapper*>* TabContentsWrapper::property_accessor() {
92  return g_tab_contents_wrapper_property_accessor.Pointer();
93}
94
95void TabContentsWrapper::RegisterUserPrefs(PrefService* prefs) {
96  prefs->RegisterBooleanPref(prefs::kAlternateErrorPagesEnabled, true);
97
98  WebPreferences pref_defaults;
99  prefs->RegisterBooleanPref(prefs::kWebKitJavascriptEnabled,
100                             pref_defaults.javascript_enabled);
101  prefs->RegisterBooleanPref(prefs::kWebKitWebSecurityEnabled,
102                             pref_defaults.web_security_enabled);
103  prefs->RegisterBooleanPref(
104      prefs::kWebKitJavascriptCanOpenWindowsAutomatically, true);
105  prefs->RegisterBooleanPref(prefs::kWebKitLoadsImagesAutomatically,
106                             pref_defaults.loads_images_automatically);
107  prefs->RegisterBooleanPref(prefs::kWebKitPluginsEnabled,
108                             pref_defaults.plugins_enabled);
109  prefs->RegisterBooleanPref(prefs::kWebKitDomPasteEnabled,
110                             pref_defaults.dom_paste_enabled);
111  prefs->RegisterBooleanPref(prefs::kWebKitShrinksStandaloneImagesToFit,
112                             pref_defaults.shrinks_standalone_images_to_fit);
113  prefs->RegisterDictionaryPref(prefs::kWebKitInspectorSettings);
114  prefs->RegisterBooleanPref(prefs::kWebKitTextAreasAreResizable,
115                             pref_defaults.text_areas_are_resizable);
116  prefs->RegisterBooleanPref(prefs::kWebKitJavaEnabled,
117                             pref_defaults.java_enabled);
118  prefs->RegisterBooleanPref(prefs::kWebkitTabsToLinks,
119                             pref_defaults.tabs_to_links);
120
121  prefs->RegisterLocalizedStringPref(prefs::kAcceptLanguages,
122                                     IDS_ACCEPT_LANGUAGES);
123  prefs->RegisterLocalizedStringPref(prefs::kDefaultCharset,
124                                     IDS_DEFAULT_ENCODING);
125  prefs->RegisterLocalizedStringPref(prefs::kWebKitStandardFontFamily,
126                                     IDS_STANDARD_FONT_FAMILY);
127  prefs->RegisterLocalizedStringPref(prefs::kWebKitFixedFontFamily,
128                                     IDS_FIXED_FONT_FAMILY);
129  prefs->RegisterLocalizedStringPref(prefs::kWebKitSerifFontFamily,
130                                     IDS_SERIF_FONT_FAMILY);
131  prefs->RegisterLocalizedStringPref(prefs::kWebKitSansSerifFontFamily,
132                                     IDS_SANS_SERIF_FONT_FAMILY);
133  prefs->RegisterLocalizedStringPref(prefs::kWebKitCursiveFontFamily,
134                                     IDS_CURSIVE_FONT_FAMILY);
135  prefs->RegisterLocalizedStringPref(prefs::kWebKitFantasyFontFamily,
136                                     IDS_FANTASY_FONT_FAMILY);
137  prefs->RegisterLocalizedIntegerPref(prefs::kWebKitDefaultFontSize,
138                                      IDS_DEFAULT_FONT_SIZE);
139  prefs->RegisterLocalizedIntegerPref(prefs::kWebKitDefaultFixedFontSize,
140                                      IDS_DEFAULT_FIXED_FONT_SIZE);
141  prefs->RegisterLocalizedIntegerPref(prefs::kWebKitMinimumFontSize,
142                                      IDS_MINIMUM_FONT_SIZE);
143  prefs->RegisterLocalizedIntegerPref(prefs::kWebKitMinimumLogicalFontSize,
144                                      IDS_MINIMUM_LOGICAL_FONT_SIZE);
145  prefs->RegisterLocalizedBooleanPref(prefs::kWebKitUsesUniversalDetector,
146                                      IDS_USES_UNIVERSAL_DETECTOR);
147  prefs->RegisterLocalizedStringPref(prefs::kStaticEncodings,
148                                     IDS_STATIC_ENCODING_LIST);
149  prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, "");
150}
151
152string16 TabContentsWrapper::GetDefaultTitle() {
153  return l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE);
154}
155
156string16 TabContentsWrapper::GetStatusText() const {
157  if (!tab_contents()->is_loading() ||
158      tab_contents()->load_state() == net::LOAD_STATE_IDLE) {
159    return string16();
160  }
161
162  switch (tab_contents()->load_state()) {
163    case net::LOAD_STATE_WAITING_FOR_CACHE:
164      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_CACHE);
165    case net::LOAD_STATE_ESTABLISHING_PROXY_TUNNEL:
166      return
167          l10n_util::GetStringUTF16(IDS_LOAD_STATE_ESTABLISHING_PROXY_TUNNEL);
168    case net::LOAD_STATE_RESOLVING_PROXY_FOR_URL:
169      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_PROXY_FOR_URL);
170    case net::LOAD_STATE_RESOLVING_HOST:
171      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_HOST);
172    case net::LOAD_STATE_CONNECTING:
173      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_CONNECTING);
174    case net::LOAD_STATE_SSL_HANDSHAKE:
175      return l10n_util::GetStringUTF16(IDS_LOAD_STATE_SSL_HANDSHAKE);
176    case net::LOAD_STATE_SENDING_REQUEST:
177      if (tab_contents()->upload_size())
178        return l10n_util::GetStringFUTF16Int(
179                    IDS_LOAD_STATE_SENDING_REQUEST_WITH_PROGRESS,
180                    static_cast<int>((100 * tab_contents()->upload_position()) /
181                        tab_contents()->upload_size()));
182      else
183        return l10n_util::GetStringUTF16(IDS_LOAD_STATE_SENDING_REQUEST);
184    case net::LOAD_STATE_WAITING_FOR_RESPONSE:
185      return l10n_util::GetStringFUTF16(IDS_LOAD_STATE_WAITING_FOR_RESPONSE,
186                                        tab_contents()->load_state_host());
187    // Ignore net::LOAD_STATE_READING_RESPONSE and net::LOAD_STATE_IDLE
188    case net::LOAD_STATE_IDLE:
189    case net::LOAD_STATE_READING_RESPONSE:
190      break;
191  }
192
193  return string16();
194}
195
196TabContentsWrapper* TabContentsWrapper::Clone() {
197  TabContents* new_contents = tab_contents()->Clone();
198  TabContentsWrapper* new_wrapper = new TabContentsWrapper(new_contents);
199
200  new_wrapper->extension_tab_helper()->CopyStateFrom(
201      *extension_tab_helper_.get());
202  return new_wrapper;
203}
204
205TabContentsWrapper* TabContentsWrapper::GetCurrentWrapperForContents(
206    TabContents* contents) {
207  TabContentsWrapper** wrapper =
208      property_accessor()->GetProperty(contents->property_bag());
209
210  return wrapper ? *wrapper : NULL;
211}
212
213////////////////////////////////////////////////////////////////////////////////
214// TabContentsWrapper, TabContentsObserver implementation:
215
216void TabContentsWrapper::DidNavigateMainFramePostCommit(
217    const NavigationController::LoadCommittedDetails& /*details*/,
218    const ViewHostMsg_FrameNavigate_Params& /*params*/) {
219  UpdateStarredStateForCurrentURL();
220}
221
222bool TabContentsWrapper::OnMessageReceived(const IPC::Message& message) {
223  bool handled = true;
224  IPC_BEGIN_MESSAGE_MAP(TabContentsWrapper, message)
225    IPC_MESSAGE_HANDLER(ViewHostMsg_PageContents, OnPageContents)
226    IPC_MESSAGE_HANDLER(ViewHostMsg_JSOutOfMemory, OnJSOutOfMemory)
227    IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterProtocolHandler,
228                        OnRegisterProtocolHandler)
229    IPC_MESSAGE_HANDLER(ViewHostMsg_Thumbnail, OnMsgThumbnail)
230    IPC_MESSAGE_UNHANDLED(handled = false)
231  IPC_END_MESSAGE_MAP()
232  return handled;
233}
234
235////////////////////////////////////////////////////////////////////////////////
236// TabContentsWrapper, NotificationObserver implementation:
237
238void TabContentsWrapper::Observe(NotificationType type,
239                                 const NotificationSource& source,
240                                 const NotificationDetails& details) {
241  switch (type.value) {
242    case NotificationType::BOOKMARK_MODEL_LOADED:
243      // BookmarkModel finished loading, fall through to update starred state.
244    case NotificationType::URLS_STARRED: {
245      // Somewhere, a URL has been starred.
246      // Ignore notifications for profiles other than our current one.
247      Profile* source_profile = Source<Profile>(source).ptr();
248      if (!source_profile || !source_profile->IsSameProfile(profile()))
249        return;
250
251      UpdateStarredStateForCurrentURL();
252      break;
253    }
254
255    default:
256      NOTREACHED();
257  }
258}
259
260////////////////////////////////////////////////////////////////////////////////
261// Internal helpers
262
263void TabContentsWrapper::OnPageContents(const GURL& url,
264                                        int32 page_id,
265                                        const string16& contents) {
266  // Don't index any https pages. People generally don't want their bank
267  // accounts, etc. indexed on their computer, especially since some of these
268  // things are not marked cachable.
269  // TODO(brettw) we may want to consider more elaborate heuristics such as
270  // the cachability of the page. We may also want to consider subframes (this
271  // test will still index subframes if the subframe is SSL).
272  // TODO(zelidrag) bug chromium-os:2808 - figure out if we want to reenable
273  // content indexing for chromeos in some future releases.
274#if !defined(OS_CHROMEOS)
275  if (!url.SchemeIsSecure()) {
276    Profile* p = profile();
277    if (p && !p->IsOffTheRecord()) {
278      HistoryService* hs = p->GetHistoryService(Profile::IMPLICIT_ACCESS);
279      if (hs)
280        hs->SetPageContents(url, contents);
281    }
282  }
283#endif
284}
285
286void TabContentsWrapper::OnJSOutOfMemory() {
287  tab_contents()->AddInfoBar(new SimpleAlertInfoBarDelegate(tab_contents(),
288      NULL, l10n_util::GetStringUTF16(IDS_JS_OUT_OF_MEMORY_PROMPT), true));
289}
290
291void TabContentsWrapper::OnRegisterProtocolHandler(const std::string& protocol,
292                                                   const GURL& url,
293                                                   const string16& title) {
294  ProtocolHandlerRegistry* registry = profile()->GetProtocolHandlerRegistry();
295  ProtocolHandler* handler =
296      ProtocolHandler::CreateProtocolHandler(protocol, url, title);
297  if ((handler != NULL) &&
298      registry->CanSchemeBeOverridden(handler->protocol())) {
299    tab_contents()->AddInfoBar(registry->IsAlreadyRegistered(handler) ?
300      static_cast<InfoBarDelegate*>(new SimpleAlertInfoBarDelegate(
301          tab_contents(), NULL, l10n_util::GetStringFUTF16(
302              IDS_REGISTER_PROTOCOL_HANDLER_ALREADY_REGISTERED,
303              handler->title(), UTF8ToUTF16(handler->protocol())), true)) :
304      new RegisterProtocolHandlerInfoBarDelegate(tab_contents(), registry,
305                                                 handler));
306  }
307}
308
309void TabContentsWrapper::OnMsgThumbnail(const GURL& url,
310                                        const ThumbnailScore& score,
311                                        const SkBitmap& bitmap) {
312  if (profile()->IsOffTheRecord())
313    return;
314
315  // Tell History about this thumbnail
316  history::TopSites* ts = profile()->GetTopSites();
317  if (ts)
318    ts->SetPageThumbnail(url, bitmap, score);
319}
320
321void TabContentsWrapper::UpdateStarredStateForCurrentURL() {
322  BookmarkModel* model = tab_contents()->profile()->GetBookmarkModel();
323  const bool old_state = is_starred_;
324  is_starred_ = (model && model->IsBookmarked(tab_contents()->GetURL()));
325
326  if (is_starred_ != old_state && delegate())
327    delegate()->URLStarredChanged(this, is_starred_);
328}
329