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.h" | 5 #include "ui/gfx/image/image.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
11 #include "third_party/skia/include/core/SkBitmap.h" | 11 #include "third_party/skia/include/core/SkBitmap.h" |
| 12 #include "ui/gfx/codec/png_codec.h" |
| 13 #include "ui/gfx/image/image_png.h" |
12 #include "ui/gfx/image/image_skia.h" | 14 #include "ui/gfx/image/image_skia.h" |
13 #include "ui/gfx/size.h" | 15 #include "ui/gfx/size.h" |
14 | 16 |
15 #if defined(TOOLKIT_GTK) | 17 #if defined(TOOLKIT_GTK) |
16 #include <gdk-pixbuf/gdk-pixbuf.h> | 18 #include <gdk-pixbuf/gdk-pixbuf.h> |
17 #include <gdk/gdk.h> | 19 #include <gdk/gdk.h> |
18 #include <glib-object.h> | 20 #include <glib-object.h> |
19 #include "ui/gfx/canvas.h" | 21 #include "ui/gfx/canvas.h" |
20 #include "ui/gfx/gtk_util.h" | 22 #include "ui/gfx/gtk_util.h" |
21 #include "ui/gfx/image/cairo_cached_surface.h" | 23 #include "ui/gfx/image/cairo_cached_surface.h" |
(...skipping 12 matching lines...) Expand all Loading... |
34 gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf), | 36 gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf), |
35 gdk_pixbuf_get_height(pixbuf)), false); | 37 gdk_pixbuf_get_height(pixbuf)), false); |
36 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas()); | 38 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas()); |
37 cairo_t* cr = scoped_platform_paint.GetPlatformSurface(); | 39 cairo_t* cr = scoped_platform_paint.GetPlatformSurface(); |
38 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); | 40 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); |
39 cairo_paint(cr); | 41 cairo_paint(cr); |
40 return ImageSkia(SkBitmap(canvas.ExtractBitmap())); | 42 return ImageSkia(SkBitmap(canvas.ExtractBitmap())); |
41 } | 43 } |
42 #endif | 44 #endif |
43 | 45 |
| 46 const ImageSkia ImageSkiaFromImagePNG(const ImagePNG& png) { |
| 47 SkBitmap bitmap; |
| 48 if (!gfx::PNGCodec::Decode(&png.Image().front(), png.Image().size(), &bitmap)) |
| 49 LOG(WARNING) << "Unable to decode PNG, returning empty bitmap"; |
| 50 return ImageSkia(bitmap); |
| 51 } |
| 52 |
| 53 class ImageRepPNG; |
44 class ImageRepSkia; | 54 class ImageRepSkia; |
45 class ImageRepGdk; | 55 class ImageRepGdk; |
46 class ImageRepCairo; | 56 class ImageRepCairo; |
47 class ImageRepCocoa; | 57 class ImageRepCocoa; |
48 | 58 |
49 // An ImageRep is the object that holds the backing memory for an Image. Each | 59 // An ImageRep is the object that holds the backing memory for an Image. Each |
50 // RepresentationType has an ImageRep subclass that is responsible for freeing | 60 // RepresentationType has an ImageRep subclass that is responsible for freeing |
51 // the memory that the ImageRep holds. When an ImageRep is created, it expects | 61 // the memory that the ImageRep holds. When an ImageRep is created, it expects |
52 // to take ownership of the image, without having to retain it or increase its | 62 // to take ownership of the image, without having to retain it or increase its |
53 // reference count. | 63 // reference count. |
54 class ImageRep { | 64 class ImageRep { |
55 public: | 65 public: |
56 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {} | 66 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {} |
57 | 67 |
58 // Deletes the associated pixels of an ImageRep. | 68 // Deletes the associated pixels of an ImageRep. |
59 virtual ~ImageRep() {} | 69 virtual ~ImageRep() {} |
60 | 70 |
61 // Cast helpers ("fake RTTI"). | 71 // Cast helpers ("fake RTTI"). |
| 72 ImageRepPNG* AsImageRepPNG() { |
| 73 CHECK_EQ(type_, Image::kImageRepPNG); |
| 74 return reinterpret_cast<ImageRepPNG*>(this); |
| 75 } |
| 76 |
62 ImageRepSkia* AsImageRepSkia() { | 77 ImageRepSkia* AsImageRepSkia() { |
63 CHECK_EQ(type_, Image::kImageRepSkia); | 78 CHECK_EQ(type_, Image::kImageRepSkia); |
64 return reinterpret_cast<ImageRepSkia*>(this); | 79 return reinterpret_cast<ImageRepSkia*>(this); |
65 } | 80 } |
66 | 81 |
67 #if defined(TOOLKIT_GTK) | 82 #if defined(TOOLKIT_GTK) |
68 ImageRepGdk* AsImageRepGdk() { | 83 ImageRepGdk* AsImageRepGdk() { |
69 CHECK_EQ(type_, Image::kImageRepGdk); | 84 CHECK_EQ(type_, Image::kImageRepGdk); |
70 return reinterpret_cast<ImageRepGdk*>(this); | 85 return reinterpret_cast<ImageRepGdk*>(this); |
71 } | 86 } |
(...skipping 10 matching lines...) Expand all Loading... |
82 return reinterpret_cast<ImageRepCocoa*>(this); | 97 return reinterpret_cast<ImageRepCocoa*>(this); |
83 } | 98 } |
84 #endif | 99 #endif |
85 | 100 |
86 Image::RepresentationType type() const { return type_; } | 101 Image::RepresentationType type() const { return type_; } |
87 | 102 |
88 private: | 103 private: |
89 Image::RepresentationType type_; | 104 Image::RepresentationType type_; |
90 }; | 105 }; |
91 | 106 |
| 107 class ImageRepPNG : public ImageRep { |
| 108 public: |
| 109 explicit ImageRepPNG(const ImagePNG& png) |
| 110 : ImageRep(Image::kImageRepPNG), |
| 111 image_(png) { |
| 112 } |
| 113 |
| 114 virtual ~ImageRepPNG() { |
| 115 } |
| 116 |
| 117 const ImagePNG& image() const { return image_; } |
| 118 |
| 119 private: |
| 120 ImagePNG image_; |
| 121 |
| 122 DISALLOW_COPY_AND_ASSIGN(ImageRepPNG); |
| 123 }; |
| 124 |
92 class ImageRepSkia : public ImageRep { | 125 class ImageRepSkia : public ImageRep { |
93 public: | 126 public: |
94 // Takes ownership of |image|. | 127 // Takes ownership of |image|. |
95 explicit ImageRepSkia(ImageSkia* image) | 128 explicit ImageRepSkia(ImageSkia* image) |
96 : ImageRep(Image::kImageRepSkia), | 129 : ImageRep(Image::kImageRepSkia), |
97 image_(image) { | 130 image_(image) { |
98 } | 131 } |
99 | 132 |
100 virtual ~ImageRepSkia() { | 133 virtual ~ImageRepSkia() { |
101 } | 134 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 | 245 |
213 friend class base::RefCounted<ImageStorage>; | 246 friend class base::RefCounted<ImageStorage>; |
214 }; | 247 }; |
215 | 248 |
216 } // namespace internal | 249 } // namespace internal |
217 | 250 |
218 Image::Image() { | 251 Image::Image() { |
219 // |storage_| is NULL for empty Images. | 252 // |storage_| is NULL for empty Images. |
220 } | 253 } |
221 | 254 |
| 255 Image::Image(const ImagePNG& image) |
| 256 : storage_(new internal::ImageStorage(Image::kImageRepPNG)) { |
| 257 internal::ImageRepPNG* rep = new internal::ImageRepPNG(image); |
| 258 AddRepresentation(rep); |
| 259 } |
| 260 |
222 Image::Image(const ImageSkia& image) | 261 Image::Image(const ImageSkia& image) |
223 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { | 262 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { |
224 internal::ImageRepSkia* rep = new internal::ImageRepSkia( | 263 internal::ImageRepSkia* rep = new internal::ImageRepSkia( |
225 new ImageSkia(image)); | 264 new ImageSkia(image)); |
226 AddRepresentation(rep); | 265 AddRepresentation(rep); |
227 } | 266 } |
228 | 267 |
229 Image::Image(const ImageSkiaRep& image_skia_rep) | 268 Image::Image(const ImageSkiaRep& image_skia_rep) |
230 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { | 269 : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { |
231 internal::ImageRepSkia* rep = | 270 internal::ImageRepSkia* rep = |
(...skipping 28 matching lines...) Expand all Loading... |
260 } | 299 } |
261 | 300 |
262 Image& Image::operator=(const Image& other) { | 301 Image& Image::operator=(const Image& other) { |
263 storage_ = other.storage_; | 302 storage_ = other.storage_; |
264 return *this; | 303 return *this; |
265 } | 304 } |
266 | 305 |
267 Image::~Image() { | 306 Image::~Image() { |
268 } | 307 } |
269 | 308 |
| 309 const ImagePNG* Image::ToImagePNG() const { |
| 310 internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false); |
| 311 if (!rep) { |
| 312 switch (DefaultRepresentationType()) { |
| 313 // For both native types, ensure that there is an ImageRepSkia and fall |
| 314 // through to that case |
| 315 #if defined(TOOLKIT_GTK) |
| 316 case kImageRepGdk: |
| 317 ToImageSkia(); |
| 318 #elif defined(OS_MACOSX) |
| 319 case kImageRepCocoa: |
| 320 ToImageSkia(); |
| 321 #endif |
| 322 case kImageRepSkia: { |
| 323 internal::ImageRepSkia* skia_rep = |
| 324 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); |
| 325 rep = new internal::ImageRepPNG( |
| 326 ImagePNG::FromSkBitmap(skia_rep->image()->bitmap())); |
| 327 break; |
| 328 } |
| 329 default: |
| 330 NOTREACHED(); |
| 331 } |
| 332 CHECK(rep); |
| 333 AddRepresentation(rep); |
| 334 } |
| 335 return &rep->AsImageRepPNG()->image(); |
| 336 } |
| 337 |
270 const SkBitmap* Image::ToSkBitmap() const { | 338 const SkBitmap* Image::ToSkBitmap() const { |
271 // Possibly create and cache an intermediate ImageRepSkia. | 339 // Possibly create and cache an intermediate ImageRepSkia. |
272 return ToImageSkia()->bitmap(); | 340 return ToImageSkia()->bitmap(); |
273 } | 341 } |
274 | 342 |
275 const ImageSkia* Image::ToImageSkia() const { | 343 const ImageSkia* Image::ToImageSkia() const { |
276 internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false); | 344 internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false); |
277 if (!rep) { | 345 if (!rep) { |
| 346 switch (DefaultRepresentationType()) { |
| 347 case kImageRepPNG: { |
| 348 internal::ImageRepPNG* png_rep = |
| 349 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG(); |
| 350 rep = new internal::ImageRepSkia(new ImageSkia( |
| 351 internal::ImageSkiaFromImagePNG(png_rep->image()))); |
| 352 break; |
| 353 } |
278 #if defined(TOOLKIT_GTK) | 354 #if defined(TOOLKIT_GTK) |
279 internal::ImageRepGdk* native_rep = | 355 case kImageRepGdk: { |
280 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk(); | 356 internal::ImageRepGdk* native_rep = |
281 rep = new internal::ImageRepSkia(new ImageSkia( | 357 GetRepresentation(kImageRepGdk, true)->AsImageRepGdk(); |
282 internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf()))); | 358 rep = new internal::ImageRepSkia(new ImageSkia( |
| 359 internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf()))); |
| 360 break; |
| 361 } |
283 #elif defined(OS_MACOSX) | 362 #elif defined(OS_MACOSX) |
284 internal::ImageRepCocoa* native_rep = | 363 case kImageRepCocoa: { |
285 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa(); | 364 internal::ImageRepCocoa* native_rep = |
286 rep = new internal::ImageRepSkia(new ImageSkia( | 365 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa(); |
287 ImageSkiaFromNSImage(native_rep->image()))); | 366 rep = new internal::ImageRepSkia(new ImageSkia( |
| 367 ImageSkiaFromNSImage(native_rep->image()))); |
| 368 break; |
| 369 } |
288 #endif | 370 #endif |
| 371 default: |
| 372 NOTREACHED(); |
| 373 } |
289 CHECK(rep); | 374 CHECK(rep); |
290 AddRepresentation(rep); | 375 AddRepresentation(rep); |
291 } | 376 } |
292 return rep->AsImageRepSkia()->image(); | 377 return rep->AsImageRepSkia()->image(); |
293 } | 378 } |
294 | 379 |
295 #if defined(TOOLKIT_GTK) | 380 #if defined(TOOLKIT_GTK) |
296 GdkPixbuf* Image::ToGdkPixbuf() const { | 381 GdkPixbuf* Image::ToGdkPixbuf() const { |
297 internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false); | 382 internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false); |
298 if (!rep) { | 383 if (!rep) { |
299 internal::ImageRepSkia* skia_rep = | 384 switch (DefaultRepresentationType()) { |
300 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); | 385 case kImageRepPNG: |
301 rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap( | 386 // Ensure that there is an ImageRepSkia and fall through to that case. |
302 *skia_rep->image()->bitmap())); | 387 ToImageSkia(); |
| 388 case kImageRepSkia: { |
| 389 internal::ImageRepSkia* skia_rep = |
| 390 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); |
| 391 rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap( |
| 392 *skia_rep->image()->bitmap())); |
| 393 break; |
| 394 } |
| 395 default: |
| 396 NOTREACHED(); |
| 397 } |
303 CHECK(rep); | 398 CHECK(rep); |
304 AddRepresentation(rep); | 399 AddRepresentation(rep); |
305 } | 400 } |
306 return rep->AsImageRepGdk()->pixbuf(); | 401 return rep->AsImageRepGdk()->pixbuf(); |
307 } | 402 } |
308 | 403 |
309 CairoCachedSurface* const Image::ToCairo() const { | 404 CairoCachedSurface* const Image::ToCairo() const { |
310 internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false); | 405 internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false); |
311 if (!rep) { | 406 if (!rep) { |
312 // Handle any-to-Cairo conversion. This may create and cache an intermediate | 407 // Handle any-to-Cairo conversion. This may create and cache an intermediate |
313 // pixbuf before sending the data to the display server. | 408 // pixbuf before sending the data to the display server. |
314 rep = new internal::ImageRepCairo(ToGdkPixbuf()); | 409 rep = new internal::ImageRepCairo(ToGdkPixbuf()); |
315 CHECK(rep); | 410 CHECK(rep); |
316 AddRepresentation(rep); | 411 AddRepresentation(rep); |
317 } | 412 } |
318 return rep->AsImageRepCairo()->surface(); | 413 return rep->AsImageRepCairo()->surface(); |
319 } | 414 } |
320 #endif | 415 #endif |
321 | 416 |
322 #if defined(OS_MACOSX) | 417 #if defined(OS_MACOSX) |
323 NSImage* Image::ToNSImage() const { | 418 NSImage* Image::ToNSImage() const { |
324 internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false); | 419 internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false); |
325 if (!rep) { | 420 if (!rep) { |
326 internal::ImageRepSkia* skia_rep = | 421 switch (DefaultRepresentationType()) { |
327 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); | 422 case kImageRepPNG: |
328 NSImage* image = NSImageFromImageSkia(*skia_rep->image()); | 423 // Ensure that there is a ImageRepSkia and fall through to that case. |
329 base::mac::NSObjectRetain(image); | 424 ToImageSkia(); |
330 rep = new internal::ImageRepCocoa(image); | 425 case kImageRepSkia: { |
| 426 internal::ImageRepSkia* skia_rep = |
| 427 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); |
| 428 NSImage* image = NSImageFromImageSkia(*skia_rep->image()); |
| 429 base::mac::NSObjectRetain(image); |
| 430 rep = new internal::ImageRepCocoa(image); |
| 431 break; |
| 432 } |
| 433 default: |
| 434 NOTREACHED(); |
| 435 } |
331 CHECK(rep); | 436 CHECK(rep); |
332 AddRepresentation(rep); | 437 AddRepresentation(rep); |
333 } | 438 } |
334 return rep->AsImageRepCocoa()->image(); | 439 return rep->AsImageRepCocoa()->image(); |
335 } | 440 } |
336 #endif | 441 #endif |
337 | 442 |
| 443 ImagePNG* Image::CopyImagePNG() const { |
| 444 return new ImagePNG(*ToImagePNG()); |
| 445 } |
| 446 |
338 ImageSkia* Image::CopyImageSkia() const { | 447 ImageSkia* Image::CopyImageSkia() const { |
339 return new ImageSkia(*ToImageSkia()); | 448 return new ImageSkia(*ToImageSkia()); |
340 } | 449 } |
341 | 450 |
342 SkBitmap* Image::CopySkBitmap() const { | 451 SkBitmap* Image::CopySkBitmap() const { |
343 return new SkBitmap(*ToSkBitmap()); | 452 return new SkBitmap(*ToSkBitmap()); |
344 } | 453 } |
345 | 454 |
346 #if defined(TOOLKIT_GTK) | 455 #if defined(TOOLKIT_GTK) |
347 GdkPixbuf* Image::CopyGdkPixbuf() const { | 456 GdkPixbuf* Image::CopyGdkPixbuf() const { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 } | 512 } |
404 return it->second; | 513 return it->second; |
405 } | 514 } |
406 | 515 |
407 void Image::AddRepresentation(internal::ImageRep* rep) const { | 516 void Image::AddRepresentation(internal::ImageRep* rep) const { |
408 CHECK(storage_.get()); | 517 CHECK(storage_.get()); |
409 storage_->representations().insert(std::make_pair(rep->type(), rep)); | 518 storage_->representations().insert(std::make_pair(rep->type(), rep)); |
410 } | 519 } |
411 | 520 |
412 } // namespace gfx | 521 } // namespace gfx |
OLD | NEW |