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 3 // found in the LICENSE file. 4 5 #include "ui/gfx/image/image_skia.h" 6 7 #include "base/command_line.h" 8 #include "base/logging.h" 9 #include "base/threading/simple_thread.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 #include "third_party/skia/include/core/SkBitmap.h" 12 #include "ui/gfx/image/image_skia_rep.h" 13 #include "ui/gfx/image/image_skia_source.h" 14 #include "ui/gfx/size.h" 15 #include "ui/gfx/switches.h" 16 17 // Duplicated from base/threading/non_thread_safe.h so that we can be 18 // good citizens there and undef the macro. 19 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) 20 #define ENABLE_NON_THREAD_SAFE 1 21 #else 22 #define ENABLE_NON_THREAD_SAFE 0 23 #endif 24 25 namespace gfx { 26 27 namespace { 28 29 class FixedSource : public ImageSkiaSource { 30 public: 31 FixedSource(const ImageSkiaRep& image) : image_(image) {} 32 33 virtual ~FixedSource() { 34 } 35 36 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { 37 return image_; 38 } 39 40 private: 41 ImageSkiaRep image_; 42 43 DISALLOW_COPY_AND_ASSIGN(FixedSource); 44 }; 45 46 class DynamicSource : public ImageSkiaSource { 47 public: 48 DynamicSource(const gfx::Size& size) 49 : size_(size), 50 last_requested_scale_(0.0f) {} 51 52 virtual ~DynamicSource() { 53 } 54 55 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { 56 last_requested_scale_ = scale; 57 return gfx::ImageSkiaRep(size_, scale); 58 } 59 60 float GetLastRequestedScaleAndReset() { 61 float result = last_requested_scale_; 62 last_requested_scale_ = 0.0f; 63 return result; 64 } 65 66 private: 67 gfx::Size size_; 68 float last_requested_scale_; 69 70 DISALLOW_COPY_AND_ASSIGN(DynamicSource); 71 }; 72 73 class NullSource: public ImageSkiaSource { 74 public: 75 NullSource() { 76 } 77 78 virtual ~NullSource() { 79 } 80 81 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { 82 return gfx::ImageSkiaRep(); 83 } 84 85 private: 86 DISALLOW_COPY_AND_ASSIGN(NullSource); 87 }; 88 89 } // namespace 90 91 namespace test { 92 class TestOnThread : public base::SimpleThread { 93 public: 94 explicit TestOnThread(ImageSkia* image_skia) 95 : SimpleThread("image_skia_on_thread"), 96 image_skia_(image_skia), 97 can_read_(false), 98 can_modify_(false) { 99 } 100 101 virtual void Run() OVERRIDE { 102 can_read_ = image_skia_->CanRead(); 103 can_modify_ = image_skia_->CanModify(); 104 if (can_read_) 105 image_skia_->image_reps(); 106 } 107 108 void StartAndJoin() { 109 Start(); 110 Join(); 111 } 112 113 bool can_read() const { return can_read_; } 114 115 bool can_modify() const { return can_modify_; } 116 117 private: 118 ImageSkia* image_skia_; 119 120 bool can_read_; 121 bool can_modify_; 122 123 DISALLOW_COPY_AND_ASSIGN(TestOnThread); 124 }; 125 126 } // namespace test 127 128 class ImageSkiaTest : public testing::Test { 129 public: 130 ImageSkiaTest() { 131 // In the test, we assume that we support 1.0f and 2.0f DSFs. 132 old_scales_ = ImageSkia::GetSupportedScales(); 133 134 // Sets the list of scale factors supported by resource bundle. 135 std::vector<float> supported_scales; 136 supported_scales.push_back(1.0f); 137 supported_scales.push_back(2.0f); 138 ImageSkia::SetSupportedScales(supported_scales); 139 } 140 virtual ~ImageSkiaTest() { 141 ImageSkia::SetSupportedScales(old_scales_); 142 } 143 144 private: 145 std::vector<float> old_scales_; 146 DISALLOW_COPY_AND_ASSIGN(ImageSkiaTest); 147 }; 148 149 TEST_F(ImageSkiaTest, FixedSource) { 150 ImageSkiaRep image(Size(100, 200), 1.0f); 151 ImageSkia image_skia(new FixedSource(image), Size(100, 200)); 152 EXPECT_EQ(0U, image_skia.image_reps().size()); 153 154 const ImageSkiaRep& result_100p = image_skia.GetRepresentation(1.0f); 155 EXPECT_EQ(100, result_100p.GetWidth()); 156 EXPECT_EQ(200, result_100p.GetHeight()); 157 EXPECT_EQ(1.0f, result_100p.scale()); 158 EXPECT_EQ(1U, image_skia.image_reps().size()); 159 160 const ImageSkiaRep& result_200p = image_skia.GetRepresentation(2.0f); 161 162 EXPECT_EQ(100, result_200p.GetWidth()); 163 EXPECT_EQ(200, result_200p.GetHeight()); 164 EXPECT_EQ(100, result_200p.pixel_width()); 165 EXPECT_EQ(200, result_200p.pixel_height()); 166 EXPECT_EQ(1.0f, result_200p.scale()); 167 EXPECT_EQ(1U, image_skia.image_reps().size()); 168 169 // Get the representation again and make sure it doesn't 170 // generate new image skia rep. 171 image_skia.GetRepresentation(1.0f); 172 image_skia.GetRepresentation(2.0f); 173 EXPECT_EQ(1U, image_skia.image_reps().size()); 174 } 175 176 TEST_F(ImageSkiaTest, DynamicSource) { 177 ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200)); 178 EXPECT_EQ(0U, image_skia.image_reps().size()); 179 const ImageSkiaRep& result_100p = image_skia.GetRepresentation(1.0f); 180 EXPECT_EQ(100, result_100p.GetWidth()); 181 EXPECT_EQ(200, result_100p.GetHeight()); 182 EXPECT_EQ(1.0f, result_100p.scale()); 183 EXPECT_EQ(1U, image_skia.image_reps().size()); 184 185 const ImageSkiaRep& result_200p = 186 image_skia.GetRepresentation(2.0f); 187 EXPECT_EQ(100, result_200p.GetWidth()); 188 EXPECT_EQ(200, result_200p.GetHeight()); 189 EXPECT_EQ(200, result_200p.pixel_width()); 190 EXPECT_EQ(400, result_200p.pixel_height()); 191 EXPECT_EQ(2.0f, result_200p.scale()); 192 EXPECT_EQ(2U, image_skia.image_reps().size()); 193 194 // Get the representation again and make sure it doesn't 195 // generate new image skia rep. 196 image_skia.GetRepresentation(1.0f); 197 EXPECT_EQ(2U, image_skia.image_reps().size()); 198 image_skia.GetRepresentation(2.0f); 199 EXPECT_EQ(2U, image_skia.image_reps().size()); 200 } 201 202 // Tests that image_reps returns all of the representations in the 203 // image when there are multiple representations for a scale factor. 204 // This currently is the case with ImageLoader::LoadImages. 205 TEST_F(ImageSkiaTest, ManyRepsPerScaleFactor) { 206 const int kSmallIcon1x = 16; 207 const int kSmallIcon2x = 32; 208 const int kLargeIcon1x = 32; 209 210 ImageSkia image(new NullSource(), gfx::Size(kSmallIcon1x, kSmallIcon1x)); 211 // Simulate a source which loads images on a delay. Upon 212 // GetImageForScaleFactor, it immediately returns null and starts loading 213 // image reps slowly. 214 image.GetRepresentation(1.0f); 215 image.GetRepresentation(2.0f); 216 217 // After a lengthy amount of simulated time, finally loaded image reps. 218 image.AddRepresentation(ImageSkiaRep( 219 gfx::Size(kSmallIcon1x, kSmallIcon1x), 1.0f)); 220 image.AddRepresentation(ImageSkiaRep( 221 gfx::Size(kSmallIcon2x, kSmallIcon2x), 2.0f)); 222 image.AddRepresentation(ImageSkiaRep( 223 gfx::Size(kLargeIcon1x, kLargeIcon1x), 1.0f)); 224 225 std::vector<ImageSkiaRep> image_reps = image.image_reps(); 226 EXPECT_EQ(3u, image_reps.size()); 227 228 int num_1x = 0; 229 int num_2x = 0; 230 for (size_t i = 0; i < image_reps.size(); ++i) { 231 if (image_reps[i].scale() == 1.0f) 232 num_1x++; 233 else if (image_reps[i].scale() == 2.0f) 234 num_2x++; 235 } 236 EXPECT_EQ(2, num_1x); 237 EXPECT_EQ(1, num_2x); 238 } 239 240 TEST_F(ImageSkiaTest, GetBitmap) { 241 ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200)); 242 const SkBitmap* bitmap = image_skia.bitmap(); 243 EXPECT_NE(static_cast<SkBitmap*>(NULL), bitmap); 244 EXPECT_FALSE(bitmap->isNull()); 245 } 246 247 TEST_F(ImageSkiaTest, GetBitmapFromEmpty) { 248 // Create an image with 1 representation and remove it so the ImageSkiaStorage 249 // is left with no representations. 250 ImageSkia empty_image(ImageSkiaRep(Size(100, 200), 1.0f)); 251 ImageSkia empty_image_copy(empty_image); 252 empty_image.RemoveRepresentation(1.0f); 253 254 // Check that ImageSkia::bitmap() still returns a valid SkBitmap pointer for 255 // the image and all its copies. 256 const SkBitmap* bitmap = empty_image_copy.bitmap(); 257 ASSERT_NE(static_cast<SkBitmap*>(NULL), bitmap); 258 EXPECT_TRUE(bitmap->isNull()); 259 EXPECT_TRUE(bitmap->empty()); 260 } 261 262 TEST_F(ImageSkiaTest, BackedBySameObjectAs) { 263 // Null images should all be backed by the same object (NULL). 264 ImageSkia image; 265 ImageSkia unrelated; 266 EXPECT_TRUE(image.BackedBySameObjectAs(unrelated)); 267 268 image.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), 269 1.0f)); 270 ImageSkia copy = image; 271 copy.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), 272 2.0f)); 273 unrelated.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), 274 1.0f)); 275 EXPECT_TRUE(image.BackedBySameObjectAs(copy)); 276 EXPECT_FALSE(image.BackedBySameObjectAs(unrelated)); 277 EXPECT_FALSE(copy.BackedBySameObjectAs(unrelated)); 278 } 279 280 #if ENABLE_NON_THREAD_SAFE 281 TEST_F(ImageSkiaTest, EmptyOnThreadTest) { 282 ImageSkia empty; 283 test::TestOnThread empty_on_thread(&empty); 284 empty_on_thread.Start(); 285 empty_on_thread.Join(); 286 EXPECT_TRUE(empty_on_thread.can_read()); 287 EXPECT_TRUE(empty_on_thread.can_modify()); 288 } 289 290 TEST_F(ImageSkiaTest, StaticOnThreadTest) { 291 ImageSkia image(ImageSkiaRep(Size(100, 200), 1.0f)); 292 EXPECT_FALSE(image.IsThreadSafe()); 293 294 test::TestOnThread image_on_thread(&image); 295 // an image that was never accessed on this thread can be 296 // read by other thread. 297 image_on_thread.StartAndJoin(); 298 EXPECT_TRUE(image_on_thread.can_read()); 299 EXPECT_TRUE(image_on_thread.can_modify()); 300 EXPECT_FALSE(image.CanRead()); 301 EXPECT_FALSE(image.CanModify()); 302 303 image.DetachStorageFromThread(); 304 // An image is accessed by this thread, 305 // so other thread cannot read/modify it. 306 image.image_reps(); 307 test::TestOnThread image_on_thread2(&image); 308 image_on_thread2.StartAndJoin(); 309 EXPECT_FALSE(image_on_thread2.can_read()); 310 EXPECT_FALSE(image_on_thread2.can_modify()); 311 EXPECT_TRUE(image.CanRead()); 312 EXPECT_TRUE(image.CanModify()); 313 314 image.DetachStorageFromThread(); 315 scoped_ptr<ImageSkia> deep_copy(image.DeepCopy()); 316 EXPECT_FALSE(deep_copy->IsThreadSafe()); 317 test::TestOnThread deepcopy_on_thread(deep_copy.get()); 318 deepcopy_on_thread.StartAndJoin(); 319 EXPECT_TRUE(deepcopy_on_thread.can_read()); 320 EXPECT_TRUE(deepcopy_on_thread.can_modify()); 321 EXPECT_FALSE(deep_copy->CanRead()); 322 EXPECT_FALSE(deep_copy->CanModify()); 323 324 scoped_ptr<ImageSkia> deep_copy2(image.DeepCopy()); 325 EXPECT_EQ(1U, deep_copy2->image_reps().size()); 326 // Access it from current thread so that it can't be 327 // accessed from another thread. 328 deep_copy2->image_reps(); 329 EXPECT_FALSE(deep_copy2->IsThreadSafe()); 330 test::TestOnThread deepcopy2_on_thread(deep_copy2.get()); 331 deepcopy2_on_thread.StartAndJoin(); 332 EXPECT_FALSE(deepcopy2_on_thread.can_read()); 333 EXPECT_FALSE(deepcopy2_on_thread.can_modify()); 334 EXPECT_TRUE(deep_copy2->CanRead()); 335 EXPECT_TRUE(deep_copy2->CanModify()); 336 337 image.DetachStorageFromThread(); 338 image.SetReadOnly(); 339 // A read-only ImageSkia with no source is thread safe. 340 EXPECT_TRUE(image.IsThreadSafe()); 341 test::TestOnThread readonly_on_thread(&image); 342 readonly_on_thread.StartAndJoin(); 343 EXPECT_TRUE(readonly_on_thread.can_read()); 344 EXPECT_FALSE(readonly_on_thread.can_modify()); 345 EXPECT_TRUE(image.CanRead()); 346 EXPECT_FALSE(image.CanModify()); 347 348 image.DetachStorageFromThread(); 349 image.MakeThreadSafe(); 350 EXPECT_TRUE(image.IsThreadSafe()); 351 test::TestOnThread threadsafe_on_thread(&image); 352 threadsafe_on_thread.StartAndJoin(); 353 EXPECT_TRUE(threadsafe_on_thread.can_read()); 354 EXPECT_FALSE(threadsafe_on_thread.can_modify()); 355 EXPECT_TRUE(image.CanRead()); 356 EXPECT_FALSE(image.CanModify()); 357 } 358 359 TEST_F(ImageSkiaTest, SourceOnThreadTest) { 360 ImageSkia image(new DynamicSource(Size(100, 200)), Size(100, 200)); 361 EXPECT_FALSE(image.IsThreadSafe()); 362 363 test::TestOnThread image_on_thread(&image); 364 image_on_thread.StartAndJoin(); 365 // an image that was never accessed on this thread can be 366 // read by other thread. 367 EXPECT_TRUE(image_on_thread.can_read()); 368 EXPECT_TRUE(image_on_thread.can_modify()); 369 EXPECT_FALSE(image.CanRead()); 370 EXPECT_FALSE(image.CanModify()); 371 372 image.DetachStorageFromThread(); 373 // An image is accessed by this thread, 374 // so other thread cannot read/modify it. 375 image.image_reps(); 376 test::TestOnThread image_on_thread2(&image); 377 image_on_thread2.StartAndJoin(); 378 EXPECT_FALSE(image_on_thread2.can_read()); 379 EXPECT_FALSE(image_on_thread2.can_modify()); 380 EXPECT_TRUE(image.CanRead()); 381 EXPECT_TRUE(image.CanModify()); 382 383 image.DetachStorageFromThread(); 384 image.SetReadOnly(); 385 EXPECT_FALSE(image.IsThreadSafe()); 386 test::TestOnThread readonly_on_thread(&image); 387 readonly_on_thread.StartAndJoin(); 388 EXPECT_TRUE(readonly_on_thread.can_read()); 389 EXPECT_FALSE(readonly_on_thread.can_modify()); 390 EXPECT_FALSE(image.CanRead()); 391 EXPECT_FALSE(image.CanModify()); 392 393 image.DetachStorageFromThread(); 394 image.MakeThreadSafe(); 395 EXPECT_TRUE(image.IsThreadSafe()); 396 // Check if image reps are generated for supported scale factors. 397 EXPECT_EQ(ImageSkia::GetSupportedScales().size(), 398 image.image_reps().size()); 399 test::TestOnThread threadsafe_on_thread(&image); 400 threadsafe_on_thread.StartAndJoin(); 401 EXPECT_TRUE(threadsafe_on_thread.can_read()); 402 EXPECT_FALSE(threadsafe_on_thread.can_modify()); 403 EXPECT_TRUE(image.CanRead()); 404 EXPECT_FALSE(image.CanModify()); 405 } 406 #endif // ENABLE_NON_THREAD_SAFE 407 408 // Just in case we ever get lumped together with other compilation units. 409 #undef ENABLE_NON_THREAD_SAFE 410 411 TEST_F(ImageSkiaTest, Unscaled) { 412 SkBitmap bitmap; 413 414 // An ImageSkia created with 1x bitmap is unscaled. 415 ImageSkia image_skia = ImageSkia::CreateFrom1xBitmap(bitmap); 416 EXPECT_TRUE(image_skia.GetRepresentation(1.0f).unscaled()); 417 ImageSkiaRep rep_2x(Size(100, 100), 2.0f); 418 419 // When reps for other scales are added, the unscaled image 420 // becomes scaled. 421 image_skia.AddRepresentation(rep_2x); 422 EXPECT_FALSE(image_skia.GetRepresentation(1.0f).unscaled()); 423 EXPECT_FALSE(image_skia.GetRepresentation(2.0f).unscaled()); 424 } 425 426 TEST_F(ImageSkiaTest, ArbitraryScaleFactor) { 427 // Do not test if the ImageSkia doesn't support arbitrary scale factors. 428 if (!ImageSkia::IsDSFScalingInImageSkiaEnabled()) 429 return; 430 431 // source is owned by |image| 432 DynamicSource* source = new DynamicSource(Size(100, 200)); 433 ImageSkia image(source, gfx::Size(100, 200)); 434 435 image.GetRepresentation(1.5f); 436 EXPECT_EQ(2.0f, source->GetLastRequestedScaleAndReset()); 437 std::vector<ImageSkiaRep> image_reps = image.image_reps(); 438 EXPECT_EQ(2u, image_reps.size()); 439 440 std::vector<float> scale_factors; 441 for (size_t i = 0; i < image_reps.size(); ++i) { 442 scale_factors.push_back(image_reps[i].scale()); 443 } 444 std::sort(scale_factors.begin(), scale_factors.end()); 445 EXPECT_EQ(1.5f, scale_factors[0]); 446 EXPECT_EQ(2.0f, scale_factors[1]); 447 448 // Requesting 1.75 scale factor also falls back to 2.0f and rescale. 449 // However, the image already has the 2.0f data, so it won't fetch again. 450 image.GetRepresentation(1.75f); 451 EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset()); 452 image_reps = image.image_reps(); 453 EXPECT_EQ(3u, image_reps.size()); 454 455 scale_factors.clear(); 456 for (size_t i = 0; i < image_reps.size(); ++i) { 457 scale_factors.push_back(image_reps[i].scale()); 458 } 459 std::sort(scale_factors.begin(), scale_factors.end()); 460 EXPECT_EQ(1.5f, scale_factors[0]); 461 EXPECT_EQ(1.75f, scale_factors[1]); 462 EXPECT_EQ(2.0f, scale_factors[2]); 463 464 // 1.25 is falled back to 1.0. 465 image.GetRepresentation(1.25f); 466 EXPECT_EQ(1.0f, source->GetLastRequestedScaleAndReset()); 467 image_reps = image.image_reps(); 468 EXPECT_EQ(5u, image_reps.size()); 469 470 // Scale factor less than 1.0f will be falled back to 1.0f 471 image.GetRepresentation(0.75f); 472 EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset()); 473 image_reps = image.image_reps(); 474 EXPECT_EQ(6u, image_reps.size()); 475 476 scale_factors.clear(); 477 for (size_t i = 0; i < image_reps.size(); ++i) { 478 scale_factors.push_back(image_reps[i].scale()); 479 } 480 std::sort(scale_factors.begin(), scale_factors.end()); 481 EXPECT_EQ(0.75f, scale_factors[0]); 482 EXPECT_EQ(1.0f, scale_factors[1]); 483 EXPECT_EQ(1.25f, scale_factors[2]); 484 EXPECT_EQ(1.5f, scale_factors[3]); 485 EXPECT_EQ(1.75f, scale_factors[4]); 486 EXPECT_EQ(2.0f, scale_factors[5]); 487 488 // Scale factor greater than 2.0f is falled back to 2.0f because it's not 489 // supported. 490 image.GetRepresentation(3.0f); 491 EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset()); 492 image_reps = image.image_reps(); 493 EXPECT_EQ(7u, image_reps.size()); 494 } 495 496 TEST_F(ImageSkiaTest, ArbitraryScaleFactorWithMissingResource) { 497 // Do not test if the ImageSkia doesn't support arbitrary scale factors. 498 if (!ImageSkia::IsDSFScalingInImageSkiaEnabled()) 499 return; 500 501 ImageSkia image(new FixedSource( 502 ImageSkiaRep(Size(100, 200), 1.0f)), Size(100, 200)); 503 504 // Requesting 1.5f -- falls back to 2.0f, but couldn't find. It should 505 // look up 1.0f and then rescale it. 506 const ImageSkiaRep& rep = image.GetRepresentation(1.5f); 507 EXPECT_EQ(1.5f, rep.scale()); 508 EXPECT_EQ(2U, image.image_reps().size()); 509 EXPECT_EQ(1.0f, image.image_reps()[0].scale()); 510 EXPECT_EQ(1.5f, image.image_reps()[1].scale()); 511 } 512 513 TEST_F(ImageSkiaTest, UnscaledImageForArbitraryScaleFactor) { 514 // Do not test if the ImageSkia doesn't support arbitrary scale factors. 515 if (!ImageSkia::IsDSFScalingInImageSkiaEnabled()) 516 return; 517 518 // 0.0f means unscaled. 519 ImageSkia image(new FixedSource( 520 ImageSkiaRep(Size(100, 200), 0.0f)), Size(100, 200)); 521 522 // Requesting 2.0f, which should return 1.0f unscaled image. 523 const ImageSkiaRep& rep = image.GetRepresentation(2.0f); 524 EXPECT_EQ(1.0f, rep.scale()); 525 EXPECT_EQ("100x200", rep.pixel_size().ToString()); 526 EXPECT_TRUE(rep.unscaled()); 527 EXPECT_EQ(1U, image.image_reps().size()); 528 529 // Same for any other scale factors. 530 const ImageSkiaRep& rep15 = image.GetRepresentation(1.5f); 531 EXPECT_EQ(1.0f, rep15.scale()); 532 EXPECT_EQ("100x200", rep15.pixel_size().ToString()); 533 EXPECT_TRUE(rep15.unscaled()); 534 EXPECT_EQ(1U, image.image_reps().size()); 535 536 const ImageSkiaRep& rep12 = image.GetRepresentation(1.2f); 537 EXPECT_EQ(1.0f, rep12.scale()); 538 EXPECT_EQ("100x200", rep12.pixel_size().ToString()); 539 EXPECT_TRUE(rep12.unscaled()); 540 EXPECT_EQ(1U, image.image_reps().size()); 541 } 542 543 } // namespace gfx 544