• 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/gfx/image/image_skia.h"
6 
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/threading/simple_thread.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "third_party/skia/include/core/SkBitmap.h"
12 #include "ui/gfx/image/image_skia_rep.h"
13 #include "ui/gfx/image/image_skia_source.h"
14 #include "ui/gfx/size.h"
15 #include "ui/gfx/switches.h"
16 
17 // Duplicated from base/threading/non_thread_safe.h so that we can be
18 // good citizens there and undef the macro.
19 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
20 #define ENABLE_NON_THREAD_SAFE 1
21 #else
22 #define ENABLE_NON_THREAD_SAFE 0
23 #endif
24 
25 namespace gfx {
26 
27 namespace {
28 
29 class FixedSource : public ImageSkiaSource {
30  public:
FixedSource(const ImageSkiaRep & image)31   FixedSource(const ImageSkiaRep& image) : image_(image) {}
32 
~FixedSource()33   virtual ~FixedSource() {
34   }
35 
GetImageForScale(float scale)36   virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
37     return image_;
38   }
39 
40  private:
41   ImageSkiaRep image_;
42 
43   DISALLOW_COPY_AND_ASSIGN(FixedSource);
44 };
45 
46 class DynamicSource : public ImageSkiaSource {
47  public:
DynamicSource(const gfx::Size & size)48   DynamicSource(const gfx::Size& size)
49       : size_(size),
50         last_requested_scale_(0.0f) {}
51 
~DynamicSource()52   virtual ~DynamicSource() {
53   }
54 
GetImageForScale(float scale)55   virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
56     last_requested_scale_ = scale;
57     return gfx::ImageSkiaRep(size_, scale);
58   }
59 
GetLastRequestedScaleAndReset()60   float GetLastRequestedScaleAndReset() {
61     float result = last_requested_scale_;
62     last_requested_scale_ = 0.0f;
63     return result;
64   }
65 
66  private:
67   gfx::Size size_;
68   float last_requested_scale_;
69 
70   DISALLOW_COPY_AND_ASSIGN(DynamicSource);
71 };
72 
73 class NullSource: public ImageSkiaSource {
74  public:
NullSource()75   NullSource() {
76   }
77 
~NullSource()78   virtual ~NullSource() {
79   }
80 
GetImageForScale(float scale)81   virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
82     return gfx::ImageSkiaRep();
83   }
84 
85  private:
86   DISALLOW_COPY_AND_ASSIGN(NullSource);
87 };
88 
89 }  // namespace
90 
91 namespace test {
92 class TestOnThread : public base::SimpleThread {
93  public:
TestOnThread(ImageSkia * image_skia)94   explicit TestOnThread(ImageSkia* image_skia)
95       : SimpleThread("image_skia_on_thread"),
96         image_skia_(image_skia),
97         can_read_(false),
98         can_modify_(false) {
99   }
100 
Run()101   virtual void Run() OVERRIDE {
102     can_read_ = image_skia_->CanRead();
103     can_modify_ = image_skia_->CanModify();
104     if (can_read_)
105       image_skia_->image_reps();
106   }
107 
StartAndJoin()108   void StartAndJoin() {
109     Start();
110     Join();
111   }
112 
can_read() const113   bool can_read() const { return can_read_; }
114 
can_modify() const115   bool can_modify() const { return can_modify_; }
116 
117  private:
118   ImageSkia* image_skia_;
119 
120   bool can_read_;
121   bool can_modify_;
122 
123   DISALLOW_COPY_AND_ASSIGN(TestOnThread);
124 };
125 
126 }  // namespace test
127 
128 class ImageSkiaTest : public testing::Test {
129  public:
ImageSkiaTest()130   ImageSkiaTest() {
131     // In the test, we assume that we support 1.0f and 2.0f DSFs.
132     old_scales_ = ImageSkia::GetSupportedScales();
133 
134     // Sets the list of scale factors supported by resource bundle.
135     std::vector<float> supported_scales;
136     supported_scales.push_back(1.0f);
137     supported_scales.push_back(2.0f);
138     ImageSkia::SetSupportedScales(supported_scales);
139   }
~ImageSkiaTest()140   virtual ~ImageSkiaTest() {
141     ImageSkia::SetSupportedScales(old_scales_);
142   }
143 
144  private:
145   std::vector<float> old_scales_;
146   DISALLOW_COPY_AND_ASSIGN(ImageSkiaTest);
147 };
148 
TEST_F(ImageSkiaTest,FixedSource)149 TEST_F(ImageSkiaTest, FixedSource) {
150   ImageSkiaRep image(Size(100, 200), 1.0f);
151   ImageSkia image_skia(new FixedSource(image), Size(100, 200));
152   EXPECT_EQ(0U, image_skia.image_reps().size());
153 
154   const ImageSkiaRep& result_100p = image_skia.GetRepresentation(1.0f);
155   EXPECT_EQ(100, result_100p.GetWidth());
156   EXPECT_EQ(200, result_100p.GetHeight());
157   EXPECT_EQ(1.0f, result_100p.scale());
158   EXPECT_EQ(1U, image_skia.image_reps().size());
159 
160   const ImageSkiaRep& result_200p = image_skia.GetRepresentation(2.0f);
161 
162   EXPECT_EQ(100, result_200p.GetWidth());
163   EXPECT_EQ(200, result_200p.GetHeight());
164   EXPECT_EQ(100, result_200p.pixel_width());
165   EXPECT_EQ(200, result_200p.pixel_height());
166   EXPECT_EQ(1.0f, result_200p.scale());
167   EXPECT_EQ(1U, image_skia.image_reps().size());
168 
169   // Get the representation again and make sure it doesn't
170   // generate new image skia rep.
171   image_skia.GetRepresentation(1.0f);
172   image_skia.GetRepresentation(2.0f);
173   EXPECT_EQ(1U, image_skia.image_reps().size());
174 }
175 
TEST_F(ImageSkiaTest,DynamicSource)176 TEST_F(ImageSkiaTest, DynamicSource) {
177   ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200));
178   EXPECT_EQ(0U, image_skia.image_reps().size());
179   const ImageSkiaRep& result_100p = image_skia.GetRepresentation(1.0f);
180   EXPECT_EQ(100, result_100p.GetWidth());
181   EXPECT_EQ(200, result_100p.GetHeight());
182   EXPECT_EQ(1.0f, result_100p.scale());
183   EXPECT_EQ(1U, image_skia.image_reps().size());
184 
185   const ImageSkiaRep& result_200p =
186       image_skia.GetRepresentation(2.0f);
187   EXPECT_EQ(100, result_200p.GetWidth());
188   EXPECT_EQ(200, result_200p.GetHeight());
189   EXPECT_EQ(200, result_200p.pixel_width());
190   EXPECT_EQ(400, result_200p.pixel_height());
191   EXPECT_EQ(2.0f, result_200p.scale());
192   EXPECT_EQ(2U, image_skia.image_reps().size());
193 
194   // Get the representation again and make sure it doesn't
195   // generate new image skia rep.
196   image_skia.GetRepresentation(1.0f);
197   EXPECT_EQ(2U, image_skia.image_reps().size());
198   image_skia.GetRepresentation(2.0f);
199   EXPECT_EQ(2U, image_skia.image_reps().size());
200 }
201 
202 // Tests that image_reps returns all of the representations in the
203 // image when there are multiple representations for a scale factor.
204 // This currently is the case with ImageLoader::LoadImages.
TEST_F(ImageSkiaTest,ManyRepsPerScaleFactor)205 TEST_F(ImageSkiaTest, ManyRepsPerScaleFactor) {
206   const int kSmallIcon1x = 16;
207   const int kSmallIcon2x = 32;
208   const int kLargeIcon1x = 32;
209 
210   ImageSkia image(new NullSource(), gfx::Size(kSmallIcon1x, kSmallIcon1x));
211   // Simulate a source which loads images on a delay. Upon
212   // GetImageForScaleFactor, it immediately returns null and starts loading
213   // image reps slowly.
214   image.GetRepresentation(1.0f);
215   image.GetRepresentation(2.0f);
216 
217   // After a lengthy amount of simulated time, finally loaded image reps.
218   image.AddRepresentation(ImageSkiaRep(
219       gfx::Size(kSmallIcon1x, kSmallIcon1x), 1.0f));
220   image.AddRepresentation(ImageSkiaRep(
221       gfx::Size(kSmallIcon2x, kSmallIcon2x), 2.0f));
222   image.AddRepresentation(ImageSkiaRep(
223       gfx::Size(kLargeIcon1x, kLargeIcon1x), 1.0f));
224 
225   std::vector<ImageSkiaRep> image_reps = image.image_reps();
226   EXPECT_EQ(3u, image_reps.size());
227 
228   int num_1x = 0;
229   int num_2x = 0;
230   for (size_t i = 0; i < image_reps.size(); ++i) {
231     if (image_reps[i].scale() == 1.0f)
232       num_1x++;
233     else if (image_reps[i].scale() == 2.0f)
234       num_2x++;
235   }
236   EXPECT_EQ(2, num_1x);
237   EXPECT_EQ(1, num_2x);
238 }
239 
TEST_F(ImageSkiaTest,GetBitmap)240 TEST_F(ImageSkiaTest, GetBitmap) {
241   ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200));
242   const SkBitmap* bitmap = image_skia.bitmap();
243   EXPECT_NE(static_cast<SkBitmap*>(NULL), bitmap);
244   EXPECT_FALSE(bitmap->isNull());
245 }
246 
TEST_F(ImageSkiaTest,GetBitmapFromEmpty)247 TEST_F(ImageSkiaTest, GetBitmapFromEmpty) {
248   // Create an image with 1 representation and remove it so the ImageSkiaStorage
249   // is left with no representations.
250   ImageSkia empty_image(ImageSkiaRep(Size(100, 200), 1.0f));
251   ImageSkia empty_image_copy(empty_image);
252   empty_image.RemoveRepresentation(1.0f);
253 
254   // Check that ImageSkia::bitmap() still returns a valid SkBitmap pointer for
255   // the image and all its copies.
256   const SkBitmap* bitmap = empty_image_copy.bitmap();
257   ASSERT_NE(static_cast<SkBitmap*>(NULL), bitmap);
258   EXPECT_TRUE(bitmap->isNull());
259   EXPECT_TRUE(bitmap->empty());
260 }
261 
TEST_F(ImageSkiaTest,BackedBySameObjectAs)262 TEST_F(ImageSkiaTest, BackedBySameObjectAs) {
263   // Null images should all be backed by the same object (NULL).
264   ImageSkia image;
265   ImageSkia unrelated;
266   EXPECT_TRUE(image.BackedBySameObjectAs(unrelated));
267 
268   image.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10),
269                                             1.0f));
270   ImageSkia copy = image;
271   copy.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10),
272                                            2.0f));
273   unrelated.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10),
274                                                 1.0f));
275   EXPECT_TRUE(image.BackedBySameObjectAs(copy));
276   EXPECT_FALSE(image.BackedBySameObjectAs(unrelated));
277   EXPECT_FALSE(copy.BackedBySameObjectAs(unrelated));
278 }
279 
280 #if ENABLE_NON_THREAD_SAFE
TEST_F(ImageSkiaTest,EmptyOnThreadTest)281 TEST_F(ImageSkiaTest, EmptyOnThreadTest) {
282   ImageSkia empty;
283   test::TestOnThread empty_on_thread(&empty);
284   empty_on_thread.Start();
285   empty_on_thread.Join();
286   EXPECT_TRUE(empty_on_thread.can_read());
287   EXPECT_TRUE(empty_on_thread.can_modify());
288 }
289 
TEST_F(ImageSkiaTest,StaticOnThreadTest)290 TEST_F(ImageSkiaTest, StaticOnThreadTest) {
291   ImageSkia image(ImageSkiaRep(Size(100, 200), 1.0f));
292   EXPECT_FALSE(image.IsThreadSafe());
293 
294   test::TestOnThread image_on_thread(&image);
295   // an image that was never accessed on this thread can be
296   // read by other thread.
297   image_on_thread.StartAndJoin();
298   EXPECT_TRUE(image_on_thread.can_read());
299   EXPECT_TRUE(image_on_thread.can_modify());
300   EXPECT_FALSE(image.CanRead());
301   EXPECT_FALSE(image.CanModify());
302 
303   image.DetachStorageFromThread();
304   // An image is accessed by this thread,
305   // so other thread cannot read/modify it.
306   image.image_reps();
307   test::TestOnThread image_on_thread2(&image);
308   image_on_thread2.StartAndJoin();
309   EXPECT_FALSE(image_on_thread2.can_read());
310   EXPECT_FALSE(image_on_thread2.can_modify());
311   EXPECT_TRUE(image.CanRead());
312   EXPECT_TRUE(image.CanModify());
313 
314   image.DetachStorageFromThread();
315   scoped_ptr<ImageSkia> deep_copy(image.DeepCopy());
316   EXPECT_FALSE(deep_copy->IsThreadSafe());
317   test::TestOnThread deepcopy_on_thread(deep_copy.get());
318   deepcopy_on_thread.StartAndJoin();
319   EXPECT_TRUE(deepcopy_on_thread.can_read());
320   EXPECT_TRUE(deepcopy_on_thread.can_modify());
321   EXPECT_FALSE(deep_copy->CanRead());
322   EXPECT_FALSE(deep_copy->CanModify());
323 
324   scoped_ptr<ImageSkia> deep_copy2(image.DeepCopy());
325   EXPECT_EQ(1U, deep_copy2->image_reps().size());
326   // Access it from current thread so that it can't be
327   // accessed from another thread.
328   deep_copy2->image_reps();
329   EXPECT_FALSE(deep_copy2->IsThreadSafe());
330   test::TestOnThread deepcopy2_on_thread(deep_copy2.get());
331   deepcopy2_on_thread.StartAndJoin();
332   EXPECT_FALSE(deepcopy2_on_thread.can_read());
333   EXPECT_FALSE(deepcopy2_on_thread.can_modify());
334   EXPECT_TRUE(deep_copy2->CanRead());
335   EXPECT_TRUE(deep_copy2->CanModify());
336 
337   image.DetachStorageFromThread();
338   image.SetReadOnly();
339   // A read-only ImageSkia with no source is thread safe.
340   EXPECT_TRUE(image.IsThreadSafe());
341   test::TestOnThread readonly_on_thread(&image);
342   readonly_on_thread.StartAndJoin();
343   EXPECT_TRUE(readonly_on_thread.can_read());
344   EXPECT_FALSE(readonly_on_thread.can_modify());
345   EXPECT_TRUE(image.CanRead());
346   EXPECT_FALSE(image.CanModify());
347 
348   image.DetachStorageFromThread();
349   image.MakeThreadSafe();
350   EXPECT_TRUE(image.IsThreadSafe());
351   test::TestOnThread threadsafe_on_thread(&image);
352   threadsafe_on_thread.StartAndJoin();
353   EXPECT_TRUE(threadsafe_on_thread.can_read());
354   EXPECT_FALSE(threadsafe_on_thread.can_modify());
355   EXPECT_TRUE(image.CanRead());
356   EXPECT_FALSE(image.CanModify());
357 }
358 
TEST_F(ImageSkiaTest,SourceOnThreadTest)359 TEST_F(ImageSkiaTest, SourceOnThreadTest) {
360   ImageSkia image(new DynamicSource(Size(100, 200)), Size(100, 200));
361   EXPECT_FALSE(image.IsThreadSafe());
362 
363   test::TestOnThread image_on_thread(&image);
364   image_on_thread.StartAndJoin();
365   // an image that was never accessed on this thread can be
366   // read by other thread.
367   EXPECT_TRUE(image_on_thread.can_read());
368   EXPECT_TRUE(image_on_thread.can_modify());
369   EXPECT_FALSE(image.CanRead());
370   EXPECT_FALSE(image.CanModify());
371 
372   image.DetachStorageFromThread();
373   // An image is accessed by this thread,
374   // so other thread cannot read/modify it.
375   image.image_reps();
376   test::TestOnThread image_on_thread2(&image);
377   image_on_thread2.StartAndJoin();
378   EXPECT_FALSE(image_on_thread2.can_read());
379   EXPECT_FALSE(image_on_thread2.can_modify());
380   EXPECT_TRUE(image.CanRead());
381   EXPECT_TRUE(image.CanModify());
382 
383   image.DetachStorageFromThread();
384   image.SetReadOnly();
385   EXPECT_FALSE(image.IsThreadSafe());
386   test::TestOnThread readonly_on_thread(&image);
387   readonly_on_thread.StartAndJoin();
388   EXPECT_TRUE(readonly_on_thread.can_read());
389   EXPECT_FALSE(readonly_on_thread.can_modify());
390   EXPECT_FALSE(image.CanRead());
391   EXPECT_FALSE(image.CanModify());
392 
393   image.DetachStorageFromThread();
394   image.MakeThreadSafe();
395   EXPECT_TRUE(image.IsThreadSafe());
396   // Check if image reps are generated for supported scale factors.
397   EXPECT_EQ(ImageSkia::GetSupportedScales().size(),
398            image.image_reps().size());
399   test::TestOnThread threadsafe_on_thread(&image);
400   threadsafe_on_thread.StartAndJoin();
401   EXPECT_TRUE(threadsafe_on_thread.can_read());
402   EXPECT_FALSE(threadsafe_on_thread.can_modify());
403   EXPECT_TRUE(image.CanRead());
404   EXPECT_FALSE(image.CanModify());
405 }
406 #endif  // ENABLE_NON_THREAD_SAFE
407 
408 // Just in case we ever get lumped together with other compilation units.
409 #undef ENABLE_NON_THREAD_SAFE
410 
TEST_F(ImageSkiaTest,Unscaled)411 TEST_F(ImageSkiaTest, Unscaled) {
412   SkBitmap bitmap;
413 
414   // An ImageSkia created with 1x bitmap is unscaled.
415   ImageSkia image_skia = ImageSkia::CreateFrom1xBitmap(bitmap);
416   EXPECT_TRUE(image_skia.GetRepresentation(1.0f).unscaled());
417   ImageSkiaRep rep_2x(Size(100, 100), 2.0f);
418 
419   // When reps for other scales are added, the unscaled image
420   // becomes scaled.
421   image_skia.AddRepresentation(rep_2x);
422   EXPECT_FALSE(image_skia.GetRepresentation(1.0f).unscaled());
423   EXPECT_FALSE(image_skia.GetRepresentation(2.0f).unscaled());
424 }
425 
426 namespace {
427 
GetSortedScaleFactors(const gfx::ImageSkia & image)428 std::vector<float> GetSortedScaleFactors(const gfx::ImageSkia& image) {
429   const std::vector<ImageSkiaRep>& image_reps = image.image_reps();
430   std::vector<float> scale_factors;
431   for (size_t i = 0; i < image_reps.size(); ++i) {
432     scale_factors.push_back(image_reps[i].scale());
433   }
434   std::sort(scale_factors.begin(), scale_factors.end());
435   return scale_factors;
436 }
437 
438 }  // namespace
439 
TEST_F(ImageSkiaTest,ArbitraryScaleFactor)440 TEST_F(ImageSkiaTest, ArbitraryScaleFactor) {
441   // Do not test if the ImageSkia doesn't support arbitrary scale factors.
442   if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
443     return;
444 
445   // source is owned by |image|
446   DynamicSource* source = new DynamicSource(Size(100, 200));
447   ImageSkia image(source, gfx::Size(100, 200));
448 
449   image.GetRepresentation(1.5f);
450   EXPECT_EQ(2.0f, source->GetLastRequestedScaleAndReset());
451   std::vector<ImageSkiaRep> image_reps = image.image_reps();
452   EXPECT_EQ(2u, image_reps.size());
453 
454   std::vector<float> scale_factors = GetSortedScaleFactors(image);
455   EXPECT_EQ(1.5f, scale_factors[0]);
456   EXPECT_EQ(2.0f, scale_factors[1]);
457 
458   // Requesting 1.75 scale factor also falls back to 2.0f and rescale.
459   // However, the image already has the 2.0f data, so it won't fetch again.
460   image.GetRepresentation(1.75f);
461   EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
462   image_reps = image.image_reps();
463   EXPECT_EQ(3u, image_reps.size());
464 
465   scale_factors = GetSortedScaleFactors(image);
466   EXPECT_EQ(1.5f, scale_factors[0]);
467   EXPECT_EQ(1.75f, scale_factors[1]);
468   EXPECT_EQ(2.0f, scale_factors[2]);
469 
470   // Requesting 1.25 scale factor also falls back to 2.0f and rescale.
471   // However, the image already has the 2.0f data, so it won't fetch again.
472   image.GetRepresentation(1.25f);
473   EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
474   image_reps = image.image_reps();
475   EXPECT_EQ(4u, image_reps.size());
476   scale_factors = GetSortedScaleFactors(image);
477   EXPECT_EQ(1.25f, scale_factors[0]);
478   EXPECT_EQ(1.5f, scale_factors[1]);
479   EXPECT_EQ(1.75f, scale_factors[2]);
480   EXPECT_EQ(2.0f, scale_factors[3]);
481 
482   // 1.20 is falled back to 1.0.
483   image.GetRepresentation(1.20f);
484   EXPECT_EQ(1.0f, source->GetLastRequestedScaleAndReset());
485   image_reps = image.image_reps();
486   EXPECT_EQ(6u, image_reps.size());
487   scale_factors = GetSortedScaleFactors(image);
488   EXPECT_EQ(1.0f, scale_factors[0]);
489   EXPECT_EQ(1.2f, scale_factors[1]);
490   EXPECT_EQ(1.25f, scale_factors[2]);
491   EXPECT_EQ(1.5f, scale_factors[3]);
492   EXPECT_EQ(1.75f, scale_factors[4]);
493   EXPECT_EQ(2.0f, scale_factors[5]);
494 
495   // Scale factor less than 1.0f will be falled back to 1.0f
496   image.GetRepresentation(0.75f);
497   EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
498   image_reps = image.image_reps();
499   EXPECT_EQ(7u, image_reps.size());
500 
501   scale_factors = GetSortedScaleFactors(image);
502   EXPECT_EQ(0.75f, scale_factors[0]);
503   EXPECT_EQ(1.0f, scale_factors[1]);
504   EXPECT_EQ(1.2f, scale_factors[2]);
505   EXPECT_EQ(1.25f, scale_factors[3]);
506   EXPECT_EQ(1.5f, scale_factors[4]);
507   EXPECT_EQ(1.75f, scale_factors[5]);
508   EXPECT_EQ(2.0f, scale_factors[6]);
509 
510   // Scale factor greater than 2.0f is falled back to 2.0f because it's not
511   // supported.
512   image.GetRepresentation(3.0f);
513   EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
514   image_reps = image.image_reps();
515   EXPECT_EQ(8u, image_reps.size());
516 }
517 
TEST_F(ImageSkiaTest,ArbitraryScaleFactorWithMissingResource)518 TEST_F(ImageSkiaTest, ArbitraryScaleFactorWithMissingResource) {
519   // Do not test if the ImageSkia doesn't support arbitrary scale factors.
520   if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
521     return;
522 
523   ImageSkia image(new FixedSource(
524       ImageSkiaRep(Size(100, 200), 1.0f)), Size(100, 200));
525 
526   // Requesting 1.5f -- falls back to 2.0f, but couldn't find. It should
527   // look up 1.0f and then rescale it.
528   const ImageSkiaRep& rep = image.GetRepresentation(1.5f);
529   EXPECT_EQ(1.5f, rep.scale());
530   EXPECT_EQ(2U, image.image_reps().size());
531   EXPECT_EQ(1.0f, image.image_reps()[0].scale());
532   EXPECT_EQ(1.5f, image.image_reps()[1].scale());
533 }
534 
TEST_F(ImageSkiaTest,UnscaledImageForArbitraryScaleFactor)535 TEST_F(ImageSkiaTest, UnscaledImageForArbitraryScaleFactor) {
536   // Do not test if the ImageSkia doesn't support arbitrary scale factors.
537   if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
538     return;
539 
540   // 0.0f means unscaled.
541   ImageSkia image(new FixedSource(
542       ImageSkiaRep(Size(100, 200), 0.0f)), Size(100, 200));
543 
544   // Requesting 2.0f, which should return 1.0f unscaled image.
545   const ImageSkiaRep& rep = image.GetRepresentation(2.0f);
546   EXPECT_EQ(1.0f, rep.scale());
547   EXPECT_EQ("100x200", rep.pixel_size().ToString());
548   EXPECT_TRUE(rep.unscaled());
549   EXPECT_EQ(1U, image.image_reps().size());
550 
551   // Same for any other scale factors.
552   const ImageSkiaRep& rep15 = image.GetRepresentation(1.5f);
553   EXPECT_EQ(1.0f, rep15.scale());
554   EXPECT_EQ("100x200", rep15.pixel_size().ToString());
555   EXPECT_TRUE(rep15.unscaled());
556   EXPECT_EQ(1U, image.image_reps().size());
557 
558   const ImageSkiaRep& rep12 = image.GetRepresentation(1.2f);
559   EXPECT_EQ(1.0f, rep12.scale());
560   EXPECT_EQ("100x200", rep12.pixel_size().ToString());
561   EXPECT_TRUE(rep12.unscaled());
562   EXPECT_EQ(1U, image.image_reps().size());
563 }
564 
565 }  // namespace gfx
566