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   zoom_level_changed_callbacks_.Notify(change);
    116 }
    117 
    118 void HostZoomMapImpl::SetZoomLevelForHostAndScheme(const std::string& scheme,
    119                                                    const std::string& host,
    120                                                    double level) {
    121   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    122   {
    123     base::AutoLock auto_lock(lock_);
    124     scheme_host_zoom_levels_[scheme][host] = level;
    125   }
    126 
    127   // Notify renderers from this browser context.
    128   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
    129        !i.IsAtEnd(); i.Advance()) {
    130     RenderProcessHost* render_process_host = i.GetCurrentValue();
    131     if (HostZoomMap::GetForBrowserContext(
    132             render_process_host->GetBrowserContext()) == this) {
    133       render_process_host->Send(
    134           new ViewMsg_SetZoomLevelForCurrentURL(scheme, host, level));
    135     }
    136   }
    137 
    138   HostZoomMap::ZoomLevelChange change;
    139   change.mode = HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST;
    140   change.host = host;
    141   change.scheme = scheme;
    142   change.zoom_level = level;
    143 
    144   zoom_level_changed_callbacks_.Notify(change);
    145 }
    146 
    147 double HostZoomMapImpl::GetDefaultZoomLevel() const {
    148   return default_zoom_level_;
    149 }
    150 
    151 void HostZoomMapImpl::SetDefaultZoomLevel(double level) {
    152   default_zoom_level_ = level;
    153 }
    154 
    155 scoped_ptr<HostZoomMap::Subscription>
    156 HostZoomMapImpl::AddZoomLevelChangedCallback(
    157     const ZoomLevelChangedCallback& callback) {
    158   return zoom_level_changed_callbacks_.Add(callback);
    159 }
    160 
    161 double HostZoomMapImpl::GetTemporaryZoomLevel(int render_process_id,
    162                                               int render_view_id) const {
    163   base::AutoLock auto_lock(lock_);
    164   for (size_t i = 0; i < temporary_zoom_levels_.size(); ++i) {
    165     if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
    166         temporary_zoom_levels_[i].render_view_id == render_view_id) {
    167       return temporary_zoom_levels_[i].zoom_level;
    168     }
    169   }
    170   return 0;
    171 }
    172 
    173 void HostZoomMapImpl::SetTemporaryZoomLevel(int render_process_id,
    174                                             int render_view_id,
    175                                             double level) {
    176   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    177 
    178   {
    179     base::AutoLock auto_lock(lock_);
    180     size_t i;
    181     for (i = 0; i < temporary_zoom_levels_.size(); ++i) {
    182       if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
    183           temporary_zoom_levels_[i].render_view_id == render_view_id) {
    184         if (level) {
    185           temporary_zoom_levels_[i].zoom_level = level;
    186         } else {
    187           temporary_zoom_levels_.erase(temporary_zoom_levels_.begin() + i);
    188         }
    189         break;
    190       }
    191     }
    192 
    193     if (level && i == temporary_zoom_levels_.size()) {
    194       TemporaryZoomLevel temp;
    195       temp.render_process_id = render_process_id;
    196       temp.render_view_id = render_view_id;
    197       temp.zoom_level = level;
    198       temporary_zoom_levels_.push_back(temp);
    199     }
    200   }
    201 
    202   HostZoomMap::ZoomLevelChange change;
    203   change.mode = HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM;
    204   change.zoom_level = level;
    205 
    206   zoom_level_changed_callbacks_.Notify(change);
    207 }
    208 
    209 void HostZoomMapImpl::Observe(int type,
    210                               const NotificationSource& source,
    211                               const NotificationDetails& details) {
    212   switch (type) {
    213     case NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: {
    214       base::AutoLock auto_lock(lock_);
    215       int render_view_id = Source<RenderViewHost>(source)->GetRoutingID();
    216       int render_process_id =
    217           Source<RenderViewHost>(source)->GetProcess()->GetID();
    218 
    219       for (size_t i = 0; i < temporary_zoom_levels_.size(); ++i) {
    220         if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
    221             temporary_zoom_levels_[i].render_view_id == render_view_id) {
    222           temporary_zoom_levels_.erase(temporary_zoom_levels_.begin() + i);
    223           break;
    224         }
    225       }
    226       break;
    227     }
    228     default:
    229       NOTREACHED() << "Unexpected preference observed.";
    230   }
    231 }
    232 
    233 HostZoomMapImpl::~HostZoomMapImpl() {
    234 }
    235 
    236 }  // namespace content
    237