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.
5 #include "ui/gfx/image/image_family.h"
9 #include "ui/gfx/image/image.h"
10 #include "ui/gfx/image/image_skia.h"
11 #include "ui/gfx/size.h"
15 ImageFamily::const_iterator::const_iterator() {}
17 ImageFamily::const_iterator::const_iterator(const const_iterator
& other
)
18 : map_iterator_(other
.map_iterator_
) {}
20 ImageFamily::const_iterator::const_iterator(
21 const std::map
<MapKey
, gfx::Image
>::const_iterator
& other
)
22 : map_iterator_(other
) {}
24 ImageFamily::ImageFamily() {}
25 ImageFamily::~ImageFamily() {}
27 void ImageFamily::Add(const gfx::Image
& image
) {
28 gfx::Size size
= image
.Size();
30 map_
[MapKey(1.0f
, 0)] = image
;
32 float aspect
= static_cast<float>(size
.width()) / size
.height();
33 DCHECK_GT(aspect
, 0.0f
);
34 map_
[MapKey(aspect
, size
.width())] = image
;
38 void ImageFamily::Add(const gfx::ImageSkia
& image_skia
) {
39 Add(gfx::Image(image_skia
));
42 const gfx::Image
* ImageFamily::GetBest(int width
, int height
) const {
46 // If either |width| or |height| is 0, both are.
48 if (height
== 0 || width
== 0) {
49 desired_aspect
= 1.0f
;
53 desired_aspect
= static_cast<float>(width
) / height
;
55 DCHECK_GT(desired_aspect
, 0.0f
);
57 float closest_aspect
= GetClosestAspect(desired_aspect
);
59 // If thinner than desired, search for images with width such that the
60 // corresponding height is greater than or equal to the desired |height|.
61 int desired_width
= closest_aspect
<= desired_aspect
?
62 width
: static_cast<int>(ceilf(height
* closest_aspect
));
64 // Get the best-sized image with the aspect ratio.
65 return GetWithExactAspect(closest_aspect
, desired_width
);
68 float ImageFamily::GetClosestAspect(float desired_aspect
) const {
69 // Find the two aspect ratios on either side of |desired_aspect|.
70 std::map
<MapKey
, gfx::Image
>::const_iterator greater_or_equal
=
71 map_
.lower_bound(MapKey(desired_aspect
, 0));
72 // Early exit optimization if there is an exact match.
73 if (greater_or_equal
!= map_
.end() &&
74 greater_or_equal
->first
.aspect() == desired_aspect
) {
75 return desired_aspect
;
78 // No exact match; |greater_or_equal| will point to the first image with
79 // aspect ratio >= |desired_aspect|, and |less_than| will point to the last
80 // image with aspect ratio < |desired_aspect|.
81 if (greater_or_equal
!= map_
.begin()) {
82 std::map
<MapKey
, gfx::Image
>::const_iterator less_than
=
85 float thinner_aspect
= less_than
->first
.aspect();
86 DCHECK_GT(thinner_aspect
, 0.0f
);
87 DCHECK_LT(thinner_aspect
, desired_aspect
);
88 if (greater_or_equal
!= map_
.end()) {
89 float wider_aspect
= greater_or_equal
->first
.aspect();
90 DCHECK_GT(wider_aspect
, desired_aspect
);
91 if ((wider_aspect
/ desired_aspect
) < (desired_aspect
/ thinner_aspect
))
94 return thinner_aspect
;
96 // No aspect ratio is less than or equal to |desired_aspect|.
97 DCHECK(greater_or_equal
!= map_
.end());
98 float wider_aspect
= greater_or_equal
->first
.aspect();
99 DCHECK_GT(wider_aspect
, desired_aspect
);
104 const gfx::Image
* ImageFamily::GetWithExactAspect(float aspect
,
106 // Find the two images of given aspect ratio on either side of |width|.
107 std::map
<MapKey
, gfx::Image
>::const_iterator greater_or_equal
=
108 map_
.lower_bound(MapKey(aspect
, width
));
109 if (greater_or_equal
!= map_
.end() &&
110 greater_or_equal
->first
.aspect() == aspect
) {
111 // We have found the smallest image of the same size or greater.
112 return &greater_or_equal
->second
;
115 DCHECK(greater_or_equal
!= map_
.begin());
116 std::map
<MapKey
, gfx::Image
>::const_iterator less_than
= greater_or_equal
;
118 // This must be true because there must be at least one image with |aspect|.
119 DCHECK_EQ(less_than
->first
.aspect(), aspect
);
120 // We have found the largest image smaller than desired.
121 return &less_than
->second
;