Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(352)

Side by Side Diff: ui/gfx/image/image_skia.cc

Issue 10245003: Makes ImageSkia more like SkBitmap (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Nicer diff Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 #include "base/message_loop.h"
13 #include "third_party/skia/include/core/SkPixelRef.h"
12 14
13 namespace gfx { 15 namespace gfx {
14 16
15 ImageSkia::ImageSkia(const SkBitmap* bitmap) 17 namespace internal {
16 : size_(bitmap->width(), bitmap->height()), 18
17 mip_map_build_pending_(false) { 19 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a
18 CHECK(bitmap); 20 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's
19 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() 21 // information.
20 bitmaps_.push_back(bitmap); 22 class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> {
23 public:
24 ImageSkiaStorage() {
25 }
26
27 void add_bitmap(const SkBitmap& bitmap) {
Robert Sesek 2012/05/05 02:08:34 naming: AddBitmap
pkotwicz 2012/05/08 22:10:14 Done.
28 bitmaps_.push_back(bitmap);
29 }
30
31 const std::vector<SkBitmap>& bitmaps() const { return bitmaps_; }
32
33 void set_size(const gfx::Size& size) { size_ = size; }
34 const gfx::Size& size() const { return size_; }
35
36 private:
37 ~ImageSkiaStorage() {
38 }
39
40 // Bitmaps at different densities.
41 std::vector<SkBitmap> bitmaps_;
42
43 // Size of the image in DIP.
44 gfx::Size size_;
45
46 friend class base::RefCounted<ImageSkiaStorage>;
47 };
48
49 } // internal
50
51 ImageSkia::ImageSkia() : storage_(NULL) {
21 } 52 }
22 53
23 ImageSkia::ImageSkia(const std::vector<const SkBitmap*>& bitmaps) 54 ImageSkia::ImageSkia(const SkBitmap& bitmap) {
24 : bitmaps_(bitmaps), 55 Init(bitmap);
25 mip_map_build_pending_(false) { 56 }
26 CHECK(!bitmaps_.empty()); 57
27 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() for each 58 ImageSkia::ImageSkia(const SkBitmap& bitmap, float dip_scale_factor) {
28 // vector element. 59 Init(bitmap, dip_scale_factor);
29 // Assume that the smallest bitmap represents 1x scale factor. 60 }
30 for (size_t i = 0; i < bitmaps_.size(); ++i) { 61
31 gfx::Size bitmap_size(bitmaps_[i]->width(), bitmaps_[i]->height()); 62 ImageSkia::ImageSkia(const SkBitmap* bitmap) {
32 if (size_.IsEmpty() || bitmap_size.GetArea() < size_.GetArea()) 63 Init(*bitmap);
33 size_ = bitmap_size; 64
65 if (MessageLoop::current()) {
66 // Use DeleteSoon such that |bitmap| is still valid if caller uses |bitmap|
67 // immediately after having called constructor.
68 MessageLoop::current()->DeleteSoon(FROM_HERE, bitmap);
69 } else {
70 // Hit in unittests.
Robert Sesek 2012/05/05 02:08:34 It's generally not a good thing to have different
pkotwicz 2012/05/08 22:10:14 Will keep this given this constructor is going awa
71 delete bitmap;
34 } 72 }
35 } 73 }
36 74
37 ImageSkia::~ImageSkia() { 75 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) {
38 STLDeleteElements(&bitmaps_);
39 } 76 }
40 77
41 void ImageSkia::BuildMipMap() { 78 ImageSkia& ImageSkia::operator=(const ImageSkia& other) {
42 mip_map_build_pending_ = true; 79 storage_ = other.storage_;
80 return *this;
43 } 81 }
44 82
45 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, int x, int y) { 83 ImageSkia& ImageSkia::operator=(const SkBitmap& other) {
46 SkPaint p; 84 Init(other);
47 DrawToCanvasInt(canvas, x, y, p); 85 return *this;
48 } 86 }
49 87
50 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, 88 ImageSkia::operator SkBitmap&() const {
51 int x, int y, 89 if (isNull()) {
52 const SkPaint& paint) { 90 // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is
53 91 // done.
54 if (IsZeroSized()) 92 // Static null bitmap such that we are not returning a temporary.
55 return; 93 static SkBitmap* null_bitmap = new SkBitmap();
56 94 return *null_bitmap;
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 } 95 }
67 96
68 float bitmap_scale_x = static_cast<float>(bitmap->width()) / width(); 97 std::vector<SkBitmap>& v = const_cast<std::vector<SkBitmap>&>(bitmaps());
Robert Sesek 2012/05/05 02:08:34 Why do you need to const_cast the vector? Can't yo
pkotwicz 2012/05/08 22:10:14 Done.
69 float bitmap_scale_y = static_cast<float>(bitmap->height()) / height(); 98 return v[0];
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 } 99 }
78 100
79 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, 101 ImageSkia::~ImageSkia() {
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 } 102 }
87 103
88 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, 104 void ImageSkia::AddBitmapForScale(const SkBitmap& bitmap,
89 int src_x, int src_y, int src_w, int src_h, 105 float dip_scale_factor) {
90 int dest_x, int dest_y, int dest_w, int dest_h, 106 DCHECK(!bitmap.isNull());
91 bool filter,
92 const SkPaint& paint) {
93 if (IsZeroSized())
94 return;
95 107
96 SkMatrix m = canvas->sk_canvas()->getTotalMatrix(); 108 if (isNull()) {
97 float scale_x = std::abs(SkScalarToFloat(m.getScaleX())); 109 Init(bitmap, dip_scale_factor);
98 float scale_y = std::abs(SkScalarToFloat(m.getScaleY())); 110 } else {
99 111 // We currently assume that the bitmap size = 1x size * |dip_scale_factor|.
100 const SkBitmap* bitmap = GetBitmapForScale(scale_x, scale_y); 112 // TODO(pkotwicz): Do something better because of rounding errors when
101 113 // |dip_scale_factor| is not an int.
102 if (mip_map_build_pending_) { 114 DCHECK_EQ(static_cast<int>(width() * dip_scale_factor), bitmap.width());
103 const_cast<SkBitmap*>(bitmap)->buildMipMap(); 115 DCHECK_EQ(static_cast<int>(height() * dip_scale_factor), bitmap.height());
104 mip_map_build_pending_ = false; 116 storage_->add_bitmap(bitmap);
105 } 117 }
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 } 118 }
122 119
123 const SkBitmap* ImageSkia::GetBitmapForScale(float x_scale_factor, 120 const SkBitmap& ImageSkia::GetBitmapForScale(float x_scale_factor,
124 float y_scale_factor) const { 121 float y_scale_factor,
122 float* bitmap_scale_factor) const {
123
124 // Static null bitmap such that we are not returning a temporary.
125 static SkBitmap* null_bitmap = new SkBitmap();
126
127 if (empty())
128 return *null_bitmap;
129
125 // Get the desired bitmap width and height given |x_scale_factor|, 130 // Get the desired bitmap width and height given |x_scale_factor|,
126 // |y_scale_factor| and |size_| at 1x density. 131 // |y_scale_factor| and size at 1x density.
127 float desired_width = size_.width() * x_scale_factor; 132 float desired_width = width() * x_scale_factor;
128 float desired_height = size_.height() * y_scale_factor; 133 float desired_height = height() * y_scale_factor;
129 134
135 const std::vector<SkBitmap>& bitmaps = storage_->bitmaps();
130 size_t closest_index = 0; 136 size_t closest_index = 0;
131 float smallest_diff = std::numeric_limits<float>::max(); 137 float smallest_diff = std::numeric_limits<float>::max();
132 for (size_t i = 0; i < bitmaps_.size(); ++i) { 138 for (size_t i = 0; i < bitmaps.size(); ++i) {
133 if (bitmaps_[i]->isNull()) 139 float diff = std::abs(bitmaps[i].width() - desired_width) +
134 continue; 140 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) { 141 if (diff < smallest_diff) {
139 closest_index = i; 142 closest_index = i;
140 smallest_diff = diff; 143 smallest_diff = diff;
141 } 144 }
142 } 145 }
143 return bitmaps_[closest_index]; 146 if (smallest_diff < std::numeric_limits<float>::max()) {
147 *bitmap_scale_factor = bitmaps[closest_index].width() / width();
148 return bitmaps[closest_index];
149 }
150
151 return *null_bitmap;
152 }
153
154 bool ImageSkia::empty() const {
155 return isNull() || storage_->size().IsEmpty();
156 }
157
158 int ImageSkia::width() const {
159 return isNull() ? 0 : storage_->size().width();
160 }
161
162 int ImageSkia::height() const {
163 return isNull() ? 0 : storage_->size().height();
164 }
165
166 bool ImageSkia::extractSubset(ImageSkia* dst, SkIRect& subset) const {
167 if (isNull())
168 return false;
169 SkBitmap dst_bitmap;
170 bool return_value = bitmaps()[0].extractSubset(&dst_bitmap, subset);
171 *dst = ImageSkia(dst_bitmap);
172 return return_value;
173 }
174
175 const std::vector<SkBitmap>& ImageSkia::bitmaps() const {
176 return storage_->bitmaps();
177 }
178
179 void ImageSkia::Init(const SkBitmap& bitmap) {
180 Init(bitmap, 1.0f);
181 }
182
183 void ImageSkia::Init(const SkBitmap& bitmap, float scale_factor) {
184 DCHECK(scale_factor > 0.0f);
Robert Sesek 2012/05/05 02:08:34 DCHECK_GT
pkotwicz 2012/05/08 22:10:14 Done.
185 if (bitmap.isNull()) {
186 storage_ = NULL;
187 return;
188 }
189 storage_ = new internal::ImageSkiaStorage();
190 storage_->set_size(gfx::Size(static_cast<int>(bitmap.width() / scale_factor),
191 static_cast<int>(bitmap.height() / scale_factor)));
192 storage_->add_bitmap(bitmap);
144 } 193 }
145 194
146 } // namespace gfx 195 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698