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