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