1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "gtest/gtest.h"
8
9 #include "mozilla/gfx/2D.h"
10 #include "Common.h"
11 #include "Decoder.h"
12 #include "DecoderFactory.h"
13 #include "SourceBuffer.h"
14 #include "SurfaceFilters.h"
15 #include "SurfacePipe.h"
16
17 using namespace mozilla;
18 using namespace mozilla::gfx;
19 using namespace mozilla::image;
20
21 template <typename Func>
WithDeinterlacingFilter(const IntSize & aSize,bool aProgressiveDisplay,Func aFunc)22 void WithDeinterlacingFilter(const IntSize& aSize, bool aProgressiveDisplay,
23 Func aFunc) {
24 RefPtr<image::Decoder> decoder = CreateTrivialDecoder();
25 ASSERT_TRUE(bool(decoder));
26
27 WithFilterPipeline(
28 decoder, std::forward<Func>(aFunc),
29 DeinterlacingConfig<uint32_t>{aProgressiveDisplay},
30 SurfaceConfig{decoder, aSize, SurfaceFormat::OS_RGBA, false});
31 }
32
AssertConfiguringDeinterlacingFilterFails(const IntSize & aSize)33 void AssertConfiguringDeinterlacingFilterFails(const IntSize& aSize) {
34 RefPtr<image::Decoder> decoder = CreateTrivialDecoder();
35 ASSERT_TRUE(decoder != nullptr);
36
37 AssertConfiguringPipelineFails(
38 decoder, DeinterlacingConfig<uint32_t>{/* mProgressiveDisplay = */ true},
39 SurfaceConfig{decoder, aSize, SurfaceFormat::OS_RGBA, false});
40 }
41
42 class ImageDeinterlacingFilter : public ::testing::Test {
43 protected:
44 AutoInitializeImageLib mInit;
45 };
46
TEST_F(ImageDeinterlacingFilter,WritePixels100_100)47 TEST_F(ImageDeinterlacingFilter, WritePixels100_100) {
48 WithDeinterlacingFilter(
49 IntSize(100, 100), /* aProgressiveDisplay = */ true,
50 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
51 CheckWritePixels(aDecoder, aFilter,
52 /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
53 /* aInputRect = */ Some(IntRect(0, 0, 100, 100)));
54 });
55 }
56
TEST_F(ImageDeinterlacingFilter,WritePixels99_99)57 TEST_F(ImageDeinterlacingFilter, WritePixels99_99) {
58 WithDeinterlacingFilter(IntSize(99, 99), /* aProgressiveDisplay = */ true,
59 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
60 CheckWritePixels(
61 aDecoder, aFilter,
62 /* aOutputRect = */ Some(IntRect(0, 0, 99, 99)),
63 /* aInputRect = */ Some(IntRect(0, 0, 99, 99)));
64 });
65 }
66
TEST_F(ImageDeinterlacingFilter,WritePixels8_8)67 TEST_F(ImageDeinterlacingFilter, WritePixels8_8) {
68 WithDeinterlacingFilter(IntSize(8, 8), /* aProgressiveDisplay = */ true,
69 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
70 CheckWritePixels(
71 aDecoder, aFilter,
72 /* aOutputRect = */ Some(IntRect(0, 0, 8, 8)),
73 /* aInputRect = */ Some(IntRect(0, 0, 8, 8)));
74 });
75 }
76
TEST_F(ImageDeinterlacingFilter,WritePixels7_7)77 TEST_F(ImageDeinterlacingFilter, WritePixels7_7) {
78 WithDeinterlacingFilter(IntSize(7, 7), /* aProgressiveDisplay = */ true,
79 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
80 CheckWritePixels(
81 aDecoder, aFilter,
82 /* aOutputRect = */ Some(IntRect(0, 0, 7, 7)),
83 /* aInputRect = */ Some(IntRect(0, 0, 7, 7)));
84 });
85 }
86
TEST_F(ImageDeinterlacingFilter,WritePixels3_3)87 TEST_F(ImageDeinterlacingFilter, WritePixels3_3) {
88 WithDeinterlacingFilter(IntSize(3, 3), /* aProgressiveDisplay = */ true,
89 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
90 CheckWritePixels(
91 aDecoder, aFilter,
92 /* aOutputRect = */ Some(IntRect(0, 0, 3, 3)),
93 /* aInputRect = */ Some(IntRect(0, 0, 3, 3)));
94 });
95 }
96
TEST_F(ImageDeinterlacingFilter,WritePixels1_1)97 TEST_F(ImageDeinterlacingFilter, WritePixels1_1) {
98 WithDeinterlacingFilter(IntSize(1, 1), /* aProgressiveDisplay = */ true,
99 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
100 CheckWritePixels(
101 aDecoder, aFilter,
102 /* aOutputRect = */ Some(IntRect(0, 0, 1, 1)),
103 /* aInputRect = */ Some(IntRect(0, 0, 1, 1)));
104 });
105 }
106
TEST_F(ImageDeinterlacingFilter,WritePixelsNonProgressiveOutput51_52)107 TEST_F(ImageDeinterlacingFilter, WritePixelsNonProgressiveOutput51_52) {
108 WithDeinterlacingFilter(
109 IntSize(51, 52), /* aProgressiveDisplay = */ false,
110 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
111 // Fill the image. The output should be green for even rows and red for
112 // odd rows but we need to write the rows in the order that the
113 // deinterlacer expects them.
114 uint32_t count = 0;
115 auto result = aFilter->WritePixels<uint32_t>([&]() {
116 uint32_t row = count / 51; // Integer division.
117 ++count;
118
119 // Note that we use a switch statement here, even though it's quite
120 // verbose, because it's useful to have the mappings between input and
121 // output rows available when debugging these tests.
122
123 switch (row) {
124 // First pass. Output rows are positioned at 8n + 0.
125 case 0: // Output row 0.
126 case 1: // Output row 8.
127 case 2: // Output row 16.
128 case 3: // Output row 24.
129 case 4: // Output row 32.
130 case 5: // Output row 40.
131 case 6: // Output row 48.
132 return AsVariant(BGRAColor::Green().AsPixel());
133
134 // Second pass. Rows are positioned at 8n + 4.
135 case 7: // Output row 4.
136 case 8: // Output row 12.
137 case 9: // Output row 20.
138 case 10: // Output row 28.
139 case 11: // Output row 36.
140 case 12: // Output row 44.
141 return AsVariant(BGRAColor::Green().AsPixel());
142
143 // Third pass. Rows are positioned at 4n + 2.
144 case 13: // Output row 2.
145 case 14: // Output row 6.
146 case 15: // Output row 10.
147 case 16: // Output row 14.
148 case 17: // Output row 18.
149 case 18: // Output row 22.
150 case 19: // Output row 26.
151 case 20: // Output row 30.
152 case 21: // Output row 34.
153 case 22: // Output row 38.
154 case 23: // Output row 42.
155 case 24: // Output row 46.
156 case 25: // Output row 50.
157 return AsVariant(BGRAColor::Green().AsPixel());
158
159 // Fourth pass. Rows are positioned at 2n + 1.
160 case 26: // Output row 1.
161 case 27: // Output row 3.
162 case 28: // Output row 5.
163 case 29: // Output row 7.
164 case 30: // Output row 9.
165 case 31: // Output row 11.
166 case 32: // Output row 13.
167 case 33: // Output row 15.
168 case 34: // Output row 17.
169 case 35: // Output row 19.
170 case 36: // Output row 21.
171 case 37: // Output row 23.
172 case 38: // Output row 25.
173 case 39: // Output row 27.
174 case 40: // Output row 29.
175 case 41: // Output row 31.
176 case 42: // Output row 33.
177 case 43: // Output row 35.
178 case 44: // Output row 37.
179 case 45: // Output row 39.
180 case 46: // Output row 41.
181 case 47: // Output row 43.
182 case 48: // Output row 45.
183 case 49: // Output row 47.
184 case 50: // Output row 49.
185 case 51: // Output row 51.
186 return AsVariant(BGRAColor::Red().AsPixel());
187
188 default:
189 MOZ_ASSERT_UNREACHABLE("Unexpected row");
190 return AsVariant(BGRAColor::Transparent().AsPixel());
191 }
192 });
193 EXPECT_EQ(WriteState::FINISHED, result);
194 EXPECT_EQ(51u * 52u, count);
195
196 AssertCorrectPipelineFinalState(aFilter, IntRect(0, 0, 51, 52),
197 IntRect(0, 0, 51, 52));
198
199 // Check that the generated image is correct. As mentioned above, we
200 // expect even rows to be green and odd rows to be red.
201 RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
202 RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
203
204 for (uint32_t row = 0; row < 52; ++row) {
205 EXPECT_TRUE(RowsAreSolidColor(
206 surface, row, 1,
207 row % 2 == 0 ? BGRAColor::Green() : BGRAColor::Red()));
208 }
209 });
210 }
211
TEST_F(ImageDeinterlacingFilter,WritePixelsOutput20_20)212 TEST_F(ImageDeinterlacingFilter, WritePixelsOutput20_20) {
213 WithDeinterlacingFilter(
214 IntSize(20, 20), /* aProgressiveDisplay = */ true,
215 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
216 // Fill the image. The output should be green for even rows and red for
217 // odd rows but we need to write the rows in the order that the
218 // deinterlacer expects them.
219 uint32_t count = 0;
220 auto result = aFilter->WritePixels<uint32_t>([&]() {
221 uint32_t row = count / 20; // Integer division.
222 ++count;
223
224 // Note that we use a switch statement here, even though it's quite
225 // verbose, because it's useful to have the mappings between input and
226 // output rows available when debugging these tests.
227
228 switch (row) {
229 // First pass. Output rows are positioned at 8n + 0.
230 case 0: // Output row 0.
231 case 1: // Output row 8.
232 case 2: // Output row 16.
233 return AsVariant(BGRAColor::Green().AsPixel());
234
235 // Second pass. Rows are positioned at 8n + 4.
236 case 3: // Output row 4.
237 case 4: // Output row 12.
238 return AsVariant(BGRAColor::Green().AsPixel());
239
240 // Third pass. Rows are positioned at 4n + 2.
241 case 5: // Output row 2.
242 case 6: // Output row 6.
243 case 7: // Output row 10.
244 case 8: // Output row 14.
245 case 9: // Output row 18.
246 return AsVariant(BGRAColor::Green().AsPixel());
247
248 // Fourth pass. Rows are positioned at 2n + 1.
249 case 10: // Output row 1.
250 case 11: // Output row 3.
251 case 12: // Output row 5.
252 case 13: // Output row 7.
253 case 14: // Output row 9.
254 case 15: // Output row 11.
255 case 16: // Output row 13.
256 case 17: // Output row 15.
257 case 18: // Output row 17.
258 case 19: // Output row 19.
259 return AsVariant(BGRAColor::Red().AsPixel());
260
261 default:
262 MOZ_ASSERT_UNREACHABLE("Unexpected row");
263 return AsVariant(BGRAColor::Transparent().AsPixel());
264 }
265 });
266 EXPECT_EQ(WriteState::FINISHED, result);
267 EXPECT_EQ(20u * 20u, count);
268
269 AssertCorrectPipelineFinalState(aFilter, IntRect(0, 0, 20, 20),
270 IntRect(0, 0, 20, 20));
271
272 // Check that the generated image is correct. As mentioned above, we
273 // expect even rows to be green and odd rows to be red.
274 RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
275 RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
276
277 for (uint32_t row = 0; row < 20; ++row) {
278 EXPECT_TRUE(RowsAreSolidColor(
279 surface, row, 1,
280 row % 2 == 0 ? BGRAColor::Green() : BGRAColor::Red()));
281 }
282 });
283 }
284
TEST_F(ImageDeinterlacingFilter,WritePixelsOutput7_7)285 TEST_F(ImageDeinterlacingFilter, WritePixelsOutput7_7) {
286 WithDeinterlacingFilter(
287 IntSize(7, 7), /* aProgressiveDisplay = */ true,
288 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
289 // Fill the image. The output should be a repeating pattern of two green
290 // rows followed by two red rows but we need to write the rows in the
291 // order that the deinterlacer expects them.
292 uint32_t count = 0;
293 auto result = aFilter->WritePixels<uint32_t>([&]() {
294 uint32_t row = count / 7; // Integer division.
295 ++count;
296
297 switch (row) {
298 // First pass. Output rows are positioned at 8n + 0.
299 case 0: // Output row 0.
300 return AsVariant(BGRAColor::Green().AsPixel());
301
302 // Second pass. Rows are positioned at 8n + 4.
303 case 1: // Output row 4.
304 return AsVariant(BGRAColor::Green().AsPixel());
305
306 // Third pass. Rows are positioned at 4n + 2.
307 case 2: // Output row 2.
308 case 3: // Output row 6.
309 return AsVariant(BGRAColor::Red().AsPixel());
310
311 // Fourth pass. Rows are positioned at 2n + 1.
312 case 4: // Output row 1.
313 return AsVariant(BGRAColor::Green().AsPixel());
314
315 case 5: // Output row 3.
316 return AsVariant(BGRAColor::Red().AsPixel());
317
318 case 6: // Output row 5.
319 return AsVariant(BGRAColor::Green().AsPixel());
320
321 default:
322 MOZ_ASSERT_UNREACHABLE("Unexpected row");
323 return AsVariant(BGRAColor::Transparent().AsPixel());
324 }
325 });
326 EXPECT_EQ(WriteState::FINISHED, result);
327 EXPECT_EQ(7u * 7u, count);
328
329 AssertCorrectPipelineFinalState(aFilter, IntRect(0, 0, 7, 7),
330 IntRect(0, 0, 7, 7));
331
332 // Check that the generated image is correct. As mentioned above, we
333 // expect two green rows, followed by two red rows, then two green rows,
334 // etc.
335 RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
336 RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
337
338 for (uint32_t row = 0; row < 7; ++row) {
339 BGRAColor color = row == 0 || row == 1 || row == 4 || row == 5
340 ? BGRAColor::Green()
341 : BGRAColor::Red();
342 EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, color));
343 }
344 });
345 }
346
TEST_F(ImageDeinterlacingFilter,WritePixelsOutput3_3)347 TEST_F(ImageDeinterlacingFilter, WritePixelsOutput3_3) {
348 WithDeinterlacingFilter(
349 IntSize(3, 3), /* aProgressiveDisplay = */ true,
350 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
351 // Fill the image. The output should be green, red, green in that order,
352 // but we need to write the rows in the order that the deinterlacer
353 // expects them.
354 uint32_t count = 0;
355 auto result = aFilter->WritePixels<uint32_t>([&]() {
356 uint32_t row = count / 3; // Integer division.
357 ++count;
358
359 switch (row) {
360 // First pass. Output rows are positioned at 8n + 0.
361 case 0: // Output row 0.
362 return AsVariant(BGRAColor::Green().AsPixel());
363
364 // Second pass. Rows are positioned at 8n + 4.
365 // No rows for this pass.
366
367 // Third pass. Rows are positioned at 4n + 2.
368 case 1: // Output row 2.
369 return AsVariant(BGRAColor::Green().AsPixel());
370
371 // Fourth pass. Rows are positioned at 2n + 1.
372 case 2: // Output row 1.
373 return AsVariant(BGRAColor::Red().AsPixel());
374
375 default:
376 MOZ_ASSERT_UNREACHABLE("Unexpected row");
377 return AsVariant(BGRAColor::Transparent().AsPixel());
378 }
379 });
380 EXPECT_EQ(WriteState::FINISHED, result);
381 EXPECT_EQ(3u * 3u, count);
382
383 AssertCorrectPipelineFinalState(aFilter, IntRect(0, 0, 3, 3),
384 IntRect(0, 0, 3, 3));
385
386 // Check that the generated image is correct. As mentioned above, we
387 // expect green, red, green in that order.
388 RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
389 RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
390
391 for (uint32_t row = 0; row < 3; ++row) {
392 EXPECT_TRUE(RowsAreSolidColor(
393 surface, row, 1,
394 row == 0 || row == 2 ? BGRAColor::Green() : BGRAColor::Red()));
395 }
396 });
397 }
398
TEST_F(ImageDeinterlacingFilter,WritePixelsOutput1_1)399 TEST_F(ImageDeinterlacingFilter, WritePixelsOutput1_1) {
400 WithDeinterlacingFilter(
401 IntSize(1, 1), /* aProgressiveDisplay = */ true,
402 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
403 // Fill the image. The output should be a single red row.
404 uint32_t count = 0;
405 auto result = aFilter->WritePixels<uint32_t>([&]() {
406 ++count;
407 return AsVariant(BGRAColor::Red().AsPixel());
408 });
409 EXPECT_EQ(WriteState::FINISHED, result);
410 EXPECT_EQ(1u, count);
411
412 AssertCorrectPipelineFinalState(aFilter, IntRect(0, 0, 1, 1),
413 IntRect(0, 0, 1, 1));
414
415 // Check that the generated image is correct. As mentioned above, we
416 // expect a single red row.
417 RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
418 RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
419
420 EXPECT_TRUE(RowsAreSolidColor(surface, 0, 1, BGRAColor::Red()));
421 });
422 }
423
WriteRowAndCheckInterlacerOutput(image::Decoder * aDecoder,SurfaceFilter * aFilter,BGRAColor aColor,WriteState aNextState,IntRect aInvalidRect,uint32_t aFirstHaeberliRow,uint32_t aLastHaeberliRow)424 void WriteRowAndCheckInterlacerOutput(image::Decoder* aDecoder,
425 SurfaceFilter* aFilter, BGRAColor aColor,
426 WriteState aNextState,
427 IntRect aInvalidRect,
428 uint32_t aFirstHaeberliRow,
429 uint32_t aLastHaeberliRow) {
430 uint32_t count = 0;
431
432 auto result = aFilter->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
433 if (count < 7) {
434 ++count;
435 return AsVariant(aColor.AsPixel());
436 }
437 return AsVariant(WriteState::NEED_MORE_DATA);
438 });
439
440 EXPECT_EQ(aNextState, result);
441 EXPECT_EQ(7u, count);
442
443 // Assert that we got the expected invalidation region.
444 Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
445 EXPECT_TRUE(invalidRect.isSome());
446 EXPECT_EQ(aInvalidRect, invalidRect->mInputSpaceRect);
447 EXPECT_EQ(aInvalidRect, invalidRect->mOutputSpaceRect);
448
449 // Check that the portion of the image generated so far is correct. The rows
450 // from aFirstHaeberliRow to aLastHaeberliRow should be filled with aColor.
451 // Note that this is not the same as the set of rows in aInvalidRect, because
452 // after writing a row the deinterlacer seeks to the next row to write, which
453 // may involve copying previously-written rows in the buffer to the output
454 // even though they don't change in this pass.
455 RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
456 RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
457
458 for (uint32_t row = aFirstHaeberliRow; row <= aLastHaeberliRow; ++row) {
459 EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, aColor));
460 }
461 }
462
TEST_F(ImageDeinterlacingFilter,WritePixelsIntermediateOutput7_7)463 TEST_F(ImageDeinterlacingFilter, WritePixelsIntermediateOutput7_7) {
464 WithDeinterlacingFilter(
465 IntSize(7, 7), /* aProgressiveDisplay = */ true,
466 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
467 // Fill the image. The output should be a repeating pattern of two green
468 // rows followed by two red rows but we need to write the rows in the
469 // order that the deinterlacer expects them.
470
471 // First pass. Output rows are positioned at 8n + 0.
472
473 // Output row 0. The invalid rect is the entire image because this is
474 // the end of the first pass.
475 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
476 WriteState::NEED_MORE_DATA,
477 IntRect(0, 0, 7, 7), 0, 4);
478
479 // Second pass. Rows are positioned at 8n + 4.
480
481 // Output row 4. The invalid rect is the entire image because this is
482 // the end of the second pass.
483 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
484 WriteState::NEED_MORE_DATA,
485 IntRect(0, 0, 7, 7), 1, 4);
486
487 // Third pass. Rows are positioned at 4n + 2.
488
489 // Output row 2. The invalid rect contains the Haeberli rows for this
490 // output row (rows 2 and 3) as well as the rows that we copy from
491 // previous passes when seeking to the next output row (rows 4 and 5).
492 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
493 WriteState::NEED_MORE_DATA,
494 IntRect(0, 2, 7, 4), 2, 3);
495
496 // Output row 6. The invalid rect is the entire image because this is
497 // the end of the third pass.
498 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
499 WriteState::NEED_MORE_DATA,
500 IntRect(0, 0, 7, 7), 6, 6);
501
502 // Fourth pass. Rows are positioned at 2n + 1.
503
504 // Output row 1. The invalid rect contains the Haeberli rows for this
505 // output row (just row 1) as well as the rows that we copy from
506 // previous passes when seeking to the next output row (row 2).
507 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
508 WriteState::NEED_MORE_DATA,
509 IntRect(0, 1, 7, 2), 1, 1);
510
511 // Output row 3. The invalid rect contains the Haeberli rows for this
512 // output row (just row 3) as well as the rows that we copy from
513 // previous passes when seeking to the next output row (row 4).
514 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
515 WriteState::NEED_MORE_DATA,
516 IntRect(0, 3, 7, 2), 3, 3);
517
518 // Output row 5. The invalid rect contains the Haeberli rows for this
519 // output row (just row 5) as well as the rows that we copy from
520 // previous passes when seeking to the next output row (row 6).
521 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
522 WriteState::FINISHED,
523 IntRect(0, 5, 7, 2), 5, 5);
524
525 // Assert that we're in the expected final state.
526 EXPECT_TRUE(aFilter->IsSurfaceFinished());
527 Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
528 EXPECT_TRUE(invalidRect.isNothing());
529
530 // Check that the generated image is correct. As mentioned above, we
531 // expect two green rows, followed by two red rows, then two green rows,
532 // etc.
533 RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
534 RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
535
536 for (uint32_t row = 0; row < 7; ++row) {
537 BGRAColor color = row == 0 || row == 1 || row == 4 || row == 5
538 ? BGRAColor::Green()
539 : BGRAColor::Red();
540 EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, color));
541 }
542 });
543 }
544
TEST_F(ImageDeinterlacingFilter,WritePixelsNonProgressiveIntermediateOutput7_7)545 TEST_F(ImageDeinterlacingFilter,
546 WritePixelsNonProgressiveIntermediateOutput7_7) {
547 WithDeinterlacingFilter(
548 IntSize(7, 7), /* aProgressiveDisplay = */ false,
549 [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
550 // Fill the image. The output should be a repeating pattern of two green
551 // rows followed by two red rows but we need to write the rows in the
552 // order that the deinterlacer expects them.
553
554 // First pass. Output rows are positioned at 8n + 0.
555
556 // Output row 0. The invalid rect is the entire image because this is
557 // the end of the first pass.
558 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
559 WriteState::NEED_MORE_DATA,
560 IntRect(0, 0, 7, 7), 0, 0);
561
562 // Second pass. Rows are positioned at 8n + 4.
563
564 // Output row 4. The invalid rect is the entire image because this is
565 // the end of the second pass.
566 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
567 WriteState::NEED_MORE_DATA,
568 IntRect(0, 0, 7, 7), 4, 4);
569
570 // Third pass. Rows are positioned at 4n + 2.
571
572 // Output row 2. The invalid rect contains the Haeberli rows for this
573 // output row (rows 2 and 3) as well as the rows that we copy from
574 // previous passes when seeking to the next output row (rows 4 and 5).
575 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
576 WriteState::NEED_MORE_DATA,
577 IntRect(0, 2, 7, 4), 2, 2);
578
579 // Output row 6. The invalid rect is the entire image because this is
580 // the end of the third pass.
581 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
582 WriteState::NEED_MORE_DATA,
583 IntRect(0, 0, 7, 7), 6, 6);
584
585 // Fourth pass. Rows are positioned at 2n + 1.
586
587 // Output row 1. The invalid rect contains the Haeberli rows for this
588 // output row (just row 1) as well as the rows that we copy from
589 // previous passes when seeking to the next output row (row 2).
590 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
591 WriteState::NEED_MORE_DATA,
592 IntRect(0, 1, 7, 2), 1, 1);
593
594 // Output row 3. The invalid rect contains the Haeberli rows for this
595 // output row (just row 3) as well as the rows that we copy from
596 // previous passes when seeking to the next output row (row 4).
597 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
598 WriteState::NEED_MORE_DATA,
599 IntRect(0, 3, 7, 2), 3, 3);
600
601 // Output row 5. The invalid rect contains the Haeberli rows for this
602 // output row (just row 5) as well as the rows that we copy from
603 // previous passes when seeking to the next output row (row 6).
604 WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
605 WriteState::FINISHED,
606 IntRect(0, 5, 7, 2), 5, 5);
607
608 // Assert that we're in the expected final state.
609 EXPECT_TRUE(aFilter->IsSurfaceFinished());
610 Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
611 EXPECT_TRUE(invalidRect.isNothing());
612
613 // Check that the generated image is correct. As mentioned above, we
614 // expect two green rows, followed by two red rows, then two green rows,
615 // etc.
616 RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
617 RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
618
619 for (uint32_t row = 0; row < 7; ++row) {
620 BGRAColor color = row == 0 || row == 1 || row == 4 || row == 5
621 ? BGRAColor::Green()
622 : BGRAColor::Red();
623 EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, color));
624 }
625 });
626 }
627
TEST_F(ImageDeinterlacingFilter,DeinterlacingFailsFor0_0)628 TEST_F(ImageDeinterlacingFilter, DeinterlacingFailsFor0_0) {
629 // A 0x0 input size is invalid, so configuration should fail.
630 AssertConfiguringDeinterlacingFilterFails(IntSize(0, 0));
631 }
632
TEST_F(ImageDeinterlacingFilter,DeinterlacingFailsForMinus1_Minus1)633 TEST_F(ImageDeinterlacingFilter, DeinterlacingFailsForMinus1_Minus1) {
634 // A negative input size is invalid, so configuration should fail.
635 AssertConfiguringDeinterlacingFilterFails(IntSize(-1, -1));
636 }
637