Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / base / resource / resource_bundle_unittest.cc
blobcf4914730aaa5eb547f88a82ca3e65636496fedc
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.
5 #include "ui/base/resource/resource_bundle.h"
7 #include "base/base_paths.h"
8 #include "base/big_endian.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/logging.h"
13 #include "base/memory/ref_counted_memory.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/skia/include/core/SkBitmap.h"
18 #include "ui/base/layout.h"
19 #include "ui/base/resource/data_pack.h"
20 #include "ui/gfx/codec/png_codec.h"
21 #include "ui/gfx/font_list.h"
22 #include "ui/gfx/image/image_skia.h"
23 #include "ui/resources/grit/ui_resources.h"
24 #include "ui/strings/grit/app_locale_settings.h"
26 #if defined(OS_WIN)
27 #include "ui/gfx/win/dpi.h"
28 #endif
30 using ::testing::_;
31 using ::testing::Between;
32 using ::testing::Property;
33 using ::testing::Return;
34 using ::testing::ReturnArg;
36 namespace ui {
38 extern const char kSamplePakContents[];
39 extern const size_t kSamplePakSize;
40 extern const char kSamplePakContents2x[];
41 extern const size_t kSamplePakSize2x;
42 extern const char kEmptyPakContents[];
43 extern const size_t kEmptyPakSize;
45 namespace {
47 const unsigned char kPngMagic[8] = { 0x89, 'P', 'N', 'G', 13, 10, 26, 10 };
48 const size_t kPngChunkMetadataSize = 12;
49 const unsigned char kPngIHDRChunkType[4] = { 'I', 'H', 'D', 'R' };
51 // Custom chunk that GRIT adds to PNG to indicate that it could not find a
52 // bitmap at the requested scale factor and fell back to 1x.
53 const unsigned char kPngScaleChunk[12] = { 0x00, 0x00, 0x00, 0x00,
54 'c', 's', 'C', 'l',
55 0xc1, 0x30, 0x60, 0x4d };
57 // Mock for the ResourceBundle::Delegate class.
58 class MockResourceBundleDelegate : public ui::ResourceBundle::Delegate {
59 public:
60 MockResourceBundleDelegate() {
62 ~MockResourceBundleDelegate() override {
65 MOCK_METHOD2(GetPathForResourcePack, base::FilePath(
66 const base::FilePath& pack_path, ui::ScaleFactor scale_factor));
67 MOCK_METHOD2(GetPathForLocalePack, base::FilePath(
68 const base::FilePath& pack_path, const std::string& locale));
69 MOCK_METHOD1(GetImageNamed, gfx::Image(int resource_id));
70 MOCK_METHOD2(GetNativeImageNamed,
71 gfx::Image(int resource_id,
72 ui::ResourceBundle::ImageRTL rtl));
73 MOCK_METHOD2(LoadDataResourceBytes,
74 base::RefCountedStaticMemory*(int resource_id,
75 ui::ScaleFactor scale_factor));
76 MOCK_METHOD2(GetRawDataResourceMock, base::StringPiece(
77 int resource_id,
78 ui::ScaleFactor scale_factor));
79 bool GetRawDataResource(int resource_id,
80 ui::ScaleFactor scale_factor,
81 base::StringPiece* value) override {
82 *value = GetRawDataResourceMock(resource_id, scale_factor);
83 return true;
85 MOCK_METHOD1(GetLocalizedStringMock, base::string16(int message_id));
86 bool GetLocalizedString(int message_id,
87 base::string16* value) override {
88 *value = GetLocalizedStringMock(message_id);
89 return true;
91 MOCK_METHOD1(GetFontMock,
92 gfx::Font*(ui::ResourceBundle::FontStyle style));
93 scoped_ptr<gfx::Font> GetFont(ui::ResourceBundle::FontStyle style) override {
94 return make_scoped_ptr(GetFontMock(style));
98 // Returns |bitmap_data| with |custom_chunk| inserted after the IHDR chunk.
99 void AddCustomChunk(const base::StringPiece& custom_chunk,
100 std::vector<unsigned char>* bitmap_data) {
101 EXPECT_LT(arraysize(kPngMagic) + kPngChunkMetadataSize, bitmap_data->size());
102 EXPECT_TRUE(std::equal(
103 bitmap_data->begin(),
104 bitmap_data->begin() + arraysize(kPngMagic),
105 kPngMagic));
106 std::vector<unsigned char>::iterator ihdr_start =
107 bitmap_data->begin() + arraysize(kPngMagic);
108 char ihdr_length_data[sizeof(uint32)];
109 for (size_t i = 0; i < sizeof(uint32); ++i)
110 ihdr_length_data[i] = *(ihdr_start + i);
111 uint32 ihdr_chunk_length = 0;
112 base::ReadBigEndian(reinterpret_cast<char*>(ihdr_length_data),
113 &ihdr_chunk_length);
114 EXPECT_TRUE(std::equal(
115 ihdr_start + sizeof(uint32),
116 ihdr_start + sizeof(uint32) + sizeof(kPngIHDRChunkType),
117 kPngIHDRChunkType));
119 bitmap_data->insert(ihdr_start + kPngChunkMetadataSize + ihdr_chunk_length,
120 custom_chunk.begin(), custom_chunk.end());
123 // Creates datapack at |path| with a single bitmap at resource ID 3
124 // which is |edge_size|x|edge_size| pixels.
125 // If |custom_chunk| is non empty, adds it after the IHDR chunk
126 // in the encoded bitmap data.
127 void CreateDataPackWithSingleBitmap(const base::FilePath& path,
128 int edge_size,
129 const base::StringPiece& custom_chunk) {
130 SkBitmap bitmap;
131 bitmap.allocN32Pixels(edge_size, edge_size);
132 bitmap.eraseColor(SK_ColorWHITE);
133 std::vector<unsigned char> bitmap_data;
134 EXPECT_TRUE(gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &bitmap_data));
136 if (custom_chunk.size() > 0)
137 AddCustomChunk(custom_chunk, &bitmap_data);
139 std::map<uint16, base::StringPiece> resources;
140 resources[3u] = base::StringPiece(
141 reinterpret_cast<const char*>(&bitmap_data[0]), bitmap_data.size());
142 DataPack::WritePack(path, resources, ui::DataPack::BINARY);
145 } // namespace
147 class ResourceBundleTest : public testing::Test {
148 public:
149 ResourceBundleTest() : resource_bundle_(NULL) {
152 ~ResourceBundleTest() override {}
154 // Overridden from testing::Test:
155 void TearDown() override { delete resource_bundle_; }
157 // Returns new ResoureBundle with the specified |delegate|. The
158 // ResourceBundleTest class manages the lifetime of the returned
159 // ResourceBundle.
160 ResourceBundle* CreateResourceBundle(ResourceBundle::Delegate* delegate) {
161 DCHECK(!resource_bundle_);
163 resource_bundle_ = new ResourceBundle(delegate);
164 return resource_bundle_;
167 protected:
168 ResourceBundle* resource_bundle_;
170 private:
171 DISALLOW_COPY_AND_ASSIGN(ResourceBundleTest);
174 TEST_F(ResourceBundleTest, DelegateGetPathForResourcePack) {
175 MockResourceBundleDelegate delegate;
176 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
178 base::FilePath pack_path(FILE_PATH_LITERAL("/path/to/test_path.pak"));
179 ui::ScaleFactor pack_scale_factor = ui::SCALE_FACTOR_200P;
181 EXPECT_CALL(delegate,
182 GetPathForResourcePack(
183 Property(&base::FilePath::value, pack_path.value()),
184 pack_scale_factor))
185 .Times(1)
186 .WillOnce(Return(pack_path));
188 resource_bundle->AddDataPackFromPath(pack_path, pack_scale_factor);
191 #if defined(OS_LINUX)
192 // Fails consistently on Linux: crbug.com/161902
193 #define MAYBE_DelegateGetPathForLocalePack DISABLED_DelegateGetPathForLocalePack
194 #else
195 #define MAYBE_DelegateGetPathForLocalePack DelegateGetPathForLocalePack
196 #endif
197 TEST_F(ResourceBundleTest, MAYBE_DelegateGetPathForLocalePack) {
198 MockResourceBundleDelegate delegate;
199 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
201 std::string locale = "en-US";
203 // Cancel the load.
204 EXPECT_CALL(delegate, GetPathForLocalePack(_, locale))
205 .Times(2)
206 .WillRepeatedly(Return(base::FilePath()))
207 .RetiresOnSaturation();
209 EXPECT_FALSE(resource_bundle->LocaleDataPakExists(locale));
210 EXPECT_EQ("", resource_bundle->LoadLocaleResources(locale));
212 // Allow the load to proceed.
213 EXPECT_CALL(delegate, GetPathForLocalePack(_, locale))
214 .Times(2)
215 .WillRepeatedly(ReturnArg<0>());
217 EXPECT_TRUE(resource_bundle->LocaleDataPakExists(locale));
218 EXPECT_EQ(locale, resource_bundle->LoadLocaleResources(locale));
221 TEST_F(ResourceBundleTest, DelegateGetImageNamed) {
222 MockResourceBundleDelegate delegate;
223 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
225 gfx::Image empty_image = resource_bundle->GetEmptyImage();
226 int resource_id = 5;
228 EXPECT_CALL(delegate, GetImageNamed(resource_id))
229 .Times(1)
230 .WillOnce(Return(empty_image));
232 gfx::Image result = resource_bundle->GetImageNamed(resource_id);
233 EXPECT_EQ(empty_image.ToSkBitmap(), result.ToSkBitmap());
236 TEST_F(ResourceBundleTest, DelegateGetNativeImageNamed) {
237 MockResourceBundleDelegate delegate;
238 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
240 gfx::Image empty_image = resource_bundle->GetEmptyImage();
241 int resource_id = 5;
243 // Some platforms delegate GetNativeImageNamed calls to GetImageNamed.
244 EXPECT_CALL(delegate, GetImageNamed(resource_id))
245 .Times(Between(0, 1))
246 .WillOnce(Return(empty_image));
247 EXPECT_CALL(delegate,
248 GetNativeImageNamed(resource_id, ui::ResourceBundle::RTL_DISABLED))
249 .Times(Between(0, 1))
250 .WillOnce(Return(empty_image));
252 gfx::Image result = resource_bundle->GetNativeImageNamed(resource_id);
253 EXPECT_EQ(empty_image.ToSkBitmap(), result.ToSkBitmap());
256 TEST_F(ResourceBundleTest, DelegateLoadDataResourceBytes) {
257 MockResourceBundleDelegate delegate;
258 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
260 // Create the data resource for testing purposes.
261 unsigned char data[] = "My test data";
262 scoped_refptr<base::RefCountedStaticMemory> static_memory(
263 new base::RefCountedStaticMemory(data, sizeof(data)));
265 int resource_id = 5;
266 ui::ScaleFactor scale_factor = ui::SCALE_FACTOR_NONE;
268 EXPECT_CALL(delegate, LoadDataResourceBytes(resource_id, scale_factor))
269 .Times(1).WillOnce(Return(static_memory.get()));
271 scoped_refptr<base::RefCountedStaticMemory> result =
272 resource_bundle->LoadDataResourceBytesForScale(resource_id, scale_factor);
273 EXPECT_EQ(static_memory, result);
276 TEST_F(ResourceBundleTest, DelegateGetRawDataResource) {
277 MockResourceBundleDelegate delegate;
278 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
280 // Create the string piece for testing purposes.
281 char data[] = "My test data";
282 base::StringPiece string_piece(data);
284 int resource_id = 5;
286 EXPECT_CALL(delegate, GetRawDataResourceMock(
287 resource_id, ui::SCALE_FACTOR_NONE))
288 .Times(1)
289 .WillOnce(Return(string_piece));
291 base::StringPiece result = resource_bundle->GetRawDataResource(
292 resource_id);
293 EXPECT_EQ(string_piece.data(), result.data());
296 TEST_F(ResourceBundleTest, DelegateGetLocalizedString) {
297 MockResourceBundleDelegate delegate;
298 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
300 base::string16 data = base::ASCIIToUTF16("My test data");
301 int resource_id = 5;
303 EXPECT_CALL(delegate, GetLocalizedStringMock(resource_id))
304 .Times(1)
305 .WillOnce(Return(data));
307 base::string16 result = resource_bundle->GetLocalizedString(resource_id);
308 EXPECT_EQ(data, result);
311 TEST_F(ResourceBundleTest, OverrideStringResource) {
312 ResourceBundle* resource_bundle = CreateResourceBundle(NULL);
314 base::string16 data = base::ASCIIToUTF16("My test data");
315 int resource_id = 5;
317 base::string16 result = resource_bundle->GetLocalizedString(resource_id);
318 EXPECT_EQ(base::string16(), result);
320 resource_bundle->OverrideLocaleStringResource(resource_id, data);
322 result = resource_bundle->GetLocalizedString(resource_id);
323 EXPECT_EQ(data, result);
326 TEST_F(ResourceBundleTest, DelegateGetLocalizedStringWithOverride) {
327 MockResourceBundleDelegate delegate;
328 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
330 base::string16 delegate_data = base::ASCIIToUTF16("My delegate data");
331 int resource_id = 5;
333 EXPECT_CALL(delegate, GetLocalizedStringMock(resource_id)).Times(1).WillOnce(
334 Return(delegate_data));
336 base::string16 override_data = base::ASCIIToUTF16("My override data");
338 base::string16 result = resource_bundle->GetLocalizedString(resource_id);
339 EXPECT_EQ(delegate_data, result);
342 #if (defined(USE_OZONE) && !defined(USE_PANGO)) || defined(OS_ANDROID)
343 #define MAYBE_DelegateGetFontList DISABLED_DelegateGetFontList
344 #else
345 #define MAYBE_DelegateGetFontList DelegateGetFontList
346 #endif
348 TEST_F(ResourceBundleTest, MAYBE_DelegateGetFontList) {
349 MockResourceBundleDelegate delegate;
350 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
352 // Should be called once for each font type. When we return NULL the default
353 // font will be created.
354 gfx::Font* test_font = NULL;
355 EXPECT_CALL(delegate, GetFontMock(_))
356 .Times(8)
357 .WillRepeatedly(Return(test_font));
359 const gfx::FontList* font_list =
360 &resource_bundle->GetFontList(ui::ResourceBundle::BaseFont);
361 EXPECT_TRUE(font_list);
363 const gfx::Font* font =
364 &resource_bundle->GetFont(ui::ResourceBundle::BaseFont);
365 EXPECT_TRUE(font);
368 #if defined(OS_CHROMEOS) && defined(USE_PANGO)
369 TEST_F(ResourceBundleTest, FontListReload) {
370 MockResourceBundleDelegate delegate;
371 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
373 // Should be called once for each font type. When we return NULL the default
374 // font will be created.
375 gfx::Font* test_font = nullptr;
376 EXPECT_CALL(delegate, GetFontMock(_))
377 .Times(16)
378 .WillRepeatedly(Return(test_font));
380 EXPECT_CALL(delegate, GetLocalizedStringMock(IDS_UI_FONT_FAMILY_CROS))
381 .WillOnce(Return(base::UTF8ToUTF16("test font, 12px")));
382 resource_bundle->ReloadFonts();
383 // Don't test the font name; it'll get mapped to something else by Fontconfig.
384 EXPECT_EQ(12, gfx::FontList().GetPrimaryFont().GetFontSize());
385 EXPECT_EQ(gfx::Font::NORMAL, gfx::FontList().GetPrimaryFont().GetStyle());
387 EXPECT_CALL(delegate, GetLocalizedStringMock(IDS_UI_FONT_FAMILY_CROS))
388 .WillOnce(Return(base::UTF8ToUTF16("test font 2, Bold 10px")));
389 resource_bundle->ReloadFonts();
390 EXPECT_EQ(10, gfx::FontList().GetPrimaryFont().GetFontSize());
391 EXPECT_EQ(gfx::Font::BOLD, gfx::FontList().GetPrimaryFont().GetStyle());
393 #endif
395 TEST_F(ResourceBundleTest, LocaleDataPakExists) {
396 ResourceBundle* resource_bundle = CreateResourceBundle(NULL);
398 // Check that ResourceBundle::LocaleDataPakExists returns the correct results.
399 EXPECT_TRUE(resource_bundle->LocaleDataPakExists("en-US"));
400 EXPECT_FALSE(resource_bundle->LocaleDataPakExists("not_a_real_locale"));
403 class ResourceBundleImageTest : public ResourceBundleTest {
404 public:
405 ResourceBundleImageTest() {}
407 ~ResourceBundleImageTest() override {}
409 void SetUp() override {
410 // Create a temporary directory to write test resource bundles to.
411 ASSERT_TRUE(dir_.CreateUniqueTempDir());
414 // Returns resource bundle which uses an empty data pak for locale data.
415 ui::ResourceBundle* CreateResourceBundleWithEmptyLocalePak() {
416 // Write an empty data pak for locale data.
417 const base::FilePath& locale_path = dir_path().Append(
418 FILE_PATH_LITERAL("locale.pak"));
419 EXPECT_EQ(base::WriteFile(locale_path, kEmptyPakContents, kEmptyPakSize),
420 static_cast<int>(kEmptyPakSize));
422 ui::ResourceBundle* resource_bundle = CreateResourceBundle(NULL);
424 // Load the empty locale data pak.
425 resource_bundle->LoadTestResources(base::FilePath(), locale_path);
426 return resource_bundle;
429 // Returns the path of temporary directory to write test data packs into.
430 const base::FilePath& dir_path() { return dir_.path(); }
432 // Returns the number of DataPacks managed by |resource_bundle|.
433 size_t NumDataPacksInResourceBundle(ResourceBundle* resource_bundle) {
434 DCHECK(resource_bundle);
435 return resource_bundle->data_packs_.size();
438 // Returns the number of DataPacks managed by |resource_bundle| which are
439 // flagged as containing only material design resources.
440 size_t NumMaterialDesignDataPacksInResourceBundle(
441 ResourceBundle* resource_bundle) {
442 DCHECK(resource_bundle);
443 size_t num_material_packs = 0;
444 for (size_t i = 0; i < resource_bundle->data_packs_.size(); i++) {
445 if (resource_bundle->data_packs_[i]->HasOnlyMaterialDesignAssets())
446 num_material_packs++;
449 return num_material_packs;
452 private:
453 scoped_ptr<DataPack> locale_pack_;
454 base::ScopedTempDir dir_;
456 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageTest);
459 // Verify that we don't crash when trying to load a resource that is not found.
460 // In some cases, we fail to mmap resources.pak, but try to keep going anyway.
461 TEST_F(ResourceBundleImageTest, LoadDataResourceBytes) {
462 base::FilePath data_path = dir_path().Append(FILE_PATH_LITERAL("sample.pak"));
464 // Dump contents into the pak files.
465 ASSERT_EQ(base::WriteFile(data_path, kEmptyPakContents,
466 kEmptyPakSize), static_cast<int>(kEmptyPakSize));
468 // Create a resource bundle from the file.
469 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
470 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
472 const int kUnfoundResourceId = 10000;
473 EXPECT_EQ(NULL, resource_bundle->LoadDataResourceBytes(
474 kUnfoundResourceId));
476 // Give a .pak file that doesn't exist so we will fail to load it.
477 resource_bundle->AddDataPackFromPath(
478 base::FilePath(FILE_PATH_LITERAL("non-existant-file.pak")),
479 ui::SCALE_FACTOR_NONE);
480 EXPECT_EQ(NULL, resource_bundle->LoadDataResourceBytes(
481 kUnfoundResourceId));
484 TEST_F(ResourceBundleImageTest, GetRawDataResource) {
485 base::FilePath data_path = dir_path().Append(FILE_PATH_LITERAL("sample.pak"));
486 base::FilePath data_2x_path =
487 dir_path().Append(FILE_PATH_LITERAL("sample_2x.pak"));
489 // Dump contents into the pak files.
490 ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents,
491 kSamplePakSize), static_cast<int>(kSamplePakSize));
492 ASSERT_EQ(base::WriteFile(data_2x_path, kSamplePakContents2x,
493 kSamplePakSize2x), static_cast<int>(kSamplePakSize2x));
495 // Load the regular and 2x pak files.
496 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
497 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
498 resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P);
500 // Resource ID 4 exists in both 1x and 2x paks, so we expect a different
501 // result when requesting the 2x scale.
502 EXPECT_EQ("this is id 4", resource_bundle->GetRawDataResourceForScale(4,
503 SCALE_FACTOR_100P));
504 EXPECT_EQ("this is id 4 2x", resource_bundle->GetRawDataResourceForScale(4,
505 SCALE_FACTOR_200P));
507 // Resource ID 6 only exists in the 1x pak so we expect the same resource
508 // for both scale factor requests.
509 EXPECT_EQ("this is id 6", resource_bundle->GetRawDataResourceForScale(6,
510 SCALE_FACTOR_100P));
511 EXPECT_EQ("this is id 6", resource_bundle->GetRawDataResourceForScale(6,
512 SCALE_FACTOR_200P));
515 // Test requesting image reps at various scale factors from the image returned
516 // via ResourceBundle::GetImageNamed().
517 TEST_F(ResourceBundleImageTest, GetImageNamed) {
518 #if defined(OS_WIN)
519 gfx::InitDeviceScaleFactor(2.0);
520 #endif
521 std::vector<ScaleFactor> supported_factors;
522 supported_factors.push_back(SCALE_FACTOR_100P);
523 supported_factors.push_back(SCALE_FACTOR_200P);
524 test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
525 base::FilePath data_1x_path = dir_path().AppendASCII("sample_1x.pak");
526 base::FilePath data_2x_path = dir_path().AppendASCII("sample_2x.pak");
528 // Create the pak files.
529 CreateDataPackWithSingleBitmap(data_1x_path, 10, base::StringPiece());
530 CreateDataPackWithSingleBitmap(data_2x_path, 20, base::StringPiece());
532 // Load the regular and 2x pak files.
533 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
534 resource_bundle->AddDataPackFromPath(data_1x_path, SCALE_FACTOR_100P);
535 resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P);
537 EXPECT_EQ(SCALE_FACTOR_200P, resource_bundle->GetMaxScaleFactor());
539 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
541 #if defined(OS_CHROMEOS) || defined(OS_WIN)
542 // ChromeOS/Windows load highest scale factor first.
543 EXPECT_EQ(ui::SCALE_FACTOR_200P,
544 GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
545 #else
546 EXPECT_EQ(ui::SCALE_FACTOR_100P,
547 GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
548 #endif
550 // Resource ID 3 exists in both 1x and 2x paks. Image reps should be
551 // available for both scale factors in |image_skia|.
552 gfx::ImageSkiaRep image_rep =
553 image_skia->GetRepresentation(
554 GetScaleForScaleFactor(ui::SCALE_FACTOR_100P));
555 EXPECT_EQ(ui::SCALE_FACTOR_100P, GetSupportedScaleFactor(image_rep.scale()));
556 image_rep =
557 image_skia->GetRepresentation(
558 GetScaleForScaleFactor(ui::SCALE_FACTOR_200P));
559 EXPECT_EQ(ui::SCALE_FACTOR_200P, GetSupportedScaleFactor(image_rep.scale()));
561 // The 1.4x pack was not loaded. Requesting the 1.4x resource should return
562 // either the 1x or the 2x resource.
563 image_rep = image_skia->GetRepresentation(
564 ui::GetScaleForScaleFactor(ui::SCALE_FACTOR_140P));
565 ui::ScaleFactor scale_factor = GetSupportedScaleFactor(image_rep.scale());
566 EXPECT_TRUE(scale_factor == ui::SCALE_FACTOR_100P ||
567 scale_factor == ui::SCALE_FACTOR_200P);
569 // ImageSkia scales image if the one for the requested scale factor is not
570 // available.
571 EXPECT_EQ(1.4f, image_skia->GetRepresentation(1.4f).scale());
574 // Verifies that the correct number of DataPacks managed by ResourceBundle
575 // are flagged as containing only material design assets.
576 TEST_F(ResourceBundleImageTest, CountMaterialDesignDataPacksInResourceBundle) {
577 ResourceBundle* resource_bundle = CreateResourceBundle(nullptr);
578 EXPECT_EQ(0u, NumDataPacksInResourceBundle(resource_bundle));
579 EXPECT_EQ(0u, NumMaterialDesignDataPacksInResourceBundle(resource_bundle));
581 // Add a non-material data pack.
582 base::FilePath default_path = dir_path().AppendASCII("default.pak");
583 CreateDataPackWithSingleBitmap(default_path, 10, base::StringPiece());
584 resource_bundle->AddDataPackFromPath(default_path, SCALE_FACTOR_100P);
585 EXPECT_EQ(1u, NumDataPacksInResourceBundle(resource_bundle));
586 EXPECT_EQ(0u, NumMaterialDesignDataPacksInResourceBundle(resource_bundle));
588 // Add a material data pack.
589 base::FilePath material_path1 = dir_path().AppendASCII("material1.pak");
590 CreateDataPackWithSingleBitmap(material_path1, 10, base::StringPiece());
591 resource_bundle->AddMaterialDesignDataPackFromPath(material_path1,
592 SCALE_FACTOR_100P);
593 EXPECT_EQ(2u, NumDataPacksInResourceBundle(resource_bundle));
594 EXPECT_EQ(1u, NumMaterialDesignDataPacksInResourceBundle(resource_bundle));
597 // Verifies that data packs containing material design resources are permitted
598 // to have resource IDs which are present within other data packs managed by
599 // ResourceBundle. This test passes if it does not trigger the DCHECK in
600 // DataPack::CheckForDuplicateResources().
601 TEST_F(ResourceBundleImageTest, NoCrashWithDuplicateMaterialDesignResources) {
602 // Create two data packs, each containing a single asset with the same ID.
603 base::FilePath default_path = dir_path().AppendASCII("default.pak");
604 base::FilePath material_path = dir_path().AppendASCII("material.pak");
605 CreateDataPackWithSingleBitmap(default_path, 10, base::StringPiece());
606 CreateDataPackWithSingleBitmap(material_path, 10, base::StringPiece());
608 // Should not crash.
609 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
610 resource_bundle->AddMaterialDesignDataPackFromPath(material_path,
611 SCALE_FACTOR_100P);
612 resource_bundle->AddDataPackFromPath(default_path, SCALE_FACTOR_100P);
615 // Verifies that ResourceBundle searches data pack A before data pack B for
616 // an asset if A was added to the ResourceBundle before B.
617 TEST_F(ResourceBundleImageTest, DataPackSearchOrder) {
618 // Create two .pak files, each containing a single image with the
619 // same asset ID but different sizes (note that the images must be
620 // different sizes in this test in order to correctly determine
621 // from which data pack the asset was pulled).
622 const int default_size = 10;
623 const int material_size = 16;
624 ASSERT_NE(default_size, material_size);
625 base::FilePath default_path = dir_path().AppendASCII("default.pak");
626 base::FilePath material_path = dir_path().AppendASCII("material.pak");
627 CreateDataPackWithSingleBitmap(default_path,
628 default_size,
629 base::StringPiece());
630 CreateDataPackWithSingleBitmap(material_path,
631 material_size,
632 base::StringPiece());
634 ScaleFactor scale_factor = SCALE_FACTOR_100P;
635 int expected_size = material_size;
636 #if defined(OS_IOS)
637 // iOS retina devices do not use 100P scaling. See crbug.com/298406.
638 scale_factor = SCALE_FACTOR_200P;
639 expected_size = material_size / 2;
640 #endif
642 // Load the 'material' data pack into ResourceBundle first.
643 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
644 resource_bundle->AddMaterialDesignDataPackFromPath(material_path,
645 scale_factor);
646 resource_bundle->AddDataPackFromPath(default_path, scale_factor);
648 // A request for the image with ID 3 should return the image from the material
649 // data pack.
650 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
651 const SkBitmap* bitmap = image_skia->bitmap();
652 ASSERT_TRUE(bitmap);
653 EXPECT_EQ(expected_size, bitmap->width());
654 EXPECT_EQ(expected_size, bitmap->height());
656 // A subsequent request for the image with ID 3 (i.e., after the image
657 // has been cached by ResourceBundle) should also return the image
658 // from the material data pack.
659 gfx::ImageSkia* image_skia2 = resource_bundle->GetImageSkiaNamed(3);
660 const SkBitmap* bitmap2 = image_skia2->bitmap();
661 ASSERT_TRUE(bitmap2);
662 EXPECT_EQ(expected_size, bitmap2->width());
663 EXPECT_EQ(expected_size, bitmap2->height());
666 // Test that GetImageNamed() behaves properly for images which GRIT has
667 // annotated as having fallen back to 1x.
668 TEST_F(ResourceBundleImageTest, GetImageNamedFallback1x) {
669 std::vector<ScaleFactor> supported_factors;
670 supported_factors.push_back(SCALE_FACTOR_100P);
671 supported_factors.push_back(SCALE_FACTOR_200P);
672 test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
673 base::FilePath data_path = dir_path().AppendASCII("sample.pak");
674 base::FilePath data_2x_path = dir_path().AppendASCII("sample_2x.pak");
676 // Create the pak files.
677 CreateDataPackWithSingleBitmap(data_path, 10, base::StringPiece());
678 // 2x data pack bitmap has custom chunk to indicate that the 2x bitmap is not
679 // available and that GRIT fell back to 1x.
680 CreateDataPackWithSingleBitmap(data_2x_path, 10, base::StringPiece(
681 reinterpret_cast<const char*>(kPngScaleChunk),
682 arraysize(kPngScaleChunk)));
684 // Load the regular and 2x pak files.
685 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
686 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
687 resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P);
689 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
691 // The image rep for 2x should be available. It should be resized to the
692 // proper 2x size.
693 gfx::ImageSkiaRep image_rep =
694 image_skia->GetRepresentation(GetScaleForScaleFactor(
695 ui::SCALE_FACTOR_200P));
696 EXPECT_EQ(ui::SCALE_FACTOR_200P, GetSupportedScaleFactor(image_rep.scale()));
697 EXPECT_EQ(20, image_rep.pixel_width());
698 EXPECT_EQ(20, image_rep.pixel_height());
701 #if defined(OS_WIN)
702 // Tests GetImageNamed() behaves properly when the size of a scaled image
703 // requires rounding as a result of using a non-integer scale factor.
704 // Scale factors of 140 and 1805 are Windows specific.
705 TEST_F(ResourceBundleImageTest, GetImageNamedFallback1xRounding) {
706 std::vector<ScaleFactor> supported_factors;
707 supported_factors.push_back(SCALE_FACTOR_100P);
708 supported_factors.push_back(SCALE_FACTOR_140P);
709 supported_factors.push_back(SCALE_FACTOR_180P);
710 test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
712 base::FilePath data_path = dir_path().AppendASCII("sample.pak");
713 base::FilePath data_140P_path = dir_path().AppendASCII("sample_140P.pak");
714 base::FilePath data_180P_path = dir_path().AppendASCII("sample_180P.pak");
716 CreateDataPackWithSingleBitmap(data_path, 8, base::StringPiece());
717 // Mark 140% and 180% images as requiring 1x fallback.
718 CreateDataPackWithSingleBitmap(data_140P_path, 8, base::StringPiece(
719 reinterpret_cast<const char*>(kPngScaleChunk),
720 arraysize(kPngScaleChunk)));
721 CreateDataPackWithSingleBitmap(data_180P_path, 8, base::StringPiece(
722 reinterpret_cast<const char*>(kPngScaleChunk),
723 arraysize(kPngScaleChunk)));
725 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
726 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
727 resource_bundle->AddDataPackFromPath(data_140P_path, SCALE_FACTOR_140P);
728 resource_bundle->AddDataPackFromPath(data_180P_path, SCALE_FACTOR_180P);
730 // Non-integer dimensions should be rounded up.
731 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
732 gfx::ImageSkiaRep image_rep =
733 image_skia->GetRepresentation(
734 GetScaleForScaleFactor(ui::SCALE_FACTOR_140P));
735 EXPECT_EQ(12, image_rep.pixel_width());
736 image_rep = image_skia->GetRepresentation(
737 GetScaleForScaleFactor(ui::SCALE_FACTOR_180P));
738 EXPECT_EQ(15, image_rep.pixel_width());
740 #endif
742 #if defined(OS_IOS)
743 // Fails on devices that have non-100P scaling. See crbug.com/298406
744 #define MAYBE_FallbackToNone DISABLED_FallbackToNone
745 #else
746 #define MAYBE_FallbackToNone FallbackToNone
747 #endif
748 TEST_F(ResourceBundleImageTest, MAYBE_FallbackToNone) {
749 base::FilePath data_default_path = dir_path().AppendASCII("sample.pak");
751 // Create the pak files.
752 CreateDataPackWithSingleBitmap(data_default_path, 10, base::StringPiece());
754 // Load the regular pak files only.
755 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
756 resource_bundle->AddDataPackFromPath(data_default_path, SCALE_FACTOR_NONE);
758 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
759 EXPECT_EQ(1u, image_skia->image_reps().size());
760 EXPECT_TRUE(image_skia->image_reps()[0].unscaled());
761 EXPECT_EQ(ui::SCALE_FACTOR_100P,
762 GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
765 } // namespace ui