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/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/path_service.h" 15 #include "base/strings/utf_string_conversions.h" 16 #include "testing/gmock/include/gmock/gmock.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 #include "third_party/skia/include/core/SkBitmap.h" 19 #include "ui/base/layout.h" 20 #include "ui/base/resource/data_pack.h" 21 #include "ui/gfx/codec/png_codec.h" 22 #include "ui/gfx/image/image_skia.h" 23 #include "ui/resources/grit/ui_resources.h" 24 25 #if defined(OS_WIN) 26 #include "ui/gfx/win/dpi.h" 27 #endif 28 29 using ::testing::_; 30 using ::testing::Between; 31 using ::testing::Property; 32 using ::testing::Return; 33 using ::testing::ReturnArg; 34 35 namespace ui { 36 37 extern const char kSamplePakContents[]; 38 extern const size_t kSamplePakSize; 39 extern const char kSamplePakContents2x[]; 40 extern const size_t kSamplePakSize2x; 41 extern const char kEmptyPakContents[]; 42 extern const size_t kEmptyPakSize; 43 44 namespace { 45 46 const unsigned char kPngMagic[8] = { 0x89, 'P', 'N', 'G', 13, 10, 26, 10 }; 47 const size_t kPngChunkMetadataSize = 12; 48 const unsigned char kPngIHDRChunkType[4] = { 'I', 'H', 'D', 'R' }; 49 50 // Custom chunk that GRIT adds to PNG to indicate that it could not find a 51 // bitmap at the requested scale factor and fell back to 1x. 52 const unsigned char kPngScaleChunk[12] = { 0x00, 0x00, 0x00, 0x00, 53 'c', 's', 'C', 'l', 54 0xc1, 0x30, 0x60, 0x4d }; 55 56 // Mock for the ResourceBundle::Delegate class. 57 class MockResourceBundleDelegate : public ui::ResourceBundle::Delegate { 58 public: 59 MockResourceBundleDelegate() { 60 } 61 virtual ~MockResourceBundleDelegate() { 62 } 63 64 MOCK_METHOD2(GetPathForResourcePack, base::FilePath( 65 const base::FilePath& pack_path, ui::ScaleFactor scale_factor)); 66 MOCK_METHOD2(GetPathForLocalePack, base::FilePath( 67 const base::FilePath& pack_path, const std::string& locale)); 68 MOCK_METHOD1(GetImageNamed, gfx::Image(int resource_id)); 69 MOCK_METHOD2(GetNativeImageNamed, 70 gfx::Image(int resource_id, 71 ui::ResourceBundle::ImageRTL rtl)); 72 MOCK_METHOD2(LoadDataResourceBytes, 73 base::RefCountedStaticMemory*(int resource_id, 74 ui::ScaleFactor scale_factor)); 75 MOCK_METHOD2(GetRawDataResourceMock, base::StringPiece( 76 int resource_id, 77 ui::ScaleFactor scale_factor)); 78 virtual bool GetRawDataResource(int resource_id, 79 ui::ScaleFactor scale_factor, 80 base::StringPiece* value) OVERRIDE { 81 *value = GetRawDataResourceMock(resource_id, scale_factor); 82 return true; 83 } 84 MOCK_METHOD1(GetLocalizedStringMock, base::string16(int message_id)); 85 virtual bool GetLocalizedString(int message_id, 86 base::string16* value) OVERRIDE { 87 *value = GetLocalizedStringMock(message_id); 88 return true; 89 } 90 MOCK_METHOD1(GetFontMock, 91 gfx::Font*(ui::ResourceBundle::FontStyle style)); 92 virtual scoped_ptr<gfx::Font> GetFont( 93 ui::ResourceBundle::FontStyle style) OVERRIDE { 94 return scoped_ptr<gfx::Font>(GetFontMock(style)); 95 } 96 }; 97 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)); 118 119 bitmap_data->insert(ihdr_start + kPngChunkMetadataSize + ihdr_chunk_length, 120 custom_chunk.begin(), custom_chunk.end()); 121 } 122 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)); 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: 149 ResourceBundleTest() : resource_bundle_(NULL) { 150 } 151 152 virtual ~ResourceBundleTest() { 153 } 154 155 // Overridden from testing::Test: 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. 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 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 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 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 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 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 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 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 TEST_F(ResourceBundleTest, OverrideStringResource) { 315 ResourceBundle* resource_bundle = CreateResourceBundle(NULL); 316 317 base::string16 data = base::ASCIIToUTF16("My test data"); 318 int resource_id = 5; 319 320 base::string16 result = resource_bundle->GetLocalizedString(resource_id); 321 EXPECT_EQ(base::string16(), result); 322 323 resource_bundle->OverrideLocaleStringResource(resource_id, data); 324 325 result = resource_bundle->GetLocalizedString(resource_id); 326 EXPECT_EQ(data, result); 327 } 328 329 TEST_F(ResourceBundleTest, DelegateGetLocalizedStringWithOverride) { 330 MockResourceBundleDelegate delegate; 331 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate); 332 333 base::string16 delegate_data = base::ASCIIToUTF16("My delegate data"); 334 int resource_id = 5; 335 336 EXPECT_CALL(delegate, GetLocalizedStringMock(resource_id)).Times(1).WillOnce( 337 Return(delegate_data)); 338 339 base::string16 override_data = base::ASCIIToUTF16("My override data"); 340 341 base::string16 result = resource_bundle->GetLocalizedString(resource_id); 342 EXPECT_EQ(delegate_data, result); 343 } 344 345 #if defined(USE_OZONE) && !defined(USE_PANGO) 346 #define MAYBE_DelegateGetFontList DISABLED_DelegateGetFontList 347 #else 348 #define MAYBE_DelegateGetFontList DelegateGetFontList 349 #endif 350 351 TEST_F(ResourceBundleTest, MAYBE_DelegateGetFontList) { 352 MockResourceBundleDelegate delegate; 353 ResourceBundle* resource_bundle = CreateResourceBundle(&delegate); 354 355 // Should be called once for each font type. When we return NULL the default 356 // font will be created. 357 gfx::Font* test_font = NULL; 358 EXPECT_CALL(delegate, GetFontMock(_)) 359 .Times(8) 360 .WillRepeatedly(Return(test_font)); 361 362 const gfx::FontList* font_list = 363 &resource_bundle->GetFontList(ui::ResourceBundle::BaseFont); 364 EXPECT_TRUE(font_list); 365 366 const gfx::Font* font = 367 &resource_bundle->GetFont(ui::ResourceBundle::BaseFont); 368 EXPECT_TRUE(font); 369 } 370 371 TEST_F(ResourceBundleTest, LocaleDataPakExists) { 372 ResourceBundle* resource_bundle = CreateResourceBundle(NULL); 373 374 // Check that ResourceBundle::LocaleDataPakExists returns the correct results. 375 EXPECT_TRUE(resource_bundle->LocaleDataPakExists("en-US")); 376 EXPECT_FALSE(resource_bundle->LocaleDataPakExists("not_a_real_locale")); 377 } 378 379 class ResourceBundleImageTest : public ResourceBundleTest { 380 public: 381 ResourceBundleImageTest() {} 382 383 virtual ~ResourceBundleImageTest() { 384 } 385 386 virtual void SetUp() OVERRIDE { 387 // Create a temporary directory to write test resource bundles to. 388 ASSERT_TRUE(dir_.CreateUniqueTempDir()); 389 } 390 391 // Returns resource bundle which uses an empty data pak for locale data. 392 ui::ResourceBundle* CreateResourceBundleWithEmptyLocalePak() { 393 // Write an empty data pak for locale data. 394 const base::FilePath& locale_path = dir_path().Append( 395 FILE_PATH_LITERAL("locale.pak")); 396 EXPECT_EQ(base::WriteFile(locale_path, kEmptyPakContents, kEmptyPakSize), 397 static_cast<int>(kEmptyPakSize)); 398 399 ui::ResourceBundle* resource_bundle = CreateResourceBundle(NULL); 400 401 // Load the empty locale data pak. 402 resource_bundle->LoadTestResources(base::FilePath(), locale_path); 403 return resource_bundle; 404 } 405 406 // Returns the path of temporary directory to write test data packs into. 407 const base::FilePath& dir_path() { return dir_.path(); } 408 409 private: 410 scoped_ptr<DataPack> locale_pack_; 411 base::ScopedTempDir dir_; 412 413 DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageTest); 414 }; 415 416 // Verify that we don't crash when trying to load a resource that is not found. 417 // In some cases, we fail to mmap resources.pak, but try to keep going anyway. 418 TEST_F(ResourceBundleImageTest, LoadDataResourceBytes) { 419 base::FilePath data_path = dir_path().Append(FILE_PATH_LITERAL("sample.pak")); 420 421 // Dump contents into the pak files. 422 ASSERT_EQ(base::WriteFile(data_path, kEmptyPakContents, 423 kEmptyPakSize), static_cast<int>(kEmptyPakSize)); 424 425 // Create a resource bundle from the file. 426 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak(); 427 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P); 428 429 const int kUnfoundResourceId = 10000; 430 EXPECT_EQ(NULL, resource_bundle->LoadDataResourceBytes( 431 kUnfoundResourceId)); 432 433 // Give a .pak file that doesn't exist so we will fail to load it. 434 resource_bundle->AddDataPackFromPath( 435 base::FilePath(FILE_PATH_LITERAL("non-existant-file.pak")), 436 ui::SCALE_FACTOR_NONE); 437 EXPECT_EQ(NULL, resource_bundle->LoadDataResourceBytes( 438 kUnfoundResourceId)); 439 } 440 441 TEST_F(ResourceBundleImageTest, GetRawDataResource) { 442 base::FilePath data_path = dir_path().Append(FILE_PATH_LITERAL("sample.pak")); 443 base::FilePath data_2x_path = 444 dir_path().Append(FILE_PATH_LITERAL("sample_2x.pak")); 445 446 // Dump contents into the pak files. 447 ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents, 448 kSamplePakSize), static_cast<int>(kSamplePakSize)); 449 ASSERT_EQ(base::WriteFile(data_2x_path, kSamplePakContents2x, 450 kSamplePakSize2x), static_cast<int>(kSamplePakSize2x)); 451 452 // Load the regular and 2x pak files. 453 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak(); 454 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P); 455 resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P); 456 457 // Resource ID 4 exists in both 1x and 2x paks, so we expect a different 458 // result when requesting the 2x scale. 459 EXPECT_EQ("this is id 4", resource_bundle->GetRawDataResourceForScale(4, 460 SCALE_FACTOR_100P)); 461 EXPECT_EQ("this is id 4 2x", resource_bundle->GetRawDataResourceForScale(4, 462 SCALE_FACTOR_200P)); 463 464 // Resource ID 6 only exists in the 1x pak so we expect the same resource 465 // for both scale factor requests. 466 EXPECT_EQ("this is id 6", resource_bundle->GetRawDataResourceForScale(6, 467 SCALE_FACTOR_100P)); 468 EXPECT_EQ("this is id 6", resource_bundle->GetRawDataResourceForScale(6, 469 SCALE_FACTOR_200P)); 470 } 471 472 // Test requesting image reps at various scale factors from the image returned 473 // via ResourceBundle::GetImageNamed(). 474 TEST_F(ResourceBundleImageTest, GetImageNamed) { 475 #if defined(OS_WIN) 476 gfx::ForceHighDPISupportForTesting(2.0); 477 #endif 478 std::vector<ScaleFactor> supported_factors; 479 supported_factors.push_back(SCALE_FACTOR_100P); 480 supported_factors.push_back(SCALE_FACTOR_200P); 481 test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors); 482 base::FilePath data_1x_path = dir_path().AppendASCII("sample_1x.pak"); 483 base::FilePath data_2x_path = dir_path().AppendASCII("sample_2x.pak"); 484 485 // Create the pak files. 486 CreateDataPackWithSingleBitmap(data_1x_path, 10, base::StringPiece()); 487 CreateDataPackWithSingleBitmap(data_2x_path, 20, base::StringPiece()); 488 489 // Load the regular and 2x pak files. 490 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak(); 491 resource_bundle->AddDataPackFromPath(data_1x_path, SCALE_FACTOR_100P); 492 resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P); 493 494 EXPECT_EQ(SCALE_FACTOR_200P, resource_bundle->GetMaxScaleFactor()); 495 496 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3); 497 498 #if defined(OS_CHROMEOS) || defined(OS_WIN) 499 // ChromeOS/Windows load highest scale factor first. 500 EXPECT_EQ(ui::SCALE_FACTOR_200P, 501 GetSupportedScaleFactor(image_skia->image_reps()[0].scale())); 502 #else 503 EXPECT_EQ(ui::SCALE_FACTOR_100P, 504 GetSupportedScaleFactor(image_skia->image_reps()[0].scale())); 505 #endif 506 507 // Resource ID 3 exists in both 1x and 2x paks. Image reps should be 508 // available for both scale factors in |image_skia|. 509 gfx::ImageSkiaRep image_rep = 510 image_skia->GetRepresentation( 511 GetScaleForScaleFactor(ui::SCALE_FACTOR_100P)); 512 EXPECT_EQ(ui::SCALE_FACTOR_100P, GetSupportedScaleFactor(image_rep.scale())); 513 image_rep = 514 image_skia->GetRepresentation( 515 GetScaleForScaleFactor(ui::SCALE_FACTOR_200P)); 516 EXPECT_EQ(ui::SCALE_FACTOR_200P, GetSupportedScaleFactor(image_rep.scale())); 517 518 // The 1.4x pack was not loaded. Requesting the 1.4x resource should return 519 // either the 1x or the 2x resource. 520 image_rep = image_skia->GetRepresentation( 521 ui::GetScaleForScaleFactor(ui::SCALE_FACTOR_140P)); 522 ui::ScaleFactor scale_factor = GetSupportedScaleFactor(image_rep.scale()); 523 EXPECT_TRUE(scale_factor == ui::SCALE_FACTOR_100P || 524 scale_factor == ui::SCALE_FACTOR_200P); 525 526 // ImageSkia scales image if the one for the requested scale factor is not 527 // available. 528 EXPECT_EQ(1.4f, image_skia->GetRepresentation(1.4f).scale()); 529 } 530 531 // Test that GetImageNamed() behaves properly for images which GRIT has 532 // annotated as having fallen back to 1x. 533 TEST_F(ResourceBundleImageTest, GetImageNamedFallback1x) { 534 std::vector<ScaleFactor> supported_factors; 535 supported_factors.push_back(SCALE_FACTOR_100P); 536 supported_factors.push_back(SCALE_FACTOR_200P); 537 test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors); 538 base::FilePath data_path = dir_path().AppendASCII("sample.pak"); 539 base::FilePath data_2x_path = dir_path().AppendASCII("sample_2x.pak"); 540 541 // Create the pak files. 542 CreateDataPackWithSingleBitmap(data_path, 10, base::StringPiece()); 543 // 2x data pack bitmap has custom chunk to indicate that the 2x bitmap is not 544 // available and that GRIT fell back to 1x. 545 CreateDataPackWithSingleBitmap(data_2x_path, 10, base::StringPiece( 546 reinterpret_cast<const char*>(kPngScaleChunk), 547 arraysize(kPngScaleChunk))); 548 549 // Load the regular and 2x pak files. 550 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak(); 551 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P); 552 resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P); 553 554 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3); 555 556 // The image rep for 2x should be available. It should be resized to the 557 // proper 2x size. 558 gfx::ImageSkiaRep image_rep = 559 image_skia->GetRepresentation(GetScaleForScaleFactor( 560 ui::SCALE_FACTOR_200P)); 561 EXPECT_EQ(ui::SCALE_FACTOR_200P, GetSupportedScaleFactor(image_rep.scale())); 562 EXPECT_EQ(20, image_rep.pixel_width()); 563 EXPECT_EQ(20, image_rep.pixel_height()); 564 } 565 566 #if defined(OS_WIN) 567 // Tests GetImageNamed() behaves properly when the size of a scaled image 568 // requires rounding as a result of using a non-integer scale factor. 569 // Scale factors of 140 and 1805 are Windows specific. 570 TEST_F(ResourceBundleImageTest, GetImageNamedFallback1xRounding) { 571 std::vector<ScaleFactor> supported_factors; 572 supported_factors.push_back(SCALE_FACTOR_100P); 573 supported_factors.push_back(SCALE_FACTOR_140P); 574 supported_factors.push_back(SCALE_FACTOR_180P); 575 test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors); 576 577 base::FilePath data_path = dir_path().AppendASCII("sample.pak"); 578 base::FilePath data_140P_path = dir_path().AppendASCII("sample_140P.pak"); 579 base::FilePath data_180P_path = dir_path().AppendASCII("sample_180P.pak"); 580 581 CreateDataPackWithSingleBitmap(data_path, 8, base::StringPiece()); 582 // Mark 140% and 180% images as requiring 1x fallback. 583 CreateDataPackWithSingleBitmap(data_140P_path, 8, base::StringPiece( 584 reinterpret_cast<const char*>(kPngScaleChunk), 585 arraysize(kPngScaleChunk))); 586 CreateDataPackWithSingleBitmap(data_180P_path, 8, base::StringPiece( 587 reinterpret_cast<const char*>(kPngScaleChunk), 588 arraysize(kPngScaleChunk))); 589 590 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak(); 591 resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P); 592 resource_bundle->AddDataPackFromPath(data_140P_path, SCALE_FACTOR_140P); 593 resource_bundle->AddDataPackFromPath(data_180P_path, SCALE_FACTOR_180P); 594 595 // Non-integer dimensions should be rounded up. 596 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3); 597 gfx::ImageSkiaRep image_rep = 598 image_skia->GetRepresentation( 599 GetScaleForScaleFactor(ui::SCALE_FACTOR_140P)); 600 EXPECT_EQ(12, image_rep.pixel_width()); 601 image_rep = image_skia->GetRepresentation( 602 GetScaleForScaleFactor(ui::SCALE_FACTOR_180P)); 603 EXPECT_EQ(15, image_rep.pixel_width()); 604 } 605 #endif 606 607 #if defined(OS_IOS) 608 // Fails on devices that have non-100P scaling. See crbug.com/298406 609 #define MAYBE_FallbackToNone DISABLED_FallbackToNone 610 #else 611 #define MAYBE_FallbackToNone FallbackToNone 612 #endif 613 TEST_F(ResourceBundleImageTest, MAYBE_FallbackToNone) { 614 base::FilePath data_default_path = dir_path().AppendASCII("sample.pak"); 615 616 // Create the pak files. 617 CreateDataPackWithSingleBitmap(data_default_path, 10, base::StringPiece()); 618 619 // Load the regular pak files only. 620 ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak(); 621 resource_bundle->AddDataPackFromPath(data_default_path, SCALE_FACTOR_NONE); 622 623 gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3); 624 EXPECT_EQ(1u, image_skia->image_reps().size()); 625 EXPECT_TRUE(image_skia->image_reps()[0].unscaled()); 626 EXPECT_EQ(ui::SCALE_FACTOR_100P, 627 GetSupportedScaleFactor(image_skia->image_reps()[0].scale())); 628 } 629 630 } // namespace ui 631