blob: c6b224742bb4a1d091c9bc18febf24994dd22f2b [file] [log] [blame]
[email protected]40a080e2011-02-11 17:42:281// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/gfx/image.h"
6
[email protected]66171ab2011-03-03 15:50:077#include <algorithm>
8
[email protected]40a080e2011-02-11 17:42:289#include "base/logging.h"
[email protected]7b9cf722011-04-27 20:50:5210#include "base/stl_util-inl.h"
[email protected]6f01e952011-02-22 17:59:4711#include "third_party/skia/include/core/SkBitmap.h"
[email protected]40a080e2011-02-11 17:42:2812
13#if defined(OS_LINUX)
14#include <gdk-pixbuf/gdk-pixbuf.h>
15#include <glib-object.h>
16#include "ui/gfx/canvas_skia.h"
17#include "ui/gfx/gtk_util.h"
18#elif defined(OS_MACOSX)
19#include "base/mac/mac_util.h"
20#include "skia/ext/skia_utils_mac.h"
21#endif
22
[email protected]40a080e2011-02-11 17:42:2823namespace gfx {
24
25namespace internal {
26
27#if defined(OS_MACOSX)
28// This is a wrapper around gfx::NSImageToSkBitmap() because this cross-platform
29// file cannot include the [square brackets] of ObjC.
[email protected]7b9cf722011-04-27 20:50:5230bool NSImageToSkBitmaps(NSImage* image, std::vector<const SkBitmap*>* bitmaps);
[email protected]40a080e2011-02-11 17:42:2831#endif
32
33#if defined(OS_LINUX)
34const SkBitmap* GdkPixbufToSkBitmap(GdkPixbuf* pixbuf) {
[email protected]06ec9a22011-02-17 17:24:0735 gfx::CanvasSkia canvas(gdk_pixbuf_get_width(pixbuf),
36 gdk_pixbuf_get_height(pixbuf),
[email protected]2a4f026f2011-03-30 14:44:3137 /*is_opaque=*/false);
[email protected]40a080e2011-02-11 17:42:2838 canvas.DrawGdkPixbuf(pixbuf, 0, 0);
39 return new SkBitmap(canvas.ExtractBitmap());
40}
41#endif
42
43class SkBitmapRep;
44class GdkPixbufRep;
45class NSImageRep;
46
47// An ImageRep is the object that holds the backing memory for an Image. Each
48// RepresentationType has an ImageRep subclass that is responsible for freeing
49// the memory that the ImageRep holds. When an ImageRep is created, it expects
50// to take ownership of the image, without having to retain it or increase its
51// reference count.
52class ImageRep {
53 public:
54 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
55
56 // Deletes the associated pixels of an ImageRep.
57 virtual ~ImageRep() {}
58
59 // Cast helpers ("fake RTTI").
60 SkBitmapRep* AsSkBitmapRep() {
61 CHECK_EQ(type_, Image::kSkBitmapRep);
62 return reinterpret_cast<SkBitmapRep*>(this);
63 }
64
65#if defined(OS_LINUX)
66 GdkPixbufRep* AsGdkPixbufRep() {
67 CHECK_EQ(type_, Image::kGdkPixbufRep);
68 return reinterpret_cast<GdkPixbufRep*>(this);
69 }
70#endif
71
72#if defined(OS_MACOSX)
73 NSImageRep* AsNSImageRep() {
74 CHECK_EQ(type_, Image::kNSImageRep);
75 return reinterpret_cast<NSImageRep*>(this);
76 }
77#endif
78
79 Image::RepresentationType type() const { return type_; }
80
81 private:
82 Image::RepresentationType type_;
83};
84
85class SkBitmapRep : public ImageRep {
86 public:
87 explicit SkBitmapRep(const SkBitmap* bitmap)
[email protected]7b9cf722011-04-27 20:50:5288 : ImageRep(Image::kSkBitmapRep) {
[email protected]954ec2e62011-04-25 13:10:3389 CHECK(bitmap);
[email protected]7b9cf722011-04-27 20:50:5290 bitmaps_.push_back(bitmap);
91 }
92
93 explicit SkBitmapRep(const std::vector<const SkBitmap*>& bitmaps)
94 : ImageRep(Image::kSkBitmapRep),
95 bitmaps_(bitmaps) {
96 CHECK(!bitmaps_.empty());
[email protected]40a080e2011-02-11 17:42:2897 }
98
99 virtual ~SkBitmapRep() {
[email protected]7b9cf722011-04-27 20:50:52100 STLDeleteElements(&bitmaps_);
[email protected]40a080e2011-02-11 17:42:28101 }
102
[email protected]7b9cf722011-04-27 20:50:52103 const SkBitmap* bitmap() const { return bitmaps_[0]; }
104
105 const std::vector<const SkBitmap*>& bitmaps() const { return bitmaps_; }
[email protected]40a080e2011-02-11 17:42:28106
107 private:
[email protected]7b9cf722011-04-27 20:50:52108 std::vector<const SkBitmap*> bitmaps_;
[email protected]40a080e2011-02-11 17:42:28109
110 DISALLOW_COPY_AND_ASSIGN(SkBitmapRep);
111};
112
113#if defined(OS_LINUX)
114class GdkPixbufRep : public ImageRep {
115 public:
116 explicit GdkPixbufRep(GdkPixbuf* pixbuf)
117 : ImageRep(Image::kGdkPixbufRep),
118 pixbuf_(pixbuf) {
119 CHECK(pixbuf);
120 }
121
122 virtual ~GdkPixbufRep() {
123 if (pixbuf_) {
124 g_object_unref(pixbuf_);
125 pixbuf_ = NULL;
126 }
127 }
128
129 GdkPixbuf* pixbuf() const { return pixbuf_; }
130
131 private:
132 GdkPixbuf* pixbuf_;
133
134 DISALLOW_COPY_AND_ASSIGN(GdkPixbufRep);
135};
136#endif
137
138#if defined(OS_MACOSX)
139class NSImageRep : public ImageRep {
140 public:
141 explicit NSImageRep(NSImage* image)
142 : ImageRep(Image::kNSImageRep),
143 image_(image) {
144 CHECK(image);
145 }
146
147 virtual ~NSImageRep() {
148 base::mac::NSObjectRelease(image_);
149 image_ = nil;
150 }
151
152 NSImage* image() const { return image_; }
153
154 private:
155 NSImage* image_;
156
157 DISALLOW_COPY_AND_ASSIGN(NSImageRep);
158};
159#endif
160
[email protected]8779d8b2011-04-22 01:08:51161// The Storage class acts similarly to the pixels in a SkBitmap: the Image
162// class holds a refptr instance of Storage, which in turn holds all the
163// ImageReps. This way, the Image can be cheaply copied.
164class ImageStorage : public base::RefCounted<ImageStorage> {
165 public:
166 ImageStorage(gfx::Image::RepresentationType default_type)
167 : default_representation_type_(default_type) {
168 }
169
170 gfx::Image::RepresentationType default_representation_type() {
171 return default_representation_type_;
172 }
173 gfx::Image::RepresentationMap& representations() { return representations_; }
174
175 private:
176 ~ImageStorage() {
177 for (gfx::Image::RepresentationMap::iterator it = representations_.begin();
178 it != representations_.end();
179 ++it) {
180 delete it->second;
181 }
182 representations_.clear();
183 }
184
185 // The type of image that was passed to the constructor. This key will always
186 // exist in the |representations_| map.
187 gfx::Image::RepresentationType default_representation_type_;
188
189 // All the representations of an Image. Size will always be at least one, with
190 // more for any converted representations.
191 gfx::Image::RepresentationMap representations_;
192
193 friend class base::RefCounted<ImageStorage>;
194};
195
[email protected]40a080e2011-02-11 17:42:28196} // namespace internal
197
198Image::Image(const SkBitmap* bitmap)
[email protected]8779d8b2011-04-22 01:08:51199 : storage_(new internal::ImageStorage(Image::kSkBitmapRep)) {
[email protected]40a080e2011-02-11 17:42:28200 internal::SkBitmapRep* rep = new internal::SkBitmapRep(bitmap);
201 AddRepresentation(rep);
202}
203
[email protected]7b9cf722011-04-27 20:50:52204Image::Image(const std::vector<const SkBitmap*>& bitmaps)
205 : storage_(new internal::ImageStorage(Image::kSkBitmapRep)) {
206 internal::SkBitmapRep* rep = new internal::SkBitmapRep(bitmaps);
207 AddRepresentation(rep);
208}
209
[email protected]40a080e2011-02-11 17:42:28210#if defined(OS_LINUX)
211Image::Image(GdkPixbuf* pixbuf)
[email protected]8779d8b2011-04-22 01:08:51212 : storage_(new internal::ImageStorage(Image::kGdkPixbufRep)) {
[email protected]40a080e2011-02-11 17:42:28213 internal::GdkPixbufRep* rep = new internal::GdkPixbufRep(pixbuf);
214 AddRepresentation(rep);
215}
216#endif
217
218#if defined(OS_MACOSX)
[email protected]8779d8b2011-04-22 01:08:51219Image::Image(NSImage* image)
220 : storage_(new internal::ImageStorage(Image::kNSImageRep)) {
[email protected]40a080e2011-02-11 17:42:28221 internal::NSImageRep* rep = new internal::NSImageRep(image);
222 AddRepresentation(rep);
223}
224#endif
225
[email protected]8779d8b2011-04-22 01:08:51226Image::Image(const Image& other) : storage_(other.storage_) {
227}
228
229Image& Image::operator=(const Image& other) {
230 storage_ = other.storage_;
231 return *this;
232}
233
[email protected]40a080e2011-02-11 17:42:28234Image::~Image() {
[email protected]40a080e2011-02-11 17:42:28235}
236
[email protected]15a20842011-05-04 01:29:28237Image::operator const SkBitmap*() const {
[email protected]40a080e2011-02-11 17:42:28238 internal::ImageRep* rep = GetRepresentation(Image::kSkBitmapRep);
239 return rep->AsSkBitmapRep()->bitmap();
240}
241
[email protected]15a20842011-05-04 01:29:28242Image::operator const SkBitmap&() const {
[email protected]40a080e2011-02-11 17:42:28243 return *(this->operator const SkBitmap*());
244}
245
246#if defined(OS_LINUX)
[email protected]15a20842011-05-04 01:29:28247Image::operator GdkPixbuf*() const {
[email protected]40a080e2011-02-11 17:42:28248 internal::ImageRep* rep = GetRepresentation(Image::kGdkPixbufRep);
249 return rep->AsGdkPixbufRep()->pixbuf();
250}
251#endif
252
253#if defined(OS_MACOSX)
[email protected]15a20842011-05-04 01:29:28254Image::operator NSImage*() const {
[email protected]40a080e2011-02-11 17:42:28255 internal::ImageRep* rep = GetRepresentation(Image::kNSImageRep);
256 return rep->AsNSImageRep()->image();
257}
258#endif
259
[email protected]15a20842011-05-04 01:29:28260bool Image::HasRepresentation(RepresentationType type) const {
[email protected]8779d8b2011-04-22 01:08:51261 return storage_->representations().count(type) != 0;
262}
263
[email protected]15a20842011-05-04 01:29:28264size_t Image::RepresentationCount() const {
[email protected]8779d8b2011-04-22 01:08:51265 return storage_->representations().size();
[email protected]c41b06f2011-02-24 15:53:26266}
267
[email protected]66171ab2011-03-03 15:50:07268void Image::SwapRepresentations(gfx::Image* other) {
[email protected]8779d8b2011-04-22 01:08:51269 storage_.swap(other->storage_);
[email protected]66171ab2011-03-03 15:50:07270}
271
[email protected]15a20842011-05-04 01:29:28272internal::ImageRep* Image::DefaultRepresentation() const {
[email protected]8779d8b2011-04-22 01:08:51273 RepresentationMap& representations = storage_->representations();
[email protected]40a080e2011-02-11 17:42:28274 RepresentationMap::iterator it =
[email protected]8779d8b2011-04-22 01:08:51275 representations.find(storage_->default_representation_type());
276 DCHECK(it != representations.end());
[email protected]40a080e2011-02-11 17:42:28277 return it->second;
278}
279
[email protected]15a20842011-05-04 01:29:28280internal::ImageRep* Image::GetRepresentation(
281 RepresentationType rep_type) const {
[email protected]40a080e2011-02-11 17:42:28282 // If the requested rep is the default, return it.
283 internal::ImageRep* default_rep = DefaultRepresentation();
[email protected]8779d8b2011-04-22 01:08:51284 if (rep_type == storage_->default_representation_type())
[email protected]40a080e2011-02-11 17:42:28285 return default_rep;
286
287 // Check to see if the representation already exists.
[email protected]8779d8b2011-04-22 01:08:51288 RepresentationMap::iterator it = storage_->representations().find(rep_type);
289 if (it != storage_->representations().end())
[email protected]40a080e2011-02-11 17:42:28290 return it->second;
291
292 // At this point, the requested rep does not exist, so it must be converted
293 // from the default rep.
294
295 // Handle native-to-Skia conversion.
296 if (rep_type == Image::kSkBitmapRep) {
297 internal::SkBitmapRep* rep = NULL;
298#if defined(OS_LINUX)
[email protected]8779d8b2011-04-22 01:08:51299 if (storage_->default_representation_type() == Image::kGdkPixbufRep) {
[email protected]40a080e2011-02-11 17:42:28300 internal::GdkPixbufRep* pixbuf_rep = default_rep->AsGdkPixbufRep();
301 rep = new internal::SkBitmapRep(
302 internal::GdkPixbufToSkBitmap(pixbuf_rep->pixbuf()));
303 }
304#elif defined(OS_MACOSX)
[email protected]8779d8b2011-04-22 01:08:51305 if (storage_->default_representation_type() == Image::kNSImageRep) {
[email protected]40a080e2011-02-11 17:42:28306 internal::NSImageRep* nsimage_rep = default_rep->AsNSImageRep();
[email protected]7b9cf722011-04-27 20:50:52307 std::vector<const SkBitmap*> bitmaps;
308 CHECK(internal::NSImageToSkBitmaps(nsimage_rep->image(), &bitmaps));
309 rep = new internal::SkBitmapRep(bitmaps);
[email protected]40a080e2011-02-11 17:42:28310 }
311#endif
[email protected]2a4f026f2011-03-30 14:44:31312 CHECK(rep);
313 AddRepresentation(rep);
314 return rep;
[email protected]40a080e2011-02-11 17:42:28315 }
316
317 // Handle Skia-to-native conversions.
318 if (default_rep->type() == Image::kSkBitmapRep) {
319 internal::SkBitmapRep* skia_rep = default_rep->AsSkBitmapRep();
320 internal::ImageRep* native_rep = NULL;
321#if defined(OS_LINUX)
322 if (rep_type == Image::kGdkPixbufRep) {
[email protected]06ec9a22011-02-17 17:24:07323 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(skia_rep->bitmap());
[email protected]40a080e2011-02-11 17:42:28324 native_rep = new internal::GdkPixbufRep(pixbuf);
325 }
326#elif defined(OS_MACOSX)
327 if (rep_type == Image::kNSImageRep) {
[email protected]7b9cf722011-04-27 20:50:52328 NSImage* image = gfx::SkBitmapsToNSImage(skia_rep->bitmaps());
[email protected]40a080e2011-02-11 17:42:28329 base::mac::NSObjectRetain(image);
330 native_rep = new internal::NSImageRep(image);
331 }
332#endif
[email protected]2a4f026f2011-03-30 14:44:31333 CHECK(native_rep);
334 AddRepresentation(native_rep);
335 return native_rep;
[email protected]40a080e2011-02-11 17:42:28336 }
337
338 // Something went seriously wrong...
339 return NULL;
340}
341
[email protected]15a20842011-05-04 01:29:28342void Image::AddRepresentation(internal::ImageRep* rep) const {
[email protected]8779d8b2011-04-22 01:08:51343 storage_->representations().insert(std::make_pair(rep->type(), rep));
[email protected]40a080e2011-02-11 17:42:28344}
345
[email protected]15a20842011-05-04 01:29:28346size_t Image::GetNumberOfSkBitmaps() const {
[email protected]7b9cf722011-04-27 20:50:52347 return GetRepresentation(Image::kSkBitmapRep)->AsSkBitmapRep()->
348 bitmaps().size();
349}
350
[email protected]15a20842011-05-04 01:29:28351const SkBitmap* Image::GetSkBitmapAtIndex(size_t index) const {
[email protected]7b9cf722011-04-27 20:50:52352 return GetRepresentation(Image::kSkBitmapRep)->AsSkBitmapRep()->
353 bitmaps()[index];
354}
355
[email protected]40a080e2011-02-11 17:42:28356} // namespace gfx