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