• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
const_iterator()15 ImageFamily::const_iterator::const_iterator() {}
16 
const_iterator(const const_iterator & other)17 ImageFamily::const_iterator::const_iterator(const const_iterator& other)
18     : map_iterator_(other.map_iterator_) {}
19 
const_iterator(const std::map<MapKey,gfx::Image>::const_iterator & other)20 ImageFamily::const_iterator::const_iterator(
21     const std::map<MapKey, gfx::Image>::const_iterator& other)
22     : map_iterator_(other) {}
23 
~const_iterator()24 ImageFamily::const_iterator::~const_iterator() {}
25 
ImageFamily()26 ImageFamily::ImageFamily() {}
~ImageFamily()27 ImageFamily::~ImageFamily() {}
28 
Add(const gfx::Image & image)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 
Add(const gfx::ImageSkia & image_skia)40 void ImageFamily::Add(const gfx::ImageSkia& image_skia) {
41   Add(gfx::Image(image_skia));
42 }
43 
GetBest(int width,int height) const44 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 
GetClosestAspect(float desired_aspect) const70 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 
GetBest(const gfx::Size & size) const106 const gfx::Image* ImageFamily::GetBest(const gfx::Size& size) const {
107   return GetBest(size.width(), size.height());
108 }
109 
GetWithExactAspect(float aspect,int width) const110 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