• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetExpectedColorForPoint(int x,int y)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:
TestPaintingWindowDelegate(const gfx::Size & window_size)39   explicit TestPaintingWindowDelegate(const gfx::Size& window_size)
40       : window_size_(window_size) {
41   }
42 
~TestPaintingWindowDelegate()43   virtual ~TestPaintingWindowDelegate() {
44   }
45 
OnPaint(gfx::Canvas * canvas)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 
GetFailedPixelsCountWithScaleFactor(const gfx::Image & image,int scale_factor)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 
GetFailedPixelsCount(const gfx::Image & image)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:
SnapshotAuraTest()84   SnapshotAuraTest() {}
~SnapshotAuraTest()85   virtual ~SnapshotAuraTest() {}
86 
SetUp()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 
TearDown()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:
test_window()112   aura::Window* test_window() { return test_window_.get(); }
root_window()113   aura::Window* root_window() { return helper_->root_window(); }
test_screen()114   aura::TestScreen* test_screen() { return helper_->test_screen(); }
115 
WaitForDraw()116   void WaitForDraw() {
117     helper_->host()->compositor()->ScheduleDraw();
118     ui::DrawWaiterForTest::Wait(helper_->host()->compositor());
119   }
120 
SetupTestWindow(const gfx::Rect & window_bounds)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 
GrabSnapshotForTestWindow()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:
SnapshotHolder()159     SnapshotHolder() : completed_(false) {}
160 
SnapshotCallback(scoped_refptr<base::RefCountedBytes> png_data)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     }
completed() const167     bool completed() const {
168       return completed_;
169     };
image() const170     const gfx::Image& image() const { return image_; }
171 
172    private:
173     friend class base::RefCountedThreadSafe<SnapshotHolder>;
174 
~SnapshotHolder()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 
TEST_F(SnapshotAuraTest,FullScreenWindow)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 
TEST_F(SnapshotAuraTest,PartialBounds)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 
TEST_F(SnapshotAuraTest,Rotated)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 
TEST_F(SnapshotAuraTest,UIScale)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 
TEST_F(SnapshotAuraTest,DeviceScaleFactor)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 
TEST_F(SnapshotAuraTest,RotateAndUIScale)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 
TEST_F(SnapshotAuraTest,RotateAndUIScaleAndScaleFactor)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