| OLD | NEW |
| (Empty) |
| 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)) || defined(OS_ANDROID) | |
| 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 | |
| OLD | NEW |