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::GetBest(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::GetBest(const gfx::Size& size) const { 105 return GetBest(size.width(), size.height()); 106 } 107 108 const gfx::Image* ImageFamily::GetWithExactAspect(float aspect, 109 int width) const { 110 // Find the two images of given aspect ratio on either side of |width|. 111 std::map<MapKey, gfx::Image>::const_iterator greater_or_equal = 112 map_.lower_bound(MapKey(aspect, width)); 113 if (greater_or_equal != map_.end() && 114 greater_or_equal->first.aspect() == aspect) { 115 // We have found the smallest image of the same size or greater. 116 return &greater_or_equal->second; 117 } 118 119 DCHECK(greater_or_equal != map_.begin()); 120 std::map<MapKey, gfx::Image>::const_iterator less_than = greater_or_equal; 121 --less_than; 122 // This must be true because there must be at least one image with |aspect|. 123 DCHECK_EQ(less_than->first.aspect(), aspect); 124 // We have found the largest image smaller than desired. 125 return &less_than->second; 126 } 127 128 } // namespace gfx 129