Home | History | Annotate | Download | only in content_settings
      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_bubble_model.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/prefs/pref_service.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "chrome/browser/chrome_notification_types.h"
     11 #include "chrome/browser/content_settings/content_settings_utils.h"
     12 #include "chrome/browser/content_settings/cookie_settings.h"
     13 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
     14 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
     15 #include "chrome/browser/favicon/favicon_tab_helper.h"
     16 #include "chrome/browser/infobars/infobar_service.h"
     17 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
     18 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
     21 #include "chrome/browser/ui/browser_navigator.h"
     22 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
     23 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h"
     24 #include "chrome/browser/ui/content_settings/media_setting_changed_infobar_delegate.h"
     25 #include "chrome/common/chrome_switches.h"
     26 #include "chrome/common/content_settings.h"
     27 #include "chrome/common/pref_names.h"
     28 #include "chrome/common/render_messages.h"
     29 #include "content/public/browser/notification_service.h"
     30 #include "content/public/browser/render_process_host.h"
     31 #include "content/public/browser/render_view_host.h"
     32 #include "content/public/browser/user_metrics.h"
     33 #include "content/public/browser/web_contents.h"
     34 #include "content/public/browser/web_contents_delegate.h"
     35 #include "grit/generated_resources.h"
     36 #include "grit/theme_resources.h"
     37 #include "grit/ui_resources.h"
     38 #include "net/base/net_util.h"
     39 #include "ui/base/l10n/l10n_util.h"
     40 #include "ui/base/resource/resource_bundle.h"
     41 
     42 using content::UserMetricsAction;
     43 using content::WebContents;
     44 using content_settings::SettingInfo;
     45 using content_settings::SettingSource;
     46 using content_settings::SETTING_SOURCE_USER;
     47 using content_settings::SETTING_SOURCE_NONE;
     48 
     49 namespace {
     50 
     51 const int kAllowButtonIndex = 0;
     52 
     53 struct ContentSettingsTypeIdEntry {
     54   ContentSettingsType type;
     55   int id;
     56 };
     57 
     58 int GetIdForContentType(const ContentSettingsTypeIdEntry* entries,
     59                         size_t num_entries,
     60                         ContentSettingsType type) {
     61   for (size_t i = 0; i < num_entries; ++i) {
     62     if (entries[i].type == type)
     63       return entries[i].id;
     64   }
     65   return 0;
     66 }
     67 
     68 const content::MediaStreamDevice& GetMediaDeviceById(
     69     const std::string& device_id,
     70     const content::MediaStreamDevices& devices) {
     71   DCHECK(!devices.empty());
     72   for (content::MediaStreamDevices::const_iterator it = devices.begin();
     73        it != devices.end(); ++it) {
     74     if (it->id == device_id)
     75       return *(it);
     76   }
     77 
     78   // A device with the |device_id| was not found. It is likely that the device
     79   // has been unplugged from the OS. Return the first device as the default
     80   // device.
     81   return *devices.begin();
     82 }
     83 
     84 }  // namespace
     85 
     86 ContentSettingTitleAndLinkModel::ContentSettingTitleAndLinkModel(
     87     Delegate* delegate,
     88     WebContents* web_contents,
     89     Profile* profile,
     90     ContentSettingsType content_type)
     91     : ContentSettingBubbleModel(web_contents, profile, content_type),
     92         delegate_(delegate) {
     93   // Notifications do not have a bubble.
     94   DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
     95   SetTitle();
     96   SetManageLink();
     97 }
     98 
     99 void ContentSettingTitleAndLinkModel::SetTitle() {
    100   static const ContentSettingsTypeIdEntry kBlockedTitleIDs[] = {
    101     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_TITLE},
    102     {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_TITLE},
    103     {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_TITLE},
    104     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_MESSAGE},
    105     {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_TITLE},
    106     {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
    107         IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT},
    108     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
    109         IDS_BLOCKED_PPAPI_BROKER_TITLE},
    110     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_TITLE},
    111   };
    112   // Fields as for kBlockedTitleIDs, above.
    113   static const ContentSettingsTypeIdEntry kAccessedTitleIDs[] = {
    114     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ACCESSED_COOKIES_TITLE},
    115     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_TITLE},
    116     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_TITLE},
    117   };
    118   const ContentSettingsTypeIdEntry *title_ids = kBlockedTitleIDs;
    119   size_t num_title_ids = arraysize(kBlockedTitleIDs);
    120   if (web_contents() &&
    121       TabSpecificContentSettings::FromWebContents(
    122           web_contents())->IsContentAllowed(content_type()) &&
    123       !TabSpecificContentSettings::FromWebContents(
    124           web_contents())->IsContentBlocked(content_type())) {
    125     title_ids = kAccessedTitleIDs;
    126     num_title_ids = arraysize(kAccessedTitleIDs);
    127   }
    128   int title_id =
    129       GetIdForContentType(title_ids, num_title_ids, content_type());
    130   if (title_id)
    131     set_title(l10n_util::GetStringUTF8(title_id));
    132 }
    133 
    134 void ContentSettingTitleAndLinkModel::SetManageLink() {
    135   static const ContentSettingsTypeIdEntry kLinkIDs[] = {
    136     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_LINK},
    137     {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_LINK},
    138     {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_LINK},
    139     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LINK},
    140     {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_LINK},
    141     {CONTENT_SETTINGS_TYPE_GEOLOCATION, IDS_GEOLOCATION_BUBBLE_MANAGE_LINK},
    142     {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_LEARN_MORE},
    143     {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, IDS_HANDLERS_BUBBLE_MANAGE_LINK},
    144     {CONTENT_SETTINGS_TYPE_MEDIASTREAM, IDS_MEDIASTREAM_BUBBLE_MANAGE_LINK},
    145     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_PPAPI_BROKER_BUBBLE_MANAGE_LINK},
    146     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOADS_LINK},
    147     {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, IDS_MIDI_SYSEX_BUBBLE_MANAGE_LINK},
    148   };
    149   set_manage_link(l10n_util::GetStringUTF8(
    150       GetIdForContentType(kLinkIDs, arraysize(kLinkIDs), content_type())));
    151 }
    152 
    153 void ContentSettingTitleAndLinkModel::OnManageLinkClicked() {
    154   if (delegate_)
    155     delegate_->ShowContentSettingsPage(content_type());
    156 }
    157 
    158 class ContentSettingTitleLinkAndCustomModel
    159     : public ContentSettingTitleAndLinkModel {
    160  public:
    161   ContentSettingTitleLinkAndCustomModel(Delegate* delegate,
    162                                         WebContents* web_contents,
    163                                         Profile* profile,
    164                                         ContentSettingsType content_type);
    165   virtual ~ContentSettingTitleLinkAndCustomModel() {}
    166 
    167  private:
    168   void SetCustomLink();
    169   virtual void OnCustomLinkClicked() OVERRIDE {}
    170 };
    171 
    172 ContentSettingTitleLinkAndCustomModel::ContentSettingTitleLinkAndCustomModel(
    173     Delegate* delegate,
    174     WebContents* web_contents,
    175     Profile* profile,
    176     ContentSettingsType content_type)
    177     : ContentSettingTitleAndLinkModel(
    178           delegate, web_contents, profile, content_type) {
    179   SetCustomLink();
    180 }
    181 
    182 void ContentSettingTitleLinkAndCustomModel::SetCustomLink() {
    183   static const ContentSettingsTypeIdEntry kCustomIDs[] = {
    184     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_INFO},
    185     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LOAD_ALL},
    186     {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_ALLOW_INSECURE_CONTENT_BUTTON},
    187   };
    188   int custom_link_id =
    189       GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type());
    190   if (custom_link_id)
    191     set_custom_link(l10n_util::GetStringUTF8(custom_link_id));
    192 }
    193 
    194 class ContentSettingSingleRadioGroup
    195     : public ContentSettingTitleLinkAndCustomModel {
    196  public:
    197   ContentSettingSingleRadioGroup(Delegate* delegate,
    198                                  WebContents* web_contents,
    199                                  Profile* profile,
    200                                  ContentSettingsType content_type);
    201   virtual ~ContentSettingSingleRadioGroup();
    202 
    203  protected:
    204   bool settings_changed() const;
    205   int selected_item() const { return selected_item_; }
    206 
    207  private:
    208   void SetRadioGroup();
    209   void AddException(ContentSetting setting);
    210   virtual void OnRadioClicked(int radio_index) OVERRIDE;
    211 
    212   ContentSetting block_setting_;
    213   int selected_item_;
    214 };
    215 
    216 ContentSettingSingleRadioGroup::ContentSettingSingleRadioGroup(
    217     Delegate* delegate,
    218     WebContents* web_contents,
    219     Profile* profile,
    220     ContentSettingsType content_type)
    221     : ContentSettingTitleLinkAndCustomModel(delegate, web_contents, profile,
    222                                             content_type),
    223       block_setting_(CONTENT_SETTING_BLOCK),
    224       selected_item_(0) {
    225   SetRadioGroup();
    226 }
    227 
    228 ContentSettingSingleRadioGroup::~ContentSettingSingleRadioGroup() {
    229   if (settings_changed()) {
    230     ContentSetting setting =
    231         selected_item_ == kAllowButtonIndex ?
    232                           CONTENT_SETTING_ALLOW :
    233                           block_setting_;
    234     AddException(setting);
    235   }
    236 }
    237 
    238 bool ContentSettingSingleRadioGroup::settings_changed() const {
    239   return selected_item_ != bubble_content().radio_group.default_item;
    240 }
    241 
    242 // Initialize the radio group by setting the appropriate labels for the
    243 // content type and setting the default value based on the content setting.
    244 void ContentSettingSingleRadioGroup::SetRadioGroup() {
    245   GURL url = web_contents()->GetURL();
    246   base::string16 display_host;
    247   net::AppendFormattedHost(
    248       url,
    249       profile()->GetPrefs()->GetString(prefs::kAcceptLanguages),
    250       &display_host);
    251 
    252   if (display_host.empty())
    253     display_host = ASCIIToUTF16(url.spec());
    254 
    255   TabSpecificContentSettings* content_settings =
    256       TabSpecificContentSettings::FromWebContents(web_contents());
    257   bool allowed =
    258       !content_settings->IsContentBlocked(content_type());
    259   DCHECK(!allowed ||
    260          content_settings->IsContentAllowed(content_type()));
    261 
    262   RadioGroup radio_group;
    263   radio_group.url = url;
    264 
    265   static const ContentSettingsTypeIdEntry kBlockedAllowIDs[] = {
    266     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK},
    267     {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_UNBLOCK},
    268     {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_UNBLOCK},
    269     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_UNBLOCK_ALL},
    270     {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_UNBLOCK},
    271     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_UNBLOCK},
    272     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_UNBLOCK},
    273   };
    274   // Fields as for kBlockedAllowIDs, above.
    275   static const ContentSettingsTypeIdEntry kAllowedAllowIDs[] = {
    276     // TODO(bauerb): The string shouldn't be "unblock" (they weren't blocked).
    277     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK},
    278     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_NO_ACTION},
    279     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_NO_ACTION},
    280   };
    281 
    282   std::string radio_allow_label;
    283   if (allowed) {
    284     int resource_id = GetIdForContentType(kAllowedAllowIDs,
    285                                           arraysize(kAllowedAllowIDs),
    286                                           content_type());
    287     radio_allow_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ?
    288         l10n_util::GetStringFUTF8(resource_id, display_host) :
    289         l10n_util::GetStringUTF8(resource_id);
    290   } else {
    291     radio_allow_label = l10n_util::GetStringFUTF8(
    292         GetIdForContentType(kBlockedAllowIDs, arraysize(kBlockedAllowIDs),
    293                             content_type()),
    294         display_host);
    295   }
    296 
    297   static const ContentSettingsTypeIdEntry kBlockedBlockIDs[] = {
    298     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION},
    299     {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_NO_ACTION},
    300     {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_NO_ACTION},
    301     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_NO_ACTION},
    302     {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_NO_ACTION},
    303     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_NO_ACTION},
    304     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_NO_ACTION},
    305   };
    306   static const ContentSettingsTypeIdEntry kAllowedBlockIDs[] = {
    307     // TODO(bauerb): The string should say "block".
    308     {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION},
    309     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_BLOCK},
    310     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_BLOCK},
    311   };
    312 
    313   std::string radio_block_label;
    314   if (allowed) {
    315     int resource_id = GetIdForContentType(kAllowedBlockIDs,
    316                                           arraysize(kAllowedBlockIDs),
    317                                           content_type());
    318     radio_block_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ?
    319         l10n_util::GetStringUTF8(resource_id) :
    320         l10n_util::GetStringFUTF8(resource_id, display_host);
    321   } else {
    322     radio_block_label = l10n_util::GetStringUTF8(
    323         GetIdForContentType(kBlockedBlockIDs, arraysize(kBlockedBlockIDs),
    324                             content_type()));
    325   }
    326 
    327   radio_group.radio_items.push_back(radio_allow_label);
    328   radio_group.radio_items.push_back(radio_block_label);
    329   ContentSetting setting;
    330   SettingSource setting_source = SETTING_SOURCE_NONE;
    331   bool setting_is_wildcard = false;
    332 
    333   if (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) {
    334     CookieSettings* cookie_settings =
    335         CookieSettings::Factory::GetForProfile(profile()).get();
    336     setting = cookie_settings->GetCookieSetting(
    337         url, url, true, &setting_source);
    338   } else {
    339     SettingInfo info;
    340     HostContentSettingsMap* map = profile()->GetHostContentSettingsMap();
    341     scoped_ptr<Value> value(map->GetWebsiteSetting(
    342         url, url, content_type(), std::string(), &info));
    343     setting = content_settings::ValueToContentSetting(value.get());
    344     setting_source = info.source;
    345     setting_is_wildcard =
    346         info.primary_pattern == ContentSettingsPattern::Wildcard() &&
    347         info.secondary_pattern == ContentSettingsPattern::Wildcard();
    348   }
    349 
    350   if (content_type() == CONTENT_SETTINGS_TYPE_PLUGINS &&
    351       setting == CONTENT_SETTING_ALLOW &&
    352       setting_is_wildcard) {
    353     // In the corner case of unrecognized plugins (which are now blocked by
    354     // default) we indicate the blocked state in the UI and allow the user to
    355     // whitelist.
    356     radio_group.default_item = 1;
    357   } else if (setting == CONTENT_SETTING_ALLOW) {
    358     radio_group.default_item = kAllowButtonIndex;
    359     // |block_setting_| is already set to |CONTENT_SETTING_BLOCK|.
    360   } else {
    361     radio_group.default_item = 1;
    362     block_setting_ = setting;
    363   }
    364   if (setting_source != SETTING_SOURCE_USER) {
    365     set_radio_group_enabled(false);
    366   } else {
    367     set_radio_group_enabled(true);
    368   }
    369   selected_item_ = radio_group.default_item;
    370   set_radio_group(radio_group);
    371 }
    372 
    373 void ContentSettingSingleRadioGroup::AddException(ContentSetting setting) {
    374   if (profile()) {
    375     profile()->GetHostContentSettingsMap()->AddExceptionForURL(
    376         bubble_content().radio_group.url,
    377         bubble_content().radio_group.url,
    378         content_type(),
    379         setting);
    380   }
    381 }
    382 
    383 void ContentSettingSingleRadioGroup::OnRadioClicked(int radio_index) {
    384   selected_item_ = radio_index;
    385 }
    386 
    387 class ContentSettingCookiesBubbleModel : public ContentSettingSingleRadioGroup {
    388  public:
    389   ContentSettingCookiesBubbleModel(Delegate* delegate,
    390                                    WebContents* web_contents,
    391                                    Profile* profile,
    392                                    ContentSettingsType content_type);
    393 
    394   virtual ~ContentSettingCookiesBubbleModel();
    395 
    396  private:
    397   virtual void OnCustomLinkClicked() OVERRIDE;
    398 };
    399 
    400 ContentSettingCookiesBubbleModel::ContentSettingCookiesBubbleModel(
    401     Delegate* delegate,
    402     WebContents* web_contents,
    403     Profile* profile,
    404     ContentSettingsType content_type)
    405     : ContentSettingSingleRadioGroup(
    406           delegate, web_contents, profile, content_type) {
    407   DCHECK_EQ(CONTENT_SETTINGS_TYPE_COOKIES, content_type);
    408   set_custom_link_enabled(true);
    409 }
    410 
    411 ContentSettingCookiesBubbleModel::~ContentSettingCookiesBubbleModel() {
    412   // On some plattforms e.g. MacOS X it is possible to close a tab while the
    413   // cookies settings bubble is open. This resets the web contents to NULL.
    414   if (settings_changed() && web_contents()) {
    415     CollectedCookiesInfoBarDelegate::Create(
    416         InfoBarService::FromWebContents(web_contents()));
    417   }
    418 }
    419 
    420 void ContentSettingCookiesBubbleModel::OnCustomLinkClicked() {
    421   if (!web_contents())
    422     return;
    423   content::NotificationService::current()->Notify(
    424       chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN,
    425       content::Source<TabSpecificContentSettings>(
    426           TabSpecificContentSettings::FromWebContents(web_contents())),
    427       content::NotificationService::NoDetails());
    428   delegate()->ShowCollectedCookiesDialog(web_contents());
    429 }
    430 
    431 class ContentSettingPluginBubbleModel : public ContentSettingSingleRadioGroup {
    432  public:
    433   ContentSettingPluginBubbleModel(Delegate* delegate,
    434                                   WebContents* web_contents,
    435                                   Profile* profile,
    436                                   ContentSettingsType content_type);
    437 
    438   virtual ~ContentSettingPluginBubbleModel();
    439 
    440  private:
    441   virtual void OnCustomLinkClicked() OVERRIDE;
    442 };
    443 
    444 ContentSettingPluginBubbleModel::ContentSettingPluginBubbleModel(
    445     Delegate* delegate,
    446     WebContents* web_contents,
    447     Profile* profile,
    448     ContentSettingsType content_type)
    449     : ContentSettingSingleRadioGroup(
    450           delegate, web_contents, profile, content_type) {
    451   DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_PLUGINS);
    452   set_custom_link_enabled(web_contents &&
    453                           TabSpecificContentSettings::FromWebContents(
    454                               web_contents)->load_plugins_link_enabled());
    455 }
    456 
    457 ContentSettingPluginBubbleModel::~ContentSettingPluginBubbleModel() {
    458   if (settings_changed()) {
    459     // If the user elected to allow all plugins then run plugins at this time.
    460     if (selected_item() == kAllowButtonIndex)
    461       OnCustomLinkClicked();
    462   }
    463 }
    464 
    465 void ContentSettingPluginBubbleModel::OnCustomLinkClicked() {
    466   content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble"));
    467   DCHECK(web_contents());
    468   content::RenderViewHost* host = web_contents()->GetRenderViewHost();
    469 #if defined(ENABLE_PLUGINS)
    470   ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
    471       host->GetProcess()->GetID());
    472 #endif
    473   // TODO(bauerb): We should send the identifiers of blocked plug-ins here.
    474   host->Send(new ChromeViewMsg_LoadBlockedPlugins(host->GetRoutingID(),
    475                                                   std::string()));
    476   set_custom_link_enabled(false);
    477   TabSpecificContentSettings::FromWebContents(web_contents())->
    478       set_load_plugins_link_enabled(false);
    479 }
    480 
    481 class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup {
    482  public:
    483   ContentSettingPopupBubbleModel(Delegate* delegate,
    484                                  WebContents* web_contents,
    485                                  Profile* profile,
    486                                  ContentSettingsType content_type);
    487   virtual ~ContentSettingPopupBubbleModel() {}
    488 
    489  private:
    490   void SetPopups();
    491   virtual void OnPopupClicked(int index) OVERRIDE;
    492 };
    493 
    494 ContentSettingPopupBubbleModel::ContentSettingPopupBubbleModel(
    495     Delegate* delegate,
    496     WebContents* web_contents,
    497     Profile* profile,
    498     ContentSettingsType content_type)
    499     : ContentSettingSingleRadioGroup(
    500         delegate, web_contents, profile, content_type) {
    501   SetPopups();
    502 }
    503 
    504 
    505 void ContentSettingPopupBubbleModel::SetPopups() {
    506   std::map<int32, GURL> blocked_popups =
    507       PopupBlockerTabHelper::FromWebContents(web_contents())
    508           ->GetBlockedPopupRequests();
    509   for (std::map<int32, GURL>::const_iterator iter = blocked_popups.begin();
    510        iter != blocked_popups.end();
    511        ++iter) {
    512     std::string title(iter->second.spec());
    513     // The popup may not have a valid URL.
    514     if (title.empty())
    515       title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
    516     PopupItem popup_item(
    517         ui::ResourceBundle::GetSharedInstance().GetImageNamed(
    518             IDR_DEFAULT_FAVICON),
    519         title,
    520         iter->first);
    521     add_popup(popup_item);
    522   }
    523 }
    524 
    525 void ContentSettingPopupBubbleModel::OnPopupClicked(int index) {
    526   if (web_contents()) {
    527     PopupBlockerTabHelper::FromWebContents(web_contents())->
    528         ShowBlockedPopup(bubble_content().popup_items[index].popup_id);
    529   }
    530 }
    531 
    532 // The model of the content settings bubble for media settings.
    533 class ContentSettingMediaStreamBubbleModel
    534     : public ContentSettingTitleAndLinkModel {
    535  public:
    536   ContentSettingMediaStreamBubbleModel(Delegate* delegate,
    537                                        WebContents* web_contents,
    538                                        Profile* profile);
    539 
    540   virtual ~ContentSettingMediaStreamBubbleModel();
    541 
    542  private:
    543   void SetTitle();
    544   // Sets the data for the radio buttons of the bubble.
    545   void SetRadioGroup();
    546   // Sets the data for the media menus of the bubble.
    547   void SetMediaMenus();
    548   // Updates the camera and microphone setting with the passed |setting|.
    549   void UpdateSettings(ContentSetting setting);
    550   // Updates the camera and microphone default device with the passed |type|
    551   // and device.
    552   void UpdateDefaultDeviceForType(content::MediaStreamType type,
    553                                   const std::string& device);
    554 
    555   // ContentSettingBubbleModel implementation.
    556   virtual void OnRadioClicked(int radio_index) OVERRIDE;
    557   virtual void OnMediaMenuClicked(content::MediaStreamType type,
    558                                   const std::string& selected_device) OVERRIDE;
    559 
    560   // The index of the selected radio item.
    561   int selected_item_;
    562   // The content settings that are associated with the individual radio
    563   // buttons.
    564   ContentSetting radio_item_setting_[2];
    565   // The state of the microphone and camera access.
    566   TabSpecificContentSettings::MicrophoneCameraState state_;
    567 };
    568 
    569 ContentSettingMediaStreamBubbleModel::ContentSettingMediaStreamBubbleModel(
    570     Delegate* delegate,
    571     WebContents* web_contents,
    572     Profile* profile)
    573     : ContentSettingTitleAndLinkModel(
    574           delegate, web_contents, profile, CONTENT_SETTINGS_TYPE_MEDIASTREAM),
    575       selected_item_(0),
    576       state_(TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED) {
    577   DCHECK(profile);
    578   // Initialize the content settings associated with the individual radio
    579   // buttons.
    580   radio_item_setting_[0] = CONTENT_SETTING_ASK;
    581   radio_item_setting_[1] = CONTENT_SETTING_BLOCK;
    582 
    583   TabSpecificContentSettings* content_settings =
    584       TabSpecificContentSettings::FromWebContents(web_contents);
    585   state_ = content_settings->GetMicrophoneCameraState();
    586 
    587   SetTitle();
    588   SetRadioGroup();
    589   SetMediaMenus();
    590 }
    591 
    592 ContentSettingMediaStreamBubbleModel::~ContentSettingMediaStreamBubbleModel() {
    593   // On some platforms (e.g. MacOS X) it is possible to close a tab while the
    594   // media stream bubble is open. This resets the web contents to NULL.
    595   if (!web_contents())
    596     return;
    597 
    598   bool media_setting_changed = false;
    599   for (MediaMenuMap::const_iterator it = bubble_content().media_menus.begin();
    600       it != bubble_content().media_menus.end(); ++it) {
    601     if (it->second.selected_device.id != it->second.default_device.id) {
    602       UpdateDefaultDeviceForType(it->first, it->second.selected_device.id);
    603       media_setting_changed = true;
    604     }
    605   }
    606 
    607   // Update the media settings if the radio button selection was changed.
    608   if (selected_item_ != bubble_content().radio_group.default_item) {
    609     UpdateSettings(radio_item_setting_[selected_item_]);
    610     media_setting_changed = true;
    611   }
    612 
    613   // Trigger the reload infobar if the media setting has been changed.
    614   if (media_setting_changed) {
    615     MediaSettingChangedInfoBarDelegate::Create(
    616         InfoBarService::FromWebContents(web_contents()));
    617   }
    618 }
    619 
    620 void ContentSettingMediaStreamBubbleModel::SetTitle() {
    621   int title_id = 0;
    622   switch (state_) {
    623     case TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED:
    624       // If neither microphone nor camera stream was accessed, then there is no
    625       // icon didplayed in the omnibox and no settings bubble availbale. Hence
    626       // there is no title.
    627       NOTREACHED();
    628       return;
    629     case TabSpecificContentSettings::MICROPHONE_ACCESSED:
    630       title_id = IDS_MICROPHONE_ACCESSED;
    631       break;
    632     case TabSpecificContentSettings::CAMERA_ACCESSED:
    633       title_id = IDS_CAMERA_ACCESSED;
    634       break;
    635     case TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED:
    636       title_id = IDS_MICROPHONE_CAMERA_ALLOWED;
    637       break;
    638     case TabSpecificContentSettings::MICROPHONE_BLOCKED:
    639       title_id = IDS_MICROPHONE_BLOCKED;
    640       break;
    641     case TabSpecificContentSettings::CAMERA_BLOCKED:
    642       title_id = IDS_CAMERA_BLOCKED;
    643       break;
    644     case TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED:
    645       title_id = IDS_MICROPHONE_CAMERA_BLOCKED;
    646       break;
    647   }
    648   set_title(l10n_util::GetStringUTF8(title_id));
    649 }
    650 
    651 void ContentSettingMediaStreamBubbleModel::SetRadioGroup() {
    652   TabSpecificContentSettings* content_settings =
    653       TabSpecificContentSettings::FromWebContents(web_contents());
    654   GURL url = content_settings->media_stream_access_origin();
    655   RadioGroup radio_group;
    656   radio_group.url = url;
    657 
    658   base::string16 display_host_utf16;
    659   net::AppendFormattedHost(
    660       url,
    661       profile()->GetPrefs()->GetString(prefs::kAcceptLanguages),
    662       &display_host_utf16);
    663   std::string display_host(UTF16ToUTF8(display_host_utf16));
    664   if (display_host.empty())
    665     display_host = url.spec();
    666 
    667   int radio_allow_label_id = 0;
    668   int radio_block_label_id = 0;
    669   switch (state_) {
    670     case TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED:
    671       NOTREACHED();
    672       return;
    673     case TabSpecificContentSettings::MICROPHONE_ACCESSED:
    674       radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_NO_ACTION;
    675       radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_BLOCK;
    676       selected_item_ = 0;
    677       break;
    678     case TabSpecificContentSettings::CAMERA_ACCESSED:
    679       radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_NO_ACTION;
    680       radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_BLOCK;
    681       selected_item_ = 0;
    682       break;
    683     case TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED:
    684       radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION;
    685       radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_BLOCK;
    686       selected_item_ = 0;
    687       break;
    688     case TabSpecificContentSettings::MICROPHONE_BLOCKED:
    689       if (url.SchemeIsSecure()) {
    690         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_ALLOW;
    691         radio_item_setting_[0] = CONTENT_SETTING_ALLOW;
    692       } else {
    693         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_ASK;
    694       }
    695 
    696       radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_NO_ACTION;
    697       selected_item_ = 1;
    698       break;
    699     case TabSpecificContentSettings::CAMERA_BLOCKED:
    700       if (url.SchemeIsSecure()) {
    701         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ALLOW;
    702         radio_item_setting_[0] = CONTENT_SETTING_ALLOW;
    703       } else {
    704         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ASK;
    705       }
    706 
    707       radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_NO_ACTION;
    708       selected_item_ = 1;
    709       break;
    710     case TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED:
    711       if (url.SchemeIsSecure()) {
    712         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ALLOW;
    713         radio_item_setting_[0] = CONTENT_SETTING_ALLOW;
    714       } else {
    715         radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ASK;
    716       }
    717 
    718       radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION;
    719       selected_item_ = 1;
    720       break;
    721   }
    722 
    723   std::string radio_allow_label = l10n_util::GetStringFUTF8(
    724       radio_allow_label_id, UTF8ToUTF16(display_host));
    725   std::string radio_block_label =
    726       l10n_util::GetStringUTF8(radio_block_label_id);
    727 
    728   radio_group.default_item = selected_item_;
    729   radio_group.radio_items.push_back(radio_allow_label);
    730   radio_group.radio_items.push_back(radio_block_label);
    731 
    732   set_radio_group(radio_group);
    733   set_radio_group_enabled(true);
    734 }
    735 
    736 void ContentSettingMediaStreamBubbleModel::UpdateSettings(
    737     ContentSetting setting) {
    738   if (profile()) {
    739     HostContentSettingsMap* content_settings =
    740         profile()->GetHostContentSettingsMap();
    741     TabSpecificContentSettings* tab_content_settings =
    742         TabSpecificContentSettings::FromWebContents(web_contents());
    743     // The same patterns must be used as in other places (e.g. the infobar) in
    744     // order to override the existing rule. Otherwise a new rule is created.
    745     // TODO(markusheintz): Extract to a helper so that there is only a single
    746     // place to touch.
    747     ContentSettingsPattern primary_pattern =
    748         ContentSettingsPattern::FromURLNoWildcard(
    749             tab_content_settings->media_stream_access_origin());
    750     ContentSettingsPattern secondary_pattern =
    751         ContentSettingsPattern::Wildcard();
    752     if (state_ == TabSpecificContentSettings::MICROPHONE_ACCESSED ||
    753         state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED ||
    754         state_ == TabSpecificContentSettings::MICROPHONE_BLOCKED ||
    755         state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED) {
    756       content_settings->SetContentSetting(
    757           primary_pattern, secondary_pattern,
    758           CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting);
    759     }
    760     if (state_ == TabSpecificContentSettings::CAMERA_ACCESSED ||
    761         state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED ||
    762         state_ == TabSpecificContentSettings::CAMERA_BLOCKED ||
    763         state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED) {
    764       content_settings->SetContentSetting(
    765           primary_pattern, secondary_pattern,
    766           CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting);
    767     }
    768   }
    769 }
    770 
    771 void ContentSettingMediaStreamBubbleModel::UpdateDefaultDeviceForType(
    772     content::MediaStreamType type,
    773     const std::string& device) {
    774   PrefService* prefs = profile()->GetPrefs();
    775   if (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
    776     prefs->SetString(prefs::kDefaultAudioCaptureDevice, device);
    777   } else {
    778     DCHECK_EQ(content::MEDIA_DEVICE_VIDEO_CAPTURE, type);
    779     prefs->SetString(prefs::kDefaultVideoCaptureDevice, device);
    780   }
    781 }
    782 
    783 void ContentSettingMediaStreamBubbleModel::SetMediaMenus() {
    784   TabSpecificContentSettings* content_settings =
    785       TabSpecificContentSettings::FromWebContents(web_contents());
    786   const std::string& requested_microphone =
    787        content_settings->media_stream_requested_audio_device();
    788    const std::string& requested_camera =
    789        content_settings->media_stream_requested_video_device();
    790 
    791   // Add microphone menu.
    792   PrefService* prefs = profile()->GetPrefs();
    793   MediaCaptureDevicesDispatcher* dispatcher =
    794       MediaCaptureDevicesDispatcher::GetInstance();
    795   const content::MediaStreamDevices& microphones =
    796       dispatcher->GetAudioCaptureDevices();
    797 
    798   bool show_mic_menu =
    799       (state_ == TabSpecificContentSettings::MICROPHONE_ACCESSED ||
    800        state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED ||
    801        state_ == TabSpecificContentSettings::MICROPHONE_BLOCKED ||
    802        state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED);
    803   bool show_camera_menu =
    804       (state_ == TabSpecificContentSettings::CAMERA_ACCESSED ||
    805        state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED ||
    806        state_ == TabSpecificContentSettings::CAMERA_BLOCKED ||
    807        state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED);
    808   DCHECK(show_mic_menu || show_camera_menu);
    809 
    810   if (show_mic_menu) {
    811     MediaMenu mic_menu;
    812     mic_menu.label = l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_MIC_LABEL);
    813     if (!microphones.empty()) {
    814       std::string preferred_mic;
    815       if (requested_microphone.empty()) {
    816         preferred_mic = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
    817         mic_menu.disabled = false;
    818       } else {
    819         // Set the |disabled| to true in order to disable the device selection
    820         // menu on the media settings bubble. This must be done if the website
    821         // manages the microphone devices itself.
    822         preferred_mic = requested_microphone;
    823         mic_menu.disabled = true;
    824       }
    825 
    826       mic_menu.default_device = GetMediaDeviceById(preferred_mic, microphones);
    827       mic_menu.selected_device = mic_menu.default_device;
    828     }
    829     add_media_menu(content::MEDIA_DEVICE_AUDIO_CAPTURE, mic_menu);
    830   }
    831 
    832   if (show_camera_menu) {
    833     const content::MediaStreamDevices& cameras =
    834         dispatcher->GetVideoCaptureDevices();
    835     MediaMenu camera_menu;
    836     camera_menu.label =
    837         l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_CAMERA_LABEL);
    838     if (!cameras.empty()) {
    839       std::string preferred_camera;
    840       if (requested_camera.empty()) {
    841         preferred_camera = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
    842         camera_menu.disabled = false;
    843       } else {
    844         // Disable the menu since the website is managing the camera devices
    845         // itself.
    846         preferred_camera = requested_camera;
    847         camera_menu.disabled = true;
    848       }
    849 
    850       camera_menu.default_device =
    851           GetMediaDeviceById(preferred_camera, cameras);
    852       camera_menu.selected_device = camera_menu.default_device;
    853     }
    854     add_media_menu(content::MEDIA_DEVICE_VIDEO_CAPTURE, camera_menu);
    855   }
    856 }
    857 
    858 void ContentSettingMediaStreamBubbleModel::OnRadioClicked(int radio_index) {
    859   selected_item_ = radio_index;
    860 }
    861 
    862 void ContentSettingMediaStreamBubbleModel::OnMediaMenuClicked(
    863     content::MediaStreamType type,
    864     const std::string& selected_device_id) {
    865   DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
    866          type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
    867   DCHECK_EQ(1U, bubble_content().media_menus.count(type));
    868   MediaCaptureDevicesDispatcher* dispatcher =
    869       MediaCaptureDevicesDispatcher::GetInstance();
    870   const content::MediaStreamDevices& devices =
    871       (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) ?
    872           dispatcher->GetAudioCaptureDevices() :
    873           dispatcher->GetVideoCaptureDevices();
    874   set_selected_device(GetMediaDeviceById(selected_device_id, devices));
    875 }
    876 
    877 class ContentSettingDomainListBubbleModel
    878     : public ContentSettingTitleAndLinkModel {
    879  public:
    880   ContentSettingDomainListBubbleModel(Delegate* delegate,
    881                                       WebContents* web_contents,
    882                                       Profile* profile,
    883                                       ContentSettingsType content_type);
    884   virtual ~ContentSettingDomainListBubbleModel() {}
    885 
    886  private:
    887   void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id);
    888   void SetDomainsAndCustomLink();
    889   virtual void OnCustomLinkClicked() OVERRIDE;
    890 };
    891 
    892 ContentSettingDomainListBubbleModel::ContentSettingDomainListBubbleModel(
    893     Delegate* delegate,
    894     WebContents* web_contents,
    895     Profile* profile,
    896     ContentSettingsType content_type)
    897     : ContentSettingTitleAndLinkModel(
    898         delegate, web_contents, profile, content_type) {
    899   DCHECK_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION, content_type) <<
    900       "SetDomains currently only supports geolocation content type";
    901   SetDomainsAndCustomLink();
    902 }
    903 
    904 void ContentSettingDomainListBubbleModel::MaybeAddDomainList(
    905     const std::set<std::string>& hosts, int title_id) {
    906   if (!hosts.empty()) {
    907     DomainList domain_list;
    908     domain_list.title = l10n_util::GetStringUTF8(title_id);
    909     domain_list.hosts = hosts;
    910     add_domain_list(domain_list);
    911   }
    912 }
    913 
    914 void ContentSettingDomainListBubbleModel::SetDomainsAndCustomLink() {
    915   TabSpecificContentSettings* content_settings =
    916       TabSpecificContentSettings::FromWebContents(web_contents());
    917   const ContentSettingsUsagesState& usages =
    918       content_settings->geolocation_usages_state();
    919   ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state;
    920   unsigned int tab_state_flags = 0;
    921   usages.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags);
    922   // Divide the tab's current geolocation users into sets according to their
    923   // permission state.
    924   MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW],
    925                      IDS_GEOLOCATION_BUBBLE_SECTION_ALLOWED);
    926 
    927   MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK],
    928                      IDS_GEOLOCATION_BUBBLE_SECTION_DENIED);
    929 
    930   if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) {
    931     set_custom_link(l10n_util::GetStringUTF8(
    932         IDS_GEOLOCATION_BUBBLE_CLEAR_LINK));
    933     set_custom_link_enabled(true);
    934   } else if (tab_state_flags &
    935              ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) {
    936     set_custom_link(l10n_util::GetStringUTF8(
    937         IDS_GEOLOCATION_BUBBLE_REQUIRE_RELOAD_TO_CLEAR));
    938   }
    939 }
    940 
    941 void ContentSettingDomainListBubbleModel::OnCustomLinkClicked() {
    942   if (!web_contents())
    943     return;
    944   // Reset this embedder's entry to default for each of the requesting
    945   // origins currently on the page.
    946   const GURL& embedder_url = web_contents()->GetURL();
    947   TabSpecificContentSettings* content_settings =
    948       TabSpecificContentSettings::FromWebContents(web_contents());
    949   const ContentSettingsUsagesState::StateMap& state_map =
    950       content_settings->geolocation_usages_state().state_map();
    951   HostContentSettingsMap* settings_map =
    952       profile()->GetHostContentSettingsMap();
    953 
    954   for (ContentSettingsUsagesState::StateMap::const_iterator it =
    955        state_map.begin(); it != state_map.end(); ++it) {
    956     settings_map->SetContentSetting(
    957         ContentSettingsPattern::FromURLNoWildcard(it->first),
    958         ContentSettingsPattern::FromURLNoWildcard(embedder_url),
    959         CONTENT_SETTINGS_TYPE_GEOLOCATION,
    960         std::string(),
    961         CONTENT_SETTING_DEFAULT);
    962   }
    963 }
    964 
    965 class ContentSettingMixedScriptBubbleModel
    966     : public ContentSettingTitleLinkAndCustomModel {
    967  public:
    968   ContentSettingMixedScriptBubbleModel(Delegate* delegate,
    969                                        WebContents* web_contents,
    970                                        Profile* profile,
    971                                        ContentSettingsType content_type);
    972 
    973   virtual ~ContentSettingMixedScriptBubbleModel() {}
    974 
    975  private:
    976   virtual void OnCustomLinkClicked() OVERRIDE;
    977 };
    978 
    979 ContentSettingMixedScriptBubbleModel::ContentSettingMixedScriptBubbleModel(
    980     Delegate* delegate,
    981     WebContents* web_contents,
    982     Profile* profile,
    983     ContentSettingsType content_type)
    984     : ContentSettingTitleLinkAndCustomModel(
    985         delegate, web_contents, profile, content_type) {
    986   DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_MIXEDSCRIPT);
    987   set_custom_link_enabled(true);
    988 }
    989 
    990 void ContentSettingMixedScriptBubbleModel::OnCustomLinkClicked() {
    991   content::RecordAction(UserMetricsAction("MixedScript_LoadAnyway_Bubble"));
    992   DCHECK(web_contents());
    993   content::RenderViewHost* host = web_contents()->GetRenderViewHost();
    994   host->Send(new ChromeViewMsg_SetAllowRunningInsecureContent(
    995       host->GetRoutingID(), true));
    996 }
    997 
    998 ContentSettingRPHBubbleModel::ContentSettingRPHBubbleModel(
    999     Delegate* delegate,
   1000     WebContents* web_contents,
   1001     Profile* profile,
   1002     ProtocolHandlerRegistry* registry,
   1003     ContentSettingsType content_type)
   1004     : ContentSettingTitleAndLinkModel(
   1005           delegate, web_contents, profile, content_type),
   1006       selected_item_(0),
   1007       registry_(registry),
   1008       pending_handler_(ProtocolHandler::EmptyProtocolHandler()),
   1009       previous_handler_(ProtocolHandler::EmptyProtocolHandler()) {
   1010 
   1011   DCHECK_EQ(CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, content_type);
   1012 
   1013   TabSpecificContentSettings* content_settings =
   1014       TabSpecificContentSettings::FromWebContents(web_contents);
   1015   pending_handler_ = content_settings->pending_protocol_handler();
   1016   previous_handler_ = content_settings->previous_protocol_handler();
   1017 
   1018   base::string16 protocol;
   1019   if (pending_handler_.protocol() == "mailto") {
   1020     protocol = l10n_util::GetStringUTF16(
   1021         IDS_REGISTER_PROTOCOL_HANDLER_MAILTO_NAME);
   1022   } else if (pending_handler_.protocol() == "webcal") {
   1023     protocol = l10n_util::GetStringUTF16(
   1024         IDS_REGISTER_PROTOCOL_HANDLER_WEBCAL_NAME);
   1025   } else {
   1026     protocol = UTF8ToUTF16(pending_handler_.protocol());
   1027   }
   1028 
   1029   if (previous_handler_.IsEmpty()) {
   1030     set_title(l10n_util::GetStringFUTF8(
   1031         IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM,
   1032         pending_handler_.title(), UTF8ToUTF16(pending_handler_.url().host()),
   1033         protocol));
   1034   } else {
   1035     set_title(l10n_util::GetStringFUTF8(
   1036         IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE,
   1037         pending_handler_.title(), UTF8ToUTF16(pending_handler_.url().host()),
   1038         protocol, previous_handler_.title()));
   1039   }
   1040 
   1041   std::string radio_allow_label =
   1042       l10n_util::GetStringFUTF8(IDS_REGISTER_PROTOCOL_HANDLER_ACCEPT,
   1043                                 pending_handler_.title());
   1044   std::string radio_deny_label =
   1045       l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_DENY);
   1046   std::string radio_ignore_label =
   1047       l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_IGNORE);
   1048 
   1049   GURL url = web_contents->GetURL();
   1050   RadioGroup radio_group;
   1051   radio_group.url = url;
   1052 
   1053   radio_group.radio_items.push_back(radio_allow_label);
   1054   radio_group.radio_items.push_back(radio_deny_label);
   1055   radio_group.radio_items.push_back(radio_ignore_label);
   1056   ContentSetting setting =
   1057       content_settings->pending_protocol_handler_setting();
   1058   if (setting == CONTENT_SETTING_ALLOW)
   1059     radio_group.default_item = RPH_ALLOW;
   1060   else if (setting == CONTENT_SETTING_BLOCK)
   1061     radio_group.default_item = RPH_BLOCK;
   1062   else
   1063     radio_group.default_item = RPH_IGNORE;
   1064 
   1065   selected_item_ = radio_group.default_item;
   1066   set_radio_group_enabled(true);
   1067   set_radio_group(radio_group);
   1068 }
   1069 
   1070 void ContentSettingRPHBubbleModel::OnRadioClicked(int radio_index) {
   1071   if (selected_item_ == radio_index)
   1072     return;
   1073 
   1074   selected_item_ = radio_index;
   1075 
   1076   if (radio_index == RPH_ALLOW)
   1077     RegisterProtocolHandler();
   1078   else if (radio_index == RPH_BLOCK)
   1079     UnregisterProtocolHandler();
   1080   else if (radio_index == RPH_IGNORE)
   1081     IgnoreProtocolHandler();
   1082   else
   1083     NOTREACHED();
   1084 }
   1085 
   1086 void ContentSettingRPHBubbleModel::OnDoneClicked() {
   1087   // The user has one chance to deal with the RPH content setting UI,
   1088   // then we remove it.
   1089   TabSpecificContentSettings::FromWebContents(web_contents())->
   1090       ClearPendingProtocolHandler();
   1091   content::NotificationService::current()->Notify(
   1092       chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
   1093       content::Source<WebContents>(web_contents()),
   1094       content::NotificationService::NoDetails());
   1095 }
   1096 
   1097 void ContentSettingRPHBubbleModel::RegisterProtocolHandler() {
   1098   // A no-op if the handler hasn't been ignored, but needed in case the user
   1099   // selects sequences like register/ignore/register.
   1100   registry_->RemoveIgnoredHandler(pending_handler_);
   1101 
   1102   registry_->OnAcceptRegisterProtocolHandler(pending_handler_);
   1103   TabSpecificContentSettings::FromWebContents(web_contents())->
   1104       set_pending_protocol_handler_setting(CONTENT_SETTING_ALLOW);
   1105 }
   1106 
   1107 void ContentSettingRPHBubbleModel::UnregisterProtocolHandler() {
   1108   registry_->OnDenyRegisterProtocolHandler(pending_handler_);
   1109   TabSpecificContentSettings::FromWebContents(web_contents())->
   1110       set_pending_protocol_handler_setting(CONTENT_SETTING_BLOCK);
   1111   ClearOrSetPreviousHandler();
   1112 }
   1113 
   1114 void ContentSettingRPHBubbleModel::IgnoreProtocolHandler() {
   1115   registry_->OnIgnoreRegisterProtocolHandler(pending_handler_);
   1116   TabSpecificContentSettings::FromWebContents(web_contents())->
   1117       set_pending_protocol_handler_setting(CONTENT_SETTING_DEFAULT);
   1118   ClearOrSetPreviousHandler();
   1119 }
   1120 
   1121 void ContentSettingRPHBubbleModel::ClearOrSetPreviousHandler() {
   1122   if (previous_handler_.IsEmpty()) {
   1123     registry_->ClearDefault(pending_handler_.protocol());
   1124   } else {
   1125     registry_->OnAcceptRegisterProtocolHandler(previous_handler_);
   1126   }
   1127 }
   1128 
   1129 // TODO(toyoshim): Should share as many code with geolocation as possible.
   1130 class ContentSettingMIDISysExBubbleModel
   1131     : public ContentSettingTitleAndLinkModel {
   1132  public:
   1133   ContentSettingMIDISysExBubbleModel(Delegate* delegate,
   1134                                      WebContents* web_contents,
   1135                                      Profile* profile,
   1136                                      ContentSettingsType content_type);
   1137   virtual ~ContentSettingMIDISysExBubbleModel() {}
   1138 
   1139  private:
   1140   void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id);
   1141   void SetDomainsAndCustomLink();
   1142   virtual void OnCustomLinkClicked() OVERRIDE;
   1143 };
   1144 
   1145 ContentSettingMIDISysExBubbleModel::ContentSettingMIDISysExBubbleModel(
   1146     Delegate* delegate,
   1147     WebContents* web_contents,
   1148     Profile* profile,
   1149     ContentSettingsType content_type)
   1150     : ContentSettingTitleAndLinkModel(
   1151         delegate, web_contents, profile, content_type) {
   1152   DCHECK_EQ(CONTENT_SETTINGS_TYPE_MIDI_SYSEX, content_type);
   1153   SetDomainsAndCustomLink();
   1154 }
   1155 
   1156 void ContentSettingMIDISysExBubbleModel::MaybeAddDomainList(
   1157     const std::set<std::string>& hosts, int title_id) {
   1158   if (!hosts.empty()) {
   1159     DomainList domain_list;
   1160     domain_list.title = l10n_util::GetStringUTF8(title_id);
   1161     domain_list.hosts = hosts;
   1162     add_domain_list(domain_list);
   1163   }
   1164 }
   1165 
   1166 void ContentSettingMIDISysExBubbleModel::SetDomainsAndCustomLink() {
   1167   TabSpecificContentSettings* content_settings =
   1168       TabSpecificContentSettings::FromWebContents(web_contents());
   1169   const ContentSettingsUsagesState& usages_state =
   1170       content_settings->midi_usages_state();
   1171   ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state;
   1172   unsigned int tab_state_flags = 0;
   1173   usages_state.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags);
   1174   // Divide the tab's current MIDI sysex users into sets according to their
   1175   // permission state.
   1176   MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW],
   1177                      IDS_MIDI_SYSEX_BUBBLE_ALLOWED);
   1178 
   1179   MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK],
   1180                      IDS_MIDI_SYSEX_BUBBLE_DENIED);
   1181 
   1182   if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) {
   1183     set_custom_link(l10n_util::GetStringUTF8(
   1184         IDS_MIDI_SYSEX_BUBBLE_CLEAR_LINK));
   1185     set_custom_link_enabled(true);
   1186   } else if (tab_state_flags &
   1187              ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) {
   1188     set_custom_link(l10n_util::GetStringUTF8(
   1189         IDS_MIDI_SYSEX_BUBBLE_REQUIRE_RELOAD_TO_CLEAR));
   1190   }
   1191 }
   1192 
   1193 void ContentSettingMIDISysExBubbleModel::OnCustomLinkClicked() {
   1194   if (!web_contents())
   1195     return;
   1196   // Reset this embedder's entry to default for each of the requesting
   1197   // origins currently on the page.
   1198   TabSpecificContentSettings* content_settings =
   1199       TabSpecificContentSettings::FromWebContents(web_contents());
   1200   const ContentSettingsUsagesState::StateMap& state_map =
   1201       content_settings->midi_usages_state().state_map();
   1202   HostContentSettingsMap* settings_map =
   1203       profile()->GetHostContentSettingsMap();
   1204 
   1205   for (ContentSettingsUsagesState::StateMap::const_iterator it =
   1206        state_map.begin(); it != state_map.end(); ++it) {
   1207     settings_map->SetContentSetting(
   1208         ContentSettingsPattern::FromURLNoWildcard(it->first),
   1209         ContentSettingsPattern::Wildcard(),
   1210         CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
   1211         std::string(),
   1212         CONTENT_SETTING_DEFAULT);
   1213   }
   1214 }
   1215 
   1216 // static
   1217 ContentSettingBubbleModel*
   1218     ContentSettingBubbleModel::CreateContentSettingBubbleModel(
   1219         Delegate* delegate,
   1220         WebContents* web_contents,
   1221         Profile* profile,
   1222         ContentSettingsType content_type) {
   1223   if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
   1224     return new ContentSettingCookiesBubbleModel(delegate, web_contents, profile,
   1225                                                 content_type);
   1226   }
   1227   if (content_type == CONTENT_SETTINGS_TYPE_POPUPS) {
   1228     return new ContentSettingPopupBubbleModel(delegate, web_contents, profile,
   1229                                               content_type);
   1230   }
   1231   if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
   1232     return new ContentSettingDomainListBubbleModel(delegate, web_contents,
   1233                                                    profile, content_type);
   1234   }
   1235   if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) {
   1236     return new ContentSettingMediaStreamBubbleModel(delegate, web_contents,
   1237                                                     profile);
   1238   }
   1239   if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
   1240     return new ContentSettingPluginBubbleModel(delegate, web_contents, profile,
   1241                                                content_type);
   1242   }
   1243   if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) {
   1244     return new ContentSettingMixedScriptBubbleModel(delegate, web_contents,
   1245                                                     profile, content_type);
   1246   }
   1247   if (content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
   1248     ProtocolHandlerRegistry* registry =
   1249         ProtocolHandlerRegistryFactory::GetForProfile(profile);
   1250     return new ContentSettingRPHBubbleModel(delegate, web_contents, profile,
   1251                                             registry, content_type);
   1252   }
   1253   if (content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
   1254     return new ContentSettingMIDISysExBubbleModel(delegate, web_contents,
   1255                                                   profile, content_type);
   1256   }
   1257   return new ContentSettingSingleRadioGroup(delegate, web_contents, profile,
   1258                                             content_type);
   1259 }
   1260 
   1261 ContentSettingBubbleModel::ContentSettingBubbleModel(
   1262     WebContents* web_contents,
   1263     Profile* profile,
   1264     ContentSettingsType content_type)
   1265     : web_contents_(web_contents),
   1266       profile_(profile),
   1267       content_type_(content_type) {
   1268   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
   1269                  content::Source<WebContents>(web_contents));
   1270   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
   1271                  content::Source<Profile>(profile_));
   1272 }
   1273 
   1274 ContentSettingBubbleModel::~ContentSettingBubbleModel() {
   1275 }
   1276 
   1277 ContentSettingBubbleModel::RadioGroup::RadioGroup() : default_item(0) {}
   1278 
   1279 ContentSettingBubbleModel::RadioGroup::~RadioGroup() {}
   1280 
   1281 ContentSettingBubbleModel::DomainList::DomainList() {}
   1282 
   1283 ContentSettingBubbleModel::DomainList::~DomainList() {}
   1284 
   1285 ContentSettingBubbleModel::MediaMenu::MediaMenu() : disabled(false) {}
   1286 
   1287 ContentSettingBubbleModel::MediaMenu::~MediaMenu() {}
   1288 
   1289 ContentSettingBubbleModel::BubbleContent::BubbleContent()
   1290     : radio_group_enabled(false),
   1291       custom_link_enabled(false) {
   1292 }
   1293 
   1294 ContentSettingBubbleModel::BubbleContent::~BubbleContent() {}
   1295 
   1296 void ContentSettingBubbleModel::Observe(
   1297     int type,
   1298     const content::NotificationSource& source,
   1299     const content::NotificationDetails& details) {
   1300   if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
   1301     DCHECK_EQ(web_contents_,
   1302               content::Source<WebContents>(source).ptr());
   1303     web_contents_ = NULL;
   1304   } else {
   1305     DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
   1306     DCHECK_EQ(profile_, content::Source<Profile>(source).ptr());
   1307     profile_ = NULL;
   1308   }
   1309 }
   1310