blob: cea297bda3ad77b5f84cac658f4848af5f81767a [file] [log] [blame]
// Copyright (c) 2012 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/content_settings/content_setting_image_model.h"
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/plugins/plugin_utils.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_features.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icons_public.h"
using content::WebContents;
// The image models hierarchy:
//
// ContentSettingImageModel - base class
// ContentSettingSimpleImageModel - single content setting
// ContentSettingBlockedImageModel - generic blocked setting
// ContentSettingGeolocationImageModel - geolocation
// ContentSettingRPHImageModel - protocol handlers
// ContentSettingMIDISysExImageModel - midi sysex
// ContentSettingMediaImageModel - media
// ContentSettingSubresourceFilterImageModel - deceptive content
class ContentSettingBlockedImageModel : public ContentSettingSimpleImageModel {
public:
explicit ContentSettingBlockedImageModel(ContentSettingsType content_type);
void UpdateFromWebContents(WebContents* web_contents) override;
private:
DISALLOW_COPY_AND_ASSIGN(ContentSettingBlockedImageModel);
};
class ContentSettingGeolocationImageModel
: public ContentSettingSimpleImageModel {
public:
ContentSettingGeolocationImageModel();
void UpdateFromWebContents(WebContents* web_contents) override;
private:
DISALLOW_COPY_AND_ASSIGN(ContentSettingGeolocationImageModel);
};
// Image model for displaying media icons in the location bar.
class ContentSettingMediaImageModel : public ContentSettingImageModel {
public:
ContentSettingMediaImageModel();
void UpdateFromWebContents(WebContents* web_contents) override;
ContentSettingBubbleModel* CreateBubbleModel(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents,
Profile* profile) override;
bool ShouldRunAnimation(WebContents* web_contents) override;
void SetAnimationHasRun(WebContents* web_contents) override;
private:
DISALLOW_COPY_AND_ASSIGN(ContentSettingMediaImageModel);
};
class ContentSettingRPHImageModel : public ContentSettingSimpleImageModel {
public:
ContentSettingRPHImageModel();
void UpdateFromWebContents(WebContents* web_contents) override;
};
class ContentSettingMIDISysExImageModel
: public ContentSettingSimpleImageModel {
public:
ContentSettingMIDISysExImageModel();
void UpdateFromWebContents(WebContents* web_contents) override;
private:
DISALLOW_COPY_AND_ASSIGN(ContentSettingMIDISysExImageModel);
};
namespace {
struct ContentSettingsImageDetails {
ContentSettingsType type;
gfx::VectorIconId icon_id;
int blocked_tooltip_id;
int blocked_explanatory_text_id;
int accessed_tooltip_id;
};
const ContentSettingsImageDetails kImageDetails[] = {
{CONTENT_SETTINGS_TYPE_COOKIES, gfx::VectorIconId::COOKIE,
IDS_BLOCKED_COOKIES_TITLE, 0, IDS_ACCESSED_COOKIES_TITLE},
{CONTENT_SETTINGS_TYPE_IMAGES, gfx::VectorIconId::IMAGE,
IDS_BLOCKED_IMAGES_TITLE, 0, 0},
{CONTENT_SETTINGS_TYPE_JAVASCRIPT, gfx::VectorIconId::CODE,
IDS_BLOCKED_JAVASCRIPT_TITLE, 0, 0},
{CONTENT_SETTINGS_TYPE_PLUGINS, gfx::VectorIconId::EXTENSION,
IDS_BLOCKED_PLUGINS_MESSAGE, IDS_BLOCKED_PLUGIN_EXPLANATORY_TEXT, 0},
{CONTENT_SETTINGS_TYPE_POPUPS, gfx::VectorIconId::WEB,
IDS_BLOCKED_POPUPS_TOOLTIP, IDS_BLOCKED_POPUPS_EXPLANATORY_TEXT, 0},
{CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, gfx::VectorIconId::MIXED_CONTENT,
IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT, 0, 0},
{CONTENT_SETTINGS_TYPE_PPAPI_BROKER, gfx::VectorIconId::EXTENSION,
IDS_BLOCKED_PPAPI_BROKER_TITLE, 0, IDS_ALLOWED_PPAPI_BROKER_TITLE},
{CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
gfx::VectorIconId::FILE_DOWNLOAD, IDS_BLOCKED_DOWNLOAD_TITLE,
IDS_BLOCKED_DOWNLOADS_EXPLANATION, IDS_ALLOWED_DOWNLOAD_TITLE},
};
const ContentSettingsImageDetails* GetImageDetails(ContentSettingsType type) {
for (const ContentSettingsImageDetails& image_details : kImageDetails) {
if (image_details.type == type)
return &image_details;
}
return nullptr;
}
} // namespace
// Single content setting ------------------------------------------------------
ContentSettingSimpleImageModel::ContentSettingSimpleImageModel(
ContentSettingsType content_type)
: ContentSettingImageModel(),
content_type_(content_type) {
}
ContentSettingBubbleModel* ContentSettingSimpleImageModel::CreateBubbleModel(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents,
Profile* profile) {
return ContentSettingBubbleModel::CreateContentSettingBubbleModel(
delegate,
web_contents,
profile,
content_type());
}
bool ContentSettingSimpleImageModel::ShouldRunAnimation(
WebContents* web_contents) {
if (!web_contents)
return false;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (!content_settings)
return false;
return !content_settings->IsBlockageIndicated(content_type());
}
void ContentSettingSimpleImageModel::SetAnimationHasRun(
WebContents* web_contents) {
if (!web_contents)
return;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (content_settings)
content_settings->SetBlockageHasBeenIndicated(content_type());
}
// static
std::unique_ptr<ContentSettingImageModel>
ContentSettingSimpleImageModel::CreateForContentTypeForTesting(
ContentSettingsType content_settings_type) {
if (content_settings_type == CONTENT_SETTINGS_TYPE_GEOLOCATION)
return base::MakeUnique<ContentSettingGeolocationImageModel>();
if (content_settings_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS)
return base::MakeUnique<ContentSettingRPHImageModel>();
if (content_settings_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX)
return base::MakeUnique<ContentSettingMIDISysExImageModel>();
return base::MakeUnique<ContentSettingBlockedImageModel>(
content_settings_type);
}
// Generic blocked content settings --------------------------------------------
ContentSettingBlockedImageModel::ContentSettingBlockedImageModel(
ContentSettingsType content_type)
: ContentSettingSimpleImageModel(content_type) {
}
void ContentSettingBlockedImageModel::UpdateFromWebContents(
WebContents* web_contents) {
set_visible(false);
if (!web_contents)
return;
const ContentSettingsType type = content_type();
const ContentSettingsImageDetails* image_details = GetImageDetails(type);
DCHECK(image_details) << "No entry for " << type << " in kImageDetails[].";
int tooltip_id = image_details->blocked_tooltip_id;
int explanation_id = image_details->blocked_explanatory_text_id;
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
HostContentSettingsMap* map =
HostContentSettingsMapFactory::GetForProfile(profile);
if (type == CONTENT_SETTINGS_TYPE_PLUGINS) {
GURL url = web_contents->GetURL();
ContentSetting setting =
map->GetContentSetting(url, url, type, std::string());
// For plugins, show the animated explanation in these cases:
// - The plugin is blocked despite the user having content setting ALLOW.
// - The user has disabled Flash using BLOCK and HTML5 By Default feature.
bool show_explanation = setting == CONTENT_SETTING_ALLOW ||
(setting == CONTENT_SETTING_BLOCK &&
PluginUtils::ShouldPreferHtmlOverPlugins(map));
if (!show_explanation)
explanation_id = 0;
}
// If a content type is blocked by default and was accessed, display the
// content blocked page action.
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (!content_settings)
return;
if (!content_settings->IsContentBlocked(type)) {
if (!content_settings->IsContentAllowed(type))
return;
// For cookies, only show the cookie blocked page action if cookies are
// blocked by default.
if (type == CONTENT_SETTINGS_TYPE_COOKIES &&
(map->GetDefaultContentSetting(type, nullptr) != CONTENT_SETTING_BLOCK))
return;
tooltip_id = image_details->accessed_tooltip_id;
explanation_id = 0;
}
set_visible(true);
gfx::VectorIconId badge_id = gfx::VectorIconId::VECTOR_ICON_NONE;
if (type == CONTENT_SETTINGS_TYPE_PPAPI_BROKER)
badge_id = gfx::VectorIconId::WARNING_BADGE;
else if (content_settings->IsContentBlocked(type))
badge_id = gfx::VectorIconId::BLOCKED_BADGE;
set_icon_by_vector_id(image_details->icon_id, badge_id);
set_explanatory_string_id(explanation_id);
DCHECK(tooltip_id);
set_tooltip(l10n_util::GetStringUTF16(tooltip_id));
}
// Geolocation -----------------------------------------------------------------
ContentSettingGeolocationImageModel::ContentSettingGeolocationImageModel()
: ContentSettingSimpleImageModel(CONTENT_SETTINGS_TYPE_GEOLOCATION) {
}
void ContentSettingGeolocationImageModel::UpdateFromWebContents(
WebContents* web_contents) {
set_visible(false);
if (!web_contents)
return;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (!content_settings)
return;
const ContentSettingsUsagesState& usages_state = content_settings->
geolocation_usages_state();
if (usages_state.state_map().empty())
return;
set_visible(true);
// If any embedded site has access the allowed icon takes priority over the
// blocked icon.
unsigned int state_flags = 0;
usages_state.GetDetailedInfo(nullptr, &state_flags);
bool allowed =
!!(state_flags & ContentSettingsUsagesState::TABSTATE_HAS_ANY_ALLOWED);
set_icon_by_vector_id(gfx::VectorIconId::MY_LOCATION,
allowed ? gfx::VectorIconId::VECTOR_ICON_NONE
: gfx::VectorIconId::BLOCKED_BADGE);
set_tooltip(l10n_util::GetStringUTF16(allowed
? IDS_GEOLOCATION_ALLOWED_TOOLTIP
: IDS_GEOLOCATION_BLOCKED_TOOLTIP));
}
// Media -----------------------------------------------------------------------
ContentSettingMediaImageModel::ContentSettingMediaImageModel()
: ContentSettingImageModel() {
}
void ContentSettingMediaImageModel::UpdateFromWebContents(
WebContents* web_contents) {
set_visible(false);
if (!web_contents)
return;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (!content_settings)
return;
TabSpecificContentSettings::MicrophoneCameraState state =
content_settings->GetMicrophoneCameraState();
// If neither the microphone nor the camera stream was accessed then no icon
// is displayed in the omnibox.
if (state == TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED)
return;
bool is_mic = (state & TabSpecificContentSettings::MICROPHONE_ACCESSED) != 0;
bool is_cam = (state & TabSpecificContentSettings::CAMERA_ACCESSED) != 0;
DCHECK(is_mic || is_cam);
int id = IDS_CAMERA_BLOCKED;
if (state & (TabSpecificContentSettings::MICROPHONE_BLOCKED |
TabSpecificContentSettings::CAMERA_BLOCKED)) {
set_icon_by_vector_id(gfx::VectorIconId::VIDEOCAM,
gfx::VectorIconId::BLOCKED_BADGE);
if (is_mic)
id = is_cam ? IDS_MICROPHONE_CAMERA_BLOCKED : IDS_MICROPHONE_BLOCKED;
} else {
set_icon_by_vector_id(gfx::VectorIconId::VIDEOCAM,
gfx::VectorIconId::VECTOR_ICON_NONE);
id = IDS_CAMERA_ACCESSED;
if (is_mic)
id = is_cam ? IDS_MICROPHONE_CAMERA_ALLOWED : IDS_MICROPHONE_ACCESSED;
}
set_tooltip(l10n_util::GetStringUTF16(id));
set_visible(true);
}
ContentSettingBubbleModel* ContentSettingMediaImageModel::CreateBubbleModel(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents,
Profile* profile) {
return new ContentSettingMediaStreamBubbleModel(delegate,
web_contents,
profile);
}
bool ContentSettingMediaImageModel::ShouldRunAnimation(
WebContents* web_contents) {
if (!web_contents)
return false;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (!content_settings)
return false;
return (!content_settings->IsBlockageIndicated(
CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) &&
!content_settings->IsBlockageIndicated(
CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
}
void ContentSettingMediaImageModel::SetAnimationHasRun(
WebContents* web_contents) {
if (!web_contents)
return;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (content_settings) {
content_settings->SetBlockageHasBeenIndicated(
CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
content_settings->SetBlockageHasBeenIndicated(
CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
}
}
// Subresource Filter ----------------------------------------------------------
ContentSettingSubresourceFilterImageModel::
ContentSettingSubresourceFilterImageModel()
: ContentSettingImageModel() {}
void ContentSettingSubresourceFilterImageModel::UpdateFromWebContents(
WebContents* web_contents) {
set_visible(false);
if (!web_contents)
return;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (!content_settings || !content_settings->IsSubresourceBlocked())
return;
set_icon_by_vector_id(gfx::VectorIconId::SUBRESOURCE_FILTER_ACTIVE,
gfx::VectorIconId::BLOCKED_BADGE);
set_explanatory_string_id(IDS_FILTERED_DECEPTIVE_CONTENT_PROMPT_TITLE);
set_tooltip(
l10n_util::GetStringUTF16(IDS_FILTERED_DECEPTIVE_CONTENT_PROMPT_TITLE));
set_visible(true);
}
ContentSettingBubbleModel*
ContentSettingSubresourceFilterImageModel::CreateBubbleModel(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents,
Profile* profile) {
return new ContentSettingSubresourceFilterBubbleModel(delegate, web_contents,
profile);
}
bool ContentSettingSubresourceFilterImageModel::ShouldRunAnimation(
WebContents* web_contents) {
if (!web_contents)
return false;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
return content_settings &&
!content_settings->IsSubresourceBlockageIndicated();
}
void ContentSettingSubresourceFilterImageModel::SetAnimationHasRun(
WebContents* web_contents) {
if (!web_contents)
return;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (content_settings)
content_settings->SetSubresourceBlockageIndicated();
}
// Protocol handlers -----------------------------------------------------------
ContentSettingRPHImageModel::ContentSettingRPHImageModel()
: ContentSettingSimpleImageModel(CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
set_icon_by_vector_id(gfx::VectorIconId::PROTOCOL_HANDLER,
gfx::VectorIconId::VECTOR_ICON_NONE);
set_tooltip(l10n_util::GetStringUTF16(IDS_REGISTER_PROTOCOL_HANDLER_TOOLTIP));
}
void ContentSettingRPHImageModel::UpdateFromWebContents(
WebContents* web_contents) {
set_visible(false);
if (!web_contents)
return;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (!content_settings)
return;
if (content_settings->pending_protocol_handler().IsEmpty())
return;
set_visible(true);
}
// MIDI SysEx ------------------------------------------------------------------
ContentSettingMIDISysExImageModel::ContentSettingMIDISysExImageModel()
: ContentSettingSimpleImageModel(CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
}
void ContentSettingMIDISysExImageModel::UpdateFromWebContents(
WebContents* web_contents) {
set_visible(false);
if (!web_contents)
return;
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (!content_settings)
return;
const ContentSettingsUsagesState& usages_state =
content_settings->midi_usages_state();
if (usages_state.state_map().empty())
return;
set_visible(true);
// If any embedded site has access the allowed icon takes priority over the
// blocked icon.
unsigned int state_flags = 0;
usages_state.GetDetailedInfo(nullptr, &state_flags);
bool allowed =
!!(state_flags & ContentSettingsUsagesState::TABSTATE_HAS_ANY_ALLOWED);
set_icon_by_vector_id(gfx::VectorIconId::MIDI,
allowed ? gfx::VectorIconId::VECTOR_ICON_NONE
: gfx::VectorIconId::BLOCKED_BADGE);
set_tooltip(l10n_util::GetStringUTF16(allowed
? IDS_MIDI_SYSEX_ALLOWED_TOOLTIP
: IDS_MIDI_SYSEX_BLOCKED_TOOLTIP));
}
// Base class ------------------------------------------------------------------
gfx::Image ContentSettingImageModel::GetIcon(SkColor nearby_text_color) const {
#if defined(OS_MACOSX)
SkColor icon_color = nearby_text_color;
#else
SkColor icon_color = color_utils::DeriveDefaultIconColor(nearby_text_color);
#endif
return gfx::Image(
gfx::CreateVectorIconWithBadge(icon_id_, 16, icon_color, icon_badge_id_));
}
ContentSettingImageModel::ContentSettingImageModel()
: is_visible_(false),
icon_id_(gfx::VectorIconId::VECTOR_ICON_NONE),
icon_badge_id_(gfx::VectorIconId::VECTOR_ICON_NONE),
explanatory_string_id_(0) {}
// static
ScopedVector<ContentSettingImageModel>
ContentSettingImageModel::GenerateContentSettingImageModels() {
ScopedVector<ContentSettingImageModel> result;
// The ordering of the models here influences the order in which icons are
// shown in the omnibox.
result.push_back(
new ContentSettingBlockedImageModel(CONTENT_SETTINGS_TYPE_COOKIES));
result.push_back(
new ContentSettingBlockedImageModel(CONTENT_SETTINGS_TYPE_IMAGES));
result.push_back(
new ContentSettingBlockedImageModel(CONTENT_SETTINGS_TYPE_JAVASCRIPT));
result.push_back(
new ContentSettingBlockedImageModel(CONTENT_SETTINGS_TYPE_PPAPI_BROKER));
result.push_back(
new ContentSettingBlockedImageModel(CONTENT_SETTINGS_TYPE_PLUGINS));
result.push_back(
new ContentSettingBlockedImageModel(CONTENT_SETTINGS_TYPE_POPUPS));
result.push_back(new ContentSettingGeolocationImageModel());
result.push_back(
new ContentSettingBlockedImageModel(CONTENT_SETTINGS_TYPE_MIXEDSCRIPT));
result.push_back(new ContentSettingRPHImageModel());
result.push_back(new ContentSettingMediaImageModel());
result.push_back(new ContentSettingSubresourceFilterImageModel());
result.push_back(
new ContentSettingBlockedImageModel(
CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS));
result.push_back(new ContentSettingMIDISysExImageModel());
return result;
}
#if defined(OS_MACOSX)
bool ContentSettingImageModel::UpdateFromWebContentsAndCheckIfIconChanged(
content::WebContents* web_contents) {
gfx::VectorIconId old_icon = icon_id_;
gfx::VectorIconId old_badge_icon = icon_badge_id_;
UpdateFromWebContents(web_contents);
return old_icon != icon_id_ && old_badge_icon != icon_badge_id_;
}
#endif