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

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

Issue 10799014: Add support for PNG representation in gfx::Image (Closed) Base URL: http://git.chromium.org/chromium/src.git@bookmark-sync
Patch Set: Created 8 years, 5 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
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.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
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
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
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
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
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
OLDNEW
« ui/gfx/image/image.h ('K') | « ui/gfx/image/image.h ('k') | ui/gfx/image/image_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698