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