Index: ui/gfx/icon_family.cc |
diff --git a/ui/gfx/icon_family.cc b/ui/gfx/icon_family.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..092114881768bcfca9419d8d20789343b443b93d |
--- /dev/null |
+++ b/ui/gfx/icon_family.cc |
@@ -0,0 +1,120 @@ |
+// 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/icon_family.h" |
+ |
+#include <algorithm> |
+ |
+#include "ui/gfx/image/image.h" |
+#include "ui/gfx/image/image_skia.h" |
+ |
+namespace gfx { |
+ |
+IconFamily::IconFamily() {} |
+IconFamily::~IconFamily() {} |
+ |
+void IconFamily::Add(const gfx::Image& icon) |
+{ |
+ if (icon.IsEmpty()) |
+ return; |
+ const gfx::ImageSkia* imageskia = icon.ToImageSkia(); |
+ if (imageskia) |
+ Add(*imageskia); |
+} |
+ |
+void IconFamily::Add(const gfx::ImageSkia& icon) |
+{ |
+ int width = icon.width(); |
+ int height = icon.height(); |
+ float aspect; |
+ if (height == 0) { |
+ // Assume the image is square. |
+ aspect = 1.0f; |
+ } else { |
+ aspect = static_cast<float>(width) / height; |
+ } |
+ int size = std::min(width, height); |
+ map_[MapKey(aspect, size)] = icon; |
+} |
+ |
+const gfx::ImageSkia* IconFamily::Get(int width, int height) const |
+{ |
+ if (map_.empty()) |
+ return NULL; |
+ |
+ float desired_aspect; |
+ if (height == 0) { |
+ if (width == 0) { |
+ // Choose a square image if possible. |
+ desired_aspect = 1.0f; |
+ } else { |
+ // Choose the widest possible aspect ratio (since infinity is not a |
+ // well-defined concept in C++). |
+ desired_aspect = (--map_.end())->first.first; |
+ } |
+ } else { |
+ desired_aspect = static_cast<float>(width) / height; |
+ } |
+ int desired_size = std::max(width, height); |
+ |
+ // Get iterator to images >= and < the desired aspect ratio and size. |
+ std::map<MapKey, gfx::ImageSkia>::const_iterator greater_or_equal = |
+ map_.lower_bound(MapKey(desired_aspect, desired_size)); |
+ if (greater_or_equal != map_.end() && |
+ greater_or_equal->first.aspect() == desired_aspect) { |
+ // Exact same aspect ratio, and we have found the smallest image of the same |
+ // size or greater. This is ideal. |
+ return &greater_or_equal->second; |
+ } |
+ |
+ float closest_aspect; // Closest aspect ratio to the desired one. |
+ if (greater_or_equal != map_.begin()) { |
+ std::map<MapKey, gfx::ImageSkia>::const_iterator less_than = |
+ greater_or_equal; |
+ --less_than; |
+ if (less_than->first.aspect() == desired_aspect) { |
+ // Exact same aspect ratio, and we have found the largest image smaller |
+ // than desired. |
+ return &less_than->second; |
+ } |
+ |
+ float thinner_aspect = less_than->first.aspect(); |
+ DCHECK(thinner_aspect < desired_aspect); |
+ closest_aspect = thinner_aspect; |
+ if (greater_or_equal != map_.end()) { |
+ float wider_aspect = greater_or_equal->first.aspect(); |
+ DCHECK(wider_aspect > desired_aspect); |
+ if ((wider_aspect - desired_aspect) < (desired_aspect - thinner_aspect)) |
+ closest_aspect = wider_aspect; |
+ } |
+ } else { |
+ // No aspect ratio is less than or equal to desired_aspect. |
+ DCHECK(greater_or_equal != map_.end()); |
+ closest_aspect = greater_or_equal->first.aspect(); |
+ DCHECK(closest_aspect > desired_aspect); |
+ } |
+ |
+ // Search again, this time with the aspect ratio we know exists. |
+ greater_or_equal = map_.lower_bound(MapKey(closest_aspect, desired_size)); |
+ if (greater_or_equal != map_.end() && |
+ greater_or_equal->first.aspect() == closest_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::ImageSkia>::const_iterator less_than = greater_or_equal; |
+ --less_than; |
+ // This must be true because there must be at least one image with |
+ // closest_aspect. |
+ DCHECK(less_than->first.aspect() == closest_aspect); |
+ // We have found the largest image smaller than desired. |
+ return &less_than->second; |
+} |
+ |
+IconFamily::const_iterator::const_iterator( |
+ const std::map<MapKey, gfx::ImageSkia>::const_iterator& other) |
+ : map_iterator_(other) {} |
+ |
+} // namespace gfx |