1 /*
2 * Copyright (c) 2019 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 "modules/desktop_capture/desktop_frame.h"
12
13 #include <memory>
14
15 #include "modules/desktop_capture/desktop_region.h"
16 #include "modules/desktop_capture/test_utils.h"
17 #include "rtc_base/arraysize.h"
18 #include "test/gtest.h"
19
20 namespace webrtc {
21
22 namespace {
23
CreateTestFrame(DesktopRect rect,int pixels_value)24 std::unique_ptr<DesktopFrame> CreateTestFrame(DesktopRect rect,
25 int pixels_value) {
26 DesktopSize size = rect.size();
27 auto frame = std::make_unique<BasicDesktopFrame>(size);
28 frame->set_top_left(rect.top_left());
29 memset(frame->data(), pixels_value, frame->stride() * size.height());
30 return frame;
31 }
32
33 struct TestData {
34 const char* description;
35 DesktopRect dest_frame_rect;
36 DesktopRect src_frame_rect;
37 double horizontal_scale;
38 double vertical_scale;
39 DesktopRect expected_overlap_rect;
40 };
41
RunTest(const TestData & test)42 void RunTest(const TestData& test) {
43 // Copy a source frame with all bits set into a dest frame with none set.
44 auto dest_frame = CreateTestFrame(test.dest_frame_rect, 0);
45 auto src_frame = CreateTestFrame(test.src_frame_rect, 0xff);
46
47 dest_frame->CopyIntersectingPixelsFrom(
48 *src_frame, test.horizontal_scale, test.vertical_scale);
49
50 // Translate the expected overlap rect to be relative to the dest frame/rect.
51 DesktopVector dest_frame_origin = test.dest_frame_rect.top_left();
52 DesktopRect relative_expected_overlap_rect = test.expected_overlap_rect;
53 relative_expected_overlap_rect.Translate(-dest_frame_origin.x(),
54 -dest_frame_origin.y());
55
56 // Confirm bits are now set in the dest frame if & only if they fall in the
57 // expected range.
58 for (int y = 0; y < dest_frame->size().height(); ++y) {
59 SCOPED_TRACE(y);
60
61 for (int x = 0; x < dest_frame->size().width(); ++x) {
62 SCOPED_TRACE(x);
63
64 DesktopVector point(x, y);
65 uint8_t* data = dest_frame->GetFrameDataAtPos(point);
66 uint32_t pixel_value = *reinterpret_cast<uint32_t*>(data);
67 bool was_copied = pixel_value == 0xffffffff;
68 ASSERT_TRUE(was_copied || pixel_value == 0);
69
70 bool expected_to_be_copied =
71 relative_expected_overlap_rect.Contains(point);
72
73 ASSERT_EQ(was_copied, expected_to_be_copied);
74 }
75 }
76 }
77
RunTests(const TestData * tests,int num_tests)78 void RunTests(const TestData* tests, int num_tests) {
79 for (int i = 0; i < num_tests; i++) {
80 const TestData& test = tests[i];
81
82 SCOPED_TRACE(test.description);
83
84 RunTest(test);
85 }
86 }
87
88 } // namespace
89
TEST(DesktopFrameTest,CopyIntersectingPixelsMatchingRects)90 TEST(DesktopFrameTest, CopyIntersectingPixelsMatchingRects) {
91 const TestData tests[] = {
92 {"0 origin",
93 DesktopRect::MakeXYWH(0, 0, 2, 2),
94 DesktopRect::MakeXYWH(0, 0, 2, 2),
95 1.0, 1.0,
96 DesktopRect::MakeXYWH(0, 0, 2, 2)},
97
98 {"Negative origin",
99 DesktopRect::MakeXYWH(-1, -1, 2, 2),
100 DesktopRect::MakeXYWH(-1, -1, 2, 2),
101 1.0, 1.0,
102 DesktopRect::MakeXYWH(-1, -1, 2, 2)}
103 };
104
105 RunTests(tests, arraysize(tests));
106 }
107
TEST(DesktopFrameTest,CopyIntersectingPixelsMatchingRectsScaled)108 TEST(DesktopFrameTest, CopyIntersectingPixelsMatchingRectsScaled) {
109 // The scale factors shouldn't affect matching rects (they're only applied
110 // to any difference between the origins)
111 const TestData tests[] = {
112 {"0 origin 2x",
113 DesktopRect::MakeXYWH(0, 0, 2, 2),
114 DesktopRect::MakeXYWH(0, 0, 2, 2),
115 2.0, 2.0,
116 DesktopRect::MakeXYWH(0, 0, 2, 2)},
117
118 {"0 origin 0.5x",
119 DesktopRect::MakeXYWH(0, 0, 2, 2),
120 DesktopRect::MakeXYWH(0, 0, 2, 2),
121 0.5, 0.5,
122 DesktopRect::MakeXYWH(0, 0, 2, 2)},
123
124 {"Negative origin 2x",
125 DesktopRect::MakeXYWH(-1, -1, 2, 2),
126 DesktopRect::MakeXYWH(-1, -1, 2, 2),
127 2.0, 2.0,
128 DesktopRect::MakeXYWH(-1, -1, 2, 2)},
129
130 {"Negative origin 0.5x",
131 DesktopRect::MakeXYWH(-1, -1, 2, 2),
132 DesktopRect::MakeXYWH(-1, -1, 2, 2),
133 0.5, 0.5,
134 DesktopRect::MakeXYWH(-1, -1, 2, 2)}
135 };
136
137 RunTests(tests, arraysize(tests));
138 }
139
TEST(DesktopFrameTest,CopyIntersectingPixelsFullyContainedRects)140 TEST(DesktopFrameTest, CopyIntersectingPixelsFullyContainedRects) {
141 const TestData tests[] = {
142 {"0 origin top left",
143 DesktopRect::MakeXYWH(0, 0, 2, 2),
144 DesktopRect::MakeXYWH(0, 0, 1, 1),
145 1.0, 1.0,
146 DesktopRect::MakeXYWH(0, 0, 1, 1)},
147
148 {"0 origin bottom right",
149 DesktopRect::MakeXYWH(0, 0, 2, 2),
150 DesktopRect::MakeXYWH(1, 1, 1, 1),
151 1.0, 1.0,
152 DesktopRect::MakeXYWH(1, 1, 1, 1)},
153
154 {"Negative origin bottom left",
155 DesktopRect::MakeXYWH(-1, -1, 2, 2),
156 DesktopRect::MakeXYWH(-1, 0, 1, 1),
157 1.0, 1.0,
158 DesktopRect::MakeXYWH(-1, 0, 1, 1)}
159 };
160
161 RunTests(tests, arraysize(tests));
162 }
163
TEST(DesktopFrameTest,CopyIntersectingPixelsFullyContainedRectsScaled)164 TEST(DesktopFrameTest, CopyIntersectingPixelsFullyContainedRectsScaled) {
165 const TestData tests[] = {
166 {"0 origin top left 2x",
167 DesktopRect::MakeXYWH(0, 0, 2, 2),
168 DesktopRect::MakeXYWH(0, 0, 1, 1),
169 2.0, 2.0,
170 DesktopRect::MakeXYWH(0, 0, 1, 1)},
171
172 {"0 origin top left 0.5x",
173 DesktopRect::MakeXYWH(0, 0, 2, 2),
174 DesktopRect::MakeXYWH(0, 0, 1, 1),
175 0.5, 0.5,
176 DesktopRect::MakeXYWH(0, 0, 1, 1)},
177
178 {"0 origin bottom left 2x",
179 DesktopRect::MakeXYWH(0, 0, 4, 4),
180 DesktopRect::MakeXYWH(1, 1, 2, 2),
181 2.0, 2.0,
182 DesktopRect::MakeXYWH(2, 2, 2, 2)},
183
184 {"0 origin bottom middle 2x/1x",
185 DesktopRect::MakeXYWH(0, 0, 4, 3),
186 DesktopRect::MakeXYWH(1, 1, 2, 2),
187 2.0, 1.0,
188 DesktopRect::MakeXYWH(2, 1, 2, 2)},
189
190 {"0 origin middle 0.5x",
191 DesktopRect::MakeXYWH(0, 0, 3, 3),
192 DesktopRect::MakeXYWH(2, 2, 1, 1),
193 0.5, 0.5,
194 DesktopRect::MakeXYWH(1, 1, 1, 1)},
195
196 {"Negative origin bottom left 2x",
197 DesktopRect::MakeXYWH(-1, -1, 3, 3),
198 DesktopRect::MakeXYWH(-1, 0, 1, 1),
199 2.0, 2.0,
200 DesktopRect::MakeXYWH(-1, 1, 1, 1)},
201
202 {"Negative origin near middle 0.5x",
203 DesktopRect::MakeXYWH(-2, -2, 2, 2),
204 DesktopRect::MakeXYWH(0, 0, 1, 1),
205 0.5, 0.5,
206 DesktopRect::MakeXYWH(-1, -1, 1, 1)}
207 };
208
209 RunTests(tests, arraysize(tests));
210 }
211
212
TEST(DesktopFrameTest,CopyIntersectingPixelsPartiallyContainedRects)213 TEST(DesktopFrameTest, CopyIntersectingPixelsPartiallyContainedRects) {
214 const TestData tests[] = {
215 {"Top left",
216 DesktopRect::MakeXYWH(0, 0, 2, 2),
217 DesktopRect::MakeXYWH(-1, -1, 2, 2),
218 1.0, 1.0,
219 DesktopRect::MakeXYWH(0, 0, 1, 1)},
220
221 {"Top right",
222 DesktopRect::MakeXYWH(0, 0, 2, 2),
223 DesktopRect::MakeXYWH(1, -1, 2, 2),
224 1.0, 1.0,
225 DesktopRect::MakeXYWH(1, 0, 1, 1)},
226
227 {"Bottom right",
228 DesktopRect::MakeXYWH(0, 0, 2, 2),
229 DesktopRect::MakeXYWH(1, 1, 2, 2),
230 1.0, 1.0,
231 DesktopRect::MakeXYWH(1, 1, 1, 1)},
232
233 {"Bottom left",
234 DesktopRect::MakeXYWH(0, 0, 2, 2),
235 DesktopRect::MakeXYWH(-1, 1, 2, 2),
236 1.0, 1.0,
237 DesktopRect::MakeXYWH(0, 1, 1, 1)}
238 };
239
240 RunTests(tests, arraysize(tests));
241 }
242
TEST(DesktopFrameTest,CopyIntersectingPixelsPartiallyContainedRectsScaled)243 TEST(DesktopFrameTest, CopyIntersectingPixelsPartiallyContainedRectsScaled) {
244 const TestData tests[] = {
245 {"Top left 2x",
246 DesktopRect::MakeXYWH(0, 0, 2, 2),
247 DesktopRect::MakeXYWH(-1, -1, 3, 3),
248 2.0, 2.0,
249 DesktopRect::MakeXYWH(0, 0, 1, 1)},
250
251 {"Top right 0.5x",
252 DesktopRect::MakeXYWH(0, 0, 2, 2),
253 DesktopRect::MakeXYWH(2, -2, 2, 2),
254 0.5, 0.5,
255 DesktopRect::MakeXYWH(1, 0, 1, 1)},
256
257 {"Bottom right 2x",
258 DesktopRect::MakeXYWH(0, 0, 3, 3),
259 DesktopRect::MakeXYWH(-1, 1, 3, 3),
260 2.0, 2.0,
261 DesktopRect::MakeXYWH(0, 2, 1, 1)},
262
263 {"Bottom left 0.5x",
264 DesktopRect::MakeXYWH(0, 0, 2, 2),
265 DesktopRect::MakeXYWH(-2, 2, 2, 2),
266 0.5, 0.5,
267 DesktopRect::MakeXYWH(0, 1, 1, 1)}
268 };
269
270 RunTests(tests, arraysize(tests));
271 }
272
273
TEST(DesktopFrameTest,CopyIntersectingPixelsUncontainedRects)274 TEST(DesktopFrameTest, CopyIntersectingPixelsUncontainedRects) {
275 const TestData tests[] = {
276 {"Left",
277 DesktopRect::MakeXYWH(0, 0, 2, 2),
278 DesktopRect::MakeXYWH(-1, 0, 1, 2),
279 1.0, 1.0,
280 DesktopRect::MakeXYWH(0, 0, 0, 0)},
281
282 {"Top",
283 DesktopRect::MakeXYWH(0, 0, 2, 2),
284 DesktopRect::MakeXYWH(0, -1, 2, 1),
285 1.0, 1.0,
286 DesktopRect::MakeXYWH(0, 0, 0, 0)},
287
288 {"Right",
289 DesktopRect::MakeXYWH(0, 0, 2, 2),
290 DesktopRect::MakeXYWH(2, 0, 1, 2),
291 1.0, 1.0,
292 DesktopRect::MakeXYWH(0, 0, 0, 0)},
293
294
295 {"Bottom",
296 DesktopRect::MakeXYWH(0, 0, 2, 2),
297 DesktopRect::MakeXYWH(0, 2, 2, 1),
298 1.0, 1.0,
299 DesktopRect::MakeXYWH(0, 0, 0, 0)}
300 };
301
302 RunTests(tests, arraysize(tests));
303 }
304
TEST(DesktopFrameTest,CopyIntersectingPixelsUncontainedRectsScaled)305 TEST(DesktopFrameTest, CopyIntersectingPixelsUncontainedRectsScaled) {
306 const TestData tests[] = {
307 {"Left 2x",
308 DesktopRect::MakeXYWH(0, 0, 2, 2),
309 DesktopRect::MakeXYWH(-1, 0, 2, 2),
310 2.0, 2.0,
311 DesktopRect::MakeXYWH(0, 0, 0, 0)},
312
313 {"Top 0.5x",
314 DesktopRect::MakeXYWH(0, 0, 2, 2),
315 DesktopRect::MakeXYWH(0, -2, 2, 1),
316 0.5, 0.5,
317 DesktopRect::MakeXYWH(0, 0, 0, 0)},
318
319 {"Right 2x",
320 DesktopRect::MakeXYWH(0, 0, 2, 2),
321 DesktopRect::MakeXYWH(1, 0, 1, 2),
322 2.0, 2.0,
323 DesktopRect::MakeXYWH(0, 0, 0, 0)},
324
325
326 {"Bottom 0.5x",
327 DesktopRect::MakeXYWH(0, 0, 2, 2),
328 DesktopRect::MakeXYWH(0, 4, 2, 1),
329 0.5, 0.5,
330 DesktopRect::MakeXYWH(0, 0, 0, 0)}
331 };
332
333 RunTests(tests, arraysize(tests));
334 }
335
336 } // namespace webrtc
337