Home | History | Annotate | Download | only in image
      1 // Copyright 2013 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 "ui/gfx/image/image_family.h"
      6 
      7 #include <cmath>
      8 
      9 #include "ui/gfx/image/image.h"
     10 #include "ui/gfx/image/image_skia.h"
     11 #include "ui/gfx/size.h"
     12 
     13 namespace gfx {
     14 
     15 ImageFamily::const_iterator::const_iterator() {}
     16 
     17 ImageFamily::const_iterator::const_iterator(const const_iterator& other)
     18     : map_iterator_(other.map_iterator_) {}
     19 
     20 ImageFamily::const_iterator::const_iterator(
     21     const std::map<MapKey, gfx::Image>::const_iterator& other)
     22     : map_iterator_(other) {}
     23 
     24 ImageFamily::const_iterator::~const_iterator() {}
     25 
     26 ImageFamily::ImageFamily() {}
     27 ImageFamily::~ImageFamily() {}
     28 
     29 void ImageFamily::Add(const gfx::Image& image) {
     30   gfx::Size size = image.Size();
     31   if (size.IsEmpty()) {
     32     map_[MapKey(1.0f, 0)] = image;
     33   } else {
     34     float aspect = static_cast<float>(size.width()) / size.height();
     35     DCHECK_GT(aspect, 0.0f);
     36     map_[MapKey(aspect, size.width())] = image;
     37   }
     38 }
     39 
     40 void ImageFamily::Add(const gfx::ImageSkia& image_skia) {
     41   Add(gfx::Image(image_skia));
     42 }
     43 
     44 const gfx::Image* ImageFamily::GetBest(int width, int height) const {
     45   if (map_.empty())
     46     return NULL;
     47 
     48   // If either |width| or |height| is 0, both are.
     49   float desired_aspect;
     50   if (height == 0 || width == 0) {
     51     desired_aspect = 1.0f;
     52     height = 0;
     53     width = 0;
     54   } else {
     55     desired_aspect = static_cast<float>(width) / height;
     56   }
     57   DCHECK_GT(desired_aspect, 0.0f);
     58 
     59   float closest_aspect = GetClosestAspect(desired_aspect);
     60 
     61   // If thinner than desired, search for images with width such that the
     62   // corresponding height is greater than or equal to the desired |height|.
     63   int desired_width = closest_aspect <= desired_aspect ?
     64       width : static_cast<int>(ceilf(height * closest_aspect));
     65 
     66   // Get the best-sized image with the aspect ratio.
     67   return GetWithExactAspect(closest_aspect, desired_width);
     68 }
     69 
     70 float ImageFamily::GetClosestAspect(float desired_aspect) const {
     71   // Find the two aspect ratios on either side of |desired_aspect|.
     72   std::map<MapKey, gfx::Image>::const_iterator greater_or_equal =
     73       map_.lower_bound(MapKey(desired_aspect, 0));
     74   // Early exit optimization if there is an exact match.
     75   if (greater_or_equal != map_.end() &&
     76       greater_or_equal->first.aspect() == desired_aspect) {
     77     return desired_aspect;
     78   }
     79 
     80   // No exact match; |greater_or_equal| will point to the first image with
     81   // aspect ratio >= |desired_aspect|, and |less_than| will point to the last
     82   // image with aspect ratio < |desired_aspect|.
     83   if (greater_or_equal != map_.begin()) {
     84     std::map<MapKey, gfx::Image>::const_iterator less_than =
     85         greater_or_equal;
     86     --less_than;
     87     float thinner_aspect = less_than->first.aspect();
     88     DCHECK_GT(thinner_aspect, 0.0f);
     89     DCHECK_LT(thinner_aspect, desired_aspect);
     90     if (greater_or_equal != map_.end()) {
     91       float wider_aspect = greater_or_equal->first.aspect();
     92       DCHECK_GT(wider_aspect, desired_aspect);
     93       if ((wider_aspect / desired_aspect) < (desired_aspect / thinner_aspect))
     94         return wider_aspect;
     95     }
     96     return thinner_aspect;
     97   } else {
     98     // No aspect ratio is less than or equal to |desired_aspect|.
     99     DCHECK(greater_or_equal != map_.end());
    100     float wider_aspect = greater_or_equal->first.aspect();
    101     DCHECK_GT(wider_aspect, desired_aspect);
    102     return wider_aspect;
    103   }
    104 }
    105 
    106 const gfx::Image* ImageFamily::GetBest(const gfx::Size& size) const {
    107   return GetBest(size.width(), size.height());
    108 }
    109 
    110 const gfx::Image* ImageFamily::GetWithExactAspect(float aspect,
    111                                                   int width) const {
    112   // Find the two images of given aspect ratio on either side of |width|.
    113   std::map<MapKey, gfx::Image>::const_iterator greater_or_equal =
    114       map_.lower_bound(MapKey(aspect, width));
    115   if (greater_or_equal != map_.end() &&
    116       greater_or_equal->first.aspect() == aspect) {
    117     // We have found the smallest image of the same size or greater.
    118     return &greater_or_equal->second;
    119   }
    120 
    121   DCHECK(greater_or_equal != map_.begin());
    122   std::map<MapKey, gfx::Image>::const_iterator less_than = greater_or_equal;
    123   --less_than;
    124   // This must be true because there must be at least one image with |aspect|.
    125   DCHECK_EQ(less_than->first.aspect(), aspect);
    126   // We have found the largest image smaller than desired.
    127   return &less_than->second;
    128 }
    129 
    130 }  // namespace gfx
    131