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