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