Home | History | Annotate | Download | only in resource
      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