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: 58 MockResourceBundleDelegate() { 59 } 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)); 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)); 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)); 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. 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. 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: 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 #if defined(USE_OZONE) && !defined(USE_PANGO) 315 #define MAYBE_DelegateGetFontList DISABLED_DelegateGetFontList 316 #else 317 #define MAYBE_DelegateGetFontList DelegateGetFontList 318 #endif 319 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 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: 350 ResourceBundleImageTest() {} 351 352 virtual ~ResourceBundleImageTest() { 353 } 354 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. 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. 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. 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 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(). 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. 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. 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 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