// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "base/lazy_instance.h"
#include "chrome/browser/autocomplete_history_manager.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/automation/automation_tab_helper.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
#include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h"
#include "chrome/browser/extensions/extension_tab_helper.h"
#include "chrome/browser/extensions/extension_webnavigation_api.h"
#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/top_sites.h"
#include "chrome/browser/password_manager/password_manager.h"
#include "chrome/browser/password_manager_delegate_impl.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prerender/prerender_observer.h"
#include "chrome/browser/printing/print_preview_message_handler.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h"
#include "chrome/browser/translate/translate_tab_helper.h"
#include "chrome/browser/ui/download/download_tab_helper.h"
#include "chrome/browser/ui/find_bar/find_tab_helper.h"
#include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper_delegate.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_service.h"
#include "content/common/view_messages.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/platform_locale_settings.h"
#include "ui/base/l10n/l10n_util.h"
#include "webkit/glue/webpreferences.h"
static base::LazyInstance<PropertyAccessor<TabContentsWrapper*> >
g_tab_contents_wrapper_property_accessor(base::LINKER_INITIALIZED);
////////////////////////////////////////////////////////////////////////////////
// TabContentsWrapper, public:
TabContentsWrapper::TabContentsWrapper(TabContents* contents)
: TabContentsObserver(contents),
delegate_(NULL),
is_starred_(false),
tab_contents_(contents) {
DCHECK(contents);
// Stash this in the property bag so it can be retrieved without having to
// go to a Browser.
property_accessor()->SetProperty(contents->property_bag(), this);
// Create the tab helpers.
autocomplete_history_manager_.reset(new AutocompleteHistoryManager(contents));
autofill_manager_.reset(new AutofillManager(contents));
automation_tab_helper_.reset(new AutomationTabHelper(contents));
download_tab_helper_.reset(new DownloadTabHelper(contents));
extension_tab_helper_.reset(new ExtensionTabHelper(this));
find_tab_helper_.reset(new FindTabHelper(contents));
password_manager_delegate_.reset(new PasswordManagerDelegateImpl(contents));
password_manager_.reset(
new PasswordManager(contents, password_manager_delegate_.get()));
search_engine_tab_helper_.reset(new SearchEngineTabHelper(contents));
translate_tab_helper_.reset(new TranslateTabHelper(contents));
print_view_manager_.reset(new printing::PrintViewManager(contents));
// Register for notifications about URL starredness changing on any profile.
registrar_.Add(this, NotificationType::URLS_STARRED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
NotificationService::AllSources());
// Create the per-tab observers.
file_select_observer_.reset(new FileSelectObserver(contents));
prerender_observer_.reset(new prerender::PrerenderObserver(contents));
print_preview_.reset(new printing::PrintPreviewMessageHandler(contents));
webnavigation_observer_.reset(
new ExtensionWebNavigationTabObserver(contents));
}
TabContentsWrapper::~TabContentsWrapper() {
// We don't want any notifications while we're running our destructor.
registrar_.RemoveAll();
}
PropertyAccessor<TabContentsWrapper*>* TabContentsWrapper::property_accessor() {
return g_tab_contents_wrapper_property_accessor.Pointer();
}
void TabContentsWrapper::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterBooleanPref(prefs::kAlternateErrorPagesEnabled, true);
WebPreferences pref_defaults;
prefs->RegisterBooleanPref(prefs::kWebKitJavascriptEnabled,
pref_defaults.javascript_enabled);
prefs->RegisterBooleanPref(prefs::kWebKitWebSecurityEnabled,
pref_defaults.web_security_enabled);
prefs->RegisterBooleanPref(
prefs::kWebKitJavascriptCanOpenWindowsAutomatically, true);
prefs->RegisterBooleanPref(prefs::kWebKitLoadsImagesAutomatically,
pref_defaults.loads_images_automatically);
prefs->RegisterBooleanPref(prefs::kWebKitPluginsEnabled,
pref_defaults.plugins_enabled);
prefs->RegisterBooleanPref(prefs::kWebKitDomPasteEnabled,
pref_defaults.dom_paste_enabled);
prefs->RegisterBooleanPref(prefs::kWebKitShrinksStandaloneImagesToFit,
pref_defaults.shrinks_standalone_images_to_fit);
prefs->RegisterDictionaryPref(prefs::kWebKitInspectorSettings);
prefs->RegisterBooleanPref(prefs::kWebKitTextAreasAreResizable,
pref_defaults.text_areas_are_resizable);
prefs->RegisterBooleanPref(prefs::kWebKitJavaEnabled,
pref_defaults.java_enabled);
prefs->RegisterBooleanPref(prefs::kWebkitTabsToLinks,
pref_defaults.tabs_to_links);
prefs->RegisterLocalizedStringPref(prefs::kAcceptLanguages,
IDS_ACCEPT_LANGUAGES);
prefs->RegisterLocalizedStringPref(prefs::kDefaultCharset,
IDS_DEFAULT_ENCODING);
prefs->RegisterLocalizedStringPref(prefs::kWebKitStandardFontFamily,
IDS_STANDARD_FONT_FAMILY);
prefs->RegisterLocalizedStringPref(prefs::kWebKitFixedFontFamily,
IDS_FIXED_FONT_FAMILY);
prefs->RegisterLocalizedStringPref(prefs::kWebKitSerifFontFamily,
IDS_SERIF_FONT_FAMILY);
prefs->RegisterLocalizedStringPref(prefs::kWebKitSansSerifFontFamily,
IDS_SANS_SERIF_FONT_FAMILY);
prefs->RegisterLocalizedStringPref(prefs::kWebKitCursiveFontFamily,
IDS_CURSIVE_FONT_FAMILY);
prefs->RegisterLocalizedStringPref(prefs::kWebKitFantasyFontFamily,
IDS_FANTASY_FONT_FAMILY);
prefs->RegisterLocalizedIntegerPref(prefs::kWebKitDefaultFontSize,
IDS_DEFAULT_FONT_SIZE);
prefs->RegisterLocalizedIntegerPref(prefs::kWebKitDefaultFixedFontSize,
IDS_DEFAULT_FIXED_FONT_SIZE);
prefs->RegisterLocalizedIntegerPref(prefs::kWebKitMinimumFontSize,
IDS_MINIMUM_FONT_SIZE);
prefs->RegisterLocalizedIntegerPref(prefs::kWebKitMinimumLogicalFontSize,
IDS_MINIMUM_LOGICAL_FONT_SIZE);
prefs->RegisterLocalizedBooleanPref(prefs::kWebKitUsesUniversalDetector,
IDS_USES_UNIVERSAL_DETECTOR);
prefs->RegisterLocalizedStringPref(prefs::kStaticEncodings,
IDS_STATIC_ENCODING_LIST);
prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, "");
}
string16 TabContentsWrapper::GetDefaultTitle() {
return l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE);
}
string16 TabContentsWrapper::GetStatusText() const {
if (!tab_contents()->is_loading() ||
tab_contents()->load_state() == net::LOAD_STATE_IDLE) {
return string16();
}
switch (tab_contents()->load_state()) {
case net::LOAD_STATE_WAITING_FOR_CACHE:
return l10n_util::GetStringUTF16(IDS_LOAD_STATE_WAITING_FOR_CACHE);
case net::LOAD_STATE_ESTABLISHING_PROXY_TUNNEL:
return
l10n_util::GetStringUTF16(IDS_LOAD_STATE_ESTABLISHING_PROXY_TUNNEL);
case net::LOAD_STATE_RESOLVING_PROXY_FOR_URL:
return l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_PROXY_FOR_URL);
case net::LOAD_STATE_RESOLVING_HOST:
return l10n_util::GetStringUTF16(IDS_LOAD_STATE_RESOLVING_HOST);
case net::LOAD_STATE_CONNECTING:
return l10n_util::GetStringUTF16(IDS_LOAD_STATE_CONNECTING);
case net::LOAD_STATE_SSL_HANDSHAKE:
return l10n_util::GetStringUTF16(IDS_LOAD_STATE_SSL_HANDSHAKE);
case net::LOAD_STATE_SENDING_REQUEST:
if (tab_contents()->upload_size())
return l10n_util::GetStringFUTF16Int(
IDS_LOAD_STATE_SENDING_REQUEST_WITH_PROGRESS,
static_cast<int>((100 * tab_contents()->upload_position()) /
tab_contents()->upload_size()));
else
return l10n_util::GetStringUTF16(IDS_LOAD_STATE_SENDING_REQUEST);
case net::LOAD_STATE_WAITING_FOR_RESPONSE:
return l10n_util::GetStringFUTF16(IDS_LOAD_STATE_WAITING_FOR_RESPONSE,
tab_contents()->load_state_host());
// Ignore net::LOAD_STATE_READING_RESPONSE and net::LOAD_STATE_IDLE
case net::LOAD_STATE_IDLE:
case net::LOAD_STATE_READING_RESPONSE:
break;
}
return string16();
}
TabContentsWrapper* TabContentsWrapper::Clone() {
TabContents* new_contents = tab_contents()->Clone();
TabContentsWrapper* new_wrapper = new TabContentsWrapper(new_contents);
new_wrapper->extension_tab_helper()->CopyStateFrom(
*extension_tab_helper_.get());
return new_wrapper;
}
TabContentsWrapper* TabContentsWrapper::GetCurrentWrapperForContents(
TabContents* contents) {
TabContentsWrapper** wrapper =
property_accessor()->GetProperty(contents->property_bag());
return wrapper ? *wrapper : NULL;
}
////////////////////////////////////////////////////////////////////////////////
// TabContentsWrapper, TabContentsObserver implementation:
void TabContentsWrapper::DidNavigateMainFramePostCommit(
const NavigationController::LoadCommittedDetails& /*details*/,
const ViewHostMsg_FrameNavigate_Params& /*params*/) {
UpdateStarredStateForCurrentURL();
}
bool TabContentsWrapper::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(TabContentsWrapper, message)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageContents, OnPageContents)
IPC_MESSAGE_HANDLER(ViewHostMsg_JSOutOfMemory, OnJSOutOfMemory)
IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterProtocolHandler,
OnRegisterProtocolHandler)
IPC_MESSAGE_HANDLER(ViewHostMsg_Thumbnail, OnMsgThumbnail)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
////////////////////////////////////////////////////////////////////////////////
// TabContentsWrapper, NotificationObserver implementation:
void TabContentsWrapper::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type.value) {
case NotificationType::BOOKMARK_MODEL_LOADED:
// BookmarkModel finished loading, fall through to update starred state.
case NotificationType::URLS_STARRED: {
// Somewhere, a URL has been starred.
// Ignore notifications for profiles other than our current one.
Profile* source_profile = Source<Profile>(source).ptr();
if (!source_profile || !source_profile->IsSameProfile(profile()))
return;
UpdateStarredStateForCurrentURL();
break;
}
default:
NOTREACHED();
}
}
////////////////////////////////////////////////////////////////////////////////
// Internal helpers
void TabContentsWrapper::OnPageContents(const GURL& url,
int32 page_id,
const string16& contents) {
// Don't index any https pages. People generally don't want their bank
// accounts, etc. indexed on their computer, especially since some of these
// things are not marked cachable.
// TODO(brettw) we may want to consider more elaborate heuristics such as
// the cachability of the page. We may also want to consider subframes (this
// test will still index subframes if the subframe is SSL).
// TODO(zelidrag) bug chromium-os:2808 - figure out if we want to reenable
// content indexing for chromeos in some future releases.
#if !defined(OS_CHROMEOS)
if (!url.SchemeIsSecure()) {
Profile* p = profile();
if (p && !p->IsOffTheRecord()) {
HistoryService* hs = p->GetHistoryService(Profile::IMPLICIT_ACCESS);
if (hs)
hs->SetPageContents(url, contents);
}
}
#endif
}
void TabContentsWrapper::OnJSOutOfMemory() {
tab_contents()->AddInfoBar(new SimpleAlertInfoBarDelegate(tab_contents(),
NULL, l10n_util::GetStringUTF16(IDS_JS_OUT_OF_MEMORY_PROMPT), true));
}
void TabContentsWrapper::OnRegisterProtocolHandler(const std::string& protocol,
const GURL& url,
const string16& title) {
ProtocolHandlerRegistry* registry = profile()->GetProtocolHandlerRegistry();
ProtocolHandler* handler =
ProtocolHandler::CreateProtocolHandler(protocol, url, title);
if ((handler != NULL) &&
registry->CanSchemeBeOverridden(handler->protocol())) {
tab_contents()->AddInfoBar(registry->IsAlreadyRegistered(handler) ?
static_cast<InfoBarDelegate*>(new SimpleAlertInfoBarDelegate(
tab_contents(), NULL, l10n_util::GetStringFUTF16(
IDS_REGISTER_PROTOCOL_HANDLER_ALREADY_REGISTERED,
handler->title(), UTF8ToUTF16(handler->protocol())), true)) :
new RegisterProtocolHandlerInfoBarDelegate(tab_contents(), registry,
handler));
}
}
void TabContentsWrapper::OnMsgThumbnail(const GURL& url,
const ThumbnailScore& score,
const SkBitmap& bitmap) {
if (profile()->IsOffTheRecord())
return;
// Tell History about this thumbnail
history::TopSites* ts = profile()->GetTopSites();
if (ts)
ts->SetPageThumbnail(url, bitmap, score);
}
void TabContentsWrapper::UpdateStarredStateForCurrentURL() {
BookmarkModel* model = tab_contents()->profile()->GetBookmarkModel();
const bool old_state = is_starred_;
is_starred_ = (model && model->IsBookmarked(tab_contents()->GetURL()));
if (is_starred_ != old_state && delegate())
delegate()->URLStarredChanged(this, is_starred_);
}