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/. */
10 #include "gtest/gtest.h"
12 #include "mozilla/gfx/2D.h"
13 #include "mozilla/Maybe.h"
16 #include "DecoderFactory.h"
17 #include "SourceBuffer.h"
18 #include "SurfaceFilters.h"
19 #include "SurfacePipe.h"
21 using namespace mozilla
;
22 using namespace mozilla::gfx
;
23 using namespace mozilla::image
;
28 template <typename Func
>
29 void WithADAM7InterpolatingFilter(const IntSize
& aSize
, Func aFunc
) {
30 RefPtr
<image::Decoder
> decoder
= CreateTrivialDecoder();
31 ASSERT_TRUE(bool(decoder
));
34 decoder
, std::forward
<Func
>(aFunc
), ADAM7InterpolatingConfig
{},
35 SurfaceConfig
{decoder
, aSize
, SurfaceFormat::OS_RGBA
, false});
38 void AssertConfiguringADAM7InterpolatingFilterFails(const IntSize
& aSize
) {
39 RefPtr
<image::Decoder
> decoder
= CreateTrivialDecoder();
40 ASSERT_TRUE(bool(decoder
));
42 AssertConfiguringPipelineFails(
43 decoder
, ADAM7InterpolatingConfig
{},
44 SurfaceConfig
{decoder
, aSize
, SurfaceFormat::OS_RGBA
, false});
47 uint8_t InterpolateByte(uint8_t aByteA
, uint8_t aByteB
, float aWeight
) {
48 return uint8_t(aByteA
* aWeight
+ aByteB
* (1.0f
- aWeight
));
51 BGRAColor
InterpolateColors(BGRAColor aColor1
, BGRAColor aColor2
,
53 return BGRAColor(InterpolateByte(aColor1
.mBlue
, aColor2
.mBlue
, aWeight
),
54 InterpolateByte(aColor1
.mGreen
, aColor2
.mGreen
, aWeight
),
55 InterpolateByte(aColor1
.mRed
, aColor2
.mRed
, aWeight
),
56 InterpolateByte(aColor1
.mAlpha
, aColor2
.mAlpha
, aWeight
));
59 enum class ShouldInterpolate
{ eYes
, eNo
};
61 BGRAColor
HorizontallyInterpolatedPixel(uint32_t aCol
, uint32_t aWidth
,
62 const vector
<float>& aWeights
,
63 ShouldInterpolate aShouldInterpolate
,
64 const vector
<BGRAColor
>& aColors
) {
65 // We cycle through the vector of weights forever.
66 float weight
= aWeights
[aCol
% aWeights
.size()];
68 // Find the columns of the two final pixels for this set of weights.
69 uint32_t finalPixel1
= aCol
- aCol
% aWeights
.size();
70 uint32_t finalPixel2
= finalPixel1
+ aWeights
.size();
72 // If |finalPixel2| is past the end of the row, that means that there is no
73 // final pixel after the pixel at |finalPixel1|. In that case, we just want to
74 // duplicate |finalPixel1|'s color until the end of the row. We can do that by
75 // setting |finalPixel2| equal to |finalPixel1| so that the interpolation has
77 if (finalPixel2
>= aWidth
) {
78 finalPixel2
= finalPixel1
;
81 // We cycle through the vector of colors forever (subject to the above
82 // constraint about the end of the row).
83 BGRAColor color1
= aColors
[finalPixel1
% aColors
.size()];
84 BGRAColor color2
= aColors
[finalPixel2
% aColors
.size()];
86 // If we're not interpolating, we treat all pixels which aren't final as
87 // transparent. Since the number of weights we have is equal to the stride
88 // between final pixels, we can check if |aCol| is a final pixel by checking
89 // whether |aCol| is a multiple of |aWeights.size()|.
90 if (aShouldInterpolate
== ShouldInterpolate::eNo
) {
91 return aCol
% aWeights
.size() == 0 ? color1
: BGRAColor::Transparent();
95 return InterpolateColors(color1
, color2
, weight
);
98 vector
<float>& InterpolationWeights(int32_t aStride
) {
99 // Precalculated interpolation weights. These are used to interpolate
100 // between final pixels or between important rows. Although no interpolation
101 // is actually applied to the previous final pixel or important row value,
102 // the arrays still start with 1.0f, which is always skipped, primarily
103 // because otherwise |stride1Weights| would have zero elements.
104 static vector
<float> stride8Weights
= {1.0f
, 7 / 8.0f
, 6 / 8.0f
,
105 5 / 8.0f
, 4 / 8.0f
, 3 / 8.0f
,
107 static vector
<float> stride4Weights
= {1.0f
, 3 / 4.0f
, 2 / 4.0f
, 1 / 4.0f
};
108 static vector
<float> stride2Weights
= {1.0f
, 1 / 2.0f
};
109 static vector
<float> stride1Weights
= {1.0f
};
113 return stride8Weights
;
115 return stride4Weights
;
117 return stride2Weights
;
119 return stride1Weights
;
125 int32_t ImportantRowStride(uint8_t aPass
) {
126 // The stride between important rows for each pass, with a dummy value for
127 // the nonexistent pass 0 and for pass 8, since the tests run an extra pass to
128 // make sure nothing breaks.
129 static int32_t strides
[] = {1, 8, 8, 4, 4, 2, 2, 1, 1};
131 return strides
[aPass
];
134 size_t FinalPixelStride(uint8_t aPass
) {
135 // The stride between the final pixels in important rows for each pass, with
136 // a dummy value for the nonexistent pass 0 and for pass 8, since the tests
137 // run an extra pass to make sure nothing breaks.
138 static size_t strides
[] = {1, 8, 4, 4, 2, 2, 1, 1, 1};
140 return strides
[aPass
];
143 bool IsImportantRow(int32_t aRow
, uint8_t aPass
) {
144 return aRow
% ImportantRowStride(aPass
) == 0;
148 * ADAM7 breaks up the image into 8x8 blocks. On each of the 7 passes, a new
149 * set of pixels in each block receives their final values, according to the
161 * This function produces a row of pixels @aWidth wide, suitable for testing
162 * horizontal interpolation on pass @aPass. The pattern of pixels used is
163 * determined by @aPass and @aRow, which determine which pixels are final
164 * according to the table above, and @aColors, from which the pixel values
167 * There are two different behaviors: if |eNo| is passed for
168 * @aShouldInterpolate, non-final pixels are treated as transparent. If |eNo|
169 * is passed, non-final pixels get interpolated in from the surrounding final
170 * pixels. The intention is that |eNo| is passed to generate input which will
171 * be run through ADAM7InterpolatingFilter, and |eYes| is passed to generate
172 * reference data to check that the filter is performing horizontal
173 * interpolation correctly.
175 * This function does not perform vertical interpolation. Rows which aren't on
176 * the current pass are filled with transparent pixels.
178 * @return a vector<BGRAColor> representing a row of pixels.
180 vector
<BGRAColor
> ADAM7HorizontallyInterpolatedRow(
181 uint8_t aPass
, uint32_t aRow
, uint32_t aWidth
,
182 ShouldInterpolate aShouldInterpolate
, const vector
<BGRAColor
>& aColors
) {
185 EXPECT_GT(aColors
.size(), 0u);
187 vector
<BGRAColor
> result(aWidth
);
189 if (IsImportantRow(aRow
, aPass
)) {
190 vector
<float>& weights
= InterpolationWeights(FinalPixelStride(aPass
));
192 // Compute the horizontally interpolated row.
194 generate(result
.begin(), result
.end(), [&] {
195 return HorizontallyInterpolatedPixel(col
++, aWidth
, weights
,
196 aShouldInterpolate
, aColors
);
199 // This is an unimportant row; just make the entire thing transparent.
200 generate(result
.begin(), result
.end(),
201 [] { return BGRAColor::Transparent(); });
204 EXPECT_EQ(result
.size(), size_t(aWidth
));
209 WriteState
WriteUninterpolatedPixels(SurfaceFilter
* aFilter
,
210 const IntSize
& aSize
, uint8_t aPass
,
211 const vector
<BGRAColor
>& aColors
) {
212 WriteState result
= WriteState::NEED_MORE_DATA
;
214 for (int32_t row
= 0; row
< aSize
.height
; ++row
) {
215 // Compute uninterpolated pixels for this row.
216 vector
<BGRAColor
> pixels
= ADAM7HorizontallyInterpolatedRow(
217 aPass
, row
, aSize
.width
, ShouldInterpolate::eNo
, aColors
);
219 // Write them to the surface.
220 auto pixelIterator
= pixels
.cbegin();
221 result
= aFilter
->WritePixelsToRow
<uint32_t>(
222 [&] { return AsVariant((*pixelIterator
++).AsPixel()); });
224 if (result
!= WriteState::NEED_MORE_DATA
) {
232 bool CheckHorizontallyInterpolatedImage(image::Decoder
* aDecoder
,
233 const IntSize
& aSize
, uint8_t aPass
,
234 const vector
<BGRAColor
>& aColors
) {
235 RawAccessFrameRef currentFrame
= aDecoder
->GetCurrentFrameRef();
236 RefPtr
<SourceSurface
> surface
= currentFrame
->GetSourceSurface();
238 for (int32_t row
= 0; row
< aSize
.height
; ++row
) {
239 if (!IsImportantRow(row
, aPass
)) {
240 continue; // Don't check rows which aren't important on this pass.
243 // Compute the expected pixels, *with* interpolation to match what the
244 // filter should have done.
245 vector
<BGRAColor
> expectedPixels
= ADAM7HorizontallyInterpolatedRow(
246 aPass
, row
, aSize
.width
, ShouldInterpolate::eYes
, aColors
);
248 if (!RowHasPixels(surface
, row
, expectedPixels
)) {
256 void CheckHorizontalInterpolation(const IntSize
& aSize
,
257 const vector
<BGRAColor
>& aColors
) {
258 const IntRect
surfaceRect(IntPoint(0, 0), aSize
);
260 WithADAM7InterpolatingFilter(
261 aSize
, [&](image::Decoder
* aDecoder
, SurfaceFilter
* aFilter
) {
262 // We check horizontal interpolation behavior for each pass
263 // individually. In addition to the normal 7 passes that ADAM7 includes,
264 // we also check an eighth pass to verify that nothing breaks if extra
266 for (uint8_t pass
= 1; pass
<= 8; ++pass
) {
267 // Write our color pattern to the surface. We don't perform any
268 // interpolation when writing to the filter so that we can check that
269 // the filter itself *does*.
271 WriteUninterpolatedPixels(aFilter
, aSize
, pass
, aColors
);
273 EXPECT_EQ(WriteState::FINISHED
, result
);
274 AssertCorrectPipelineFinalState(aFilter
, surfaceRect
, surfaceRect
);
276 // Check that the generated image matches the expected pattern, with
277 // interpolation applied.
278 EXPECT_TRUE(CheckHorizontallyInterpolatedImage(aDecoder
, aSize
, pass
,
281 // Prepare for the next pass.
282 aFilter
->ResetToFirstRow();
287 BGRAColor
ADAM7RowColor(int32_t aRow
, uint8_t aPass
,
288 const vector
<BGRAColor
>& aColors
) {
291 EXPECT_LT(0u, aColors
.size());
293 // If this is an important row, select the color from the provided vector of
294 // colors, which we cycle through infinitely. If not, just fill the row with
295 // transparent pixels.
296 return IsImportantRow(aRow
, aPass
) ? aColors
[aRow
% aColors
.size()]
297 : BGRAColor::Transparent();
300 WriteState
WriteRowColorPixels(SurfaceFilter
* aFilter
, const IntSize
& aSize
,
302 const vector
<BGRAColor
>& aColors
) {
303 WriteState result
= WriteState::NEED_MORE_DATA
;
305 for (int32_t row
= 0; row
< aSize
.height
; ++row
) {
306 const uint32_t color
= ADAM7RowColor(row
, aPass
, aColors
).AsPixel();
308 // Fill the surface with |color| pixels.
310 aFilter
->WritePixelsToRow
<uint32_t>([&] { return AsVariant(color
); });
312 if (result
!= WriteState::NEED_MORE_DATA
) {
320 bool CheckVerticallyInterpolatedImage(image::Decoder
* aDecoder
,
321 const IntSize
& aSize
, uint8_t aPass
,
322 const vector
<BGRAColor
>& aColors
) {
323 vector
<float>& weights
= InterpolationWeights(ImportantRowStride(aPass
));
325 for (int32_t row
= 0; row
< aSize
.height
; ++row
) {
326 // Vertically interpolation takes place between two important rows. The
327 // separation between the important rows is determined by the stride of this
328 // pass. When there is no "next" important row because we'd run off the
329 // bottom of the image, we use the same row for both. This matches
330 // ADAM7InterpolatingFilter's behavior of duplicating the last important row
331 // since there isn't another important row to vertically interpolate it
333 const int32_t stride
= ImportantRowStride(aPass
);
334 const int32_t prevImportantRow
= row
- row
% stride
;
335 const int32_t maybeNextImportantRow
= prevImportantRow
+ stride
;
336 const int32_t nextImportantRow
= maybeNextImportantRow
< aSize
.height
337 ? maybeNextImportantRow
340 // Retrieve the colors for the important rows we're going to interpolate.
341 const BGRAColor prevImportantRowColor
=
342 ADAM7RowColor(prevImportantRow
, aPass
, aColors
);
343 const BGRAColor nextImportantRowColor
=
344 ADAM7RowColor(nextImportantRow
, aPass
, aColors
);
346 // The weight we'll use for interpolation is also determined by the stride.
347 // A row halfway between two important rows should have pixels that have a
348 // 50% contribution from each of the important rows, for example.
349 const float weight
= weights
[row
% stride
];
350 const BGRAColor interpolatedColor
=
351 InterpolateColors(prevImportantRowColor
, nextImportantRowColor
, weight
);
353 // Generate a row of expected pixels. Every pixel in the row is always the
354 // same color since we're only testing vertical interpolation between
355 // solid-colored rows.
356 vector
<BGRAColor
> expectedPixels(aSize
.width
);
357 generate(expectedPixels
.begin(), expectedPixels
.end(),
358 [&] { return interpolatedColor
; });
360 // Check that the pixels match.
361 RawAccessFrameRef currentFrame
= aDecoder
->GetCurrentFrameRef();
362 RefPtr
<SourceSurface
> surface
= currentFrame
->GetSourceSurface();
363 if (!RowHasPixels(surface
, row
, expectedPixels
)) {
371 void CheckVerticalInterpolation(const IntSize
& aSize
,
372 const vector
<BGRAColor
>& aColors
) {
373 const IntRect
surfaceRect(IntPoint(0, 0), aSize
);
375 WithADAM7InterpolatingFilter(aSize
, [&](image::Decoder
* aDecoder
,
376 SurfaceFilter
* aFilter
) {
377 for (uint8_t pass
= 1; pass
<= 8; ++pass
) {
378 // Write a pattern of rows to the surface. Important rows will receive a
379 // color selected from |aColors|; unimportant rows will be transparent.
380 WriteState result
= WriteRowColorPixels(aFilter
, aSize
, pass
, aColors
);
382 EXPECT_EQ(WriteState::FINISHED
, result
);
383 AssertCorrectPipelineFinalState(aFilter
, surfaceRect
, surfaceRect
);
385 // Check that the generated image matches the expected pattern, with
386 // interpolation applied.
388 CheckVerticallyInterpolatedImage(aDecoder
, aSize
, pass
, aColors
));
390 // Prepare for the next pass.
391 aFilter
->ResetToFirstRow();
396 void CheckInterpolation(const IntSize
& aSize
,
397 const vector
<BGRAColor
>& aColors
) {
398 CheckHorizontalInterpolation(aSize
, aColors
);
399 CheckVerticalInterpolation(aSize
, aColors
);
402 void CheckADAM7InterpolatingWritePixels(const IntSize
& aSize
) {
403 // This test writes 8 passes of green pixels (the seven ADAM7 passes, plus one
404 // extra to make sure nothing goes wrong if we write too much input) and
405 // verifies that the output is a solid green surface each time. Because all
406 // the pixels are the same color, interpolation doesn't matter; we test the
407 // correctness of the interpolation algorithm itself separately.
408 WithADAM7InterpolatingFilter(
409 aSize
, [&](image::Decoder
* aDecoder
, SurfaceFilter
* aFilter
) {
410 IntRect
rect(IntPoint(0, 0), aSize
);
412 for (int32_t pass
= 1; pass
<= 8; ++pass
) {
413 // We only actually write up to the last important row for each pass,
414 // because that row unambiguously determines the remaining rows.
415 const int32_t lastRow
= aSize
.height
- 1;
416 const int32_t lastImportantRow
=
417 lastRow
- (lastRow
% ImportantRowStride(pass
));
418 const IntRect
inputWriteRect(0, 0, aSize
.width
, lastImportantRow
+ 1);
420 CheckWritePixels(aDecoder
, aFilter
,
421 /* aOutputRect = */ Some(rect
),
422 /* aInputRect = */ Some(rect
),
423 /* aInputWriteRect = */ Some(inputWriteRect
));
425 aFilter
->ResetToFirstRow();
426 EXPECT_FALSE(aFilter
->IsSurfaceFinished());
427 Maybe
<SurfaceInvalidRect
> invalidRect
= aFilter
->TakeInvalidRect();
428 EXPECT_TRUE(invalidRect
.isNothing());
433 TEST(ImageADAM7InterpolatingFilter
, WritePixels100_100
)
434 { CheckADAM7InterpolatingWritePixels(IntSize(100, 100)); }
436 TEST(ImageADAM7InterpolatingFilter
, WritePixels99_99
)
437 { CheckADAM7InterpolatingWritePixels(IntSize(99, 99)); }
439 TEST(ImageADAM7InterpolatingFilter
, WritePixels66_33
)
440 { CheckADAM7InterpolatingWritePixels(IntSize(66, 33)); }
442 TEST(ImageADAM7InterpolatingFilter
, WritePixels33_66
)
443 { CheckADAM7InterpolatingWritePixels(IntSize(33, 66)); }
445 TEST(ImageADAM7InterpolatingFilter
, WritePixels15_15
)
446 { CheckADAM7InterpolatingWritePixels(IntSize(15, 15)); }
448 TEST(ImageADAM7InterpolatingFilter
, WritePixels9_9
)
449 { CheckADAM7InterpolatingWritePixels(IntSize(9, 9)); }
451 TEST(ImageADAM7InterpolatingFilter
, WritePixels8_8
)
452 { CheckADAM7InterpolatingWritePixels(IntSize(8, 8)); }
454 TEST(ImageADAM7InterpolatingFilter
, WritePixels7_7
)
455 { CheckADAM7InterpolatingWritePixels(IntSize(7, 7)); }
457 TEST(ImageADAM7InterpolatingFilter
, WritePixels3_3
)
458 { CheckADAM7InterpolatingWritePixels(IntSize(3, 3)); }
460 TEST(ImageADAM7InterpolatingFilter
, WritePixels1_1
)
461 { CheckADAM7InterpolatingWritePixels(IntSize(1, 1)); }
463 TEST(ImageADAM7InterpolatingFilter
, TrivialInterpolation48_48
)
464 { CheckInterpolation(IntSize(48, 48), {BGRAColor::Green()}); }
466 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput33_17
)
468 // We check interpolation using irregular patterns to make sure that the
469 // interpolation will look different for different passes.
472 {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
473 BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Blue(),
474 BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Red(),
475 BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
476 BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
477 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
478 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
479 BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
480 BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
481 BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Blue(),
482 BGRAColor::Red(), BGRAColor::Blue()});
485 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput32_16
)
489 {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
490 BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Blue(),
491 BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Red(),
492 BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
493 BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
494 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
495 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
496 BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
497 BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
498 BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Blue(),
499 BGRAColor::Red(), BGRAColor::Blue()});
502 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput31_15
)
506 {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
507 BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Blue(),
508 BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Red(),
509 BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
510 BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
511 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
512 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
513 BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
514 BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
515 BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Blue(),
516 BGRAColor::Red(), BGRAColor::Blue()});
519 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput17_33
)
521 CheckInterpolation(IntSize(17, 33),
522 {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
523 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
524 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
525 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
526 BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(),
530 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput16_32
)
532 CheckInterpolation(IntSize(16, 32),
533 {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
534 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
535 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
536 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
537 BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(),
541 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput15_31
)
543 CheckInterpolation(IntSize(15, 31),
544 {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
545 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
546 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
547 BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
548 BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(),
552 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput9_9
)
554 CheckInterpolation(IntSize(9, 9),
555 {BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
556 BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Red(),
557 BGRAColor::Red(), BGRAColor::Blue()});
560 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput8_8
)
562 CheckInterpolation(IntSize(8, 8),
563 {BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
564 BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Red(),
565 BGRAColor::Red(), BGRAColor::Blue()});
568 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput7_7
)
570 CheckInterpolation(IntSize(7, 7),
571 {BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
572 BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Red(),
573 BGRAColor::Red(), BGRAColor::Blue()});
576 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput3_3
)
578 CheckInterpolation(IntSize(3, 3), {BGRAColor::Green(), BGRAColor::Red(),
579 BGRAColor::Blue(), BGRAColor::Red()});
582 TEST(ImageADAM7InterpolatingFilter
, InterpolationOutput1_1
)
583 { CheckInterpolation(IntSize(1, 1), {BGRAColor::Blue()}); }
585 TEST(ImageADAM7InterpolatingFilter
, ADAM7InterpolationFailsFor0_0
)
587 // A 0x0 input size is invalid, so configuration should fail.
588 AssertConfiguringADAM7InterpolatingFilterFails(IntSize(0, 0));
591 TEST(ImageADAM7InterpolatingFilter
, ADAM7InterpolationFailsForMinus1_Minus1
)
593 // A negative input size is invalid, so configuration should fail.
594 AssertConfiguringADAM7InterpolatingFilterFails(IntSize(-1, -1));