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/base/resource/resource_bundle.h"
6
7 #include "base/base_paths.h"
8 #include "base/big_endian.h"
9 #include "base/file_util.h"
10 #include "base/files/file_path.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/path_service.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "grit/ui_resources.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/skia/include/core/SkBitmap.h"
20 #include "ui/base/layout.h"
21 #include "ui/base/resource/data_pack.h"
22 #include "ui/gfx/codec/png_codec.h"
23 #include "ui/gfx/image/image_skia.h"
24 #if defined(OS_WIN)
25 #include "ui/gfx/win/dpi.h"
26 #endif
27
28 using ::testing::_;
29 using ::testing::Between;
30 using ::testing::Property;
31 using ::testing::Return;
32 using ::testing::ReturnArg;
33
34 namespace ui {
35
36 extern const char kSamplePakContents[];
37 extern const size_t kSamplePakSize;
38 extern const char kSamplePakContents2x[];
39 extern const size_t kSamplePakSize2x;
40 extern const char kEmptyPakContents[];
41 extern const size_t kEmptyPakSize;
42
43 namespace {
44
45 const unsigned char kPngMagic[8] = { 0x89, 'P', 'N', 'G', 13, 10, 26, 10 };
46 const size_t kPngChunkMetadataSize = 12;
47 const unsigned char kPngIHDRChunkType[4] = { 'I', 'H', 'D', 'R' };
48
49 // Custom chunk that GRIT adds to PNG to indicate that it could not find a
50 // bitmap at the requested scale factor and fell back to 1x.
51 const unsigned char kPngScaleChunk[12] = { 0x00, 0x00, 0x00, 0x00,
52 'c', 's', 'C', 'l',
53 0xc1, 0x30, 0x60, 0x4d };
54
55 // Mock for the ResourceBundle::Delegate class.
56 class MockResourceBundleDelegate : public ui::ResourceBundle::Delegate {
57 public:
MockResourceBundleDelegate()58 MockResourceBundleDelegate() {
59 }
~MockResourceBundleDelegate()60 virtual ~MockResourceBundleDelegate() {
61 }
62
63 MOCK_METHOD2(GetPathForResourcePack, base::FilePath(
64 const base::FilePath& pack_path, ui::ScaleFactor scale_factor));
65 MOCK_METHOD2(GetPathForLocalePack, base::FilePath(
66 const base::FilePath& pack_path, const std::string& locale));
67 MOCK_METHOD1(GetImageNamed, gfx::Image(int resource_id));
68 MOCK_METHOD2(GetNativeImageNamed,
69 gfx::Image(int resource_id,
70 ui::ResourceBundle::ImageRTL rtl));
71 MOCK_METHOD2(LoadDataResourceBytes,
72 base::RefCountedStaticMemory*(int resource_id,
73 ui::ScaleFactor scale_factor));
74 MOCK_METHOD2(GetRawDataResourceMock, base::StringPiece(
75 int resource_id,
76 ui::ScaleFactor scale_factor));
GetRawDataResource(int resource_id,ui::ScaleFactor scale_factor,base::StringPiece * value)77 virtual bool GetRawDataResource(int resource_id,
78 ui::ScaleFactor scale_factor,
79 base::StringPiece* value) OVERRIDE {
80 *value = GetRawDataResourceMock(resource_id, scale_factor);
81 return true;
82 }
83 MOCK_METHOD1(GetLocalizedStringMock, base::string16(int message_id));
GetLocalizedString(int message_id,base::string16 * value)84 virtual bool GetLocalizedString(int message_id,
85 base::string16* value) OVERRIDE {
86 *value = GetLocalizedStringMock(message_id);
87 return true;
88 }
89 MOCK_METHOD1(GetFontMock,
90 gfx::Font*(ui::ResourceBundle::FontStyle style));
GetFont(ui::ResourceBundle::FontStyle style)91 virtual scoped_ptr<gfx::Font> GetFont(
92 ui::ResourceBundle::FontStyle style) OVERRIDE {
93 return scoped_ptr<gfx::Font>(GetFontMock(style));
94 }
95 };
96
97 // Returns |bitmap_data| with |custom_chunk| inserted after the IHDR chunk.
AddCustomChunk(const base::StringPiece & custom_chunk,std::vector<unsigned char> * bitmap_data)98 void AddCustomChunk(const base::StringPiece& custom_chunk,
99 std::vector<unsigned char>* bitmap_data) {
100 EXPECT_LT(arraysize(kPngMagic) + kPngChunkMetadataSize, bitmap_data->size());
101 EXPECT_TRUE(std::equal(
102 bitmap_data->begin(),
103 bitmap_data->begin() + arraysize(kPngMagic),
104 kPngMagic));
105 std::vector<unsigned char>::iterator ihdr_start =
106 bitmap_data->begin() + arraysize(kPngMagic);
107 char ihdr_length_data[sizeof(uint32)];
108 for (size_t i = 0; i < sizeof(uint32); ++i)
109 ihdr_length_data[i] = *(ihdr_start + i);
110 uint32 ihdr_chunk_length = 0;
111 base::ReadBigEndian(reinterpret_cast<char*>(ihdr_length_data),
112 &ihdr_chunk_length);
113 EXPECT_TRUE(std::equal(
114 ihdr_start + sizeof(uint32),
115 ihdr_start + sizeof(uint32) + sizeof(kPngIHDRChunkType),
116 kPngIHDRChunkType));
117
118 bitmap_data->insert(ihdr_start + kPngChunkMetadataSize + ihdr_chunk_length,
119 custom_chunk.begin(), custom_chunk.end());
120 }
121
122 // Creates datapack at |path| with a single bitmap at resource ID 3
123 // which is |edge_size|x|edge_size| pixels.
124 // If |custom_chunk| is non empty, adds it after the IHDR chunk
125 // in the encoded bitmap data.
CreateDataPackWithSingleBitmap(const base::FilePath & path,int edge_size,const base::StringPiece & custom_chunk)126 void CreateDataPackWithSingleBitmap(const base::FilePath& path,
127 int edge_size,
128 const base::StringPiece& custom_chunk) {
129 SkBitmap bitmap;
130 bitmap.setConfig(SkBitmap::kARGB_8888_Config, edge_size, edge_size);
131 bitmap.allocPixels();
132 bitmap.eraseColor(SK_ColorWHITE);
133 std::vector<unsigned char> bitmap_data;
134 EXPECT_TRUE(gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &bitmap_data));
135
136 if (custom_chunk.size() > 0)
137 AddCustomChunk(custom_chunk, &bitmap_data);
138
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);
143 }
144
145 } // namespace
146
147 class ResourceBundleTest : public testing::Test {
148 public:
ResourceBundleTest()149 ResourceBundleTest() : resource_bundle_(NULL) {
150 }
151
~ResourceBundleTest()152 virtual ~ResourceBundleTest() {
153 }
154
155 // Overridden from testing::Test:
TearDown()156 virtual void TearDown() OVERRIDE {
157 delete resource_bundle_;
158 }
159
160 // Returns new ResoureBundle with the specified |delegate|. The
161 // ResourceBundleTest class manages the lifetime of the returned
162 // ResourceBundle.
CreateResourceBundle(ResourceBundle::Delegate * delegate)163 ResourceBundle* CreateResourceBundle(ResourceBundle::Delegate* delegate) {
164 DCHECK(!resource_bundle_);
165
166 resource_bundle_ = new ResourceBundle(delegate);
167 return resource_bundle_;
168 }
169
170 protected:
171 ResourceBundle* resource_bundle_;
172
173 private:
174 DISALLOW_COPY_AND_ASSIGN(ResourceBundleTest);
175 };
176
TEST_F(ResourceBundleTest,DelegateGetPathForResourcePack)177 TEST_F(ResourceBundleTest, DelegateGetPathForResourcePack) {
178 MockResourceBundleDelegate delegate;
179 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
180
181 base::FilePath pack_path(FILE_PATH_LITERAL("/path/to/test_path.pak"));
182 ui::ScaleFactor pack_scale_factor = ui::SCALE_FACTOR_200P;
183
184 EXPECT_CALL(delegate,
185 GetPathForResourcePack(
186 Property(&base::FilePath::value, pack_path.value()),
187 pack_scale_factor))
188 .Times(1)
189 .WillOnce(Return(pack_path));
190
191 resource_bundle->AddDataPackFromPath(pack_path, pack_scale_factor);
192 }
193
194 #if defined(OS_LINUX)
195 // Fails consistently on Linux: crbug.com/161902
196 #define MAYBE_DelegateGetPathForLocalePack DISABLED_DelegateGetPathForLocalePack
197 #else
198 #define MAYBE_DelegateGetPathForLocalePack DelegateGetPathForLocalePack
199 #endif
TEST_F(ResourceBundleTest,MAYBE_DelegateGetPathForLocalePack)200 TEST_F(ResourceBundleTest, MAYBE_DelegateGetPathForLocalePack) {
201 MockResourceBundleDelegate delegate;
202 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
203
204 std::string locale = "en-US";
205
206 // Cancel the load.
207 EXPECT_CALL(delegate, GetPathForLocalePack(_, locale))
208 .Times(2)
209 .WillRepeatedly(Return(base::FilePath()))
210 .RetiresOnSaturation();
211
212 EXPECT_FALSE(resource_bundle->LocaleDataPakExists(locale));
213 EXPECT_EQ("", resource_bundle->LoadLocaleResources(locale));
214
215 // Allow the load to proceed.
216 EXPECT_CALL(delegate, GetPathForLocalePack(_, locale))
217 .Times(2)
218 .WillRepeatedly(ReturnArg<0>());
219
220 EXPECT_TRUE(resource_bundle->LocaleDataPakExists(locale));
221 EXPECT_EQ(locale, resource_bundle->LoadLocaleResources(locale));
222 }
223
TEST_F(ResourceBundleTest,DelegateGetImageNamed)224 TEST_F(ResourceBundleTest, DelegateGetImageNamed) {
225 MockResourceBundleDelegate delegate;
226 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
227
228 gfx::Image empty_image = resource_bundle->GetEmptyImage();
229 int resource_id = 5;
230
231 EXPECT_CALL(delegate, GetImageNamed(resource_id))
232 .Times(1)
233 .WillOnce(Return(empty_image));
234
235 gfx::Image result = resource_bundle->GetImageNamed(resource_id);
236 EXPECT_EQ(empty_image.ToSkBitmap(), result.ToSkBitmap());
237 }
238
TEST_F(ResourceBundleTest,DelegateGetNativeImageNamed)239 TEST_F(ResourceBundleTest, DelegateGetNativeImageNamed) {
240 MockResourceBundleDelegate delegate;
241 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
242
243 gfx::Image empty_image = resource_bundle->GetEmptyImage();
244 int resource_id = 5;
245
246 // Some platforms delegate GetNativeImageNamed calls to GetImageNamed.
247 EXPECT_CALL(delegate, GetImageNamed(resource_id))
248 .Times(Between(0, 1))
249 .WillOnce(Return(empty_image));
250 EXPECT_CALL(delegate,
251 GetNativeImageNamed(resource_id, ui::ResourceBundle::RTL_DISABLED))
252 .Times(Between(0, 1))
253 .WillOnce(Return(empty_image));
254
255 gfx::Image result = resource_bundle->GetNativeImageNamed(resource_id);
256 EXPECT_EQ(empty_image.ToSkBitmap(), result.ToSkBitmap());
257 }
258
TEST_F(ResourceBundleTest,DelegateLoadDataResourceBytes)259 TEST_F(ResourceBundleTest, DelegateLoadDataResourceBytes) {
260 MockResourceBundleDelegate delegate;
261 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
262
263 // Create the data resource for testing purposes.
264 unsigned char data[] = "My test data";
265 scoped_refptr<base::RefCountedStaticMemory> static_memory(
266 new base::RefCountedStaticMemory(data, sizeof(data)));
267
268 int resource_id = 5;
269 ui::ScaleFactor scale_factor = ui::SCALE_FACTOR_NONE;
270
271 EXPECT_CALL(delegate, LoadDataResourceBytes(resource_id, scale_factor))
272 .Times(1).WillOnce(Return(static_memory.get()));
273
274 scoped_refptr<base::RefCountedStaticMemory> result =
275 resource_bundle->LoadDataResourceBytesForScale(resource_id, scale_factor);
276 EXPECT_EQ(static_memory, result);
277 }
278
TEST_F(ResourceBundleTest,DelegateGetRawDataResource)279 TEST_F(ResourceBundleTest, DelegateGetRawDataResource) {
280 MockResourceBundleDelegate delegate;
281 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
282
283 // Create the string piece for testing purposes.
284 char data[] = "My test data";
285 base::StringPiece string_piece(data);
286
287 int resource_id = 5;
288
289 EXPECT_CALL(delegate, GetRawDataResourceMock(
290 resource_id, ui::SCALE_FACTOR_NONE))
291 .Times(1)
292 .WillOnce(Return(string_piece));
293
294 base::StringPiece result = resource_bundle->GetRawDataResource(
295 resource_id);
296 EXPECT_EQ(string_piece.data(), result.data());
297 }
298
TEST_F(ResourceBundleTest,DelegateGetLocalizedString)299 TEST_F(ResourceBundleTest, DelegateGetLocalizedString) {
300 MockResourceBundleDelegate delegate;
301 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
302
303 base::string16 data = base::ASCIIToUTF16("My test data");
304 int resource_id = 5;
305
306 EXPECT_CALL(delegate, GetLocalizedStringMock(resource_id))
307 .Times(1)
308 .WillOnce(Return(data));
309
310 base::string16 result = resource_bundle->GetLocalizedString(resource_id);
311 EXPECT_EQ(data, result);
312 }
313
314 #if defined(USE_OZONE) && !defined(USE_PANGO)
315 #define MAYBE_DelegateGetFontList DISABLED_DelegateGetFontList
316 #else
317 #define MAYBE_DelegateGetFontList DelegateGetFontList
318 #endif
319
TEST_F(ResourceBundleTest,MAYBE_DelegateGetFontList)320 TEST_F(ResourceBundleTest, MAYBE_DelegateGetFontList) {
321 MockResourceBundleDelegate delegate;
322 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
323
324 // Should be called once for each font type. When we return NULL the default
325 // font will be created.
326 gfx::Font* test_font = NULL;
327 EXPECT_CALL(delegate, GetFontMock(_))
328 .Times(8)
329 .WillRepeatedly(Return(test_font));
330
331 const gfx::FontList* font_list =
332 &resource_bundle->GetFontList(ui::ResourceBundle::BaseFont);
333 EXPECT_TRUE(font_list);
334
335 const gfx::Font* font =
336 &resource_bundle->GetFont(ui::ResourceBundle::BaseFont);
337 EXPECT_TRUE(font);
338 }
339
TEST_F(ResourceBundleTest,LocaleDataPakExists)340 TEST_F(ResourceBundleTest, LocaleDataPakExists) {
341 ResourceBundle* resource_bundle = CreateResourceBundle(NULL);
342
343 // Check that ResourceBundle::LocaleDataPakExists returns the correct results.
344 EXPECT_TRUE(resource_bundle->LocaleDataPakExists("en-US"));
345 EXPECT_FALSE(resource_bundle->LocaleDataPakExists("not_a_real_locale"));
346 }
347
348 class ResourceBundleImageTest : public ResourceBundleTest {
349 public:
ResourceBundleImageTest()350 ResourceBundleImageTest() {}
351
~ResourceBundleImageTest()352 virtual ~ResourceBundleImageTest() {
353 }
354
SetUp()355 virtual void SetUp() OVERRIDE {
356 // Create a temporary directory to write test resource bundles to.
357 ASSERT_TRUE(dir_.CreateUniqueTempDir());
358 }
359
360 // Returns resource bundle which uses an empty data pak for locale data.
CreateResourceBundleWithEmptyLocalePak()361 ui::ResourceBundle* CreateResourceBundleWithEmptyLocalePak() {
362 // Write an empty data pak for locale data.
363 const base::FilePath& locale_path = dir_path().Append(
364 FILE_PATH_LITERAL("locale.pak"));
365 EXPECT_EQ(base::WriteFile(locale_path, kEmptyPakContents,
366 kEmptyPakSize),
367 static_cast<int>(kEmptyPakSize));
368
369 ui::ResourceBundle* resource_bundle = CreateResourceBundle(NULL);
370
371 // Load the empty locale data pak.
372 resource_bundle->LoadTestResources(base::FilePath(), locale_path);
373 return resource_bundle;
374 }
375
376 // Returns the path of temporary directory to write test data packs into.
dir_path()377 const base::FilePath& dir_path() { return dir_.path(); }
378
379 private:
380 scoped_ptr<DataPack> locale_pack_;
381 base::ScopedTempDir dir_;
382
383 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageTest);
384 };
385
386 // Verify that we don't crash when trying to load a resource that is not found.
387 // In some cases, we fail to mmap resources.pak, but try to keep going anyway.
TEST_F(ResourceBundleImageTest,LoadDataResourceBytes)388 TEST_F(ResourceBundleImageTest, LoadDataResourceBytes) {
389 base::FilePath data_path = dir_path().Append(FILE_PATH_LITERAL("sample.pak"));
390
391 // Dump contents into the pak files.
392 ASSERT_EQ(base::WriteFile(data_path, kEmptyPakContents,
393 kEmptyPakSize), static_cast<int>(kEmptyPakSize));
394
395 // Create a resource bundle from the file.
396 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
397 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
398
399 const int kUnfoundResourceId = 10000;
400 EXPECT_EQ(NULL, resource_bundle->LoadDataResourceBytes(
401 kUnfoundResourceId));
402
403 // Give a .pak file that doesn't exist so we will fail to load it.
404 resource_bundle->AddDataPackFromPath(
405 base::FilePath(FILE_PATH_LITERAL("non-existant-file.pak")),
406 ui::SCALE_FACTOR_NONE);
407 EXPECT_EQ(NULL, resource_bundle->LoadDataResourceBytes(
408 kUnfoundResourceId));
409 }
410
TEST_F(ResourceBundleImageTest,GetRawDataResource)411 TEST_F(ResourceBundleImageTest, GetRawDataResource) {
412 base::FilePath data_path = dir_path().Append(FILE_PATH_LITERAL("sample.pak"));
413 base::FilePath data_2x_path =
414 dir_path().Append(FILE_PATH_LITERAL("sample_2x.pak"));
415
416 // Dump contents into the pak files.
417 ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents,
418 kSamplePakSize), static_cast<int>(kSamplePakSize));
419 ASSERT_EQ(base::WriteFile(data_2x_path, kSamplePakContents2x,
420 kSamplePakSize2x), static_cast<int>(kSamplePakSize2x));
421
422 // Load the regular and 2x pak files.
423 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
424 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
425 resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P);
426
427 // Resource ID 4 exists in both 1x and 2x paks, so we expect a different
428 // result when requesting the 2x scale.
429 EXPECT_EQ("this is id 4", resource_bundle->GetRawDataResourceForScale(4,
430 SCALE_FACTOR_100P));
431 EXPECT_EQ("this is id 4 2x", resource_bundle->GetRawDataResourceForScale(4,
432 SCALE_FACTOR_200P));
433
434 // Resource ID 6 only exists in the 1x pak so we expect the same resource
435 // for both scale factor requests.
436 EXPECT_EQ("this is id 6", resource_bundle->GetRawDataResourceForScale(6,
437 SCALE_FACTOR_100P));
438 EXPECT_EQ("this is id 6", resource_bundle->GetRawDataResourceForScale(6,
439 SCALE_FACTOR_200P));
440 }
441
442 // Test requesting image reps at various scale factors from the image returned
443 // via ResourceBundle::GetImageNamed().
TEST_F(ResourceBundleImageTest,GetImageNamed)444 TEST_F(ResourceBundleImageTest, GetImageNamed) {
445 #if defined(OS_WIN)
446 gfx::ForceHighDPISupportForTesting(2.0);
447 #endif
448 std::vector<ScaleFactor> supported_factors;
449 supported_factors.push_back(SCALE_FACTOR_100P);
450 supported_factors.push_back(SCALE_FACTOR_200P);
451 test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
452 base::FilePath data_1x_path = dir_path().AppendASCII("sample_1x.pak");
453 base::FilePath data_2x_path = dir_path().AppendASCII("sample_2x.pak");
454
455 // Create the pak files.
456 CreateDataPackWithSingleBitmap(data_1x_path, 10, base::StringPiece());
457 CreateDataPackWithSingleBitmap(data_2x_path, 20, base::StringPiece());
458
459 // Load the regular and 2x pak files.
460 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
461 resource_bundle->AddDataPackFromPath(data_1x_path, SCALE_FACTOR_100P);
462 resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P);
463
464 EXPECT_EQ(SCALE_FACTOR_200P, resource_bundle->GetMaxScaleFactor());
465
466 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
467
468 #if defined(OS_CHROMEOS) || defined(OS_WIN)
469 // ChromeOS/Windows load highest scale factor first.
470 EXPECT_EQ(ui::SCALE_FACTOR_200P,
471 GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
472 #else
473 EXPECT_EQ(ui::SCALE_FACTOR_100P,
474 GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
475 #endif
476
477 // Resource ID 3 exists in both 1x and 2x paks. Image reps should be
478 // available for both scale factors in |image_skia|.
479 gfx::ImageSkiaRep image_rep =
480 image_skia->GetRepresentation(
481 GetScaleForScaleFactor(ui::SCALE_FACTOR_100P));
482 EXPECT_EQ(ui::SCALE_FACTOR_100P, GetSupportedScaleFactor(image_rep.scale()));
483 image_rep =
484 image_skia->GetRepresentation(
485 GetScaleForScaleFactor(ui::SCALE_FACTOR_200P));
486 EXPECT_EQ(ui::SCALE_FACTOR_200P, GetSupportedScaleFactor(image_rep.scale()));
487
488 // The 1.4x pack was not loaded. Requesting the 1.4x resource should return
489 // either the 1x or the 2x resource.
490 image_rep = image_skia->GetRepresentation(
491 ui::GetScaleForScaleFactor(ui::SCALE_FACTOR_140P));
492 ui::ScaleFactor scale_factor = GetSupportedScaleFactor(image_rep.scale());
493 EXPECT_TRUE(scale_factor == ui::SCALE_FACTOR_100P ||
494 scale_factor == ui::SCALE_FACTOR_200P);
495
496 // ImageSkia scales image if the one for the requested scale factor is not
497 // available.
498 EXPECT_EQ(1.4f, image_skia->GetRepresentation(1.4f).scale());
499 }
500
501 // Test that GetImageNamed() behaves properly for images which GRIT has
502 // annotated as having fallen back to 1x.
TEST_F(ResourceBundleImageTest,GetImageNamedFallback1x)503 TEST_F(ResourceBundleImageTest, GetImageNamedFallback1x) {
504 std::vector<ScaleFactor> supported_factors;
505 supported_factors.push_back(SCALE_FACTOR_100P);
506 supported_factors.push_back(SCALE_FACTOR_200P);
507 test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
508 base::FilePath data_path = dir_path().AppendASCII("sample.pak");
509 base::FilePath data_2x_path = dir_path().AppendASCII("sample_2x.pak");
510
511 // Create the pak files.
512 CreateDataPackWithSingleBitmap(data_path, 10, base::StringPiece());
513 // 2x data pack bitmap has custom chunk to indicate that the 2x bitmap is not
514 // available and that GRIT fell back to 1x.
515 CreateDataPackWithSingleBitmap(data_2x_path, 10, base::StringPiece(
516 reinterpret_cast<const char*>(kPngScaleChunk),
517 arraysize(kPngScaleChunk)));
518
519 // Load the regular and 2x pak files.
520 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
521 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
522 resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P);
523
524 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
525
526 // The image rep for 2x should be available. It should be resized to the
527 // proper 2x size.
528 gfx::ImageSkiaRep image_rep =
529 image_skia->GetRepresentation(GetScaleForScaleFactor(
530 ui::SCALE_FACTOR_200P));
531 EXPECT_EQ(ui::SCALE_FACTOR_200P, GetSupportedScaleFactor(image_rep.scale()));
532 EXPECT_EQ(20, image_rep.pixel_width());
533 EXPECT_EQ(20, image_rep.pixel_height());
534 }
535
536 #if defined(OS_WIN)
537 // Tests GetImageNamed() behaves properly when the size of a scaled image
538 // requires rounding as a result of using a non-integer scale factor.
539 // Scale factors of 140 and 1805 are Windows specific.
TEST_F(ResourceBundleImageTest,GetImageNamedFallback1xRounding)540 TEST_F(ResourceBundleImageTest, GetImageNamedFallback1xRounding) {
541 std::vector<ScaleFactor> supported_factors;
542 supported_factors.push_back(SCALE_FACTOR_100P);
543 supported_factors.push_back(SCALE_FACTOR_140P);
544 supported_factors.push_back(SCALE_FACTOR_180P);
545 test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
546
547 base::FilePath data_path = dir_path().AppendASCII("sample.pak");
548 base::FilePath data_140P_path = dir_path().AppendASCII("sample_140P.pak");
549 base::FilePath data_180P_path = dir_path().AppendASCII("sample_180P.pak");
550
551 CreateDataPackWithSingleBitmap(data_path, 8, base::StringPiece());
552 // Mark 140% and 180% images as requiring 1x fallback.
553 CreateDataPackWithSingleBitmap(data_140P_path, 8, base::StringPiece(
554 reinterpret_cast<const char*>(kPngScaleChunk),
555 arraysize(kPngScaleChunk)));
556 CreateDataPackWithSingleBitmap(data_180P_path, 8, base::StringPiece(
557 reinterpret_cast<const char*>(kPngScaleChunk),
558 arraysize(kPngScaleChunk)));
559
560 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
561 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
562 resource_bundle->AddDataPackFromPath(data_140P_path, SCALE_FACTOR_140P);
563 resource_bundle->AddDataPackFromPath(data_180P_path, SCALE_FACTOR_180P);
564
565 // Non-integer dimensions should be rounded up.
566 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
567 gfx::ImageSkiaRep image_rep =
568 image_skia->GetRepresentation(
569 GetScaleForScaleFactor(ui::SCALE_FACTOR_140P));
570 EXPECT_EQ(12, image_rep.pixel_width());
571 image_rep = image_skia->GetRepresentation(
572 GetScaleForScaleFactor(ui::SCALE_FACTOR_180P));
573 EXPECT_EQ(15, image_rep.pixel_width());
574 }
575 #endif
576
577 #if defined(OS_IOS)
578 // Fails on devices that have non-100P scaling. See crbug.com/298406
579 #define MAYBE_FallbackToNone DISABLED_FallbackToNone
580 #else
581 #define MAYBE_FallbackToNone FallbackToNone
582 #endif
TEST_F(ResourceBundleImageTest,MAYBE_FallbackToNone)583 TEST_F(ResourceBundleImageTest, MAYBE_FallbackToNone) {
584 base::FilePath data_default_path = dir_path().AppendASCII("sample.pak");
585
586 // Create the pak files.
587 CreateDataPackWithSingleBitmap(data_default_path, 10, base::StringPiece());
588
589 // Load the regular pak files only.
590 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
591 resource_bundle->AddDataPackFromPath(data_default_path, SCALE_FACTOR_NONE);
592
593 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
594 EXPECT_EQ(1u, image_skia->image_reps().size());
595 EXPECT_TRUE(image_skia->image_reps()[0].unscaled());
596 EXPECT_EQ(ui::SCALE_FACTOR_100P,
597 GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
598 }
599
600 } // namespace ui
601