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 "base/memory/scoped_ptr.h"
6#include "base/message_loop/message_loop.h"
7#include "cc/output/software_frame_data.h"
8#include "content/browser/compositor/software_output_device_ozone.h"
9#include "testing/gtest/include/gtest/gtest.h"
10#include "third_party/skia/include/core/SkDevice.h"
11#include "third_party/skia/include/core/SkSurface.h"
12#include "ui/compositor/compositor.h"
13#include "ui/compositor/test/context_factories_for_test.h"
14#include "ui/gfx/size.h"
15#include "ui/gfx/skia_util.h"
16#include "ui/gfx/vsync_provider.h"
17#include "ui/gl/gl_implementation.h"
18#include "ui/ozone/public/surface_factory_ozone.h"
19#include "ui/ozone/public/surface_ozone_canvas.h"
20
21namespace {
22
23class MockSurfaceOzone : public ui::SurfaceOzoneCanvas {
24 public:
25  MockSurfaceOzone() {}
26  virtual ~MockSurfaceOzone() {}
27
28  // ui::SurfaceOzoneCanvas overrides:
29  virtual void ResizeCanvas(const gfx::Size& size) OVERRIDE {
30    surface_ = skia::AdoptRef(SkSurface::NewRaster(
31        SkImageInfo::MakeN32Premul(size.width(), size.height())));
32  }
33  virtual skia::RefPtr<SkCanvas> GetCanvas() OVERRIDE {
34    return skia::SharePtr(surface_->getCanvas());
35  }
36  virtual void PresentCanvas(const gfx::Rect& damage) OVERRIDE {}
37  virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE {
38    return scoped_ptr<gfx::VSyncProvider>();
39  }
40
41 private:
42  skia::RefPtr<SkSurface> surface_;
43
44  DISALLOW_COPY_AND_ASSIGN(MockSurfaceOzone);
45};
46
47class MockSurfaceFactoryOzone : public ui::SurfaceFactoryOzone {
48 public:
49  MockSurfaceFactoryOzone() {}
50  virtual ~MockSurfaceFactoryOzone() {}
51
52  virtual bool LoadEGLGLES2Bindings(
53      AddGLLibraryCallback add_gl_library,
54      SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE {
55    return false;
56  }
57  virtual scoped_ptr<ui::SurfaceOzoneCanvas> CreateCanvasForWidget(
58      gfx::AcceleratedWidget widget) OVERRIDE {
59    return make_scoped_ptr<ui::SurfaceOzoneCanvas>(new MockSurfaceOzone());
60  }
61
62 private:
63  DISALLOW_COPY_AND_ASSIGN(MockSurfaceFactoryOzone);
64};
65
66}  // namespace
67
68class SoftwareOutputDeviceOzoneTest : public testing::Test {
69 public:
70  SoftwareOutputDeviceOzoneTest();
71  virtual ~SoftwareOutputDeviceOzoneTest();
72
73  virtual void SetUp() OVERRIDE;
74  virtual void TearDown() OVERRIDE;
75
76 protected:
77  scoped_ptr<content::SoftwareOutputDeviceOzone> output_device_;
78  bool enable_pixel_output_;
79
80 private:
81  scoped_ptr<ui::Compositor> compositor_;
82  scoped_ptr<base::MessageLoop> message_loop_;
83  scoped_ptr<ui::SurfaceFactoryOzone> surface_factory_;
84
85  DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceOzoneTest);
86};
87
88SoftwareOutputDeviceOzoneTest::SoftwareOutputDeviceOzoneTest()
89    : enable_pixel_output_(false) {
90  message_loop_.reset(new base::MessageLoopForUI);
91}
92
93SoftwareOutputDeviceOzoneTest::~SoftwareOutputDeviceOzoneTest() {
94}
95
96void SoftwareOutputDeviceOzoneTest::SetUp() {
97  ui::ContextFactory* context_factory =
98      ui::InitializeContextFactoryForTests(enable_pixel_output_);
99
100  surface_factory_.reset(new MockSurfaceFactoryOzone());
101
102  const gfx::Size size(500, 400);
103  const gfx::AcceleratedWidget kTestAcceleratedWidget = 1;
104  compositor_.reset(
105      new ui::Compositor(kTestAcceleratedWidget,
106                         context_factory,
107                         base::MessageLoopProxy::current()));
108  compositor_->SetScaleAndSize(1.0f, size);
109
110  output_device_.reset(new content::SoftwareOutputDeviceOzone(
111      compositor_.get()));
112  output_device_->Resize(size, 1.f);
113}
114
115void SoftwareOutputDeviceOzoneTest::TearDown() {
116  output_device_.reset();
117  compositor_.reset();
118  surface_factory_.reset();
119  ui::TerminateContextFactoryForTests();
120}
121
122class SoftwareOutputDeviceOzonePixelTest
123    : public SoftwareOutputDeviceOzoneTest {
124 protected:
125  virtual void SetUp() OVERRIDE;
126};
127
128void SoftwareOutputDeviceOzonePixelTest::SetUp() {
129  enable_pixel_output_ = true;
130  SoftwareOutputDeviceOzoneTest::SetUp();
131}
132
133TEST_F(SoftwareOutputDeviceOzoneTest, CheckCorrectResizeBehavior) {
134  gfx::Rect damage(0, 0, 100, 100);
135  gfx::Size size(200, 100);
136  // Reduce size.
137  output_device_->Resize(size, 1.f);
138
139  SkCanvas* canvas = output_device_->BeginPaint(damage);
140  gfx::Size canvas_size(canvas->getDeviceSize().width(),
141                        canvas->getDeviceSize().height());
142  EXPECT_EQ(size.ToString(), canvas_size.ToString());
143
144  size.SetSize(1000, 500);
145  // Increase size.
146  output_device_->Resize(size, 1.f);
147
148  canvas = output_device_->BeginPaint(damage);
149  canvas_size.SetSize(canvas->getDeviceSize().width(),
150                      canvas->getDeviceSize().height());
151  EXPECT_EQ(size.ToString(), canvas_size.ToString());
152
153}
154
155TEST_F(SoftwareOutputDeviceOzonePixelTest, CheckCopyToBitmap) {
156  const int width = 6;
157  const int height = 4;
158  const gfx::Rect area(width, height);
159  output_device_->Resize(area.size(), 1.f);
160  SkCanvas* canvas = output_device_->BeginPaint(area);
161
162  // Clear the background to black.
163  canvas->drawColor(SK_ColorBLACK);
164
165  cc::SoftwareFrameData frame;
166  output_device_->EndPaint(&frame);
167
168  // Draw a white rectangle.
169  gfx::Rect damage(area.width() / 2, area.height() / 2);
170  canvas = output_device_->BeginPaint(damage);
171  canvas->clipRect(gfx::RectToSkRect(damage), SkRegion::kReplace_Op);
172
173  canvas->drawColor(SK_ColorWHITE);
174
175  output_device_->EndPaint(&frame);
176
177  SkPMColor pixels[width * height];
178  output_device_->CopyToPixels(area, pixels);
179
180  // Check that the copied bitmap contains the same pixel values as what we
181  // painted.
182  const SkPMColor white = SkPreMultiplyColor(SK_ColorWHITE);
183  const SkPMColor black = SkPreMultiplyColor(SK_ColorBLACK);
184  for (int i = 0; i < area.height(); ++i) {
185    for (int j = 0; j < area.width(); ++j) {
186      if (j < damage.width() && i < damage.height())
187        EXPECT_EQ(white, pixels[i * area.width() + j]);
188      else
189        EXPECT_EQ(black, pixels[i * area.width() + j]);
190    }
191  }
192}
193