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.
5 #include "ui/snapshot/snapshot.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"
32 SkColor GetExpectedColorForPoint(int x, int y) {
33 return SkColorSetRGB(std::min(x, 255), std::min(y, 255), 0);
36 // Paint simple rectangle on the specified aura window.
37 class TestPaintingWindowDelegate : public aura::test::TestWindowDelegate {
39 explicit TestPaintingWindowDelegate(const gfx::Size& window_size)
40 : window_size_(window_size) {
43 ~TestPaintingWindowDelegate() override {}
45 void OnPaint(gfx::Canvas* canvas) override {
46 for (int y = 0; y < window_size_.height(); ++y) {
47 for (int x = 0; x < window_size_.width(); ++x)
48 canvas->FillRect(gfx::Rect(x, y, 1, 1), GetExpectedColorForPoint(x, y));
53 gfx::Size window_size_;
55 DISALLOW_COPY_AND_ASSIGN(TestPaintingWindowDelegate);
58 size_t GetFailedPixelsCountWithScaleFactor(const gfx::Image& image,
60 const SkBitmap* bitmap = image.ToSkBitmap();
61 uint32* bitmap_data = reinterpret_cast<uint32*>(
62 bitmap->pixelRef()->pixels());
64 for (int y = 0; y < bitmap->height(); y += scale_factor) {
65 for (int x = 0; x < bitmap->width(); x += scale_factor) {
66 if (static_cast<SkColor>(bitmap_data[x + y * bitmap->width()]) !=
67 GetExpectedColorForPoint(x / scale_factor, y / scale_factor)) {
75 size_t GetFailedPixelsCount(const gfx::Image& image) {
76 return GetFailedPixelsCountWithScaleFactor(image, 1);
81 class SnapshotAuraTest : public testing::Test {
84 ~SnapshotAuraTest() override {}
86 void SetUp() override {
87 testing::Test::SetUp();
89 // The ContextFactory must exist before any Compositors are created.
90 // Snapshot test tests real drawing and readback, so needs pixel output.
91 bool enable_pixel_output = true;
92 ui::ContextFactory* context_factory =
93 ui::InitializeContextFactoryForTests(enable_pixel_output);
96 new aura::test::AuraTestHelper(base::MessageLoopForUI::current()));
97 helper_->SetUp(context_factory);
98 new ::wm::DefaultActivationClient(helper_->root_window());
101 void TearDown() override {
102 test_window_.reset();
104 helper_->RunAllPendingInMessageLoop();
106 ui::TerminateContextFactoryForTests();
107 testing::Test::TearDown();
111 aura::Window* test_window() { return test_window_.get(); }
112 aura::Window* root_window() { return helper_->root_window(); }
113 aura::TestScreen* test_screen() { return helper_->test_screen(); }
116 helper_->host()->compositor()->ScheduleDraw();
117 ui::DrawWaiterForTest::Wait(helper_->host()->compositor());
120 void SetupTestWindow(const gfx::Rect& window_bounds) {
121 delegate_.reset(new TestPaintingWindowDelegate(window_bounds.size()));
122 test_window_.reset(aura::test::CreateTestWindowWithDelegate(
123 delegate_.get(), 0, window_bounds, root_window()));
126 gfx::Image GrabSnapshotForTestWindow() {
127 gfx::Rect source_rect(test_window_->bounds().size());
128 aura::Window::ConvertRectToTarget(
129 test_window(), root_window(), &source_rect);
131 scoped_refptr<base::TestSimpleTaskRunner> task_runner(
132 new base::TestSimpleTaskRunner());
133 scoped_refptr<SnapshotHolder> holder(new SnapshotHolder);
134 ui::GrabWindowSnapshotAsync(
138 base::Bind(&SnapshotHolder::SnapshotCallback, holder));
140 // Wait for copy response.
142 // Run internal snapshot callback to scale/rotate response image.
143 task_runner->RunUntilIdle();
144 // Run SnapshotHolder callback.
145 helper_->RunAllPendingInMessageLoop();
147 if (holder->completed())
148 return holder->image();
150 // Callback never called.
156 class SnapshotHolder : public base::RefCountedThreadSafe<SnapshotHolder> {
158 SnapshotHolder() : completed_(false) {}
160 void SnapshotCallback(scoped_refptr<base::RefCountedBytes> png_data) {
162 image_ = gfx::Image::CreateFrom1xPNGBytes(&(png_data->data()[0]),
166 bool completed() const {
169 const gfx::Image& image() const { return image_; }
172 friend class base::RefCountedThreadSafe<SnapshotHolder>;
174 virtual ~SnapshotHolder() {}
180 scoped_ptr<aura::test::AuraTestHelper> helper_;
181 scoped_ptr<aura::Window> test_window_;
182 scoped_ptr<TestPaintingWindowDelegate> delegate_;
183 std::vector<unsigned char> png_representation_;
185 DISALLOW_COPY_AND_ASSIGN(SnapshotAuraTest);
188 TEST_F(SnapshotAuraTest, FullScreenWindow) {
189 SetupTestWindow(root_window()->bounds());
192 gfx::Image snapshot = GrabSnapshotForTestWindow();
193 EXPECT_EQ(test_window()->bounds().size().ToString(),
194 snapshot.Size().ToString());
195 EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
198 TEST_F(SnapshotAuraTest, PartialBounds) {
199 gfx::Rect test_bounds(100, 100, 300, 200);
200 SetupTestWindow(test_bounds);
203 gfx::Image snapshot = GrabSnapshotForTestWindow();
204 EXPECT_EQ(test_bounds.size().ToString(), snapshot.Size().ToString());
205 EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
208 TEST_F(SnapshotAuraTest, Rotated) {
209 test_screen()->SetDisplayRotation(gfx::Display::ROTATE_90);
211 gfx::Rect test_bounds(100, 100, 300, 200);
212 SetupTestWindow(test_bounds);
215 gfx::Image snapshot = GrabSnapshotForTestWindow();
216 EXPECT_EQ(test_bounds.size().ToString(), snapshot.Size().ToString());
217 EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
220 TEST_F(SnapshotAuraTest, UIScale) {
221 const float kUIScale = 1.25f;
222 test_screen()->SetUIScale(kUIScale);
224 gfx::Rect test_bounds(100, 100, 300, 200);
225 SetupTestWindow(test_bounds);
228 // Snapshot always captures the physical pixels.
229 gfx::SizeF snapshot_size(test_bounds.size());
231 gfx::Image snapshot = GrabSnapshotForTestWindow();
232 EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
233 snapshot.Size().ToString());
234 EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
237 TEST_F(SnapshotAuraTest, DeviceScaleFactor) {
238 test_screen()->SetDeviceScaleFactor(2.0f);
240 gfx::Rect test_bounds(100, 100, 150, 100);
241 SetupTestWindow(test_bounds);
244 // Snapshot always captures the physical pixels.
245 gfx::SizeF snapshot_size(test_bounds.size());
246 snapshot_size.Scale(2.0f);
248 gfx::Image snapshot = GrabSnapshotForTestWindow();
249 EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
250 snapshot.Size().ToString());
251 EXPECT_EQ(0u, GetFailedPixelsCountWithScaleFactor(snapshot, 2));
254 TEST_F(SnapshotAuraTest, RotateAndUIScale) {
255 const float kUIScale = 1.25f;
256 test_screen()->SetUIScale(kUIScale);
257 test_screen()->SetDisplayRotation(gfx::Display::ROTATE_90);
259 gfx::Rect test_bounds(100, 100, 300, 200);
260 SetupTestWindow(test_bounds);
263 // Snapshot always captures the physical pixels.
264 gfx::SizeF snapshot_size(test_bounds.size());
266 gfx::Image snapshot = GrabSnapshotForTestWindow();
267 EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
268 snapshot.Size().ToString());
269 EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
272 TEST_F(SnapshotAuraTest, RotateAndUIScaleAndScaleFactor) {
273 test_screen()->SetDeviceScaleFactor(2.0f);
274 const float kUIScale = 1.25f;
275 test_screen()->SetUIScale(kUIScale);
276 test_screen()->SetDisplayRotation(gfx::Display::ROTATE_90);
278 gfx::Rect test_bounds(20, 30, 150, 100);
279 SetupTestWindow(test_bounds);
282 // Snapshot always captures the physical pixels.
283 gfx::SizeF snapshot_size(test_bounds.size());
284 snapshot_size.Scale(2.0f);
286 gfx::Image snapshot = GrabSnapshotForTestWindow();
287 EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
288 snapshot.Size().ToString());
289 EXPECT_EQ(0u, GetFailedPixelsCountWithScaleFactor(snapshot, 2));