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 |