// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/gfx/image/image_family.h" #include <cmath> #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/size.h" namespace gfx { ImageFamily::const_iterator::const_iterator() {} ImageFamily::const_iterator::const_iterator(const const_iterator& other) : map_iterator_(other.map_iterator_) {} ImageFamily::const_iterator::const_iterator( const std::map<MapKey, gfx::Image>::const_iterator& other) : map_iterator_(other) {} ImageFamily::const_iterator::~const_iterator() {} ImageFamily::ImageFamily() {} ImageFamily::~ImageFamily() {} void ImageFamily::Add(const gfx::Image& image) { gfx::Size size = image.Size(); if (size.IsEmpty()) { map_[MapKey(1.0f, 0)] = image; } else { float aspect = static_cast<float>(size.width()) / size.height(); DCHECK_GT(aspect, 0.0f); map_[MapKey(aspect, size.width())] = image; } } void ImageFamily::Add(const gfx::ImageSkia& image_skia) { Add(gfx::Image(image_skia)); } const gfx::Image* ImageFamily::GetBest(int width, int height) const { if (map_.empty()) return NULL; // If either |width| or |height| is 0, both are. float desired_aspect; if (height == 0 || width == 0) { desired_aspect = 1.0f; height = 0; width = 0; } else { desired_aspect = static_cast<float>(width) / height; } DCHECK_GT(desired_aspect, 0.0f); float closest_aspect = GetClosestAspect(desired_aspect); // If thinner than desired, search for images with width such that the // corresponding height is greater than or equal to the desired |height|. int desired_width = closest_aspect <= desired_aspect ? width : static_cast<int>(ceilf(height * closest_aspect)); // Get the best-sized image with the aspect ratio. return GetWithExactAspect(closest_aspect, desired_width); } float ImageFamily::GetClosestAspect(float desired_aspect) const { // Find the two aspect ratios on either side of |desired_aspect|. std::map<MapKey, gfx::Image>::const_iterator greater_or_equal = map_.lower_bound(MapKey(desired_aspect, 0)); // Early exit optimization if there is an exact match. if (greater_or_equal != map_.end() && greater_or_equal->first.aspect() == desired_aspect) { return desired_aspect; } // No exact match; |greater_or_equal| will point to the first image with // aspect ratio >= |desired_aspect|, and |less_than| will point to the last // image with aspect ratio < |desired_aspect|. if (greater_or_equal != map_.begin()) { std::map<MapKey, gfx::Image>::const_iterator less_than = greater_or_equal; --less_than; float thinner_aspect = less_than->first.aspect(); DCHECK_GT(thinner_aspect, 0.0f); DCHECK_LT(thinner_aspect, desired_aspect); if (greater_or_equal != map_.end()) { float wider_aspect = greater_or_equal->first.aspect(); DCHECK_GT(wider_aspect, desired_aspect); if ((wider_aspect / desired_aspect) < (desired_aspect / thinner_aspect)) return wider_aspect; } return thinner_aspect; } else { // No aspect ratio is less than or equal to |desired_aspect|. DCHECK(greater_or_equal != map_.end()); float wider_aspect = greater_or_equal->first.aspect(); DCHECK_GT(wider_aspect, desired_aspect); return wider_aspect; } } const gfx::Image* ImageFamily::GetBest(const gfx::Size& size) const { return GetBest(size.width(), size.height()); } const gfx::Image* ImageFamily::GetWithExactAspect(float aspect, int width) const { // Find the two images of given aspect ratio on either side of |width|. std::map<MapKey, gfx::Image>::const_iterator greater_or_equal = map_.lower_bound(MapKey(aspect, width)); if (greater_or_equal != map_.end() && greater_or_equal->first.aspect() == aspect) { // We have found the smallest image of the same size or greater. return &greater_or_equal->second; } DCHECK(greater_or_equal != map_.begin()); std::map<MapKey, gfx::Image>::const_iterator less_than = greater_or_equal; --less_than; // This must be true because there must be at least one image with |aspect|. DCHECK_EQ(less_than->first.aspect(), aspect); // We have found the largest image smaller than desired. return &less_than->second; } } // namespace gfx