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::const_iterator::~const_iterator() {} 25 26 ImageFamily::ImageFamily() {} 27 ImageFamily::~ImageFamily() {} 28 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 40 void ImageFamily::Add(const gfx::ImageSkia& image_skia) { 41 Add(gfx::Image(image_skia)); 42 } 43 44 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 70 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 106 const gfx::Image* ImageFamily::GetBest(const gfx::Size& size) const { 107 return GetBest(size.width(), size.height()); 108 } 109 110 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