resource_bundle_unittest.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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
28using ::testing::_;
29using ::testing::Between;
30using ::testing::Property;
31using ::testing::Return;
32using ::testing::ReturnArg;
33
34namespace ui {
35
36extern const char kSamplePakContents[];
37extern const size_t kSamplePakSize;
38extern const char kSamplePakContents2x[];
39extern const size_t kSamplePakSize2x;
40extern const char kEmptyPakContents[];
41extern const size_t kEmptyPakSize;
42
43namespace {
44
45const unsigned char kPngMagic[8] = { 0x89, 'P', 'N', 'G', 13, 10, 26, 10 };
46const size_t kPngChunkMetadataSize = 12;
47const 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.
51const 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.
56class 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.
98void 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.
126void 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
147class 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
177TEST_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
200TEST_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
224TEST_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
239TEST_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
259TEST_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
279TEST_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
299TEST_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
320TEST_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
340TEST_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
348class 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.
388TEST_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
411TEST_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().
444TEST_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.
503TEST_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.
540TEST_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
583TEST_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