Home | History | Annotate | Download | only in image
      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/logging.h"
      8 #include "base/threading/simple_thread.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 #include "third_party/skia/include/core/SkBitmap.h"
     11 #include "ui/base/layout.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 
     16 // Duplicated from base/threading/non_thread_safe.h so that we can be
     17 // good citizens there and undef the macro.
     18 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
     19 #define ENABLE_NON_THREAD_SAFE 1
     20 #else
     21 #define ENABLE_NON_THREAD_SAFE 0
     22 #endif
     23 
     24 namespace gfx {
     25 
     26 namespace {
     27 
     28 class FixedSource : public ImageSkiaSource {
     29  public:
     30   FixedSource(const ImageSkiaRep& image) : image_(image) {}
     31 
     32   virtual ~FixedSource() {
     33   }
     34 
     35   virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE {
     36     return image_;
     37   }
     38 
     39  private:
     40   ImageSkiaRep image_;
     41 
     42   DISALLOW_COPY_AND_ASSIGN(FixedSource);
     43 };
     44 
     45 class DynamicSource : public ImageSkiaSource {
     46  public:
     47   DynamicSource(const gfx::Size& size) : size_(size) {}
     48 
     49   virtual ~DynamicSource() {
     50   }
     51 
     52   virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE {
     53     return gfx::ImageSkiaRep(size_, scale_factor);
     54   }
     55 
     56  private:
     57   gfx::Size size_;
     58 
     59   DISALLOW_COPY_AND_ASSIGN(DynamicSource);
     60 };
     61 
     62 class NullSource: public ImageSkiaSource {
     63  public:
     64   NullSource() {
     65   }
     66 
     67   virtual ~NullSource() {
     68   }
     69 
     70   virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE {
     71     return gfx::ImageSkiaRep();
     72   }
     73 
     74  private:
     75   DISALLOW_COPY_AND_ASSIGN(NullSource);
     76 };
     77 
     78 }  // namespace
     79 
     80 namespace test {
     81 class TestOnThread : public base::SimpleThread {
     82  public:
     83   explicit TestOnThread(ImageSkia* image_skia)
     84       : SimpleThread("image_skia_on_thread"),
     85         image_skia_(image_skia),
     86         can_read_(false),
     87         can_modify_(false) {
     88   }
     89 
     90   virtual void Run() OVERRIDE {
     91     can_read_ = image_skia_->CanRead();
     92     can_modify_ = image_skia_->CanModify();
     93     if (can_read_)
     94       image_skia_->image_reps();
     95   }
     96 
     97   void StartAndJoin() {
     98     Start();
     99     Join();
    100   }
    101 
    102   bool can_read() const { return can_read_; }
    103 
    104   bool can_modify() const { return can_modify_; }
    105 
    106  private:
    107   ImageSkia* image_skia_;
    108 
    109   bool can_read_;
    110   bool can_modify_;
    111 
    112   DISALLOW_COPY_AND_ASSIGN(TestOnThread);
    113 };
    114 
    115 }  // namespace test
    116 
    117 TEST(ImageSkiaTest, FixedSource) {
    118   ImageSkiaRep image(Size(100, 200), ui::SCALE_FACTOR_100P);
    119   ImageSkia image_skia(new FixedSource(image), Size(100, 200));
    120   EXPECT_EQ(0U, image_skia.image_reps().size());
    121 
    122   const ImageSkiaRep& result_100p =
    123       image_skia.GetRepresentation(ui::SCALE_FACTOR_100P);
    124   EXPECT_EQ(100, result_100p.GetWidth());
    125   EXPECT_EQ(200, result_100p.GetHeight());
    126   EXPECT_EQ(ui::SCALE_FACTOR_100P, result_100p.scale_factor());
    127   EXPECT_EQ(1U, image_skia.image_reps().size());
    128 
    129   const ImageSkiaRep& result_200p =
    130       image_skia.GetRepresentation(ui::SCALE_FACTOR_200P);
    131 
    132   EXPECT_EQ(100, result_200p.GetWidth());
    133   EXPECT_EQ(200, result_200p.GetHeight());
    134   EXPECT_EQ(100, result_200p.pixel_width());
    135   EXPECT_EQ(200, result_200p.pixel_height());
    136   EXPECT_EQ(ui::SCALE_FACTOR_100P, result_200p.scale_factor());
    137   EXPECT_EQ(1U, image_skia.image_reps().size());
    138 
    139   // Get the representation again and make sure it doesn't
    140   // generate new image skia rep.
    141   image_skia.GetRepresentation(ui::SCALE_FACTOR_100P);
    142   image_skia.GetRepresentation(ui::SCALE_FACTOR_200P);
    143   EXPECT_EQ(1U, image_skia.image_reps().size());
    144 }
    145 
    146 TEST(ImageSkiaTest, DynamicSource) {
    147   ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200));
    148   EXPECT_EQ(0U, image_skia.image_reps().size());
    149   const ImageSkiaRep& result_100p =
    150       image_skia.GetRepresentation(ui::SCALE_FACTOR_100P);
    151   EXPECT_EQ(100, result_100p.GetWidth());
    152   EXPECT_EQ(200, result_100p.GetHeight());
    153   EXPECT_EQ(ui::SCALE_FACTOR_100P, result_100p.scale_factor());
    154   EXPECT_EQ(1U, image_skia.image_reps().size());
    155 
    156   const ImageSkiaRep& result_200p =
    157       image_skia.GetRepresentation(ui::SCALE_FACTOR_200P);
    158   EXPECT_EQ(100, result_200p.GetWidth());
    159   EXPECT_EQ(200, result_200p.GetHeight());
    160   EXPECT_EQ(200, result_200p.pixel_width());
    161   EXPECT_EQ(400, result_200p.pixel_height());
    162   EXPECT_EQ(ui::SCALE_FACTOR_200P, result_200p.scale_factor());
    163   EXPECT_EQ(2U, image_skia.image_reps().size());
    164 
    165   // Get the representation again and make sure it doesn't
    166   // generate new image skia rep.
    167   image_skia.GetRepresentation(ui::SCALE_FACTOR_100P);
    168   EXPECT_EQ(2U, image_skia.image_reps().size());
    169   image_skia.GetRepresentation(ui::SCALE_FACTOR_200P);
    170   EXPECT_EQ(2U, image_skia.image_reps().size());
    171 }
    172 
    173 // Tests that image_reps returns all of the representations in the
    174 // image when there are multiple representations for a scale factor.
    175 // This currently is the case with ImageLoader::LoadImages.
    176 TEST(ImageSkiaTest, ManyRepsPerScaleFactor) {
    177   const int kSmallIcon1x = 16;
    178   const int kSmallIcon2x = 32;
    179   const int kLargeIcon1x = 32;
    180 
    181   ImageSkia image(new NullSource(), gfx::Size(kSmallIcon1x, kSmallIcon1x));
    182   // Simulate a source which loads images on a delay. Upon
    183   // GetImageForScaleFactor, it immediately returns null and starts loading
    184   // image reps slowly.
    185   image.GetRepresentation(ui::SCALE_FACTOR_100P);
    186   image.GetRepresentation(ui::SCALE_FACTOR_200P);
    187 
    188   // After a lengthy amount of simulated time, finally loaded image reps.
    189   image.AddRepresentation(ImageSkiaRep(
    190       gfx::Size(kSmallIcon1x, kSmallIcon1x), ui::SCALE_FACTOR_100P));
    191   image.AddRepresentation(ImageSkiaRep(
    192       gfx::Size(kSmallIcon2x, kSmallIcon2x), ui::SCALE_FACTOR_200P));
    193   image.AddRepresentation(ImageSkiaRep(
    194       gfx::Size(kLargeIcon1x, kLargeIcon1x), ui::SCALE_FACTOR_100P));
    195 
    196   std::vector<ImageSkiaRep> image_reps = image.image_reps();
    197   EXPECT_EQ(3u, image_reps.size());
    198 
    199   int num_1x = 0;
    200   int num_2x = 0;
    201   for (size_t i = 0; i < image_reps.size(); ++i) {
    202     if (image_reps[i].scale_factor() == ui::SCALE_FACTOR_100P)
    203       num_1x++;
    204     else if (image_reps[i].scale_factor() == ui::SCALE_FACTOR_200P)
    205       num_2x++;
    206   }
    207   EXPECT_EQ(2, num_1x);
    208   EXPECT_EQ(1, num_2x);
    209 }
    210 
    211 TEST(ImageSkiaTest, GetBitmap) {
    212   ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200));
    213   const SkBitmap* bitmap = image_skia.bitmap();
    214   EXPECT_NE(static_cast<SkBitmap*>(NULL), bitmap);
    215   EXPECT_FALSE(bitmap->isNull());
    216 }
    217 
    218 TEST(ImageSkiaTest, GetBitmapFromEmpty) {
    219   // Create an image with 1 representation and remove it so the ImageSkiaStorage
    220   // is left with no representations.
    221   ImageSkia empty_image(ImageSkiaRep(Size(100, 200), ui::SCALE_FACTOR_100P));
    222   ImageSkia empty_image_copy(empty_image);
    223   empty_image.RemoveRepresentation(ui::SCALE_FACTOR_100P);
    224 
    225   // Check that ImageSkia::bitmap() still returns a valid SkBitmap pointer for
    226   // the image and all its copies.
    227   const SkBitmap* bitmap = empty_image_copy.bitmap();
    228   ASSERT_NE(static_cast<SkBitmap*>(NULL), bitmap);
    229   EXPECT_TRUE(bitmap->isNull());
    230   EXPECT_TRUE(bitmap->empty());
    231 }
    232 
    233 TEST(ImageSkiaTest, BackedBySameObjectAs) {
    234   // Null images should all be backed by the same object (NULL).
    235   ImageSkia image;
    236   ImageSkia unrelated;
    237   EXPECT_TRUE(image.BackedBySameObjectAs(unrelated));
    238 
    239   image.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10),
    240                                             ui::SCALE_FACTOR_100P));
    241   ImageSkia copy = image;
    242   copy.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10),
    243                                            ui::SCALE_FACTOR_200P));
    244   unrelated.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10),
    245                                                 ui::SCALE_FACTOR_100P));
    246   EXPECT_TRUE(image.BackedBySameObjectAs(copy));
    247   EXPECT_FALSE(image.BackedBySameObjectAs(unrelated));
    248   EXPECT_FALSE(copy.BackedBySameObjectAs(unrelated));
    249 }
    250 
    251 #if ENABLE_NON_THREAD_SAFE
    252 TEST(ImageSkiaTest, EmptyOnThreadTest) {
    253   ImageSkia empty;
    254   test::TestOnThread empty_on_thread(&empty);
    255   empty_on_thread.Start();
    256   empty_on_thread.Join();
    257   EXPECT_TRUE(empty_on_thread.can_read());
    258   EXPECT_TRUE(empty_on_thread.can_modify());
    259 }
    260 
    261 TEST(ImageSkiaTest, StaticOnThreadTest) {
    262   ImageSkia image(ImageSkiaRep(Size(100, 200), ui::SCALE_FACTOR_100P));
    263   EXPECT_FALSE(image.IsThreadSafe());
    264 
    265   test::TestOnThread image_on_thread(&image);
    266   // an image that was never accessed on this thread can be
    267   // read by other thread.
    268   image_on_thread.StartAndJoin();
    269   EXPECT_TRUE(image_on_thread.can_read());
    270   EXPECT_TRUE(image_on_thread.can_modify());
    271   EXPECT_FALSE(image.CanRead());
    272   EXPECT_FALSE(image.CanModify());
    273 
    274   image.DetachStorageFromThread();
    275   // An image is accessed by this thread,
    276   // so other thread cannot read/modify it.
    277   image.image_reps();
    278   test::TestOnThread image_on_thread2(&image);
    279   image_on_thread2.StartAndJoin();
    280   EXPECT_FALSE(image_on_thread2.can_read());
    281   EXPECT_FALSE(image_on_thread2.can_modify());
    282   EXPECT_TRUE(image.CanRead());
    283   EXPECT_TRUE(image.CanModify());
    284 
    285   image.DetachStorageFromThread();
    286   scoped_ptr<ImageSkia> deep_copy(image.DeepCopy());
    287   EXPECT_FALSE(deep_copy->IsThreadSafe());
    288   test::TestOnThread deepcopy_on_thread(deep_copy.get());
    289   deepcopy_on_thread.StartAndJoin();
    290   EXPECT_TRUE(deepcopy_on_thread.can_read());
    291   EXPECT_TRUE(deepcopy_on_thread.can_modify());
    292   EXPECT_FALSE(deep_copy->CanRead());
    293   EXPECT_FALSE(deep_copy->CanModify());
    294 
    295   scoped_ptr<ImageSkia> deep_copy2(image.DeepCopy());
    296   EXPECT_EQ(1U, deep_copy2->image_reps().size());
    297   // Access it from current thread so that it can't be
    298   // accessed from another thread.
    299   deep_copy2->image_reps();
    300   EXPECT_FALSE(deep_copy2->IsThreadSafe());
    301   test::TestOnThread deepcopy2_on_thread(deep_copy2.get());
    302   deepcopy2_on_thread.StartAndJoin();
    303   EXPECT_FALSE(deepcopy2_on_thread.can_read());
    304   EXPECT_FALSE(deepcopy2_on_thread.can_modify());
    305   EXPECT_TRUE(deep_copy2->CanRead());
    306   EXPECT_TRUE(deep_copy2->CanModify());
    307 
    308   image.DetachStorageFromThread();
    309   image.SetReadOnly();
    310   // A read-only ImageSkia with no source is thread safe.
    311   EXPECT_TRUE(image.IsThreadSafe());
    312   test::TestOnThread readonly_on_thread(&image);
    313   readonly_on_thread.StartAndJoin();
    314   EXPECT_TRUE(readonly_on_thread.can_read());
    315   EXPECT_FALSE(readonly_on_thread.can_modify());
    316   EXPECT_TRUE(image.CanRead());
    317   EXPECT_FALSE(image.CanModify());
    318 
    319   image.DetachStorageFromThread();
    320   image.MakeThreadSafe();
    321   EXPECT_TRUE(image.IsThreadSafe());
    322   test::TestOnThread threadsafe_on_thread(&image);
    323   threadsafe_on_thread.StartAndJoin();
    324   EXPECT_TRUE(threadsafe_on_thread.can_read());
    325   EXPECT_FALSE(threadsafe_on_thread.can_modify());
    326   EXPECT_TRUE(image.CanRead());
    327   EXPECT_FALSE(image.CanModify());
    328 }
    329 
    330 TEST(ImageSkiaTest, SourceOnThreadTest) {
    331   ImageSkia image(new DynamicSource(Size(100, 200)), Size(100, 200));
    332   EXPECT_FALSE(image.IsThreadSafe());
    333 
    334   test::TestOnThread image_on_thread(&image);
    335   image_on_thread.StartAndJoin();
    336   // an image that was never accessed on this thread can be
    337   // read by other thread.
    338   EXPECT_TRUE(image_on_thread.can_read());
    339   EXPECT_TRUE(image_on_thread.can_modify());
    340   EXPECT_FALSE(image.CanRead());
    341   EXPECT_FALSE(image.CanModify());
    342 
    343   image.DetachStorageFromThread();
    344   // An image is accessed by this thread,
    345   // so other thread cannot read/modify it.
    346   image.image_reps();
    347   test::TestOnThread image_on_thread2(&image);
    348   image_on_thread2.StartAndJoin();
    349   EXPECT_FALSE(image_on_thread2.can_read());
    350   EXPECT_FALSE(image_on_thread2.can_modify());
    351   EXPECT_TRUE(image.CanRead());
    352   EXPECT_TRUE(image.CanModify());
    353 
    354   image.DetachStorageFromThread();
    355   image.SetReadOnly();
    356   EXPECT_FALSE(image.IsThreadSafe());
    357   test::TestOnThread readonly_on_thread(&image);
    358   readonly_on_thread.StartAndJoin();
    359   EXPECT_TRUE(readonly_on_thread.can_read());
    360   EXPECT_FALSE(readonly_on_thread.can_modify());
    361   EXPECT_FALSE(image.CanRead());
    362   EXPECT_FALSE(image.CanModify());
    363 
    364   image.DetachStorageFromThread();
    365   image.MakeThreadSafe();
    366   EXPECT_TRUE(image.IsThreadSafe());
    367   // Check if image reps are generated for supported scale factors.
    368   EXPECT_EQ(ui::GetSupportedScaleFactors().size(),
    369             image.image_reps().size());
    370   test::TestOnThread threadsafe_on_thread(&image);
    371   threadsafe_on_thread.StartAndJoin();
    372   EXPECT_TRUE(threadsafe_on_thread.can_read());
    373   EXPECT_FALSE(threadsafe_on_thread.can_modify());
    374   EXPECT_TRUE(image.CanRead());
    375   EXPECT_FALSE(image.CanModify());
    376 }
    377 #endif  // ENABLE_NON_THREAD_SAFE
    378 
    379 // Just in case we ever get lumped together with other compilation units.
    380 #undef ENABLE_NON_THREAD_SAFE
    381 
    382 }  // namespace gfx
    383