Formatting automated-tests
[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.Reserve(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.PushBack(PixelRGBA8888((red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u, (alpha1 + alpha2) >> 1u));
133   }
134
135   for(size_t i = scanlineLength / 2; i < reference.Capacity(); ++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.Reserve(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.PushBack(PixelRGB565((red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u));
167   }
168
169   for(size_t i = scanlineLength / 2; i < reference.Capacity(); ++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.Reserve(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.PushBack((c11 + c21) >> 1u);
201     reference.PushBack((c12 + c22) >> 1u);
202   }
203
204   for(size_t i = scanlineLength; i < reference.Capacity(); ++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 * 2);
216   reference.Reserve(scanlineLength + 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.PushBack((c1 + c2) >> 1u);
232   }
233
234   for(size_t i = scanlineLength; i < reference.Capacity(); ++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.Reserve(scanlineLength);
248   scanline2.Reserve(scanlineLength);
249   reference.Reserve(scanlineLength + 32);
250   output.Reserve(scanlineLength + 32);
251
252   for(size_t i = scanlineLength; i < output.Capacity(); ++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.PushBack(PixelRGBA8888(red1, green1, blue1, alpha1));
274     scanline2.PushBack(PixelRGBA8888(red2, green2, blue2, alpha2));
275
276     // Average the two pixels manually as a reference:
277     reference.PushBack(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.Capacity(); 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;
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, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
414   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
415   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
416   DALI_TEST_EQUALS(check_4x4[0], (unsigned char)0x7f, TEST_LOCATION);
417
418   // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
419   unsigned char single_4x4[16 * 3] = {
420     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};
421   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
422   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
423   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
424   DALI_TEST_EQUALS(single_4x4[0], (unsigned char)0xf, TEST_LOCATION);
425
426   // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
427   // (white pixel at bottom-right of image)
428   unsigned char single_4x4_2[16 * 3] = {
429     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};
430   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4_2, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
431   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
432   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
433   DALI_TEST_EQUALS(single_4x4_2[0], (unsigned char)0xf, TEST_LOCATION);
434
435   // Build a larger ~600 x ~600 uniform magenta image for tests which only test output dimensions:
436
437   unsigned char magenta_600_x_600[608 * 608 * 3];
438   for(unsigned int i = 0; i < sizeof(magenta_600_x_600); i += 3)
439   {
440     magenta_600_x_600[i]     = 0xff;
441     magenta_600_x_600[i + 1] = 0;
442     magenta_600_x_600[i + 2] = 0xff;
443   }
444
445   // Scaling to 0 x 0 should stop at 1 x 1:
446   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
447   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
448   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
449
450   // Scaling to 1 x 1 should hit 1 x 1:
451   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 608, 608, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
452   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
453   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
454
455   // Scaling to original dimensions should NOP:
456   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 384, BoxDimensionTestBoth, outWidth, outHeight);
457   DALI_TEST_EQUALS(outWidth, 384u, TEST_LOCATION);
458   DALI_TEST_EQUALS(outHeight, 384u, TEST_LOCATION);
459
460   // More dimension tests:
461
462   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 44, 11, BoxDimensionTestBoth, outWidth, outHeight);
463   DALI_TEST_EQUALS(outWidth, 44u, TEST_LOCATION);
464   DALI_TEST_EQUALS(outHeight, 44u, TEST_LOCATION);
465
466   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 3, 48, BoxDimensionTestBoth, outWidth, outHeight);
467   DALI_TEST_EQUALS(outWidth, 48u, TEST_LOCATION);
468   DALI_TEST_EQUALS(outHeight, 48u, TEST_LOCATION);
469
470   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 3, 3, BoxDimensionTestBoth, outWidth, outHeight);
471   DALI_TEST_CHECK(outWidth == 3u && outHeight == 3u);
472
473   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 320, 320, 5, 5, BoxDimensionTestBoth, outWidth, outHeight);
474   DALI_TEST_CHECK(outWidth == 5u && outHeight == 5u);
475
476   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 448, 448, 7, 7, BoxDimensionTestBoth, outWidth, outHeight);
477   DALI_TEST_CHECK(outWidth == 7u && outHeight == 7u);
478
479   Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 11, 11, BoxDimensionTestBoth, outWidth, outHeight);
480   DALI_TEST_CHECK(outWidth == 11u && outHeight == 11u);
481
482   // Check that no pixel values were modified by the repeated averaging of identical pixels in tests above:
483   unsigned int numNonMagenta = 0u;
484   for(unsigned i = 0; i < sizeof(magenta_600_x_600); i += 3)
485   {
486     numNonMagenta += magenta_600_x_600[i] == 0xff && magenta_600_x_600[i + 1] == 0x00 && magenta_600_x_600[i + 2] == 0xff ? 0 : 1;
487   }
488   DALI_TEST_EQUALS(numNonMagenta, 0u, TEST_LOCATION);
489
490   END_TEST;
491 }
492
493 /**
494  * @brief Test that resizing RGBA8888 images as raw pixel arrays produces a result of the correct dimensions.
495  */
496 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)
497 {
498   unsigned int resultingWidth = -1, resultingHeight = -1;
499   Dali::Internal::Platform::DownscaleInPlacePow2RGBA8888(
500     reinterpret_cast<unsigned char*>(pixels),
501     inputWidth,
502     inputHeight,
503     desiredWidth,
504     desiredHeight,
505     BoxDimensionTestBoth,
506     resultingWidth,
507     resultingHeight);
508
509   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
510   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
511 }
512
513 /**
514  * @brief Test that resizing RGB565 images as raw pixel arrays produces a result of the correct dimensions.
515  */
516 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)
517 {
518   unsigned int resultingWidth = -1, resultingHeight = -1;
519   Dali::Internal::Platform::DownscaleInPlacePow2RGB565(
520     reinterpret_cast<unsigned char*>(pixels),
521     inputWidth,
522     inputHeight,
523     desiredWidth,
524     desiredHeight,
525     BoxDimensionTestBoth,
526     resultingWidth,
527     resultingHeight);
528
529   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
530   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
531 }
532
533 /**
534  * @brief Test that resizing 2-byte-per-pixel images as raw pixel arrays produces a result of the correct dimensions.
535  */
536 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)
537 {
538   unsigned int resultingWidth = -1, resultingHeight = -1;
539   Dali::Internal::Platform::DownscaleInPlacePow2ComponentPair(
540     pixels,
541     inputWidth,
542     inputHeight,
543     desiredWidth,
544     desiredHeight,
545     BoxDimensionTestBoth,
546     resultingWidth,
547     resultingHeight);
548
549   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
550   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
551 }
552
553 /**
554  * @brief Test that resizing single-byte-per-pixel images as raw pixel arrays produces a result of the correct dimensions.
555  */
556 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)
557 {
558   unsigned int resultingWidth = -1, resultingHeight = -1;
559   Dali::Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(
560     pixels,
561     inputWidth,
562     inputHeight,
563     desiredWidth,
564     desiredHeight,
565     BoxDimensionTestBoth,
566     resultingWidth,
567     resultingHeight);
568
569   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
570   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
571 }
572
573 /**
574  * @brief Test downscaling of RGBA8888 images in raw image arrays.
575  */
576 int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888(void)
577 {
578   uint32_t image[608 * 608];
579   for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i)
580   {
581     image[i] = 0xffffffff;
582   }
583   unsigned char* const pixels         = reinterpret_cast<unsigned char*>(image);
584   unsigned int         resultingWidth = -1, resultingHeight = -1;
585
586   // Test downscaling where the input size is an exact multiple of the desired size:
587   // (We expect a perfect result here)
588
589   DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight);
590   DALI_TEST_EQUALS(resultingWidth, 75u, TEST_LOCATION);
591   DALI_TEST_EQUALS(resultingHeight, 75u, TEST_LOCATION);
592
593   DownscaleInPlacePow2RGBA8888(pixels, 512, 512, 16, 16, BoxDimensionTestBoth, resultingWidth, resultingHeight);
594   DALI_TEST_EQUALS(resultingWidth, 16u, TEST_LOCATION);
595   DALI_TEST_EQUALS(resultingHeight, 16u, TEST_LOCATION);
596
597   DownscaleInPlacePow2RGBA8888(pixels, 512, 64, 16, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight);
598   DALI_TEST_EQUALS(resultingWidth, 16u, TEST_LOCATION);
599   DALI_TEST_EQUALS(resultingHeight, 2u, TEST_LOCATION);
600
601   DownscaleInPlacePow2RGBA8888(pixels, 64, 1024, 4, 64, BoxDimensionTestBoth, resultingWidth, resultingHeight);
602   DALI_TEST_EQUALS(resultingWidth, 4u, TEST_LOCATION);
603   DALI_TEST_EQUALS(resultingHeight, 64u, TEST_LOCATION);
604
605   // Test downscaling where the input size is slightly off being an exact multiple of the desired size:
606   // (We expect a perfect match at the end because of rounding-down to an even width and height at each step)
607
608   DownscaleInPlacePow2RGBA8888(pixels, 601, 603, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight);
609   DALI_TEST_EQUALS(resultingWidth, 75u, TEST_LOCATION);
610   DALI_TEST_EQUALS(resultingHeight, 75u, TEST_LOCATION);
611
612   DownscaleInPlacePow2RGBA8888(pixels, 736 + 1, 352 + 3, 23, 11, BoxDimensionTestBoth, resultingWidth, resultingHeight);
613   DALI_TEST_EQUALS(resultingWidth, 23u, TEST_LOCATION);
614   DALI_TEST_EQUALS(resultingHeight, 11u, TEST_LOCATION);
615
616   DownscaleInPlacePow2RGBA8888(pixels, 384 + 3, 896 + 1, 3, 7, BoxDimensionTestBoth, resultingWidth, resultingHeight);
617   DALI_TEST_EQUALS(resultingWidth, 3u, TEST_LOCATION);
618   DALI_TEST_EQUALS(resultingHeight, 7u, TEST_LOCATION);
619
620   // Test downscales with source dimensions which are under a nice power of two by one:
621
622   // The target is hit exactly due to losing spare columns or rows at each iteration:
623   DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 7, 3, BoxDimensionTestBoth, resultingWidth, resultingHeight);
624   DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
625   DALI_TEST_EQUALS(resultingHeight, 3u, TEST_LOCATION);
626
627   // 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.
628   DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 4, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight);
629   DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
630   DALI_TEST_EQUALS(resultingHeight, 3u, TEST_LOCATION);
631
632   // Should stop at almost twice the requested dimensions:
633   DownscaleInPlacePow2RGBA8888(pixels, 15, 127, 4, 32, BoxDimensionTestBoth, resultingWidth, resultingHeight);
634   DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
635   DALI_TEST_EQUALS(resultingHeight, 63u, TEST_LOCATION);
636
637   // Test downscales to 1 in one or both dimensions:
638   // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
639   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 512, 1, 1, 1, 1, TEST_LOCATION);
640   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 32, 16, 1, 16, 1, TEST_LOCATION);
641   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 32, 7, 1, 16, 1, TEST_LOCATION);
642   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 32, 7, 1, 16, 1, TEST_LOCATION);
643   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 32, 5, 1, 16, 1, TEST_LOCATION);
644   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 32, 3, 1, 16, 1, TEST_LOCATION);
645   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 32, 512, 1, 1, 1, 16, TEST_LOCATION);
646   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 32, 512, 1, 16, 1, 16, TEST_LOCATION);
647   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 32, 512, 1, 3, 1, 16, TEST_LOCATION);
648   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 33, 33, 1, 1, 1, 1, TEST_LOCATION);
649   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 17 * 19, 17 * 19, 1, 1, 1, 1, TEST_LOCATION);
650   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 33, 33, 3, 1, 4, 4, TEST_LOCATION);
651   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 33, 9, 3, 1, 4, 1, TEST_LOCATION);
652
653   // Test downscales to zero in one or both dimensions:
654   // Scaling should stop when one or both dimensions reach 1.
655   // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
656   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 512, 0, 0, 1, 1, TEST_LOCATION);
657   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 256, 0, 0, 2, 1, TEST_LOCATION);
658   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 128, 0, 0, 4, 1, TEST_LOCATION);
659   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 512, 16, 0, 0, 32, 1, TEST_LOCATION);
660   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 128, 512, 0, 0, 1, 4, TEST_LOCATION);
661   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 32, 512, 0, 0, 1, 16, TEST_LOCATION);
662   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 8, 512, 0, 0, 1, 64, TEST_LOCATION);
663   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 2, 512, 0, 0, 1, 256, TEST_LOCATION);
664
665   END_TEST;
666 }
667
668 /**
669  * @brief Test downscalings of RGBA8888 images in raw image arrays that should have no effect on the input.
670  */
671 int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888Nops(void)
672 {
673   uint32_t       image[608 * 608];
674   const uint32_t numPixels = sizeof(image) / sizeof(image[0]);
675   for(unsigned i = 0; i < numPixels; ++i)
676   {
677     image[i] = RandomPixelRGBA8888();
678   }
679   const uint32_t       imageHash      = HashPixels(image, numPixels);
680   unsigned char* const pixels         = reinterpret_cast<unsigned char*>(image);
681   unsigned int         resultingWidth = -1, resultingHeight = -1;
682
683   // Test downscales to the same size:
684   // The point is just to be sure the downscale is a NOP in this case:
685
686   DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 600, BoxDimensionTestBoth, resultingWidth, resultingHeight);
687   DALI_TEST_EQUALS(resultingWidth, 600u, TEST_LOCATION);
688   DALI_TEST_EQUALS(resultingHeight, 600u, TEST_LOCATION);
689
690   DownscaleInPlacePow2RGBA8888(pixels, 512, 128, 512, 128, BoxDimensionTestBoth, resultingWidth, resultingHeight);
691   DALI_TEST_EQUALS(resultingWidth, 512u, TEST_LOCATION);
692   DALI_TEST_EQUALS(resultingHeight, 128u, TEST_LOCATION);
693
694   DownscaleInPlacePow2RGBA8888(pixels, 17, 1001, 17, 1001, BoxDimensionTestBoth, resultingWidth, resultingHeight);
695   DALI_TEST_EQUALS(resultingWidth, 17u, TEST_LOCATION);
696   DALI_TEST_EQUALS(resultingHeight, 1001u, TEST_LOCATION);
697
698   // Test downscales that request a larger size (we never upscale so these are NOPs too):
699   // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
700   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 300, 300, 600, 600, 300, 300, TEST_LOCATION);
701   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 3, 127, 99, 599, 3, 127, TEST_LOCATION);
702   TestDownscaleOutputsExpectedDimensionsRGBA8888(image, 600, 600, 999, 999, 600, 600, TEST_LOCATION); //< checks no out of bounds mem access in this case
703
704   // Make sure that none of these NOP downscalings has affected the pixels of the image:
705   DALI_TEST_EQUALS(HashPixels(image, numPixels), imageHash, TEST_LOCATION);
706
707   END_TEST;
708 }
709
710 /**
711  * @brief Do additional downscaling testing using RGB565 images in raw image
712  * arrays to shake out differences relating to the pixel format.
713  */
714 int UtcDaliImageOperationsDownscaleInPlacePow2RGB565(void)
715 {
716   // Test that calling with null and zero parameters doesn't blow up:
717   unsigned int outWidth, outHeight;
718   DownscaleInPlacePow2RGB565(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
719
720   uint16_t image[608 * 608];
721   for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i)
722   {
723     image[i] = 0xffff;
724   }
725
726   // Do a straightforward test using an exact divisor target size:
727   TestDownscaleOutputsExpectedDimensionsRGB565(image, 600, 600, 75, 75, 75, 75, TEST_LOCATION);
728   // Test that a slightly smaller than possible to achieve target results in the
729   // next-higher exact divisor output image dimensions:
730   TestDownscaleOutputsExpectedDimensionsRGB565(image, 600, 600, 71, 69, 75, 75, TEST_LOCATION);
731   // Test that resizing from a starting size that is slightly larger than an exact
732   // multiple of the desired dimensions still results in the desired ones being
733   // reached:
734   // Parameters:                                       input-x  input-y, desired-x, desired-y, expected-x, expected-y
735   TestDownscaleOutputsExpectedDimensionsRGB565(image, 600 + 1, 600 + 1, 75, 75, 75, 75, TEST_LOCATION);
736   TestDownscaleOutputsExpectedDimensionsRGB565(image, 256 + 1, 512 + 1, 2, 4, 2, 4, TEST_LOCATION);
737   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 1, 128 + 1, 16, 4, 16, 4, TEST_LOCATION);
738   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 1, 64 + 1, 16, 2, 16, 2, TEST_LOCATION);
739   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 3, 512 + 3, 16, 16, 16, 16, TEST_LOCATION);
740   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 3, 256 + 3, 16, 8, 16, 8, TEST_LOCATION);
741   TestDownscaleOutputsExpectedDimensionsRGB565(image, 256 + 3, 512 + 3, 4, 8, 4, 8, TEST_LOCATION);
742   TestDownscaleOutputsExpectedDimensionsRGB565(image, 256 + 7, 512 + 7, 4, 8, 4, 8, TEST_LOCATION);
743   TestDownscaleOutputsExpectedDimensionsRGB565(image, 256 + 7, 512 + 7, 2, 4, 2, 4, TEST_LOCATION);
744   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 7, 128 + 7, 16, 4, 16, 4, TEST_LOCATION);
745   TestDownscaleOutputsExpectedDimensionsRGB565(image, 512 + 7, 64 + 7, 16, 2, 16, 2, TEST_LOCATION);
746
747   END_TEST;
748 }
749
750 /**
751  * @brief Do additional downscaling testing using 2-byte-per-pixel images in
752  * raw image arrays to shake out differences relating to the pixel format.
753  */
754 int UtcDaliImageOperationsDownscaleInPlacePow2ComponentPair(void)
755 {
756   // Simple test that a null pointer does not get dereferenced in the function:
757   unsigned int outWidth, outHeight;
758   DownscaleInPlacePow2ComponentPair(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
759
760   // Simple tests of dimensions output:
761
762   uint8_t image[608 * 608 * 2];
763   for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i)
764   {
765     image[i] = 0xff;
766   }
767
768   TestDownscaleOutputsExpectedDimensions2ComponentPair(image,
769                                                        600,
770                                                        600, //< Input dimensions
771                                                        37,
772                                                        37, //< Requested dimensions
773                                                        37,
774                                                        37, //< Expected output dimensions
775                                                        TEST_LOCATION);
776   TestDownscaleOutputsExpectedDimensions2ComponentPair(image,
777                                                        600,
778                                                        600, //< Input dimensions
779                                                        34,
780                                                        35, //< Requested dimensions to scale-down to
781                                                        37,
782                                                        37, //< Expected output dimensions achieved
783                                                        TEST_LOCATION);
784   ///@note: No need to be as comprehensive as with RGB888 and RGBA8888 as the logic is shared.
785
786   END_TEST;
787 }
788
789 /**
790  * @brief Do additional downscaling testing using 1-byte-per-pixel images in
791  * raw image arrays to shake out differences relating to the pixel format.
792  */
793 int UtcDaliImageOperationsDownscaleInPlacePow2SingleBytePerPixel(void)
794 {
795   // Simple test that a null pointer does not get dereferenced in the function:
796   unsigned int outWidth, outHeight;
797   DownscaleInPlacePow2SingleBytePerPixel(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
798
799   // Tests of output dimensions from downscaling:
800   uint8_t image[608 * 608];
801   for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i)
802   {
803     image[i] = 0xff;
804   }
805
806   TestDownscaleOutputsExpectedDimensionsSingleComponent(image,
807                                                         600,
808                                                         300, //< Input dimensions
809                                                         150,
810                                                         75, //< Requested dimensions to scale-down to
811                                                         150,
812                                                         75, //< Expected output dimensions achieved
813                                                         TEST_LOCATION);
814   TestDownscaleOutputsExpectedDimensionsSingleComponent(image, 577, 411, 142, 99, 144, 102, TEST_LOCATION);
815
816   END_TEST;
817 }
818
819 /**
820  * @brief Test the function for averaging pairs of pixels on a scanline.
821  */
822 int UtcDaliImageOperationsHalveScanlineInPlaceRGB888(void)
823 {
824   // Red and cyan, averaging to grey:
825   unsigned char shortEven[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
826   unsigned char shortOdd[]  = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xC, 0xC, 0xC};
827
828   Dali::Internal::Platform::HalveScanlineInPlaceRGB888(shortEven, 4u);
829   Dali::Internal::Platform::HalveScanlineInPlaceRGB888(shortOdd, 4u);
830
831   for(unsigned i = 0; i < (sizeof(shortEven) >> 1u); ++i)
832   {
833     DALI_TEST_EQUALS(unsigned(shortEven[i]), 0x7fu, TEST_LOCATION);
834     DALI_TEST_EQUALS(unsigned(shortOdd[i]), 0x7fu, TEST_LOCATION);
835   }
836
837   END_TEST;
838 }
839
840 /**
841  * @brief Test the function for averaging pairs of pixels on a scanline.
842  */
843 int UtcDaliImageOperationsHalveScanlineInPlaceRGBA8888(void)
844 {
845   const size_t           scanlineLength = 4096u;
846   Dali::Vector<uint32_t> scanline;
847   Dali::Vector<uint32_t> reference;
848   SetupScanlineForHalvingTestsRGBA8888(scanlineLength, scanline, reference);
849
850   HalveScanlineInPlaceRGBA8888((uint8_t*)&scanline[0], scanlineLength);
851
852   // Check that the halving matches the independently calculated reference:
853   size_t numMatches = 0;
854   for(int i = 0, length = reference.Size(); i < length; ++i)
855   {
856     DALI_TEST_EQUALS(scanline[i], reference[i], TEST_LOCATION);
857     numMatches += scanline[i] == reference[i];
858   }
859   DALI_TEST_EQUALS(numMatches, scanlineLength / 2, TEST_LOCATION);
860
861   // Test for no beyond-bounds writes:
862   for(size_t i = scanlineLength / 2; i < reference.Capacity(); ++i)
863   {
864     DALI_TEST_EQUALS(reference[i], (uint32_t)0xEEEEEEEE, TEST_LOCATION);
865   }
866
867   END_TEST;
868 }
869
870 /**
871  * @brief Test the function for averaging pairs of pixels on a scanline.
872  */
873 int UtcDaliImageOperationsHalveScanlineInPlaceRGB565(void)
874 {
875   const size_t           scanlineLength = 4096u;
876   Dali::Vector<uint16_t> scanline;
877   Dali::Vector<uint16_t> reference;
878   SetupScanlineForHalvingTestsRGB565(scanlineLength, scanline, reference);
879
880   HalveScanlineInPlaceRGB565((unsigned char*)(&scanline[0]), scanlineLength);
881
882   // Check output against reference:
883   size_t numMatches = 0;
884   for(int i = 0, length = reference.Size(); i < length; ++i)
885   {
886     DALI_TEST_EQUALS(scanline[i], reference[i], TEST_LOCATION);
887     numMatches += scanline[i] == reference[i];
888   }
889   DALI_TEST_EQUALS(numMatches, scanlineLength / 2, TEST_LOCATION);
890
891   // Test for no beyond-bounds writes:
892   for(size_t i = scanlineLength / 2; i < reference.Capacity(); ++i)
893   {
894     DALI_TEST_EQUALS(reference[i], (uint16_t)0xEEEE, TEST_LOCATION);
895   }
896
897   END_TEST;
898 }
899
900 /**
901  * @brief Test the function for averaging pairs of pixels on a scanline.
902  */
903 int UtcDaliImageOperationsHalveScanlineInPlace2Bytes(void)
904 {
905   const size_t          scanlineLength = 4096u;
906   Dali::Vector<uint8_t> scanline;
907   Dali::Vector<uint8_t> reference;
908   SetupScanlineForHalvingTests2Bytes(scanlineLength, scanline, reference);
909
910   HalveScanlineInPlace2Bytes(&scanline[0], scanlineLength);
911
912   // Test the output against the reference (no differences):
913   size_t numMatches = 0;
914   for(int i = 0, length = reference.Size(); i < length; ++i)
915   {
916     DALI_TEST_EQUALS(1u * scanline[i], 1u * reference[i], TEST_LOCATION);
917     numMatches += scanline[i] == reference[i];
918   }
919   // The number of matching bytes should be double the number of pixels, which happens to be the original scanline length in pixels:
920   DALI_TEST_EQUALS(numMatches, scanlineLength, TEST_LOCATION);
921
922   END_TEST;
923 }
924
925 /**
926  * @brief Test the function for averaging pairs of pixels on a scanline.
927  */
928 int UtcDaliImageOperationsHalveScanlineInPlace1Byte(void)
929 {
930   const size_t          scanlineLength = 4096u;
931   Dali::Vector<uint8_t> scanline;
932   Dali::Vector<uint8_t> reference;
933   SetupScanlineForHalvingTests1Byte(scanlineLength, scanline, reference);
934
935   HalveScanlineInPlace1Byte(&scanline[0], scanlineLength);
936
937   // Test the reference matches the output:
938   size_t numMatches = 0;
939   for(int i = 0, length = reference.Size(); i < length; ++i)
940   {
941     DALI_TEST_EQUALS(1u * scanline[i], 1u * reference[i], TEST_LOCATION);
942     numMatches += scanline[i] == reference[i];
943   }
944   DALI_TEST_EQUALS(numMatches, scanlineLength / 2, TEST_LOCATION);
945
946   END_TEST;
947 }
948
949 /**
950  * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
951  */
952 int UtcDaliImageOperationsAverageScanlines1(void)
953 {
954   // Red and cyan, averaging to grey:
955   unsigned char shortEven1[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
956   unsigned char shortEven2[] = {0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0};
957   unsigned char outputBuffer[sizeof(shortEven1)];
958
959   AverageScanlines1(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1));
960   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
961   {
962     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION);
963   }
964
965   // Longer test reusing RGBA setup/test logic:
966   const size_t           scanlineLength = 4096u;
967   Dali::Vector<uint32_t> scanline1;
968   Dali::Vector<uint32_t> scanline2;
969   Dali::Vector<uint32_t> reference;
970   Dali::Vector<uint32_t> output;
971   SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
972
973   AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
974
975   // Check the output matches the independently generated reference:
976   size_t numMatches = 0;
977   MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
978   DALI_TEST_EQUALS(numMatches, reference.Capacity(), TEST_LOCATION);
979
980   END_TEST;
981 }
982
983 /**
984  * @brief Test the function for averaging vertically-adjacent pairs of 2-byte-per-pixel pixels on a scanline.
985  */
986 int UtcDaliImageOperationsAverageScanlines2(void)
987 {
988   // Red and cyan, averaging to grey:
989   unsigned char shortEven1[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
990   unsigned char shortEven2[] = {0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0};
991   unsigned char outputBuffer[sizeof(shortEven1)];
992
993   AverageScanlines2(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) / 2);
994
995   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
996   {
997     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION);
998   }
999
1000   // Longer test reusing RGBA setup/test logic:
1001   const size_t           scanlineLength = 4096u;
1002   Dali::Vector<uint32_t> scanline1;
1003   Dali::Vector<uint32_t> scanline2;
1004   Dali::Vector<uint32_t> reference;
1005   Dali::Vector<uint32_t> output;
1006   SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1007
1008   AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
1009
1010   // Check the output matches the independently generated reference:
1011   size_t numMatches = 0;
1012   MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1013   DALI_TEST_EQUALS(numMatches, reference.Capacity(), TEST_LOCATION);
1014
1015   END_TEST;
1016 }
1017
1018 /**
1019  * @brief Test the function for averaging vertically-adjacent pairs of RGB888 pixels on a scanline.
1020  */
1021 int UtcDaliImageOperationsAverageScanlines3(void)
1022 {
1023   // Red and cyan, averaging to grey:
1024   unsigned char shortEven1[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
1025   unsigned char shortEven2[] = {0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0};
1026   unsigned char outputBuffer[sizeof(shortEven1)];
1027
1028   AverageScanlines3(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) / 3);
1029   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
1030   {
1031     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION);
1032   }
1033
1034   // Longer test reusing RGBA setup/test logic:
1035   const size_t           scanlineLength = 3 * 4 * 90u;
1036   Dali::Vector<uint32_t> scanline1;
1037   Dali::Vector<uint32_t> scanline2;
1038   Dali::Vector<uint32_t> reference;
1039   Dali::Vector<uint32_t> output;
1040   SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1041
1042   AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
1043
1044   // Check the output matches the independently generated reference:
1045   size_t numMatches = 0;
1046   MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1047   DALI_TEST_EQUALS(numMatches, reference.Capacity(), TEST_LOCATION);
1048
1049   END_TEST;
1050 }
1051
1052 /**
1053  * @brief Test the function for averaging vertically-adjacent pairs of RGBA8888 pixels on a scanline.
1054  */
1055 int UtcDaliImageOperationsAverageScanlinesRGBA8888(void)
1056 {
1057   const size_t           scanlineLength = 4096u;
1058   Dali::Vector<uint32_t> scanline1;
1059   Dali::Vector<uint32_t> scanline2;
1060   Dali::Vector<uint32_t> reference;
1061   Dali::Vector<uint32_t> output;
1062   SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1063
1064   AverageScanlinesRGBA8888((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength);
1065
1066   // Check the output matches the independently generated reference:
1067   size_t numMatches = 0;
1068   MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1069   DALI_TEST_EQUALS(numMatches, reference.Capacity(), TEST_LOCATION);
1070
1071   END_TEST;
1072 }
1073
1074 /**
1075  * @brief Test the function for averaging vertically-adjacent pairs of RGB565 pixels on a scanline.
1076  */
1077 int UtcDaliImageOperationsAverageScanlinesRGB565(void)
1078 {
1079   // Red and cyan, averaging to grey:
1080   const uint16_t shortEven1[] = {0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xBEEF, 0xBEEF};
1081   const uint16_t shortEven2[] = {0x7ff, 0x7ff, 0x7ff, 0x7ff, 0x7ff, 0x7ff, 0xBEEF, 0xBEEF};
1082   const size_t   arrayLength  = sizeof(shortEven1) / sizeof(shortEven1[0]) - 2;
1083   uint16_t       outputBuffer[arrayLength + 2];
1084   outputBuffer[arrayLength]     = 0xDEAD;
1085   outputBuffer[arrayLength + 1] = 0xDEAD;
1086
1087   Dali::Internal::Platform::AverageScanlinesRGB565((const unsigned char*)shortEven1, (const unsigned char*)shortEven2, (unsigned char*)outputBuffer, arrayLength);
1088   for(unsigned i = 0; i < arrayLength; ++i)
1089   {
1090     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0xffff - (1u << 15) - (1u << 10) - (1u << 4), TEST_LOCATION);
1091   }
1092
1093   // Check for buffer overrun:
1094   DALI_TEST_EQUALS(outputBuffer[arrayLength], (uint16_t)0xDEAD, TEST_LOCATION);
1095   DALI_TEST_EQUALS(outputBuffer[arrayLength + 1], (uint16_t)0xDEAD, TEST_LOCATION);
1096
1097   END_TEST;
1098 }
1099
1100 namespace
1101 {
1102 void MakeSingleColorImageRGBA8888(unsigned int width, unsigned int height, uint32_t* inputImage)
1103 {
1104   const uint32_t inPixel = PixelRGBA8888(255, 192, 128, 64);
1105   for(unsigned int i = 0; i < width * height; ++i)
1106   {
1107     inputImage[i] = inPixel;
1108   }
1109 }
1110
1111 /*
1112  * @brief Make an image with a checkerboard pattern.
1113  * @note This is an easy pattern to scan for correctness after a downscaling test.
1114  */
1115 Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > MakeCheckerboardImageRGBA8888(unsigned int width, unsigned int height, unsigned int checkerSize)
1116 {
1117   const unsigned int                                    imageWidth  = width * checkerSize;
1118   const unsigned int                                    imageHeight = height * checkerSize;
1119   Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image       = new Dali::RefCountedVector<uint32_t>;
1120   image->GetVector().Resize(imageWidth * imageHeight);
1121
1122   uint32_t rowColor = 0xffffffff;
1123   for(unsigned int cy = 0; cy < height; ++cy)
1124   {
1125     rowColor            = rowColor == 0xffffffff ? 0xff000000 : 0xffffffff;
1126     uint32_t checkColor = rowColor;
1127     for(unsigned int cx = 0; cx < width; ++cx)
1128     {
1129       checkColor            = checkColor == 0xffffffff ? 0xff000000 : 0xffffffff;
1130       uint32_t paintedColor = checkColor;
1131       // Draw 3 special case checks as r,g,b:
1132       if(cx == 0 && cy == 0)
1133       {
1134         paintedColor = 0xff0000ff; // Red
1135       }
1136       else if(cx == 7 && cy == 0)
1137       {
1138         paintedColor = 0xff00ff00; // Green
1139       }
1140       else if(cx == 7 && cy == 7)
1141       {
1142         paintedColor = 0xffff0000; // blue
1143       }
1144       uint32_t* check = &image->GetVector()[(cy * checkerSize * imageWidth) + (cx * checkerSize)];
1145       for(unsigned int py = 0; py < checkerSize; ++py)
1146       {
1147         uint32_t* checkLine = check + py * imageWidth;
1148         for(unsigned int px = 0; px < checkerSize; ++px)
1149         {
1150           checkLine[px] = paintedColor;
1151         }
1152       }
1153     }
1154   }
1155
1156   return image;
1157 }
1158
1159 } // namespace
1160
1161 /**
1162  * @brief Test the right pixels are generated when downsampling a checkerboard into a small image.
1163  */
1164 int UtcDaliImageOperationsPointSampleCheckerboardRGBA888(void)
1165 {
1166   Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image         = MakeCheckerboardImageRGBA8888(8, 8, 32);
1167   const unsigned int                                    desiredWidth  = 8;
1168   const unsigned int                                    desiredHeight = 8;
1169
1170   uint32_t outputImage[desiredWidth * desiredHeight];
1171
1172   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)&image->GetVector()[0], 256, 256, (unsigned char*)outputImage, desiredWidth, desiredHeight);
1173
1174   DALI_TEST_EQUALS(outputImage[0], (uint32_t)0xff0000ff, TEST_LOCATION);         // < Red corner pixel
1175   DALI_TEST_EQUALS(outputImage[7], (uint32_t)0xff00ff00, TEST_LOCATION);         // < Green corner pixel
1176   DALI_TEST_EQUALS(outputImage[8 * 8 - 1], (uint32_t)0xffff0000, TEST_LOCATION); // < Blue corner pixel
1177
1178   DALI_TEST_EQUALS(outputImage[1], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1179   DALI_TEST_EQUALS(outputImage[2], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1180   DALI_TEST_EQUALS(outputImage[3], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1181   DALI_TEST_EQUALS(outputImage[4], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1182   DALI_TEST_EQUALS(outputImage[5], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1183   DALI_TEST_EQUALS(outputImage[6], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1184
1185   // Second scanline:
1186   DALI_TEST_EQUALS(outputImage[8 + 0], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1187   DALI_TEST_EQUALS(outputImage[8 + 1], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1188   DALI_TEST_EQUALS(outputImage[8 + 2], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1189   DALI_TEST_EQUALS(outputImage[8 + 3], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1190   DALI_TEST_EQUALS(outputImage[8 + 4], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1191   DALI_TEST_EQUALS(outputImage[8 + 5], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1192   DALI_TEST_EQUALS(outputImage[8 + 6], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1193   DALI_TEST_EQUALS(outputImage[8 + 7], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1194
1195   // Third scanline:
1196   DALI_TEST_EQUALS(outputImage[16 + 0], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1197   DALI_TEST_EQUALS(outputImage[16 + 1], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1198   DALI_TEST_EQUALS(outputImage[16 + 2], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1199   DALI_TEST_EQUALS(outputImage[16 + 3], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1200   DALI_TEST_EQUALS(outputImage[16 + 4], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1201   DALI_TEST_EQUALS(outputImage[16 + 5], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1202   DALI_TEST_EQUALS(outputImage[16 + 6], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1203   DALI_TEST_EQUALS(outputImage[16 + 7], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1204
1205   // ... could do more scanlines (there are 8)
1206
1207   // Sample a few more pixels:
1208
1209   // Diagonals:
1210   DALI_TEST_EQUALS(outputImage[24 + 3], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1211   DALI_TEST_EQUALS(outputImage[32 + 4], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1212   DALI_TEST_EQUALS(outputImage[40 + 5], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1213   DALI_TEST_EQUALS(outputImage[48 + 6], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1214   DALI_TEST_EQUALS(outputImage[24 + 4], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1215   DALI_TEST_EQUALS(outputImage[32 + 3], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1216   DALI_TEST_EQUALS(outputImage[40 + 2], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1217   DALI_TEST_EQUALS(outputImage[48 + 1], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1218   DALI_TEST_EQUALS(outputImage[56 + 0], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1219
1220   END_TEST;
1221 }
1222
1223 /**
1224  * @brief Test that a scaling preserves input color in destination image.
1225  */
1226 int UtcDaliImageOperationsPointSampleRGBA888PixelsCorrectColor(void)
1227 {
1228   const unsigned int inputWidth    = 137;
1229   const unsigned int inputHeight   = 571;
1230   const unsigned int desiredWidth  = 59;
1231   const unsigned int desiredHeight = 257;
1232
1233   uint32_t inputImage[inputWidth * inputHeight];
1234   MakeSingleColorImageRGBA8888(inputWidth, inputHeight, inputImage);
1235
1236   const size_t          outputBufferSize = desiredWidth * desiredHeight;
1237   std::vector<uint32_t> buffer;
1238   buffer.resize(outputBufferSize);
1239   uint32_t* outputImage = &buffer[0];
1240
1241   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, inputWidth, inputHeight, (unsigned char*)outputImage, desiredWidth, desiredHeight);
1242
1243   // Check that all the output pixels are the right color:
1244   const uint32_t reference           = inputImage[inputWidth * inputHeight / 2];
1245   unsigned int   differentColorCount = 0;
1246   for(unsigned int i = 0; i < desiredWidth * desiredHeight; ++i)
1247   {
1248     if(outputImage[i] != reference)
1249     {
1250       ++differentColorCount;
1251     }
1252   }
1253
1254   DALI_TEST_EQUALS(0U, differentColorCount, TEST_LOCATION);
1255
1256   END_TEST;
1257 }
1258
1259 /**
1260  * @brief Test that scaling down to a 1x1 image works.
1261  */
1262 int UtcDaliImageOperationsPointSampleRGBA888ScaleToSinglePixel(void)
1263 {
1264   const unsigned int desiredWidth  = 1;
1265   const unsigned int desiredHeight = 1;
1266
1267   uint32_t inputImage[1024 * 1024];
1268   MakeSingleColorImageRGBA8888(1024, 1024, inputImage);
1269   uint32_t outputImage = 0;
1270
1271   // Try several different starting image sizes:
1272
1273   // 1x1 -> 1x1:
1274   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1275   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1276   outputImage = 0;
1277
1278   // Single-pixel wide tall stripe:
1279   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1024, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1280   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1281   outputImage = 0;
1282
1283   // Single-pixel tall, wide strip:
1284   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1024, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1285   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1286   outputImage = 0;
1287
1288   // Square mid-size image:
1289   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1290   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1291   outputImage = 0;
1292
1293   // Wide mid-size image:
1294   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1295   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1296   outputImage = 0;
1297
1298   // Tall mid-size image:
1299   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 467, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1300   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1301   outputImage = 0;
1302
1303   // 0 x 0 input image (make sure output not written to):
1304   outputImage = 0xDEADBEEF;
1305   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1306   DALI_TEST_EQUALS(outputImage, (uint32_t)0xDEADBEEF, TEST_LOCATION);
1307   outputImage = 0;
1308
1309   END_TEST;
1310 }
1311
1312 /**
1313  * @brief Test that downsampling to 0 - area images is a NOP and does not modify the destination.
1314  * (edge-case)
1315  */
1316 int UtcDaliImageOperationsPointSampleRGBA888N(void)
1317 {
1318   uint32_t inputImage[128 * 128];
1319   MakeSingleColorImageRGBA8888(128, 128, inputImage);
1320   uint32_t outputImage[128 * 128];
1321   memset(outputImage, 0xaa, 128 * 128 * sizeof(uint32_t));
1322
1323   // Try several different starting image sizes:
1324
1325   // 1x1 -> 1x1:
1326   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, (unsigned char*)outputImage, 0, 0);
1327   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1328
1329   // Single-pixel wide tall stripe:
1330   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 102, (unsigned char*)outputImage, 0, 33);
1331   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1332
1333   // Single-pixel tall, wide strip:
1334   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 102, 1, (unsigned char*)outputImage, 0, 67);
1335   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1336
1337   // Square mid-size image:
1338   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, (unsigned char*)outputImage, 21, 0);
1339   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1340
1341   // Wide mid-size image to 0 height
1342   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, (unsigned char*)outputImage, 99, 0);
1343   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1344
1345   // Tall mid-size image to 0 height, over width
1346   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 46, (unsigned char*)outputImage, 9999, 0);
1347   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1348
1349   // 0 x 0 input image:
1350   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, (unsigned char*)outputImage, 200, 99);
1351   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1352
1353   END_TEST;
1354 }
1355
1356 /**
1357  * @brief Test the small int (x,y) tuple.
1358  */
1359 int UtcDaliImageOperationsUint16Pair(void)
1360 {
1361   Uint16Pair vec1(2, 3);
1362
1363   DALI_TEST_EQUALS(vec1.GetWidth(), (uint16_t)2, TEST_LOCATION);
1364   DALI_TEST_EQUALS(vec1.GetX(), (uint16_t)2, TEST_LOCATION);
1365
1366   DALI_TEST_EQUALS(vec1.GetHeight(), (uint16_t)3, TEST_LOCATION);
1367   DALI_TEST_EQUALS(vec1.GetY(), (uint16_t)3, TEST_LOCATION);
1368
1369   Uint16Pair vec1Copy = vec1;
1370
1371   DALI_TEST_EQUALS(vec1Copy.GetWidth(), (uint16_t)2, TEST_LOCATION);
1372   DALI_TEST_EQUALS(vec1Copy.GetX(), (uint16_t)2, TEST_LOCATION);
1373
1374   DALI_TEST_EQUALS(vec1Copy.GetHeight(), (uint16_t)3, TEST_LOCATION);
1375   DALI_TEST_EQUALS(vec1Copy.GetY(), (uint16_t)3, TEST_LOCATION);
1376
1377   Uint16Pair vec2(65535u, 65535u);
1378
1379   DALI_TEST_EQUALS(vec2.GetX(), (uint16_t)65535u, TEST_LOCATION);
1380   DALI_TEST_EQUALS(vec2.GetY(), (uint16_t)65535u, TEST_LOCATION);
1381
1382   END_TEST;
1383 }
1384
1385 /**
1386  * @brief Test the four-tap linear blending for single-byte modes.
1387  */
1388 int UtcDaliImageOperationsBilinearFilter1BPP(void)
1389 {
1390   // Zeros blend to zero:
1391   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 0, 0), TEST_LOCATION);
1392   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 32768, 0), TEST_LOCATION);
1393   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 65535, 0), TEST_LOCATION);
1394   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 0, 32768), TEST_LOCATION);
1395   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 0, 65535), TEST_LOCATION);
1396
1397   // Ones and zeros average to 0.5:
1398   DALI_TEST_EQUALS(127u, BilinearFilter1Component(255, 0, 0, 255, 32768, 32768), TEST_LOCATION);
1399   DALI_TEST_EQUALS(127u, BilinearFilter1Component(0, 255, 0, 255, 32768, 32768), TEST_LOCATION);
1400
1401   // Quarters ones average to 0.25:
1402   DALI_TEST_EQUALS(64u, BilinearFilter1Component(255, 0, 0, 0, 32768, 32768), TEST_LOCATION);
1403   DALI_TEST_EQUALS(64u, BilinearFilter1Component(0, 255, 0, 0, 32768, 32768), TEST_LOCATION);
1404   DALI_TEST_EQUALS(64u, BilinearFilter1Component(0, 0, 255, 0, 32768, 32768), TEST_LOCATION);
1405   DALI_TEST_EQUALS(64u, BilinearFilter1Component(0, 0, 0, 255, 32768, 32768), TEST_LOCATION);
1406
1407   // Horizontal blends:
1408   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 255, 0, 255, 0, 32768), TEST_LOCATION);
1409   for(unsigned y = 0; y < 65536u; y += 256)
1410   {
1411     // Vertical blends don't change result in this case as there is no vertical gradient in inputs:
1412     DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 255, 0, 255, 0, y), TEST_LOCATION);
1413   }
1414   DALI_TEST_EQUALS(5u, BilinearFilter1Component(0, 255, 0, 255, 1233, 32768), TEST_LOCATION);
1415   DALI_TEST_EQUALS(29u, BilinearFilter1Component(0, 255, 0, 255, 7539, 32768), TEST_LOCATION);
1416   DALI_TEST_EQUALS(29u, BilinearFilter1Component(0, 255, 0, 255, 7539, 32768), TEST_LOCATION);
1417   DALI_TEST_EQUALS(67u, BilinearFilter1Component(0, 255, 0, 255, 17291, 32768), TEST_LOCATION);
1418   DALI_TEST_EQUALS(123u, BilinearFilter1Component(0, 255, 0, 255, 31671, 32768), TEST_LOCATION);
1419   DALI_TEST_EQUALS(184u, BilinearFilter1Component(0, 255, 0, 255, 47231, 32768), TEST_LOCATION);
1420   DALI_TEST_EQUALS(207u, BilinearFilter1Component(0, 255, 0, 255, 53129, 32768), TEST_LOCATION);
1421   DALI_TEST_EQUALS(239u, BilinearFilter1Component(0, 255, 0, 255, 61392, 32768), TEST_LOCATION);
1422   DALI_TEST_EQUALS(255u, BilinearFilter1Component(0, 255, 0, 255, 65535, 32768), TEST_LOCATION);
1423
1424   // Vertical Blends:
1425   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 255, 255, 32768, 0), TEST_LOCATION);
1426   DALI_TEST_EQUALS(60u, BilinearFilter1Component(0, 0, 255, 255, 32768, 15379), TEST_LOCATION);
1427   DALI_TEST_EQUALS(130u, BilinearFilter1Component(0, 0, 255, 255, 32768, 33451), TEST_LOCATION);
1428   DALI_TEST_EQUALS(186u, BilinearFilter1Component(0, 0, 255, 255, 32768, 47836), TEST_LOCATION);
1429   DALI_TEST_EQUALS(244u, BilinearFilter1Component(0, 0, 255, 255, 32768, 62731), TEST_LOCATION);
1430   DALI_TEST_EQUALS(255u, BilinearFilter1Component(0, 0, 255, 255, 32768, 65535), TEST_LOCATION);
1431
1432   END_TEST;
1433 }