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/content_settings/content_setting_image_model.h"
6
7#include "chrome/browser/content_settings/host_content_settings_map.h"
8#include "chrome/browser/content_settings/tab_specific_content_settings.h"
9#include "chrome/browser/prerender/prerender_manager.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/grit/generated_resources.h"
12#include "content/public/browser/web_contents.h"
13#include "grit/theme_resources.h"
14#include "ui/base/l10n/l10n_util.h"
15
16using content::WebContents;
17
18class ContentSettingBlockedImageModel : public ContentSettingImageModel {
19 public:
20  explicit ContentSettingBlockedImageModel(
21      ContentSettingsType content_settings_type);
22
23  virtual void UpdateFromWebContents(WebContents* web_contents) OVERRIDE;
24};
25
26class ContentSettingGeolocationImageModel : public ContentSettingImageModel {
27 public:
28  ContentSettingGeolocationImageModel();
29
30  virtual void UpdateFromWebContents(WebContents* web_contents) OVERRIDE;
31};
32
33// Image model for displaying media icons in the location bar.
34class ContentSettingMediaImageModel : public ContentSettingImageModel {
35 public:
36  explicit ContentSettingMediaImageModel(ContentSettingsType type);
37
38  virtual void UpdateFromWebContents(WebContents* web_contents) OVERRIDE;
39};
40
41class ContentSettingRPHImageModel : public ContentSettingImageModel {
42 public:
43  ContentSettingRPHImageModel();
44
45  virtual void UpdateFromWebContents(WebContents* web_contents) OVERRIDE;
46};
47
48class ContentSettingNotificationsImageModel : public ContentSettingImageModel {
49 public:
50  ContentSettingNotificationsImageModel();
51
52  virtual void UpdateFromWebContents(WebContents* web_contents) OVERRIDE;
53};
54
55class ContentSettingMIDISysExImageModel : public ContentSettingImageModel {
56 public:
57  ContentSettingMIDISysExImageModel();
58
59  virtual void UpdateFromWebContents(WebContents* web_contents) OVERRIDE;
60};
61
62namespace {
63
64struct ContentSettingsTypeIdEntry {
65  ContentSettingsType type;
66  int id;
67};
68
69int GetIdForContentType(const ContentSettingsTypeIdEntry* entries,
70                        size_t num_entries,
71                        ContentSettingsType type) {
72  for (size_t i = 0; i < num_entries; ++i) {
73    if (entries[i].type == type)
74      return entries[i].id;
75  }
76  return 0;
77}
78
79}  // namespace
80
81ContentSettingBlockedImageModel::ContentSettingBlockedImageModel(
82    ContentSettingsType content_settings_type)
83    : ContentSettingImageModel(content_settings_type) {
84}
85
86void ContentSettingBlockedImageModel::UpdateFromWebContents(
87    WebContents* web_contents) {
88  set_visible(false);
89  if (!web_contents)
90    return;
91
92  static const ContentSettingsTypeIdEntry kBlockedIconIDs[] = {
93    {CONTENT_SETTINGS_TYPE_COOKIES, IDR_BLOCKED_COOKIES},
94    {CONTENT_SETTINGS_TYPE_IMAGES, IDR_BLOCKED_IMAGES},
95    {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDR_BLOCKED_JAVASCRIPT},
96    {CONTENT_SETTINGS_TYPE_PLUGINS, IDR_BLOCKED_PLUGINS},
97    {CONTENT_SETTINGS_TYPE_POPUPS, IDR_BLOCKED_POPUPS},
98    {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDR_BLOCKED_MIXED_CONTENT},
99    {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDR_BLOCKED_PPAPI_BROKER},
100    {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDR_BLOCKED_DOWNLOADS},
101  };
102  static const ContentSettingsTypeIdEntry kBlockedTooltipIDs[] = {
103    {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_TITLE},
104    {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_TITLE},
105    {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_TITLE},
106    {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_MESSAGE},
107    {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_TOOLTIP},
108    {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
109        IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT},
110    {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_TITLE},
111    {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_TITLE},
112  };
113  static const ContentSettingsTypeIdEntry kBlockedExplanatoryTextIDs[] = {
114    {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_EXPLANATORY_TEXT},
115    {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGIN_EXPLANATORY_TEXT},
116    {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
117        IDS_BLOCKED_DOWNLOADS_EXPLANATION},
118  };
119
120  ContentSettingsType type = get_content_settings_type();
121  int icon_id = GetIdForContentType(
122      kBlockedIconIDs, arraysize(kBlockedIconIDs), type);
123  int tooltip_id = GetIdForContentType(
124      kBlockedTooltipIDs, arraysize(kBlockedTooltipIDs), type);
125  int explanation_id = GetIdForContentType(
126      kBlockedExplanatoryTextIDs, arraysize(kBlockedExplanatoryTextIDs), type);
127
128  // For plugins, don't show the animated explanation unless the plugin was
129  // blocked despite the user's content settings being set to allow it (e.g.
130  // due to auto-blocking NPAPI plugins).
131  Profile* profile =
132      Profile::FromBrowserContext(web_contents->GetBrowserContext());
133  HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
134  if (type == CONTENT_SETTINGS_TYPE_PLUGINS) {
135    GURL url = web_contents->GetURL();
136    if (map->GetContentSetting(url, url, type, std::string()) !=
137        CONTENT_SETTING_ALLOW)
138      explanation_id = 0;
139  }
140
141  // If a content type is blocked by default and was accessed, display the
142  // content blocked page action.
143  TabSpecificContentSettings* content_settings =
144      TabSpecificContentSettings::FromWebContents(web_contents);
145  if (!content_settings)
146    return;
147  if (!content_settings->IsContentBlocked(type)) {
148    if (!content_settings->IsContentAllowed(type))
149      return;
150
151    // For cookies, only show the cookie blocked page action if cookies are
152    // blocked by default.
153    if (type == CONTENT_SETTINGS_TYPE_COOKIES &&
154        (map->GetDefaultContentSetting(type, NULL) != CONTENT_SETTING_BLOCK))
155      return;
156
157    static const ContentSettingsTypeIdEntry kAccessedIconIDs[] = {
158      {CONTENT_SETTINGS_TYPE_COOKIES, IDR_ACCESSED_COOKIES},
159      {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDR_BLOCKED_PPAPI_BROKER},
160      {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDR_ALLOWED_DOWNLOADS},
161    };
162    static const ContentSettingsTypeIdEntry kAccessedTooltipIDs[] = {
163      {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ACCESSED_COOKIES_TITLE},
164      {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_TITLE},
165      {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_TITLE},
166    };
167    icon_id = GetIdForContentType(
168        kAccessedIconIDs, arraysize(kAccessedIconIDs), type);
169    tooltip_id = GetIdForContentType(
170        kAccessedTooltipIDs, arraysize(kAccessedTooltipIDs), type);
171    explanation_id = 0;
172  }
173  set_visible(true);
174  DCHECK(icon_id);
175  set_icon(icon_id);
176  set_explanatory_string_id(explanation_id);
177  DCHECK(tooltip_id);
178  set_tooltip(l10n_util::GetStringUTF8(tooltip_id));
179}
180
181ContentSettingGeolocationImageModel::ContentSettingGeolocationImageModel()
182    : ContentSettingImageModel(CONTENT_SETTINGS_TYPE_GEOLOCATION) {
183}
184
185void ContentSettingGeolocationImageModel::UpdateFromWebContents(
186    WebContents* web_contents) {
187  set_visible(false);
188  if (!web_contents)
189    return;
190  TabSpecificContentSettings* content_settings =
191      TabSpecificContentSettings::FromWebContents(web_contents);
192  if (!content_settings)
193    return;
194  const ContentSettingsUsagesState& usages_state = content_settings->
195      geolocation_usages_state();
196  if (usages_state.state_map().empty())
197    return;
198  set_visible(true);
199
200  // If any embedded site has access the allowed icon takes priority over the
201  // blocked icon.
202  unsigned int state_flags = 0;
203  usages_state.GetDetailedInfo(NULL, &state_flags);
204  bool allowed =
205      !!(state_flags & ContentSettingsUsagesState::TABSTATE_HAS_ANY_ALLOWED);
206  set_icon(allowed ? IDR_ALLOWED_LOCATION : IDR_BLOCKED_LOCATION);
207  set_tooltip(l10n_util::GetStringUTF8(allowed ?
208      IDS_GEOLOCATION_ALLOWED_TOOLTIP : IDS_GEOLOCATION_BLOCKED_TOOLTIP));
209}
210
211ContentSettingMediaImageModel::ContentSettingMediaImageModel(
212    ContentSettingsType type)
213    : ContentSettingImageModel(type) {
214}
215
216void ContentSettingMediaImageModel::UpdateFromWebContents(
217    WebContents* web_contents) {
218  set_visible(false);
219
220  // As long as a single icon is used to display the status of the camera and
221  // microphone usage only display an icon for the
222  // CONTENT_SETTINGS_TYPE_MEDIASTREAM. Don't display anything for
223  // CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
224  // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
225  // FIXME: Remove this hack and either display a two omnibox icons (one for
226  // camera and one for microphone), or don't create one image model per
227  // content type but per icon to display. The later is probably the right
228  // thing to do, bebacuse this also allows to add more content settings type
229  // for which no omnibox icon exists.
230  if (get_content_settings_type() == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
231      get_content_settings_type() == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
232    return;
233  }
234
235  // The ContentSettingMediaImageModel must not be used with a content type
236  // other then: CONTENT_SETTINGS_TYPE_MEDIASTREAM,
237  // CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
238  // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
239  DCHECK_EQ(get_content_settings_type(), CONTENT_SETTINGS_TYPE_MEDIASTREAM);
240
241  if (!web_contents)
242    return;
243
244  TabSpecificContentSettings* content_settings =
245      TabSpecificContentSettings::FromWebContents(web_contents);
246  if (!content_settings)
247    return;
248  TabSpecificContentSettings::MicrophoneCameraState state =
249      content_settings->GetMicrophoneCameraState();
250
251  switch (state) {
252    case TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED:
253      // If neither the microphone nor the camera stream was accessed then no
254      // icon is displayed in the omnibox.
255      return;
256    case TabSpecificContentSettings::MICROPHONE_ACCESSED:
257      set_icon(IDR_ASK_MEDIA);
258      set_tooltip(l10n_util::GetStringUTF8(IDS_MICROPHONE_ACCESSED));
259      break;
260    case TabSpecificContentSettings::CAMERA_ACCESSED:
261      set_icon(IDR_ASK_MEDIA);
262      set_tooltip(l10n_util::GetStringUTF8(IDS_CAMERA_ACCESSED));
263      break;
264    case TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED:
265      set_icon(IDR_ASK_MEDIA);
266      set_tooltip(l10n_util::GetStringUTF8(IDS_MICROPHONE_CAMERA_ALLOWED));
267      break;
268    case TabSpecificContentSettings::MICROPHONE_BLOCKED:
269      set_icon(IDR_BLOCKED_MEDIA);
270      set_tooltip(l10n_util::GetStringUTF8(IDS_MICROPHONE_BLOCKED));
271      break;
272    case TabSpecificContentSettings::CAMERA_BLOCKED:
273      set_icon(IDR_BLOCKED_MEDIA);
274      set_tooltip(l10n_util::GetStringUTF8(IDS_CAMERA_BLOCKED));
275      break;
276    case TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED:
277      set_icon(IDR_BLOCKED_MEDIA);
278      set_tooltip(l10n_util::GetStringUTF8(IDS_MICROPHONE_CAMERA_BLOCKED));
279      break;
280  }
281  set_visible(true);
282}
283
284ContentSettingRPHImageModel::ContentSettingRPHImageModel()
285    : ContentSettingImageModel(
286        CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
287  set_icon(IDR_REGISTER_PROTOCOL_HANDLER);
288  set_tooltip(l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_TOOLTIP));
289}
290
291void ContentSettingRPHImageModel::UpdateFromWebContents(
292    WebContents* web_contents) {
293  set_visible(false);
294  if (!web_contents)
295    return;
296
297  TabSpecificContentSettings* content_settings =
298      TabSpecificContentSettings::FromWebContents(web_contents);
299  if (!content_settings)
300    return;
301  if (content_settings->pending_protocol_handler().IsEmpty())
302    return;
303
304  set_visible(true);
305}
306
307ContentSettingNotificationsImageModel::ContentSettingNotificationsImageModel()
308    : ContentSettingImageModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
309}
310
311void ContentSettingNotificationsImageModel::UpdateFromWebContents(
312    WebContents* web_contents) {
313  // Notifications do not have a bubble.
314  set_visible(false);
315}
316
317ContentSettingMIDISysExImageModel::ContentSettingMIDISysExImageModel()
318    : ContentSettingImageModel(CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
319}
320
321void ContentSettingMIDISysExImageModel::UpdateFromWebContents(
322    WebContents* web_contents) {
323  set_visible(false);
324  if (!web_contents)
325    return;
326  TabSpecificContentSettings* content_settings =
327      TabSpecificContentSettings::FromWebContents(web_contents);
328  if (!content_settings)
329    return;
330  const ContentSettingsUsagesState& usages_state =
331      content_settings->midi_usages_state();
332  if (usages_state.state_map().empty())
333    return;
334  set_visible(true);
335
336  // If any embedded site has access the allowed icon takes priority over the
337  // blocked icon.
338  unsigned int state_flags = 0;
339  usages_state.GetDetailedInfo(NULL, &state_flags);
340  bool allowed =
341      !!(state_flags & ContentSettingsUsagesState::TABSTATE_HAS_ANY_ALLOWED);
342  set_icon(allowed ? IDR_ALLOWED_MIDI_SYSEX : IDR_BLOCKED_MIDI_SYSEX);
343  set_tooltip(l10n_util::GetStringUTF8(allowed ?
344      IDS_MIDI_SYSEX_ALLOWED_TOOLTIP : IDS_MIDI_SYSEX_BLOCKED_TOOLTIP));
345}
346
347ContentSettingImageModel::ContentSettingImageModel(
348    ContentSettingsType content_settings_type)
349    : content_settings_type_(content_settings_type),
350      is_visible_(false),
351      icon_(0),
352      explanatory_string_id_(0) {
353}
354
355// static
356ContentSettingImageModel*
357    ContentSettingImageModel::CreateContentSettingImageModel(
358    ContentSettingsType content_settings_type) {
359  switch (content_settings_type) {
360    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
361      return new ContentSettingGeolocationImageModel();
362    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
363      return new ContentSettingNotificationsImageModel();
364    case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS:
365      return new ContentSettingRPHImageModel();
366    case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
367    case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
368    case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
369      return new ContentSettingMediaImageModel(content_settings_type);
370    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
371      return new ContentSettingMIDISysExImageModel();
372    default:
373      return new ContentSettingBlockedImageModel(content_settings_type);
374  }
375}
376