Bug 1539720 - Fix test_reftests_with_caret.html failures. r=emilio CLOSED TREE
[gecko.git] / image / test / gtest / TestADAM7InterpolatingFilter.cpp
blobb2ae6b5a581d9abc4724845477b334cac2caf348
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/. */
7 #include <algorithm>
8 #include <vector>
10 #include "gtest/gtest.h"
12 #include "mozilla/gfx/2D.h"
13 #include "mozilla/Maybe.h"
14 #include "Common.h"
15 #include "Decoder.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;
25 using std::generate;
26 using std::vector;
28 template <typename Func>
29 void WithADAM7InterpolatingFilter(const IntSize& aSize, Func aFunc) {
30 RefPtr<image::Decoder> decoder = CreateTrivialDecoder();
31 ASSERT_TRUE(bool(decoder));
33 WithFilterPipeline(
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,
52 float aWeight) {
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
76 // no effect.
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();
94 // Interpolate.
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,
106 2 / 8.0f, 1 / 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};
111 switch (aStride) {
112 case 8:
113 return stride8Weights;
114 case 4:
115 return stride4Weights;
116 case 2:
117 return stride2Weights;
118 case 1:
119 return stride1Weights;
120 default:
121 MOZ_CRASH();
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
150 * following pattern:
152 * 1 6 4 6 2 6 4 6
153 * 7 7 7 7 7 7 7 7
154 * 5 6 5 6 5 6 5 6
155 * 7 7 7 7 7 7 7 7
156 * 3 6 4 6 3 6 4 6
157 * 7 7 7 7 7 7 7 7
158 * 5 6 5 6 5 6 5 6
159 * 7 7 7 7 7 7 7 7
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
165 * are selected.
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) {
183 EXPECT_GT(aPass, 0);
184 EXPECT_LE(aPass, 8);
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.
193 uint32_t col = 0;
194 generate(result.begin(), result.end(), [&] {
195 return HorizontallyInterpolatedPixel(col++, aWidth, weights,
196 aShouldInterpolate, aColors);
198 } else {
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));
206 return result;
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) {
225 break;
229 return result;
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)) {
249 return false;
253 return true;
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
265 // data is written.
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*.
270 WriteState result =
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,
279 aColors));
281 // Prepare for the next pass.
282 aFilter->ResetToFirstRow();
287 BGRAColor ADAM7RowColor(int32_t aRow, uint8_t aPass,
288 const vector<BGRAColor>& aColors) {
289 EXPECT_LT(0, aPass);
290 EXPECT_GE(8, aPass);
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,
301 uint8_t aPass,
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.
309 result =
310 aFilter->WritePixelsToRow<uint32_t>([&] { return AsVariant(color); });
312 if (result != WriteState::NEED_MORE_DATA) {
313 break;
317 return result;
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
332 // with.
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
338 : prevImportantRow;
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)) {
364 return false;
368 return true;
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.
387 EXPECT_TRUE(
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.
470 CheckInterpolation(
471 IntSize(33, 17),
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)
487 CheckInterpolation(
488 IntSize(32, 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)
504 CheckInterpolation(
505 IntSize(31, 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(),
527 BGRAColor::Blue()});
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(),
538 BGRAColor::Blue()});
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(),
549 BGRAColor::Blue()});
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));