| 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 #include <set> | 8 #include <set> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 // the memory that the ImageRep holds. When an ImageRep is created, it expects | 174 // the memory that the ImageRep holds. When an ImageRep is created, it expects |
| 175 // to take ownership of the image, without having to retain it or increase its | 175 // to take ownership of the image, without having to retain it or increase its |
| 176 // reference count. | 176 // reference count. |
| 177 class ImageRep { | 177 class ImageRep { |
| 178 public: | 178 public: |
| 179 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {} | 179 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {} |
| 180 | 180 |
| 181 // Deletes the associated pixels of an ImageRep. | 181 // Deletes the associated pixels of an ImageRep. |
| 182 virtual ~ImageRep() {} | 182 virtual ~ImageRep() {} |
| 183 | 183 |
| 184 virtual std::unique_ptr<ImageRep> Clone() = 0; |
| 185 |
| 184 // Cast helpers ("fake RTTI"). | 186 // Cast helpers ("fake RTTI"). |
| 185 ImageRepPNG* AsImageRepPNG() { | 187 ImageRepPNG* AsImageRepPNG() { |
| 186 CHECK_EQ(type_, Image::kImageRepPNG); | 188 CHECK_EQ(type_, Image::kImageRepPNG); |
| 187 return reinterpret_cast<ImageRepPNG*>(this); | 189 return reinterpret_cast<ImageRepPNG*>(this); |
| 188 } | 190 } |
| 189 | 191 |
| 190 ImageRepSkia* AsImageRepSkia() { | 192 ImageRepSkia* AsImageRepSkia() { |
| 191 CHECK_EQ(type_, Image::kImageRepSkia); | 193 CHECK_EQ(type_, Image::kImageRepSkia); |
| 192 return reinterpret_cast<ImageRepSkia*>(this); | 194 return reinterpret_cast<ImageRepSkia*>(this); |
| 193 } | 195 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 217 class ImageRepPNG : public ImageRep { | 219 class ImageRepPNG : public ImageRep { |
| 218 public: | 220 public: |
| 219 ImageRepPNG() : ImageRep(Image::kImageRepPNG) { | 221 ImageRepPNG() : ImageRep(Image::kImageRepPNG) { |
| 220 } | 222 } |
| 221 | 223 |
| 222 ImageRepPNG(const std::vector<ImagePNGRep>& image_png_reps) | 224 ImageRepPNG(const std::vector<ImagePNGRep>& image_png_reps) |
| 223 : ImageRep(Image::kImageRepPNG), | 225 : ImageRep(Image::kImageRepPNG), |
| 224 image_png_reps_(image_png_reps) { | 226 image_png_reps_(image_png_reps) { |
| 225 } | 227 } |
| 226 | 228 |
| 229 ImageRepPNG(const ImageRepPNG& other) |
| 230 : ImageRep(Image::kImageRepPNG), |
| 231 image_png_reps_(other.image_png_reps_), |
| 232 size_cache_(other.size_cache_ ? new gfx::Size(*other.size_cache_) |
| 233 : nullptr) {} |
| 234 |
| 235 std::unique_ptr<ImageRep> Clone() override { |
| 236 return base::WrapUnique(new ImageRepPNG(*this)); |
| 237 } |
| 238 |
| 227 ~ImageRepPNG() override {} | 239 ~ImageRepPNG() override {} |
| 228 | 240 |
| 229 int Width() const override { return Size().width(); } | 241 int Width() const override { return Size().width(); } |
| 230 | 242 |
| 231 int Height() const override { return Size().height(); } | 243 int Height() const override { return Size().height(); } |
| 232 | 244 |
| 233 gfx::Size Size() const override { | 245 gfx::Size Size() const override { |
| 234 // Read the PNG data to get the image size, caching it. | 246 // Read the PNG data to get the image size, caching it. |
| 235 if (!size_cache_) { | 247 if (!size_cache_) { |
| 236 for (std::vector<ImagePNGRep>::const_iterator it = image_reps().begin(); | 248 for (std::vector<ImagePNGRep>::const_iterator it = image_reps().begin(); |
| 237 it != image_reps().end(); ++it) { | 249 it != image_reps().end(); ++it) { |
| 238 if (it->scale == 1.0f) { | 250 if (it->scale == 1.0f) { |
| 239 size_cache_.reset(new gfx::Size(it->Size())); | 251 size_cache_.reset(new gfx::Size(it->Size())); |
| 240 return *size_cache_; | 252 return *size_cache_; |
| 241 } | 253 } |
| 242 } | 254 } |
| 243 size_cache_.reset(new gfx::Size); | 255 size_cache_.reset(new gfx::Size); |
| 244 } | 256 } |
| 245 | 257 |
| 246 return *size_cache_; | 258 return *size_cache_; |
| 247 } | 259 } |
| 248 | 260 |
| 249 const std::vector<ImagePNGRep>& image_reps() const { return image_png_reps_; } | 261 const std::vector<ImagePNGRep>& image_reps() const { return image_png_reps_; } |
| 250 | 262 |
| 251 private: | 263 private: |
| 252 std::vector<ImagePNGRep> image_png_reps_; | 264 std::vector<ImagePNGRep> image_png_reps_; |
| 253 | 265 |
| 254 // Cached to avoid having to parse the raw data multiple times. | 266 // Cached to avoid having to parse the raw data multiple times. |
| 255 mutable std::unique_ptr<gfx::Size> size_cache_; | 267 mutable std::unique_ptr<gfx::Size> size_cache_; |
| 256 | |
| 257 DISALLOW_COPY_AND_ASSIGN(ImageRepPNG); | |
| 258 }; | 268 }; |
| 259 | 269 |
| 260 class ImageRepSkia : public ImageRep { | 270 class ImageRepSkia : public ImageRep { |
| 261 public: | 271 public: |
| 262 // Takes ownership of |image|. | 272 // Takes ownership of |image|. |
| 263 explicit ImageRepSkia(ImageSkia* image) | 273 explicit ImageRepSkia(ImageSkia* image) |
| 264 : ImageRep(Image::kImageRepSkia), | 274 : ImageRep(Image::kImageRepSkia), |
| 265 image_(image) { | 275 image_(image) { |
| 266 } | 276 } |
| 267 | 277 |
| 268 ~ImageRepSkia() override {} | 278 ImageRepSkia(const ImageRepSkia& other) |
| 279 : ImageRep(Image::kImageRepSkia), image_(new ImageSkia(*other.image_)) {} |
| 280 |
| 281 std::unique_ptr<ImageRep> Clone() override { |
| 282 return base::WrapUnique(new ImageRepSkia(*this)); |
| 283 } |
| 284 |
| 285 ~ImageRepSkia() override { |
| 286 // TODO(mgiuca): Obviously bad, but we just leak the pointer because there |
| 287 // is a lot of code depending on this outliving the Image. |
| 288 image_.release(); |
| 289 } |
| 269 | 290 |
| 270 int Width() const override { return image_->width(); } | 291 int Width() const override { return image_->width(); } |
| 271 | 292 |
| 272 int Height() const override { return image_->height(); } | 293 int Height() const override { return image_->height(); } |
| 273 | 294 |
| 274 gfx::Size Size() const override { return image_->size(); } | 295 gfx::Size Size() const override { return image_->size(); } |
| 275 | 296 |
| 297 // So... this no longer returns a stable pointer because the Image owns the |
| 298 // ImageSkia and if the local image is destroyed, so is the ImageSkia. Major |
| 299 // problem with this approach: any call to ToImageSkia will now require the |
| 300 // immediate Image object to outlive the ImageSkia*. See |
| 301 // ThemeService::GetImageSkiaNamed, which very deeply relies on the ImageSkia* |
| 302 // outliving the immediate Image object there. |
| 276 ImageSkia* image() { return image_.get(); } | 303 ImageSkia* image() { return image_.get(); } |
| 277 | 304 |
| 278 private: | 305 private: |
| 279 std::unique_ptr<ImageSkia> image_; | 306 std::unique_ptr<ImageSkia> image_; |
| 280 | |
| 281 DISALLOW_COPY_AND_ASSIGN(ImageRepSkia); | |
| 282 }; | 307 }; |
| 283 | 308 |
| 284 #if defined(OS_IOS) | 309 #if defined(OS_IOS) |
| 285 class ImageRepCocoaTouch : public ImageRep { | 310 class ImageRepCocoaTouch : public ImageRep { |
| 286 public: | 311 public: |
| 287 explicit ImageRepCocoaTouch(UIImage* image) | 312 explicit ImageRepCocoaTouch(UIImage* image) |
| 288 : ImageRep(Image::kImageRepCocoaTouch), | 313 : ImageRep(Image::kImageRepCocoaTouch), |
| 289 image_(image) { | 314 image_(image) { |
| 290 CHECK(image); | 315 CHECK(image); |
| 291 } | 316 } |
| 292 | 317 |
| 318 // TODO(mgiuca): |image_| double-free!!! DO NOT SUBMIT. |
| 319 ImageRepCocoaTouch(const ImageRepCocoaTouch& other) = default; |
| 320 |
| 321 std::unique_ptr<ImageRep> Clone() override { |
| 322 return base::WrapUnique(new ImageRepCocoaTouch(*this)); |
| 323 } |
| 324 |
| 293 ~ImageRepCocoaTouch() override { | 325 ~ImageRepCocoaTouch() override { |
| 294 base::mac::NSObjectRelease(image_); | 326 base::mac::NSObjectRelease(image_); |
| 295 image_ = nil; | 327 image_ = nil; |
| 296 } | 328 } |
| 297 | 329 |
| 298 int Width() const override { return Size().width(); } | 330 int Width() const override { return Size().width(); } |
| 299 | 331 |
| 300 int Height() const override { return Size().height(); } | 332 int Height() const override { return Size().height(); } |
| 301 | 333 |
| 302 gfx::Size Size() const override { return internal::UIImageSize(image_); } | 334 gfx::Size Size() const override { return internal::UIImageSize(image_); } |
| 303 | 335 |
| 304 UIImage* image() const { return image_; } | 336 UIImage* image() const { return image_; } |
| 305 | 337 |
| 306 private: | 338 private: |
| 307 UIImage* image_; | 339 UIImage* image_; |
| 308 | |
| 309 DISALLOW_COPY_AND_ASSIGN(ImageRepCocoaTouch); | |
| 310 }; | 340 }; |
| 311 #elif defined(OS_MACOSX) | 341 #elif defined(OS_MACOSX) |
| 312 class ImageRepCocoa : public ImageRep { | 342 class ImageRepCocoa : public ImageRep { |
| 313 public: | 343 public: |
| 314 explicit ImageRepCocoa(NSImage* image) | 344 explicit ImageRepCocoa(NSImage* image) |
| 315 : ImageRep(Image::kImageRepCocoa), | 345 : ImageRep(Image::kImageRepCocoa), |
| 316 image_(image) { | 346 image_(image) { |
| 317 CHECK(image); | 347 CHECK(image); |
| 318 } | 348 } |
| 319 | 349 |
| 350 // TODO(mgiuca): |image_| double-free!!! DO NOT SUBMIT. |
| 351 ImageRepCocoa(const ImageRepCocoa& other) = default; |
| 352 |
| 353 std::unique_ptr<ImageRep> Clone() override { |
| 354 return base::WrapUnique(new ImageRepCocoa(*this)); |
| 355 } |
| 356 |
| 320 ~ImageRepCocoa() override { | 357 ~ImageRepCocoa() override { |
| 321 base::mac::NSObjectRelease(image_); | 358 base::mac::NSObjectRelease(image_); |
| 322 image_ = nil; | 359 image_ = nil; |
| 323 } | 360 } |
| 324 | 361 |
| 325 int Width() const override { return Size().width(); } | 362 int Width() const override { return Size().width(); } |
| 326 | 363 |
| 327 int Height() const override { return Size().height(); } | 364 int Height() const override { return Size().height(); } |
| 328 | 365 |
| 329 gfx::Size Size() const override { return internal::NSImageSize(image_); } | 366 gfx::Size Size() const override { return internal::NSImageSize(image_); } |
| 330 | 367 |
| 331 NSImage* image() const { return image_; } | 368 NSImage* image() const { return image_; } |
| 332 | 369 |
| 333 private: | 370 private: |
| 334 NSImage* image_; | 371 NSImage* image_; |
| 335 | |
| 336 DISALLOW_COPY_AND_ASSIGN(ImageRepCocoa); | |
| 337 }; | 372 }; |
| 338 #endif // defined(OS_MACOSX) | 373 #endif // defined(OS_MACOSX) |
| 339 | 374 |
| 340 // The Storage class acts similarly to the pixels in a SkBitmap: the Image | 375 // The Storage class acts similarly to the pixels in a SkBitmap: the Image |
| 341 // class holds a refptr instance of Storage, which in turn holds all the | 376 // class holds a refptr instance of Storage, which in turn holds all the |
| 342 // ImageReps. This way, the Image can be cheaply copied. | 377 // ImageReps. This way, the Image can be cheaply copied. |
| 343 class ImageStorage : public base::RefCounted<ImageStorage> { | 378 class ImageStorage { |
| 344 public: | 379 public: |
| 345 ImageStorage(Image::RepresentationType default_type) | 380 ImageStorage(Image::RepresentationType default_type) |
| 346 : default_representation_type_(default_type) | 381 : default_representation_type_(default_type) |
| 347 #if defined(OS_MACOSX) && !defined(OS_IOS) | 382 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 348 , | 383 , |
| 349 default_representation_color_space_( | 384 default_representation_color_space_( |
| 350 base::mac::GetGenericRGBColorSpace()) | 385 base::mac::GetGenericRGBColorSpace()) |
| 351 #endif // defined(OS_MACOSX) && !defined(OS_IOS) | 386 #endif // defined(OS_MACOSX) && !defined(OS_IOS) |
| 352 { | 387 { |
| 353 } | 388 } |
| 354 | 389 |
| 390 ImageStorage(const ImageStorage& other) |
| 391 : default_representation_type_(other.default_representation_type_) |
| 392 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 393 , |
| 394 default_representation_color_space_( |
| 395 other.default_representation_color_space_) |
| 396 #endif // defined(OS_MACOSX) && !defined(OS_IOS) |
| 397 { |
| 398 for (const auto& item : other.representations_) |
| 399 representations_.insert(std::make_pair(item.first, item.second->Clone())); |
| 400 } |
| 401 |
| 402 ~ImageStorage() {} |
| 403 |
| 355 Image::RepresentationType default_representation_type() { | 404 Image::RepresentationType default_representation_type() { |
| 356 return default_representation_type_; | 405 return default_representation_type_; |
| 357 } | 406 } |
| 358 Image::RepresentationMap& representations() { return representations_; } | 407 Image::RepresentationMap& representations() { return representations_; } |
| 359 | 408 |
| 360 #if defined(OS_MACOSX) && !defined(OS_IOS) | 409 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 361 void set_default_representation_color_space(CGColorSpaceRef color_space) { | 410 void set_default_representation_color_space(CGColorSpaceRef color_space) { |
| 362 default_representation_color_space_ = color_space; | 411 default_representation_color_space_ = color_space; |
| 363 } | 412 } |
| 364 CGColorSpaceRef default_representation_color_space() { | 413 CGColorSpaceRef default_representation_color_space() { |
| 365 return default_representation_color_space_; | 414 return default_representation_color_space_; |
| 366 } | 415 } |
| 367 #endif // defined(OS_MACOSX) && !defined(OS_IOS) | 416 #endif // defined(OS_MACOSX) && !defined(OS_IOS) |
| 368 | 417 |
| 369 private: | 418 private: |
| 370 friend class base::RefCounted<ImageStorage>; | 419 friend class base::RefCounted<ImageStorage>; |
| 371 | 420 |
| 372 ~ImageStorage() {} | |
| 373 | |
| 374 // The type of image that was passed to the constructor. This key will always | 421 // The type of image that was passed to the constructor. This key will always |
| 375 // exist in the |representations_| map. | 422 // exist in the |representations_| map. |
| 376 Image::RepresentationType default_representation_type_; | 423 Image::RepresentationType default_representation_type_; |
| 377 | 424 |
| 378 #if defined(OS_MACOSX) && !defined(OS_IOS) | 425 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 379 // The default representation's colorspace. This is used for converting to | 426 // The default representation's colorspace. This is used for converting to |
| 380 // NSImage. This field exists to compensate for PNGCodec not writing or | 427 // NSImage. This field exists to compensate for PNGCodec not writing or |
| 381 // reading colorspace ancillary chunks. (sRGB, iCCP). | 428 // reading colorspace ancillary chunks. (sRGB, iCCP). |
| 382 // Not owned. | 429 // Not owned. |
| 383 CGColorSpaceRef default_representation_color_space_; | 430 CGColorSpaceRef default_representation_color_space_; |
| 384 #endif // defined(OS_MACOSX) && !defined(OS_IOS) | 431 #endif // defined(OS_MACOSX) && !defined(OS_IOS) |
| 385 | 432 |
| 386 // All the representations of an Image. Size will always be at least one, with | 433 // All the representations of an Image. Size will always be at least one, with |
| 387 // more for any converted representations. | 434 // more for any converted representations. |
| 388 Image::RepresentationMap representations_; | 435 Image::RepresentationMap representations_; |
| 389 | |
| 390 DISALLOW_COPY_AND_ASSIGN(ImageStorage); | |
| 391 }; | 436 }; |
| 392 | 437 |
| 393 } // namespace internal | 438 } // namespace internal |
| 394 | 439 |
| 395 Image::Image() { | 440 Image::Image() { |
| 396 // |storage_| is NULL for empty Images. | 441 // |storage_| is NULL for empty Images. |
| 397 } | 442 } |
| 398 | 443 |
| 399 Image::Image(const std::vector<ImagePNGRep>& image_reps) { | 444 Image::Image(const std::vector<ImagePNGRep>& image_reps) { |
| 400 // Do not store obviously invalid ImagePNGReps. | 445 // Do not store obviously invalid ImagePNGReps. |
| 401 std::vector<ImagePNGRep> filtered; | 446 std::vector<ImagePNGRep> filtered; |
| 402 for (size_t i = 0; i < image_reps.size(); ++i) { | 447 for (size_t i = 0; i < image_reps.size(); ++i) { |
| 403 if (image_reps[i].raw_data.get() && image_reps[i].raw_data->size()) | 448 if (image_reps[i].raw_data.get() && image_reps[i].raw_data->size()) |
| 404 filtered.push_back(image_reps[i]); | 449 filtered.push_back(image_reps[i]); |
| 405 } | 450 } |
| 406 | 451 |
| 407 if (filtered.empty()) | 452 if (filtered.empty()) |
| 408 return; | 453 return; |
| 409 | 454 |
| 410 storage_ = new internal::ImageStorage(Image::kImageRepPNG); | 455 storage_.reset(new internal::ImageStorage(Image::kImageRepPNG)); |
| 411 AddRepresentation(base::WrapUnique(new internal::ImageRepPNG(filtered))); | 456 AddRepresentation(base::WrapUnique(new internal::ImageRepPNG(filtered))); |
| 412 } | 457 } |
| 413 | 458 |
| 414 Image::Image(const ImageSkia& image) { | 459 Image::Image(const ImageSkia& image) { |
| 415 if (!image.isNull()) { | 460 if (!image.isNull()) { |
| 416 storage_ = new internal::ImageStorage(Image::kImageRepSkia); | 461 storage_.reset(new internal::ImageStorage(Image::kImageRepSkia)); |
| 417 AddRepresentation( | 462 AddRepresentation( |
| 418 base::WrapUnique(new internal::ImageRepSkia(new ImageSkia(image)))); | 463 base::WrapUnique(new internal::ImageRepSkia(new ImageSkia(image)))); |
| 419 } | 464 } |
| 420 } | 465 } |
| 421 | 466 |
| 422 #if defined(OS_IOS) | 467 #if defined(OS_IOS) |
| 423 Image::Image(UIImage* image) | 468 Image::Image(UIImage* image) |
| 424 : storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) { | 469 : storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) { |
| 425 if (image) | 470 if (image) |
| 426 AddRepresentation( | 471 AddRepresentation( |
| 427 base::WrapUnique(new internal::ImageRepCocoaTouch(image))); | 472 base::WrapUnique(new internal::ImageRepCocoaTouch(image))); |
| 428 } | 473 } |
| 429 #elif defined(OS_MACOSX) | 474 #elif defined(OS_MACOSX) |
| 430 Image::Image(NSImage* image) { | 475 Image::Image(NSImage* image) { |
| 431 if (image) { | 476 if (image) { |
| 432 storage_ = new internal::ImageStorage(Image::kImageRepCocoa); | 477 storage_.reset(new internal::ImageStorage(Image::kImageRepCocoa)); |
| 433 AddRepresentation(base::WrapUnique(new internal::ImageRepCocoa(image))); | 478 AddRepresentation(base::WrapUnique(new internal::ImageRepCocoa(image))); |
| 434 } | 479 } |
| 435 } | 480 } |
| 436 #endif | 481 #endif |
| 437 | 482 |
| 438 Image::Image(const Image& other) : storage_(other.storage_) { | 483 Image::Image(const Image& other) |
| 439 } | 484 : storage_(other.storage_ ? new internal::ImageStorage(*other.storage_) |
| 485 : nullptr) {} |
| 440 | 486 |
| 441 Image& Image::operator=(const Image& other) { | 487 Image& Image::operator=(const Image& other) { |
| 442 storage_ = other.storage_; | 488 storage_.reset(other.storage_ ? new internal::ImageStorage(*other.storage_) |
| 489 : nullptr); |
| 443 return *this; | 490 return *this; |
| 444 } | 491 } |
| 445 | 492 |
| 446 Image::~Image() { | 493 Image::~Image() { |
| 447 } | 494 } |
| 448 | 495 |
| 449 // static | 496 // static |
| 450 Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) { | 497 Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) { |
| 451 return Image(ImageSkia::CreateFrom1xBitmap(bitmap)); | 498 return Image(ImageSkia::CreateFrom1xBitmap(bitmap)); |
| 452 } | 499 } |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 757 storage_->representations().insert(std::make_pair(type, std::move(rep))); | 804 storage_->representations().insert(std::make_pair(type, std::move(rep))); |
| 758 | 805 |
| 759 // insert should not fail (implies that there was already a representation of | 806 // insert should not fail (implies that there was already a representation of |
| 760 // that type in the map). | 807 // that type in the map). |
| 761 CHECK(result.second) << "type was already in map."; | 808 CHECK(result.second) << "type was already in map."; |
| 762 | 809 |
| 763 return result.first->second.get(); | 810 return result.first->second.get(); |
| 764 } | 811 } |
| 765 | 812 |
| 766 } // namespace gfx | 813 } // namespace gfx |
| OLD | NEW |