| OLD | NEW |
| (Empty) |
| 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 "chrome/browser/extensions/extension_icon_image.h" | |
| 6 | |
| 7 #include "base/json/json_file_value_serializer.h" | |
| 8 #include "base/message_loop/message_loop.h" | |
| 9 #include "base/path_service.h" | |
| 10 #include "chrome/browser/extensions/image_loader.h" | |
| 11 #include "chrome/common/chrome_paths.h" | |
| 12 #include "chrome/common/extensions/extension_constants.h" | |
| 13 #include "chrome/test/base/testing_profile.h" | |
| 14 #include "content/public/test/test_browser_thread.h" | |
| 15 #include "extensions/common/extension.h" | |
| 16 #include "extensions/common/manifest.h" | |
| 17 #include "extensions/common/manifest_handlers/icons_handler.h" | |
| 18 #include "grit/theme_resources.h" | |
| 19 #include "skia/ext/image_operations.h" | |
| 20 #include "testing/gtest/include/gtest/gtest.h" | |
| 21 #include "ui/base/resource/resource_bundle.h" | |
| 22 #include "ui/gfx/image/image_skia_source.h" | |
| 23 #include "ui/gfx/skia_util.h" | |
| 24 | |
| 25 using content::BrowserThread; | |
| 26 using extensions::Extension; | |
| 27 using extensions::IconImage; | |
| 28 using extensions::Manifest; | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 SkBitmap CreateBlankBitmapForScale(int size_dip, ui::ScaleFactor scale_factor) { | |
| 33 SkBitmap bitmap; | |
| 34 const float scale = ui::GetScaleForScaleFactor(scale_factor); | |
| 35 bitmap.setConfig(SkBitmap::kARGB_8888_Config, | |
| 36 static_cast<int>(size_dip * scale), | |
| 37 static_cast<int>(size_dip * scale)); | |
| 38 bitmap.allocPixels(); | |
| 39 bitmap.eraseColor(SkColorSetARGB(0, 0, 0, 0)); | |
| 40 return bitmap; | |
| 41 } | |
| 42 | |
| 43 SkBitmap EnsureBitmapSize(const SkBitmap& original, int size) { | |
| 44 if (original.width() == size && original.height() == size) | |
| 45 return original; | |
| 46 | |
| 47 SkBitmap resized = skia::ImageOperations::Resize( | |
| 48 original, skia::ImageOperations::RESIZE_LANCZOS3, size, size); | |
| 49 return resized; | |
| 50 } | |
| 51 | |
| 52 // Used to test behavior including images defined by an image skia source. | |
| 53 // |GetImageForScale| simply returns image representation from the image given | |
| 54 // in the ctor. | |
| 55 class MockImageSkiaSource : public gfx::ImageSkiaSource { | |
| 56 public: | |
| 57 explicit MockImageSkiaSource(const gfx::ImageSkia& image) | |
| 58 : image_(image) { | |
| 59 } | |
| 60 virtual ~MockImageSkiaSource() {} | |
| 61 | |
| 62 virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE { | |
| 63 return image_.GetRepresentation(scale); | |
| 64 } | |
| 65 | |
| 66 private: | |
| 67 gfx::ImageSkia image_; | |
| 68 }; | |
| 69 | |
| 70 // Helper class for synchronously loading extension image resource. | |
| 71 class TestImageLoader { | |
| 72 public: | |
| 73 explicit TestImageLoader(const Extension* extension) | |
| 74 : extension_(extension), | |
| 75 waiting_(false), | |
| 76 image_loaded_(false) { | |
| 77 } | |
| 78 virtual ~TestImageLoader() {} | |
| 79 | |
| 80 void OnImageLoaded(const gfx::Image& image) { | |
| 81 image_ = image; | |
| 82 image_loaded_ = true; | |
| 83 if (waiting_) | |
| 84 base::MessageLoop::current()->Quit(); | |
| 85 } | |
| 86 | |
| 87 SkBitmap LoadBitmap(const std::string& path, | |
| 88 int size) { | |
| 89 image_loaded_ = false; | |
| 90 | |
| 91 image_loader_.LoadImageAsync( | |
| 92 extension_, extension_->GetResource(path), gfx::Size(size, size), | |
| 93 base::Bind(&TestImageLoader::OnImageLoaded, | |
| 94 base::Unretained(this))); | |
| 95 | |
| 96 // If |image_| still hasn't been loaded (i.e. it is being loaded | |
| 97 // asynchronously), wait for it. | |
| 98 if (!image_loaded_) { | |
| 99 waiting_ = true; | |
| 100 base::MessageLoop::current()->Run(); | |
| 101 waiting_ = false; | |
| 102 } | |
| 103 | |
| 104 EXPECT_TRUE(image_loaded_); | |
| 105 | |
| 106 return image_.IsEmpty() ? SkBitmap() : *image_.ToSkBitmap(); | |
| 107 } | |
| 108 | |
| 109 private: | |
| 110 const Extension* extension_; | |
| 111 bool waiting_; | |
| 112 bool image_loaded_; | |
| 113 gfx::Image image_; | |
| 114 extensions::ImageLoader image_loader_; | |
| 115 | |
| 116 DISALLOW_COPY_AND_ASSIGN(TestImageLoader); | |
| 117 }; | |
| 118 | |
| 119 class ExtensionIconImageTest : public testing::Test, | |
| 120 public IconImage::Observer { | |
| 121 public: | |
| 122 ExtensionIconImageTest() | |
| 123 : image_loaded_count_(0), | |
| 124 quit_in_image_loaded_(false), | |
| 125 ui_thread_(BrowserThread::UI, &ui_loop_), | |
| 126 file_thread_(BrowserThread::FILE), | |
| 127 io_thread_(BrowserThread::IO) { | |
| 128 } | |
| 129 | |
| 130 virtual ~ExtensionIconImageTest() {} | |
| 131 | |
| 132 void WaitForImageLoad() { | |
| 133 quit_in_image_loaded_ = true; | |
| 134 base::MessageLoop::current()->Run(); | |
| 135 quit_in_image_loaded_ = false; | |
| 136 } | |
| 137 | |
| 138 int ImageLoadedCount() { | |
| 139 int result = image_loaded_count_; | |
| 140 image_loaded_count_ = 0; | |
| 141 return result; | |
| 142 } | |
| 143 | |
| 144 scoped_refptr<Extension> CreateExtension(const char* name, | |
| 145 Manifest::Location location) { | |
| 146 // Create and load an extension. | |
| 147 base::FilePath test_file; | |
| 148 if (!PathService::Get(chrome::DIR_TEST_DATA, &test_file)) { | |
| 149 EXPECT_FALSE(true); | |
| 150 return NULL; | |
| 151 } | |
| 152 test_file = test_file.AppendASCII("extensions").AppendASCII(name); | |
| 153 int error_code = 0; | |
| 154 std::string error; | |
| 155 JSONFileValueSerializer serializer(test_file.AppendASCII("app.json")); | |
| 156 scoped_ptr<base::DictionaryValue> valid_value( | |
| 157 static_cast<base::DictionaryValue*>(serializer.Deserialize(&error_code, | |
| 158 &error))); | |
| 159 EXPECT_EQ(0, error_code) << error; | |
| 160 if (error_code != 0) | |
| 161 return NULL; | |
| 162 | |
| 163 EXPECT_TRUE(valid_value.get()); | |
| 164 if (!valid_value) | |
| 165 return NULL; | |
| 166 | |
| 167 return Extension::Create(test_file, location, *valid_value, | |
| 168 Extension::NO_FLAGS, &error); | |
| 169 } | |
| 170 | |
| 171 // testing::Test overrides: | |
| 172 virtual void SetUp() OVERRIDE { | |
| 173 file_thread_.Start(); | |
| 174 io_thread_.Start(); | |
| 175 } | |
| 176 | |
| 177 // IconImage::Delegate overrides: | |
| 178 virtual void OnExtensionIconImageChanged(IconImage* image) OVERRIDE { | |
| 179 image_loaded_count_++; | |
| 180 if (quit_in_image_loaded_) | |
| 181 base::MessageLoop::current()->Quit(); | |
| 182 } | |
| 183 | |
| 184 gfx::ImageSkia GetDefaultIcon() { | |
| 185 return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( | |
| 186 IDR_EXTENSIONS_FAVICON); | |
| 187 } | |
| 188 | |
| 189 // Loads an image to be used in test from the extension. | |
| 190 // The image will be loaded from the relative path |path|. | |
| 191 SkBitmap GetTestBitmap(const Extension* extension, | |
| 192 const std::string& path, | |
| 193 int size) { | |
| 194 TestImageLoader image_loader(extension); | |
| 195 return image_loader.LoadBitmap(path, size); | |
| 196 } | |
| 197 | |
| 198 private: | |
| 199 int image_loaded_count_; | |
| 200 bool quit_in_image_loaded_; | |
| 201 base::MessageLoop ui_loop_; | |
| 202 content::TestBrowserThread ui_thread_; | |
| 203 content::TestBrowserThread file_thread_; | |
| 204 content::TestBrowserThread io_thread_; | |
| 205 | |
| 206 DISALLOW_COPY_AND_ASSIGN(ExtensionIconImageTest); | |
| 207 }; | |
| 208 | |
| 209 } // namespace | |
| 210 | |
| 211 TEST_F(ExtensionIconImageTest, Basic) { | |
| 212 std::vector<ui::ScaleFactor> supported_factors; | |
| 213 supported_factors.push_back(ui::SCALE_FACTOR_100P); | |
| 214 supported_factors.push_back(ui::SCALE_FACTOR_200P); | |
| 215 ui::test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors); | |
| 216 scoped_ptr<Profile> profile(new TestingProfile()); | |
| 217 scoped_refptr<Extension> extension(CreateExtension( | |
| 218 "extension_icon_image", Manifest::INVALID_LOCATION)); | |
| 219 ASSERT_TRUE(extension.get() != NULL); | |
| 220 | |
| 221 gfx::ImageSkia default_icon = GetDefaultIcon(); | |
| 222 | |
| 223 // Load images we expect to find as representations in icon_image, so we | |
| 224 // can later use them to validate icon_image. | |
| 225 SkBitmap bitmap_16 = GetTestBitmap(extension.get(), "16.png", 16); | |
| 226 ASSERT_FALSE(bitmap_16.empty()); | |
| 227 | |
| 228 // There is no image of size 32 defined in the extension manifest, so we | |
| 229 // should expect manifest image of size 48 resized to size 32. | |
| 230 SkBitmap bitmap_48_resized_to_32 = | |
| 231 GetTestBitmap(extension.get(), "48.png", 32); | |
| 232 ASSERT_FALSE(bitmap_48_resized_to_32.empty()); | |
| 233 | |
| 234 IconImage image(profile.get(), | |
| 235 extension.get(), | |
| 236 extensions::IconsInfo::GetIcons(extension.get()), | |
| 237 16, | |
| 238 default_icon, | |
| 239 this); | |
| 240 | |
| 241 // No representations in |image_| yet. | |
| 242 gfx::ImageSkia::ImageSkiaReps image_reps = image.image_skia().image_reps(); | |
| 243 ASSERT_EQ(0u, image_reps.size()); | |
| 244 | |
| 245 // Gets representation for a scale factor. | |
| 246 gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f); | |
| 247 | |
| 248 // Before the image representation is loaded, image should contain blank | |
| 249 // image representation. | |
| 250 EXPECT_TRUE(gfx::BitmapsAreEqual( | |
| 251 representation.sk_bitmap(), | |
| 252 CreateBlankBitmapForScale(16, ui::SCALE_FACTOR_100P))); | |
| 253 | |
| 254 WaitForImageLoad(); | |
| 255 EXPECT_EQ(1, ImageLoadedCount()); | |
| 256 ASSERT_EQ(1u, image.image_skia().image_reps().size()); | |
| 257 | |
| 258 representation = image.image_skia().GetRepresentation(1.0f); | |
| 259 | |
| 260 // We should get the right representation now. | |
| 261 EXPECT_TRUE(gfx::BitmapsAreEqual(representation.sk_bitmap(), bitmap_16)); | |
| 262 EXPECT_EQ(16, representation.pixel_width()); | |
| 263 | |
| 264 // Gets representation for an additional scale factor. | |
| 265 representation = image.image_skia().GetRepresentation(2.0f); | |
| 266 | |
| 267 EXPECT_TRUE(gfx::BitmapsAreEqual( | |
| 268 representation.sk_bitmap(), | |
| 269 CreateBlankBitmapForScale(16, ui::SCALE_FACTOR_200P))); | |
| 270 | |
| 271 WaitForImageLoad(); | |
| 272 EXPECT_EQ(1, ImageLoadedCount()); | |
| 273 ASSERT_EQ(2u, image.image_skia().image_reps().size()); | |
| 274 | |
| 275 representation = image.image_skia().GetRepresentation(2.0f); | |
| 276 | |
| 277 // Image should have been resized. | |
| 278 EXPECT_EQ(32, representation.pixel_width()); | |
| 279 EXPECT_TRUE(gfx::BitmapsAreEqual(representation.sk_bitmap(), | |
| 280 bitmap_48_resized_to_32)); | |
| 281 } | |
| 282 | |
| 283 // There is no resource with either exact or bigger size, but there is a smaller | |
| 284 // resource. | |
| 285 TEST_F(ExtensionIconImageTest, FallbackToSmallerWhenNoBigger) { | |
| 286 std::vector<ui::ScaleFactor> supported_factors; | |
| 287 supported_factors.push_back(ui::SCALE_FACTOR_100P); | |
| 288 supported_factors.push_back(ui::SCALE_FACTOR_200P); | |
| 289 ui::test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors); | |
| 290 scoped_ptr<Profile> profile(new TestingProfile()); | |
| 291 scoped_refptr<Extension> extension(CreateExtension( | |
| 292 "extension_icon_image", Manifest::INVALID_LOCATION)); | |
| 293 ASSERT_TRUE(extension.get() != NULL); | |
| 294 | |
| 295 gfx::ImageSkia default_icon = GetDefaultIcon(); | |
| 296 | |
| 297 // Load images we expect to find as representations in icon_image, so we | |
| 298 // can later use them to validate icon_image. | |
| 299 SkBitmap bitmap_48 = GetTestBitmap(extension.get(), "48.png", 48); | |
| 300 ASSERT_FALSE(bitmap_48.empty()); | |
| 301 | |
| 302 IconImage image(profile.get(), | |
| 303 extension.get(), | |
| 304 extensions::IconsInfo::GetIcons(extension.get()), | |
| 305 32, | |
| 306 default_icon, | |
| 307 this); | |
| 308 | |
| 309 gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(2.0f); | |
| 310 | |
| 311 WaitForImageLoad(); | |
| 312 EXPECT_EQ(1, ImageLoadedCount()); | |
| 313 ASSERT_EQ(1u, image.image_skia().image_reps().size()); | |
| 314 | |
| 315 representation = image.image_skia().GetRepresentation(2.0f); | |
| 316 | |
| 317 // We should have loaded the biggest smaller resource resized to the actual | |
| 318 // size. | |
| 319 EXPECT_EQ(2.0f, representation.scale()); | |
| 320 EXPECT_EQ(64, representation.pixel_width()); | |
| 321 EXPECT_TRUE(gfx::BitmapsAreEqual(representation.sk_bitmap(), | |
| 322 EnsureBitmapSize(bitmap_48, 64))); | |
| 323 } | |
| 324 | |
| 325 // There is no resource with exact size, but there is a smaller and a bigger | |
| 326 // one. Requested size is smaller than 32 though, so the smaller resource should | |
| 327 // be loaded. | |
| 328 TEST_F(ExtensionIconImageTest, FallbackToSmaller) { | |
| 329 scoped_ptr<Profile> profile(new TestingProfile()); | |
| 330 scoped_refptr<Extension> extension(CreateExtension( | |
| 331 "extension_icon_image", Manifest::INVALID_LOCATION)); | |
| 332 ASSERT_TRUE(extension.get() != NULL); | |
| 333 | |
| 334 gfx::ImageSkia default_icon = GetDefaultIcon(); | |
| 335 | |
| 336 // Load images we expect to find as representations in icon_image, so we | |
| 337 // can later use them to validate icon_image. | |
| 338 SkBitmap bitmap_16 = GetTestBitmap(extension.get(), "16.png", 16); | |
| 339 ASSERT_FALSE(bitmap_16.empty()); | |
| 340 | |
| 341 IconImage image(profile.get(), | |
| 342 extension.get(), | |
| 343 extensions::IconsInfo::GetIcons(extension.get()), | |
| 344 17, | |
| 345 default_icon, | |
| 346 this); | |
| 347 | |
| 348 gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f); | |
| 349 | |
| 350 WaitForImageLoad(); | |
| 351 EXPECT_EQ(1, ImageLoadedCount()); | |
| 352 ASSERT_EQ(1u, image.image_skia().image_reps().size()); | |
| 353 | |
| 354 representation = image.image_skia().GetRepresentation(1.0f); | |
| 355 | |
| 356 // We should have loaded smaller (resized) resource. | |
| 357 EXPECT_EQ(1.0f, representation.scale()); | |
| 358 EXPECT_EQ(17, representation.pixel_width()); | |
| 359 EXPECT_TRUE(gfx::BitmapsAreEqual(representation.sk_bitmap(), | |
| 360 EnsureBitmapSize(bitmap_16, 17))); | |
| 361 } | |
| 362 | |
| 363 // If resource set is empty, |GetRepresentation| should synchronously return | |
| 364 // default icon, without notifying observer of image change. | |
| 365 TEST_F(ExtensionIconImageTest, NoResources) { | |
| 366 scoped_ptr<Profile> profile(new TestingProfile()); | |
| 367 scoped_refptr<Extension> extension(CreateExtension( | |
| 368 "extension_icon_image", Manifest::INVALID_LOCATION)); | |
| 369 ASSERT_TRUE(extension.get() != NULL); | |
| 370 | |
| 371 ExtensionIconSet empty_icon_set; | |
| 372 gfx::ImageSkia default_icon = GetDefaultIcon(); | |
| 373 | |
| 374 const int kRequestedSize = 24; | |
| 375 IconImage image(profile.get(), | |
| 376 extension.get(), | |
| 377 empty_icon_set, | |
| 378 kRequestedSize, | |
| 379 default_icon, | |
| 380 this); | |
| 381 | |
| 382 gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f); | |
| 383 EXPECT_TRUE(gfx::BitmapsAreEqual( | |
| 384 representation.sk_bitmap(), | |
| 385 EnsureBitmapSize( | |
| 386 default_icon.GetRepresentation(1.0f).sk_bitmap(), | |
| 387 kRequestedSize))); | |
| 388 | |
| 389 EXPECT_EQ(0, ImageLoadedCount()); | |
| 390 // We should have a default icon representation. | |
| 391 ASSERT_EQ(1u, image.image_skia().image_reps().size()); | |
| 392 | |
| 393 representation = image.image_skia().GetRepresentation(1.0f); | |
| 394 EXPECT_TRUE(gfx::BitmapsAreEqual( | |
| 395 representation.sk_bitmap(), | |
| 396 EnsureBitmapSize( | |
| 397 default_icon.GetRepresentation(1.0f).sk_bitmap(), | |
| 398 kRequestedSize))); | |
| 399 } | |
| 400 | |
| 401 // If resource set is invalid, image load should be done asynchronously and | |
| 402 // the observer should be notified when it's done. |GetRepresentation| should | |
| 403 // return the default icon representation once image load is done. | |
| 404 TEST_F(ExtensionIconImageTest, InvalidResource) { | |
| 405 scoped_ptr<Profile> profile(new TestingProfile()); | |
| 406 scoped_refptr<Extension> extension(CreateExtension( | |
| 407 "extension_icon_image", Manifest::INVALID_LOCATION)); | |
| 408 ASSERT_TRUE(extension.get() != NULL); | |
| 409 | |
| 410 const int kInvalidIconSize = 24; | |
| 411 ExtensionIconSet invalid_icon_set; | |
| 412 invalid_icon_set.Add(kInvalidIconSize, "invalid.png"); | |
| 413 | |
| 414 gfx::ImageSkia default_icon = GetDefaultIcon(); | |
| 415 | |
| 416 IconImage image(profile.get(), | |
| 417 extension.get(), | |
| 418 invalid_icon_set, | |
| 419 kInvalidIconSize, | |
| 420 default_icon, | |
| 421 this); | |
| 422 | |
| 423 gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f); | |
| 424 EXPECT_TRUE(gfx::BitmapsAreEqual( | |
| 425 representation.sk_bitmap(), | |
| 426 CreateBlankBitmapForScale(kInvalidIconSize, ui::SCALE_FACTOR_100P))); | |
| 427 | |
| 428 WaitForImageLoad(); | |
| 429 EXPECT_EQ(1, ImageLoadedCount()); | |
| 430 // We should have default icon representation now. | |
| 431 ASSERT_EQ(1u, image.image_skia().image_reps().size()); | |
| 432 | |
| 433 representation = image.image_skia().GetRepresentation(1.0f); | |
| 434 EXPECT_TRUE(gfx::BitmapsAreEqual( | |
| 435 representation.sk_bitmap(), | |
| 436 EnsureBitmapSize( | |
| 437 default_icon.GetRepresentation(1.0f).sk_bitmap(), | |
| 438 kInvalidIconSize))); | |
| 439 } | |
| 440 | |
| 441 // Test that IconImage works with lazily (but synchronously) created default | |
| 442 // icon when IconImage returns synchronously. | |
| 443 TEST_F(ExtensionIconImageTest, LazyDefaultIcon) { | |
| 444 scoped_ptr<Profile> profile(new TestingProfile()); | |
| 445 scoped_refptr<Extension> extension(CreateExtension( | |
| 446 "extension_icon_image", Manifest::INVALID_LOCATION)); | |
| 447 ASSERT_TRUE(extension.get() != NULL); | |
| 448 | |
| 449 gfx::ImageSkia default_icon = GetDefaultIcon(); | |
| 450 gfx::ImageSkia lazy_default_icon(new MockImageSkiaSource(default_icon), | |
| 451 default_icon.size()); | |
| 452 | |
| 453 ExtensionIconSet empty_icon_set; | |
| 454 | |
| 455 const int kRequestedSize = 128; | |
| 456 IconImage image(profile.get(), | |
| 457 extension.get(), | |
| 458 empty_icon_set, | |
| 459 kRequestedSize, | |
| 460 lazy_default_icon, | |
| 461 this); | |
| 462 | |
| 463 ASSERT_FALSE(lazy_default_icon.HasRepresentation(1.0f)); | |
| 464 | |
| 465 gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f); | |
| 466 | |
| 467 // The resouce set is empty, so we should get the result right away. | |
| 468 EXPECT_TRUE(lazy_default_icon.HasRepresentation(1.0f)); | |
| 469 EXPECT_TRUE(gfx::BitmapsAreEqual( | |
| 470 representation.sk_bitmap(), | |
| 471 EnsureBitmapSize( | |
| 472 default_icon.GetRepresentation(1.0f).sk_bitmap(), | |
| 473 kRequestedSize))); | |
| 474 | |
| 475 // We should have a default icon representation. | |
| 476 ASSERT_EQ(1u, image.image_skia().image_reps().size()); | |
| 477 } | |
| 478 | |
| 479 // Test that IconImage works with lazily (but synchronously) created default | |
| 480 // icon when IconImage returns asynchronously. | |
| 481 TEST_F(ExtensionIconImageTest, LazyDefaultIcon_AsyncIconImage) { | |
| 482 scoped_ptr<Profile> profile(new TestingProfile()); | |
| 483 scoped_refptr<Extension> extension(CreateExtension( | |
| 484 "extension_icon_image", Manifest::INVALID_LOCATION)); | |
| 485 ASSERT_TRUE(extension.get() != NULL); | |
| 486 | |
| 487 gfx::ImageSkia default_icon = GetDefaultIcon(); | |
| 488 gfx::ImageSkia lazy_default_icon(new MockImageSkiaSource(default_icon), | |
| 489 default_icon.size()); | |
| 490 | |
| 491 const int kInvalidIconSize = 24; | |
| 492 ExtensionIconSet invalid_icon_set; | |
| 493 invalid_icon_set.Add(kInvalidIconSize, "invalid.png"); | |
| 494 | |
| 495 IconImage image(profile.get(), | |
| 496 extension.get(), | |
| 497 invalid_icon_set, | |
| 498 kInvalidIconSize, | |
| 499 lazy_default_icon, | |
| 500 this); | |
| 501 | |
| 502 ASSERT_FALSE(lazy_default_icon.HasRepresentation(1.0f)); | |
| 503 | |
| 504 gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f); | |
| 505 | |
| 506 WaitForImageLoad(); | |
| 507 EXPECT_EQ(1, ImageLoadedCount()); | |
| 508 // We should have default icon representation now. | |
| 509 ASSERT_EQ(1u, image.image_skia().image_reps().size()); | |
| 510 | |
| 511 EXPECT_TRUE(lazy_default_icon.HasRepresentation(1.0f)); | |
| 512 | |
| 513 representation = image.image_skia().GetRepresentation(1.0f); | |
| 514 EXPECT_TRUE(gfx::BitmapsAreEqual( | |
| 515 representation.sk_bitmap(), | |
| 516 EnsureBitmapSize( | |
| 517 default_icon.GetRepresentation(1.0f).sk_bitmap(), | |
| 518 kInvalidIconSize))); | |
| 519 } | |
| 520 | |
| 521 // Tests behavior of image created by IconImage after IconImage host goes | |
| 522 // away. The image should still return loaded representations. If requested | |
| 523 // representation was not loaded while IconImage host was around, transparent | |
| 524 // representations should be returned. | |
| 525 TEST_F(ExtensionIconImageTest, IconImageDestruction) { | |
| 526 scoped_ptr<Profile> profile(new TestingProfile()); | |
| 527 scoped_refptr<Extension> extension(CreateExtension( | |
| 528 "extension_icon_image", Manifest::INVALID_LOCATION)); | |
| 529 ASSERT_TRUE(extension.get() != NULL); | |
| 530 | |
| 531 gfx::ImageSkia default_icon = GetDefaultIcon(); | |
| 532 | |
| 533 // Load images we expect to find as representations in icon_image, so we | |
| 534 // can later use them to validate icon_image. | |
| 535 SkBitmap bitmap_16 = GetTestBitmap(extension.get(), "16.png", 16); | |
| 536 ASSERT_FALSE(bitmap_16.empty()); | |
| 537 | |
| 538 scoped_ptr<IconImage> image( | |
| 539 new IconImage(profile.get(), | |
| 540 extension.get(), | |
| 541 extensions::IconsInfo::GetIcons(extension.get()), | |
| 542 16, | |
| 543 default_icon, | |
| 544 this)); | |
| 545 | |
| 546 // Load an image representation. | |
| 547 gfx::ImageSkiaRep representation = | |
| 548 image->image_skia().GetRepresentation(1.0f); | |
| 549 | |
| 550 WaitForImageLoad(); | |
| 551 EXPECT_EQ(1, ImageLoadedCount()); | |
| 552 ASSERT_EQ(1u, image->image_skia().image_reps().size()); | |
| 553 | |
| 554 // Stash loaded image skia, and destroy |image|. | |
| 555 gfx::ImageSkia image_skia = image->image_skia(); | |
| 556 image.reset(); | |
| 557 extension = NULL; | |
| 558 | |
| 559 // Image skia should still be able to get previously loaded representation. | |
| 560 representation = image_skia.GetRepresentation(1.0f); | |
| 561 | |
| 562 EXPECT_EQ(1.0f, representation.scale()); | |
| 563 EXPECT_EQ(16, representation.pixel_width()); | |
| 564 EXPECT_TRUE(gfx::BitmapsAreEqual(representation.sk_bitmap(), bitmap_16)); | |
| 565 | |
| 566 // When requesting another representation, we should not crash and return some | |
| 567 // image of the size. It could be blank or a rescale from the existing 1.0f | |
| 568 // icon. | |
| 569 representation = image_skia.GetRepresentation(2.0f); | |
| 570 | |
| 571 EXPECT_EQ(16, representation.GetWidth()); | |
| 572 EXPECT_EQ(16, representation.GetHeight()); | |
| 573 EXPECT_EQ(2.0f, representation.scale()); | |
| 574 } | |
| OLD | NEW |