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::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::ImageFamily() {} |
| 25 ImageFamily::~ImageFamily() {} |
| 26 |
| 27 void ImageFamily::Add(const gfx::Image& image) { |
| 28 gfx::Size size = image.Size(); |
| 29 if (size.IsEmpty()) { |
| 30 map_[MapKey(1.0f, 0)] = image; |
| 31 } else { |
| 32 float aspect = static_cast<float>(size.width()) / size.height(); |
| 33 DCHECK_GT(aspect, 0.0f); |
| 34 map_[MapKey(aspect, size.width())] = image; |
| 35 } |
| 36 } |
| 37 |
| 38 void ImageFamily::Add(const gfx::ImageSkia& image_skia) { |
| 39 Add(gfx::Image(image_skia)); |
| 40 } |
| 41 |
| 42 const gfx::Image* ImageFamily::Get(int width, int height) const { |
| 43 if (map_.empty()) |
| 44 return NULL; |
| 45 |
| 46 // If either |width| or |height| is 0, both are. |
| 47 float desired_aspect; |
| 48 if (height == 0 || width == 0) { |
| 49 desired_aspect = 1.0f; |
| 50 height = 0; |
| 51 width = 0; |
| 52 } else { |
| 53 desired_aspect = static_cast<float>(width) / height; |
| 54 } |
| 55 DCHECK_GT(desired_aspect, 0.0f); |
| 56 |
| 57 float closest_aspect = GetClosestAspect(desired_aspect); |
| 58 |
| 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)); |
| 63 |
| 64 // Get the best-sized image with the aspect ratio. |
| 65 return GetWithExactAspect(closest_aspect, desired_width); |
| 66 } |
| 67 |
| 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; |
| 76 } |
| 77 |
| 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 = |
| 83 greater_or_equal; |
| 84 --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)) |
| 92 return wider_aspect; |
| 93 } |
| 94 return thinner_aspect; |
| 95 } else { |
| 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); |
| 100 return wider_aspect; |
| 101 } |
| 102 } |
| 103 |
| 104 const gfx::Image* ImageFamily::GetWithExactAspect(float aspect, |
| 105 int width) const { |
| 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; |
| 113 } |
| 114 |
| 115 DCHECK(greater_or_equal != map_.begin()); |
| 116 std::map<MapKey, gfx::Image>::const_iterator less_than = greater_or_equal; |
| 117 --less_than; |
| 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; |
| 122 } |
| 123 |
| 124 } // namespace gfx |
OLD | NEW |