Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / desktop_capture / desktop_and_cursor_composer_unittest.cc
1 /*
2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #include "webrtc/modules/desktop_capture/desktop_and_cursor_composer.h"
12
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
15 #include "webrtc/modules/desktop_capture/desktop_frame.h"
16 #include "webrtc/modules/desktop_capture/mouse_cursor.h"
17 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
18 #include "webrtc/modules/desktop_capture/window_capturer.h"
19 #include "webrtc/system_wrappers/interface/logging.h"
20 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
21
22 namespace webrtc {
23
24 namespace {
25
26 const int kScreenWidth = 100;
27 const int kScreenHeight = 100;
28 const int kCursorWidth = 10;
29 const int kCursorHeight = 10;
30
31 const int kTestCursorSize = 3;
32 const uint32_t kTestCursorData[kTestCursorSize][kTestCursorSize] = {
33   { 0xffffffff, 0x99990000, 0xaa222222, },
34   { 0x88008800, 0xaa0000aa, 0xaa333333, },
35   { 0x00000000, 0xaa0000aa, 0xaa333333, },
36 };
37
38 uint32_t GetFakeFramePixelValue(const DesktopVector& p) {
39   uint32_t r = 100 + p.x();
40   uint32_t g = 100 + p.y();
41   uint32_t b = 100 + p.x() + p.y();
42   return b + (g << 8) + (r << 16) + 0xff000000;
43 }
44
45 uint32_t GetFramePixel(const DesktopFrame& frame, const DesktopVector& pos) {
46   return *reinterpret_cast<uint32_t*>(frame.data() + pos.y() * frame.stride() +
47                                       pos.x() * DesktopFrame::kBytesPerPixel);
48 }
49
50 // Blends two pixel values taking into account alpha.
51 uint32_t BlendPixels(uint32_t dest, uint32_t src) {
52   uint8_t alpha = 255 - ((src & 0xff000000) >> 24);
53   uint32_t r =
54       ((dest & 0x00ff0000) >> 16) * alpha / 255 + ((src & 0x00ff0000) >> 16);
55   uint32_t g =
56       ((dest & 0x0000ff00) >> 8) * alpha / 255 + ((src & 0x0000ff00) >> 8);
57   uint32_t b = (dest & 0x000000ff) * alpha / 255 + (src & 0x000000ff);
58   return b + (g << 8) + (r << 16) + 0xff000000;
59 }
60
61 DesktopFrame* CreateTestFrame() {
62   DesktopFrame* frame =
63       new BasicDesktopFrame(DesktopSize(kScreenWidth, kScreenHeight));
64   uint32_t* data = reinterpret_cast<uint32_t*>(frame->data());
65   for (int y = 0; y < kScreenHeight; ++y) {
66     for (int x = 0; x < kScreenWidth; ++x) {
67       *(data++) = GetFakeFramePixelValue(DesktopVector(x, y));
68     }
69   }
70   return frame;
71 }
72
73 class FakeScreenCapturer : public DesktopCapturer {
74  public:
75   FakeScreenCapturer() {}
76
77   virtual void Start(Callback* callback) OVERRIDE {
78     callback_ = callback;
79   }
80
81   virtual void Capture(const DesktopRegion& region) OVERRIDE {
82     callback_->OnCaptureCompleted(next_frame_.release());
83   }
84
85   void SetNextFrame(DesktopFrame* next_frame) {
86     next_frame_.reset(next_frame);
87   }
88
89  private:
90   Callback* callback_;
91
92   scoped_ptr<DesktopFrame> next_frame_;
93 };
94
95 class FakeMouseMonitor : public MouseCursorMonitor {
96  public:
97   FakeMouseMonitor() : changed_(true) {}
98
99   void SetState(CursorState state, const DesktopVector& pos) {
100     state_ = state;
101     position_ = pos;
102   }
103
104   void SetHotspot(const DesktopVector& hotspot) {
105     if (!hotspot_.equals(hotspot))
106       changed_ = true;
107     hotspot_ = hotspot;
108   }
109
110   virtual void Init(Callback* callback, Mode mode) OVERRIDE {
111     callback_ = callback;
112   }
113
114   virtual void Capture() OVERRIDE {
115     if (changed_) {
116       scoped_ptr<DesktopFrame> image(
117           new BasicDesktopFrame(DesktopSize(kCursorWidth, kCursorHeight)));
118       uint32_t* data = reinterpret_cast<uint32_t*>(image->data());
119       memset(data, 0, image->stride() * kCursorHeight);
120
121       // Set four pixels near the hotspot and leave all other blank.
122       for (int y = 0; y < kTestCursorSize; ++y) {
123         for (int x = 0; x < kTestCursorSize; ++x) {
124           data[(hotspot_.y() + y) * kCursorWidth + (hotspot_.x() + x)] =
125               kTestCursorData[y][x];
126         }
127       }
128
129       callback_->OnMouseCursor(new MouseCursor(image.release(), hotspot_));
130     }
131
132     callback_->OnMouseCursorPosition(state_, position_);
133   }
134
135  private:
136   Callback* callback_;
137   CursorState state_;
138   DesktopVector position_;
139   DesktopVector hotspot_;
140   bool changed_;
141 };
142
143 void VerifyFrame(const DesktopFrame& frame,
144                  MouseCursorMonitor::CursorState state,
145                  const DesktopVector& pos) {
146   // Verify that all other pixels are set to their original values.
147   DesktopRect image_rect =
148       DesktopRect::MakeWH(kTestCursorSize, kTestCursorSize);
149   image_rect.Translate(pos);
150
151   for (int y = 0; y < kScreenHeight; ++y) {
152     for (int x = 0; x < kScreenWidth; ++x) {
153       DesktopVector p(x, y);
154       if (state == MouseCursorMonitor::INSIDE && image_rect.Contains(p)) {
155         EXPECT_EQ(BlendPixels(GetFakeFramePixelValue(p),
156                               kTestCursorData[y - pos.y()][x - pos.x()]),
157                   GetFramePixel(frame, p));
158       } else {
159         EXPECT_EQ(GetFakeFramePixelValue(p), GetFramePixel(frame, p));
160       }
161     }
162   }
163 }
164
165 class DesktopAndCursorComposerTest : public testing::Test,
166                                      public DesktopCapturer::Callback {
167  public:
168   DesktopAndCursorComposerTest()
169       : fake_screen_(new FakeScreenCapturer()),
170         fake_cursor_(new FakeMouseMonitor()),
171         blender_(fake_screen_, fake_cursor_) {
172   }
173
174   // DesktopCapturer::Callback interface
175   virtual SharedMemory* CreateSharedMemory(size_t size) OVERRIDE {
176     return NULL;
177   }
178
179   virtual void OnCaptureCompleted(DesktopFrame* frame) OVERRIDE {
180     frame_.reset(frame);
181   }
182
183  protected:
184   // Owned by |blender_|.
185   FakeScreenCapturer* fake_screen_;
186   FakeMouseMonitor* fake_cursor_;
187
188   DesktopAndCursorComposer blender_;
189   scoped_ptr<DesktopFrame> frame_;
190 };
191
192 // Verify DesktopAndCursorComposer can handle the case when the screen capturer
193 // fails.
194 TEST_F(DesktopAndCursorComposerTest, Error) {
195   blender_.Start(this);
196
197   fake_cursor_->SetHotspot(DesktopVector());
198   fake_cursor_->SetState(MouseCursorMonitor::INSIDE, DesktopVector());
199   fake_screen_->SetNextFrame(NULL);
200
201   blender_.Capture(DesktopRegion());
202
203   EXPECT_EQ(frame_, static_cast<DesktopFrame*>(NULL));
204 }
205
206 TEST_F(DesktopAndCursorComposerTest, Blend) {
207   struct {
208     int x, y;
209     int hotspot_x, hotspot_y;
210     bool inside;
211   } tests[] = {
212     {0, 0, 0, 0, true},
213     {50, 50, 0, 0, true},
214     {100, 50, 0, 0, true},
215     {50, 100, 0, 0, true},
216     {100, 100, 0, 0, true},
217     {0, 0, 2, 5, true},
218     {1, 1, 2, 5, true},
219     {50, 50, 2, 5, true},
220     {100, 100, 2, 5, true},
221     {0, 0, 5, 2, true},
222     {50, 50, 5, 2, true},
223     {100, 100, 5, 2, true},
224     {0, 0, 0, 0, false},
225   };
226
227   blender_.Start(this);
228
229   for (size_t i = 0; i < (sizeof(tests) / sizeof(tests[0])); ++i) {
230     SCOPED_TRACE(i);
231
232     DesktopVector hotspot(tests[i].hotspot_x, tests[i].hotspot_y);
233     fake_cursor_->SetHotspot(hotspot);
234
235     MouseCursorMonitor::CursorState state = tests[i].inside
236                                                 ? MouseCursorMonitor::INSIDE
237                                                 : MouseCursorMonitor::OUTSIDE;
238     DesktopVector pos(tests[i].x, tests[i].y);
239     fake_cursor_->SetState(state, pos);
240
241     scoped_ptr<SharedDesktopFrame> frame(
242         SharedDesktopFrame::Wrap(CreateTestFrame()));
243     fake_screen_->SetNextFrame(frame->Share());
244
245     blender_.Capture(DesktopRegion());
246
247     VerifyFrame(*frame_, state, pos);
248
249     // Verify that the cursor is erased before the frame buffer is returned to
250     // the screen capturer.
251     frame_.reset();
252     VerifyFrame(*frame, MouseCursorMonitor::OUTSIDE, DesktopVector());
253   }
254 }
255
256 }  // namespace
257
258 }  // namespace webrtc