Home | History | Annotate | Download | only in browser
      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 "content/browser/host_zoom_map_impl.h"
      6 
      7 #include <cmath>
      8 
      9 #include "base/strings/string_piece.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "base/values.h"
     12 #include "content/browser/renderer_host/render_process_host_impl.h"
     13 #include "content/browser/renderer_host/render_view_host_impl.h"
     14 #include "content/common/view_messages.h"
     15 #include "content/public/browser/browser_context.h"
     16 #include "content/public/browser/browser_thread.h"
     17 #include "content/public/browser/notification_service.h"
     18 #include "content/public/browser/notification_types.h"
     19 #include "content/public/browser/resource_context.h"
     20 #include "content/public/common/page_zoom.h"
     21 #include "net/base/net_util.h"
     22 
     23 static const char* kHostZoomMapKeyName = "content_host_zoom_map";
     24 
     25 namespace content {
     26 
     27 HostZoomMap* HostZoomMap::GetForBrowserContext(BrowserContext* context) {
     28   HostZoomMapImpl* rv = static_cast<HostZoomMapImpl*>(
     29       context->GetUserData(kHostZoomMapKeyName));
     30   if (!rv) {
     31     rv = new HostZoomMapImpl();
     32     context->SetUserData(kHostZoomMapKeyName, rv);
     33   }
     34   return rv;
     35 }
     36 
     37 HostZoomMapImpl::HostZoomMapImpl()
     38     : default_zoom_level_(0.0) {
     39   registrar_.Add(
     40       this, NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW,
     41       NotificationService::AllSources());
     42 }
     43 
     44 void HostZoomMapImpl::CopyFrom(HostZoomMap* copy_interface) {
     45   // This can only be called on the UI thread to avoid deadlocks, otherwise
     46   //   UI: a.CopyFrom(b);
     47   //   IO: b.CopyFrom(a);
     48   // can deadlock.
     49   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     50   HostZoomMapImpl* copy = static_cast<HostZoomMapImpl*>(copy_interface);
     51   base::AutoLock auto_lock(lock_);
     52   base::AutoLock copy_auto_lock(copy->lock_);
     53   host_zoom_levels_.
     54       insert(copy->host_zoom_levels_.begin(), copy->host_zoom_levels_.end());
     55   for (SchemeHostZoomLevels::const_iterator i(copy->
     56            scheme_host_zoom_levels_.begin());
     57        i != copy->scheme_host_zoom_levels_.end(); ++i) {
     58     scheme_host_zoom_levels_[i->first] = HostZoomLevels();
     59     scheme_host_zoom_levels_[i->first].
     60         insert(i->second.begin(), i->second.end());
     61   }
     62   default_zoom_level_ = copy->default_zoom_level_;
     63 }
     64 
     65 double HostZoomMapImpl::GetZoomLevelForHost(const std::string& host) const {
     66   base::AutoLock auto_lock(lock_);
     67   HostZoomLevels::const_iterator i(host_zoom_levels_.find(host));
     68   return (i == host_zoom_levels_.end()) ? default_zoom_level_ : i->second;
     69 }
     70 
     71 double HostZoomMapImpl::GetZoomLevelForHostAndScheme(
     72     const std::string& scheme,
     73     const std::string& host) const {
     74   {
     75     base::AutoLock auto_lock(lock_);
     76     SchemeHostZoomLevels::const_iterator scheme_iterator(
     77         scheme_host_zoom_levels_.find(scheme));
     78     if (scheme_iterator != scheme_host_zoom_levels_.end()) {
     79       HostZoomLevels::const_iterator i(scheme_iterator->second.find(host));
     80       if (i != scheme_iterator->second.end())
     81         return i->second;
     82     }
     83   }
     84   return GetZoomLevelForHost(host);
     85 }
     86 
     87 void HostZoomMapImpl::SetZoomLevelForHost(const std::string& host,
     88                                           double level) {
     89   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     90 
     91   {
     92     base::AutoLock auto_lock(lock_);
     93 
     94     if (ZoomValuesEqual(level, default_zoom_level_))
     95       host_zoom_levels_.erase(host);
     96     else
     97       host_zoom_levels_[host] = level;
     98   }
     99 
    100   // Notify renderers from this browser context.
    101   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
    102        !i.IsAtEnd(); i.Advance()) {
    103     RenderProcessHost* render_process_host = i.GetCurrentValue();
    104     if (HostZoomMap::GetForBrowserContext(
    105             render_process_host->GetBrowserContext()) == this) {
    106       render_process_host->Send(
    107           new ViewMsg_SetZoomLevelForCurrentURL(std::string(), host, level));
    108     }
    109   }
    110   HostZoomMap::ZoomLevelChange change;
    111   change.mode = HostZoomMap::ZOOM_CHANGED_FOR_HOST;
    112   change.host = host;
    113   change.zoom_level = level;
    114 
    115   for (size_t i = 0; i < zoom_level_changed_callbacks_.size(); i++)
    116     zoom_level_changed_callbacks_[i].Run(change);
    117 }
    118 
    119 void HostZoomMapImpl::SetZoomLevelForHostAndScheme(const std::string& scheme,
    120                                                    const std::string& host,
    121                                                    double level) {
    122   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    123   {
    124     base::AutoLock auto_lock(lock_);
    125     scheme_host_zoom_levels_[scheme][host] = level;
    126   }
    127 
    128   // Notify renderers from this browser context.
    129   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
    130        !i.IsAtEnd(); i.Advance()) {
    131     RenderProcessHost* render_process_host = i.GetCurrentValue();
    132     if (HostZoomMap::GetForBrowserContext(
    133             render_process_host->GetBrowserContext()) == this) {
    134       render_process_host->Send(
    135           new ViewMsg_SetZoomLevelForCurrentURL(scheme, host, level));
    136     }
    137   }
    138 
    139   HostZoomMap::ZoomLevelChange change;
    140   change.mode = HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST;
    141   change.host = host;
    142   change.scheme = scheme;
    143   change.zoom_level = level;
    144 
    145   for (size_t i = 0; i < zoom_level_changed_callbacks_.size(); i++)
    146     zoom_level_changed_callbacks_[i].Run(change);
    147 }
    148 
    149 double HostZoomMapImpl::GetDefaultZoomLevel() const {
    150   return default_zoom_level_;
    151 }
    152 
    153 void HostZoomMapImpl::SetDefaultZoomLevel(double level) {
    154   default_zoom_level_ = level;
    155 }
    156 
    157 void HostZoomMapImpl::AddZoomLevelChangedCallback(
    158     const ZoomLevelChangedCallback& callback) {
    159   zoom_level_changed_callbacks_.push_back(callback);
    160 }
    161 
    162 void HostZoomMapImpl::RemoveZoomLevelChangedCallback(
    163     const ZoomLevelChangedCallback& callback) {
    164   for (size_t i = 0; i < zoom_level_changed_callbacks_.size(); i++) {
    165     if (zoom_level_changed_callbacks_[i].Equals(callback)) {
    166       zoom_level_changed_callbacks_.erase(
    167           zoom_level_changed_callbacks_.begin() + i);
    168       return;
    169     }
    170   }
    171 }
    172 
    173 double HostZoomMapImpl::GetTemporaryZoomLevel(int render_process_id,
    174                                               int render_view_id) const {
    175   base::AutoLock auto_lock(lock_);
    176   for (size_t i = 0; i < temporary_zoom_levels_.size(); ++i) {
    177     if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
    178         temporary_zoom_levels_[i].render_view_id == render_view_id) {
    179       return temporary_zoom_levels_[i].zoom_level;
    180     }
    181   }
    182   return 0;
    183 }
    184 
    185 void HostZoomMapImpl::SetTemporaryZoomLevel(int render_process_id,
    186                                             int render_view_id,
    187                                             double level) {
    188   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    189 
    190   {
    191     base::AutoLock auto_lock(lock_);
    192     size_t i;
    193     for (i = 0; i < temporary_zoom_levels_.size(); ++i) {
    194       if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
    195           temporary_zoom_levels_[i].render_view_id == render_view_id) {
    196         if (level) {
    197           temporary_zoom_levels_[i].zoom_level = level;
    198         } else {
    199           temporary_zoom_levels_.erase(temporary_zoom_levels_.begin() + i);
    200         }
    201         break;
    202       }
    203     }
    204 
    205     if (level && i == temporary_zoom_levels_.size()) {
    206       TemporaryZoomLevel temp;
    207       temp.render_process_id = render_process_id;
    208       temp.render_view_id = render_view_id;
    209       temp.zoom_level = level;
    210       temporary_zoom_levels_.push_back(temp);
    211     }
    212   }
    213 
    214   HostZoomMap::ZoomLevelChange change;
    215   change.mode = HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM;
    216   change.zoom_level = level;
    217 
    218   for (size_t i = 0; i < zoom_level_changed_callbacks_.size(); i++)
    219     zoom_level_changed_callbacks_[i].Run(change);
    220 }
    221 
    222 void HostZoomMapImpl::Observe(int type,
    223                               const NotificationSource& source,
    224                               const NotificationDetails& details) {
    225   switch (type) {
    226     case NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: {
    227       base::AutoLock auto_lock(lock_);
    228       int render_view_id = Source<RenderViewHost>(source)->GetRoutingID();
    229       int render_process_id =
    230           Source<RenderViewHost>(source)->GetProcess()->GetID();
    231 
    232       for (size_t i = 0; i < temporary_zoom_levels_.size(); ++i) {
    233         if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
    234             temporary_zoom_levels_[i].render_view_id == render_view_id) {
    235           temporary_zoom_levels_.erase(temporary_zoom_levels_.begin() + i);
    236           break;
    237         }
    238       }
    239       break;
    240     }
    241     default:
    242       NOTREACHED() << "Unexpected preference observed.";
    243   }
    244 }
    245 
    246 HostZoomMapImpl::~HostZoomMapImpl() {
    247 }
    248 
    249 }  // namespace content
    250