[dali_2.3.27] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / automated-tests / src / dali-adaptor-internal / utc-Dali-ImageOperations.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <dali-test-suite-utils.h>
19 #include <dali/devel-api/common/ref-counted-dali-vector.h>
20 #include <dali/internal/imaging/common/image-operations.h>
21
22 #include <sys/mman.h>
23 #include <unistd.h>
24
25 using namespace Dali::Internal::Platform;
26
27 namespace
28 {
29 /**
30  * @brief Generate a random integer between zero and the parameter passed in.
31  **/
32 uint32_t RandomInRange(uint32_t max)
33 {
34   const uint32_t randToMax = lrand48() % (max + 1);
35   return randToMax;
36 }
37
38 /**
39  * @brief Random number representable in an 8 bit color component.
40  */
41 inline uint32_t RandomComponent8()
42 {
43   return RandomInRange(255u);
44 }
45
46 /**
47  * @brief Random number representable in a 5 bit color component.
48  */
49 inline uint32_t RandomComponent5()
50 {
51   return RandomInRange(31u);
52 }
53
54 /**
55  * @brief Random number representable in a 6 bit color component.
56  */
57 inline uint32_t RandomComponent6()
58 {
59   return RandomInRange(63u);
60 }
61
62 /**
63  * @brief RGBA8888 Pixels from separate color components.
64  */
65 inline uint32_t PixelRGBA8888(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
66 {
67   return (r << 24) + (g << 16) + (b << 8) + a;
68 }
69
70 /**
71  * @brief RGB565 Pixels from color components in the low bits of passed-in words.
72  */
73 inline uint16_t PixelRGB565(uint32_t r, uint32_t g, uint32_t b)
74 {
75   return (r << 11) + (g << 5) + b;
76 }
77
78 /**
79  * @brief RGBA8888 Pixels with random color components.
80  */
81 inline uint32_t RandomPixelRGBA8888()
82 {
83   const uint32_t randomPixel = PixelRGBA8888(RandomComponent8(), RandomComponent8(), RandomComponent8(), RandomComponent8());
84   return randomPixel;
85 }
86
87 /**
88  * @brief Return a hash over a set of pixels.
89  *
90  * Used to check a buffer of pixels is unmodified by an operation given inputs
91  * that should mean that it is not changed.
92  */
93 inline uint32_t HashPixels(const uint32_t* const pixels, unsigned int numPixels)
94 {
95   uint32_t hash = 5381;
96
97   for(unsigned int i = 0; i < numPixels; ++i)
98   {
99     hash = hash * 33 + pixels[i];
100   }
101
102   return hash;
103 }
104
105 /**
106  * @brief Build some dummy scanlines to exercise scanline averaging code on.
107  */
108 void SetupScanlineForHalvingTestsRGBA8888(size_t scanlineLength, Dali::Vector<uint32_t>& scanline, Dali::Vector<uint32_t>& reference)
109 {
110   scanline.Resize(scanlineLength);
111   reference.Resize(scanlineLength / 2 + 32);
112
113   // Prepare some random pixels:
114   srand(19 * 23 * 47 * 53);
115   for(size_t i = 0; i < scanlineLength / 2; ++i)
116   {
117     // Generate random colors:
118     const uint32_t red1   = RandomComponent8();
119     const uint32_t red2   = RandomComponent8();
120     const uint32_t green1 = RandomComponent8();
121     const uint32_t green2 = RandomComponent8();
122     const uint32_t blue1  = RandomComponent8();
123     const uint32_t blue2  = RandomComponent8();
124     const uint32_t alpha1 = RandomComponent8();
125     const uint32_t alpha2 = RandomComponent8();
126
127     // The average of these pixels should equal the reference:
128     scanline[i * 2]     = PixelRGBA8888(red1, green1, blue1, alpha1);
129     scanline[i * 2 + 1] = PixelRGBA8888(red2, green2, blue2, alpha2);
130
131     // Average the two pixels manually as a reference:
132     reference[i] = (PixelRGBA8888((red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u, (alpha1 + alpha2) >> 1u));
133   }
134
135   for(size_t i = scanlineLength / 2; i < reference.Count(); ++i)
136   {
137     reference[i] = 0xEEEEEEEE;
138   }
139 }
140
141 /**
142  * @brief Build some dummy scanlines to exercise scanline averaging code on.
143  */
144 void SetupScanlineForHalvingTestsRGB565(size_t scanlineLength, Dali::Vector<uint16_t>& scanline, Dali::Vector<uint16_t>& reference)
145 {
146   scanline.Resize(scanlineLength);
147   reference.Resize(scanlineLength / 2 + 32);
148
149   // Prepare some random pixels:
150   srand48(19 * 23 * 47 * 53);
151   for(size_t i = 0; i < scanlineLength / 2; ++i)
152   {
153     // Generate random colors:
154     const uint32_t red1   = RandomComponent5();
155     const uint32_t red2   = RandomComponent5();
156     const uint32_t green1 = RandomComponent6();
157     const uint32_t green2 = RandomComponent6();
158     const uint32_t blue1  = RandomComponent5();
159     const uint32_t blue2  = RandomComponent5();
160
161     // The average of these pixels should equal the reference:
162     scanline[i * 2]     = PixelRGB565(red1, green1, blue1);
163     scanline[i * 2 + 1] = PixelRGB565(red2, green2, blue2);
164
165     // Average the two pixels manually as a reference:
166     reference[i] = (PixelRGB565((red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u));
167   }
168
169   for(size_t i = scanlineLength / 2; i < reference.Count(); ++i)
170   {
171     reference[i] = 0xEEEE;
172   }
173 }
174
175 /**
176  * @brief Build some dummy scanlines to exercise scanline averaging code on.
177  */
178 void SetupScanlineForHalvingTests2Bytes(size_t scanlineLength, Dali::Vector<uint8_t>& scanline, Dali::Vector<uint8_t>& reference)
179 {
180   scanline.Resize(scanlineLength * 2);
181   reference.Resize(scanlineLength + 32);
182
183   // Prepare some random pixels:
184   srand48(19 * 23 * 47 * 53 * 59);
185   for(size_t i = 0; i < scanlineLength / 2; ++i)
186   {
187     // Generate random colors:
188     const uint32_t c11 = RandomComponent8();
189     const uint32_t c12 = RandomComponent8();
190     const uint32_t c21 = RandomComponent8();
191     const uint32_t c22 = RandomComponent8();
192
193     // The average of these pixels should equal the reference:
194     scanline[i * 4]     = c11;
195     scanline[i * 4 + 1] = c12;
196     scanline[i * 4 + 2] = c21;
197     scanline[i * 4 + 3] = c22;
198
199     // Average the two pixels manually as a reference:
200     reference[i * 2]     = ((c11 + c21) >> 1u);
201     reference[i * 2 + 1] = ((c12 + c22) >> 1u);
202   }
203
204   for(size_t i = scanlineLength; i < reference.Count(); ++i)
205   {
206     reference[i] = 0xEE;
207   }
208 }
209
210 /**
211  * @brief Build some dummy 1 byte per pixel scanlines to exercise scanline averaging code on.
212  */
213 void SetupScanlineForHalvingTests1Byte(size_t scanlineLength, Dali::Vector<uint8_t>& scanline, Dali::Vector<uint8_t>& reference)
214 {
215   scanline.Resize(scanlineLength);
216   reference.Resize(scanlineLength / 2 + 32);
217
218   // Prepare some random pixels:
219   srand48(19 * 23 * 47 * 53 * 63);
220   for(size_t i = 0; i < scanlineLength / 2; ++i)
221   {
222     // Generate random colors:
223     const uint32_t c1 = RandomComponent8();
224     const uint32_t c2 = RandomComponent8();
225
226     // The average of these pixels should equal the reference:
227     scanline[i * 2]     = c1;
228     scanline[i * 2 + 1] = c2;
229
230     // Average the two pixels manually as a reference:
231     reference[i] = ((c1 + c2) >> 1u);
232   }
233
234   for(size_t i = scanlineLength / 2; i < reference.Count(); ++i)
235   {
236     reference[i] = 0xEE;
237   }
238 }
239
240 /**
241  * @brief Build some dummy scanlines to exercise vertical averaging code on.
242  *
243  * All tested formats bar RGB565 can share this setup.
244  */
245 void SetupScanlinesRGBA8888(size_t scanlineLength, Dali::Vector<uint32_t>& scanline1, Dali::Vector<uint32_t>& scanline2, Dali::Vector<uint32_t>& reference, Dali::Vector<uint32_t>& output)
246 {
247   scanline1.Resize(scanlineLength);
248   scanline2.Resize(scanlineLength);
249   reference.Resize(scanlineLength + 32);
250   output.Resize(scanlineLength + 32);
251
252   for(size_t i = scanlineLength; i < output.Count(); ++i)
253   {
254     output[i]    = 0xDEADBEEF;
255     reference[i] = 0xDEADBEEF;
256   }
257
258   // Prepare some random pixels:
259   srand48(19 * 23 * 47);
260   for(size_t i = 0; i < scanlineLength; ++i)
261   {
262     // Generate random colors:
263     const uint32_t red1   = RandomComponent8();
264     const uint32_t red2   = RandomComponent8();
265     const uint32_t green1 = RandomComponent8();
266     const uint32_t green2 = RandomComponent8();
267     const uint32_t blue1  = RandomComponent8();
268     const uint32_t blue2  = RandomComponent8();
269     const uint32_t alpha1 = RandomComponent8();
270     const uint32_t alpha2 = RandomComponent8();
271
272     // The average of these pixels should equal the reference:
273     scanline1[i] = (PixelRGBA8888(red1, green1, blue1, alpha1));
274     scanline2[i] = (PixelRGBA8888(red2, green2, blue2, alpha2));
275
276     // Average the two pixels manually as a reference:
277     reference[i] = (PixelRGBA8888((red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u, (alpha1 + alpha2) >> 1u));
278   }
279 }
280
281 /**
282  * @brief Compares a scanline of interest to a reference, testing each pixel is the same.
283  */
284 void MatchScanlinesRGBA8888(Dali::Vector<uint32_t>& reference, Dali::Vector<uint32_t>& output, size_t& numMatches, const char* const location)
285 {
286   numMatches = 0;
287   for(size_t i = 0, length = reference.Count(); i < length; ++i)
288   {
289     DALI_TEST_EQUALS(output[i], reference[i], location);
290     numMatches += output[i] == reference[i];
291   }
292 }
293
294 } // namespace
295
296 /**
297  * @brief Test component averaging code.
298  */
299 int UtcDaliImageOperationsAverageComponent(void)
300 {
301   DALI_TEST_EQUALS(Dali::Internal::Platform::AverageComponent(0u, 0u), 0u, TEST_LOCATION);
302   DALI_TEST_EQUALS(Dali::Internal::Platform::AverageComponent(1u, 1u), 1u, TEST_LOCATION);
303   DALI_TEST_EQUALS(Dali::Internal::Platform::AverageComponent(0xffffffffu >> 1u, 0xffffffffu >> 1u), 0xffffffffu >> 1u, TEST_LOCATION);
304   const unsigned int avg3 = Dali::Internal::Platform::AverageComponent(0xfffffffeu, 1u);
305   DALI_TEST_EQUALS(avg3, 0x7fffffffu, TEST_LOCATION);
306   DALI_TEST_EQUALS(Dali::Internal::Platform::AverageComponent(255u, 255u), 255u, TEST_LOCATION);
307   DALI_TEST_EQUALS(Dali::Internal::Platform::AverageComponent(512u, 0u), 256u, TEST_LOCATION);
308   DALI_TEST_EQUALS(Dali::Internal::Platform::AverageComponent(511u, 0u), 255u, TEST_LOCATION);
309   DALI_TEST_EQUALS(Dali::Internal::Platform::AverageComponent(510u, 0u), 255u, TEST_LOCATION);
310   DALI_TEST_EQUALS(Dali::Internal::Platform::AverageComponent(509u, 0u), 254u, TEST_LOCATION);
311   DALI_TEST_EQUALS(Dali::Internal::Platform::AverageComponent(0u, 509u), 254u, TEST_LOCATION);
312   END_TEST;
313 }
314
315 /**
316  * @brief Test Pixel averaging code.
317  */
318 int UtcDaliImageOperationsAveragePixelRGBA8888(void)
319 {
320   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGBA8888(0u, 0u), 0u, TEST_LOCATION);
321   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGBA8888(0x01010101, 0x01010101), 0x01010101u, TEST_LOCATION);
322   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGBA8888(0x01010101, 0x03030303), 0x02020202u, TEST_LOCATION);
323   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGBA8888(0xffffffff, 0xffffffff), 0xffffffffu, TEST_LOCATION);
324   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGBA8888(0xffffffff, 0u), 0x7f7f7f7fu, TEST_LOCATION);
325   END_TEST;
326 }
327
328 /**
329  * @brief Test RGBA565 pixel averaging function.
330  */
331 int UtcDaliImageOperationsAveragePixelRGB565(void)
332 {
333   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGB565(0u, 0u), 0u, TEST_LOCATION);
334   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGB565(0xf800u, 0xf800u), 0xf800u, TEST_LOCATION);
335   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGB565(0xf800u, 0x800u), 1u << 15, TEST_LOCATION);
336   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGB565(0x7e0u, 0x7e0u), 0x7e0u, TEST_LOCATION);
337   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGB565(0x7e0u, 0x20u), 1u << 10, TEST_LOCATION);
338   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGB565(0x1f, 0x1f), 0x1fu, TEST_LOCATION);
339   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGB565(0x1f, 0x1), 1u << 4, TEST_LOCATION);
340   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGB565(0xf800u, 0x7e0u), 0x7800u + 0x3e0u, TEST_LOCATION);
341   DALI_TEST_EQUALS(Dali::Internal::Platform::AveragePixelRGB565(0xffff, 0xffff), 0xffffu, TEST_LOCATION);
342   END_TEST;
343 }
344
345 /**
346  * @brief Build a square bitmap, downscale it and assert the resulting bitmap has the right dimensions.
347  */
348 void TestDownscaledBitmapHasRightDimensionsAndFormat(
349   Pixel::Format     format,
350   uint32_t          sourceDimension,
351   uint32_t          targetDimension,
352   uint32_t          expectedDimension,
353   const char* const location)
354 {
355   ImageDimensions    desired(targetDimension, targetDimension);
356   FittingMode::Type  fittingMode(FittingMode::SHRINK_TO_FIT);
357   SamplingMode::Type samplingMode(SamplingMode::BOX);
358
359   Dali::Devel::PixelBuffer sourceBitmap = Dali::Devel::PixelBuffer::New(sourceDimension, sourceDimension, format);
360
361   Dali::Devel::PixelBuffer downScaled = DownscaleBitmap(sourceBitmap, desired, fittingMode, samplingMode);
362
363   DALI_TEST_EQUALS(downScaled.GetWidth(), expectedDimension, location);
364   DALI_TEST_EQUALS(downScaled.GetHeight(), expectedDimension, location);
365   DALI_TEST_EQUALS(downScaled.GetPixelFormat(), format, location);
366 }
367
368 /**
369  * @brief Test the top-level function for reducing the dimension of a bitmap,
370  * feeding it each of the five pixel formats that are output by image loaders.
371  * Simply assert that the resulting bitmaps have the expected dimensions and
372  * formats.
373  */
374 int UtcDaliImageOperationsDownscaleBitmap(void)
375 {
376   // Do Scalings that are expected to work for all pixels modes and assert the resulting bitmap dimensions:
377
378   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::RGBA8888, 1024, 8, 8, TEST_LOCATION);
379   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::RGB888, 1024, 8, 8, TEST_LOCATION);
380   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::RGB565, 1024, 8, 8, TEST_LOCATION);
381   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::LA88, 1024, 8, 8, TEST_LOCATION);
382   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::L8, 1024, 8, 8, TEST_LOCATION);
383
384   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::RGBA8888, 773, 1, 1, TEST_LOCATION);
385   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::RGB888, 787, 1, 1, TEST_LOCATION);
386   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::RGB565, 797, 1, 1, TEST_LOCATION);
387   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::LA88, 809, 1, 1, TEST_LOCATION);
388   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::L8, 811, 1, 1, TEST_LOCATION);
389
390   // Do Scalings that are expected to produce a slightly larger than requested image:
391   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::RGBA8888, 47, 7, 11, TEST_LOCATION);
392   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::RGB888, 73, 17, 18, TEST_LOCATION);
393   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::RGB565, 61, 8, 15, TEST_LOCATION);
394   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::LA88, 19, 5, 9, TEST_LOCATION);
395   TestDownscaledBitmapHasRightDimensionsAndFormat(Pixel::L8, 353, 23, 44, TEST_LOCATION);
396
397   END_TEST;
398 }
399
400 /**
401  * @brief Test downscaling of RGB888 images as raw pixel arrays.
402  */
403 int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void)
404 {
405   unsigned outWidth = -1, outHeight = -1, outStride = -1;
406
407   // Do downscaling to 1 x 1 so we can easily assert the value of the single pixel produced:
408
409   // Scale down a black/white checkerboard to mid-grey:
410   unsigned char check_4x4[16 * 3] = {
411     0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff};
412
413   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(check_4x4, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
414   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
415   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
416   DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION);
417   DALI_TEST_EQUALS(check_4x4[0], (unsigned char)0x7f, TEST_LOCATION);
418
419   // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
420   unsigned char single_4x4[16 * 3] = {
421     0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
422   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
423   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
424   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
425   DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION);
426   DALI_TEST_EQUALS(single_4x4[0], (unsigned char)0xf, TEST_LOCATION);
427
428   // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
429   // (white pixel at bottom-right of image)
430   unsigned char single_4x4_2[16 * 3] = {
431     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff};
432   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4_2, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
433   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
434   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
435   DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION);
436   DALI_TEST_EQUALS(single_4x4_2[0], (unsigned char)0xf, TEST_LOCATION);
437
438   // Build a larger ~600 x ~600 uniform magenta image for tests which only test output dimensions:
439
440   unsigned char magenta_600_x_600[608 * 608 * 3];
441   for(unsigned int i = 0; i < sizeof(magenta_600_x_600); i += 3)
442   {
443     magenta_600_x_600[i]     = 0xff;
444     magenta_600_x_600[i + 1] = 0;
445     magenta_600_x_600[i + 2] = 0xff;
446   }
447
448   // Scaling to 0 x 0 should stop at 1 x 1:
449   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
450   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
451   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
452   DALI_TEST_CHECK(outStride == outWidth);
453
454   // Scaling to 1 x 1 should hit 1 x 1:
455   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 608, 608, 608, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
456   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
457   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
458   DALI_TEST_CHECK(outStride == outWidth);
459
460   // Scaling to original dimensions should NOP:
461   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 384, 384, BoxDimensionTestBoth, outWidth, outHeight, outStride);
462   DALI_TEST_EQUALS(outWidth, 384u, TEST_LOCATION);
463   DALI_TEST_EQUALS(outHeight, 384u, TEST_LOCATION);
464   DALI_TEST_CHECK(outStride == outWidth);
465
466   // More dimension tests:
467
468   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 44, 11, BoxDimensionTestBoth, outWidth, outHeight, outStride);
469   DALI_TEST_EQUALS(outWidth, 44u, TEST_LOCATION);
470   DALI_TEST_EQUALS(outHeight, 44u, TEST_LOCATION);
471   DALI_TEST_CHECK(outStride == outWidth);
472
473   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 3, 48, BoxDimensionTestBoth, outWidth, outHeight, outStride);
474   DALI_TEST_EQUALS(outWidth, 48u, TEST_LOCATION);
475   DALI_TEST_EQUALS(outHeight, 48u, TEST_LOCATION);
476   DALI_TEST_CHECK(outStride == outWidth);
477
478   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 3, 3, BoxDimensionTestBoth, outWidth, outHeight, outStride);
479   DALI_TEST_CHECK(outWidth == 3u && outHeight == 3u);
480   DALI_TEST_CHECK(outStride == outWidth);
481
482   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 320, 320, 320, 5, 5, BoxDimensionTestBoth, outWidth, outHeight, outStride);
483   DALI_TEST_CHECK(outWidth == 5u && outHeight == 5u);
484   DALI_TEST_CHECK(outStride == outWidth);
485
486   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 448, 448, 448, 7, 7, BoxDimensionTestBoth, outWidth, outHeight, outStride);
487   DALI_TEST_CHECK(outWidth == 7u && outHeight == 7u);
488   DALI_TEST_CHECK(outStride == outWidth);
489
490   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 11, 11, BoxDimensionTestBoth, outWidth, outHeight, outStride);
491   DALI_TEST_CHECK(outWidth == 11u && outHeight == 11u);
492   DALI_TEST_CHECK(outStride == outWidth);
493
494   // Check that no pixel values were modified by the repeated averaging of identical pixels in tests above:
495   unsigned int numNonMagenta = 0u;
496   for(unsigned i = 0; i < sizeof(magenta_600_x_600); i += 3)
497   {
498     numNonMagenta += magenta_600_x_600[i] == 0xff && magenta_600_x_600[i + 1] == 0x00 && magenta_600_x_600[i + 2] == 0xff ? 0 : 1;
499   }
500   DALI_TEST_EQUALS(numNonMagenta, 0u, TEST_LOCATION);
501
502   END_TEST;
503 }
504
505 /**
506  * @brief Test that resizing RGBA8888 images as raw pixel arrays produces a result of the correct dimensions.
507  */
508 void TestDownscaleOutputsExpectedDimensionsRGBA8888(uint32_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
509 {
510   unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
511   Dali::Internal::Platform::DownscaleInPlacePow2RGBA8888(
512     reinterpret_cast<unsigned char*>(pixels),
513     inputWidth,
514     inputHeight,
515     inputWidth,
516     desiredWidth,
517     desiredHeight,
518     BoxDimensionTestBoth,
519     resultingWidth,
520     resultingHeight,
521     resultingStride);
522
523   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
524   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
525   DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
526 }
527
528 /**
529  * @brief Test that resizing RGB565 images as raw pixel arrays produces a result of the correct dimensions.
530  */
531 void TestDownscaleOutputsExpectedDimensionsRGB565(uint16_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
532 {
533   unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
534   Dali::Internal::Platform::DownscaleInPlacePow2RGB565(
535     reinterpret_cast<unsigned char*>(pixels),
536     inputWidth,
537     inputHeight,
538     inputWidth,
539     desiredWidth,
540     desiredHeight,
541     BoxDimensionTestBoth,
542     resultingWidth,
543     resultingHeight,
544     resultingStride);
545
546   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
547   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
548   DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
549 }
550
551 /**
552  * @brief Test that resizing 2-byte-per-pixel images as raw pixel arrays produces a result of the correct dimensions.
553  */
554 void TestDownscaleOutputsExpectedDimensions2ComponentPair(uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
555 {
556   unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
557   Dali::Internal::Platform::DownscaleInPlacePow2ComponentPair(
558     pixels,
559     inputWidth,
560     inputHeight,
561     inputWidth,
562     desiredWidth,
563     desiredHeight,
564     BoxDimensionTestBoth,
565     resultingWidth,
566     resultingHeight,
567     resultingStride);
568
569   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
570   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
571   DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
572 }
573
574 /**
575  * @brief Test that resizing single-byte-per-pixel images as raw pixel arrays produces a result of the correct dimensions.
576  */
577 void TestDownscaleOutputsExpectedDimensionsSingleComponent(uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
578 {
579   unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
580   Dali::Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(
581     pixels,
582     inputWidth,
583     inputHeight,
584     inputWidth,
585     desiredWidth,
586     desiredHeight,
587     BoxDimensionTestBoth,
588     resultingWidth,
589     resultingHeight,
590     resultingStride);
591
592   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
593   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
594   DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
595 }
596
597 /**
598  * @brief Test downscaling of RGBA8888 images in raw image arrays.
599  */
600 int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888(void)
601 {
602   uint32_t image[608 * 608];
603   for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i)
604   {
605     image[i] = 0xffffffff;
606   }
607   unsigned char* const pixels         = reinterpret_cast<unsigned char*>(image);
608   unsigned int         resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
609
610   // Test downscaling where the input size is an exact multiple of the desired size:
611   // (We expect a perfect result here)
612
613   DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
614   DALI_TEST_EQUALS(resultingWidth, 75u, TEST_LOCATION);
615   DALI_TEST_EQUALS(resultingHeight, 75u, TEST_LOCATION);
616   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
617
618   DownscaleInPlacePow2RGBA8888(pixels, 512, 512, 512, 16, 16, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
619   DALI_TEST_EQUALS(resultingWidth, 16u, TEST_LOCATION);
620   DALI_TEST_EQUALS(resultingHeight, 16u, TEST_LOCATION);
621   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
622
623   DownscaleInPlacePow2RGBA8888(pixels, 512, 64, 512, 16, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
624   DALI_TEST_EQUALS(resultingWidth, 16u, TEST_LOCATION);
625   DALI_TEST_EQUALS(resultingHeight, 2u, TEST_LOCATION);
626   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
627
628   DownscaleInPlacePow2RGBA8888(pixels, 64, 1024, 64, 4, 64, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
629   DALI_TEST_EQUALS(resultingWidth, 4u, TEST_LOCATION);
630   DALI_TEST_EQUALS(resultingHeight, 64u, TEST_LOCATION);
631   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
632
633   // Test downscaling where the input size is slightly off being an exact multiple of the desired size:
634   // (We expect a perfect match at the end because of rounding-down to an even width and height at each step)
635
636   DownscaleInPlacePow2RGBA8888(pixels, 601, 603, 601, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
637   DALI_TEST_EQUALS(resultingWidth, 75u, TEST_LOCATION);
638   DALI_TEST_EQUALS(resultingHeight, 75u, TEST_LOCATION);
639   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
640
641   DownscaleInPlacePow2RGBA8888(pixels, 736 + 1, 352 + 3, 736 + 1, 23, 11, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
642   DALI_TEST_EQUALS(resultingWidth, 23u, TEST_LOCATION);
643   DALI_TEST_EQUALS(resultingHeight, 11u, TEST_LOCATION);
644   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
645
646   DownscaleInPlacePow2RGBA8888(pixels, 384 + 3, 896 + 1, 384 + 3, 3, 7, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
647   DALI_TEST_EQUALS(resultingWidth, 3u, TEST_LOCATION);
648   DALI_TEST_EQUALS(resultingHeight, 7u, TEST_LOCATION);
649   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
650
651   // Test downscales with source dimensions which are under a nice power of two by one:
652
653   // The target is hit exactly due to losing spare columns or rows at each iteration:
654   DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 63, 7, 3, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
655   DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
656   DALI_TEST_EQUALS(resultingHeight, 3u, TEST_LOCATION);
657   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
658
659   // Asking to downscale a bit smaller should stop at the dimensions of the last test as one more halving would go down to 3 x 1, which is too small.
660   DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 63, 4, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
661   DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
662   DALI_TEST_EQUALS(resultingHeight, 3u, TEST_LOCATION);
663   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
664
665   // Should stop at almost twice the requested dimensions:
666   DownscaleInPlacePow2RGBA8888(pixels, 15, 127, 15, 4, 32, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
667   DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
668   DALI_TEST_EQUALS(resultingHeight, 63u, TEST_LOCATION);
669   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
670
671   // Test downscales to 1 in one or both dimensions:
672   // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
673   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 512, 1, 1, 1, 1, TEST_LOCATION);
674   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 32, 16, 1, 16, 1, TEST_LOCATION);
675   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 32, 7, 1, 16, 1, TEST_LOCATION);
676   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 32, 7, 1, 16, 1, TEST_LOCATION);
677   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 32, 5, 1, 16, 1, TEST_LOCATION);
678   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 32, 3, 1, 16, 1, TEST_LOCATION);
679   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 32, 512, 1, 1, 1, 16, TEST_LOCATION);
680   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 32, 512, 1, 16, 1, 16, TEST_LOCATION);
681   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 32, 512, 1, 3, 1, 16, TEST_LOCATION);
682   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 33, 33, 1, 1, 1, 1, TEST_LOCATION);
683   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 17 * 19, 17 * 19, 1, 1, 1, 1, TEST_LOCATION);
684   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 33, 33, 3, 1, 4, 4, TEST_LOCATION);
685   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 33, 9, 3, 1, 4, 1, TEST_LOCATION);
686
687   // Test downscales to zero in one or both dimensions:
688   // Scaling should stop when one or both dimensions reach 1.
689   // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
690   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 512, 0, 0, 1, 1, TEST_LOCATION);
691   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 256, 0, 0, 2, 1, TEST_LOCATION);
692   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 128, 0, 0, 4, 1, TEST_LOCATION);
693   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 16, 0, 0, 32, 1, TEST_LOCATION);
694   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 128, 512, 0, 0, 1, 4, TEST_LOCATION);
695   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 32, 512, 0, 0, 1, 16, TEST_LOCATION);
696   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 8, 512, 0, 0, 1, 64, TEST_LOCATION);
697   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 2, 512, 0, 0, 1, 256, TEST_LOCATION);
698
699   END_TEST;
700 }
701
702 /**
703  * @brief Test downscalings of RGBA8888 images in raw image arrays that should have no effect on the input.
704  */
705 int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888Nops(void)
706 {
707   uint32_t       image[608 * 608];
708   const uint32_t numPixels = sizeof(image) / sizeof(image[0]);
709   for(unsigned i = 0; i < numPixels; ++i)
710   {
711     image[i] = RandomPixelRGBA8888();
712   }
713   const uint32_t       imageHash      = HashPixels(image, numPixels);
714   unsigned char* const pixels         = reinterpret_cast<unsigned char*>(image);
715   unsigned int         resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
716
717   // Test downscales to the same size:
718   // The point is just to be sure the downscale is a NOP in this case:
719
720   DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 600, 600, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
721   DALI_TEST_EQUALS(resultingWidth, 600u, TEST_LOCATION);
722   DALI_TEST_EQUALS(resultingHeight, 600u, TEST_LOCATION);
723   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
724
725   DownscaleInPlacePow2RGBA8888(pixels, 512, 128, 512, 512, 128, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
726   DALI_TEST_EQUALS(resultingWidth, 512u, TEST_LOCATION);
727   DALI_TEST_EQUALS(resultingHeight, 128u, TEST_LOCATION);
728   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
729
730   DownscaleInPlacePow2RGBA8888(pixels, 17, 1001, 17, 17, 1001, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
731   DALI_TEST_EQUALS(resultingWidth, 17u, TEST_LOCATION);
732   DALI_TEST_EQUALS(resultingHeight, 1001u, TEST_LOCATION);
733   DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
734
735   // Test downscales that request a larger size (we never upscale so these are NOPs too):
736   // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
737   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 300, 300, 600, 600, 300, 300, TEST_LOCATION);
738   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 3, 127, 99, 599, 3, 127, TEST_LOCATION);
739   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 600, 600, 999, 999, 600, 600, TEST_LOCATION); //< checks no out of bounds mem access in this case
740
741   // Make sure that none of these NOP downscalings has affected the pixels of the image:
742   DALI_TEST_EQUALS(HashPixels(image, numPixels), imageHash, TEST_LOCATION);
743
744   END_TEST;
745 }
746
747 /**
748  * @brief Do additional downscaling testing using RGB565 images in raw image
749  * arrays to shake out differences relating to the pixel format.
750  */
751 int UtcDaliImageOperationsDownscaleInPlacePow2RGB565(void)
752 {
753   // Test that calling with null and zero parameters doesn't blow up:
754   unsigned int outWidth, outHeight, outStride;
755   DownscaleInPlacePow2RGB565(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
756
757   uint16_t image[608 * 608];
758   for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i)
759   {
760     image[i] = 0xffff;
761   }
762
763   // Do a straightforward test using an exact divisor target size:
764   TestDownscaleOutputsExpectedDimensionsRGB565(image, 600, 600, 75, 75, 75, 75, TEST_LOCATION);
765   // Test that a slightly smaller than possible to achieve target results in the
766   // next-higher exact divisor output image dimensions:
767   TestDownscaleOutputsExpectedDimensionsRGB565(image, 600, 600, 71, 69, 75, 75, TEST_LOCATION);
768   // Test that resizing from a starting size that is slightly larger than an exact
769   // multiple of the desired dimensions still results in the desired ones being
770   // reached:
771   // Parameters:                                       input-x  input-y, desired-x, desired-y, expected-x, expected-y
772   TestDownscaleOutputsExpectedDimensionsRGB565(image, 600 + 1, 600 + 1, 75, 75, 75, 75, TEST_LOCATION);
773   TestDownscaleOutputsExpectedDimensionsRGB565(image, 256 + 1, 512 + 1, 2, 4, 2, 4, TEST_LOCATION);
774   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 1, 128 + 1, 16, 4, 16, 4, TEST_LOCATION);
775   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 1, 64 + 1, 16, 2, 16, 2, TEST_LOCATION);
776   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 3, 512 + 3, 16, 16, 16, 16, TEST_LOCATION);
777   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 3, 256 + 3, 16, 8, 16, 8, TEST_LOCATION);
778   TestDownscaleOutputsExpectedDimensionsRGB565(image, 256 + 3, 512 + 3, 4, 8, 4, 8, TEST_LOCATION);
779   TestDownscaleOutputsExpectedDimensionsRGB565(image, 256 + 7, 512 + 7, 4, 8, 4, 8, TEST_LOCATION);
780   TestDownscaleOutputsExpectedDimensionsRGB565(image, 256 + 7, 512 + 7, 2, 4, 2, 4, TEST_LOCATION);
781   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 7, 128 + 7, 16, 4, 16, 4, TEST_LOCATION);
782   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 7, 64 + 7, 16, 2, 16, 2, TEST_LOCATION);
783
784   END_TEST;
785 }
786
787 /**
788  * @brief Do additional downscaling testing using 2-byte-per-pixel images in
789  * raw image arrays to shake out differences relating to the pixel format.
790  */
791 int UtcDaliImageOperationsDownscaleInPlacePow2ComponentPair(void)
792 {
793   // Simple test that a null pointer does not get dereferenced in the function:
794   unsigned int outWidth, outHeight, outStride;
795   DownscaleInPlacePow2ComponentPair(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
796
797   // Simple tests of dimensions output:
798
799   uint8_t image[608 * 608 * 2];
800   for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i)
801   {
802     image[i] = 0xff;
803   }
804
805   TestDownscaleOutputsExpectedDimensions2ComponentPair(image,
806                                                        600,
807                                                        600, //< Input dimensions
808                                                        37,
809                                                        37, //< Requested dimensions
810                                                        37,
811                                                        37, //< Expected output dimensions
812                                                        TEST_LOCATION);
813   TestDownscaleOutputsExpectedDimensions2ComponentPair(image,
814                                                        600,
815                                                        600, //< Input dimensions
816                                                        34,
817                                                        35, //< Requested dimensions to scale-down to
818                                                        37,
819                                                        37, //< Expected output dimensions achieved
820                                                        TEST_LOCATION);
821   ///@note: No need to be as comprehensive as with RGB888 and RGBA8888 as the logic is shared.
822
823   END_TEST;
824 }
825
826 /**
827  * @brief Do additional downscaling testing using 1-byte-per-pixel images in
828  * raw image arrays to shake out differences relating to the pixel format.
829  */
830 int UtcDaliImageOperationsDownscaleInPlacePow2SingleBytePerPixel(void)
831 {
832   // Simple test that a null pointer does not get dereferenced in the function:
833   unsigned int outWidth, outHeight, outStride;
834   DownscaleInPlacePow2SingleBytePerPixel(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
835
836   // Tests of output dimensions from downscaling:
837   uint8_t image[608 * 608];
838   for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i)
839   {
840     image[i] = 0xff;
841   }
842
843   TestDownscaleOutputsExpectedDimensionsSingleComponent(image,
844                                                         600,
845                                                         300, //< Input dimensions
846                                                         150,
847                                                         75, //< Requested dimensions to scale-down to
848                                                         150,
849                                                         75, //< Expected output dimensions achieved
850                                                         TEST_LOCATION);
851   TestDownscaleOutputsExpectedDimensionsSingleComponent(image, 577, 411, 142, 99, 144, 102, TEST_LOCATION);
852
853   END_TEST;
854 }
855
856 /**
857  * @brief Test the function for averaging pairs of pixels on a scanline.
858  */
859 int UtcDaliImageOperationsHalveScanlineInPlaceRGB888(void)
860 {
861   // Red and cyan, averaging to grey:
862   unsigned char shortEven[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
863   unsigned char shortOdd[]  = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xC, 0xC, 0xC};
864
865   Dali::Internal::Platform::HalveScanlineInPlaceRGB888(shortEven, 4u);
866   Dali::Internal::Platform::HalveScanlineInPlaceRGB888(shortOdd, 4u);
867
868   for(unsigned i = 0; i < (sizeof(shortEven) >> 1u); ++i)
869   {
870     DALI_TEST_EQUALS(unsigned(shortEven[i]), 0x7fu, TEST_LOCATION);
871     DALI_TEST_EQUALS(unsigned(shortOdd[i]), 0x7fu, TEST_LOCATION);
872   }
873
874   END_TEST;
875 }
876
877 /**
878  * @brief Test the function for averaging pairs of pixels on a scanline.
879  */
880 int UtcDaliImageOperationsHalveScanlineInPlaceRGBA8888(void)
881 {
882   const size_t           scanlineLength = 4096u;
883   Dali::Vector<uint32_t> scanline;
884   Dali::Vector<uint32_t> reference;
885   SetupScanlineForHalvingTestsRGBA8888(scanlineLength, scanline, reference);
886
887   HalveScanlineInPlaceRGBA8888((uint8_t*)&scanline[0], scanlineLength);
888
889   // Check that the halving matches the independently calculated reference:
890   size_t numMatches = 0;
891   for(int i = 0, length = scanlineLength / 2; i < length; ++i)
892   {
893     DALI_TEST_EQUALS(scanline[i], reference[i], TEST_LOCATION);
894     numMatches += scanline[i] == reference[i];
895   }
896   DALI_TEST_EQUALS(numMatches, scanlineLength / 2, TEST_LOCATION);
897
898   // Test for no beyond-bounds writes:
899   for(size_t i = scanlineLength / 2; i < reference.Count(); ++i)
900   {
901     DALI_TEST_EQUALS(reference[i], (uint32_t)0xEEEEEEEE, TEST_LOCATION);
902   }
903
904   END_TEST;
905 }
906
907 /**
908  * @brief Test the function for averaging pairs of pixels on a scanline.
909  */
910 int UtcDaliImageOperationsHalveScanlineInPlaceRGB565(void)
911 {
912   const size_t           scanlineLength = 4096u;
913   Dali::Vector<uint16_t> scanline;
914   Dali::Vector<uint16_t> reference;
915   SetupScanlineForHalvingTestsRGB565(scanlineLength, scanline, reference);
916
917   HalveScanlineInPlaceRGB565((unsigned char*)(&scanline[0]), scanlineLength);
918
919   // Check output against reference:
920   size_t numMatches = 0;
921   for(int i = 0, length = scanlineLength / 2; i < length; ++i)
922   {
923     DALI_TEST_EQUALS(scanline[i], reference[i], TEST_LOCATION);
924     numMatches += scanline[i] == reference[i];
925   }
926   DALI_TEST_EQUALS(numMatches, scanlineLength / 2, TEST_LOCATION);
927
928   // Test for no beyond-bounds writes:
929   for(size_t i = scanlineLength / 2; i < reference.Count(); ++i)
930   {
931     DALI_TEST_EQUALS(reference[i], (uint16_t)0xEEEE, TEST_LOCATION);
932   }
933
934   END_TEST;
935 }
936
937 /**
938  * @brief Test the function for averaging pairs of pixels on a scanline.
939  */
940 int UtcDaliImageOperationsHalveScanlineInPlace2Bytes(void)
941 {
942   const size_t          scanlineLength = 4096u;
943   Dali::Vector<uint8_t> scanline;
944   Dali::Vector<uint8_t> reference;
945   SetupScanlineForHalvingTests2Bytes(scanlineLength, scanline, reference);
946
947   HalveScanlineInPlace2Bytes(&scanline[0], scanlineLength);
948
949   // Test the output against the reference (no differences):
950   size_t numMatches = 0;
951   for(int i = 0, length = scanlineLength; i < length; ++i)
952   {
953     DALI_TEST_EQUALS(1u * scanline[i], 1u * reference[i], TEST_LOCATION);
954     numMatches += scanline[i] == reference[i];
955   }
956   // The number of matching bytes should be double the number of pixels, which happens to be the original scanline length in pixels:
957   DALI_TEST_EQUALS(numMatches, scanlineLength, TEST_LOCATION);
958
959   END_TEST;
960 }
961
962 /**
963  * @brief Test the function for averaging pairs of pixels on a scanline.
964  */
965 int UtcDaliImageOperationsHalveScanlineInPlace1Byte(void)
966 {
967   const size_t          scanlineLength = 4096u;
968   Dali::Vector<uint8_t> scanline;
969   Dali::Vector<uint8_t> reference;
970   SetupScanlineForHalvingTests1Byte(scanlineLength, scanline, reference);
971
972   HalveScanlineInPlace1Byte(&scanline[0], scanlineLength);
973
974   // Test the reference matches the output:
975   size_t numMatches = 0;
976   for(int i = 0, length = scanlineLength / 2; i < length; ++i)
977   {
978     DALI_TEST_EQUALS(1u * scanline[i], 1u * reference[i], TEST_LOCATION);
979     numMatches += scanline[i] == reference[i];
980   }
981   // Only half will be matched
982   DALI_TEST_EQUALS(numMatches, scanlineLength / 2, TEST_LOCATION);
983
984   END_TEST;
985 }
986
987 /**
988  * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
989  */
990 int UtcDaliImageOperationsAverageScanlines1ExceptTest(void)
991 {
992   // Edge cases for averagescanlines1:
993   unsigned char shortEven1[]   = {0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x02, 0x03, 0x00, 0x01};
994   unsigned char shortEven2[]   = {0x00, 0xff, 0x00, 0xff, 0x01, 0x01, 0xff, 0xfe, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x03, 0x02};
995   unsigned char expectBuffer[] = {0x00, 0x7f, 0x7f, 0xff, 0x80, 0x7f, 0x80, 0x7f, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
996   unsigned char outputBuffer[sizeof(shortEven1)];
997
998   AverageScanlines1(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1));
999   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
1000   {
1001     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), unsigned(expectBuffer[i]), TEST_LOCATION);
1002   }
1003
1004   END_TEST;
1005 }
1006
1007 /**
1008  * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
1009  */
1010 int UtcDaliImageOperationsAverageScanlines1(void)
1011 {
1012   // Red and cyan, averaging to grey:
1013   unsigned char shortEven1[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
1014   unsigned char shortEven2[] = {0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0};
1015   unsigned char outputBuffer[sizeof(shortEven1)];
1016
1017   AverageScanlines1(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1));
1018   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
1019   {
1020     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION);
1021   }
1022
1023   // Longer test reusing RGBA setup/test logic:
1024   {
1025     const size_t           scanlineLength = 4096u;
1026     Dali::Vector<uint32_t> scanline1;
1027     Dali::Vector<uint32_t> scanline2;
1028     Dali::Vector<uint32_t> reference;
1029     Dali::Vector<uint32_t> output;
1030     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1031
1032     AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
1033
1034     // Check the output matches the independently generated reference:
1035     size_t numMatches = 0;
1036     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1037     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1038   }
1039
1040   // Longer test reusing RGBA setup/test logic with none-8-divisable length
1041   {
1042     const size_t           scanlineLength = 1003u;
1043     Dali::Vector<uint32_t> scanline1;
1044     Dali::Vector<uint32_t> scanline2;
1045     Dali::Vector<uint32_t> reference;
1046     Dali::Vector<uint32_t> output;
1047     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1048
1049     AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
1050
1051     // Check the output matches the independently generated reference:
1052     size_t numMatches = 0;
1053     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1054     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1055   }
1056
1057   // Very short test reusing RGBA setup/test logic with less-than-8 length
1058   {
1059     const size_t           scanlineLength = 1003u;
1060     Dali::Vector<uint32_t> scanline1;
1061     Dali::Vector<uint32_t> scanline2;
1062     Dali::Vector<uint32_t> reference;
1063     Dali::Vector<uint32_t> output;
1064     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1065
1066     AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
1067
1068     // Check the output matches the independently generated reference:
1069     size_t numMatches = 0;
1070     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1071     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1072   }
1073
1074   END_TEST;
1075 }
1076
1077 /**
1078  * @brief Test the function for averaging vertically-adjacent pairs of 2-byte-per-pixel pixels on a scanline.
1079  */
1080 int UtcDaliImageOperationsAverageScanlines2(void)
1081 {
1082   // Red and cyan, averaging to grey:
1083   unsigned char shortEven1[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
1084   unsigned char shortEven2[] = {0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0};
1085   unsigned char outputBuffer[sizeof(shortEven1)];
1086
1087   AverageScanlines2(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) / 2);
1088
1089   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
1090   {
1091     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION);
1092   }
1093
1094   // Longer test reusing RGBA setup/test logic:
1095   {
1096     const size_t           scanlineLength = 4096u;
1097     Dali::Vector<uint32_t> scanline1;
1098     Dali::Vector<uint32_t> scanline2;
1099     Dali::Vector<uint32_t> reference;
1100     Dali::Vector<uint32_t> output;
1101     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1102
1103     AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
1104
1105     // Check the output matches the independently generated reference:
1106     size_t numMatches = 0;
1107     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1108     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1109   }
1110
1111   // Longer test reusing RGBA setup/test logic with none-8-divisable length
1112   {
1113     const size_t           scanlineLength = 501u;
1114     Dali::Vector<uint32_t> scanline1;
1115     Dali::Vector<uint32_t> scanline2;
1116     Dali::Vector<uint32_t> reference;
1117     Dali::Vector<uint32_t> output;
1118     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1119
1120     AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
1121
1122     // Check the output matches the independently generated reference:
1123     size_t numMatches = 0;
1124     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1125     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1126   }
1127
1128   // Very short test reusing RGBA setup/test logic with less-than-8 length
1129   {
1130     const size_t           scanlineLength = 3u;
1131     Dali::Vector<uint32_t> scanline1;
1132     Dali::Vector<uint32_t> scanline2;
1133     Dali::Vector<uint32_t> reference;
1134     Dali::Vector<uint32_t> output;
1135     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1136
1137     AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
1138
1139     // Check the output matches the independently generated reference:
1140     size_t numMatches = 0;
1141     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1142     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1143   }
1144
1145   END_TEST;
1146 }
1147
1148 /**
1149  * @brief Test the function for averaging vertically-adjacent pairs of RGB888 pixels on a scanline.
1150  */
1151 int UtcDaliImageOperationsAverageScanlines3(void)
1152 {
1153   // Red and cyan, averaging to grey:
1154   unsigned char shortEven1[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
1155   unsigned char shortEven2[] = {0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0};
1156   unsigned char outputBuffer[sizeof(shortEven1)];
1157
1158   AverageScanlines3(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) / 3);
1159   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
1160   {
1161     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION);
1162   }
1163
1164   // Longer test reusing RGBA setup/test logic:
1165   {
1166     const size_t           scanlineLength = 3 * 4 * 90u;
1167     Dali::Vector<uint32_t> scanline1;
1168     Dali::Vector<uint32_t> scanline2;
1169     Dali::Vector<uint32_t> reference;
1170     Dali::Vector<uint32_t> output;
1171     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1172
1173     AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
1174
1175     // Check the output matches the independently generated reference:
1176     size_t numMatches = 0;
1177     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1178     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1179   }
1180
1181   // Longer test reusing RGBA setup/test logic with none-8-divisable length
1182   {
1183     const size_t           scanlineLength = 3 * 501u;
1184     Dali::Vector<uint32_t> scanline1;
1185     Dali::Vector<uint32_t> scanline2;
1186     Dali::Vector<uint32_t> reference;
1187     Dali::Vector<uint32_t> output;
1188     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1189
1190     AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
1191
1192     // Check the output matches the independently generated reference:
1193     size_t numMatches = 0;
1194     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1195     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1196   }
1197
1198   // Very short test reusing RGBA setup/test logic with less-than-8 length
1199   {
1200     const size_t           scanlineLength = 3u;
1201     Dali::Vector<uint32_t> scanline1;
1202     Dali::Vector<uint32_t> scanline2;
1203     Dali::Vector<uint32_t> reference;
1204     Dali::Vector<uint32_t> output;
1205     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1206
1207     AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
1208
1209     // Check the output matches the independently generated reference:
1210     size_t numMatches = 0;
1211     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1212     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1213   }
1214
1215   END_TEST;
1216 }
1217
1218 /**
1219  * @brief Test the function for averaging vertically-adjacent pairs of RGBA8888 pixels on a scanline.
1220  */
1221 int UtcDaliImageOperationsAverageScanlinesRGBA8888(void)
1222 {
1223   const size_t           scanlineLength = 4096u;
1224   Dali::Vector<uint32_t> scanline1;
1225   Dali::Vector<uint32_t> scanline2;
1226   Dali::Vector<uint32_t> reference;
1227   Dali::Vector<uint32_t> output;
1228   SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1229
1230   AverageScanlinesRGBA8888((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength);
1231
1232   // Check the output matches the independently generated reference:
1233   size_t numMatches = 0;
1234   MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1235   DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1236
1237   END_TEST;
1238 }
1239
1240 /**
1241  * @brief Test the function for averaging vertically-adjacent pairs of RGB565 pixels on a scanline.
1242  */
1243 int UtcDaliImageOperationsAverageScanlinesRGB565(void)
1244 {
1245   // Red and cyan, averaging to grey:
1246   const uint16_t shortEven1[] = {0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xBEEF, 0xBEEF};
1247   const uint16_t shortEven2[] = {0x7ff, 0x7ff, 0x7ff, 0x7ff, 0x7ff, 0x7ff, 0xBEEF, 0xBEEF};
1248   const size_t   arrayLength  = sizeof(shortEven1) / sizeof(shortEven1[0]) - 2;
1249   uint16_t       outputBuffer[arrayLength + 2];
1250   outputBuffer[arrayLength]     = 0xDEAD;
1251   outputBuffer[arrayLength + 1] = 0xDEAD;
1252
1253   Dali::Internal::Platform::AverageScanlinesRGB565((const unsigned char*)shortEven1, (const unsigned char*)shortEven2, (unsigned char*)outputBuffer, arrayLength);
1254   for(unsigned i = 0; i < arrayLength; ++i)
1255   {
1256     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0xffff - (1u << 15) - (1u << 10) - (1u << 4), TEST_LOCATION);
1257   }
1258
1259   // Check for buffer overrun:
1260   DALI_TEST_EQUALS(outputBuffer[arrayLength], (uint16_t)0xDEAD, TEST_LOCATION);
1261   DALI_TEST_EQUALS(outputBuffer[arrayLength + 1], (uint16_t)0xDEAD, TEST_LOCATION);
1262
1263   END_TEST;
1264 }
1265
1266 namespace
1267 {
1268 void MakeSingleColorImageRGBA8888(unsigned int width, unsigned int height, uint32_t* inputImage)
1269 {
1270   const uint32_t inPixel = PixelRGBA8888(255, 192, 128, 64);
1271   for(unsigned int i = 0; i < width * height; ++i)
1272   {
1273     inputImage[i] = inPixel;
1274   }
1275 }
1276
1277 /*
1278  * @brief Make an image with a checkerboard pattern.
1279  * @note This is an easy pattern to scan for correctness after a downscaling test.
1280  */
1281 Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > MakeCheckerboardImageRGBA8888(unsigned int width, unsigned int height, unsigned int checkerSize)
1282 {
1283   const unsigned int                                    imageWidth  = width * checkerSize;
1284   const unsigned int                                    imageHeight = height * checkerSize;
1285   Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image       = new Dali::RefCountedVector<uint32_t>;
1286   image->GetVector().Resize(imageWidth * imageHeight);
1287
1288   uint32_t rowColor = 0xffffffff;
1289   for(unsigned int cy = 0; cy < height; ++cy)
1290   {
1291     rowColor            = rowColor == 0xffffffff ? 0xff000000 : 0xffffffff;
1292     uint32_t checkColor = rowColor;
1293     for(unsigned int cx = 0; cx < width; ++cx)
1294     {
1295       checkColor            = checkColor == 0xffffffff ? 0xff000000 : 0xffffffff;
1296       uint32_t paintedColor = checkColor;
1297       // Draw 3 special case checks as r,g,b:
1298       if(cx == 0 && cy == 0)
1299       {
1300         paintedColor = 0xff0000ff; // Red
1301       }
1302       else if(cx == 7 && cy == 0)
1303       {
1304         paintedColor = 0xff00ff00; // Green
1305       }
1306       else if(cx == 7 && cy == 7)
1307       {
1308         paintedColor = 0xffff0000; // blue
1309       }
1310       uint32_t* check = &image->GetVector()[(cy * checkerSize * imageWidth) + (cx * checkerSize)];
1311       for(unsigned int py = 0; py < checkerSize; ++py)
1312       {
1313         uint32_t* checkLine = check + py * imageWidth;
1314         for(unsigned int px = 0; px < checkerSize; ++px)
1315         {
1316           checkLine[px] = paintedColor;
1317         }
1318       }
1319     }
1320   }
1321
1322   return image;
1323 }
1324
1325 } // namespace
1326
1327 /**
1328  * @brief Test the right pixels are generated when downsampling a checkerboard into a small image.
1329  */
1330 int UtcDaliImageOperationsPointSampleCheckerboardRGBA888(void)
1331 {
1332   Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image         = MakeCheckerboardImageRGBA8888(8, 8, 32);
1333   const unsigned int                                    desiredWidth  = 8;
1334   const unsigned int                                    desiredHeight = 8;
1335
1336   uint32_t outputImage[desiredWidth * desiredHeight];
1337
1338   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)&image->GetVector()[0], 256, 256, 256, (unsigned char*)outputImage, desiredWidth, desiredHeight);
1339
1340   DALI_TEST_EQUALS(outputImage[0], (uint32_t)0xff0000ff, TEST_LOCATION);         // < Red corner pixel
1341   DALI_TEST_EQUALS(outputImage[7], (uint32_t)0xff00ff00, TEST_LOCATION);         // < Green corner pixel
1342   DALI_TEST_EQUALS(outputImage[8 * 8 - 1], (uint32_t)0xffff0000, TEST_LOCATION); // < Blue corner pixel
1343
1344   DALI_TEST_EQUALS(outputImage[1], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1345   DALI_TEST_EQUALS(outputImage[2], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1346   DALI_TEST_EQUALS(outputImage[3], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1347   DALI_TEST_EQUALS(outputImage[4], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1348   DALI_TEST_EQUALS(outputImage[5], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1349   DALI_TEST_EQUALS(outputImage[6], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1350
1351   // Second scanline:
1352   DALI_TEST_EQUALS(outputImage[8 + 0], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1353   DALI_TEST_EQUALS(outputImage[8 + 1], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1354   DALI_TEST_EQUALS(outputImage[8 + 2], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1355   DALI_TEST_EQUALS(outputImage[8 + 3], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1356   DALI_TEST_EQUALS(outputImage[8 + 4], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1357   DALI_TEST_EQUALS(outputImage[8 + 5], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1358   DALI_TEST_EQUALS(outputImage[8 + 6], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1359   DALI_TEST_EQUALS(outputImage[8 + 7], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1360
1361   // Third scanline:
1362   DALI_TEST_EQUALS(outputImage[16 + 0], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1363   DALI_TEST_EQUALS(outputImage[16 + 1], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1364   DALI_TEST_EQUALS(outputImage[16 + 2], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1365   DALI_TEST_EQUALS(outputImage[16 + 3], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1366   DALI_TEST_EQUALS(outputImage[16 + 4], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1367   DALI_TEST_EQUALS(outputImage[16 + 5], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1368   DALI_TEST_EQUALS(outputImage[16 + 6], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1369   DALI_TEST_EQUALS(outputImage[16 + 7], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1370
1371   // ... could do more scanlines (there are 8)
1372
1373   // Sample a few more pixels:
1374
1375   // Diagonals:
1376   DALI_TEST_EQUALS(outputImage[24 + 3], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1377   DALI_TEST_EQUALS(outputImage[32 + 4], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1378   DALI_TEST_EQUALS(outputImage[40 + 5], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1379   DALI_TEST_EQUALS(outputImage[48 + 6], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1380   DALI_TEST_EQUALS(outputImage[24 + 4], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1381   DALI_TEST_EQUALS(outputImage[32 + 3], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1382   DALI_TEST_EQUALS(outputImage[40 + 2], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1383   DALI_TEST_EQUALS(outputImage[48 + 1], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1384   DALI_TEST_EQUALS(outputImage[56 + 0], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1385
1386   END_TEST;
1387 }
1388
1389 /**
1390  * @brief Test that a scaling preserves input color in destination image.
1391  */
1392 int UtcDaliImageOperationsPointSampleRGBA888PixelsCorrectColor(void)
1393 {
1394   const unsigned int inputWidth    = 137;
1395   const unsigned int inputHeight   = 571;
1396   const unsigned int desiredWidth  = 59;
1397   const unsigned int desiredHeight = 257;
1398
1399   uint32_t inputImage[inputWidth * inputHeight];
1400   MakeSingleColorImageRGBA8888(inputWidth, inputHeight, inputImage);
1401
1402   const size_t          outputBufferSize = desiredWidth * desiredHeight;
1403   std::vector<uint32_t> buffer;
1404   buffer.resize(outputBufferSize);
1405   uint32_t* outputImage = &buffer[0];
1406
1407   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, inputWidth, inputHeight, inputWidth, (unsigned char*)outputImage, desiredWidth, desiredHeight);
1408
1409   // Check that all the output pixels are the right color:
1410   const uint32_t reference           = inputImage[inputWidth * inputHeight / 2];
1411   unsigned int   differentColorCount = 0;
1412   for(unsigned int i = 0; i < desiredWidth * desiredHeight; ++i)
1413   {
1414     if(outputImage[i] != reference)
1415     {
1416       ++differentColorCount;
1417     }
1418   }
1419
1420   DALI_TEST_EQUALS(0U, differentColorCount, TEST_LOCATION);
1421
1422   END_TEST;
1423 }
1424
1425 /**
1426  * @brief Test that scaling down to a 1x1 image works.
1427  */
1428 int UtcDaliImageOperationsPointSampleRGBA888ScaleToSinglePixel(void)
1429 {
1430   const unsigned int desiredWidth  = 1;
1431   const unsigned int desiredHeight = 1;
1432
1433   uint32_t inputImage[1024 * 1024];
1434   MakeSingleColorImageRGBA8888(1024, 1024, inputImage);
1435   uint32_t outputImage = 0;
1436
1437   // Try several different starting image sizes:
1438
1439   // 1x1 -> 1x1:
1440   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1441   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1442   outputImage = 0;
1443
1444   // Single-pixel wide tall stripe:
1445   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1024, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1446   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1447   outputImage = 0;
1448
1449   // Single-pixel tall, wide strip:
1450   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1024, 1, 1024, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1451   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1452   outputImage = 0;
1453
1454   // Square mid-size image:
1455   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, 103, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1456   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1457   outputImage = 0;
1458
1459   // Wide mid-size image:
1460   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, 313, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1461   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1462   outputImage = 0;
1463
1464   // Tall mid-size image:
1465   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 467, 53, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1466   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1467   outputImage = 0;
1468
1469   // 0 x 0 input image (make sure output not written to):
1470   outputImage = 0xDEADBEEF;
1471   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, 0, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1472   DALI_TEST_EQUALS(outputImage, (uint32_t)0xDEADBEEF, TEST_LOCATION);
1473   outputImage = 0;
1474
1475   END_TEST;
1476 }
1477
1478 /**
1479  * @brief Test that downsampling to 0 - area images is a NOP and does not modify the destination.
1480  * (edge-case)
1481  */
1482 int UtcDaliImageOperationsPointSampleRGBA888N(void)
1483 {
1484   uint32_t inputImage[128 * 128];
1485   MakeSingleColorImageRGBA8888(128, 128, inputImage);
1486   uint32_t outputImage[128 * 128];
1487   memset(outputImage, 0xaa, 128 * 128 * sizeof(uint32_t));
1488
1489   // Try several different starting image sizes:
1490
1491   // 1x1 -> 1x1:
1492   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, 1, (unsigned char*)outputImage, 0, 0);
1493   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1494
1495   // Single-pixel wide tall stripe:
1496   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 102, 1, (unsigned char*)outputImage, 0, 33);
1497   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1498
1499   // Single-pixel tall, wide strip:
1500   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 102, 1, 102, (unsigned char*)outputImage, 0, 67);
1501   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1502
1503   // Square mid-size image:
1504   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, 103, (unsigned char*)outputImage, 21, 0);
1505   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1506
1507   // Wide mid-size image to 0 height
1508   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, 313, (unsigned char*)outputImage, 99, 0);
1509   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1510
1511   // Tall mid-size image to 0 height, over width
1512   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 46, 53, (unsigned char*)outputImage, 9999, 0);
1513   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1514
1515   // 0 x 0 input image:
1516   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, 0, (unsigned char*)outputImage, 200, 99);
1517   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1518
1519   END_TEST;
1520 }
1521
1522 /**
1523  * @brief Test the small int (x,y) tuple.
1524  */
1525 int UtcDaliImageOperationsUint16Pair(void)
1526 {
1527   Uint16Pair vec1(2, 3);
1528
1529   DALI_TEST_EQUALS(vec1.GetWidth(), (uint16_t)2, TEST_LOCATION);
1530   DALI_TEST_EQUALS(vec1.GetX(), (uint16_t)2, TEST_LOCATION);
1531
1532   DALI_TEST_EQUALS(vec1.GetHeight(), (uint16_t)3, TEST_LOCATION);
1533   DALI_TEST_EQUALS(vec1.GetY(), (uint16_t)3, TEST_LOCATION);
1534
1535   Uint16Pair vec1Copy = vec1;
1536
1537   DALI_TEST_EQUALS(vec1Copy.GetWidth(), (uint16_t)2, TEST_LOCATION);
1538   DALI_TEST_EQUALS(vec1Copy.GetX(), (uint16_t)2, TEST_LOCATION);
1539
1540   DALI_TEST_EQUALS(vec1Copy.GetHeight(), (uint16_t)3, TEST_LOCATION);
1541   DALI_TEST_EQUALS(vec1Copy.GetY(), (uint16_t)3, TEST_LOCATION);
1542
1543   Uint16Pair vec2(65535u, 65535u);
1544
1545   DALI_TEST_EQUALS(vec2.GetX(), (uint16_t)65535u, TEST_LOCATION);
1546   DALI_TEST_EQUALS(vec2.GetY(), (uint16_t)65535u, TEST_LOCATION);
1547
1548   END_TEST;
1549 }
1550
1551 /**
1552  * @brief Test the four-tap linear blending for single-byte modes.
1553  */
1554 int UtcDaliImageOperationsBilinearFilter1BPP(void)
1555 {
1556   // Zeros blend to zero:
1557   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 0, 0), TEST_LOCATION);
1558   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 32768, 0), TEST_LOCATION);
1559   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 65535, 0), TEST_LOCATION);
1560   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 0, 32768), TEST_LOCATION);
1561   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 0, 65535), TEST_LOCATION);
1562
1563   // Ones and zeros average to 0.5:
1564   DALI_TEST_EQUALS(127u, BilinearFilter1Component(255, 0, 0, 255, 32768, 32768), TEST_LOCATION);
1565   DALI_TEST_EQUALS(127u, BilinearFilter1Component(0, 255, 0, 255, 32768, 32768), TEST_LOCATION);
1566
1567   // Quarters ones average to 0.25:
1568   DALI_TEST_EQUALS(64u, BilinearFilter1Component(255, 0, 0, 0, 32768, 32768), TEST_LOCATION);
1569   DALI_TEST_EQUALS(64u, BilinearFilter1Component(0, 255, 0, 0, 32768, 32768), TEST_LOCATION);
1570   DALI_TEST_EQUALS(64u, BilinearFilter1Component(0, 0, 255, 0, 32768, 32768), TEST_LOCATION);
1571   DALI_TEST_EQUALS(64u, BilinearFilter1Component(0, 0, 0, 255, 32768, 32768), TEST_LOCATION);
1572
1573   // Horizontal blends:
1574   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 255, 0, 255, 0, 32768), TEST_LOCATION);
1575   for(unsigned y = 0; y < 65536u; y += 256)
1576   {
1577     // Vertical blends don't change result in this case as there is no vertical gradient in inputs:
1578     DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 255, 0, 255, 0, y), TEST_LOCATION);
1579   }
1580   DALI_TEST_EQUALS(5u, BilinearFilter1Component(0, 255, 0, 255, 1233, 32768), TEST_LOCATION);
1581   DALI_TEST_EQUALS(29u, BilinearFilter1Component(0, 255, 0, 255, 7539, 32768), TEST_LOCATION);
1582   DALI_TEST_EQUALS(29u, BilinearFilter1Component(0, 255, 0, 255, 7539, 32768), TEST_LOCATION);
1583   DALI_TEST_EQUALS(67u, BilinearFilter1Component(0, 255, 0, 255, 17291, 32768), TEST_LOCATION);
1584   DALI_TEST_EQUALS(123u, BilinearFilter1Component(0, 255, 0, 255, 31671, 32768), TEST_LOCATION);
1585   DALI_TEST_EQUALS(184u, BilinearFilter1Component(0, 255, 0, 255, 47231, 32768), TEST_LOCATION);
1586   DALI_TEST_EQUALS(207u, BilinearFilter1Component(0, 255, 0, 255, 53129, 32768), TEST_LOCATION);
1587   DALI_TEST_EQUALS(239u, BilinearFilter1Component(0, 255, 0, 255, 61392, 32768), TEST_LOCATION);
1588   DALI_TEST_EQUALS(255u, BilinearFilter1Component(0, 255, 0, 255, 65535, 32768), TEST_LOCATION);
1589
1590   // Vertical Blends:
1591   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 255, 255, 32768, 0), TEST_LOCATION);
1592   DALI_TEST_EQUALS(60u, BilinearFilter1Component(0, 0, 255, 255, 32768, 15379), TEST_LOCATION);
1593   DALI_TEST_EQUALS(130u, BilinearFilter1Component(0, 0, 255, 255, 32768, 33451), TEST_LOCATION);
1594   DALI_TEST_EQUALS(186u, BilinearFilter1Component(0, 0, 255, 255, 32768, 47836), TEST_LOCATION);
1595   DALI_TEST_EQUALS(244u, BilinearFilter1Component(0, 0, 255, 255, 32768, 62731), TEST_LOCATION);
1596   DALI_TEST_EQUALS(255u, BilinearFilter1Component(0, 0, 255, 255, 32768, 65535), TEST_LOCATION);
1597
1598   END_TEST;
1599 }