Home | History | Annotate | Download | only in browser
      1 // Copyright 2014 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 "extensions/browser/extension_icon_image.h"
      6 
      7 #include "base/json/json_file_value_serializer.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/path_service.h"
     10 #include "chrome/common/chrome_paths.h"
     11 #include "chrome/test/base/testing_profile.h"
     12 #include "content/public/test/test_browser_thread.h"
     13 #include "extensions/browser/image_loader.h"
     14 #include "extensions/common/extension.h"
     15 #include "extensions/common/manifest.h"
     16 #include "extensions/common/manifest_handlers/icons_handler.h"
     17 #include "skia/ext/image_operations.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 #include "ui/base/resource/resource_bundle.h"
     20 #include "ui/gfx/image/image_skia_source.h"
     21 #include "ui/gfx/skia_util.h"
     22 
     23 using content::BrowserThread;
     24 using extensions::Extension;
     25 using extensions::IconImage;
     26 using extensions::Manifest;
     27 
     28 namespace {
     29 
     30 SkBitmap CreateBlankBitmapForScale(int size_dip, ui::ScaleFactor scale_factor) {
     31   SkBitmap bitmap;
     32   const float scale = ui::GetScaleForScaleFactor(scale_factor);
     33   bitmap.setConfig(SkBitmap::kARGB_8888_Config,
     34                    static_cast<int>(size_dip * scale),
     35                    static_cast<int>(size_dip * scale));
     36   bitmap.allocPixels();
     37   bitmap.eraseColor(SkColorSetARGB(0, 0, 0, 0));
     38   return bitmap;
     39 }
     40 
     41 SkBitmap EnsureBitmapSize(const SkBitmap& original, int size) {
     42   if (original.width() == size && original.height() == size)
     43     return original;
     44 
     45   SkBitmap resized = skia::ImageOperations::Resize(
     46       original, skia::ImageOperations::RESIZE_LANCZOS3, size, size);
     47   return resized;
     48 }
     49 
     50 // Used to test behavior including images defined by an image skia source.
     51 // |GetImageForScale| simply returns image representation from the image given
     52 // in the ctor.
     53 class MockImageSkiaSource : public gfx::ImageSkiaSource {
     54  public:
     55   explicit MockImageSkiaSource(const gfx::ImageSkia& image)
     56       : image_(image) {
     57   }
     58   virtual ~MockImageSkiaSource() {}
     59 
     60   virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
     61     return image_.GetRepresentation(scale);
     62   }
     63 
     64  private:
     65   gfx::ImageSkia image_;
     66 };
     67 
     68 // Helper class for synchronously loading extension image resource.
     69 class TestImageLoader {
     70  public:
     71   explicit TestImageLoader(const Extension* extension)
     72       : extension_(extension),
     73         waiting_(false),
     74         image_loaded_(false) {
     75   }
     76   virtual ~TestImageLoader() {}
     77 
     78   void OnImageLoaded(const gfx::Image& image) {
     79     image_ = image;
     80     image_loaded_ = true;
     81     if (waiting_)
     82       base::MessageLoop::current()->Quit();
     83   }
     84 
     85   SkBitmap LoadBitmap(const std::string& path,
     86                       int size) {
     87     image_loaded_ = false;
     88 
     89     image_loader_.LoadImageAsync(
     90         extension_, extension_->GetResource(path), gfx::Size(size, size),
     91         base::Bind(&TestImageLoader::OnImageLoaded,
     92                    base::Unretained(this)));
     93 
     94     // If |image_| still hasn't been loaded (i.e. it is being loaded
     95     // asynchronously), wait for it.
     96     if (!image_loaded_) {
     97       waiting_ = true;
     98       base::MessageLoop::current()->Run();
     99       waiting_ = false;
    100     }
    101 
    102     EXPECT_TRUE(image_loaded_);
    103 
    104     return image_.IsEmpty() ? SkBitmap() : *image_.ToSkBitmap();
    105   }
    106 
    107  private:
    108   const Extension* extension_;
    109   bool waiting_;
    110   bool image_loaded_;
    111   gfx::Image image_;
    112   extensions::ImageLoader image_loader_;
    113 
    114   DISALLOW_COPY_AND_ASSIGN(TestImageLoader);
    115 };
    116 
    117 class ExtensionIconImageTest : public testing::Test,
    118                                public IconImage::Observer {
    119  public:
    120   ExtensionIconImageTest()
    121       : image_loaded_count_(0),
    122         quit_in_image_loaded_(false),
    123         ui_thread_(BrowserThread::UI, &ui_loop_),
    124         file_thread_(BrowserThread::FILE),
    125         io_thread_(BrowserThread::IO) {
    126   }
    127 
    128   virtual ~ExtensionIconImageTest() {}
    129 
    130   void WaitForImageLoad() {
    131     quit_in_image_loaded_ = true;
    132     base::MessageLoop::current()->Run();
    133     quit_in_image_loaded_ = false;
    134   }
    135 
    136   int ImageLoadedCount() {
    137     int result = image_loaded_count_;
    138     image_loaded_count_ = 0;
    139     return result;
    140   }
    141 
    142   scoped_refptr<Extension> CreateExtension(const char* name,
    143                                            Manifest::Location location) {
    144     // Create and load an extension.
    145     base::FilePath test_file;
    146     if (!PathService::Get(chrome::DIR_TEST_DATA, &test_file)) {
    147       EXPECT_FALSE(true);
    148       return NULL;
    149     }
    150     test_file = test_file.AppendASCII("extensions").AppendASCII(name);
    151     int error_code = 0;
    152     std::string error;
    153     JSONFileValueSerializer serializer(test_file.AppendASCII("app.json"));
    154     scoped_ptr<base::DictionaryValue> valid_value(
    155         static_cast<base::DictionaryValue*>(serializer.Deserialize(&error_code,
    156                                                                    &error)));
    157     EXPECT_EQ(0, error_code) << error;
    158     if (error_code != 0)
    159       return NULL;
    160 
    161     EXPECT_TRUE(valid_value.get());
    162     if (!valid_value)
    163       return NULL;
    164 
    165     return Extension::Create(test_file, location, *valid_value,
    166                              Extension::NO_FLAGS, &error);
    167   }
    168 
    169   // testing::Test overrides:
    170   virtual void SetUp() OVERRIDE {
    171     file_thread_.Start();
    172     io_thread_.Start();
    173   }
    174 
    175   // IconImage::Delegate overrides:
    176   virtual void OnExtensionIconImageChanged(IconImage* image) OVERRIDE {
    177     image_loaded_count_++;
    178     if (quit_in_image_loaded_)
    179       base::MessageLoop::current()->Quit();
    180   }
    181 
    182   gfx::ImageSkia GetDefaultIcon() {
    183     return gfx::ImageSkia(gfx::ImageSkiaRep(gfx::Size(16, 16), 1.0f));
    184   }
    185 
    186   // Loads an image to be used in test from the extension.
    187   // The image will be loaded from the relative path |path|.
    188   SkBitmap GetTestBitmap(const Extension* extension,
    189                          const std::string& path,
    190                          int size) {
    191     TestImageLoader image_loader(extension);
    192     return image_loader.LoadBitmap(path, size);
    193   }
    194 
    195  private:
    196   int image_loaded_count_;
    197   bool quit_in_image_loaded_;
    198   base::MessageLoop ui_loop_;
    199   content::TestBrowserThread ui_thread_;
    200   content::TestBrowserThread file_thread_;
    201   content::TestBrowserThread io_thread_;
    202 
    203   DISALLOW_COPY_AND_ASSIGN(ExtensionIconImageTest);
    204 };
    205 
    206 }  // namespace
    207 
    208 TEST_F(ExtensionIconImageTest, Basic) {
    209   std::vector<ui::ScaleFactor> supported_factors;
    210   supported_factors.push_back(ui::SCALE_FACTOR_100P);
    211   supported_factors.push_back(ui::SCALE_FACTOR_200P);
    212   ui::test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
    213   scoped_ptr<content::BrowserContext> profile(new TestingProfile());
    214   scoped_refptr<Extension> extension(CreateExtension(
    215       "extension_icon_image", Manifest::INVALID_LOCATION));
    216   ASSERT_TRUE(extension.get() != NULL);
    217 
    218   gfx::ImageSkia default_icon = GetDefaultIcon();
    219 
    220   // Load images we expect to find as representations in icon_image, so we
    221   // can later use them to validate icon_image.
    222   SkBitmap bitmap_16 = GetTestBitmap(extension.get(), "16.png", 16);
    223   ASSERT_FALSE(bitmap_16.empty());
    224 
    225   // There is no image of size 32 defined in the extension manifest, so we
    226   // should expect manifest image of size 48 resized to size 32.
    227   SkBitmap bitmap_48_resized_to_32 =
    228       GetTestBitmap(extension.get(), "48.png", 32);
    229   ASSERT_FALSE(bitmap_48_resized_to_32.empty());
    230 
    231   IconImage image(profile.get(),
    232                   extension.get(),
    233                   extensions::IconsInfo::GetIcons(extension.get()),
    234                   16,
    235                   default_icon,
    236                   this);
    237 
    238   // No representations in |image_| yet.
    239   gfx::ImageSkia::ImageSkiaReps image_reps = image.image_skia().image_reps();
    240   ASSERT_EQ(0u, image_reps.size());
    241 
    242   // Gets representation for a scale factor.
    243   gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f);
    244 
    245   // Before the image representation is loaded, image should contain blank
    246   // image representation.
    247   EXPECT_TRUE(gfx::BitmapsAreEqual(
    248       representation.sk_bitmap(),
    249       CreateBlankBitmapForScale(16, ui::SCALE_FACTOR_100P)));
    250 
    251   WaitForImageLoad();
    252   EXPECT_EQ(1, ImageLoadedCount());
    253   ASSERT_EQ(1u, image.image_skia().image_reps().size());
    254 
    255   representation = image.image_skia().GetRepresentation(1.0f);
    256 
    257   // We should get the right representation now.
    258   EXPECT_TRUE(gfx::BitmapsAreEqual(representation.sk_bitmap(), bitmap_16));
    259   EXPECT_EQ(16, representation.pixel_width());
    260 
    261   // Gets representation for an additional scale factor.
    262   representation = image.image_skia().GetRepresentation(2.0f);
    263 
    264   EXPECT_TRUE(gfx::BitmapsAreEqual(
    265       representation.sk_bitmap(),
    266       CreateBlankBitmapForScale(16, ui::SCALE_FACTOR_200P)));
    267 
    268   WaitForImageLoad();
    269   EXPECT_EQ(1, ImageLoadedCount());
    270   ASSERT_EQ(2u, image.image_skia().image_reps().size());
    271 
    272   representation = image.image_skia().GetRepresentation(2.0f);
    273 
    274   // Image should have been resized.
    275   EXPECT_EQ(32, representation.pixel_width());
    276   EXPECT_TRUE(gfx::BitmapsAreEqual(representation.sk_bitmap(),
    277                                    bitmap_48_resized_to_32));
    278 }
    279 
    280 // There is no resource with either exact or bigger size, but there is a smaller
    281 // resource.
    282 TEST_F(ExtensionIconImageTest, FallbackToSmallerWhenNoBigger) {
    283   std::vector<ui::ScaleFactor> supported_factors;
    284   supported_factors.push_back(ui::SCALE_FACTOR_100P);
    285   supported_factors.push_back(ui::SCALE_FACTOR_200P);
    286   ui::test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
    287   scoped_ptr<content::BrowserContext> profile(new TestingProfile());
    288   scoped_refptr<Extension> extension(CreateExtension(
    289       "extension_icon_image", Manifest::INVALID_LOCATION));
    290   ASSERT_TRUE(extension.get() != NULL);
    291 
    292   gfx::ImageSkia default_icon = GetDefaultIcon();
    293 
    294   // Load images we expect to find as representations in icon_image, so we
    295   // can later use them to validate icon_image.
    296   SkBitmap bitmap_48 = GetTestBitmap(extension.get(), "48.png", 48);
    297   ASSERT_FALSE(bitmap_48.empty());
    298 
    299   IconImage image(profile.get(),
    300                   extension.get(),
    301                   extensions::IconsInfo::GetIcons(extension.get()),
    302                   32,
    303                   default_icon,
    304                   this);
    305 
    306   gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(2.0f);
    307 
    308   WaitForImageLoad();
    309   EXPECT_EQ(1, ImageLoadedCount());
    310   ASSERT_EQ(1u, image.image_skia().image_reps().size());
    311 
    312   representation = image.image_skia().GetRepresentation(2.0f);
    313 
    314   // We should have loaded the biggest smaller resource resized to the actual
    315   // size.
    316   EXPECT_EQ(2.0f, representation.scale());
    317   EXPECT_EQ(64, representation.pixel_width());
    318   EXPECT_TRUE(gfx::BitmapsAreEqual(representation.sk_bitmap(),
    319                                    EnsureBitmapSize(bitmap_48, 64)));
    320 }
    321 
    322 // There is no resource with exact size, but there is a smaller and a bigger
    323 // one. Requested size is smaller than 32 though, so the smaller resource should
    324 // be loaded.
    325 TEST_F(ExtensionIconImageTest, FallbackToSmaller) {
    326   scoped_ptr<content::BrowserContext> profile(new TestingProfile());
    327   scoped_refptr<Extension> extension(CreateExtension(
    328       "extension_icon_image", Manifest::INVALID_LOCATION));
    329   ASSERT_TRUE(extension.get() != NULL);
    330 
    331   gfx::ImageSkia default_icon = GetDefaultIcon();
    332 
    333   // Load images we expect to find as representations in icon_image, so we
    334   // can later use them to validate icon_image.
    335   SkBitmap bitmap_16 = GetTestBitmap(extension.get(), "16.png", 16);
    336   ASSERT_FALSE(bitmap_16.empty());
    337 
    338   IconImage image(profile.get(),
    339                   extension.get(),
    340                   extensions::IconsInfo::GetIcons(extension.get()),
    341                   17,
    342                   default_icon,
    343                   this);
    344 
    345   gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f);
    346 
    347   WaitForImageLoad();
    348   EXPECT_EQ(1, ImageLoadedCount());
    349   ASSERT_EQ(1u, image.image_skia().image_reps().size());
    350 
    351   representation = image.image_skia().GetRepresentation(1.0f);
    352 
    353   // We should have loaded smaller (resized) resource.
    354   EXPECT_EQ(1.0f, representation.scale());
    355   EXPECT_EQ(17, representation.pixel_width());
    356   EXPECT_TRUE(gfx::BitmapsAreEqual(representation.sk_bitmap(),
    357                                    EnsureBitmapSize(bitmap_16, 17)));
    358 }
    359 
    360 // If resource set is empty, |GetRepresentation| should synchronously return
    361 // default icon, without notifying observer of image change.
    362 TEST_F(ExtensionIconImageTest, NoResources) {
    363   scoped_ptr<content::BrowserContext> profile(new TestingProfile());
    364   scoped_refptr<Extension> extension(CreateExtension(
    365       "extension_icon_image", Manifest::INVALID_LOCATION));
    366   ASSERT_TRUE(extension.get() != NULL);
    367 
    368   ExtensionIconSet empty_icon_set;
    369   gfx::ImageSkia default_icon = GetDefaultIcon();
    370 
    371   const int kRequestedSize = 24;
    372   IconImage image(profile.get(),
    373                   extension.get(),
    374                   empty_icon_set,
    375                   kRequestedSize,
    376                   default_icon,
    377                   this);
    378 
    379   gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f);
    380   EXPECT_TRUE(gfx::BitmapsAreEqual(
    381       representation.sk_bitmap(),
    382       EnsureBitmapSize(
    383           default_icon.GetRepresentation(1.0f).sk_bitmap(),
    384           kRequestedSize)));
    385 
    386   EXPECT_EQ(0, ImageLoadedCount());
    387   // We should have a default icon representation.
    388   ASSERT_EQ(1u, image.image_skia().image_reps().size());
    389 
    390   representation = image.image_skia().GetRepresentation(1.0f);
    391   EXPECT_TRUE(gfx::BitmapsAreEqual(
    392       representation.sk_bitmap(),
    393       EnsureBitmapSize(
    394           default_icon.GetRepresentation(1.0f).sk_bitmap(),
    395           kRequestedSize)));
    396 }
    397 
    398 // If resource set is invalid, image load should be done asynchronously and
    399 // the observer should be notified when it's done. |GetRepresentation| should
    400 // return the default icon representation once image load is done.
    401 TEST_F(ExtensionIconImageTest, InvalidResource) {
    402   scoped_ptr<content::BrowserContext> profile(new TestingProfile());
    403   scoped_refptr<Extension> extension(CreateExtension(
    404       "extension_icon_image", Manifest::INVALID_LOCATION));
    405   ASSERT_TRUE(extension.get() != NULL);
    406 
    407   const int kInvalidIconSize = 24;
    408   ExtensionIconSet invalid_icon_set;
    409   invalid_icon_set.Add(kInvalidIconSize, "invalid.png");
    410 
    411   gfx::ImageSkia default_icon = GetDefaultIcon();
    412 
    413   IconImage image(profile.get(),
    414                   extension.get(),
    415                   invalid_icon_set,
    416                   kInvalidIconSize,
    417                   default_icon,
    418                   this);
    419 
    420   gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f);
    421   EXPECT_TRUE(gfx::BitmapsAreEqual(
    422       representation.sk_bitmap(),
    423       CreateBlankBitmapForScale(kInvalidIconSize, ui::SCALE_FACTOR_100P)));
    424 
    425   WaitForImageLoad();
    426   EXPECT_EQ(1, ImageLoadedCount());
    427   // We should have default icon representation now.
    428   ASSERT_EQ(1u, image.image_skia().image_reps().size());
    429 
    430   representation = image.image_skia().GetRepresentation(1.0f);
    431   EXPECT_TRUE(gfx::BitmapsAreEqual(
    432       representation.sk_bitmap(),
    433       EnsureBitmapSize(
    434           default_icon.GetRepresentation(1.0f).sk_bitmap(),
    435           kInvalidIconSize)));
    436 }
    437 
    438 // Test that IconImage works with lazily (but synchronously) created default
    439 // icon when IconImage returns synchronously.
    440 TEST_F(ExtensionIconImageTest, LazyDefaultIcon) {
    441   scoped_ptr<content::BrowserContext> profile(new TestingProfile());
    442   scoped_refptr<Extension> extension(CreateExtension(
    443       "extension_icon_image", Manifest::INVALID_LOCATION));
    444   ASSERT_TRUE(extension.get() != NULL);
    445 
    446   gfx::ImageSkia default_icon = GetDefaultIcon();
    447   gfx::ImageSkia lazy_default_icon(new MockImageSkiaSource(default_icon),
    448                                     default_icon.size());
    449 
    450   ExtensionIconSet empty_icon_set;
    451 
    452   const int kRequestedSize = 128;
    453   IconImage image(profile.get(),
    454                   extension.get(),
    455                   empty_icon_set,
    456                   kRequestedSize,
    457                   lazy_default_icon,
    458                   this);
    459 
    460   ASSERT_FALSE(lazy_default_icon.HasRepresentation(1.0f));
    461 
    462   gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f);
    463 
    464   // The resouce set is empty, so we should get the result right away.
    465   EXPECT_TRUE(lazy_default_icon.HasRepresentation(1.0f));
    466   EXPECT_TRUE(gfx::BitmapsAreEqual(
    467       representation.sk_bitmap(),
    468       EnsureBitmapSize(
    469           default_icon.GetRepresentation(1.0f).sk_bitmap(),
    470           kRequestedSize)));
    471 
    472   // We should have a default icon representation.
    473   ASSERT_EQ(1u, image.image_skia().image_reps().size());
    474 }
    475 
    476 // Test that IconImage works with lazily (but synchronously) created default
    477 // icon when IconImage returns asynchronously.
    478 TEST_F(ExtensionIconImageTest, LazyDefaultIcon_AsyncIconImage) {
    479   scoped_ptr<content::BrowserContext> profile(new TestingProfile());
    480   scoped_refptr<Extension> extension(CreateExtension(
    481       "extension_icon_image", Manifest::INVALID_LOCATION));
    482   ASSERT_TRUE(extension.get() != NULL);
    483 
    484   gfx::ImageSkia default_icon = GetDefaultIcon();
    485   gfx::ImageSkia lazy_default_icon(new MockImageSkiaSource(default_icon),
    486                                     default_icon.size());
    487 
    488   const int kInvalidIconSize = 24;
    489   ExtensionIconSet invalid_icon_set;
    490   invalid_icon_set.Add(kInvalidIconSize, "invalid.png");
    491 
    492   IconImage image(profile.get(),
    493                   extension.get(),
    494                   invalid_icon_set,
    495                   kInvalidIconSize,
    496                   lazy_default_icon,
    497                   this);
    498 
    499   ASSERT_FALSE(lazy_default_icon.HasRepresentation(1.0f));
    500 
    501   gfx::ImageSkiaRep representation = image.image_skia().GetRepresentation(1.0f);
    502 
    503   WaitForImageLoad();
    504   EXPECT_EQ(1, ImageLoadedCount());
    505   // We should have default icon representation now.
    506   ASSERT_EQ(1u, image.image_skia().image_reps().size());
    507 
    508   EXPECT_TRUE(lazy_default_icon.HasRepresentation(1.0f));
    509 
    510   representation = image.image_skia().GetRepresentation(1.0f);
    511   EXPECT_TRUE(gfx::BitmapsAreEqual(
    512       representation.sk_bitmap(),
    513       EnsureBitmapSize(
    514           default_icon.GetRepresentation(1.0f).sk_bitmap(),
    515           kInvalidIconSize)));
    516 }
    517 
    518 // Tests behavior of image created by IconImage after IconImage host goes
    519 // away. The image should still return loaded representations. If requested
    520 // representation was not loaded while IconImage host was around, transparent
    521 // representations should be returned.
    522 TEST_F(ExtensionIconImageTest, IconImageDestruction) {
    523   scoped_ptr<content::BrowserContext> profile(new TestingProfile());
    524   scoped_refptr<Extension> extension(CreateExtension(
    525       "extension_icon_image", Manifest::INVALID_LOCATION));
    526   ASSERT_TRUE(extension.get() != NULL);
    527 
    528   gfx::ImageSkia default_icon = GetDefaultIcon();
    529 
    530   // Load images we expect to find as representations in icon_image, so we
    531   // can later use them to validate icon_image.
    532   SkBitmap bitmap_16 = GetTestBitmap(extension.get(), "16.png", 16);
    533   ASSERT_FALSE(bitmap_16.empty());
    534 
    535   scoped_ptr<IconImage> image(
    536       new IconImage(profile.get(),
    537                     extension.get(),
    538                     extensions::IconsInfo::GetIcons(extension.get()),
    539                     16,
    540                     default_icon,
    541                     this));
    542 
    543   // Load an image representation.
    544   gfx::ImageSkiaRep representation =
    545       image->image_skia().GetRepresentation(1.0f);
    546 
    547   WaitForImageLoad();
    548   EXPECT_EQ(1, ImageLoadedCount());
    549   ASSERT_EQ(1u, image->image_skia().image_reps().size());
    550 
    551   // Stash loaded image skia, and destroy |image|.
    552   gfx::ImageSkia image_skia = image->image_skia();
    553   image.reset();
    554   extension = NULL;
    555 
    556   // Image skia should still be able to get previously loaded representation.
    557   representation = image_skia.GetRepresentation(1.0f);
    558 
    559   EXPECT_EQ(1.0f, representation.scale());
    560   EXPECT_EQ(16, representation.pixel_width());
    561   EXPECT_TRUE(gfx::BitmapsAreEqual(representation.sk_bitmap(), bitmap_16));
    562 
    563   // When requesting another representation, we should not crash and return some
    564   // image of the size. It could be blank or a rescale from the existing 1.0f
    565   // icon.
    566   representation = image_skia.GetRepresentation(2.0f);
    567 
    568   EXPECT_EQ(16, representation.GetWidth());
    569   EXPECT_EQ(16, representation.GetHeight());
    570   EXPECT_EQ(2.0f, representation.scale());
    571 }
    572