OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/image/image_skia.h" | 5 #include "ui/gfx/image/image_skia.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/stl_util.h" | 11 #include "ui/gfx/size.h" |
12 | 12 |
13 namespace gfx { | 13 namespace gfx { |
14 | 14 |
15 ImageSkia::ImageSkia(const SkBitmap* bitmap) | 15 namespace internal { |
16 : size_(bitmap->width(), bitmap->height()), | 16 |
17 mip_map_build_pending_(false) { | 17 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a |
18 CHECK(bitmap); | 18 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's |
19 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() | 19 // information. |
20 bitmaps_.push_back(bitmap); | 20 class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { |
| 21 public: |
| 22 ImageSkiaStorage() { |
| 23 } |
| 24 |
| 25 void AddBitmap(const SkBitmap& bitmap) { |
| 26 bitmaps_.push_back(bitmap); |
| 27 } |
| 28 |
| 29 const std::vector<SkBitmap>& bitmaps() const { return bitmaps_; } |
| 30 |
| 31 void set_size(const gfx::Size& size) { size_ = size; } |
| 32 const gfx::Size& size() const { return size_; } |
| 33 |
| 34 private: |
| 35 ~ImageSkiaStorage() { |
| 36 } |
| 37 |
| 38 // Bitmaps at different densities. |
| 39 std::vector<SkBitmap> bitmaps_; |
| 40 |
| 41 // Size of the image in DIP. |
| 42 gfx::Size size_; |
| 43 |
| 44 friend class base::RefCounted<ImageSkiaStorage>; |
| 45 }; |
| 46 |
| 47 } // internal |
| 48 |
| 49 // static |
| 50 SkBitmap* ImageSkia::null_bitmap_ = new SkBitmap(); |
| 51 |
| 52 ImageSkia::ImageSkia() : storage_(NULL) { |
21 } | 53 } |
22 | 54 |
23 ImageSkia::ImageSkia(const std::vector<const SkBitmap*>& bitmaps) | 55 ImageSkia::ImageSkia(const SkBitmap& bitmap) { |
24 : bitmaps_(bitmaps), | 56 Init(bitmap); |
25 mip_map_build_pending_(false) { | 57 } |
26 CHECK(!bitmaps_.empty()); | 58 |
27 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() for each | 59 ImageSkia::ImageSkia(const SkBitmap& bitmap, float dip_scale_factor) { |
28 // vector element. | 60 Init(bitmap, dip_scale_factor); |
29 // Assume that the smallest bitmap represents 1x scale factor. | 61 } |
30 for (size_t i = 0; i < bitmaps_.size(); ++i) { | 62 |
31 gfx::Size bitmap_size(bitmaps_[i]->width(), bitmaps_[i]->height()); | 63 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { |
32 if (size_.IsEmpty() || bitmap_size.GetArea() < size_.GetArea()) | 64 } |
33 size_ = bitmap_size; | 65 |
| 66 ImageSkia& ImageSkia::operator=(const ImageSkia& other) { |
| 67 storage_ = other.storage_; |
| 68 return *this; |
| 69 } |
| 70 |
| 71 ImageSkia& ImageSkia::operator=(const SkBitmap& other) { |
| 72 Init(other); |
| 73 return *this; |
| 74 } |
| 75 |
| 76 ImageSkia::operator SkBitmap&() const { |
| 77 if (isNull()) { |
| 78 return *null_bitmap_; |
| 79 } |
| 80 |
| 81 return const_cast<SkBitmap&>(storage_->bitmaps()[0]); |
| 82 } |
| 83 |
| 84 ImageSkia::~ImageSkia() { |
| 85 } |
| 86 |
| 87 void ImageSkia::AddBitmapForScale(const SkBitmap& bitmap, |
| 88 float dip_scale_factor) { |
| 89 DCHECK(!bitmap.isNull()); |
| 90 |
| 91 if (isNull()) { |
| 92 Init(bitmap, dip_scale_factor); |
| 93 } else { |
| 94 // We currently assume that the bitmap size = 1x size * |dip_scale_factor|. |
| 95 // TODO(pkotwicz): Do something better because of rounding errors when |
| 96 // |dip_scale_factor| is not an int. |
| 97 // TODO(pkotwicz): Remove DCHECK for dip_scale_factor == 1.0f once |
| 98 // image_loading_tracker correctly handles multiple sized images. |
| 99 DCHECK(dip_scale_factor == 1.0f || |
| 100 static_cast<int>(width() * dip_scale_factor) == bitmap.width()); |
| 101 DCHECK(dip_scale_factor == 1.0f || |
| 102 static_cast<int>(height() * dip_scale_factor) == bitmap.height()); |
| 103 storage_->AddBitmap(bitmap); |
34 } | 104 } |
35 } | 105 } |
36 | 106 |
37 ImageSkia::~ImageSkia() { | 107 const SkBitmap& ImageSkia::GetBitmapForScale(float x_scale_factor, |
38 STLDeleteElements(&bitmaps_); | 108 float y_scale_factor, |
39 } | 109 float* bitmap_scale_factor) const { |
40 | 110 |
41 void ImageSkia::BuildMipMap() { | 111 if (empty()) |
42 mip_map_build_pending_ = true; | 112 return *null_bitmap_; |
43 } | |
44 | 113 |
45 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, int x, int y) { | 114 // Get the desired bitmap width and height given |x_scale_factor|, |
46 SkPaint p; | 115 // |y_scale_factor| and size at 1x density. |
47 DrawToCanvasInt(canvas, x, y, p); | 116 float desired_width = width() * x_scale_factor; |
48 } | 117 float desired_height = height() * y_scale_factor; |
49 | 118 |
50 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, | 119 const std::vector<SkBitmap>& bitmaps = storage_->bitmaps(); |
51 int x, int y, | |
52 const SkPaint& paint) { | |
53 | |
54 if (IsZeroSized()) | |
55 return; | |
56 | |
57 SkMatrix m = canvas->sk_canvas()->getTotalMatrix(); | |
58 float scale_x = std::abs(SkScalarToFloat(m.getScaleX())); | |
59 float scale_y = std::abs(SkScalarToFloat(m.getScaleY())); | |
60 | |
61 const SkBitmap* bitmap = GetBitmapForScale(scale_x, scale_y); | |
62 | |
63 if (mip_map_build_pending_) { | |
64 const_cast<SkBitmap*>(bitmap)->buildMipMap(); | |
65 mip_map_build_pending_ = false; | |
66 } | |
67 | |
68 float bitmap_scale_x = static_cast<float>(bitmap->width()) / width(); | |
69 float bitmap_scale_y = static_cast<float>(bitmap->height()) / height(); | |
70 | |
71 canvas->Save(); | |
72 canvas->sk_canvas()->scale(1.0f / bitmap_scale_x, | |
73 1.0f / bitmap_scale_y); | |
74 canvas->sk_canvas()->drawBitmap(*bitmap, SkFloatToScalar(x * bitmap_scale_x), | |
75 SkFloatToScalar(y * bitmap_scale_y)); | |
76 canvas->Restore(); | |
77 } | |
78 | |
79 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, | |
80 int src_x, int src_y, int src_w, int src_h, | |
81 int dest_x, int dest_y, int dest_w, int dest_h, | |
82 bool filter) { | |
83 SkPaint p; | |
84 DrawToCanvasInt(canvas, src_x, src_y, src_w, src_h, dest_x, dest_y, | |
85 dest_w, dest_h, filter, p); | |
86 } | |
87 | |
88 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, | |
89 int src_x, int src_y, int src_w, int src_h, | |
90 int dest_x, int dest_y, int dest_w, int dest_h, | |
91 bool filter, | |
92 const SkPaint& paint) { | |
93 if (IsZeroSized()) | |
94 return; | |
95 | |
96 SkMatrix m = canvas->sk_canvas()->getTotalMatrix(); | |
97 float scale_x = std::abs(SkScalarToFloat(m.getScaleX())); | |
98 float scale_y = std::abs(SkScalarToFloat(m.getScaleY())); | |
99 | |
100 const SkBitmap* bitmap = GetBitmapForScale(scale_x, scale_y); | |
101 | |
102 if (mip_map_build_pending_) { | |
103 const_cast<SkBitmap*>(bitmap)->buildMipMap(); | |
104 mip_map_build_pending_ = false; | |
105 } | |
106 | |
107 float bitmap_scale_x = static_cast<float>(bitmap->width()) / width(); | |
108 float bitmap_scale_y = static_cast<float>(bitmap->height()) / height(); | |
109 | |
110 canvas->Save(); | |
111 canvas->sk_canvas()->scale(1.0f / bitmap_scale_x, | |
112 1.0f / bitmap_scale_y); | |
113 canvas->DrawBitmapFloat(*bitmap, | |
114 src_x * bitmap_scale_x, src_y * bitmap_scale_x, | |
115 src_w * bitmap_scale_x, src_h * bitmap_scale_y, | |
116 dest_x * bitmap_scale_x, dest_y * bitmap_scale_y, | |
117 dest_w * bitmap_scale_x, dest_h * bitmap_scale_y, | |
118 filter, paint); | |
119 | |
120 canvas->Restore(); | |
121 } | |
122 | |
123 const SkBitmap* ImageSkia::GetBitmapForScale(float x_scale_factor, | |
124 float y_scale_factor) const { | |
125 // Get the desired bitmap width and height given |x_scale_factor|, | |
126 // |y_scale_factor| and |size_| at 1x density. | |
127 float desired_width = size_.width() * x_scale_factor; | |
128 float desired_height = size_.height() * y_scale_factor; | |
129 | |
130 size_t closest_index = 0; | 120 size_t closest_index = 0; |
131 float smallest_diff = std::numeric_limits<float>::max(); | 121 float smallest_diff = std::numeric_limits<float>::max(); |
132 for (size_t i = 0; i < bitmaps_.size(); ++i) { | 122 for (size_t i = 0; i < bitmaps.size(); ++i) { |
133 if (bitmaps_[i]->isNull()) | 123 float diff = std::abs(bitmaps[i].width() - desired_width) + |
134 continue; | 124 std::abs(bitmaps[i].height() - desired_height); |
135 | |
136 float diff = std::abs(bitmaps_[i]->width() - desired_width) + | |
137 std::abs(bitmaps_[i]->height() - desired_height); | |
138 if (diff < smallest_diff) { | 125 if (diff < smallest_diff) { |
139 closest_index = i; | 126 closest_index = i; |
140 smallest_diff = diff; | 127 smallest_diff = diff; |
141 } | 128 } |
142 } | 129 } |
143 return bitmaps_[closest_index]; | 130 if (smallest_diff < std::numeric_limits<float>::max()) { |
| 131 *bitmap_scale_factor = static_cast<float>(bitmaps[closest_index].width()) / |
| 132 width(); |
| 133 return bitmaps[closest_index]; |
| 134 } |
| 135 |
| 136 return *null_bitmap_; |
| 137 } |
| 138 |
| 139 bool ImageSkia::empty() const { |
| 140 return isNull() || storage_->size().IsEmpty(); |
| 141 } |
| 142 |
| 143 int ImageSkia::width() const { |
| 144 return isNull() ? 0 : storage_->size().width(); |
| 145 } |
| 146 |
| 147 int ImageSkia::height() const { |
| 148 return isNull() ? 0 : storage_->size().height(); |
| 149 } |
| 150 |
| 151 bool ImageSkia::extractSubset(ImageSkia* dst, SkIRect& subset) const { |
| 152 if (isNull()) |
| 153 return false; |
| 154 SkBitmap dst_bitmap; |
| 155 bool return_value = storage_->bitmaps()[0].extractSubset(&dst_bitmap, |
| 156 subset); |
| 157 *dst = ImageSkia(dst_bitmap); |
| 158 return return_value; |
| 159 } |
| 160 |
| 161 const std::vector<SkBitmap> ImageSkia::bitmaps() const { |
| 162 return storage_->bitmaps(); |
| 163 } |
| 164 |
| 165 const SkBitmap* ImageSkia::bitmap() const { |
| 166 if (isNull()) { |
| 167 // Callers expect an SkBitmap even if it is |isNull()|. |
| 168 // TODO(pkotwicz): Fix this. |
| 169 return null_bitmap_; |
| 170 } |
| 171 |
| 172 return &storage_->bitmaps()[0]; |
| 173 } |
| 174 |
| 175 void ImageSkia::Init(const SkBitmap& bitmap) { |
| 176 Init(bitmap, 1.0f); |
| 177 } |
| 178 |
| 179 void ImageSkia::Init(const SkBitmap& bitmap, float scale_factor) { |
| 180 DCHECK_GT(scale_factor, 0.0f); |
| 181 // TODO(pkotwicz): The image should be null whenever bitmap is null. |
| 182 if (bitmap.empty() && bitmap.isNull()) { |
| 183 storage_ = NULL; |
| 184 return; |
| 185 } |
| 186 storage_ = new internal::ImageSkiaStorage(); |
| 187 storage_->set_size(gfx::Size(static_cast<int>(bitmap.width() / scale_factor), |
| 188 static_cast<int>(bitmap.height() / scale_factor))); |
| 189 storage_->AddBitmap(bitmap); |
144 } | 190 } |
145 | 191 |
146 } // namespace gfx | 192 } // namespace gfx |
OLD | NEW |