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