image_family.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image_family.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cmath>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/image/image.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/size.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)namespace gfx {
145e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)
155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)ImageFamily::const_iterator::const_iterator() {}
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageFamily::const_iterator::const_iterator(const const_iterator& other)
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : map_iterator_(other.map_iterator_) {}
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)ImageFamily::const_iterator::const_iterator(
21a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const std::map<MapKey, gfx::Image>::const_iterator& other)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : map_iterator_(other) {}
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochImageFamily::ImageFamily() {}
250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)ImageFamily::~ImageFamily() {}
260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ImageFamily::Add(const gfx::Image& image) {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size size = image.Size();
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (size.IsEmpty()) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    map_[MapKey(1.0f, 0)] = image;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    float aspect = static_cast<float>(size.width()) / size.height();
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_GT(aspect, 0.0f);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    map_[MapKey(aspect, size.width())] = image;
35424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
36424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ImageFamily::Add(const gfx::ImageSkia& image_skia) {
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  Add(gfx::Image(image_skia));
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst gfx::Image* ImageFamily::GetBest(int width, int height) const {
437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (map_.empty())
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return NULL;
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // If either |width| or |height| is 0, both are.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float desired_aspect;
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (height == 0 || width == 0) {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    desired_aspect = 1.0f;
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    height = 0;
517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    width = 0;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    desired_aspect = static_cast<float>(width) / height;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GT(desired_aspect, 0.0f);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  float closest_aspect = GetClosestAspect(desired_aspect);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If thinner than desired, search for images with width such that the
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // corresponding height is greater than or equal to the desired |height|.
61424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int desired_width = closest_aspect <= desired_aspect ?
627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      width : static_cast<int>(ceilf(height * closest_aspect));
63424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the best-sized image with the aspect ratio.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetWithExactAspect(closest_aspect, desired_width);
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)float ImageFamily::GetClosestAspect(float desired_aspect) const {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the two aspect ratios on either side of |desired_aspect|.
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::map<MapKey, gfx::Image>::const_iterator greater_or_equal =
717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      map_.lower_bound(MapKey(desired_aspect, 0));
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Early exit optimization if there is an exact match.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (greater_or_equal != map_.end() &&
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      greater_or_equal->first.aspect() == desired_aspect) {
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return desired_aspect;
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // No exact match; |greater_or_equal| will point to the first image with
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // aspect ratio >= |desired_aspect|, and |less_than| will point to the last
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // image with aspect ratio < |desired_aspect|.
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (greater_or_equal != map_.begin()) {
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::map<MapKey, gfx::Image>::const_iterator less_than =
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        greater_or_equal;
847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    --less_than;
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float thinner_aspect = less_than->first.aspect();
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_GT(thinner_aspect, 0.0f);
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK_LT(thinner_aspect, desired_aspect);
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (greater_or_equal != map_.end()) {
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      float wider_aspect = greater_or_equal->first.aspect();
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DCHECK_GT(wider_aspect, desired_aspect);
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if ((wider_aspect / desired_aspect) < (desired_aspect / thinner_aspect))
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return wider_aspect;
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return thinner_aspect;
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // No aspect ratio is less than or equal to |desired_aspect|.
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK(greater_or_equal != map_.end());
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    float wider_aspect = greater_or_equal->first.aspect();
997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK_GT(wider_aspect, desired_aspect);
1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return wider_aspect;
1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const gfx::Image* ImageFamily::GetBest(const gfx::Size& size) const {
1057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return GetBest(size.width(), size.height());
106424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const gfx::Image* ImageFamily::GetWithExactAspect(float aspect,
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                  int width) const {
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Find the two images of given aspect ratio on either side of |width|.
1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::map<MapKey, gfx::Image>::const_iterator greater_or_equal =
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      map_.lower_bound(MapKey(aspect, width));
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (greater_or_equal != map_.end() &&
1147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      greater_or_equal->first.aspect() == aspect) {
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // We have found the smallest image of the same size or greater.
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return &greater_or_equal->second;
1177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(greater_or_equal != map_.begin());
120424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::map<MapKey, gfx::Image>::const_iterator less_than = greater_or_equal;
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  --less_than;
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // This must be true because there must be at least one image with |aspect|.
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(less_than->first.aspect(), aspect);
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // We have found the largest image smaller than desired.
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return &less_than->second;
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace gfx
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)