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 "ui/gfx/size.h" | |
11 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
12 | 13 |
13 namespace gfx { | 14 namespace gfx { |
14 | 15 |
16 namespace internal { | |
17 | |
18 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a | |
19 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's | |
20 // information. | |
21 class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { | |
22 public: | |
23 ImageSkiaStorage() : build_mip_map_(false) { | |
24 } | |
25 | |
26 void add_bitmap(const SkBitmap* bitmap) { bitmaps_.push_back(bitmap); } | |
27 void set_bitmaps(const std::vector<const SkBitmap*>& bitmaps) { | |
28 bitmaps_ = bitmaps; | |
29 } | |
30 const std::vector<const SkBitmap*>& bitmaps() const { return bitmaps_; } | |
31 | |
32 void set_size(gfx::Size size) { size_ = size; } | |
33 gfx::Size size() const { return size_; } | |
34 | |
35 void set_build_mip_map() { build_mip_map_ = true; } | |
36 bool build_mip_map() const { return build_mip_map_; } | |
37 | |
38 private: | |
39 ~ImageSkiaStorage() { | |
40 STLDeleteElements(&bitmaps_); | |
41 } | |
42 | |
43 std::vector<const SkBitmap*> bitmaps_; | |
sky
2012/04/27 23:33:58
Why does this need to be pointers? It would be a l
pkotwicz
2012/04/30 20:27:07
I think this needs to be pointers as long as we ha
sky
2012/04/30 21:03:32
Is the long term plan to get rid of ToSkBitmap? If
| |
44 gfx::Size size_; | |
sky
2012/04/27 23:33:58
Document what this is.
| |
45 bool build_mip_map_; | |
sky
2012/04/27 23:33:58
Shouldn't the mip-map be per-image?
| |
46 | |
47 friend class base::RefCounted<ImageSkiaStorage>; | |
48 }; | |
49 | |
50 } // internal | |
51 | |
52 ImageSkia::ImageSkia() : storage_(NULL) { | |
53 } | |
54 | |
55 ImageSkia::ImageSkia(const SkBitmap& bitmap) | |
56 : storage_(new internal::ImageSkiaStorage()) { | |
57 storage_->set_size(gfx::Size(bitmap.width(), bitmap.height())); | |
58 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap.isNull() | |
59 storage_->add_bitmap(new SkBitmap(bitmap)); | |
60 } | |
61 | |
62 ImageSkia::ImageSkia(const SkBitmap& bitmap, float scale_factor) | |
63 : storage_(new internal::ImageSkiaStorage()) { | |
64 storage_->set_size(gfx::Size( | |
65 static_cast<int>(bitmap.width() / scale_factor), | |
66 static_cast<int>(bitmap.height() / scale_factor))); | |
67 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap.isNull() | |
68 storage_->add_bitmap(new SkBitmap(bitmap)); | |
69 } | |
70 | |
15 ImageSkia::ImageSkia(const SkBitmap* bitmap) | 71 ImageSkia::ImageSkia(const SkBitmap* bitmap) |
16 : size_(bitmap->width(), bitmap->height()), | 72 : storage_(new internal::ImageSkiaStorage()) { |
17 mip_map_build_pending_(false) { | 73 storage_->set_size(gfx::Size(bitmap->width(), bitmap->height())); |
18 CHECK(bitmap); | 74 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap.isNull() |
19 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() | 75 storage_->add_bitmap(bitmap); |
20 bitmaps_.push_back(bitmap); | |
21 } | 76 } |
22 | 77 |
23 ImageSkia::ImageSkia(const std::vector<const SkBitmap*>& bitmaps) | 78 ImageSkia::ImageSkia(const std::vector<const SkBitmap*>& bitmaps) |
24 : bitmaps_(bitmaps), | 79 : storage_(new internal::ImageSkiaStorage()) { |
25 mip_map_build_pending_(false) { | 80 storage_->set_bitmaps(bitmaps); |
26 CHECK(!bitmaps_.empty()); | |
27 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() for each | 81 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() for each |
28 // vector element. | 82 // vector element. |
29 // Assume that the smallest bitmap represents 1x scale factor. | 83 // Assume that the smallest bitmap represents 1x scale factor. |
30 for (size_t i = 0; i < bitmaps_.size(); ++i) { | 84 gfx::Size smallest_bitmap_size; |
31 gfx::Size bitmap_size(bitmaps_[i]->width(), bitmaps_[i]->height()); | 85 for (size_t i = 0; i < bitmaps.size(); ++i) { |
32 if (size_.IsEmpty() || bitmap_size.GetArea() < size_.GetArea()) | 86 gfx::Size bitmap_size(bitmaps[i]->width(), bitmaps[i]->height()); |
33 size_ = bitmap_size; | 87 if (smallest_bitmap_size.IsEmpty() || |
88 bitmap_size.GetArea() < smallest_bitmap_size.GetArea()) | |
89 smallest_bitmap_size = bitmap_size; | |
34 } | 90 } |
91 storage_->set_size(smallest_bitmap_size); | |
92 } | |
93 | |
94 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { | |
95 } | |
96 | |
97 ImageSkia& ImageSkia::operator=(const ImageSkia& other) { | |
98 storage_ = other.storage_; | |
99 return *this; | |
100 } | |
101 | |
102 ImageSkia& ImageSkia::operator=(const SkBitmap& other) { | |
103 storage_ = new internal::ImageSkiaStorage(); | |
104 storage_->set_size(gfx::Size(other.width(), other.height())); | |
105 // TODO(pkotwicz): Add a CHECK to ensure that !other.isNull() | |
106 storage_->add_bitmap(new SkBitmap(other)); | |
107 return *this; | |
108 } | |
109 | |
110 ImageSkia::operator SkBitmap() const { | |
111 return isNull() ? SkBitmap() : *bitmaps()[0]; | |
35 } | 112 } |
36 | 113 |
37 ImageSkia::~ImageSkia() { | 114 ImageSkia::~ImageSkia() { |
38 STLDeleteElements(&bitmaps_); | |
39 } | |
40 | |
41 void ImageSkia::BuildMipMap() { | |
42 mip_map_build_pending_ = true; | |
43 } | |
44 | |
45 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, int x, int y) { | |
46 SkPaint p; | |
47 DrawToCanvasInt(canvas, x, y, p); | |
48 } | |
49 | |
50 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, | |
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 } | 115 } |
122 | 116 |
123 const SkBitmap* ImageSkia::GetBitmapForScale(float x_scale_factor, | 117 const SkBitmap* ImageSkia::GetBitmapForScale(float x_scale_factor, |
124 float y_scale_factor) const { | 118 float y_scale_factor) const { |
119 if (isNull()) | |
120 return NULL; | |
121 | |
125 // Get the desired bitmap width and height given |x_scale_factor|, | 122 // Get the desired bitmap width and height given |x_scale_factor|, |
126 // |y_scale_factor| and |size_| at 1x density. | 123 // |y_scale_factor| and size at 1x density. |
127 float desired_width = size_.width() * x_scale_factor; | 124 float desired_width = width() * x_scale_factor; |
128 float desired_height = size_.height() * y_scale_factor; | 125 float desired_height = height() * y_scale_factor; |
129 | 126 |
130 size_t closest_index = 0; | 127 const std::vector<const SkBitmap*>& bitmaps = storage_->bitmaps(); |
128 size_t closest_index = -1; | |
131 float smallest_diff = std::numeric_limits<float>::max(); | 129 float smallest_diff = std::numeric_limits<float>::max(); |
132 for (size_t i = 0; i < bitmaps_.size(); ++i) { | 130 for (size_t i = 0; i < bitmaps.size(); ++i) { |
133 if (bitmaps_[i]->isNull()) | 131 if (bitmaps[i]->isNull()) |
sky
2012/04/27 23:33:58
Is there a reason to allow null/empty images into
pkotwicz
2012/04/30 20:27:07
Changed semantics such that if bitmap->isNull(), t
| |
134 continue; | 132 continue; |
135 | 133 |
136 float diff = std::abs(bitmaps_[i]->width() - desired_width) + | 134 float diff = std::abs(bitmaps[i]->width() - desired_width) + |
137 std::abs(bitmaps_[i]->height() - desired_height); | 135 std::abs(bitmaps[i]->height() - desired_height); |
138 if (diff < smallest_diff) { | 136 if (diff < smallest_diff) { |
139 closest_index = i; | 137 closest_index = i; |
140 smallest_diff = diff; | 138 smallest_diff = diff; |
141 } | 139 } |
142 } | 140 } |
143 return bitmaps_[closest_index]; | 141 return closest_index < 0 ? NULL : bitmaps[closest_index]; |
142 } | |
143 | |
144 bool ImageSkia::empty() const { | |
145 return isNull() || storage_->size().IsEmpty(); | |
146 } | |
147 | |
148 int ImageSkia::width() const { | |
149 return isNull() ? 0 : storage_->size().width(); | |
150 } | |
151 | |
152 int ImageSkia::height() const { | |
153 return isNull() ? 0 : storage_->size().height(); | |
154 } | |
155 | |
156 bool ImageSkia::extractSubset(ImageSkia* dst, SkIRect& subset) const { | |
157 if (isNull()) | |
158 return false; | |
159 SkBitmap dst_bitmap; | |
160 bool return_value = bitmaps()[0]->extractSubset(&dst_bitmap, subset); | |
161 *dst = ImageSkia(dst_bitmap); | |
162 return return_value; | |
163 } | |
164 | |
165 void ImageSkia::BuildMipMap() { | |
166 if (isNull()) | |
167 return; | |
168 | |
169 storage_->set_build_mip_map(); | |
170 // |build_mip_map_| does not need to be turned off as SkBitmap will not | |
171 // regenerate a mipmap if one exists. | |
172 } | |
173 | |
174 bool ImageSkia::ShouldBuildMipMap() const { | |
175 return storage_->build_mip_map(); | |
176 } | |
177 | |
178 const std::vector<const SkBitmap*>& ImageSkia::bitmaps() const { | |
179 return storage_->bitmaps(); | |
144 } | 180 } |
145 | 181 |
146 } // namespace gfx | 182 } // namespace gfx |
OLD | NEW |