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