1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_IMAGE_IMAGE_FAMILY_H_
#define UI_GFX_IMAGE_IMAGE_FAMILY_H_
#include <iterator>
#include <map>
#include <utility>
#include "base/component_export.h"
#include "ui/gfx/image/image.h"
namespace gfx {
class ImageSkia;
class Size;
// A collection of images at different sizes. The images should be different
// representations of the same basic concept (for example, an icon) at various
// sizes and (optionally) aspect ratios. A method is provided for finding the
// most appropriate image to fit in a given rectangle.
//
// NOTE: This is not appropriate for storing an image at a single logical pixel
// size, with high-DPI bitmap versions; use an Image or ImageSkia for that. Each
// image in an ImageFamily should have a different logical size (and may also
// include high-DPI representations).
class COMPONENT_EXPORT(GFX) ImageFamily {
private:
// An <aspect ratio, DIP width> pair.
// A 0x0 image has aspect ratio 1.0. 0xN and Nx0 images are treated as 0x0.
struct MapKey : std::pair<float, int> {
MapKey(float aspect, int width)
: std::pair<float, int>(aspect, width) {}
float aspect() const { return first; }
int width() const { return second; }
};
public:
// Type for iterating over all images in the family, in order.
// Dereferencing this iterator returns a gfx::Image.
class COMPONENT_EXPORT(GFX) const_iterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = const gfx::Image;
using difference_type = std::ptrdiff_t;
using pointer = const gfx::Image*;
using reference = const gfx::Image&;
const_iterator();
const_iterator(const const_iterator& other);
~const_iterator();
const_iterator& operator++() {
++map_iterator_;
return *this;
}
const_iterator operator++(int /*unused*/) {
const_iterator result(*this);
++(*this);
return result;
}
const_iterator& operator--() {
--map_iterator_;
return *this;
}
const_iterator operator--(int /*unused*/) {
const_iterator result(*this);
--(*this);
return result;
}
friend bool operator==(const const_iterator&,
const const_iterator&) = default;
const gfx::Image& operator*() const {
return map_iterator_->second;
}
const gfx::Image* operator->() const {
return &**this;
}
private:
friend class ImageFamily;
explicit const_iterator(
const std::map<MapKey, gfx::Image>::const_iterator& other);
std::map<MapKey, gfx::Image>::const_iterator map_iterator_;
};
ImageFamily();
ImageFamily(ImageFamily&& other);
// Even though the Images in the family are copyable (reference-counted), the
// family itself should not be implicitly copied, as it would result in a
// shallow clone of the entire map and updates to many reference counts.
// ImageFamily can be explicitly Clone()d, but std::move is preferred.
ImageFamily(const ImageFamily&) = delete;
ImageFamily& operator=(const ImageFamily&) = delete;
~ImageFamily();
ImageFamily& operator=(ImageFamily&& other);
// Gets an iterator to the first image.
const_iterator begin() const { return const_iterator(map_.begin()); }
// Gets an iterator to one after the last image.
const_iterator end() const { return const_iterator(map_.end()); }
// Determines whether the image family has no images in it.
bool empty() const { return map_.empty(); }
// Removes all images from the family.
void clear() { return map_.clear(); }
// Creates a shallow copy of the family. The Images inside share their backing
// store with the original Images.
ImageFamily Clone() const;
// Adds an image to the family. If another image is already present at the
// same size, it will be overwritten.
void Add(const gfx::Image& image);
// Adds an image to the family. If another image is already present at the
// same size, it will be overwritten.
void Add(const gfx::ImageSkia& image_skia);
// Gets the best image to use in a rectangle of |width|x|height|.
// Gets an image at the same aspect ratio as |width|:|height|, if possible, or
// if not, the closest aspect ratio. Among images of that aspect ratio,
// returns the smallest image with both its width and height bigger or equal
// to the requested size. If none exists, returns the largest image of that
// aspect ratio. If there are no images in the family, returns NULL.
const gfx::Image* GetBest(int width, int height) const;
// Gets the best image to use in a rectangle of |size|.
// Gets an image at the same aspect ratio as |size.width()|:|size.height()|,
// if possible, or if not, the closest aspect ratio. Among images of that
// aspect ratio, returns the smallest image with both its width and height
// bigger or equal to the requested size. If none exists, returns the largest
// image of that aspect ratio. If there are no images in the family, returns
// NULL.
const gfx::Image* GetBest(const gfx::Size& size) const;
// Gets an image of size |width|x|height|. If no image of that exact size
// exists, chooses the nearest larger image using GetBest() and scales it to
// the desired size. If there are no images in the family, returns an empty
// image.
gfx::Image CreateExact(int width, int height) const;
// Gets an image of size |size|. If no image of that exact size exists,
// chooses the nearest larger image using GetBest() and scales it to the
// desired size. If there are no images in the family, returns an empty image.
gfx::Image CreateExact(const gfx::Size& size) const;
private:
// Find the closest aspect ratio in the map to |desired_aspect|.
// Ties are broken by the thinner aspect.
// |map_| must not be empty. |desired_aspect| must be > 0.0.
float GetClosestAspect(float desired_aspect) const;
// Gets an image with aspect ratio |aspect|, at the best size for |width|.
// Returns the smallest image of aspect ratio |aspect| with its width bigger
// or equal to |width|. If none exists, returns the largest image of aspect
// ratio |aspect|. Behavior is undefined if there is not at least one image in
// |map_| of aspect ratio |aspect|.
const gfx::Image* GetWithExactAspect(float aspect, int width) const;
// Map from (aspect ratio, width) to image.
std::map<MapKey, gfx::Image> map_;
};
} // namespace gfx
#endif // UI_GFX_IMAGE_IMAGE_FAMILY_H_
|