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