OLD | NEW |
---|---|
(Empty) | |
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::ImageFamily() {} | |
16 ImageFamily::~ImageFamily() {} | |
17 | |
18 void ImageFamily::Add(const gfx::Image& image) { | |
19 gfx::Size size = image.Size(); | |
20 if (size.IsEmpty()) { | |
21 map_[MapKey(1.0f, 0)] = image; | |
22 } else { | |
23 float aspect = static_cast<float>(size.width()) / size.height(); | |
24 DCHECK_GT(aspect, 0.0f); | |
25 map_[MapKey(aspect, size.width())] = image; | |
26 } | |
27 } | |
28 | |
29 void ImageFamily::Add(const gfx::ImageSkia& image_skia) { | |
30 Add(gfx::Image(image_skia)); | |
31 } | |
32 | |
33 const gfx::Image* ImageFamily::Get(int width, int height) const { | |
34 if (map_.empty()) | |
35 return NULL; | |
36 | |
37 // If either width or height is 0, both are. | |
38 float desired_aspect; | |
39 if (height == 0 || width == 0) { | |
40 desired_aspect = 1.0f; | |
41 height = 0; | |
42 width = 0; | |
43 } else { | |
44 desired_aspect = static_cast<float>(width) / height; | |
45 } | |
46 DCHECK_GT(desired_aspect, 0.0f); | |
47 | |
48 float closest_aspect = GetClosestAspect(desired_aspect); | |
49 | |
50 // If thinner than desired, search for images with width such that the | |
51 // corresponding height is greater than or equal to the desired height. | |
52 int desired_width = closest_aspect <= desired_aspect ? | |
53 width : static_cast<int>(ceilf(height * closest_aspect)); | |
Robert Sesek
2013/04/01 20:57:45
Do you need this cast or can you just let it trunc
Matt Giuca
2013/04/02 06:11:28
I explicitly want ceil because it will satisfy the
| |
54 | |
55 // Get the best-sized image with the aspect ratio. | |
56 return GetWithExactAspect(closest_aspect, desired_width); | |
57 } | |
58 | |
59 float ImageFamily::GetClosestAspect(float desired_aspect) const { | |
60 // Find the two aspect ratios on either side of desired_aspect. | |
61 std::map<MapKey, gfx::Image>::const_iterator greater_or_equal = | |
62 map_.lower_bound(MapKey(desired_aspect, 0.0f)); | |
63 // Early exit optimization if there is an exact match. | |
64 if (greater_or_equal != map_.end() && | |
65 greater_or_equal->first.aspect() == desired_aspect) { | |
66 return desired_aspect; | |
67 } | |
68 | |
69 // No exact match; greater_or_equal will point to the first image with aspect | |
70 // ratio >= desired_aspect, and less_than will point to the last image with | |
71 // aspect ratio < desired_aspect. | |
72 if (greater_or_equal != map_.begin()) { | |
73 std::map<MapKey, gfx::Image>::const_iterator less_than = | |
74 greater_or_equal; | |
75 --less_than; | |
76 float thinner_aspect = less_than->first.aspect(); | |
77 DCHECK_GT(thinner_aspect, 0.0f); | |
78 DCHECK_LT(thinner_aspect, desired_aspect); | |
79 if (greater_or_equal != map_.end()) { | |
80 float wider_aspect = greater_or_equal->first.aspect(); | |
81 DCHECK_GT(wider_aspect, desired_aspect); | |
82 if ((wider_aspect / desired_aspect) < (desired_aspect / thinner_aspect)) | |
83 return wider_aspect; | |
84 } | |
85 return thinner_aspect; | |
86 } else { | |
87 // No aspect ratio is less than or equal to desired_aspect. | |
88 DCHECK(greater_or_equal != map_.end()); | |
89 float wider_aspect = greater_or_equal->first.aspect(); | |
90 DCHECK_GT(wider_aspect, desired_aspect); | |
91 return wider_aspect; | |
92 } | |
93 } | |
94 | |
95 const gfx::Image* ImageFamily::GetWithExactAspect(float aspect, | |
96 int width) const { | |
97 // Find the two images of given aspect ratio on either side of width. | |
98 std::map<MapKey, gfx::Image>::const_iterator greater_or_equal = | |
99 map_.lower_bound(MapKey(aspect, width)); | |
100 if (greater_or_equal != map_.end() && | |
101 greater_or_equal->first.aspect() == aspect) { | |
102 // We have found the smallest image of the same size or greater. | |
103 return &greater_or_equal->second; | |
104 } | |
105 | |
106 DCHECK(greater_or_equal != map_.begin()); | |
107 std::map<MapKey, gfx::Image>::const_iterator less_than = greater_or_equal; | |
108 --less_than; | |
109 // This must be true because there must be at least one image with |aspect|. | |
110 DCHECK_EQ(less_than->first.aspect(), aspect); | |
111 // We have found the largest image smaller than desired. | |
112 return &less_than->second; | |
113 } | |
114 | |
115 ImageFamily::const_iterator::const_iterator( | |
116 const std::map<MapKey, gfx::Image>::const_iterator& other) | |
117 : map_iterator_(other) {} | |
118 | |
119 } // namespace gfx | |
OLD | NEW |