Home | History | Annotate | Download | only in snapshot
      1 // Copyright (c) 2013 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/snapshot/snapshot.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/test/test_simple_task_runner.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 #include "ui/aura/test/aura_test_helper.h"
     11 #include "ui/aura/test/test_screen.h"
     12 #include "ui/aura/test/test_window_delegate.h"
     13 #include "ui/aura/test/test_windows.h"
     14 #include "ui/aura/window.h"
     15 #include "ui/aura/window_event_dispatcher.h"
     16 #include "ui/compositor/compositor.h"
     17 #include "ui/compositor/layer.h"
     18 #include "ui/compositor/test/context_factories_for_test.h"
     19 #include "ui/compositor/test/draw_waiter_for_test.h"
     20 #include "ui/gfx/canvas.h"
     21 #include "ui/gfx/gfx_paths.h"
     22 #include "ui/gfx/image/image.h"
     23 #include "ui/gfx/rect.h"
     24 #include "ui/gfx/size_conversions.h"
     25 #include "ui/gfx/transform.h"
     26 #include "ui/gl/gl_implementation.h"
     27 #include "ui/wm/core/default_activation_client.h"
     28 
     29 namespace ui {
     30 namespace {
     31 
     32 SkColor GetExpectedColorForPoint(int x, int y) {
     33   return SkColorSetRGB(std::min(x, 255), std::min(y, 255), 0);
     34 }
     35 
     36 // Paint simple rectangle on the specified aura window.
     37 class TestPaintingWindowDelegate : public aura::test::TestWindowDelegate {
     38  public:
     39   explicit TestPaintingWindowDelegate(const gfx::Size& window_size)
     40       : window_size_(window_size) {
     41   }
     42 
     43   virtual ~TestPaintingWindowDelegate() {
     44   }
     45 
     46   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
     47     for (int y = 0; y < window_size_.height(); ++y) {
     48       for (int x = 0; x < window_size_.width(); ++x)
     49         canvas->FillRect(gfx::Rect(x, y, 1, 1), GetExpectedColorForPoint(x, y));
     50     }
     51   }
     52 
     53  private:
     54   gfx::Size window_size_;
     55 
     56   DISALLOW_COPY_AND_ASSIGN(TestPaintingWindowDelegate);
     57 };
     58 
     59 size_t GetFailedPixelsCountWithScaleFactor(const gfx::Image& image,
     60                                            int scale_factor) {
     61   const SkBitmap* bitmap = image.ToSkBitmap();
     62   uint32* bitmap_data = reinterpret_cast<uint32*>(
     63       bitmap->pixelRef()->pixels());
     64   size_t result = 0;
     65   for (int y = 0; y < bitmap->height(); y += scale_factor) {
     66     for (int x = 0; x < bitmap->width(); x += scale_factor) {
     67       if (static_cast<SkColor>(bitmap_data[x + y * bitmap->width()]) !=
     68           GetExpectedColorForPoint(x / scale_factor, y / scale_factor)) {
     69         ++result;
     70       }
     71     }
     72   }
     73   return result;
     74 }
     75 
     76 size_t GetFailedPixelsCount(const gfx::Image& image) {
     77   return GetFailedPixelsCountWithScaleFactor(image, 1);
     78 }
     79 
     80 }  // namespace
     81 
     82 class SnapshotAuraTest : public testing::Test {
     83  public:
     84   SnapshotAuraTest() {}
     85   virtual ~SnapshotAuraTest() {}
     86 
     87   virtual void SetUp() OVERRIDE {
     88     testing::Test::SetUp();
     89 
     90     // The ContextFactory must exist before any Compositors are created.
     91     // Snapshot test tests real drawing and readback, so needs pixel output.
     92     bool enable_pixel_output = true;
     93     ui::ContextFactory* context_factory =
     94         ui::InitializeContextFactoryForTests(enable_pixel_output);
     95 
     96     helper_.reset(
     97         new aura::test::AuraTestHelper(base::MessageLoopForUI::current()));
     98     helper_->SetUp(context_factory);
     99     new ::wm::DefaultActivationClient(helper_->root_window());
    100   }
    101 
    102   virtual void TearDown() OVERRIDE {
    103     test_window_.reset();
    104     delegate_.reset();
    105     helper_->RunAllPendingInMessageLoop();
    106     helper_->TearDown();
    107     ui::TerminateContextFactoryForTests();
    108     testing::Test::TearDown();
    109   }
    110 
    111  protected:
    112   aura::Window* test_window() { return test_window_.get(); }
    113   aura::Window* root_window() { return helper_->root_window(); }
    114   aura::TestScreen* test_screen() { return helper_->test_screen(); }
    115 
    116   void WaitForDraw() {
    117     helper_->host()->compositor()->ScheduleDraw();
    118     ui::DrawWaiterForTest::Wait(helper_->host()->compositor());
    119   }
    120 
    121   void SetupTestWindow(const gfx::Rect& window_bounds) {
    122     delegate_.reset(new TestPaintingWindowDelegate(window_bounds.size()));
    123     test_window_.reset(aura::test::CreateTestWindowWithDelegate(
    124         delegate_.get(), 0, window_bounds, root_window()));
    125   }
    126 
    127   gfx::Image GrabSnapshotForTestWindow() {
    128     gfx::Rect source_rect(test_window_->bounds().size());
    129     aura::Window::ConvertRectToTarget(
    130         test_window(), root_window(), &source_rect);
    131 
    132     scoped_refptr<base::TestSimpleTaskRunner> task_runner(
    133         new base::TestSimpleTaskRunner());
    134     scoped_refptr<SnapshotHolder> holder(new SnapshotHolder);
    135     ui::GrabWindowSnapshotAsync(
    136         root_window(),
    137         source_rect,
    138         task_runner,
    139         base::Bind(&SnapshotHolder::SnapshotCallback, holder));
    140 
    141     // Wait for copy response.
    142     WaitForDraw();
    143     // Run internal snapshot callback to scale/rotate response image.
    144     task_runner->RunUntilIdle();
    145     // Run SnapshotHolder callback.
    146     helper_->RunAllPendingInMessageLoop();
    147 
    148     if (holder->completed())
    149       return holder->image();
    150 
    151     // Callback never called.
    152     NOTREACHED();
    153     return gfx::Image();
    154   }
    155 
    156  private:
    157   class SnapshotHolder : public base::RefCountedThreadSafe<SnapshotHolder> {
    158    public:
    159     SnapshotHolder() : completed_(false) {}
    160 
    161     void SnapshotCallback(scoped_refptr<base::RefCountedBytes> png_data) {
    162       DCHECK(!completed_);
    163       image_ = gfx::Image::CreateFrom1xPNGBytes(&(png_data->data()[0]),
    164                                                 png_data->size());
    165       completed_ = true;
    166     }
    167     bool completed() const {
    168       return completed_;
    169     };
    170     const gfx::Image& image() const { return image_; }
    171 
    172    private:
    173     friend class base::RefCountedThreadSafe<SnapshotHolder>;
    174 
    175     virtual ~SnapshotHolder() {}
    176 
    177     gfx::Image image_;
    178     bool completed_;
    179   };
    180 
    181   scoped_ptr<aura::test::AuraTestHelper> helper_;
    182   scoped_ptr<aura::Window> test_window_;
    183   scoped_ptr<TestPaintingWindowDelegate> delegate_;
    184   std::vector<unsigned char> png_representation_;
    185 
    186   DISALLOW_COPY_AND_ASSIGN(SnapshotAuraTest);
    187 };
    188 
    189 TEST_F(SnapshotAuraTest, FullScreenWindow) {
    190   SetupTestWindow(root_window()->bounds());
    191   WaitForDraw();
    192 
    193   gfx::Image snapshot = GrabSnapshotForTestWindow();
    194   EXPECT_EQ(test_window()->bounds().size().ToString(),
    195             snapshot.Size().ToString());
    196   EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
    197 }
    198 
    199 TEST_F(SnapshotAuraTest, PartialBounds) {
    200   gfx::Rect test_bounds(100, 100, 300, 200);
    201   SetupTestWindow(test_bounds);
    202   WaitForDraw();
    203 
    204   gfx::Image snapshot = GrabSnapshotForTestWindow();
    205   EXPECT_EQ(test_bounds.size().ToString(), snapshot.Size().ToString());
    206   EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
    207 }
    208 
    209 TEST_F(SnapshotAuraTest, Rotated) {
    210   test_screen()->SetDisplayRotation(gfx::Display::ROTATE_90);
    211 
    212   gfx::Rect test_bounds(100, 100, 300, 200);
    213   SetupTestWindow(test_bounds);
    214   WaitForDraw();
    215 
    216   gfx::Image snapshot = GrabSnapshotForTestWindow();
    217   EXPECT_EQ(test_bounds.size().ToString(), snapshot.Size().ToString());
    218   EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
    219 }
    220 
    221 TEST_F(SnapshotAuraTest, UIScale) {
    222   const float kUIScale = 1.25f;
    223   test_screen()->SetUIScale(kUIScale);
    224 
    225   gfx::Rect test_bounds(100, 100, 300, 200);
    226   SetupTestWindow(test_bounds);
    227   WaitForDraw();
    228 
    229   // Snapshot always captures the physical pixels.
    230   gfx::SizeF snapshot_size(test_bounds.size());
    231 
    232   gfx::Image snapshot = GrabSnapshotForTestWindow();
    233   EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
    234             snapshot.Size().ToString());
    235   EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
    236 }
    237 
    238 TEST_F(SnapshotAuraTest, DeviceScaleFactor) {
    239   test_screen()->SetDeviceScaleFactor(2.0f);
    240 
    241   gfx::Rect test_bounds(100, 100, 150, 100);
    242   SetupTestWindow(test_bounds);
    243   WaitForDraw();
    244 
    245   // Snapshot always captures the physical pixels.
    246   gfx::SizeF snapshot_size(test_bounds.size());
    247   snapshot_size.Scale(2.0f);
    248 
    249   gfx::Image snapshot = GrabSnapshotForTestWindow();
    250   EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
    251             snapshot.Size().ToString());
    252   EXPECT_EQ(0u, GetFailedPixelsCountWithScaleFactor(snapshot, 2));
    253 }
    254 
    255 TEST_F(SnapshotAuraTest, RotateAndUIScale) {
    256   const float kUIScale = 1.25f;
    257   test_screen()->SetUIScale(kUIScale);
    258   test_screen()->SetDisplayRotation(gfx::Display::ROTATE_90);
    259 
    260   gfx::Rect test_bounds(100, 100, 300, 200);
    261   SetupTestWindow(test_bounds);
    262   WaitForDraw();
    263 
    264   // Snapshot always captures the physical pixels.
    265   gfx::SizeF snapshot_size(test_bounds.size());
    266 
    267   gfx::Image snapshot = GrabSnapshotForTestWindow();
    268   EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
    269             snapshot.Size().ToString());
    270   EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
    271 }
    272 
    273 TEST_F(SnapshotAuraTest, RotateAndUIScaleAndScaleFactor) {
    274   test_screen()->SetDeviceScaleFactor(2.0f);
    275   const float kUIScale = 1.25f;
    276   test_screen()->SetUIScale(kUIScale);
    277   test_screen()->SetDisplayRotation(gfx::Display::ROTATE_90);
    278 
    279   gfx::Rect test_bounds(20, 30, 150, 100);
    280   SetupTestWindow(test_bounds);
    281   WaitForDraw();
    282 
    283   // Snapshot always captures the physical pixels.
    284   gfx::SizeF snapshot_size(test_bounds.size());
    285   snapshot_size.Scale(2.0f);
    286 
    287   gfx::Image snapshot = GrabSnapshotForTestWindow();
    288   EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
    289             snapshot.Size().ToString());
    290   EXPECT_EQ(0u, GetFailedPixelsCountWithScaleFactor(snapshot, 2));
    291 }
    292 
    293 }  // namespace ui
    294