• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
MockResourceBundleDelegate()59   MockResourceBundleDelegate() {
60   }
~MockResourceBundleDelegate()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));
GetRawDataResource(int resource_id,ui::ScaleFactor scale_factor,base::StringPiece * value)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));
GetLocalizedString(int message_id,base::string16 * value)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));
GetFont(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.
AddCustomChunk(const base::StringPiece & custom_chunk,std::vector<unsigned char> * bitmap_data)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.
CreateDataPackWithSingleBitmap(const base::FilePath & path,int edge_size,const base::StringPiece & custom_chunk)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:
ResourceBundleTest()149   ResourceBundleTest() : resource_bundle_(NULL) {
150   }
151 
~ResourceBundleTest()152   virtual ~ResourceBundleTest() {
153   }
154 
155   // Overridden from testing::Test:
TearDown()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.
CreateResourceBundle(ResourceBundle::Delegate * delegate)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 
TEST_F(ResourceBundleTest,DelegateGetPathForResourcePack)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
TEST_F(ResourceBundleTest,MAYBE_DelegateGetPathForLocalePack)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 
TEST_F(ResourceBundleTest,DelegateGetImageNamed)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 
TEST_F(ResourceBundleTest,DelegateGetNativeImageNamed)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 
TEST_F(ResourceBundleTest,DelegateLoadDataResourceBytes)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 
TEST_F(ResourceBundleTest,DelegateGetRawDataResource)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 
TEST_F(ResourceBundleTest,DelegateGetLocalizedString)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 
TEST_F(ResourceBundleTest,OverrideStringResource)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 
TEST_F(ResourceBundleTest,DelegateGetLocalizedStringWithOverride)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 
TEST_F(ResourceBundleTest,MAYBE_DelegateGetFontList)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 
TEST_F(ResourceBundleTest,LocaleDataPakExists)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:
ResourceBundleImageTest()381   ResourceBundleImageTest() {}
382 
~ResourceBundleImageTest()383   virtual ~ResourceBundleImageTest() {
384   }
385 
SetUp()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.
CreateResourceBundleWithEmptyLocalePak()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.
dir_path()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.
TEST_F(ResourceBundleImageTest,LoadDataResourceBytes)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 
TEST_F(ResourceBundleImageTest,GetRawDataResource)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().
TEST_F(ResourceBundleImageTest,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.
TEST_F(ResourceBundleImageTest,GetImageNamedFallback1x)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.
TEST_F(ResourceBundleImageTest,GetImageNamedFallback1xRounding)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
TEST_F(ResourceBundleImageTest,MAYBE_FallbackToNone)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