Keep track of Bitmap data ownership
[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], 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], 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], 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],  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],  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], 0xDEAD, TEST_LOCATION );
1088   DALI_TEST_EQUALS( outputBuffer[arrayLength+1], 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 Allocate an image buffer with protected pages to top and tail it and
1107  * SEGV if an operation strays into them.
1108  */
1109 void MakeGuardedOutputImageRGBA8888( unsigned int desiredWidth,  unsigned int desiredHeight, uint32_t *& outputBuffer, uint32_t *& outputImage )
1110 {
1111   const size_t outputBufferSize = getpagesize() + sizeof(uint32_t) * desiredWidth * desiredHeight + getpagesize();
1112   outputBuffer = (uint32_t *) valloc( outputBufferSize );
1113   mprotect( outputBuffer, getpagesize(), PROT_READ );
1114   mprotect( ((char*) outputBuffer) + outputBufferSize - getpagesize(), getpagesize(), PROT_READ );
1115   outputImage = outputBuffer + getpagesize() / sizeof(outputBuffer[0]);
1116 }
1117
1118 /**
1119  * @brief Allocate a buffer of pages that are read-only, that is big enough for the number of pixels passed-in.
1120  */
1121 uint32_t* AllocateReadOnlyPagesRGBA( unsigned int numPixels )
1122 {
1123   const unsigned int numWholePages = (numPixels * sizeof(uint32_t)) / getpagesize();
1124   bool needExtraPage = (numPixels * sizeof(uint32_t)) % getpagesize() != 0;
1125   const size_t outputBufferSize = (numWholePages + (needExtraPage ? 1 : 0)) * getpagesize();
1126   uint32_t * outputBuffer = (uint32_t *) valloc( outputBufferSize );
1127   mprotect( outputBuffer, outputBufferSize, PROT_READ );
1128
1129   return outputBuffer;
1130 }
1131
1132 /**
1133  * @brief Free a buffer of pages that are read-only.
1134  */
1135 void FreeReadOnlyPagesRGBA( uint32_t * pages, unsigned int numPixels )
1136 {
1137   const size_t bufferSize = numPixels * 4;
1138   mprotect( pages, bufferSize, PROT_READ | PROT_WRITE );
1139   free( pages );
1140 }
1141
1142 /*
1143  * @brief Make an image with a checkerboard pattern.
1144  * @note This is an easy pattern to scan for correctness after a downscaling test.
1145  */
1146 Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > MakeCheckerboardImageRGBA8888( unsigned int width,  unsigned int height, unsigned int checkerSize )
1147 {
1148   const unsigned int imageWidth = width * checkerSize;
1149   const unsigned int imageHeight = height * checkerSize;
1150   Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image = new Dali::RefCountedVector<uint32_t>;
1151   image->GetVector().Resize( imageWidth * imageHeight );
1152
1153   uint32_t rowColor = 0xffffffff;
1154   for( unsigned int cy = 0; cy < height; ++cy )
1155   {
1156     rowColor = rowColor == 0xffffffff ? 0xff000000 : 0xffffffff;
1157     uint32_t checkColor = rowColor;
1158     for( unsigned int cx = 0; cx < width; ++cx )
1159     {
1160       checkColor = checkColor == 0xffffffff ? 0xff000000 : 0xffffffff;
1161       uint32_t paintedColor = checkColor;
1162       // Draw 3 special case checks as r,g,b:
1163       if(cx == 0 && cy == 0)
1164       {
1165         paintedColor = 0xff0000ff;// Red
1166       }
1167       else if(cx == 7 && cy == 0)
1168       {
1169         paintedColor = 0xff00ff00;// Green
1170       }
1171       else if(cx == 7 && cy == 7)
1172       {
1173         paintedColor = 0xffff0000;// blue
1174       }
1175       uint32_t * check = &image->GetVector()[ (cy * checkerSize * imageWidth) + (cx * checkerSize)];
1176       for( unsigned int py = 0; py < checkerSize; ++py )
1177       {
1178         uint32_t * checkLine = check +  py * imageWidth;
1179         for( unsigned int px = 0; px < checkerSize; ++px )
1180         {
1181           checkLine[px] = paintedColor;
1182         }
1183       }
1184     }
1185   }
1186
1187   return image;
1188 }
1189
1190 }
1191
1192 /**
1193  * @brief Test that a scaling doesn't stray outside the bounds of the destination image.
1194  *
1195  * The test allocates a destination buffer that is an exact multiple of the page size
1196  * with guard pages at either end.
1197  */
1198 int UtcDaliImageOperationsPointSampleRGBA888InBounds(void)
1199 {
1200   const unsigned int inputWidth = 163;
1201   const unsigned int inputHeight = 691;
1202   const unsigned int destinationBufferSize = 4096 * 4;
1203   const unsigned int desiredWidth = 64;
1204   const unsigned int desiredHeight = destinationBufferSize / desiredWidth; // (256)
1205
1206   uint32_t inputImage[ inputWidth * inputHeight ];
1207
1208   // Allocate an output image buffer with read-only guard pages at either end:
1209   // The test will segfault if it strays into the guard pages.
1210   uint32_t *outputBuffer, *outputImage;
1211   MakeGuardedOutputImageRGBA8888( desiredWidth, desiredHeight, outputBuffer, outputImage );
1212
1213   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, inputWidth, inputHeight, (unsigned char*) outputImage, desiredWidth, desiredHeight );
1214
1215   FreeReadOnlyPagesRGBA( outputBuffer, desiredWidth * desiredHeight );
1216
1217   //! The only real test is whether the above code SEGVs, but do a fake test so we pass if that hasn't happened:
1218   DALI_TEST_EQUALS( true, true, TEST_LOCATION );
1219
1220   END_TEST;
1221 }
1222
1223 /**
1224  * @brief Test the right pixels are generated when downsampling a checkerboard into a small image.
1225  */
1226 int UtcDaliImageOperationsPointSampleCheckerboardRGBA888(void)
1227 {
1228   Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image = MakeCheckerboardImageRGBA8888( 8, 8, 32 );
1229   const unsigned int desiredWidth = 8;
1230   const unsigned int desiredHeight = 8;
1231
1232   uint32_t outputImage[ desiredWidth * desiredHeight ];
1233
1234   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) &image->GetVector()[0], 256, 256, (unsigned char*) outputImage, desiredWidth, desiredHeight );
1235
1236   DALI_TEST_EQUALS( outputImage[0], 0xff0000ff, TEST_LOCATION ); // < Red corner pixel
1237   DALI_TEST_EQUALS( outputImage[7], 0xff00ff00, TEST_LOCATION ); // < Green corner pixel
1238   DALI_TEST_EQUALS( outputImage[8*8-1], 0xffff0000, TEST_LOCATION ); // < Blue corner pixel
1239
1240   DALI_TEST_EQUALS( outputImage[1], 0xff000000, TEST_LOCATION ); // < black pixel
1241   DALI_TEST_EQUALS( outputImage[2], 0xffffffff, TEST_LOCATION ); // < white pixel
1242   DALI_TEST_EQUALS( outputImage[3], 0xff000000, TEST_LOCATION ); // < black pixel
1243   DALI_TEST_EQUALS( outputImage[4], 0xffffffff, TEST_LOCATION ); // < white pixel
1244   DALI_TEST_EQUALS( outputImage[5], 0xff000000, TEST_LOCATION ); // < black pixel
1245   DALI_TEST_EQUALS( outputImage[6], 0xffffffff, TEST_LOCATION ); // < white pixel
1246
1247   // Second scanline:
1248   DALI_TEST_EQUALS( outputImage[8+0], 0xff000000, TEST_LOCATION ); // < black pixel
1249   DALI_TEST_EQUALS( outputImage[8+1], 0xffffffff, TEST_LOCATION ); // < white pixel
1250   DALI_TEST_EQUALS( outputImage[8+2], 0xff000000, TEST_LOCATION ); // < black pixel
1251   DALI_TEST_EQUALS( outputImage[8+3], 0xffffffff, TEST_LOCATION ); // < white pixel
1252   DALI_TEST_EQUALS( outputImage[8+4], 0xff000000, TEST_LOCATION ); // < black pixel
1253   DALI_TEST_EQUALS( outputImage[8+5], 0xffffffff, TEST_LOCATION ); // < white pixel
1254   DALI_TEST_EQUALS( outputImage[8+6], 0xff000000, TEST_LOCATION ); // < black pixel
1255   DALI_TEST_EQUALS( outputImage[8+7], 0xffffffff, TEST_LOCATION ); // < white pixel
1256
1257   // Third scanline:
1258   DALI_TEST_EQUALS( outputImage[16+0], 0xffffffff, TEST_LOCATION ); // < white pixel
1259   DALI_TEST_EQUALS( outputImage[16+1], 0xff000000, TEST_LOCATION ); // < black pixel
1260   DALI_TEST_EQUALS( outputImage[16+2], 0xffffffff, TEST_LOCATION ); // < white pixel
1261   DALI_TEST_EQUALS( outputImage[16+3], 0xff000000, TEST_LOCATION ); // < black pixel
1262   DALI_TEST_EQUALS( outputImage[16+4], 0xffffffff, TEST_LOCATION ); // < white pixel
1263   DALI_TEST_EQUALS( outputImage[16+5], 0xff000000, TEST_LOCATION ); // < black pixel
1264   DALI_TEST_EQUALS( outputImage[16+6], 0xffffffff, TEST_LOCATION ); // < white pixel
1265   DALI_TEST_EQUALS( outputImage[16+7], 0xff000000, TEST_LOCATION ); // < black pixel
1266
1267   // ... could do more scanlines (there are 8)
1268
1269   // Sample a few more pixels:
1270
1271   // Diagonals:
1272   DALI_TEST_EQUALS( outputImage[24+3], 0xffffffff, TEST_LOCATION ); // < white pixel
1273   DALI_TEST_EQUALS( outputImage[32+4], 0xffffffff, TEST_LOCATION ); // < white pixel
1274   DALI_TEST_EQUALS( outputImage[40+5], 0xffffffff, TEST_LOCATION ); // < white pixel
1275   DALI_TEST_EQUALS( outputImage[48+6], 0xffffffff, TEST_LOCATION ); // < white pixel
1276   DALI_TEST_EQUALS( outputImage[24+4], 0xff000000, TEST_LOCATION ); // < black pixel
1277   DALI_TEST_EQUALS( outputImage[32+3], 0xff000000, TEST_LOCATION ); // < black pixel
1278   DALI_TEST_EQUALS( outputImage[40+2], 0xff000000, TEST_LOCATION ); // < black pixel
1279   DALI_TEST_EQUALS( outputImage[48+1], 0xff000000, TEST_LOCATION ); // < black pixel
1280   DALI_TEST_EQUALS( outputImage[56+0], 0xff000000, TEST_LOCATION ); // < black pixel
1281
1282   END_TEST;
1283 }
1284
1285 /**
1286  * @brief Test that a scaling preserves input color in destination image.
1287  */
1288 int UtcDaliImageOperationsPointSampleRGBA888PixelsCorrectColor(void)
1289 {
1290   const unsigned int inputWidth = 137;
1291   const unsigned int inputHeight = 571;
1292   const unsigned int desiredWidth = 59;
1293   const unsigned int desiredHeight = 257;
1294
1295   uint32_t inputImage[ inputWidth * inputHeight ];
1296   MakeSingleColorImageRGBA8888( inputWidth, inputHeight, inputImage );
1297
1298   uint32_t *outputBuffer, *outputImage;
1299   MakeGuardedOutputImageRGBA8888( desiredWidth, desiredHeight, outputBuffer, outputImage );
1300
1301   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, inputWidth, inputHeight, (unsigned char*) outputImage, desiredWidth, desiredHeight );
1302
1303   // Check that all the output pixels are the right color:
1304   const uint32_t reference = inputImage[ inputWidth * inputHeight / 2];
1305   unsigned int differentColorCount = 0;
1306   for( unsigned int i = 0; i < desiredWidth * desiredHeight; ++i )
1307   {
1308     if( outputImage[i] != reference )
1309     {
1310       ++differentColorCount;
1311     }
1312   }
1313
1314   FreeReadOnlyPagesRGBA( outputBuffer, desiredWidth * desiredHeight );
1315
1316   DALI_TEST_EQUALS( 0U, differentColorCount, TEST_LOCATION );
1317
1318   END_TEST;
1319 }
1320
1321 /**
1322  * @brief Test that scaling down to a 1x1 image works.
1323  */
1324 int UtcDaliImageOperationsPointSampleRGBA888ScaleToSinglePixel(void)
1325 {
1326   const unsigned int desiredWidth = 1;
1327   const unsigned int desiredHeight = 1;
1328
1329   uint32_t inputImage[ 1024 * 1024 ];
1330   MakeSingleColorImageRGBA8888( 1024, 1024, inputImage );
1331   uint32_t outputImage = 0;
1332
1333   // Try several different starting image sizes:
1334
1335   // 1x1 -> 1x1:
1336   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    1,    1, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
1337   DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
1338   outputImage = 0;
1339
1340   // Single-pixel wide tall stripe:
1341   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    1, 1024, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
1342   DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
1343   outputImage = 0;
1344
1345   // Single-pixel tall, wide strip:
1346   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, 1024,    1, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
1347   DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
1348   outputImage = 0;
1349
1350   // Square mid-size image:
1351   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  103,  103, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
1352   DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
1353   outputImage = 0;
1354
1355   // Wide mid-size image:
1356   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  313,  79, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
1357   DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
1358   outputImage = 0;
1359
1360   // Tall mid-size image:
1361   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,   53,  467, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
1362   DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
1363   outputImage = 0;
1364
1365   // 0 x 0 input image (make sure output not written to):
1366   outputImage = 0xDEADBEEF;
1367   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    0,    0, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
1368   DALI_TEST_EQUALS( outputImage, 0xDEADBEEF, TEST_LOCATION );
1369   outputImage = 0;
1370
1371   END_TEST;
1372 }
1373
1374 /**
1375  * @brief Test that downsampling to 0 - area images is a NOP and does not modify the destination.
1376  * (edge-case)
1377  */
1378 int UtcDaliImageOperationsPointSampleRGBA888ScaleToZeroDims(void)
1379 {
1380   uint32_t inputImage[ 1024 * 1024 ];
1381   MakeSingleColorImageRGBA8888( 1024, 1024, inputImage );
1382   uint32_t* outputImage = AllocateReadOnlyPagesRGBA(1);
1383
1384   // Try several different starting image sizes:
1385
1386   // 1x1 -> 1x1:
1387   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    1,    1, (unsigned char*) outputImage, 0, 0 );
1388
1389   // Single-pixel wide tall stripe:
1390   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    1, 1024, (unsigned char*) outputImage, 0, 33 );
1391
1392   // Single-pixel tall, wide strip:
1393   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, 1024,    1, (unsigned char*) outputImage, 0, 67 );
1394
1395   // Square mid-size image:
1396   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  103,  103, (unsigned char*) outputImage, 21, 0 );
1397
1398   // Wide mid-size image:
1399   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  313,  79, (unsigned char*) outputImage, 99, 0 );
1400
1401   // Tall mid-size image:
1402   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,   53,  467, (unsigned char*) outputImage, 9999, 0 );
1403
1404   // 0 x 0 input image:
1405   Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    0,    0, (unsigned char*) outputImage, 200, 99 );
1406
1407   FreeReadOnlyPagesRGBA( outputImage, getpagesize() / 4 );
1408
1409   //! The only real test is whether the above code SEGVs, but do a fake test so we pass if that hasn't happened:
1410   DALI_TEST_EQUALS( true, true, TEST_LOCATION );
1411
1412   END_TEST;
1413 }
1414
1415 /**
1416  * @brief Test that a scaling doesn't stray outside the bounds of the destination image.
1417  *
1418  * The test allocates a destination buffer that is an exact multiple of the page size
1419  * with guard pages at either end.
1420  */
1421 int UtcDaliImageOperationsPointSampleRGB88InBounds(void)
1422 {
1423   const unsigned int inputWidth = 163;
1424   const unsigned int inputHeight = 691;
1425   const unsigned int desiredWidth = 32;
1426   const unsigned int desiredHeight = 128;
1427   const unsigned int outputBuffersizeInWords = desiredWidth * (desiredHeight / 4) * 3;
1428
1429   uint8_t inputImage[ inputWidth * inputHeight ][3];
1430
1431   // Allocate an output image buffer with read-only guard pages at either end:
1432   // The test will segfault if it strays into the guard pages.
1433   uint32_t *outputBuffer, *outputImage;
1434
1435   MakeGuardedOutputImageRGBA8888( desiredWidth * (desiredHeight / 4), 3, outputBuffer, outputImage );
1436
1437   Dali::Internal::Platform::PointSample3BPP( &inputImage[0][0], inputWidth, inputHeight, (uint8_t*) outputImage, desiredWidth, desiredHeight );
1438
1439   FreeReadOnlyPagesRGBA( outputBuffer, outputBuffersizeInWords );
1440
1441   //! The only real test is whether the above code SEGVs, but do a fake test so we pass if that hasn't happened:
1442   DALI_TEST_EQUALS( true, true, TEST_LOCATION );
1443
1444   END_TEST;
1445 }
1446
1447 /**
1448  * @brief Test the small int (x,y) tuple.
1449  */
1450 int UtcDaliImageOperationsUint16Pair(void)
1451 {
1452   Uint16Pair vec1( 2, 3 );
1453
1454   DALI_TEST_EQUALS( vec1.GetWidth(), 2, TEST_LOCATION );
1455   DALI_TEST_EQUALS( vec1.GetX(),     2, TEST_LOCATION );
1456
1457   DALI_TEST_EQUALS( vec1.GetHeight(), 3, TEST_LOCATION );
1458   DALI_TEST_EQUALS( vec1.GetY(),      3, TEST_LOCATION );
1459
1460   Uint16Pair vec1Copy = vec1;
1461
1462   DALI_TEST_EQUALS( vec1Copy.GetWidth(), 2, TEST_LOCATION );
1463   DALI_TEST_EQUALS( vec1Copy.GetX(),     2, TEST_LOCATION );
1464
1465   DALI_TEST_EQUALS( vec1Copy.GetHeight(), 3, TEST_LOCATION );
1466   DALI_TEST_EQUALS( vec1Copy.GetY(),      3, TEST_LOCATION );
1467
1468   Uint16Pair vec2( 65535u, 65535u );
1469
1470   DALI_TEST_EQUALS( vec2.GetX(), 65535u, TEST_LOCATION );
1471   DALI_TEST_EQUALS( vec2.GetY(), 65535u, TEST_LOCATION );
1472
1473   END_TEST;
1474 }
1475
1476 /**
1477  * @brief Test the four-tap linear blending for single-byte modes.
1478  */
1479 int UtcDaliImageOperationsBilinearFilter1BPP(void)
1480 {
1481   // Zeros blend to zero:
1482   DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 0, 0 ), TEST_LOCATION );
1483   DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 32768, 0 ), TEST_LOCATION );
1484   DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 65535, 0 ), TEST_LOCATION );
1485   DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 0, 32768 ), TEST_LOCATION );
1486   DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 0, 65535 ), TEST_LOCATION );
1487
1488   // Ones and zeros average to 0.5:
1489   DALI_TEST_EQUALS( 127u, BilinearFilter1Component( 255, 0, 0, 255, 32768, 32768 ), TEST_LOCATION );
1490   DALI_TEST_EQUALS( 127u, BilinearFilter1Component( 0, 255, 0, 255, 32768, 32768 ), TEST_LOCATION );
1491
1492   // Quarters ones average to 0.25:
1493   DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 255, 0, 0, 0, 32768, 32768 ), TEST_LOCATION );
1494   DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 0, 255, 0, 0, 32768, 32768 ), TEST_LOCATION );
1495   DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 0, 0, 255, 0, 32768, 32768 ), TEST_LOCATION );
1496   DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 0, 0, 0, 255, 32768, 32768 ), TEST_LOCATION );
1497
1498   // Horizontal blends:
1499   DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 255, 0, 255, 0, 32768 ), TEST_LOCATION );
1500   for( unsigned y = 0; y < 65536u; y += 256 )
1501   {
1502     // Vertical blends don't change result in this case as there is no vertical gradient in inputs:
1503     DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 255, 0, 255, 0, y ), TEST_LOCATION );
1504   }
1505   DALI_TEST_EQUALS( 5u, BilinearFilter1Component( 0, 255, 0, 255, 1233, 32768 ), TEST_LOCATION );
1506   DALI_TEST_EQUALS( 29u, BilinearFilter1Component( 0, 255, 0, 255, 7539, 32768 ), TEST_LOCATION );
1507   DALI_TEST_EQUALS( 29u, BilinearFilter1Component( 0, 255, 0, 255, 7539, 32768 ), TEST_LOCATION );
1508   DALI_TEST_EQUALS( 67u, BilinearFilter1Component( 0, 255, 0, 255, 17291, 32768 ), TEST_LOCATION );
1509   DALI_TEST_EQUALS( 123u, BilinearFilter1Component( 0, 255, 0, 255, 31671, 32768 ), TEST_LOCATION );
1510   DALI_TEST_EQUALS( 184u, BilinearFilter1Component( 0, 255, 0, 255, 47231, 32768 ), TEST_LOCATION );
1511   DALI_TEST_EQUALS( 207u, BilinearFilter1Component( 0, 255, 0, 255, 53129, 32768 ), TEST_LOCATION );
1512   DALI_TEST_EQUALS( 239u, BilinearFilter1Component( 0, 255, 0, 255, 61392, 32768 ), TEST_LOCATION );
1513   DALI_TEST_EQUALS( 255u, BilinearFilter1Component( 0, 255, 0, 255, 65535, 32768 ), TEST_LOCATION );
1514
1515   // Vertical Blends:
1516   DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 0 ), TEST_LOCATION );
1517   DALI_TEST_EQUALS( 60u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 15379 ), TEST_LOCATION );
1518   DALI_TEST_EQUALS( 130u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 33451 ), TEST_LOCATION );
1519   DALI_TEST_EQUALS( 186u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 47836 ), TEST_LOCATION );
1520   DALI_TEST_EQUALS( 244u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 62731 ), TEST_LOCATION );
1521   DALI_TEST_EQUALS( 255u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 65535 ), TEST_LOCATION );
1522
1523   END_TEST;
1524 }