Merge "Fix crash issue when we decode some bmp" into 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;
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 = scanlineLength / 2; 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.Count(); ++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 = scanlineLength / 2; 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.Count(); ++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 = scanlineLength; 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 = scanlineLength / 2; i < length; ++i)
940   {
941     DALI_TEST_EQUALS(1u * scanline[i], 1u * reference[i], TEST_LOCATION);
942     numMatches += scanline[i] == reference[i];
943   }
944   // Only half will be matched
945   DALI_TEST_EQUALS(numMatches, scanlineLength / 2, TEST_LOCATION);
946
947   END_TEST;
948 }
949
950 /**
951  * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
952  */
953 int UtcDaliImageOperationsAverageScanlines1ExceptTest(void)
954 {
955   // Edge cases for averagescanlines1:
956   unsigned char shortEven1[]   = {0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x02, 0x03, 0x00, 0x01};
957   unsigned char shortEven2[]   = {0x00, 0xff, 0x00, 0xff, 0x01, 0x01, 0xff, 0xfe, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x03, 0x02};
958   unsigned char expectBuffer[] = {0x00, 0x7f, 0x7f, 0xff, 0x80, 0x7f, 0x80, 0x7f, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
959   unsigned char outputBuffer[sizeof(shortEven1)];
960
961   AverageScanlines1(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1));
962   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
963   {
964     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), unsigned(expectBuffer[i]), TEST_LOCATION);
965   }
966
967   END_TEST;
968 }
969
970 /**
971  * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
972  */
973 int UtcDaliImageOperationsAverageScanlines1(void)
974 {
975   // Red and cyan, averaging to grey:
976   unsigned char shortEven1[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
977   unsigned char shortEven2[] = {0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0};
978   unsigned char outputBuffer[sizeof(shortEven1)];
979
980   AverageScanlines1(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1));
981   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
982   {
983     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION);
984   }
985
986   // Longer test reusing RGBA setup/test logic:
987   {
988     const size_t           scanlineLength = 4096u;
989     Dali::Vector<uint32_t> scanline1;
990     Dali::Vector<uint32_t> scanline2;
991     Dali::Vector<uint32_t> reference;
992     Dali::Vector<uint32_t> output;
993     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
994
995     AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
996
997     // Check the output matches the independently generated reference:
998     size_t numMatches = 0;
999     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1000     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1001   }
1002
1003   // Longer test reusing RGBA setup/test logic with none-8-divisable length
1004   {
1005     const size_t           scanlineLength = 1003u;
1006     Dali::Vector<uint32_t> scanline1;
1007     Dali::Vector<uint32_t> scanline2;
1008     Dali::Vector<uint32_t> reference;
1009     Dali::Vector<uint32_t> output;
1010     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1011
1012     AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
1013
1014     // Check the output matches the independently generated reference:
1015     size_t numMatches = 0;
1016     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1017     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1018   }
1019
1020   // Very short test reusing RGBA setup/test logic with less-than-8 length
1021   {
1022     const size_t           scanlineLength = 1003u;
1023     Dali::Vector<uint32_t> scanline1;
1024     Dali::Vector<uint32_t> scanline2;
1025     Dali::Vector<uint32_t> reference;
1026     Dali::Vector<uint32_t> output;
1027     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1028
1029     AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
1030
1031     // Check the output matches the independently generated reference:
1032     size_t numMatches = 0;
1033     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1034     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1035   }
1036
1037   END_TEST;
1038 }
1039
1040 /**
1041  * @brief Test the function for averaging vertically-adjacent pairs of 2-byte-per-pixel pixels on a scanline.
1042  */
1043 int UtcDaliImageOperationsAverageScanlines2(void)
1044 {
1045   // Red and cyan, averaging to grey:
1046   unsigned char shortEven1[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
1047   unsigned char shortEven2[] = {0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0};
1048   unsigned char outputBuffer[sizeof(shortEven1)];
1049
1050   AverageScanlines2(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) / 2);
1051
1052   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
1053   {
1054     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION);
1055   }
1056
1057   // Longer test reusing RGBA setup/test logic:
1058   {
1059     const size_t           scanlineLength = 4096u;
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     AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
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   // Longer test reusing RGBA setup/test logic with none-8-divisable length
1075   {
1076     const size_t           scanlineLength = 501u;
1077     Dali::Vector<uint32_t> scanline1;
1078     Dali::Vector<uint32_t> scanline2;
1079     Dali::Vector<uint32_t> reference;
1080     Dali::Vector<uint32_t> output;
1081     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1082
1083     AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
1084
1085     // Check the output matches the independently generated reference:
1086     size_t numMatches = 0;
1087     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1088     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1089   }
1090
1091   // Very short test reusing RGBA setup/test logic with less-than-8 length
1092   {
1093     const size_t           scanlineLength = 3u;
1094     Dali::Vector<uint32_t> scanline1;
1095     Dali::Vector<uint32_t> scanline2;
1096     Dali::Vector<uint32_t> reference;
1097     Dali::Vector<uint32_t> output;
1098     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1099
1100     AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
1101
1102     // Check the output matches the independently generated reference:
1103     size_t numMatches = 0;
1104     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1105     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1106   }
1107
1108   END_TEST;
1109 }
1110
1111 /**
1112  * @brief Test the function for averaging vertically-adjacent pairs of RGB888 pixels on a scanline.
1113  */
1114 int UtcDaliImageOperationsAverageScanlines3(void)
1115 {
1116   // Red and cyan, averaging to grey:
1117   unsigned char shortEven1[] = {0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff};
1118   unsigned char shortEven2[] = {0, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0};
1119   unsigned char outputBuffer[sizeof(shortEven1)];
1120
1121   AverageScanlines3(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) / 3);
1122   for(unsigned i = 0; i < sizeof(shortEven1); ++i)
1123   {
1124     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION);
1125   }
1126
1127   // Longer test reusing RGBA setup/test logic:
1128   {
1129     const size_t           scanlineLength = 3 * 4 * 90u;
1130     Dali::Vector<uint32_t> scanline1;
1131     Dali::Vector<uint32_t> scanline2;
1132     Dali::Vector<uint32_t> reference;
1133     Dali::Vector<uint32_t> output;
1134     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1135
1136     AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
1137
1138     // Check the output matches the independently generated reference:
1139     size_t numMatches = 0;
1140     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1141     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1142   }
1143
1144   // Longer test reusing RGBA setup/test logic with none-8-divisable length
1145   {
1146     const size_t           scanlineLength = 3 * 501u;
1147     Dali::Vector<uint32_t> scanline1;
1148     Dali::Vector<uint32_t> scanline2;
1149     Dali::Vector<uint32_t> reference;
1150     Dali::Vector<uint32_t> output;
1151     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1152
1153     AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
1154
1155     // Check the output matches the independently generated reference:
1156     size_t numMatches = 0;
1157     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1158     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1159   }
1160
1161   // Very short test reusing RGBA setup/test logic with less-than-8 length
1162   {
1163     const size_t           scanlineLength = 3u;
1164     Dali::Vector<uint32_t> scanline1;
1165     Dali::Vector<uint32_t> scanline2;
1166     Dali::Vector<uint32_t> reference;
1167     Dali::Vector<uint32_t> output;
1168     SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1169
1170     AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
1171
1172     // Check the output matches the independently generated reference:
1173     size_t numMatches = 0;
1174     MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1175     DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1176   }
1177
1178   END_TEST;
1179 }
1180
1181 /**
1182  * @brief Test the function for averaging vertically-adjacent pairs of RGBA8888 pixels on a scanline.
1183  */
1184 int UtcDaliImageOperationsAverageScanlinesRGBA8888(void)
1185 {
1186   const size_t           scanlineLength = 4096u;
1187   Dali::Vector<uint32_t> scanline1;
1188   Dali::Vector<uint32_t> scanline2;
1189   Dali::Vector<uint32_t> reference;
1190   Dali::Vector<uint32_t> output;
1191   SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
1192
1193   AverageScanlinesRGBA8888((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength);
1194
1195   // Check the output matches the independently generated reference:
1196   size_t numMatches = 0;
1197   MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
1198   DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
1199
1200   END_TEST;
1201 }
1202
1203 /**
1204  * @brief Test the function for averaging vertically-adjacent pairs of RGB565 pixels on a scanline.
1205  */
1206 int UtcDaliImageOperationsAverageScanlinesRGB565(void)
1207 {
1208   // Red and cyan, averaging to grey:
1209   const uint16_t shortEven1[] = {0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xBEEF, 0xBEEF};
1210   const uint16_t shortEven2[] = {0x7ff, 0x7ff, 0x7ff, 0x7ff, 0x7ff, 0x7ff, 0xBEEF, 0xBEEF};
1211   const size_t   arrayLength  = sizeof(shortEven1) / sizeof(shortEven1[0]) - 2;
1212   uint16_t       outputBuffer[arrayLength + 2];
1213   outputBuffer[arrayLength]     = 0xDEAD;
1214   outputBuffer[arrayLength + 1] = 0xDEAD;
1215
1216   Dali::Internal::Platform::AverageScanlinesRGB565((const unsigned char*)shortEven1, (const unsigned char*)shortEven2, (unsigned char*)outputBuffer, arrayLength);
1217   for(unsigned i = 0; i < arrayLength; ++i)
1218   {
1219     DALI_TEST_EQUALS(unsigned(outputBuffer[i]), 0xffff - (1u << 15) - (1u << 10) - (1u << 4), TEST_LOCATION);
1220   }
1221
1222   // Check for buffer overrun:
1223   DALI_TEST_EQUALS(outputBuffer[arrayLength], (uint16_t)0xDEAD, TEST_LOCATION);
1224   DALI_TEST_EQUALS(outputBuffer[arrayLength + 1], (uint16_t)0xDEAD, TEST_LOCATION);
1225
1226   END_TEST;
1227 }
1228
1229 namespace
1230 {
1231 void MakeSingleColorImageRGBA8888(unsigned int width, unsigned int height, uint32_t* inputImage)
1232 {
1233   const uint32_t inPixel = PixelRGBA8888(255, 192, 128, 64);
1234   for(unsigned int i = 0; i < width * height; ++i)
1235   {
1236     inputImage[i] = inPixel;
1237   }
1238 }
1239
1240 /*
1241  * @brief Make an image with a checkerboard pattern.
1242  * @note This is an easy pattern to scan for correctness after a downscaling test.
1243  */
1244 Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > MakeCheckerboardImageRGBA8888(unsigned int width, unsigned int height, unsigned int checkerSize)
1245 {
1246   const unsigned int                                    imageWidth  = width * checkerSize;
1247   const unsigned int                                    imageHeight = height * checkerSize;
1248   Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image       = new Dali::RefCountedVector<uint32_t>;
1249   image->GetVector().Resize(imageWidth * imageHeight);
1250
1251   uint32_t rowColor = 0xffffffff;
1252   for(unsigned int cy = 0; cy < height; ++cy)
1253   {
1254     rowColor            = rowColor == 0xffffffff ? 0xff000000 : 0xffffffff;
1255     uint32_t checkColor = rowColor;
1256     for(unsigned int cx = 0; cx < width; ++cx)
1257     {
1258       checkColor            = checkColor == 0xffffffff ? 0xff000000 : 0xffffffff;
1259       uint32_t paintedColor = checkColor;
1260       // Draw 3 special case checks as r,g,b:
1261       if(cx == 0 && cy == 0)
1262       {
1263         paintedColor = 0xff0000ff; // Red
1264       }
1265       else if(cx == 7 && cy == 0)
1266       {
1267         paintedColor = 0xff00ff00; // Green
1268       }
1269       else if(cx == 7 && cy == 7)
1270       {
1271         paintedColor = 0xffff0000; // blue
1272       }
1273       uint32_t* check = &image->GetVector()[(cy * checkerSize * imageWidth) + (cx * checkerSize)];
1274       for(unsigned int py = 0; py < checkerSize; ++py)
1275       {
1276         uint32_t* checkLine = check + py * imageWidth;
1277         for(unsigned int px = 0; px < checkerSize; ++px)
1278         {
1279           checkLine[px] = paintedColor;
1280         }
1281       }
1282     }
1283   }
1284
1285   return image;
1286 }
1287
1288 } // namespace
1289
1290 /**
1291  * @brief Test the right pixels are generated when downsampling a checkerboard into a small image.
1292  */
1293 int UtcDaliImageOperationsPointSampleCheckerboardRGBA888(void)
1294 {
1295   Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image         = MakeCheckerboardImageRGBA8888(8, 8, 32);
1296   const unsigned int                                    desiredWidth  = 8;
1297   const unsigned int                                    desiredHeight = 8;
1298
1299   uint32_t outputImage[desiredWidth * desiredHeight];
1300
1301   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)&image->GetVector()[0], 256, 256, (unsigned char*)outputImage, desiredWidth, desiredHeight);
1302
1303   DALI_TEST_EQUALS(outputImage[0], (uint32_t)0xff0000ff, TEST_LOCATION);         // < Red corner pixel
1304   DALI_TEST_EQUALS(outputImage[7], (uint32_t)0xff00ff00, TEST_LOCATION);         // < Green corner pixel
1305   DALI_TEST_EQUALS(outputImage[8 * 8 - 1], (uint32_t)0xffff0000, TEST_LOCATION); // < Blue corner pixel
1306
1307   DALI_TEST_EQUALS(outputImage[1], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1308   DALI_TEST_EQUALS(outputImage[2], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1309   DALI_TEST_EQUALS(outputImage[3], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1310   DALI_TEST_EQUALS(outputImage[4], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1311   DALI_TEST_EQUALS(outputImage[5], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1312   DALI_TEST_EQUALS(outputImage[6], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1313
1314   // Second scanline:
1315   DALI_TEST_EQUALS(outputImage[8 + 0], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1316   DALI_TEST_EQUALS(outputImage[8 + 1], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1317   DALI_TEST_EQUALS(outputImage[8 + 2], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1318   DALI_TEST_EQUALS(outputImage[8 + 3], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1319   DALI_TEST_EQUALS(outputImage[8 + 4], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1320   DALI_TEST_EQUALS(outputImage[8 + 5], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1321   DALI_TEST_EQUALS(outputImage[8 + 6], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1322   DALI_TEST_EQUALS(outputImage[8 + 7], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1323
1324   // Third scanline:
1325   DALI_TEST_EQUALS(outputImage[16 + 0], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1326   DALI_TEST_EQUALS(outputImage[16 + 1], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1327   DALI_TEST_EQUALS(outputImage[16 + 2], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1328   DALI_TEST_EQUALS(outputImage[16 + 3], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1329   DALI_TEST_EQUALS(outputImage[16 + 4], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1330   DALI_TEST_EQUALS(outputImage[16 + 5], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1331   DALI_TEST_EQUALS(outputImage[16 + 6], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1332   DALI_TEST_EQUALS(outputImage[16 + 7], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1333
1334   // ... could do more scanlines (there are 8)
1335
1336   // Sample a few more pixels:
1337
1338   // Diagonals:
1339   DALI_TEST_EQUALS(outputImage[24 + 3], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1340   DALI_TEST_EQUALS(outputImage[32 + 4], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1341   DALI_TEST_EQUALS(outputImage[40 + 5], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1342   DALI_TEST_EQUALS(outputImage[48 + 6], (uint32_t)0xffffffff, TEST_LOCATION); // < white pixel
1343   DALI_TEST_EQUALS(outputImage[24 + 4], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1344   DALI_TEST_EQUALS(outputImage[32 + 3], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1345   DALI_TEST_EQUALS(outputImage[40 + 2], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1346   DALI_TEST_EQUALS(outputImage[48 + 1], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1347   DALI_TEST_EQUALS(outputImage[56 + 0], (uint32_t)0xff000000, TEST_LOCATION); // < black pixel
1348
1349   END_TEST;
1350 }
1351
1352 /**
1353  * @brief Test that a scaling preserves input color in destination image.
1354  */
1355 int UtcDaliImageOperationsPointSampleRGBA888PixelsCorrectColor(void)
1356 {
1357   const unsigned int inputWidth    = 137;
1358   const unsigned int inputHeight   = 571;
1359   const unsigned int desiredWidth  = 59;
1360   const unsigned int desiredHeight = 257;
1361
1362   uint32_t inputImage[inputWidth * inputHeight];
1363   MakeSingleColorImageRGBA8888(inputWidth, inputHeight, inputImage);
1364
1365   const size_t          outputBufferSize = desiredWidth * desiredHeight;
1366   std::vector<uint32_t> buffer;
1367   buffer.resize(outputBufferSize);
1368   uint32_t* outputImage = &buffer[0];
1369
1370   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, inputWidth, inputHeight, (unsigned char*)outputImage, desiredWidth, desiredHeight);
1371
1372   // Check that all the output pixels are the right color:
1373   const uint32_t reference           = inputImage[inputWidth * inputHeight / 2];
1374   unsigned int   differentColorCount = 0;
1375   for(unsigned int i = 0; i < desiredWidth * desiredHeight; ++i)
1376   {
1377     if(outputImage[i] != reference)
1378     {
1379       ++differentColorCount;
1380     }
1381   }
1382
1383   DALI_TEST_EQUALS(0U, differentColorCount, TEST_LOCATION);
1384
1385   END_TEST;
1386 }
1387
1388 /**
1389  * @brief Test that scaling down to a 1x1 image works.
1390  */
1391 int UtcDaliImageOperationsPointSampleRGBA888ScaleToSinglePixel(void)
1392 {
1393   const unsigned int desiredWidth  = 1;
1394   const unsigned int desiredHeight = 1;
1395
1396   uint32_t inputImage[1024 * 1024];
1397   MakeSingleColorImageRGBA8888(1024, 1024, inputImage);
1398   uint32_t outputImage = 0;
1399
1400   // Try several different starting image sizes:
1401
1402   // 1x1 -> 1x1:
1403   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1404   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1405   outputImage = 0;
1406
1407   // Single-pixel wide tall stripe:
1408   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1024, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1409   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1410   outputImage = 0;
1411
1412   // Single-pixel tall, wide strip:
1413   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1024, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1414   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1415   outputImage = 0;
1416
1417   // Square mid-size image:
1418   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1419   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1420   outputImage = 0;
1421
1422   // Wide mid-size image:
1423   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1424   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1425   outputImage = 0;
1426
1427   // Tall mid-size image:
1428   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 467, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1429   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
1430   outputImage = 0;
1431
1432   // 0 x 0 input image (make sure output not written to):
1433   outputImage = 0xDEADBEEF;
1434   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
1435   DALI_TEST_EQUALS(outputImage, (uint32_t)0xDEADBEEF, TEST_LOCATION);
1436   outputImage = 0;
1437
1438   END_TEST;
1439 }
1440
1441 /**
1442  * @brief Test that downsampling to 0 - area images is a NOP and does not modify the destination.
1443  * (edge-case)
1444  */
1445 int UtcDaliImageOperationsPointSampleRGBA888N(void)
1446 {
1447   uint32_t inputImage[128 * 128];
1448   MakeSingleColorImageRGBA8888(128, 128, inputImage);
1449   uint32_t outputImage[128 * 128];
1450   memset(outputImage, 0xaa, 128 * 128 * sizeof(uint32_t));
1451
1452   // Try several different starting image sizes:
1453
1454   // 1x1 -> 1x1:
1455   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, (unsigned char*)outputImage, 0, 0);
1456   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1457
1458   // Single-pixel wide tall stripe:
1459   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 102, (unsigned char*)outputImage, 0, 33);
1460   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1461
1462   // Single-pixel tall, wide strip:
1463   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 102, 1, (unsigned char*)outputImage, 0, 67);
1464   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1465
1466   // Square mid-size image:
1467   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, (unsigned char*)outputImage, 21, 0);
1468   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1469
1470   // Wide mid-size image to 0 height
1471   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, (unsigned char*)outputImage, 99, 0);
1472   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1473
1474   // Tall mid-size image to 0 height, over width
1475   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 46, (unsigned char*)outputImage, 9999, 0);
1476   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1477
1478   // 0 x 0 input image:
1479   Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, (unsigned char*)outputImage, 200, 99);
1480   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
1481
1482   END_TEST;
1483 }
1484
1485 /**
1486  * @brief Test the small int (x,y) tuple.
1487  */
1488 int UtcDaliImageOperationsUint16Pair(void)
1489 {
1490   Uint16Pair vec1(2, 3);
1491
1492   DALI_TEST_EQUALS(vec1.GetWidth(), (uint16_t)2, TEST_LOCATION);
1493   DALI_TEST_EQUALS(vec1.GetX(), (uint16_t)2, TEST_LOCATION);
1494
1495   DALI_TEST_EQUALS(vec1.GetHeight(), (uint16_t)3, TEST_LOCATION);
1496   DALI_TEST_EQUALS(vec1.GetY(), (uint16_t)3, TEST_LOCATION);
1497
1498   Uint16Pair vec1Copy = vec1;
1499
1500   DALI_TEST_EQUALS(vec1Copy.GetWidth(), (uint16_t)2, TEST_LOCATION);
1501   DALI_TEST_EQUALS(vec1Copy.GetX(), (uint16_t)2, TEST_LOCATION);
1502
1503   DALI_TEST_EQUALS(vec1Copy.GetHeight(), (uint16_t)3, TEST_LOCATION);
1504   DALI_TEST_EQUALS(vec1Copy.GetY(), (uint16_t)3, TEST_LOCATION);
1505
1506   Uint16Pair vec2(65535u, 65535u);
1507
1508   DALI_TEST_EQUALS(vec2.GetX(), (uint16_t)65535u, TEST_LOCATION);
1509   DALI_TEST_EQUALS(vec2.GetY(), (uint16_t)65535u, TEST_LOCATION);
1510
1511   END_TEST;
1512 }
1513
1514 /**
1515  * @brief Test the four-tap linear blending for single-byte modes.
1516  */
1517 int UtcDaliImageOperationsBilinearFilter1BPP(void)
1518 {
1519   // Zeros blend to zero:
1520   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 0, 0), TEST_LOCATION);
1521   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 32768, 0), TEST_LOCATION);
1522   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 65535, 0), TEST_LOCATION);
1523   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 0, 32768), TEST_LOCATION);
1524   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 0, 0, 0, 65535), TEST_LOCATION);
1525
1526   // Ones and zeros average to 0.5:
1527   DALI_TEST_EQUALS(127u, BilinearFilter1Component(255, 0, 0, 255, 32768, 32768), TEST_LOCATION);
1528   DALI_TEST_EQUALS(127u, BilinearFilter1Component(0, 255, 0, 255, 32768, 32768), TEST_LOCATION);
1529
1530   // Quarters ones average to 0.25:
1531   DALI_TEST_EQUALS(64u, BilinearFilter1Component(255, 0, 0, 0, 32768, 32768), TEST_LOCATION);
1532   DALI_TEST_EQUALS(64u, BilinearFilter1Component(0, 255, 0, 0, 32768, 32768), TEST_LOCATION);
1533   DALI_TEST_EQUALS(64u, BilinearFilter1Component(0, 0, 255, 0, 32768, 32768), TEST_LOCATION);
1534   DALI_TEST_EQUALS(64u, BilinearFilter1Component(0, 0, 0, 255, 32768, 32768), TEST_LOCATION);
1535
1536   // Horizontal blends:
1537   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 255, 0, 255, 0, 32768), TEST_LOCATION);
1538   for(unsigned y = 0; y < 65536u; y += 256)
1539   {
1540     // Vertical blends don't change result in this case as there is no vertical gradient in inputs:
1541     DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 255, 0, 255, 0, y), TEST_LOCATION);
1542   }
1543   DALI_TEST_EQUALS(5u, BilinearFilter1Component(0, 255, 0, 255, 1233, 32768), TEST_LOCATION);
1544   DALI_TEST_EQUALS(29u, BilinearFilter1Component(0, 255, 0, 255, 7539, 32768), TEST_LOCATION);
1545   DALI_TEST_EQUALS(29u, BilinearFilter1Component(0, 255, 0, 255, 7539, 32768), TEST_LOCATION);
1546   DALI_TEST_EQUALS(67u, BilinearFilter1Component(0, 255, 0, 255, 17291, 32768), TEST_LOCATION);
1547   DALI_TEST_EQUALS(123u, BilinearFilter1Component(0, 255, 0, 255, 31671, 32768), TEST_LOCATION);
1548   DALI_TEST_EQUALS(184u, BilinearFilter1Component(0, 255, 0, 255, 47231, 32768), TEST_LOCATION);
1549   DALI_TEST_EQUALS(207u, BilinearFilter1Component(0, 255, 0, 255, 53129, 32768), TEST_LOCATION);
1550   DALI_TEST_EQUALS(239u, BilinearFilter1Component(0, 255, 0, 255, 61392, 32768), TEST_LOCATION);
1551   DALI_TEST_EQUALS(255u, BilinearFilter1Component(0, 255, 0, 255, 65535, 32768), TEST_LOCATION);
1552
1553   // Vertical Blends:
1554   DALI_TEST_EQUALS(0u, BilinearFilter1Component(0, 0, 255, 255, 32768, 0), TEST_LOCATION);
1555   DALI_TEST_EQUALS(60u, BilinearFilter1Component(0, 0, 255, 255, 32768, 15379), TEST_LOCATION);
1556   DALI_TEST_EQUALS(130u, BilinearFilter1Component(0, 0, 255, 255, 32768, 33451), TEST_LOCATION);
1557   DALI_TEST_EQUALS(186u, BilinearFilter1Component(0, 0, 255, 255, 32768, 47836), TEST_LOCATION);
1558   DALI_TEST_EQUALS(244u, BilinearFilter1Component(0, 0, 255, 255, 32768, 62731), TEST_LOCATION);
1559   DALI_TEST_EQUALS(255u, BilinearFilter1Component(0, 0, 255, 255, 32768, 65535), TEST_LOCATION);
1560
1561   END_TEST;
1562 }