1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image_family.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <cmath> 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image.h" 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image_skia.h" 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/size.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace gfx { 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ImageFamily::const_iterator::const_iterator() {} 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ImageFamily::const_iterator::const_iterator(const const_iterator& other) 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : map_iterator_(other.map_iterator_) {} 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ImageFamily::const_iterator::const_iterator( 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::map<MapKey, gfx::Image>::const_iterator& other) 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : map_iterator_(other) {} 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ImageFamily::const_iterator::~const_iterator() {} 25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ImageFamily::ImageFamily() {} 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ImageFamily::~ImageFamily() {} 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ImageFamily::Add(const gfx::Image& image) { 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size size = image.Size(); 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (size.IsEmpty()) { 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) map_[MapKey(1.0f, 0)] = image; 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float aspect = static_cast<float>(size.width()) / size.height(); 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_GT(aspect, 0.0f); 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) map_[MapKey(aspect, size.width())] = image; 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ImageFamily::Add(const gfx::ImageSkia& image_skia) { 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Add(gfx::Image(image_skia)); 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const gfx::Image* ImageFamily::GetBest(int width, int height) const { 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (map_.empty()) 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return NULL; 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If either |width| or |height| is 0, both are. 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float desired_aspect; 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (height == 0 || width == 0) { 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) desired_aspect = 1.0f; 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) height = 0; 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) width = 0; 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) desired_aspect = static_cast<float>(width) / height; 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_GT(desired_aspect, 0.0f); 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float closest_aspect = GetClosestAspect(desired_aspect); 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If thinner than desired, search for images with width such that the 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // corresponding height is greater than or equal to the desired |height|. 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int desired_width = closest_aspect <= desired_aspect ? 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) width : static_cast<int>(ceilf(height * closest_aspect)); 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Get the best-sized image with the aspect ratio. 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return GetWithExactAspect(closest_aspect, desired_width); 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)float ImageFamily::GetClosestAspect(float desired_aspect) const { 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Find the two aspect ratios on either side of |desired_aspect|. 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::map<MapKey, gfx::Image>::const_iterator greater_or_equal = 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) map_.lower_bound(MapKey(desired_aspect, 0)); 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Early exit optimization if there is an exact match. 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (greater_or_equal != map_.end() && 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) greater_or_equal->first.aspect() == desired_aspect) { 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return desired_aspect; 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // No exact match; |greater_or_equal| will point to the first image with 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // aspect ratio >= |desired_aspect|, and |less_than| will point to the last 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // image with aspect ratio < |desired_aspect|. 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (greater_or_equal != map_.begin()) { 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::map<MapKey, gfx::Image>::const_iterator less_than = 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) greater_or_equal; 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) --less_than; 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float thinner_aspect = less_than->first.aspect(); 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_GT(thinner_aspect, 0.0f); 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_LT(thinner_aspect, desired_aspect); 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (greater_or_equal != map_.end()) { 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float wider_aspect = greater_or_equal->first.aspect(); 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_GT(wider_aspect, desired_aspect); 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if ((wider_aspect / desired_aspect) < (desired_aspect / thinner_aspect)) 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return wider_aspect; 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return thinner_aspect; 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // No aspect ratio is less than or equal to |desired_aspect|. 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(greater_or_equal != map_.end()); 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float wider_aspect = greater_or_equal->first.aspect(); 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_GT(wider_aspect, desired_aspect); 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return wider_aspect; 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const gfx::Image* ImageFamily::GetBest(const gfx::Size& size) const { 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return GetBest(size.width(), size.height()); 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const gfx::Image* ImageFamily::GetWithExactAspect(float aspect, 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int width) const { 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Find the two images of given aspect ratio on either side of |width|. 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::map<MapKey, gfx::Image>::const_iterator greater_or_equal = 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) map_.lower_bound(MapKey(aspect, width)); 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (greater_or_equal != map_.end() && 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) greater_or_equal->first.aspect() == aspect) { 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // We have found the smallest image of the same size or greater. 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return &greater_or_equal->second; 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(greater_or_equal != map_.begin()); 122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::map<MapKey, gfx::Image>::const_iterator less_than = greater_or_equal; 123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) --less_than; 124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // This must be true because there must be at least one image with |aspect|. 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_EQ(less_than->first.aspect(), aspect); 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // We have found the largest image smaller than desired. 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return &less_than->second; 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace gfx 131