1 /*
2  * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
3 
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10 
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13 
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 
23 #include "../../lv_conf_internal.h"
24 #if LV_USE_THORVG_INTERNAL
25 
26 #ifdef _WIN32
27     #include <malloc.h>
28 #elif defined(__linux__)
29     #include <alloca.h>
30 #else
31     #include <stdlib.h>
32 #endif
33 
34 #include "tvgMath.h"
35 #include "tvgRender.h"
36 #include "tvgSwCommon.h"
37 
38 /************************************************************************/
39 /* Internal Class Implementation                                        */
40 /************************************************************************/
41 constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
42 
43 struct FillLinear
44 {
operator ()FillLinear45     void operator()(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, SwMask op, uint8_t a)
46     {
47         fillLinear(fill, dst, y, x, len, op, a);
48     }
49 
operator ()FillLinear50     void operator()(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwMask op, uint8_t a)
51     {
52         fillLinear(fill, dst, y, x, len, cmp, op, a);
53     }
54 
operator ()FillLinear55     void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
56     {
57         fillLinear(fill, dst, y, x, len, op, a);
58     }
59 
operator ()FillLinear60     void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity)
61     {
62         fillLinear(fill, dst, y, x, len, cmp, alpha, csize, opacity);
63     }
64 
operator ()FillLinear65     void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a)
66     {
67         fillLinear(fill, dst, y, x, len, op, op2, a);
68     }
69 
70 };
71 
72 struct FillRadial
73 {
operator ()FillRadial74     void operator()(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, SwMask op, uint8_t a)
75     {
76         fillRadial(fill, dst, y, x, len, op, a);
77     }
78 
operator ()FillRadial79     void operator()(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwMask op, uint8_t a)
80     {
81         fillRadial(fill, dst, y, x, len, cmp, op, a);
82     }
83 
operator ()FillRadial84     void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
85     {
86         fillRadial(fill, dst, y, x, len, op, a);
87     }
88 
operator ()FillRadial89     void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity)
90     {
91         fillRadial(fill, dst, y, x, len, cmp, alpha, csize, opacity);
92     }
93 
operator ()FillRadial94     void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a)
95     {
96         fillRadial(fill, dst, y, x, len, op, op2, a);
97     }
98 };
99 
100 
_alpha(uint8_t * a)101 static inline uint8_t _alpha(uint8_t* a)
102 {
103     return *a;
104 }
105 
106 
_ialpha(uint8_t * a)107 static inline uint8_t _ialpha(uint8_t* a)
108 {
109     return ~(*a);
110 }
111 
112 
_abgrLuma(uint8_t * c)113 static inline uint8_t _abgrLuma(uint8_t* c)
114 {
115     auto v = *(uint32_t*)c;
116     return ((((v&0xff)*54) + (((v>>8)&0xff)*183) + (((v>>16)&0xff)*19))) >> 8; //0.2125*R + 0.7154*G + 0.0721*B
117 }
118 
119 
_argbLuma(uint8_t * c)120 static inline uint8_t _argbLuma(uint8_t* c)
121 {
122     auto v = *(uint32_t*)c;
123     return ((((v&0xff)*19) + (((v>>8)&0xff)*183) + (((v>>16)&0xff)*54))) >> 8; //0.0721*B + 0.7154*G + 0.2125*R
124 }
125 
126 
_abgrInvLuma(uint8_t * c)127 static inline uint8_t _abgrInvLuma(uint8_t* c)
128 {
129     return ~_abgrLuma(c);
130 }
131 
132 
_argbInvLuma(uint8_t * c)133 static inline uint8_t _argbInvLuma(uint8_t* c)
134 {
135     return ~_argbLuma(c);
136 }
137 
138 
_abgrJoin(uint8_t r,uint8_t g,uint8_t b,uint8_t a)139 static inline uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
140 {
141     return (a << 24 | b << 16 | g << 8 | r);
142 }
143 
144 
_argbJoin(uint8_t r,uint8_t g,uint8_t b,uint8_t a)145 static inline uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
146 {
147     return (a << 24 | r << 16 | g << 8 | b);
148 }
149 
_blending(const SwSurface * surface)150 static inline bool _blending(const SwSurface* surface)
151 {
152     return (surface->blender) ? true : false;
153 }
154 
155 
156 /* OPTIMIZE_ME: Probably, we can separate masking(8bits) / composition(32bits)
157    This would help to enhance the performance by avoiding the unnecessary matting from the composition */
_compositing(const SwSurface * surface)158 static inline bool _compositing(const SwSurface* surface)
159 {
160     if (!surface->compositor || (int)surface->compositor->method <= (int)CompositeMethod::ClipPath) return false;
161     return true;
162 }
163 
164 
_matting(const SwSurface * surface)165 static inline bool _matting(const SwSurface* surface)
166 {
167     if ((int)surface->compositor->method < (int)CompositeMethod::AddMask) return true;
168     else return false;
169 }
170 
_opMaskNone(uint8_t s,TVG_UNUSED uint8_t d,TVG_UNUSED uint8_t a)171 static inline uint8_t _opMaskNone(uint8_t s, TVG_UNUSED uint8_t d, TVG_UNUSED uint8_t a)
172 {
173     return s;
174 }
175 
_opMaskAdd(uint8_t s,uint8_t d,uint8_t a)176 static inline uint8_t _opMaskAdd(uint8_t s, uint8_t d, uint8_t a)
177 {
178     return s + MULTIPLY(d, a);
179 }
180 
181 
_opMaskSubtract(uint8_t s,uint8_t d,TVG_UNUSED uint8_t a)182 static inline uint8_t _opMaskSubtract(uint8_t s, uint8_t d, TVG_UNUSED uint8_t a)
183 {
184    return MULTIPLY(s, 255 - d);
185 }
186 
187 
_opMaskIntersect(uint8_t s,uint8_t d,TVG_UNUSED uint8_t a)188 static inline uint8_t _opMaskIntersect(uint8_t s, uint8_t d, TVG_UNUSED uint8_t a)
189 {
190    return MULTIPLY(s, d);
191 }
192 
193 
_opMaskDifference(uint8_t s,uint8_t d,uint8_t a)194 static inline uint8_t _opMaskDifference(uint8_t s, uint8_t d, uint8_t a)
195 {
196     return MULTIPLY(s, 255 - d) + MULTIPLY(d, a);
197 }
198 
199 
_opMaskLighten(uint8_t s,uint8_t d,uint8_t a)200 static inline uint8_t _opMaskLighten(uint8_t s, uint8_t d, uint8_t a)
201 {
202     return (s > d) ? s : d;
203 }
204 
205 
_opMaskDarken(uint8_t s,uint8_t d,uint8_t a)206 static inline uint8_t _opMaskDarken(uint8_t s, uint8_t d, uint8_t a)
207 {
208     return (s < d) ? s : d;
209 }
210 
211 
_direct(CompositeMethod method)212 static inline bool _direct(CompositeMethod method)
213 {
214     if (method == CompositeMethod::SubtractMask || method == CompositeMethod::IntersectMask || method == CompositeMethod::DarkenMask) return true;
215     return false;
216 }
217 
218 
_getMaskOp(CompositeMethod method)219 static inline SwMask _getMaskOp(CompositeMethod method)
220 {
221     switch (method) {
222         case CompositeMethod::AddMask: return _opMaskAdd;
223         case CompositeMethod::SubtractMask: return _opMaskSubtract;
224         case CompositeMethod::DifferenceMask: return _opMaskDifference;
225         case CompositeMethod::IntersectMask: return _opMaskIntersect;
226         case CompositeMethod::LightenMask: return _opMaskLighten;
227         case CompositeMethod::DarkenMask: return _opMaskDarken;
228         default: return nullptr;
229     }
230 }
231 
232 
_compositeMaskImage(SwSurface * surface,const SwImage * image,const SwBBox & region)233 static bool _compositeMaskImage(SwSurface* surface, const SwImage* image, const SwBBox& region)
234 {
235     auto dbuffer = &surface->buf8[region.min.y * surface->stride + region.min.x];
236     auto sbuffer = image->buf8 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
237 
238     for (auto y = region.min.y; y < region.max.y; ++y) {
239         auto dst = dbuffer;
240         auto src = sbuffer;
241         for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
242             *dst = *src + MULTIPLY(*dst, ~*src);
243         }
244         dbuffer += surface->stride;
245         sbuffer += image->stride;
246     }
247     return true;
248 }
249 
250 
251 #include "tvgSwRasterTexmap.h"
252 #include "tvgSwRasterC.h"
253 #include "tvgSwRasterAvx.h"
254 #include "tvgSwRasterNeon.h"
255 
256 
_sampleSize(float scale)257 static inline uint32_t _sampleSize(float scale)
258 {
259     auto sampleSize = static_cast<uint32_t>(0.5f / scale);
260     if (sampleSize == 0) sampleSize = 1;
261     return sampleSize;
262 }
263 
264 
265 //Bilinear Interpolation
266 //OPTIMIZE_ME: Skip the function pointer access
_interpUpScaler(const uint32_t * img,TVG_UNUSED uint32_t stride,uint32_t w,uint32_t h,float sx,float sy,TVG_UNUSED int32_t miny,TVG_UNUSED int32_t maxy,TVG_UNUSED int32_t n)267 static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, TVG_UNUSED int32_t miny, TVG_UNUSED int32_t maxy, TVG_UNUSED int32_t n)
268 {
269     auto rx = (size_t)(sx);
270     auto ry = (size_t)(sy);
271     auto rx2 = rx + 1;
272     if (rx2 >= w) rx2 = w - 1;
273     auto ry2 = ry + 1;
274     if (ry2 >= h) ry2 = h - 1;
275 
276     auto dx = (sx > 0.0f) ? static_cast<uint8_t>((sx - rx) * 255.0f) : 0;
277     auto dy = (sy > 0.0f) ? static_cast<uint8_t>((sy - ry) * 255.0f) : 0;
278 
279     auto c1 = img[rx + ry * w];
280     auto c2 = img[rx2 + ry * w];
281     auto c3 = img[rx + ry2 * w];
282     auto c4 = img[rx2 + ry2 * w];
283 
284     return INTERPOLATE(INTERPOLATE(c4, c3, dx), INTERPOLATE(c2, c1, dx), dy);
285 }
286 
287 
288 //2n x 2n Mean Kernel
289 //OPTIMIZE_ME: Skip the function pointer access
_interpDownScaler(const uint32_t * img,uint32_t stride,uint32_t w,uint32_t h,float sx,TVG_UNUSED float sy,int32_t miny,int32_t maxy,int32_t n)290 static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, float sx, TVG_UNUSED float sy, int32_t miny, int32_t maxy, int32_t n)
291 {
292     size_t c[4] = {0, 0, 0, 0};
293 
294     int32_t minx = (int32_t)sx - n;
295     if (minx < 0) minx = 0;
296 
297     int32_t maxx = (int32_t)sx + n;
298     if (maxx >= (int32_t)w) maxx = w;
299 
300     int32_t inc = (n / 2) + 1;
301     n = 0;
302 
303     auto src = img + minx + miny * stride;
304 
305     for (auto y = miny; y < maxy; y += inc) {
306         auto p = src;
307         for (auto x = minx; x < maxx; x += inc, p += inc) {
308             c[0] += A(*p);
309             c[1] += C1(*p);
310             c[2] += C2(*p);
311             c[3] += C3(*p);
312             ++n;
313         }
314         src += (stride * inc);
315     }
316 
317     c[0] /= n;
318     c[1] /= n;
319     c[2] /= n;
320     c[3] /= n;
321 
322     return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
323 }
324 
325 
326 /************************************************************************/
327 /* Rect                                                                 */
328 /************************************************************************/
329 
_rasterCompositeMaskedRect(SwSurface * surface,const SwBBox & region,SwMask maskOp,uint8_t r,uint8_t g,uint8_t b,uint8_t a)330 static bool _rasterCompositeMaskedRect(SwSurface* surface, const SwBBox& region, SwMask maskOp, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
331 {
332     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
333     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
334     auto cstride = surface->compositor->image.stride;
335     auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x);   //compositor buffer
336     auto ialpha = 255 - a;
337 
338     for (uint32_t y = 0; y < h; ++y) {
339         auto cmp = cbuffer;
340         for (uint32_t x = 0; x < w; ++x, ++cmp) {
341             *cmp = maskOp(a, *cmp, ialpha);
342         }
343         cbuffer += cstride;
344     }
345     return _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox);
346 }
347 
348 
_rasterDirectMaskedRect(SwSurface * surface,const SwBBox & region,SwMask maskOp,uint8_t r,uint8_t g,uint8_t b,uint8_t a)349 static bool _rasterDirectMaskedRect(SwSurface* surface, const SwBBox& region, SwMask maskOp, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
350 {
351     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
352     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
353     auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x);   //compositor buffer
354     auto dbuffer = surface->buf8 + (region.min.y * surface->stride + region.min.x);   //destination buffer
355 
356     for (uint32_t y = 0; y < h; ++y) {
357         auto cmp = cbuffer;
358         auto dst = dbuffer;
359         for (uint32_t x = 0; x < w; ++x, ++cmp, ++dst) {
360             auto tmp = maskOp(a, *cmp, 0);   //not use alpha.
361             *dst = tmp + MULTIPLY(*dst, ~tmp);
362         }
363         cbuffer += surface->compositor->image.stride;
364         dbuffer += surface->stride;
365     }
366     return true;
367 }
368 
369 
_rasterMaskedRect(SwSurface * surface,const SwBBox & region,uint8_t r,uint8_t g,uint8_t b,uint8_t a)370 static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
371 {
372     //8bit masking channels composition
373     if (surface->channelSize != sizeof(uint8_t)) return false;
374 
375     TVGLOG("SW_ENGINE", "Masked(%d) Rect [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y);
376 
377     auto maskOp = _getMaskOp(surface->compositor->method);
378     if (_direct(surface->compositor->method)) return _rasterDirectMaskedRect(surface, region, maskOp, r, g, b, a);
379     else return _rasterCompositeMaskedRect(surface, region, maskOp, r, g, b, a);
380     return false;
381 }
382 
383 
_rasterMattedRect(SwSurface * surface,const SwBBox & region,uint8_t r,uint8_t g,uint8_t b,uint8_t a)384 static bool _rasterMattedRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
385 {
386     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
387     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
388     auto csize = surface->compositor->image.channelSize;
389     auto cbuffer = surface->compositor->image.buf8 + ((region.min.y * surface->compositor->image.stride + region.min.x) * csize);   //compositor buffer
390     auto alpha = surface->alpha(surface->compositor->method);
391 
392     TVGLOG("SW_ENGINE", "Matted(%d) Rect [Region: %lu %lu %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h);
393 
394     //32bits channels
395     if (surface->channelSize == sizeof(uint32_t)) {
396         auto color = surface->join(r, g, b, a);
397         auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
398         for (uint32_t y = 0; y < h; ++y) {
399             auto dst = &buffer[y * surface->stride];
400             auto cmp = &cbuffer[y * surface->compositor->image.stride * csize];
401             for (uint32_t x = 0; x < w; ++x, ++dst, cmp += csize) {
402                 auto tmp = ALPHA_BLEND(color, alpha(cmp));
403                 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
404             }
405         }
406     //8bits grayscale
407     } else if (surface->channelSize == sizeof(uint8_t)) {
408         auto buffer = surface->buf8 + (region.min.y * surface->stride) + region.min.x;
409         for (uint32_t y = 0; y < h; ++y) {
410             auto dst = &buffer[y * surface->stride];
411             auto cmp = &cbuffer[y * surface->compositor->image.stride * csize];
412             for (uint32_t x = 0; x < w; ++x, ++dst, cmp += csize) {
413                 *dst = INTERPOLATE8(a, *dst, alpha(cmp));
414             }
415         }
416     }
417     return true;
418 }
419 
420 
_rasterBlendingRect(SwSurface * surface,const SwBBox & region,uint8_t r,uint8_t g,uint8_t b,uint8_t a)421 static bool _rasterBlendingRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
422 {
423     if (surface->channelSize != sizeof(uint32_t)) return false;
424 
425     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
426     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
427     auto color = surface->join(r, g, b, a);
428     auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
429 
430     for (uint32_t y = 0; y < h; ++y) {
431         auto dst = &buffer[y * surface->stride];
432         for (uint32_t x = 0; x < w; ++x, ++dst) {
433             *dst = surface->blender(color, *dst, 255);
434         }
435     }
436     return true;
437 }
438 
439 
_rasterTranslucentRect(SwSurface * surface,const SwBBox & region,uint8_t r,uint8_t g,uint8_t b,uint8_t a)440 static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
441 {
442 #if defined(THORVG_AVX_VECTOR_SUPPORT)
443     return avxRasterTranslucentRect(surface, region, r, g, b, a);
444 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
445     return neonRasterTranslucentRect(surface, region, r, g, b, a);
446 #else
447     return cRasterTranslucentRect(surface, region, r, g, b, a);
448 #endif
449 }
450 
451 
_rasterSolidRect(SwSurface * surface,const SwBBox & region,uint8_t r,uint8_t g,uint8_t b)452 static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b)
453 {
454     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
455     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
456 
457     //32bits channels
458     if (surface->channelSize == sizeof(uint32_t)) {
459         auto color = surface->join(r, g, b, 255);
460         auto buffer = surface->buf32 + (region.min.y * surface->stride);
461         for (uint32_t y = 0; y < h; ++y) {
462             rasterPixel32(buffer + y * surface->stride, color, region.min.x, w);
463         }
464         return true;
465     }
466     //8bits grayscale
467     if (surface->channelSize == sizeof(uint8_t)) {
468         for (uint32_t y = 0; y < h; ++y) {
469             rasterGrayscale8(surface->buf8, 255, (y + region.min.y) * surface->stride + region.min.x, w);
470         }
471         return true;
472     }
473     return false;
474 }
475 
476 
_rasterRect(SwSurface * surface,const SwBBox & region,uint8_t r,uint8_t g,uint8_t b,uint8_t a)477 static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
478 {
479     if (_compositing(surface)) {
480         if (_matting(surface)) return _rasterMattedRect(surface, region, r, g, b, a);
481         else return _rasterMaskedRect(surface, region, r, g, b, a);
482     } else if (_blending(surface)) {
483         return _rasterBlendingRect(surface, region, r, g, b, a);
484     } else {
485         if (a == 255) return _rasterSolidRect(surface, region, r, g, b);
486         else return _rasterTranslucentRect(surface, region, r, g, b, a);
487     }
488     return false;
489 }
490 
491 
492 /************************************************************************/
493 /* Rle                                                                  */
494 /************************************************************************/
495 
_rasterCompositeMaskedRle(SwSurface * surface,SwRle * rle,SwMask maskOp,uint8_t r,uint8_t g,uint8_t b,uint8_t a)496 static bool _rasterCompositeMaskedRle(SwSurface* surface, SwRle* rle, SwMask maskOp, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
497 {
498     auto span = rle->spans;
499     auto cbuffer = surface->compositor->image.buf8;
500     auto cstride = surface->compositor->image.stride;
501     uint8_t src;
502 
503     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
504         auto cmp = &cbuffer[span->y * cstride + span->x];
505         if (span->coverage == 255) src = a;
506         else src = MULTIPLY(a, span->coverage);
507         auto ialpha = 255 - src;
508         for (auto x = 0; x < span->len; ++x, ++cmp) {
509             *cmp = maskOp(src, *cmp, ialpha);
510         }
511     }
512     return _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox);
513 }
514 
515 
_rasterDirectMaskedRle(SwSurface * surface,SwRle * rle,SwMask maskOp,uint8_t r,uint8_t g,uint8_t b,uint8_t a)516 static bool _rasterDirectMaskedRle(SwSurface* surface, SwRle* rle, SwMask maskOp, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
517 {
518     auto span = rle->spans;
519     auto cbuffer = surface->compositor->image.buf8;
520     auto cstride = surface->compositor->image.stride;
521     uint8_t src;
522 
523     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
524         auto cmp = &cbuffer[span->y * cstride + span->x];
525         auto dst = &surface->buf8[span->y * surface->stride + span->x];
526         if (span->coverage == 255) src = a;
527         else src = MULTIPLY(a, span->coverage);
528         for (auto x = 0; x < span->len; ++x, ++cmp, ++dst) {
529             auto tmp = maskOp(src, *cmp, 0);     //not use alpha
530             *dst = tmp + MULTIPLY(*dst, ~tmp);
531         }
532     }
533     return true;
534 }
535 
536 
_rasterMaskedRle(SwSurface * surface,SwRle * rle,uint8_t r,uint8_t g,uint8_t b,uint8_t a)537 static bool _rasterMaskedRle(SwSurface* surface, SwRle* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
538 {
539     TVGLOG("SW_ENGINE", "Masked(%d) Rle", (int)surface->compositor->method);
540 
541     //8bit masking channels composition
542     if (surface->channelSize != sizeof(uint8_t)) return false;
543 
544     auto maskOp = _getMaskOp(surface->compositor->method);
545     if (_direct(surface->compositor->method)) return _rasterDirectMaskedRle(surface, rle, maskOp, r, g, b, a);
546     else return _rasterCompositeMaskedRle(surface, rle, maskOp, r, g, b, a);
547     return false;
548 }
549 
550 
_rasterMattedRle(SwSurface * surface,SwRle * rle,uint8_t r,uint8_t g,uint8_t b,uint8_t a)551 static bool _rasterMattedRle(SwSurface* surface, SwRle* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
552 {
553     TVGLOG("SW_ENGINE", "Matted(%d) Rle", (int)surface->compositor->method);
554 
555     auto span = rle->spans;
556     auto cbuffer = surface->compositor->image.buf8;
557     auto csize = surface->compositor->image.channelSize;
558     auto alpha = surface->alpha(surface->compositor->method);
559 
560     //32bit channels
561     if (surface->channelSize == sizeof(uint32_t)) {
562         uint32_t src;
563         auto color = surface->join(r, g, b, a);
564         for (uint32_t i = 0; i < rle->size; ++i, ++span) {
565             auto dst = &surface->buf32[span->y * surface->stride + span->x];
566             auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
567             if (span->coverage == 255) src = color;
568             else src = ALPHA_BLEND(color, span->coverage);
569             for (uint32_t x = 0; x < span->len; ++x, ++dst, cmp += csize) {
570                 auto tmp = ALPHA_BLEND(src, alpha(cmp));
571                 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
572             }
573         }
574     //8bit grayscale
575     } else if (surface->channelSize == sizeof(uint8_t)) {
576         uint8_t src;
577         for (uint32_t i = 0; i < rle->size; ++i, ++span) {
578             auto dst = &surface->buf8[span->y * surface->stride + span->x];
579             auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
580             if (span->coverage == 255) src = a;
581             else src = MULTIPLY(a, span->coverage);
582             for (uint32_t x = 0; x < span->len; ++x, ++dst, cmp += csize) {
583                 *dst = INTERPOLATE8(src, *dst, alpha(cmp));
584             }
585         }
586     }
587     return true;
588 }
589 
590 
_rasterBlendingRle(SwSurface * surface,const SwRle * rle,uint8_t r,uint8_t g,uint8_t b,uint8_t a)591 static bool _rasterBlendingRle(SwSurface* surface, const SwRle* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
592 {
593     if (surface->channelSize != sizeof(uint32_t)) return false;
594 
595     auto span = rle->spans;
596     auto color = surface->join(r, g, b, a);
597 
598     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
599         auto dst = &surface->buf32[span->y * surface->stride + span->x];
600         if (span->coverage == 255) {
601             for (uint32_t x = 0; x < span->len; ++x, ++dst) {
602                 *dst = surface->blender(color, *dst, 255);
603             }
604         } else {
605             for (uint32_t x = 0; x < span->len; ++x, ++dst) {
606                 auto tmp = surface->blender(color, *dst, 255);
607                 *dst = INTERPOLATE(tmp, *dst, span->coverage);
608             }
609         }
610     }
611     return true;
612 }
613 
614 
_rasterTranslucentRle(SwSurface * surface,const SwRle * rle,uint8_t r,uint8_t g,uint8_t b,uint8_t a)615 static bool _rasterTranslucentRle(SwSurface* surface, const SwRle* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
616 {
617 #if defined(THORVG_AVX_VECTOR_SUPPORT)
618     return avxRasterTranslucentRle(surface, rle, r, g, b, a);
619 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
620     return neonRasterTranslucentRle(surface, rle, r, g, b, a);
621 #else
622     return cRasterTranslucentRle(surface, rle, r, g, b, a);
623 #endif
624 }
625 
626 
_rasterSolidRle(SwSurface * surface,const SwRle * rle,uint8_t r,uint8_t g,uint8_t b)627 static bool _rasterSolidRle(SwSurface* surface, const SwRle* rle, uint8_t r, uint8_t g, uint8_t b)
628 {
629     auto span = rle->spans;
630 
631     //32bit channels
632     if (surface->channelSize == sizeof(uint32_t)) {
633         auto color = surface->join(r, g, b, 255);
634         for (uint32_t i = 0; i < rle->size; ++i, ++span) {
635             if (span->coverage == 255) {
636                 rasterPixel32(surface->buf32 + span->y * surface->stride, color, span->x, span->len);
637             } else {
638                 auto dst = &surface->buf32[span->y * surface->stride + span->x];
639                 auto src = ALPHA_BLEND(color, span->coverage);
640                 auto ialpha = 255 - span->coverage;
641                 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
642                     *dst = src + ALPHA_BLEND(*dst, ialpha);
643                 }
644             }
645         }
646     //8bit grayscale
647     } else if (surface->channelSize == sizeof(uint8_t)) {
648         for (uint32_t i = 0; i < rle->size; ++i, ++span) {
649             if (span->coverage == 255) {
650                 rasterGrayscale8(surface->buf8, span->coverage, span->y * surface->stride + span->x, span->len);
651             } else {
652                 auto dst = &surface->buf8[span->y * surface->stride + span->x];
653                 auto ialpha = 255 - span->coverage;
654                 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
655                     *dst = span->coverage + MULTIPLY(*dst, ialpha);
656                 }
657             }
658         }
659     }
660     return true;
661 }
662 
663 
_rasterRle(SwSurface * surface,SwRle * rle,uint8_t r,uint8_t g,uint8_t b,uint8_t a)664 static bool _rasterRle(SwSurface* surface, SwRle* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
665 {
666     if (!rle) return false;
667 
668     if (_compositing(surface)) {
669         if (_matting(surface)) return _rasterMattedRle(surface, rle, r, g, b, a);
670         else return _rasterMaskedRle(surface, rle, r, g, b, a);
671     } else if (_blending(surface)) {
672         return _rasterBlendingRle(surface, rle, r, g, b, a);
673     } else {
674         if (a == 255) return _rasterSolidRle(surface, rle, r, g, b);
675         else return _rasterTranslucentRle(surface, rle, r, g, b, a);
676     }
677     return false;
678 }
679 
680 
681 /************************************************************************/
682 /* RLE Scaled Image                                                     */
683 /************************************************************************/
684 
685 #define SCALED_IMAGE_RANGE_Y(y) \
686     auto sy = (y) * itransform->e22 + itransform->e23 - 0.49f; \
687     if (sy <= -0.5f || (uint32_t)(sy + 0.5f) >= image->h) continue; \
688     if (scaleMethod == _interpDownScaler) { \
689         auto my = (int32_t)nearbyint(sy); \
690         miny = my - (int32_t)sampleSize; \
691         if (miny < 0) miny = 0; \
692         maxy = my + (int32_t)sampleSize; \
693         if (maxy >= (int32_t)image->h) maxy = (int32_t)image->h; \
694     }
695 
696 #define SCALED_IMAGE_RANGE_X \
697     auto sx = (x) * itransform->e11 + itransform->e13 - 0.49f; \
698     if (sx <= -0.5f || (uint32_t)(sx + 0.5f) >= image->w) continue; \
699 
_rasterScaledMaskedRleImage(SwSurface * surface,const SwImage * image,const Matrix * itransform,const SwBBox & region,uint8_t opacity)700 static bool _rasterScaledMaskedRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
701 {
702     TVGERR("SW_ENGINE", "Not Supported Scaled Masked(%d) Rle Image", (int)surface->compositor->method);
703     return false;
704 }
705 
706 
_rasterScaledMattedRleImage(SwSurface * surface,const SwImage * image,const Matrix * itransform,const SwBBox & region,uint8_t opacity)707 static bool _rasterScaledMattedRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
708 {
709     TVGLOG("SW_ENGINE", "Scaled Matted(%d) Rle Image", (int)surface->compositor->method);
710 
711     auto span = image->rle->spans;
712     auto csize = surface->compositor->image.channelSize;
713     auto alpha = surface->alpha(surface->compositor->method);
714     auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
715     auto sampleSize = _sampleSize(image->scale);
716     int32_t miny = 0, maxy = 0;
717 
718     for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
719         SCALED_IMAGE_RANGE_Y(span->y)
720         auto dst = &surface->buf32[span->y * surface->stride + span->x];
721         auto cmp = &surface->compositor->image.buf8[(span->y * surface->compositor->image.stride + span->x) * csize];
722         auto a = MULTIPLY(span->coverage, opacity);
723         for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
724             SCALED_IMAGE_RANGE_X
725             auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
726             src = ALPHA_BLEND(src, (a == 255) ? alpha(cmp) : MULTIPLY(alpha(cmp), a));
727             *dst = src + ALPHA_BLEND(*dst, IA(src));
728         }
729     }
730     return true;
731 }
732 
733 
_rasterScaledBlendingRleImage(SwSurface * surface,const SwImage * image,const Matrix * itransform,const SwBBox & region,uint8_t opacity)734 static bool _rasterScaledBlendingRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
735 {
736     auto span = image->rle->spans;
737     auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
738     auto sampleSize = _sampleSize(image->scale);
739     int32_t miny = 0, maxy = 0;
740 
741     for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
742         SCALED_IMAGE_RANGE_Y(span->y)
743         auto dst = &surface->buf32[span->y * surface->stride + span->x];
744         auto alpha = MULTIPLY(span->coverage, opacity);
745         if (alpha == 255) {
746             for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
747                 SCALED_IMAGE_RANGE_X
748                 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
749                 auto tmp = surface->blender(src, *dst, 255);
750                 *dst = INTERPOLATE(tmp, *dst, A(src));
751             }
752         } else {
753             for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
754                 SCALED_IMAGE_RANGE_X
755                 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
756                 auto tmp = surface->blender(src, *dst, 255);
757                 *dst = INTERPOLATE(tmp, *dst, MULTIPLY(alpha, A(src)));
758             }
759         }
760     }
761     return true;
762 }
763 
764 
_rasterScaledRleImage(SwSurface * surface,const SwImage * image,const Matrix * itransform,const SwBBox & region,uint8_t opacity)765 static bool _rasterScaledRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
766 {
767     auto span = image->rle->spans;
768     auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
769     auto sampleSize = _sampleSize(image->scale);
770     int32_t miny = 0, maxy = 0;
771 
772     for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
773         SCALED_IMAGE_RANGE_Y(span->y)
774         auto dst = &surface->buf32[span->y * surface->stride + span->x];
775         auto alpha = MULTIPLY(span->coverage, opacity);
776         for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
777             SCALED_IMAGE_RANGE_X
778             auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
779             if (alpha < 255) src = ALPHA_BLEND(src, alpha);
780             *dst = src + ALPHA_BLEND(*dst, IA(src));
781         }
782     }
783     return true;
784 }
785 
786 
_scaledRleImage(SwSurface * surface,const SwImage * image,const Matrix & transform,const SwBBox & region,uint8_t opacity)787 static bool _scaledRleImage(SwSurface* surface, const SwImage* image, const Matrix& transform, const SwBBox& region, uint8_t opacity)
788 {
789     if (surface->channelSize == sizeof(uint8_t)) {
790         TVGERR("SW_ENGINE", "Not supported scaled rle image!");
791         return false;
792     }
793 
794     Matrix itransform;
795 
796     if (!inverse(&transform, &itransform)) return true;
797 
798     if (_compositing(surface)) {
799         if (_matting(surface)) return _rasterScaledMattedRleImage(surface, image, &itransform, region, opacity);
800         else return _rasterScaledMaskedRleImage(surface, image, &itransform, region, opacity);
801     } else if (_blending(surface)) {
802         return _rasterScaledBlendingRleImage(surface, image, &itransform, region, opacity);
803     } else {
804         return _rasterScaledRleImage(surface, image, &itransform, region, opacity);
805     }
806     return false;
807 }
808 
809 
810 /************************************************************************/
811 /* RLE Direct Image                                                     */
812 /************************************************************************/
813 
_rasterDirectMattedRleImage(SwSurface * surface,const SwImage * image,uint8_t opacity)814 static bool _rasterDirectMattedRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
815 {
816     TVGLOG("SW_ENGINE", "Direct Matted(%d) Rle Image", (int)surface->compositor->method);
817 
818     auto span = image->rle->spans;
819     auto csize = surface->compositor->image.channelSize;
820     auto cbuffer = surface->compositor->image.buf8;
821     auto alpha = surface->alpha(surface->compositor->method);
822 
823     for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
824         auto dst = &surface->buf32[span->y * surface->stride + span->x];
825         auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
826         auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
827         auto a = MULTIPLY(span->coverage, opacity);
828         if (a == 255) {
829             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img, cmp += csize) {
830                 auto tmp = ALPHA_BLEND(*img, alpha(cmp));
831                 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
832             }
833         } else {
834             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img, cmp += csize) {
835                 auto tmp = ALPHA_BLEND(*img, MULTIPLY(a, alpha(cmp)));
836                 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
837             }
838         }
839     }
840     return true;
841 }
842 
843 
_rasterDirectBlendingRleImage(SwSurface * surface,const SwImage * image,uint8_t opacity)844 static bool _rasterDirectBlendingRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
845 {
846     auto span = image->rle->spans;
847 
848     for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
849         auto dst = &surface->buf32[span->y * surface->stride + span->x];
850         auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
851         auto alpha = MULTIPLY(span->coverage, opacity);
852         if (alpha == 255) {
853             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
854                 *dst = surface->blender(*img, *dst, 255);
855             }
856         } else {
857             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
858                 auto tmp = surface->blender(*img, *dst, 255);
859                 *dst = INTERPOLATE(tmp, *dst, MULTIPLY(alpha, A(*img)));
860             }
861         }
862     }
863     return true;
864 }
865 
866 
_rasterDirectRleImage(SwSurface * surface,const SwImage * image,uint8_t opacity)867 static bool _rasterDirectRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
868 {
869     auto span = image->rle->spans;
870 
871     for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
872         auto dst = &surface->buf32[span->y * surface->stride + span->x];
873         auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
874         auto alpha = MULTIPLY(span->coverage, opacity);
875         if (alpha == 255) {
876             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
877                 *dst = *img + ALPHA_BLEND(*dst, IA(*img));
878             }
879         } else {
880             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
881                 auto src = ALPHA_BLEND(*img, alpha);
882                 *dst = src + ALPHA_BLEND(*dst, IA(src));
883             }
884         }
885     }
886     return true;
887 }
888 
889 
_rasterDirectMaskedRleImage(SwSurface * surface,const SwImage * image,uint8_t opacity)890 static bool _rasterDirectMaskedRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
891 {
892     TVGERR("SW_ENGINE", "Not Supported Direct Masked(%d) Rle Image", (int)surface->compositor->method);
893     return false;
894 }
895 
896 
_directRleImage(SwSurface * surface,const SwImage * image,uint8_t opacity)897 static bool _directRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
898 {
899     if (surface->channelSize == sizeof(uint8_t)) {
900         TVGERR("SW_ENGINE", "Not supported grayscale rle image!");
901         return false;
902     }
903 
904     if (_compositing(surface)) {
905         if (_matting(surface)) return _rasterDirectMattedRleImage(surface, image, opacity);
906         else return _rasterDirectMaskedRleImage(surface, image, opacity);
907     } else if (_blending(surface)) {
908         return _rasterDirectBlendingRleImage(surface, image, opacity);
909     } else {
910         return _rasterDirectRleImage(surface, image, opacity);
911     }
912     return false;
913 }
914 
915 
916 /************************************************************************/
917 /*Scaled Image                                                          */
918 /************************************************************************/
919 
_rasterScaledMaskedImage(SwSurface * surface,const SwImage * image,const Matrix * itransform,const SwBBox & region,uint8_t opacity)920 static bool _rasterScaledMaskedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
921 {
922     TVGERR("SW_ENGINE", "Not Supported Scaled Masked Image!");
923     return false;
924 }
925 
926 
_rasterScaledMattedImage(SwSurface * surface,const SwImage * image,const Matrix * itransform,const SwBBox & region,uint8_t opacity)927 static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
928 {
929     if (surface->channelSize == sizeof(uint8_t)) {
930         TVGERR("SW_ENGINE", "Not supported grayscale scaled matted image!");
931         return false;
932     }
933 
934     auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
935     auto csize = surface->compositor->image.channelSize;
936     auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
937     auto alpha = surface->alpha(surface->compositor->method);
938 
939     TVGLOG("SW_ENGINE", "Scaled Matted(%d) Image [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y);
940 
941     auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
942     auto sampleSize = _sampleSize(image->scale);
943     int32_t miny = 0, maxy = 0;
944 
945     for (auto y = region.min.y; y < region.max.y; ++y) {
946         SCALED_IMAGE_RANGE_Y(y)
947         auto dst = dbuffer;
948         auto cmp = cbuffer;
949         for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) {
950             SCALED_IMAGE_RANGE_X
951             auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
952             auto tmp = ALPHA_BLEND(src, opacity == 255 ? alpha(cmp) : MULTIPLY(opacity, alpha(cmp)));
953             *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
954         }
955         dbuffer += surface->stride;
956         cbuffer += surface->compositor->image.stride * csize;
957     }
958     return true;
959 }
960 
961 
_rasterScaledBlendingImage(SwSurface * surface,const SwImage * image,const Matrix * itransform,const SwBBox & region,uint8_t opacity)962 static bool _rasterScaledBlendingImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
963 {
964     if (surface->channelSize == sizeof(uint8_t)) {
965         TVGERR("SW_ENGINE", "Not supported grayscale scaled blending image!");
966         return false;
967     }
968 
969     auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
970     auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
971     auto sampleSize = _sampleSize(image->scale);
972     int32_t miny = 0, maxy = 0;
973 
974     for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
975         SCALED_IMAGE_RANGE_Y(y)
976         auto dst = dbuffer;
977         for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
978             SCALED_IMAGE_RANGE_X
979             auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
980             auto tmp = surface->blender(src, *dst, 255);
981             *dst = INTERPOLATE(tmp, *dst, MULTIPLY(opacity, A(src)));
982         }
983     }
984     return true;
985 }
986 
987 
_rasterScaledImage(SwSurface * surface,const SwImage * image,const Matrix * itransform,const SwBBox & region,uint8_t opacity)988 static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
989 {
990     auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
991     auto sampleSize = _sampleSize(image->scale);
992     int32_t miny = 0, maxy = 0;
993 
994     //32bits channels
995     if (surface->channelSize == sizeof(uint32_t)) {
996         auto buffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
997         for (auto y = region.min.y; y < region.max.y; ++y, buffer += surface->stride) {
998             SCALED_IMAGE_RANGE_Y(y)
999             auto dst = buffer;
1000             for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1001                 SCALED_IMAGE_RANGE_X
1002                 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
1003                 if (opacity < 255) src = ALPHA_BLEND(src, opacity);
1004                 *dst = src + ALPHA_BLEND(*dst, IA(src));
1005             }
1006         }
1007     } else if (surface->channelSize == sizeof(uint8_t)) {
1008         auto buffer = surface->buf8 + (region.min.y * surface->stride + region.min.x);
1009         for (auto y = region.min.y; y < region.max.y; ++y, buffer += surface->stride) {
1010             SCALED_IMAGE_RANGE_Y(y)
1011             auto dst = buffer;
1012             for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1013                 SCALED_IMAGE_RANGE_X
1014                 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
1015                 *dst = MULTIPLY(A(src), opacity);
1016             }
1017         }
1018     }
1019     return true;
1020 }
1021 
1022 
_scaledImage(SwSurface * surface,const SwImage * image,const Matrix & transform,const SwBBox & region,uint8_t opacity)1023 static bool _scaledImage(SwSurface* surface, const SwImage* image, const Matrix& transform, const SwBBox& region, uint8_t opacity)
1024 {
1025     Matrix itransform;
1026 
1027     if (!inverse(&transform, &itransform)) return true;
1028 
1029     if (_compositing(surface)) {
1030         if (_matting(surface)) return _rasterScaledMattedImage(surface, image, &itransform, region, opacity);
1031         else return _rasterScaledMaskedImage(surface, image, &itransform, region, opacity);
1032     } else if (_blending(surface)) {
1033         return _rasterScaledBlendingImage(surface, image, &itransform, region, opacity);
1034     } else {
1035         return _rasterScaledImage(surface, image, &itransform, region, opacity);
1036     }
1037     return false;
1038 }
1039 
1040 
1041 /************************************************************************/
1042 /* Direct Image                                                         */
1043 /************************************************************************/
1044 
_rasterDirectMaskedImage(SwSurface * surface,const SwImage * image,const SwBBox & region,uint8_t opacity)1045 static bool _rasterDirectMaskedImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1046 {
1047     TVGERR("SW_ENGINE", "Not Supported: Direct Masked Image");
1048     return false;
1049 }
1050 
1051 
_rasterDirectMattedImage(SwSurface * surface,const SwImage * image,const SwBBox & region,uint8_t opacity)1052 static bool _rasterDirectMattedImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1053 {
1054     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1055     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1056     auto csize = surface->compositor->image.channelSize;
1057     auto alpha = surface->alpha(surface->compositor->method);
1058     auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1059     auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize; //compositor buffer
1060 
1061     TVGLOG("SW_ENGINE", "Direct Matted(%d) Image  [Region: %lu %lu %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h);
1062 
1063     //32 bits
1064     if (surface->channelSize == sizeof(uint32_t)) {
1065         auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1066         for (uint32_t y = 0; y < h; ++y) {
1067             auto dst = buffer;
1068             auto cmp = cbuffer;
1069             auto src = sbuffer;
1070             if (opacity == 255) {
1071                 for (uint32_t x = 0; x < w; ++x, ++dst, ++src, cmp += csize) {
1072                     auto tmp = ALPHA_BLEND(*src, alpha(cmp));
1073                     *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
1074                 }
1075             } else {
1076                 for (uint32_t x = 0; x < w; ++x, ++dst, ++src, cmp += csize) {
1077                     auto tmp = ALPHA_BLEND(*src, MULTIPLY(opacity, alpha(cmp)));
1078                     *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
1079                 }
1080             }
1081             buffer += surface->stride;
1082             cbuffer += surface->compositor->image.stride * csize;
1083             sbuffer += image->stride;
1084         }
1085     //8 bits
1086     } else if (surface->channelSize == sizeof(uint8_t)) {
1087         auto buffer = surface->buf8 + (region.min.y * surface->stride) + region.min.x;
1088         for (uint32_t y = 0; y < h; ++y) {
1089             auto dst = buffer;
1090             auto cmp = cbuffer;
1091             auto src = sbuffer;
1092             if (opacity == 255) {
1093                 for (uint32_t x = 0; x < w; ++x, ++dst, ++src, cmp += csize) {
1094                     auto tmp = MULTIPLY(A(*src), alpha(cmp));
1095                     *dst = tmp + MULTIPLY(*dst, 255 - tmp);
1096                 }
1097             } else {
1098                 for (uint32_t x = 0; x < w; ++x, ++dst, ++src, cmp += csize) {
1099                     auto tmp = MULTIPLY(A(*src), MULTIPLY(opacity, alpha(cmp)));
1100                     *dst = tmp + MULTIPLY(*dst, 255 - tmp);
1101                 }
1102             }
1103             buffer += surface->stride;
1104             cbuffer += surface->compositor->image.stride * csize;
1105             sbuffer += image->stride;
1106         }
1107     }
1108     return true;
1109 }
1110 
1111 
_rasterDirectBlendingImage(SwSurface * surface,const SwImage * image,const SwBBox & region,uint8_t opacity)1112 static bool _rasterDirectBlendingImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1113 {
1114     if (surface->channelSize == sizeof(uint8_t)) {
1115         TVGERR("SW_ENGINE", "Not supported grayscale image!");
1116         return false;
1117     }
1118 
1119     auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x];
1120     auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1121 
1122     for (auto y = region.min.y; y < region.max.y; ++y) {
1123         auto dst = dbuffer;
1124         auto src = sbuffer;
1125         if (opacity == 255) {
1126             for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
1127                 auto tmp = surface->blender(*src, *dst, 255);
1128                 *dst = INTERPOLATE(tmp, *dst, A(*src));
1129             }
1130         } else {
1131             for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
1132                 auto tmp = surface->blender(*src, *dst, 255);
1133                 *dst = INTERPOLATE(tmp, *dst, MULTIPLY(opacity, A(*src)));
1134             }
1135         }
1136         dbuffer += surface->stride;
1137         sbuffer += image->stride;
1138     }
1139     return true;
1140 }
1141 
1142 
_rasterDirectImage(SwSurface * surface,const SwImage * image,const SwBBox & region,uint8_t opacity)1143 static bool _rasterDirectImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1144 {
1145     auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1146 
1147     //32bits channels
1148     if (surface->channelSize == sizeof(uint32_t)) {
1149         auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x];
1150 
1151         for (auto y = region.min.y; y < region.max.y; ++y) {
1152             auto dst = dbuffer;
1153             auto src = sbuffer;
1154             if (opacity == 255) {
1155                 for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
1156                     *dst = *src + ALPHA_BLEND(*dst, IA(*src));
1157                 }
1158             } else {
1159                 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
1160                     auto tmp = ALPHA_BLEND(*src, opacity);
1161                     *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
1162                 }
1163             }
1164             dbuffer += surface->stride;
1165             sbuffer += image->stride;
1166         }
1167     //8bits grayscale
1168     } else if (surface->channelSize == sizeof(uint8_t)) {
1169         auto dbuffer = &surface->buf8[region.min.y * surface->stride + region.min.x];
1170 
1171         for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride, sbuffer += image->stride) {
1172             auto dst = dbuffer;
1173             auto src = sbuffer;
1174             if (opacity == 255) {
1175                 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
1176                     *dst = *src + MULTIPLY(*dst, IA(*src));
1177                 }
1178             } else {
1179                 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
1180                     *dst = INTERPOLATE8(A(*src), *dst, opacity);
1181                 }
1182             }
1183         }
1184     }
1185     return true;
1186 }
1187 
1188 
_rasterDirectMattedBlendingImage(SwSurface * surface,const SwImage * image,const SwBBox & region,uint8_t opacity)1189 static bool _rasterDirectMattedBlendingImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1190 {
1191     if (surface->channelSize == sizeof(uint8_t)) {
1192         TVGERR("SW_ENGINE", "Not supported grayscale image!");
1193         return false;
1194     }
1195 
1196     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1197     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1198     auto csize = surface->compositor->image.channelSize;
1199     auto alpha = surface->alpha(surface->compositor->method);
1200     auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1201     auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize; //compositor buffer
1202     auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1203 
1204     for (uint32_t y = 0; y < h; ++y) {
1205         auto dst = buffer;
1206         auto cmp = cbuffer;
1207         auto src = sbuffer;
1208         if (opacity == 255) {
1209             for (uint32_t x = 0; x < w; ++x, ++dst, ++src, cmp += csize) {
1210                 auto tmp = ALPHA_BLEND(*src, alpha(cmp));
1211                 *dst = INTERPOLATE(surface->blender(tmp, *dst, 255), *dst, A(tmp));
1212             }
1213         } else {
1214             for (uint32_t x = 0; x < w; ++x, ++dst, ++src, cmp += csize) {
1215                 auto tmp = ALPHA_BLEND(*src, alpha(cmp));
1216                 *dst = INTERPOLATE(surface->blender(tmp, *dst, 255), *dst, MULTIPLY(opacity, A(tmp)));
1217             }
1218         }
1219         buffer += surface->stride;
1220         cbuffer += surface->compositor->image.stride * csize;
1221         sbuffer += image->stride;
1222     }
1223     return true;
1224 }
1225 
1226 
1227 //Blenders for the following scenarios: [Composition / Non-Composition] * [Opaque / Translucent]
_directImage(SwSurface * surface,const SwImage * image,const SwBBox & region,uint8_t opacity)1228 static bool _directImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1229 {
1230     if (_compositing(surface)) {
1231         if (_matting(surface)) {
1232             if (_blending(surface)) return _rasterDirectMattedBlendingImage(surface, image, region, opacity);
1233             else return _rasterDirectMattedImage(surface, image, region, opacity);
1234         } else return _rasterDirectMaskedImage(surface, image, region, opacity);
1235     } else if (_blending(surface)) {
1236         return _rasterDirectBlendingImage(surface, image, region, opacity);
1237     } else {
1238         return _rasterDirectImage(surface, image, region, opacity);
1239     }
1240     return false;
1241 }
1242 
1243 
1244 //Blenders for the following scenarios: [RLE / Whole] * [Direct / Scaled / Transformed]
_rasterImage(SwSurface * surface,SwImage * image,const Matrix & transform,const SwBBox & region,uint8_t opacity)1245 static bool _rasterImage(SwSurface* surface, SwImage* image, const Matrix& transform, const SwBBox& region, uint8_t opacity)
1246 {
1247     //RLE Image
1248     if (image->rle) {
1249         if (image->direct) return _directRleImage(surface, image, opacity);
1250         else if (image->scaled) return _scaledRleImage(surface, image, transform, region, opacity);
1251         else return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity);
1252     //Whole Image
1253     } else {
1254         if (image->direct) return _directImage(surface, image, region, opacity);
1255         else if (image->scaled) return _scaledImage(surface, image, transform, region, opacity);
1256         else return _rasterTexmapPolygon(surface, image, transform, &region, opacity);
1257     }
1258 }
1259 
1260 
1261 /************************************************************************/
1262 /* Rect Gradient                                                        */
1263 /************************************************************************/
1264 
1265 template<typename fillMethod>
_rasterCompositeGradientMaskedRect(SwSurface * surface,const SwBBox & region,const SwFill * fill,SwMask maskOp)1266 static bool _rasterCompositeGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwMask maskOp)
1267 {
1268     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1269     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1270     auto cstride = surface->compositor->image.stride;
1271     auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x);
1272 
1273     for (uint32_t y = 0; y < h; ++y) {
1274         fillMethod()(fill, cbuffer, region.min.y + y, region.min.x, w, maskOp, 255);
1275         cbuffer += surface->stride;
1276     }
1277     return _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox);
1278 }
1279 
1280 
1281 template<typename fillMethod>
_rasterDirectGradientMaskedRect(SwSurface * surface,const SwBBox & region,const SwFill * fill,SwMask maskOp)1282 static bool _rasterDirectGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwMask maskOp)
1283 {
1284     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1285     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1286     auto cstride = surface->compositor->image.stride;
1287     auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x);
1288     auto dbuffer = surface->buf8 + (region.min.y * surface->stride + region.min.x);
1289 
1290     for (uint32_t y = 0; y < h; ++y) {
1291         fillMethod()(fill, dbuffer, region.min.y + y, region.min.x, w, cbuffer, maskOp, 255);
1292         cbuffer += cstride;
1293         dbuffer += surface->stride;
1294     }
1295     return true;
1296 }
1297 
1298 
1299 template<typename fillMethod>
_rasterGradientMaskedRect(SwSurface * surface,const SwBBox & region,const SwFill * fill)1300 static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1301 {
1302     auto method = surface->compositor->method;
1303 
1304     TVGLOG("SW_ENGINE", "Masked(%d) Gradient [Region: %lu %lu %lu %lu]", (int)method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y);
1305 
1306     auto maskOp = _getMaskOp(method);
1307 
1308     if (_direct(method)) return _rasterDirectGradientMaskedRect<fillMethod>(surface, region, fill, maskOp);
1309     else return _rasterCompositeGradientMaskedRect<fillMethod>(surface, region, fill, maskOp);
1310 
1311     return false;
1312 }
1313 
1314 
1315 template<typename fillMethod>
_rasterGradientMattedRect(SwSurface * surface,const SwBBox & region,const SwFill * fill)1316 static bool _rasterGradientMattedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1317 {
1318     auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1319     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1320     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1321     auto csize = surface->compositor->image.channelSize;
1322     auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
1323     auto alpha = surface->alpha(surface->compositor->method);
1324 
1325     TVGLOG("SW_ENGINE", "Matted(%d) Gradient [Region: %lu %lu %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h);
1326 
1327     for (uint32_t y = 0; y < h; ++y) {
1328         fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, cbuffer, alpha, csize, 255);
1329         buffer += surface->stride;
1330         cbuffer += surface->stride * csize;
1331     }
1332     return true;
1333 }
1334 
1335 
1336 template<typename fillMethod>
_rasterBlendingGradientRect(SwSurface * surface,const SwBBox & region,const SwFill * fill)1337 static bool _rasterBlendingGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1338 {
1339     auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1340     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1341     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1342 
1343     if (fill->translucent) {
1344         for (uint32_t y = 0; y < h; ++y) {
1345             fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opBlendPreNormal, surface->blender, 255);
1346         }
1347     } else {
1348         for (uint32_t y = 0; y < h; ++y) {
1349             fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opBlendSrcOver, surface->blender, 255);
1350         }
1351     }
1352     return true;
1353 }
1354 
1355 template<typename fillMethod>
_rasterTranslucentGradientRect(SwSurface * surface,const SwBBox & region,const SwFill * fill)1356 static bool _rasterTranslucentGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1357 {
1358     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1359     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1360 
1361     //32 bits
1362     if (surface->channelSize == sizeof(uint32_t)) {
1363         auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1364         for (uint32_t y = 0; y < h; ++y) {
1365             fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, opBlendPreNormal, 255);
1366             buffer += surface->stride;
1367         }
1368     //8 bits
1369     } else if (surface->channelSize == sizeof(uint8_t)) {
1370         auto buffer = surface->buf8 + (region.min.y * surface->stride) + region.min.x;
1371         for (uint32_t y = 0; y < h; ++y) {
1372             fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, _opMaskAdd, 255);
1373             buffer += surface->stride;
1374         }
1375     }
1376     return true;
1377 }
1378 
1379 
1380 template<typename fillMethod>
_rasterSolidGradientRect(SwSurface * surface,const SwBBox & region,const SwFill * fill)1381 static bool _rasterSolidGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1382 {
1383     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1384     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1385 
1386     //32 bits
1387     if (surface->channelSize == sizeof(uint32_t)) {
1388         auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1389         for (uint32_t y = 0; y < h; ++y) {
1390             fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, opBlendSrcOver, 255);
1391             buffer += surface->stride;
1392         }
1393     //8 bits
1394     } else if (surface->channelSize == sizeof(uint8_t)) {
1395         auto buffer = surface->buf8 + (region.min.y * surface->stride) + region.min.x;
1396         for (uint32_t y = 0; y < h; ++y) {
1397             fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, _opMaskNone, 255);
1398             buffer += surface->stride;
1399         }
1400     }
1401     return true;
1402 }
1403 
1404 
_rasterLinearGradientRect(SwSurface * surface,const SwBBox & region,const SwFill * fill)1405 static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1406 {
1407     if (_compositing(surface)) {
1408         if (_matting(surface)) return _rasterGradientMattedRect<FillLinear>(surface, region, fill);
1409         else return _rasterGradientMaskedRect<FillLinear>(surface, region, fill);
1410     } else if (_blending(surface)) {
1411         return _rasterBlendingGradientRect<FillLinear>(surface, region, fill);
1412     } else {
1413         if (fill->translucent) return _rasterTranslucentGradientRect<FillLinear>(surface, region, fill);
1414         else _rasterSolidGradientRect<FillLinear>(surface, region, fill);
1415     }
1416     return false;
1417 }
1418 
1419 
_rasterRadialGradientRect(SwSurface * surface,const SwBBox & region,const SwFill * fill)1420 static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1421 {
1422     if (_compositing(surface)) {
1423         if (_matting(surface)) return _rasterGradientMattedRect<FillRadial>(surface, region, fill);
1424         else return _rasterGradientMaskedRect<FillRadial>(surface, region, fill);
1425     } else if (_blending(surface)) {
1426         return _rasterBlendingGradientRect<FillRadial>(surface, region, fill);
1427     } else {
1428         if (fill->translucent) return _rasterTranslucentGradientRect<FillRadial>(surface, region, fill);
1429         else _rasterSolidGradientRect<FillRadial>(surface, region, fill);
1430     }
1431     return false;
1432 }
1433 
1434 
1435 /************************************************************************/
1436 /* Rle Gradient                                                         */
1437 /************************************************************************/
1438 
1439 template<typename fillMethod>
_rasterCompositeGradientMaskedRle(SwSurface * surface,const SwRle * rle,const SwFill * fill,SwMask maskOp)1440 static bool _rasterCompositeGradientMaskedRle(SwSurface* surface, const SwRle* rle, const SwFill* fill, SwMask maskOp)
1441 {
1442     auto span = rle->spans;
1443     auto cstride = surface->compositor->image.stride;
1444     auto cbuffer = surface->compositor->image.buf8;
1445 
1446     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1447         auto cmp = &cbuffer[span->y * cstride + span->x];
1448         fillMethod()(fill, cmp, span->y, span->x, span->len, maskOp, span->coverage);
1449     }
1450     return _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox);
1451 }
1452 
1453 
1454 template<typename fillMethod>
_rasterDirectGradientMaskedRle(SwSurface * surface,const SwRle * rle,const SwFill * fill,SwMask maskOp)1455 static bool _rasterDirectGradientMaskedRle(SwSurface* surface, const SwRle* rle, const SwFill* fill, SwMask maskOp)
1456 {
1457     auto span = rle->spans;
1458     auto cstride = surface->compositor->image.stride;
1459     auto cbuffer = surface->compositor->image.buf8;
1460     auto dbuffer = surface->buf8;
1461 
1462     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1463         auto cmp = &cbuffer[span->y * cstride + span->x];
1464         auto dst = &dbuffer[span->y * surface->stride + span->x];
1465         fillMethod()(fill, dst, span->y, span->x, span->len, cmp, maskOp, span->coverage);
1466     }
1467     return true;
1468 }
1469 
1470 
1471 template<typename fillMethod>
_rasterGradientMaskedRle(SwSurface * surface,const SwRle * rle,const SwFill * fill)1472 static bool _rasterGradientMaskedRle(SwSurface* surface, const SwRle* rle, const SwFill* fill)
1473 {
1474     auto method = surface->compositor->method;
1475 
1476     TVGLOG("SW_ENGINE", "Masked(%d) Rle Linear Gradient", (int)method);
1477 
1478     auto maskOp = _getMaskOp(method);
1479 
1480     if (_direct(method)) return _rasterDirectGradientMaskedRle<fillMethod>(surface, rle, fill, maskOp);
1481     else return _rasterCompositeGradientMaskedRle<fillMethod>(surface, rle, fill, maskOp);
1482     return false;
1483 }
1484 
1485 
1486 template<typename fillMethod>
_rasterGradientMattedRle(SwSurface * surface,const SwRle * rle,const SwFill * fill)1487 static bool _rasterGradientMattedRle(SwSurface* surface, const SwRle* rle, const SwFill* fill)
1488 {
1489     TVGLOG("SW_ENGINE", "Matted(%d) Rle Linear Gradient", (int)surface->compositor->method);
1490 
1491     auto span = rle->spans;
1492     auto csize = surface->compositor->image.channelSize;
1493     auto cbuffer = surface->compositor->image.buf8;
1494     auto alpha = surface->alpha(surface->compositor->method);
1495 
1496     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1497         auto dst = &surface->buf32[span->y * surface->stride + span->x];
1498         auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
1499         fillMethod()(fill, dst, span->y, span->x, span->len, cmp, alpha, csize, span->coverage);
1500     }
1501     return true;
1502 }
1503 
1504 
1505 template<typename fillMethod>
_rasterBlendingGradientRle(SwSurface * surface,const SwRle * rle,const SwFill * fill)1506 static bool _rasterBlendingGradientRle(SwSurface* surface, const SwRle* rle, const SwFill* fill)
1507 {
1508     auto span = rle->spans;
1509 
1510     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1511         auto dst = &surface->buf32[span->y * surface->stride + span->x];
1512         fillMethod()(fill, dst, span->y, span->x, span->len, opBlendPreNormal, surface->blender, span->coverage);
1513     }
1514     return true;
1515 }
1516 
1517 
1518 template<typename fillMethod>
_rasterTranslucentGradientRle(SwSurface * surface,const SwRle * rle,const SwFill * fill)1519 static bool _rasterTranslucentGradientRle(SwSurface* surface, const SwRle* rle, const SwFill* fill)
1520 {
1521     auto span = rle->spans;
1522 
1523     //32 bits
1524     if (surface->channelSize == sizeof(uint32_t)) {
1525         for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1526             auto dst = &surface->buf32[span->y * surface->stride + span->x];
1527             if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendPreNormal, 255);
1528             else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendNormal, span->coverage);
1529         }
1530     //8 bits
1531     } else if (surface->channelSize == sizeof(uint8_t)) {
1532         for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1533             auto dst = &surface->buf8[span->y * surface->stride + span->x];
1534             fillMethod()(fill, dst, span->y, span->x, span->len, _opMaskAdd, span->coverage);
1535         }
1536     }
1537     return true;
1538 }
1539 
1540 
1541 template<typename fillMethod>
_rasterSolidGradientRle(SwSurface * surface,const SwRle * rle,const SwFill * fill)1542 static bool _rasterSolidGradientRle(SwSurface* surface, const SwRle* rle, const SwFill* fill)
1543 {
1544     auto span = rle->spans;
1545 
1546     //32 bits
1547     if (surface->channelSize == sizeof(uint32_t)) {
1548         for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1549             auto dst = &surface->buf32[span->y * surface->stride + span->x];
1550             if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendSrcOver, 255);
1551             else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendInterp, span->coverage);
1552         }
1553     //8 bits
1554     } else if (surface->channelSize == sizeof(uint8_t)) {
1555         for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1556             auto dst = &surface->buf8[span->y * surface->stride + span->x];
1557             if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, _opMaskNone, 255);
1558             else fillMethod()(fill, dst, span->y, span->x, span->len, _opMaskAdd, span->coverage);
1559         }
1560     }
1561 
1562     return true;
1563 }
1564 
1565 
_rasterLinearGradientRle(SwSurface * surface,const SwRle * rle,const SwFill * fill)1566 static bool _rasterLinearGradientRle(SwSurface* surface, const SwRle* rle, const SwFill* fill)
1567 {
1568     if (!rle) return false;
1569 
1570     if (_compositing(surface)) {
1571         if (_matting(surface)) return _rasterGradientMattedRle<FillLinear>(surface, rle, fill);
1572         else return _rasterGradientMaskedRle<FillLinear>(surface, rle, fill);
1573     } else if (_blending(surface)) {
1574         return _rasterBlendingGradientRle<FillLinear>(surface, rle, fill);
1575     } else {
1576         if (fill->translucent) return _rasterTranslucentGradientRle<FillLinear>(surface, rle, fill);
1577         else return _rasterSolidGradientRle<FillLinear>(surface, rle, fill);
1578     }
1579     return false;
1580 }
1581 
1582 
_rasterRadialGradientRle(SwSurface * surface,const SwRle * rle,const SwFill * fill)1583 static bool _rasterRadialGradientRle(SwSurface* surface, const SwRle* rle, const SwFill* fill)
1584 {
1585     if (!rle) return false;
1586 
1587     if (_compositing(surface)) {
1588         if (_matting(surface)) return _rasterGradientMattedRle<FillRadial>(surface, rle, fill);
1589         else return _rasterGradientMaskedRle<FillRadial>(surface, rle, fill);
1590     } else if (_blending(surface)) {
1591         return _rasterBlendingGradientRle<FillRadial>(surface, rle, fill);
1592     } else {
1593         if (fill->translucent) return _rasterTranslucentGradientRle<FillRadial>(surface, rle, fill);
1594         else return _rasterSolidGradientRle<FillRadial>(surface, rle, fill);
1595     }
1596     return false;
1597 }
1598 
1599 
1600 /************************************************************************/
1601 /* External Class Implementation                                        */
1602 /************************************************************************/
1603 
1604 
rasterGrayscale8(uint8_t * dst,uint8_t val,uint32_t offset,int32_t len)1605 void rasterGrayscale8(uint8_t *dst, uint8_t val, uint32_t offset, int32_t len)
1606 {
1607 #if defined(THORVG_AVX_VECTOR_SUPPORT)
1608     avxRasterGrayscale8(dst, val, offset, len);
1609 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
1610     neonRasterGrayscale8(dst, val, offset, len);
1611 #else
1612     cRasterPixels(dst, val, offset, len);
1613 #endif
1614 }
1615 
1616 
rasterPixel32(uint32_t * dst,uint32_t val,uint32_t offset,int32_t len)1617 void rasterPixel32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
1618 {
1619 #if defined(THORVG_AVX_VECTOR_SUPPORT)
1620     avxRasterPixel32(dst, val, offset, len);
1621 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
1622     neonRasterPixel32(dst, val, offset, len);
1623 #else
1624     cRasterPixels(dst, val, offset, len);
1625 #endif
1626 }
1627 
1628 
rasterCompositor(SwSurface * surface)1629 bool rasterCompositor(SwSurface* surface)
1630 {
1631     //See CompositeMethod, Alpha:3, InvAlpha:4, Luma:5, InvLuma:6
1632     surface->alphas[0] = _alpha;
1633     surface->alphas[1] = _ialpha;
1634 
1635     if (surface->cs == ColorSpace::ABGR8888 || surface->cs == ColorSpace::ABGR8888S) {
1636         surface->join = _abgrJoin;
1637         surface->alphas[2] = _abgrLuma;
1638         surface->alphas[3] = _abgrInvLuma;
1639     } else if (surface->cs == ColorSpace::ARGB8888 || surface->cs == ColorSpace::ARGB8888S) {
1640         surface->join = _argbJoin;
1641         surface->alphas[2] = _argbLuma;
1642         surface->alphas[3] = _argbInvLuma;
1643     } else {
1644         TVGERR("SW_ENGINE", "Unsupported Colorspace(%d) is expected!", surface->cs);
1645         return false;
1646     }
1647     return true;
1648 }
1649 
1650 
rasterClear(SwSurface * surface,uint32_t x,uint32_t y,uint32_t w,uint32_t h,pixel_t val)1651 bool rasterClear(SwSurface* surface, uint32_t x, uint32_t y, uint32_t w, uint32_t h, pixel_t val)
1652 {
1653     if (!surface || !surface->buf32 || surface->stride == 0 || surface->w == 0 || surface->h == 0) return false;
1654 
1655     //32 bits
1656     if (surface->channelSize == sizeof(uint32_t)) {
1657         //full clear
1658         if (w == surface->stride) {
1659             rasterPixel32(surface->buf32, val, surface->stride * y, w * h);
1660         //partial clear
1661         } else {
1662             for (uint32_t i = 0; i < h; i++) {
1663                 rasterPixel32(surface->buf32, val, (surface->stride * y + x) + (surface->stride * i), w);
1664             }
1665         }
1666     //8 bits
1667     } else if (surface->channelSize == sizeof(uint8_t)) {
1668         //full clear
1669         if (w == surface->stride) {
1670             rasterGrayscale8(surface->buf8, 0x00, surface->stride * y, w * h);
1671         //partial clear
1672         } else {
1673             for (uint32_t i = 0; i < h; i++) {
1674                 rasterGrayscale8(surface->buf8, 0x00, (surface->stride * y + x) + (surface->stride * i), w);
1675             }
1676         }
1677     }
1678     return true;
1679 }
1680 
1681 
rasterUnpremultiply(RenderSurface * surface)1682 void rasterUnpremultiply(RenderSurface* surface)
1683 {
1684     if (surface->channelSize != sizeof(uint32_t)) return;
1685 
1686     TVGLOG("SW_ENGINE", "Unpremultiply [Size: %d x %d]", surface->w, surface->h);
1687 
1688     //OPTIMIZE_ME: +SIMD
1689     for (uint32_t y = 0; y < surface->h; y++) {
1690         auto buffer = surface->buf32 + surface->stride * y;
1691         for (uint32_t x = 0; x < surface->w; ++x) {
1692             uint8_t a = buffer[x] >> 24;
1693             if (a == 255) {
1694                 continue;
1695             } else if (a == 0) {
1696                 buffer[x] = 0x00ffffff;
1697             } else {
1698                 uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
1699                 uint16_t g = ((buffer[x]) & 0xff00) / a;
1700                 uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
1701                 if (r > 0xff) r = 0xff;
1702                 if (g > 0xff) g = 0xff;
1703                 if (b > 0xff) b = 0xff;
1704                 buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
1705             }
1706         }
1707     }
1708     surface->premultiplied = false;
1709 }
1710 
1711 
rasterPremultiply(RenderSurface * surface)1712 void rasterPremultiply(RenderSurface* surface)
1713 {
1714     ScopedLock lock(surface->key);
1715     if (surface->premultiplied || (surface->channelSize != sizeof(uint32_t))) return;
1716     surface->premultiplied = true;
1717 
1718     TVGLOG("SW_ENGINE", "Premultiply [Size: %d x %d]", surface->w, surface->h);
1719 
1720     //OPTIMIZE_ME: +SIMD
1721     auto buffer = surface->buf32;
1722     for (uint32_t y = 0; y < surface->h; ++y, buffer += surface->stride) {
1723         auto dst = buffer;
1724         for (uint32_t x = 0; x < surface->w; ++x, ++dst) {
1725             auto c = *dst;
1726             auto a = (c >> 24);
1727             *dst = (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff);
1728         }
1729     }
1730 }
1731 
1732 
rasterGradientShape(SwSurface * surface,SwShape * shape,const Fill * fdata,uint8_t opacity)1733 bool rasterGradientShape(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity)
1734 {
1735     if (!shape->fill) return false;
1736 
1737     if (auto color = fillFetchSolid(shape->fill, fdata)) {
1738         auto a = MULTIPLY(color->a, opacity);
1739         return a > 0 ? rasterShape(surface, shape, color->r, color->g, color->b, a) : true;
1740     }
1741 
1742     auto type = fdata->type();
1743     if (shape->fastTrack) {
1744         if (type == Type::LinearGradient) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill);
1745         else if (type == Type::RadialGradient)return _rasterRadialGradientRect(surface, shape->bbox, shape->fill);
1746     } else {
1747         if (type == Type::LinearGradient) return _rasterLinearGradientRle(surface, shape->rle, shape->fill);
1748         else if (type == Type::RadialGradient) return _rasterRadialGradientRle(surface, shape->rle, shape->fill);
1749     }
1750     return false;
1751 }
1752 
1753 
rasterGradientStroke(SwSurface * surface,SwShape * shape,const Fill * fdata,uint8_t opacity)1754 bool rasterGradientStroke(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity)
1755 {
1756     if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
1757 
1758     if (auto color = fillFetchSolid(shape->stroke->fill, fdata)) {
1759         auto a = MULTIPLY(color->a, opacity);
1760         return a > 0 ? rasterStroke(surface, shape, color->r, color->g, color->b, a) : true;
1761     }
1762 
1763     auto type = fdata->type();
1764     if (type == Type::LinearGradient) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1765     else if (type == Type::RadialGradient) return _rasterRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1766 
1767     return false;
1768 }
1769 
1770 
rasterShape(SwSurface * surface,SwShape * shape,uint8_t r,uint8_t g,uint8_t b,uint8_t a)1771 bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1772 {
1773     if (a < 255) {
1774         r = MULTIPLY(r, a);
1775         g = MULTIPLY(g, a);
1776         b = MULTIPLY(b, a);
1777     }
1778     if (shape->fastTrack) return _rasterRect(surface, shape->bbox, r, g, b, a);
1779     else return _rasterRle(surface, shape->rle, r, g, b, a);
1780 }
1781 
1782 
rasterStroke(SwSurface * surface,SwShape * shape,uint8_t r,uint8_t g,uint8_t b,uint8_t a)1783 bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1784 {
1785     if (a < 255) {
1786         r = MULTIPLY(r, a);
1787         g = MULTIPLY(g, a);
1788         b = MULTIPLY(b, a);
1789     }
1790 
1791     return _rasterRle(surface, shape->strokeRle, r, g, b, a);
1792 }
1793 
1794 
rasterImage(SwSurface * surface,SwImage * image,const Matrix & transform,const SwBBox & bbox,uint8_t opacity)1795 bool rasterImage(SwSurface* surface, SwImage* image, const Matrix& transform, const SwBBox& bbox, uint8_t opacity)
1796 {
1797     //Outside of the viewport, skip the rendering
1798     if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= static_cast<SwCoord>(surface->w) || bbox.min.y >= static_cast<SwCoord>(surface->h)) return true;
1799 
1800     return _rasterImage(surface, image, transform, bbox, opacity);
1801 }
1802 
1803 
rasterConvertCS(RenderSurface * surface,ColorSpace to)1804 bool rasterConvertCS(RenderSurface* surface, ColorSpace to)
1805 {
1806     ScopedLock lock(surface->key);
1807     if (surface->cs == to) return true;
1808 
1809     //TODO: Support SIMD accelerations
1810     auto from = surface->cs;
1811 
1812     if (((from == ColorSpace::ABGR8888) || (from == ColorSpace::ABGR8888S)) && ((to == ColorSpace::ARGB8888) || (to == ColorSpace::ARGB8888S))) {
1813         surface->cs = to;
1814         return cRasterABGRtoARGB(surface);
1815     }
1816     if (((from == ColorSpace::ARGB8888) || (from == ColorSpace::ARGB8888S)) && ((to == ColorSpace::ABGR8888) || (to == ColorSpace::ABGR8888S))) {
1817         surface->cs = to;
1818         return cRasterARGBtoABGR(surface);
1819     }
1820     return false;
1821 }
1822 
1823 
1824 //TODO: SIMD OPTIMIZATION?
rasterXYFlip(uint32_t * src,uint32_t * dst,int32_t stride,int32_t w,int32_t h,const SwBBox & bbox,bool flipped)1825 void rasterXYFlip(uint32_t* src, uint32_t* dst, int32_t stride, int32_t w, int32_t h, const SwBBox& bbox, bool flipped)
1826 {
1827     constexpr int BLOCK = 8;  //experimental decision
1828 
1829     if (flipped) {
1830         src += ((bbox.min.x * stride) + bbox.min.y);
1831         dst += ((bbox.min.y * stride) + bbox.min.x);
1832     } else {
1833         src += ((bbox.min.y * stride) + bbox.min.x);
1834         dst += ((bbox.min.x * stride) + bbox.min.y);
1835     }
1836 
1837     for (int x = 0; x < w; x += BLOCK) {
1838         auto bx = std::min(w, x + BLOCK) - x;
1839         auto in = &src[x];
1840         auto out = &dst[x * stride];
1841         for (int y = 0; y < h; y += BLOCK) {
1842             auto p = &in[y * stride];
1843             auto q = &out[y];
1844             auto by = std::min(h, y + BLOCK) - y;
1845             for (int xx = 0; xx < bx; ++xx) {
1846                 for (int yy = 0; yy < by; ++yy) {
1847                     *q = *p;
1848                     p += stride;
1849                     ++q;
1850                 }
1851                 p += 1 - by * stride;
1852                 q += stride - by;
1853             }
1854         }
1855     }
1856 }
1857 
1858 #endif /* LV_USE_THORVG_INTERNAL */
1859 
1860