Revert "[Tizen] Do not call gl functions during shutdown"
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / image-operations.h
1 /*
2  * Copyright (c) 2022 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 #ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
19 #define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
20
21 // EXTERNAL INCLUDES
22 #include <stdint.h>
23
24 // INTERNAL INCLUDES
25 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
26 #include <dali/integration-api/bitmap.h>
27 #include <dali/public-api/images/image-operations.h>
28 #include <third-party/resampler/resampler.h>
29
30 namespace Dali
31 {
32 namespace Internal
33 {
34 namespace Platform
35 {
36 /**
37  * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
38  */
39 enum BoxDimensionTest
40 {
41   BoxDimensionTestEither,
42   BoxDimensionTestBoth,
43   BoxDimensionTestX,
44   BoxDimensionTestY
45 };
46
47 /**
48  * @brief The integer dimensions of an image or a region of an image packed into
49  *        16 bits per component.
50  * @note  This can only be used for images of up to 65535 x 65535 pixels.
51   */
52 typedef Uint16Pair ImageDimensions;
53
54 /**
55  * @brief Work out the true desired width and height, accounting for special
56  * rules for zeros in either or both input requested dimensions.
57  *
58  * @param[in] rawDimensions Width and height of image before processing.
59  * @param[in] requestedDimensions Width and height of area to scale image into. Can be zero.
60  * @return Dimensions of area to scale image into after special rules are applied.
61  */
62 ImageDimensions CalculateDesiredDimensions(ImageDimensions rawDimensions, ImageDimensions requestedDimensions);
63
64 /**
65  * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
66  * @{
67  */
68
69 /**
70  * @brief Apply requested attributes to bitmap.
71  *
72  * This is the top-level function which runs the on-load image post-processing
73  * pipeline. Bitmaps enter here as loaded from the file system by the file
74  * loaders and leave downscaled and filtered as requested by the application,
75  * ready for use.
76  *
77  * @param[in] bitmap The input bitmap.
78  * @param[in] requestedAttributes Attributes which should be applied to bitmap.
79  * @return A bitmap which results from applying the requested attributes to the
80  *         bitmap passed-in, or the original bitmap passed in if the attributes
81  *         have no effect.
82  */
83 Dali::Devel::PixelBuffer ApplyAttributesToBitmap(Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT);
84
85 /**
86  * @brief Apply downscaling to a bitmap according to requested attributes.
87  * @note The input bitmap pixel buffer may be modified and used as scratch working space for efficiency, so it must be discarded.
88  **/
89 Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap,
90                                          ImageDimensions          desired,
91                                          FittingMode::Type        fittingMode,
92                                          SamplingMode::Type       samplingMode);
93 /**@}*/
94
95 /**
96  * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
97  * @{
98  */
99
100 /**
101  * @brief Destructive in-place downscaling by a power of 2 factor.
102  *
103  * A box filter with a 2x2 kernel is repeatedly applied as long as the result
104  * of the next downscaling step would not be smaller than the desired
105  * dimensions.
106  * @param[in,out] pixels The buffer both to read from and write the result to.
107  * @param[in]     pixelFormat The format of the image pointed at by pixels.
108  * @param[in]     inputWidth The width of the input image.
109  * @param[in]     inputHeight The height of the input image.
110  * @param[in]     inputStride The stride of the input image.
111  * @param[in]     desiredWidth The width the client is requesting.
112  * @param[in]     desiredHeight The height the client is requesting.
113  * @param[out]    outWidth  The resulting width after downscaling.
114  * @param[out]    outHeight The resulting height after downscaling.
115  * @param[out]    outStride The resulting stride after downscaling.
116  */
117 void DownscaleInPlacePow2(unsigned char* const pixels,
118                           Pixel::Format        pixelFormat,
119                           unsigned int         inputWidth,
120                           unsigned int         inputHeight,
121                           unsigned int         inputStride,
122                           unsigned int         desiredWidth,
123                           unsigned int         desiredHeight,
124                           FittingMode::Type    fittingMode,
125                           SamplingMode::Type   samplingMode,
126                           unsigned&            outWidth,
127                           unsigned&            outHeight,
128                           unsigned&            outStride);
129
130 /**
131  * @brief Destructive in-place downscaling by a power of 2 factor.
132  *
133  * A box filter with a 2x2 kernel is repeatedly applied as long as the result
134  * of the next downscaling step would not be smaller than the desired
135  * dimensions.
136  * @param[in,out] pixels The buffer both to read from and write the result to.
137  * @param[in]     inputWidth The width of the input image.
138  * @param[in]     inputHeight The height of the input image.
139  * @param[in]     inputStride The stride of the input image.
140  * @param[in]     desiredWidth The width the client is requesting.
141  * @param[in]     desiredHeight The height the client is requesting.
142  * @param[out]    outWidth  The resulting width after downscaling.
143  * @param[out]    outHeight The resulting height after downscaling.
144  * @param[out]    outStride The resulting stride after downscaling.
145  */
146 void DownscaleInPlacePow2RGB888(unsigned char*   pixels,
147                                 unsigned int     inputWidth,
148                                 unsigned int     inputHeight,
149                                 unsigned int     inputStride,
150                                 unsigned int     desiredWidth,
151                                 unsigned int     desiredHeight,
152                                 BoxDimensionTest dimensionTest,
153                                 unsigned int&    outWidth,
154                                 unsigned int&    outHeight,
155                                 unsigned int&    outStride);
156
157 /**
158  * @copydoc DownscaleInPlacePow2RGB888
159  */
160 void DownscaleInPlacePow2RGBA8888(unsigned char*   pixels,
161                                   unsigned int     inputWidth,
162                                   unsigned int     inputHeight,
163                                   unsigned int     inputStride,
164                                   unsigned int     desiredWidth,
165                                   unsigned int     desiredHeight,
166                                   BoxDimensionTest dimensionTest,
167                                   unsigned int&    outWidth,
168                                   unsigned int&    outHeight,
169                                   unsigned int&    outStride);
170
171 /**
172  * @copydoc DownscaleInPlacePow2RGB888
173  *
174  * For the 2-byte packed 16 bit format RGB565.
175  */
176 void DownscaleInPlacePow2RGB565(unsigned char*   pixels,
177                                 unsigned int     inputWidth,
178                                 unsigned int     inputHeight,
179                                 unsigned int     inputStride,
180                                 unsigned int     desiredWidth,
181                                 unsigned int     desiredHeight,
182                                 BoxDimensionTest dimensionTest,
183                                 unsigned int&    outWidth,
184                                 unsigned int&    outHeight,
185                                 unsigned int&    outStride);
186
187 /**
188  * @copydoc DownscaleInPlacePow2RGB888
189  *
190  * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
191  */
192 void DownscaleInPlacePow2ComponentPair(unsigned char*   pixels,
193                                        unsigned int     inputWidth,
194                                        unsigned int     inputHeight,
195                                        unsigned int     inputStride,
196                                        unsigned int     desiredWidth,
197                                        unsigned int     desiredHeight,
198                                        BoxDimensionTest dimensionTest,
199                                        unsigned int&    outWidth,
200                                        unsigned int&    outHeight,
201                                        unsigned int&    outStride);
202
203 /**
204  * @copydoc DownscaleInPlacePow2RGB888
205  *
206  * For single-byte formats such as lum8 or alpha8.
207  */
208 void DownscaleInPlacePow2SingleBytePerPixel(unsigned char*   pixels,
209                                             unsigned int     inputWidth,
210                                             unsigned int     inputHeight,
211                                             unsigned int     inputStride,
212                                             unsigned int     desiredWidth,
213                                             unsigned int     desiredHeight,
214                                             BoxDimensionTest dimensionTest,
215                                             unsigned int&    outWidth,
216                                             unsigned int&    outHeight,
217                                             unsigned int&    outStride);
218
219 /**
220  * @brief Rescales an input image into the exact output dimensions passed-in.
221  *
222  * Uses point sampling, equivalent to GL_NEAREST texture filter mode, for the
223  * fastest results, at the expense of aliasing (noisy images) when downscaling.
224  * @note inPixels is allowed to alias outPixels if this is a downscaling,
225  * but not for upscaling.
226  */
227 void PointSample(const unsigned char* inPixels,
228                  unsigned int         inputWidth,
229                  unsigned int         inputHeight,
230                  unsigned int         inputStride,
231                  Pixel::Format        pixelFormat,
232                  unsigned char*       outPixels,
233                  unsigned int         desiredWidth,
234                  unsigned int         desiredHeight);
235
236 /**
237  * @copydoc PointSample
238  *
239  * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
240  */
241 void PointSample4BPP(const unsigned char* inPixels,
242                      unsigned int         inputWidth,
243                      unsigned int         inputHeight,
244                      unsigned int         inputStride,
245                      unsigned char*       outPixels,
246                      unsigned int         desiredWidth,
247                      unsigned int         desiredHeight);
248
249 /**
250  * @copydoc PointSample
251  *
252  * Specialised for 3-byte formats like RGB888 and BGR888.
253  */
254 void PointSample3BPP(const unsigned char* inPixels,
255                      unsigned int         inputWidth,
256                      unsigned int         inputHeight,
257                      unsigned int         inputStride,
258                      unsigned char*       outPixels,
259                      unsigned int         desiredWidth,
260                      unsigned int         desiredHeight);
261
262 /**
263  * @copydoc PointSample
264  *
265  * Specialised for 2-byte formats like LA88.
266  */
267 void PointSample2BPP(const unsigned char* inPixels,
268                      unsigned int         inputWidth,
269                      unsigned int         inputHeight,
270                      unsigned int         inputStride,
271                      unsigned char*       outPixels,
272                      unsigned int         desiredWidth,
273                      unsigned int         desiredHeight);
274
275 /**
276  * @copydoc PointSample
277  *
278  * Specialised for 1-byte formats like L8 and A8.
279  */
280 void PointSample1BPP(const unsigned char* inPixels,
281                      unsigned int         inputWidth,
282                      unsigned int         inputHeight,
283                      unsigned int         inputStride,
284                      unsigned char*       outPixels,
285                      unsigned int         desiredWidth,
286                      unsigned int         desiredHeight);
287
288 /**
289  * @brief Resample input image to output image using a bilinear filter.
290  *
291  * Each output pixel is formed of a weighted sum of a 2x2 block of four input
292  * pixels
293  * @pre inPixels must not alias outPixels. The input image should be a totally
294  * separate buffer from the input one.
295  */
296 void LinearSample(const unsigned char* __restrict__ inPixels,
297                   ImageDimensions inDimensions,
298                   unsigned int    inStride,
299                   Pixel::Format   pixelFormat,
300                   unsigned char* __restrict__ outPixels,
301                   ImageDimensions outDimensions);
302
303 /**
304  * @copydoc LinearSample
305  *
306  * Specialised for one byte per pixel formats.
307  */
308 void LinearSample1BPP(const unsigned char* __restrict__ inPixels,
309                       ImageDimensions inputDimensions,
310                       unsigned int    inputStride,
311                       unsigned char* __restrict__ outPixels,
312                       ImageDimensions desiredDimensions);
313
314 /**
315  * @copydoc LinearSample
316  *
317  * Specialised for two byte per pixel formats.
318  */
319 void LinearSample2BPP(const unsigned char* __restrict__ inPixels,
320                       ImageDimensions inputDimensions,
321                       unsigned int    inputStride,
322                       unsigned char* __restrict__ outPixels,
323                       ImageDimensions desiredDimensions);
324
325 /**
326  * @copydoc LinearSample
327  *
328  * Specialised for RGB565 16 bit pixel format.
329  */
330 void LinearSampleRGB565(const unsigned char* __restrict__ inPixels,
331                         ImageDimensions inputDimensions,
332                         unsigned int    inputStride,
333                         unsigned char* __restrict__ outPixels,
334                         ImageDimensions desiredDimensions);
335
336 /**
337  * @copydoc LinearSample
338  *
339  * Specialised for three byte per pixel formats like RGB888.
340  */
341 void LinearSample3BPP(const unsigned char* __restrict__ inPixels,
342                       ImageDimensions inputDimensions,
343                       unsigned int    inputStride,
344                       unsigned char* __restrict__ outPixels,
345                       ImageDimensions desiredDimensions);
346
347 /**
348  * @copydoc LinearSample
349  *
350  * Specialised for four byte per pixel formats like RGBA8888.
351  * @note, If used on RGBA8888, the A component will be blended independently.
352  */
353 void LinearSample4BPP(const unsigned char* __restrict__ inPixels,
354                       ImageDimensions inputDimensions,
355                       unsigned int    inputStride,
356                       unsigned char* __restrict__ outPixels,
357                       ImageDimensions desiredDimensions);
358
359 /**
360  * @brief Resamples the input image with the Lanczos algorithm.
361  *
362  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
363  * separate buffer from the output buffer.
364  *
365  * @param[in] inPixels Pointer to the input image buffer.
366  * @param[in] inputDimensions The input dimensions of the image.
367  * @param[in] inputStride The input stride of the image.
368  * @param[out] outPixels Pointer to the output image buffer.
369  * @param[in] desiredDimensions The output dimensions of the image.
370  */
371 void LanczosSample4BPP(const unsigned char* __restrict__ inPixels,
372                        ImageDimensions inputDimensions,
373                        unsigned int    inputStride,
374                        unsigned char* __restrict__ outPixels,
375                        ImageDimensions desiredDimensions);
376
377 /**
378  * @brief Resamples the input image with the Lanczos algorithm.
379  *
380  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
381  * separate buffer from the output buffer.
382  *
383  * @param[in] inPixels Pointer to the input image buffer.
384  * @param[in] inputDimensions The input dimensions of the image.
385  * @param[in] inputStride The input stride of the image.
386  * @param[out] outPixels Pointer to the output image buffer.
387  * @param[in] desiredDimensions The output dimensions of the image.
388  */
389 void LanczosSample1BPP(const unsigned char* __restrict__ inPixels,
390                        ImageDimensions inputDimensions,
391                        unsigned int    inputStride,
392                        unsigned char* __restrict__ outPixels,
393                        ImageDimensions desiredDimensions);
394
395 /**
396  * @brief Resamples the input image with the Lanczos algorithm.
397  *
398  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
399  * separate buffer from the output buffer.
400  *
401  * @param[in] inPixels Pointer to the input image buffer.
402  * @param[in] inputDimensions The input dimensions of the image.
403  * @param[in] inputStride The input stride of the image.
404  * @param[out] outPixels Pointer to the output image buffer.
405  * @param[in] desiredDimensions The output dimensions of the image.
406  */
407 void Resample(const unsigned char* __restrict__ inPixels,
408               ImageDimensions inputDimensions,
409               unsigned int    inputStride,
410               unsigned char* __restrict__ outPixels,
411               ImageDimensions   desiredDimensions,
412               Resampler::Filter filterType,
413               int               numChannels,
414               bool              hasAlpha);
415
416 /**
417  * @brief Rotates the input image with an implementation of the 'Rotate by Shear' algorithm.
418  *
419  * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
420  * separate buffer from the output buffer.
421  *
422  * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
423  *
424  * @param[in] pixelsIn The input buffer.
425  * @param[in] widthIn The width of the input buffer.
426  * @param[in] heightIn The height of the input buffer.
427  * @param[in] strideIn The stride of the input buffer.
428  * @param[in] pixelSize The size of the pixel.
429  * @param[in] radians The rotation angle in radians.
430  * @param[out] pixelsOut The rotated output buffer.
431  * @param[out] widthOut The width of the output buffer.
432  * @param[out] heightOut The height of the output buffer.
433  */
434 void RotateByShear(const uint8_t* const pixelsIn,
435                    unsigned int         widthIn,
436                    unsigned int         heightIn,
437                    unsigned int         strideIn,
438                    unsigned int         pixelSize,
439                    float                radians,
440                    uint8_t*&            pixelsOut,
441                    unsigned int&        widthOut,
442                    unsigned int&        heightOut);
443
444 /**
445  * @brief Applies to the input image a horizontal shear transformation.
446  *
447  * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
448  * separate buffer from the output buffer.
449  * @pre The maximun/minimum shear angle is +/-45 degrees (PI/4 around 0.79 radians).
450  *
451  * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
452  *
453  * @param[in] pixelsIn The input buffer.
454  * @param[in] widthIn The width of the input buffer.
455  * @param[in] heightIn The height of the input buffer.
456  * @param[in] strideIn The stride of the input buffer.
457  * @param[in] pixelSize The size of the pixel.
458  * @param[in] radians The shear angle in radians.
459  * @param[out] pixelsOut The rotated output buffer.
460  * @param[out] widthOut The width of the output buffer.
461  * @param[out] heightOut The height of the output buffer.
462  */
463 void HorizontalShear(const uint8_t* const pixelsIn,
464                      unsigned int         widthIn,
465                      unsigned int         heightIn,
466                      unsigned int         strideIn,
467                      unsigned int         pixelSize,
468                      float                radians,
469                      uint8_t*&            pixelsOut,
470                      unsigned int&        widthOut,
471                      unsigned int&        heightOut);
472
473 /**@}*/
474
475 /**
476  * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
477  * @{
478  */
479
480 /**
481  * @brief Average adjacent pairs of pixels, overwriting the input array.
482  * @param[in,out] pixels The array of pixels to work on.
483  * @param[i]      width  The number of pixels in the array passed-in.
484  */
485 void HalveScanlineInPlaceRGB888(unsigned char* pixels, unsigned int width);
486
487 /**
488  * @copydoc HalveScanlineInPlaceRGB888
489  */
490 void HalveScanlineInPlaceRGBA8888(unsigned char* pixels, unsigned int width);
491
492 /**
493  * @copydoc HalveScanlineInPlaceRGB888
494  */
495 void HalveScanlineInPlaceRGB565(unsigned char* pixels, unsigned int width);
496
497 /**
498  * @copydoc HalveScanlineInPlaceRGB888
499  */
500 void HalveScanlineInPlace2Bytes(unsigned char* pixels, unsigned int width);
501
502 /**
503  * @copydoc HalveScanlineInPlaceRGB888
504  */
505 void HalveScanlineInPlace1Byte(unsigned char* pixels, unsigned int width);
506
507 /**
508  * @brief Average pixels at corresponding offsets in two scanlines.
509  *
510  * outputScanline is allowed to alias scanline1.
511  * @param[in] scanline1 First scanline of pixels to average.
512  * @param[in] scanline2 Second scanline of pixels to average.
513  * @param[out] outputScanline Destination for the averaged pixels.
514  * @param[in] width The widths of all the scanlines passed-in.
515  */
516 void AverageScanlines1(const unsigned char* scanline1,
517                        const unsigned char* scanline2,
518                        unsigned char*       outputScanline,
519                        /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
520                        unsigned int width);
521
522 /**
523  * @copydoc AverageScanlines1
524  */
525 void AverageScanlines2(const unsigned char* scanline1,
526                        const unsigned char* scanline2,
527                        unsigned char*       outputScanline,
528                        /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
529                        unsigned int width);
530
531 /**
532  * @copydoc AverageScanlines1
533  */
534 void AverageScanlines3(const unsigned char* scanline1,
535                        const unsigned char* scanline2,
536                        unsigned char*       outputScanline,
537                        /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
538                        unsigned int width);
539
540 /**
541  * @copydoc AverageScanlines1
542  */
543 void AverageScanlinesRGBA8888(const unsigned char* scanline1,
544                               const unsigned char* scanline2,
545                               unsigned char*       outputScanline,
546                               unsigned int         width);
547
548 /**
549  * @copydoc AverageScanlines1
550  */
551 void AverageScanlinesRGB565(const unsigned char* scanline1,
552                             const unsigned char* scanline2,
553                             unsigned char*       outputScanline,
554                             unsigned int         width);
555 /**@}*/
556
557 /**
558  * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
559  * @{
560  */
561
562 /**
563  * @brief Average two integer arguments.
564  * @return The average of two uint arguments.
565  * @param[in] a First component to average.
566  * @param[in] b Second component to average.
567  **/
568 inline unsigned int AverageComponent(unsigned int a, unsigned int b)
569 {
570   unsigned int avg = (a + b) >> 1u;
571   return avg;
572 }
573
574 /**
575  * @brief Average a pair of RGBA8888 pixels.
576  * @return The average of two RGBA8888 pixels.
577  * @param[in] a First pixel to average.
578  * @param[in] b Second pixel to average
579  **/
580 inline uint32_t AveragePixelRGBA8888(uint32_t a, uint32_t b)
581 {
582   /**
583    * @code
584    * const unsigned int avg =
585    *   (AverageComponent((a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u) << 1u) & 0xff000000) +
586    *   (AverageComponent(a & 0x00ff0000, b & 0x00ff0000) & 0x00ff0000) +
587    *   (AverageComponent(a & 0x0000ff00, b & 0x0000ff00) & 0x0000ff00) +
588    *   (AverageComponent(a & 0x000000ff, b & 0x000000ff);
589    * return avg;
590    * @endcode
591    */
592   return (((a ^ b) & 0xfefefefeu) >> 1) + (a & b);
593   ///@ToDo: Optimise for ARM using the single ARMV6 instruction: UHADD8  R4, R0, R5. This is not Neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro.
594 }
595
596 /**
597  * @brief Average a pair of RGB565 pixels.
598  * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
599  * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
600  * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
601  **/
602 inline uint32_t AveragePixelRGB565(uint32_t a, uint32_t b)
603 {
604   /**
605    * @code
606    * const unsigned int avg =
607    *   (AverageComponent(a & 0xf800, b & 0xf800) & 0xf800) +
608    *   (AverageComponent(a & 0x7e0, b & 0x7e0) & 0x7e0) +
609    *   (AverageComponent(a & 0x1f, b & 0x1f));
610    * return avg;
611    * @endcode
612    */
613   return (((a ^ b) & 0xf7deu) >> 1) + (a & b);
614 }
615
616 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
617 inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend)
618 {
619   DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
620   /**
621    * @code
622    * const unsigned int weightedAFixed = a * (65535u - fractBlend);
623    * const unsigned int weightedBFixed = b * fractBlend;
624    * const unsigned     blended        = (weightedAFixed + weightedBFixed);
625    * @endcode
626    */
627   const unsigned int blended = (a << 16) - a + (static_cast<int32_t>(b) - static_cast<int32_t>(a)) * fractBlend;
628   return blended;
629 }
630
631 /** @brief Blend two 16.16 inputs to give a 16.32 output. */
632 inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend)
633 {
634   DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
635   /**
636    * @code
637    * // Blend while promoting intermediates to 16.32 fixed point:
638    * const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
639    * const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
640    * const uint64_t blended        = (weightedAFixed + weightedBFixed);
641    * @endcode
642    */
643   const uint64_t blended = (static_cast<uint64_t>(a) << 16) - a + (static_cast<int64_t>(b) - static_cast<int64_t>(a)) * fractBlend;
644   return blended;
645 }
646
647 /**
648  * @brief Blend 4 taps into one value using horizontal and vertical weights.
649  */
650 inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical)
651 {
652   DALI_ASSERT_DEBUG(fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point.");
653   DALI_ASSERT_DEBUG(fractBlendVertical <= 65535u && "Factor should be in 0.16 fixed-point.");
654
655   /**
656    * @code
657    * const unsigned int topBlend   = WeightedBlendIntToFixed1616(tl, tr, fractBlendHorizontal);
658    * const unsigned int botBlend   = WeightedBlendIntToFixed1616(bl, br, fractBlendHorizontal);
659    * const uint64_t     blended2x2 = WeightedBlendFixed1616ToFixed1632(topBlend, botBlend, fractBlendVertical);
660    * const unsigned int rounded    = (blended2x2 + (1u << 31u)) >> 32u;
661    * @endcode
662    */
663
664   /**
665    * Hard-coding optimize!
666    *
667    * Let p = 65536, s.t we can optimze it as << 16.
668    * Let x = fractBlendHorizontal, y = fractBlendVertical.
669    * topBlend = (tl*p - tl - tl*x + tr*x)
670    * botBlend = (bl*p - bl - bl*x + br*x)
671    * blended2x2 = topBlend*p - topBlend - topBlend*y + botBlend*y
672    *
673    * And now we can split all values.
674    * tl*p*p - tl*p - tl*x*p + tr*x*p  -  tl*p + tl + tl*x - tr*x  -  tl*y*p + tl*y + tl*x*y - tr*x*y  +  bl*y*p - bl*y - bl*x*y + br*x*y;
675    * --> (collect by p, x, and y)
676    * (tl)*p*p + (-2tl + (-tl + tr)*x + (-tl+bl)*y)*p + tl + (tl - tr)*x + (tl - bl)*y + (tl - tr - bl + br)*x*y
677    *
678    * A = (tl - tr) * x;
679    * B = (tl - bl) * y;
680    * C = (tl - tr - bl + br) * x * y;
681    * D = (2*tl + A + B)
682    * -->
683    * (tl << 32) - (D << 16) + tl + A + B + C
684    *
685    * Becareful of overflow and negative value.
686    */
687   const int32_t A = (static_cast<int32_t>(tl) - static_cast<int32_t>(tr)) * static_cast<int32_t>(fractBlendHorizontal);
688   const int32_t B = (static_cast<int32_t>(tl) - static_cast<int32_t>(bl)) * static_cast<int32_t>(fractBlendVertical);
689   const int64_t C = (static_cast<int64_t>(tl) - static_cast<int64_t>(tr) - static_cast<int64_t>(bl) + static_cast<int64_t>(br)) * static_cast<int64_t>(fractBlendHorizontal) * static_cast<int64_t>(fractBlendVertical);
690   const int64_t D = ((static_cast<int64_t>(tl) << 1) + A + B);
691
692   const uint64_t     blended2x2 = (static_cast<int64_t>(tl) << 32u) - (D << 16u) + tl + A + B + C;
693   const unsigned int rounded    = (blended2x2 + (1u << 31u)) >> 32u;
694   return rounded;
695 }
696
697 /**@}*/
698
699 } /* namespace Platform */
700 } /* namespace Internal */
701 } /* namespace Dali */
702
703 #endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H */