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/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 #if defined(USE_OZONE) && !defined(USE_PANGO)
    312 #define MAYBE_DelegateGetFontList DISABLED_DelegateGetFontList
    313 #else
    314 #define MAYBE_DelegateGetFontList DelegateGetFontList
    315 #endif
    316 
    317 TEST_F(ResourceBundleTest, MAYBE_DelegateGetFontList) {
    318   MockResourceBundleDelegate delegate;
    319   ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
    320 
    321   // Should be called once for each font type. When we return NULL the default
    322   // font will be created.
    323   gfx::Font* test_font = NULL;
    324   EXPECT_CALL(delegate, GetFontMock(_))
    325       .Times(8)
    326       .WillRepeatedly(Return(test_font));
    327 
    328   const gfx::FontList* font_list =
    329       &resource_bundle->GetFontList(ui::ResourceBundle::BaseFont);
    330   EXPECT_TRUE(font_list);
    331 
    332   const gfx::Font* font =
    333       &resource_bundle->GetFont(ui::ResourceBundle::BaseFont);
    334   EXPECT_TRUE(font);
    335 }
    336 
    337 TEST_F(ResourceBundleTest, LocaleDataPakExists) {
    338   ResourceBundle* resource_bundle = CreateResourceBundle(NULL);
    339 
    340   // Check that ResourceBundle::LocaleDataPakExists returns the correct results.
    341   EXPECT_TRUE(resource_bundle->LocaleDataPakExists("en-US"));
    342   EXPECT_FALSE(resource_bundle->LocaleDataPakExists("not_a_real_locale"));
    343 }
    344 
    345 class ResourceBundleImageTest : public ResourceBundleTest {
    346  public:
    347   ResourceBundleImageTest() {}
    348 
    349   virtual ~ResourceBundleImageTest() {
    350   }
    351 
    352   virtual void SetUp() OVERRIDE {
    353     // Create a temporary directory to write test resource bundles to.
    354     ASSERT_TRUE(dir_.CreateUniqueTempDir());
    355   }
    356 
    357   // Returns resource bundle which uses an empty data pak for locale data.
    358   ui::ResourceBundle* CreateResourceBundleWithEmptyLocalePak() {
    359     // Write an empty data pak for locale data.
    360     const base::FilePath& locale_path = dir_path().Append(
    361         FILE_PATH_LITERAL("locale.pak"));
    362     EXPECT_EQ(file_util::WriteFile(locale_path, kEmptyPakContents,
    363                                    kEmptyPakSize),
    364               static_cast<int>(kEmptyPakSize));
    365 
    366     ui::ResourceBundle* resource_bundle = CreateResourceBundle(NULL);
    367 
    368     // Load the empty locale data pak.
    369     resource_bundle->LoadTestResources(base::FilePath(), locale_path);
    370     return resource_bundle;
    371   }
    372 
    373   // Returns the path of temporary directory to write test data packs into.
    374   const base::FilePath& dir_path() { return dir_.path(); }
    375 
    376  private:
    377   scoped_ptr<DataPack> locale_pack_;
    378   base::ScopedTempDir dir_;
    379 
    380   DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageTest);
    381 };
    382 
    383 // Verify that we don't crash when trying to load a resource that is not found.
    384 // In some cases, we fail to mmap resources.pak, but try to keep going anyway.
    385 TEST_F(ResourceBundleImageTest, LoadDataResourceBytes) {
    386   base::FilePath data_path = dir_path().Append(FILE_PATH_LITERAL("sample.pak"));
    387 
    388   // Dump contents into the pak files.
    389   ASSERT_EQ(file_util::WriteFile(data_path, kEmptyPakContents,
    390       kEmptyPakSize), static_cast<int>(kEmptyPakSize));
    391 
    392   // Create a resource bundle from the file.
    393   ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
    394   resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
    395 
    396   const int kUnfoundResourceId = 10000;
    397   EXPECT_EQ(NULL, resource_bundle->LoadDataResourceBytes(
    398       kUnfoundResourceId));
    399 
    400   // Give a .pak file that doesn't exist so we will fail to load it.
    401   resource_bundle->AddDataPackFromPath(
    402       base::FilePath(FILE_PATH_LITERAL("non-existant-file.pak")),
    403       ui::SCALE_FACTOR_NONE);
    404   EXPECT_EQ(NULL, resource_bundle->LoadDataResourceBytes(
    405       kUnfoundResourceId));
    406 }
    407 
    408 TEST_F(ResourceBundleImageTest, GetRawDataResource) {
    409   base::FilePath data_path = dir_path().Append(FILE_PATH_LITERAL("sample.pak"));
    410   base::FilePath data_2x_path =
    411       dir_path().Append(FILE_PATH_LITERAL("sample_2x.pak"));
    412 
    413   // Dump contents into the pak files.
    414   ASSERT_EQ(file_util::WriteFile(data_path, kSamplePakContents,
    415       kSamplePakSize), static_cast<int>(kSamplePakSize));
    416   ASSERT_EQ(file_util::WriteFile(data_2x_path, kSamplePakContents2x,
    417       kSamplePakSize2x), static_cast<int>(kSamplePakSize2x));
    418 
    419   // Load the regular and 2x pak files.
    420   ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
    421   resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
    422   resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P);
    423 
    424   // Resource ID 4 exists in both 1x and 2x paks, so we expect a different
    425   // result when requesting the 2x scale.
    426   EXPECT_EQ("this is id 4", resource_bundle->GetRawDataResourceForScale(4,
    427       SCALE_FACTOR_100P));
    428   EXPECT_EQ("this is id 4 2x", resource_bundle->GetRawDataResourceForScale(4,
    429       SCALE_FACTOR_200P));
    430 
    431   // Resource ID 6 only exists in the 1x pak so we expect the same resource
    432   // for both scale factor requests.
    433   EXPECT_EQ("this is id 6", resource_bundle->GetRawDataResourceForScale(6,
    434       SCALE_FACTOR_100P));
    435   EXPECT_EQ("this is id 6", resource_bundle->GetRawDataResourceForScale(6,
    436       SCALE_FACTOR_200P));
    437 }
    438 
    439 // Test requesting image reps at various scale factors from the image returned
    440 // via ResourceBundle::GetImageNamed().
    441 TEST_F(ResourceBundleImageTest, GetImageNamed) {
    442   std::vector<ScaleFactor> supported_factors;
    443   supported_factors.push_back(SCALE_FACTOR_100P);
    444   supported_factors.push_back(SCALE_FACTOR_200P);
    445   test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
    446   base::FilePath data_1x_path = dir_path().AppendASCII("sample_1x.pak");
    447   base::FilePath data_2x_path = dir_path().AppendASCII("sample_2x.pak");
    448 
    449   // Create the pak files.
    450   CreateDataPackWithSingleBitmap(data_1x_path, 10, base::StringPiece());
    451   CreateDataPackWithSingleBitmap(data_2x_path, 20, base::StringPiece());
    452 
    453   // Load the regular and 2x pak files.
    454   ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
    455   resource_bundle->AddDataPackFromPath(data_1x_path, SCALE_FACTOR_100P);
    456   resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P);
    457 
    458   EXPECT_EQ(SCALE_FACTOR_200P, resource_bundle->GetMaxScaleFactor());
    459 
    460   gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
    461 
    462 #if defined(OS_CHROMEOS)
    463   // ChromeOS loads highest scale factor first.
    464   EXPECT_EQ(ui::SCALE_FACTOR_200P,
    465             GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
    466 #else
    467   EXPECT_EQ(ui::SCALE_FACTOR_100P,
    468             GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
    469 #endif
    470 
    471   // Resource ID 3 exists in both 1x and 2x paks. Image reps should be
    472   // available for both scale factors in |image_skia|.
    473   gfx::ImageSkiaRep image_rep =
    474       image_skia->GetRepresentation(GetImageScale(ui::SCALE_FACTOR_100P));
    475   EXPECT_EQ(ui::SCALE_FACTOR_100P, GetSupportedScaleFactor(image_rep.scale()));
    476   image_rep =
    477       image_skia->GetRepresentation(GetImageScale(ui::SCALE_FACTOR_200P));
    478   EXPECT_EQ(ui::SCALE_FACTOR_200P, GetSupportedScaleFactor(image_rep.scale()));
    479 
    480   // The 1.4x pack was not loaded. Requesting the 1.4x resource should return
    481   // either the 1x or the 2x resource.
    482   image_rep = image_skia->GetRepresentation(
    483       ui::GetImageScale(ui::SCALE_FACTOR_140P));
    484   ui::ScaleFactor scale_factor = GetSupportedScaleFactor(image_rep.scale());
    485   EXPECT_TRUE(scale_factor == ui::SCALE_FACTOR_100P ||
    486               scale_factor == ui::SCALE_FACTOR_200P);
    487 }
    488 
    489 // Test that GetImageNamed() behaves properly for images which GRIT has
    490 // annotated as having fallen back to 1x.
    491 TEST_F(ResourceBundleImageTest, GetImageNamedFallback1x) {
    492   std::vector<ScaleFactor> supported_factors;
    493   supported_factors.push_back(SCALE_FACTOR_100P);
    494   supported_factors.push_back(SCALE_FACTOR_200P);
    495   test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
    496   base::FilePath data_path = dir_path().AppendASCII("sample.pak");
    497   base::FilePath data_2x_path = dir_path().AppendASCII("sample_2x.pak");
    498 
    499   // Create the pak files.
    500   CreateDataPackWithSingleBitmap(data_path, 10, base::StringPiece());
    501   // 2x data pack bitmap has custom chunk to indicate that the 2x bitmap is not
    502   // available and that GRIT fell back to 1x.
    503   CreateDataPackWithSingleBitmap(data_2x_path, 10, base::StringPiece(
    504       reinterpret_cast<const char*>(kPngScaleChunk),
    505       arraysize(kPngScaleChunk)));
    506 
    507   // Load the regular and 2x pak files.
    508   ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
    509   resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
    510   resource_bundle->AddDataPackFromPath(data_2x_path, SCALE_FACTOR_200P);
    511 
    512   gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
    513 
    514   // The image rep for 2x should be available. It should be resized to the
    515   // proper 2x size.
    516   gfx::ImageSkiaRep image_rep =
    517     image_skia->GetRepresentation(GetImageScale(ui::SCALE_FACTOR_200P));
    518   EXPECT_EQ(ui::SCALE_FACTOR_200P, GetSupportedScaleFactor(image_rep.scale()));
    519   EXPECT_EQ(20, image_rep.pixel_width());
    520   EXPECT_EQ(20, image_rep.pixel_height());
    521 }
    522 
    523 #if defined(OS_WIN)
    524 // Tests GetImageNamed() behaves properly when the size of a scaled image
    525 // requires rounding as a result of using a non-integer scale factor.
    526 // Scale factors of 140 and 1805 are Windows specific.
    527 TEST_F(ResourceBundleImageTest, GetImageNamedFallback1xRounding) {
    528   std::vector<ScaleFactor> supported_factors;
    529   supported_factors.push_back(SCALE_FACTOR_100P);
    530   supported_factors.push_back(SCALE_FACTOR_140P);
    531   supported_factors.push_back(SCALE_FACTOR_180P);
    532   test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
    533 
    534   base::FilePath data_path = dir_path().AppendASCII("sample.pak");
    535   base::FilePath data_140P_path = dir_path().AppendASCII("sample_140P.pak");
    536   base::FilePath data_180P_path = dir_path().AppendASCII("sample_180P.pak");
    537 
    538   CreateDataPackWithSingleBitmap(data_path, 8, base::StringPiece());
    539   // Mark 140% and 180% images as requiring 1x fallback.
    540   CreateDataPackWithSingleBitmap(data_140P_path, 8, base::StringPiece(
    541     reinterpret_cast<const char*>(kPngScaleChunk),
    542     arraysize(kPngScaleChunk)));
    543   CreateDataPackWithSingleBitmap(data_180P_path, 8, base::StringPiece(
    544     reinterpret_cast<const char*>(kPngScaleChunk),
    545     arraysize(kPngScaleChunk)));
    546 
    547   ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
    548   resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
    549   resource_bundle->AddDataPackFromPath(data_140P_path, SCALE_FACTOR_140P);
    550   resource_bundle->AddDataPackFromPath(data_180P_path, SCALE_FACTOR_180P);
    551 
    552   // Non-integer dimensions should be rounded up.
    553   gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
    554   gfx::ImageSkiaRep image_rep =
    555     image_skia->GetRepresentation(
    556       GetImageScale(ui::SCALE_FACTOR_140P));
    557   EXPECT_EQ(12, image_rep.pixel_width());
    558   image_rep = image_skia->GetRepresentation(
    559     GetImageScale(ui::SCALE_FACTOR_180P));
    560   EXPECT_EQ(15, image_rep.pixel_width());
    561 }
    562 #endif
    563 
    564 TEST_F(ResourceBundleImageTest, FallbackToNone) {
    565   base::FilePath data_default_path = dir_path().AppendASCII("sample.pak");
    566 
    567   // Create the pak files.
    568   CreateDataPackWithSingleBitmap(data_default_path, 10, base::StringPiece());
    569 
    570     // Load the regular pak files only.
    571   ResourceBundle* resource_bundle = CreateResourceBundleWithEmptyLocalePak();
    572   resource_bundle->AddDataPackFromPath(data_default_path, SCALE_FACTOR_NONE);
    573 
    574   gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
    575   EXPECT_EQ(1u, image_skia->image_reps().size());
    576   EXPECT_EQ(ui::SCALE_FACTOR_100P,
    577             GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
    578 }
    579 
    580 }  // namespace ui
    581