updated copyright.
[platform/core/graphics/tizenvg.git] / src / lib / sw_engine / tvgSwRaster.cpp
1 /*
2  * Copyright (c) 2020 - 2023 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 #ifdef _WIN32
24     #include <malloc.h>
25 #elif defined(__linux__)
26     #include <alloca.h>
27 #else
28     #include <stdlib.h>
29 #endif
30
31 #include "tvgMath.h"
32 #include "tvgRender.h"
33 #include "tvgSwCommon.h"
34
35 /************************************************************************/
36 /* Internal Class Implementation                                        */
37 /************************************************************************/
38 constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
39
40
41 static inline uint32_t _multiplyAlpha(uint32_t c, uint32_t a)
42 {
43     return ((c * a + 0xff) >> 8);
44 }
45
46
47 static inline uint32_t _alpha(uint32_t c)
48 {
49     return (c >> 24);
50 }
51
52
53 static inline uint32_t _ialpha(uint32_t c)
54 {
55     return (~c >> 24);
56 }
57
58
59 static inline uint32_t _abgrLumaValue(uint32_t c)
60 {
61     return ((((c&0xff)*54) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*19))) >> 8; //0.2125*R + 0.7154*G + 0.0721*B
62 }
63
64
65 static inline uint32_t _argbLumaValue(uint32_t c)
66 {
67     return ((((c&0xff)*19) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*54))) >> 8; //0.0721*B + 0.7154*G + 0.2125*R
68 }
69
70
71 static inline uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
72 {
73     return (a << 24 | b << 16 | g << 8 | r);
74 }
75
76
77 static inline uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
78 {
79     return (a << 24 | r << 16 | g << 8 | b);
80 }
81
82
83 #include "tvgSwRasterTexmap.h"
84 #include "tvgSwRasterC.h"
85 #include "tvgSwRasterAvx.h"
86 #include "tvgSwRasterNeon.h"
87
88
89 static inline bool _compositing(const SwSurface* surface)
90 {
91     if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false;
92     return true;
93 }
94
95
96 static inline uint32_t _halfScale(float scale)
97 {
98     auto halfScale = static_cast<uint32_t>(0.5f / scale);
99     if (halfScale == 0) halfScale = 1;
100     return halfScale;
101 }
102
103 //Bilinear Interpolation
104 static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, float sx, float sy)
105 {
106     auto rx = (uint32_t)(sx);
107     auto ry = (uint32_t)(sy);
108     auto rx2 = rx + 1;
109     if (rx2 >= w) rx2 = w - 1;
110     auto ry2 = ry + 1;
111     if (ry2 >= h) ry2 = h - 1;
112
113     auto dx = static_cast<uint32_t>((sx - rx) * 255.0f);
114     auto dy = static_cast<uint32_t>((sy - ry) * 255.0f);
115
116     auto c1 = img[rx + ry * w];
117     auto c2 = img[rx2 + ry * w];
118     auto c3 = img[rx2 + ry2 * w];
119     auto c4 = img[rx + ry2 * w];
120
121     return INTERPOLATE(dy, INTERPOLATE(dx, c3, c4), INTERPOLATE(dx, c2, c1));
122 }
123
124
125 //2n x 2n Mean Kernel
126 static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, uint32_t rx, uint32_t ry, uint32_t n)
127 {
128     uint32_t c[4] = {0, 0, 0, 0};
129     auto n2 = n * n;
130     auto src = img + rx - n + (ry - n) * stride;
131
132     for (auto y = ry - n; y < ry + n; ++y) {
133         if (y >= h) continue;
134         auto p = src;
135         for (auto x = rx - n; x < rx + n; ++x, ++p) {
136             if (x >= w) continue;
137             c[0] += *p >> 24;
138             c[1] += (*p >> 16) & 0xff;
139             c[2] += (*p >> 8) & 0xff;
140             c[3] += *p & 0xff;
141         }
142         src += stride;
143     }
144     for (auto i = 0; i < 4; ++i) {
145         c[i] = (c[i] >> 2) / n2;
146     }
147     return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
148 }
149
150
151 /************************************************************************/
152 /* Rect                                                                 */
153 /************************************************************************/
154
155 static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t))
156 {
157     TVGLOG("SW_ENGINE", "Masked Rect");
158
159     auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
160     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
161     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
162
163     auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
164
165     for (uint32_t y = 0; y < h; ++y) {
166         auto dst = &buffer[y * surface->stride];
167         auto cmp = &cbuffer[y * surface->stride];
168         for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp) {
169             auto tmp = ALPHA_BLEND(color, blendMethod(*cmp));
170             *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
171         }
172     }
173     return true;
174 }
175
176
177 static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color)
178 {
179     auto buffer = surface->buffer + (region.min.y * surface->stride);
180     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
181     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
182
183     for (uint32_t y = 0; y < h; ++y) {
184         rasterRGBA32(buffer + y * surface->stride, color, region.min.x, w);
185     }
186     return true;
187 }
188
189
190 static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint8_t opacity)
191 {
192     if (_compositing(surface)) {
193         if (surface->compositor->method == CompositeMethod::AlphaMask) {
194             return _rasterMaskedRect(surface, region, color, _alpha);
195         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
196             return _rasterMaskedRect(surface, region, color, _ialpha);
197         } else if (surface->compositor->method == CompositeMethod::LumaMask) {
198             return _rasterMaskedRect(surface, region, color, surface->blender.lumaValue);
199         }
200     } else {
201         if (opacity == 255) {
202             return _rasterSolidRect(surface, region, color);
203         } else {
204 #if defined(THORVG_AVX_VECTOR_SUPPORT)
205             return avxRasterTranslucentRect(surface, region, color);
206 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
207             return neonRasterTranslucentRect(surface, region, color);
208 #else
209             return cRasterTranslucentRect(surface, region, color);
210 #endif
211         }
212     }
213     return false;
214 }
215
216
217 /************************************************************************/
218 /* Rle                                                                  */
219 /************************************************************************/
220
221 static bool _rasterMaskedRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t))
222 {
223     TVGLOG("SW_ENGINE", "Masked Rle");
224
225     auto span = rle->spans;
226     uint32_t src;
227     auto cbuffer = surface->compositor->image.data;
228
229     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
230         auto dst = &surface->buffer[span->y * surface->stride + span->x];
231         auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
232         if (span->coverage == 255) src = color;
233         else src = ALPHA_BLEND(color, span->coverage);
234         for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
235             auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
236             *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
237         }
238     }
239     return true;
240 }
241
242
243 static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint32_t color)
244 {
245     auto span = rle->spans;
246
247     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
248         if (span->coverage == 255) {
249             rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len);
250         } else {
251             auto dst = &surface->buffer[span->y * surface->stride + span->x];
252             auto src = ALPHA_BLEND(color, span->coverage);
253             auto ialpha = 255 - span->coverage;
254             for (uint32_t x = 0; x < span->len; ++x, ++dst) {
255                 *dst = src + ALPHA_BLEND(*dst, ialpha);
256             }
257         }
258     }
259     return true;
260 }
261
262
263 static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint8_t opacity)
264 {
265     if (!rle) return false;
266
267     if (_compositing(surface)) {
268         if (surface->compositor->method == CompositeMethod::AlphaMask) {
269             return _rasterMaskedRle(surface, rle, color, _alpha);
270         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
271             return _rasterMaskedRle(surface, rle, color, _ialpha);
272         } else if (surface->compositor->method == CompositeMethod::LumaMask) {
273             return _rasterMaskedRle(surface, rle, color, surface->blender.lumaValue);
274         }
275     } else {
276         if (opacity == 255) {
277             return _rasterSolidRle(surface, rle, color);
278         } else {
279 #if defined(THORVG_AVX_VECTOR_SUPPORT)
280             return avxRasterTranslucentRle(surface, rle, color);
281 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
282             return neonRasterTranslucentRle(surface, rle, color);
283 #else
284             return cRasterTranslucentRle(surface, rle, color);
285 #endif
286         }
287     }
288     return false;
289 }
290
291
292 /************************************************************************/
293 /* RLE Transformed RGBA Image                                           */
294 /************************************************************************/
295
296 static bool _transformedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, uint32_t opacity)
297 {
298     if (_compositing(surface)) {
299         if (surface->compositor->method == CompositeMethod::AlphaMask) {
300             return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _alpha);
301         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
302             return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _ialpha);
303         } else if (surface->compositor->method == CompositeMethod::LumaMask) {
304             return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, surface->blender.lumaValue);
305         }
306     } else {
307         return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, nullptr);
308     }
309     return false;
310 }
311
312 /************************************************************************/
313 /* RLE Scaled RGBA Image                                                */
314 /************************************************************************/
315
316 static bool _rasterScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
317 {
318     TVGLOG("SW_ENGINE", "Scaled Masked Translucent Rle Image");
319
320     auto span = image->rle->spans;
321
322     //Center (Down-Scaled)
323     if (image->scale < DOWN_SCALE_TOLERANCE) {
324         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
325             auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
326             if (sy >= image->h) continue;
327             auto dst = &surface->buffer[span->y * surface->stride + span->x];
328             auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
329             auto alpha = _multiplyAlpha(span->coverage, opacity);
330             for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
331                 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
332                 if (sx >= image->w) continue;
333                 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
334                 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
335                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
336             }
337         }
338     //Center (Up-Scaled)
339     } else {
340         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
341             auto sy = span->y * itransform->e22 + itransform->e23;
342             if ((uint32_t)sy >= image->h) continue;
343             auto dst = &surface->buffer[span->y * surface->stride + span->x];
344             auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
345             auto alpha = _multiplyAlpha(span->coverage, opacity);
346             for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
347                 auto sx = x * itransform->e11 + itransform->e13;
348                 if ((uint32_t)sx >= image->w) continue;
349                 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
350                 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
351                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
352             }
353         }
354     }
355     return true;
356 }
357
358
359 static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
360 {
361     TVGLOG("SW_ENGINE", "Scaled Masked Rle Image");
362
363     auto span = image->rle->spans;
364
365     //Center (Down-Scaled)
366     if (image->scale < DOWN_SCALE_TOLERANCE) {
367         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
368             auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
369             if (sy >= image->h) continue;
370             auto dst = &surface->buffer[span->y * surface->stride + span->x];
371             auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
372             if (span->coverage == 255) {
373                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
374                     auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
375                     if (sx >= image->w) continue;
376                     auto tmp = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
377                     *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
378                 }
379             } else {
380                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
381                     auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
382                     if (sx >= image->w) continue;
383                     auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), span->coverage);
384                     auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
385                     *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
386                 }
387             }
388         }
389     //Center (Up-Scaled)
390     } else {
391         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
392             auto sy = span->y * itransform->e22 + itransform->e23;
393             if ((uint32_t)sy >= image->h) continue;
394             auto dst = &surface->buffer[span->y * surface->stride + span->x];
395             auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
396             if (span->coverage == 255) {
397                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
398                     auto sx = x * itransform->e11 + itransform->e13;
399                     if ((uint32_t)sx >= image->w) continue;
400                     auto tmp = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
401                     *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
402                 }
403             } else {
404                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
405                     auto sx = x * itransform->e11 + itransform->e13;
406                     if ((uint32_t)sx >= image->w) continue;
407                     auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
408                     auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
409                     *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
410                 }
411             }
412         }
413     }
414     return true;
415 }
416
417
418 static bool _rasterScaledTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
419 {
420     auto span = image->rle->spans;
421
422     //Center (Down-Scaled)
423     if (image->scale < DOWN_SCALE_TOLERANCE) {
424         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
425             auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
426             if (sy >= image->h) continue;
427             auto dst = &surface->buffer[span->y * surface->stride + span->x];
428             auto alpha = _multiplyAlpha(span->coverage, opacity);
429             for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
430                 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
431                 if (sx >= image->w) continue;
432                 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
433                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
434             }
435         }
436     //Center (Up-Scaled)
437     } else {
438         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
439             auto sy = span->y * itransform->e22 + itransform->e23;
440             if ((uint32_t)sy >= image->h) continue;
441             auto dst = &surface->buffer[span->y * surface->stride + span->x];
442             auto alpha = _multiplyAlpha(span->coverage, opacity);
443             for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
444                 auto sx = x * itransform->e11 + itransform->e13;
445                 if ((uint32_t)sx >= image->w) continue;
446                 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
447                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
448             }
449         }
450     }
451     return true;
452 }
453
454
455 static bool _rasterScaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
456 {
457     auto span = image->rle->spans;
458
459     //Center (Down-Scaled)
460     if (image->scale < DOWN_SCALE_TOLERANCE) {
461         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
462             auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
463             if (sy >= image->h) continue;
464             auto dst = &surface->buffer[span->y * surface->stride + span->x];
465             if (span->coverage == 255) {
466                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
467                     auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
468                     if (sx >= image->w) continue;
469                     auto src = _interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale);
470                     *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
471                 }
472             } else {
473                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
474                     auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
475                     if (sx >= image->w) continue;
476                     auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), span->coverage);
477                     *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
478                 }
479             }
480         }
481     //Center (Up-Scaled)
482     } else {
483         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
484             auto sy = span->y * itransform->e22 + itransform->e23;
485             if ((uint32_t)sy >= image->h) continue;
486             auto dst = &surface->buffer[span->y * surface->stride + span->x];
487             if (span->coverage == 255) {
488                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
489                     auto sx = x * itransform->e11 + itransform->e13;
490                     if ((uint32_t)sx >= image->w) continue;
491                     auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
492                     *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
493                 }
494             } else {
495                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
496                     auto sx = x * itransform->e11 + itransform->e13;
497                     if ((uint32_t)sx >= image->w) continue;
498                     auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
499                     *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
500                 }
501             }
502         }
503     }
504     return true;
505 }
506
507
508 static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
509 {
510     Matrix itransform;
511
512     if (transform) {
513         if (!mathInverse(transform, &itransform)) return false;
514     } else mathIdentity(&itransform);
515
516     auto halfScale = _halfScale(image->scale);
517
518     if (_compositing(surface)) {
519         if (opacity == 255) {
520             if (surface->compositor->method == CompositeMethod::AlphaMask) {
521                 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _alpha);
522             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
523                 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
524             } else if (surface->compositor->method == CompositeMethod::LumaMask) {
525                 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
526             }
527         } else {
528             if (surface->compositor->method == CompositeMethod::AlphaMask) {
529                 return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha);
530             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
531                 return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
532             } else if (surface->compositor->method == CompositeMethod::LumaMask) {
533                 return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
534             }
535         }
536     } else {
537         if (opacity == 255) return _rasterScaledRleRGBAImage(surface, image, &itransform, region, opacity, halfScale);
538         else return _rasterScaledTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale);
539     }
540     return false;
541 }
542
543
544 /************************************************************************/
545 /* RLE Direct RGBA Image                                                */
546 /************************************************************************/
547
548 static bool _rasterDirectMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
549 {
550     TVGLOG("SW_ENGINE", "Direct Masked Rle Image");
551
552     auto span = image->rle->spans;
553     auto cbuffer = surface->compositor->image.data;
554
555     for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
556         auto dst = &surface->buffer[span->y * surface->stride + span->x];
557         auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
558         auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
559         auto alpha = _multiplyAlpha(span->coverage, opacity);
560         if (alpha == 255) {
561             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
562                 auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp));
563                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
564             }
565         } else {
566             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
567                 auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(alpha, blendMethod(*cmp)));
568                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
569             }
570         }
571     }
572     return true;
573 }
574
575
576 static bool _rasterDirectMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t (*blendMethod)(uint32_t))
577 {
578     TVGLOG("SW_ENGINE", "Direct Masked Rle Image");
579
580     auto span = image->rle->spans;
581     auto cbuffer = surface->compositor->image.data;
582
583     for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
584         auto dst = &surface->buffer[span->y * surface->stride + span->x];
585         auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
586         auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
587         if (span->coverage == 255) {
588             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
589                 auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp));
590                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
591             }
592         } else {
593             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
594                 auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(span->coverage, blendMethod(*cmp)));
595                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
596             }
597         }
598     }
599     return true;
600 }
601
602
603 static bool _rasterDirectTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity)
604 {
605     auto span = image->rle->spans;
606
607     for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
608         auto dst = &surface->buffer[span->y * surface->stride + span->x];
609         auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
610         auto alpha = _multiplyAlpha(span->coverage, opacity);
611         for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
612             auto src = ALPHA_BLEND(*img, alpha);
613             *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
614         }
615     }
616     return true;
617 }
618
619
620 static bool _rasterDirectRleRGBAImage(SwSurface* surface, const SwImage* image)
621 {
622     auto span = image->rle->spans;
623
624     for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
625         auto dst = &surface->buffer[span->y * surface->stride + span->x];
626         auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
627         if (span->coverage == 255) {
628             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
629                 *dst = *img + ALPHA_BLEND(*dst, _ialpha(*img));
630             }
631         } else {
632             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
633                 auto src = ALPHA_BLEND(*img, span->coverage);
634                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
635             }
636         }
637     }
638     return true;
639 }
640
641
642 static bool _directRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity)
643 {
644     if (_compositing(surface)) {
645         if (opacity == 255) {
646             if (surface->compositor->method == CompositeMethod::AlphaMask) {
647                 return _rasterDirectMaskedRleRGBAImage(surface, image, _alpha);
648             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
649                 return _rasterDirectMaskedRleRGBAImage(surface, image, _ialpha);
650             } else if (surface->compositor->method == CompositeMethod::LumaMask) {
651                 return _rasterDirectMaskedRleRGBAImage(surface, image, surface->blender.lumaValue);
652             }
653         } else {
654             if (surface->compositor->method == CompositeMethod::AlphaMask) {
655                 return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _alpha);
656             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
657                 return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _ialpha);
658             } else if (surface->compositor->method == CompositeMethod::LumaMask) {
659                 return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, surface->blender.lumaValue);
660             }
661         }
662     } else {
663         if (opacity == 255) return _rasterDirectRleRGBAImage(surface, image);
664         else return _rasterDirectTranslucentRleRGBAImage(surface, image, opacity);
665     }
666     return false;
667 }
668
669
670 /************************************************************************/
671 /* Transformed RGBA Image                                               */
672 /************************************************************************/
673
674 static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
675 {
676     if (_compositing(surface)) {
677         if (surface->compositor->method == CompositeMethod::AlphaMask) {
678             return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _alpha);
679         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
680             return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _ialpha);
681         } else if (surface->compositor->method == CompositeMethod::LumaMask) {
682             return _rasterTexmapPolygon(surface, image, transform, &region, opacity, surface->blender.lumaValue);
683         }
684     } else {
685         return _rasterTexmapPolygon(surface, image, transform, &region, opacity, nullptr);
686     }
687     return false;
688 }
689
690 static bool _transformedRGBAImageMesh(SwSurface* surface, const SwImage* image, const Polygon* triangles, const uint32_t count, const Matrix* transform, const SwBBox* region, uint32_t opacity)
691 {
692     if (_compositing(surface)) {
693         if (surface->compositor->method == CompositeMethod::AlphaMask) {
694             return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, _alpha);
695         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
696             return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, _ialpha);
697         } else if (surface->compositor->method == CompositeMethod::LumaMask) {
698             return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, surface->blender.lumaValue);
699         }
700     } else {
701         return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, nullptr);
702     }
703     return false;
704 }
705
706
707 /************************************************************************/
708 /*Scaled RGBA Image                                                     */
709 /************************************************************************/
710
711
712 static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
713 {
714     TVGLOG("SW_ENGINE", "Scaled Masked Image");
715
716     auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
717     auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x);
718
719     // Down-Scaled
720     if (image->scale < DOWN_SCALE_TOLERANCE) {
721         for (auto y = region.min.y; y < region.max.y; ++y) {
722             auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
723             if (sy >= image->h) continue;
724             auto dst = dbuffer;
725             auto cmp = cbuffer;
726             for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
727                 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
728                 if (sx >= image->w) continue;
729                 auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp));
730                 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
731                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
732             }
733             dbuffer += surface->stride;
734             cbuffer += surface->compositor->image.stride;
735         }
736     // Up-Scaled
737     } else {
738         for (auto y = region.min.y; y < region.max.y; ++y) {
739             auto sy = y * itransform->e22 + itransform->e23;
740             if ((uint32_t)sy >= image->h) continue;
741             auto dst = dbuffer;
742             auto cmp = cbuffer;
743             for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
744                 auto sx = x * itransform->e11 + itransform->e13;
745                 if ((uint32_t)sx >= image->w) continue;
746                 auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp));
747                 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
748                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
749             }
750             dbuffer += surface->stride;
751             cbuffer += surface->compositor->image.stride;
752         }
753     }
754     return true;
755 }
756
757
758 static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
759 {
760     TVGLOG("SW_ENGINE", "Scaled Masked Image");
761
762     auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
763     auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x);
764
765     // Down-Scaled
766     if (image->scale < DOWN_SCALE_TOLERANCE) {
767         for (auto y = region.min.y; y < region.max.y; ++y) {
768             auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
769             if (sy >= image->h) continue;
770             auto dst = dbuffer;
771             auto cmp = cbuffer;
772             for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
773                 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
774                 if (sx >= image->w) continue;
775                 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
776                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
777             }
778             dbuffer += surface->stride;
779             cbuffer += surface->compositor->image.stride;
780         }
781     // Up-Scaled
782     } else {
783         for (auto y = region.min.y; y < region.max.y; ++y) {
784             auto sy = y * itransform->e22 + itransform->e23;
785             if ((uint32_t)sy >= image->h) continue;
786             auto dst = dbuffer;
787             auto cmp = cbuffer;
788             for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
789                 auto sx = x * itransform->e11 + itransform->e13;
790                 if ((uint32_t)sx >= image->w) continue;
791                 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
792                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
793             }
794             dbuffer += surface->stride;
795             cbuffer += surface->compositor->image.stride;
796         }
797     }
798     return true;
799 }
800
801
802 static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
803 {
804     auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
805
806     // Down-Scaled
807     if (image->scale < DOWN_SCALE_TOLERANCE) {
808         for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
809             auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
810             if (sy >= image->h) continue;
811             auto dst = dbuffer;
812             for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
813                 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
814                 if (sx >= image->w) continue;
815                 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), opacity);
816                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
817             }
818         }
819     // Up-Scaled
820     } else {
821         for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
822             auto sy = fabsf(y * itransform->e22 + itransform->e23);
823             if (sy >= image->h) continue;
824             auto dst = dbuffer;
825             for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
826                 auto sx = x * itransform->e11 + itransform->e13;
827                 if ((uint32_t)sx >= image->w) continue;
828                 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), opacity);
829                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
830             }
831         }
832     }
833     return true;
834 }
835
836
837 static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale)
838 {
839     auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
840
841     // Down-Scaled
842     if (image->scale < DOWN_SCALE_TOLERANCE) {
843         for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
844             auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
845             if (sy >= image->h) continue;
846             auto dst = dbuffer;
847             for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
848                 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
849                 if (sx >= image->w) continue;
850                 auto src = _interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale);
851                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
852             }
853         }
854     // Up-Scaled
855     } else {
856         for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
857             auto sy = y * itransform->e22 + itransform->e23;
858             if ((uint32_t)sy >= image->h) continue;
859             auto dst = dbuffer;
860             for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
861                 auto sx = x * itransform->e11 + itransform->e13;
862                 if ((uint32_t)sx >= image->w) continue;
863                 auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
864                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
865             }
866         }
867     }
868     return true;
869 }
870
871
872 static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
873 {
874     Matrix itransform;
875
876     if (transform) {
877         if (!mathInverse(transform, &itransform)) return false;
878     } else mathIdentity(&itransform);
879
880     auto halfScale = _halfScale(image->scale);
881
882     if (_compositing(surface)) {
883         if (opacity == 255) {
884             if (surface->compositor->method == CompositeMethod::AlphaMask) {
885                 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _alpha);
886             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
887                 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
888             } else if (surface->compositor->method == CompositeMethod::LumaMask) {
889                 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
890             }
891         } else {
892             if (surface->compositor->method == CompositeMethod::AlphaMask) {
893                 return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha);
894             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
895                 return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
896             } else if (surface->compositor->method == CompositeMethod::LumaMask) {
897                 return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
898             }
899         }
900     } else {
901         if (opacity == 255) return _rasterScaledRGBAImage(surface, image, &itransform, region, halfScale);
902         else return _rasterScaledTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale);
903     }
904     return false;
905 }
906
907
908 /************************************************************************/
909 /* Direct RGBA Image                                                    */
910 /************************************************************************/
911
912 static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t (*blendMethod)(uint32_t))
913 {
914     TVGLOG("SW_ENGINE", "Direct Masked Image");
915
916     auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
917     auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
918     auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
919
920     auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
921     auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
922
923     for (uint32_t y = 0; y < h2; ++y) {
924         auto dst = buffer;
925         auto cmp = cbuffer;
926         auto src = sbuffer;
927         for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
928             auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
929             *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
930         }
931         buffer += surface->stride;
932         cbuffer += surface->compositor->image.stride;
933         sbuffer += image->stride;
934     }
935     return true;
936 }
937
938
939 static bool _rasterDirectMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
940 {
941     TVGLOG("SW_ENGINE", "Direct Masked Translucent Image");
942
943     auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
944     auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
945     auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
946
947     auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
948     auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
949
950     for (uint32_t y = 0; y < h2; ++y) {
951         auto dst = buffer;
952         auto cmp = cbuffer;
953         auto src = sbuffer;
954         for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
955             auto tmp = ALPHA_BLEND(*src, _multiplyAlpha(opacity, blendMethod(*cmp)));
956             *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
957         }
958         buffer += surface->stride;
959         cbuffer += surface->compositor->image.stride;
960         sbuffer += image->stride;
961     }
962     return true;
963 }
964
965
966 static bool _rasterDirectTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity)
967 {
968     auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
969     auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
970
971     for (auto y = region.min.y; y < region.max.y; ++y) {
972         auto dst = dbuffer;
973         auto src = sbuffer;
974         for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
975             auto tmp = ALPHA_BLEND(*src, opacity);
976             *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
977         }
978         dbuffer += surface->stride;
979         sbuffer += image->stride;
980     }
981     return true;
982 }
983
984
985 static bool _rasterDirectRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region)
986 {
987     auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
988     auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
989
990     for (auto y = region.min.y; y < region.max.y; ++y) {
991         auto dst = dbuffer;
992         auto src = sbuffer;
993         for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
994             *dst = *src + ALPHA_BLEND(*dst, _ialpha(*src));
995         }
996         dbuffer += surface->stride;
997         sbuffer += image->stride;
998     }
999     return true;
1000 }
1001
1002
1003 //Blenders for the following scenarios: [Composition / Non-Composition] * [Opaque / Translucent]
1004 static bool _directRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity)
1005 {
1006     if (_compositing(surface)) {
1007         if (opacity == 255) {
1008             if (surface->compositor->method == CompositeMethod::AlphaMask) {
1009                 return _rasterDirectMaskedRGBAImage(surface, image, region, _alpha);
1010             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1011                 return _rasterDirectMaskedRGBAImage(surface, image, region, _ialpha);
1012             } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1013                 return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.lumaValue);
1014             }
1015         } else {
1016             if (surface->compositor->method == CompositeMethod::AlphaMask) {
1017                 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _alpha);
1018             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1019                 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _ialpha);
1020             } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1021                 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.lumaValue);
1022             }
1023         }
1024     } else {
1025         if (opacity == 255) return _rasterDirectRGBAImage(surface, image, region);
1026         else return _rasterDirectTranslucentRGBAImage(surface, image, region, opacity);
1027     }
1028     return false;
1029 }
1030
1031
1032 //Blenders for the following scenarios: [RLE / Whole] * [Direct / Scaled / Transformed]
1033 static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
1034 {
1035     //RLE Image
1036     if (image->rle) {
1037         if (image->direct) return _directRleRGBAImage(surface, image, opacity);
1038         else if (image->scaled) return _scaledRleRGBAImage(surface, image, transform, region, opacity);
1039         else return _transformedRleRGBAImage(surface, image, transform, opacity);
1040     //Whole Image
1041     } else {
1042         if (image->direct) return _directRGBAImage(surface, image, region, opacity);
1043         else if (image->scaled) return _scaledRGBAImage(surface, image, transform, region, opacity);
1044         else return _transformedRGBAImage(surface, image, transform, region, opacity);
1045     }
1046 }
1047
1048
1049 /************************************************************************/
1050 /* Rect Linear Gradient                                                 */
1051 /************************************************************************/
1052
1053 static bool _rasterLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1054 {
1055     if (fill->linear.len < FLT_EPSILON) return false;
1056
1057     auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1058     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1059     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1060     auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;
1061
1062     auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1063     if (!sbuffer) return false;
1064
1065     for (uint32_t y = 0; y < h; ++y) {
1066         fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1067         auto dst = buffer;
1068         auto cmp = cbuffer;
1069         auto src = sbuffer;
1070         for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1071             auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1072             *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1073         }
1074         buffer += surface->stride;
1075         cbuffer += surface->stride;
1076     }
1077     return true;
1078 }
1079
1080
1081 static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1082 {
1083     if (fill->linear.len < FLT_EPSILON) return false;
1084
1085     auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1086     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1087     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1088
1089     auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1090     if (!sbuffer) return false;
1091
1092     for (uint32_t y = 0; y < h; ++y) {
1093         auto dst = buffer;
1094         fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1095         for (uint32_t x = 0; x < w; ++x, ++dst) {
1096             *dst = sbuffer[x] + ALPHA_BLEND(*dst, _ialpha(sbuffer[x]));
1097         }
1098         buffer += surface->stride;
1099     }
1100     return true;
1101 }
1102
1103
1104 static bool _rasterSolidLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1105 {
1106     if (fill->linear.len < FLT_EPSILON) return false;
1107
1108     auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1109     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1110     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1111
1112     for (uint32_t y = 0; y < h; ++y) {
1113         fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w);
1114     }
1115     return true;
1116 }
1117
1118
1119 static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1120 {
1121     if (_compositing(surface)) {
1122         if (surface->compositor->method == CompositeMethod::AlphaMask) {
1123             return _rasterLinearGradientMaskedRect(surface, region, fill, _alpha);
1124         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1125             return _rasterLinearGradientMaskedRect(surface, region, fill, _ialpha);
1126         } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1127             return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
1128         }
1129     } else {
1130         if (fill->translucent) return _rasterTranslucentLinearGradientRect(surface, region, fill);
1131         else _rasterSolidLinearGradientRect(surface, region, fill);
1132     }
1133     return false;
1134 }
1135
1136
1137 /************************************************************************/
1138 /* Rle Linear Gradient                                                  */
1139 /************************************************************************/
1140
1141 static bool _rasterLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1142 {
1143     if (fill->linear.len < FLT_EPSILON) return false;
1144
1145     auto span = rle->spans;
1146     auto cbuffer = surface->compositor->image.data;
1147     auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1148     if (!buffer) return false;
1149
1150     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1151         fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1152         auto dst = &surface->buffer[span->y * surface->stride + span->x];
1153         auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
1154         auto src = buffer;
1155         if (span->coverage == 255) {
1156             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1157                 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1158                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1159             }
1160         } else {
1161             auto ialpha = 255 - span->coverage;
1162             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1163                 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1164                 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1165                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1166             }
1167         }
1168     }
1169     return true;
1170 }
1171
1172
1173 static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1174 {
1175     if (fill->linear.len < FLT_EPSILON) return false;
1176
1177     auto span = rle->spans;
1178     auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1179     if (!buffer) return false;
1180
1181     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1182         auto dst = &surface->buffer[span->y * surface->stride + span->x];
1183         fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1184         if (span->coverage == 255) {
1185             for (uint32_t x = 0; x < span->len; ++x, ++dst) {
1186                 *dst = buffer[x] + ALPHA_BLEND(*dst, _ialpha(buffer[x]));
1187             }
1188         } else {
1189             for (uint32_t x = 0; x < span->len; ++x, ++dst) {
1190                 auto tmp = ALPHA_BLEND(buffer[x], span->coverage);
1191                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1192             }
1193         }
1194     }
1195     return true;
1196 }
1197
1198
1199 static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1200 {
1201     if (fill->linear.len < FLT_EPSILON) return false;
1202
1203     auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1204     if (!buf) return false;
1205
1206     auto span = rle->spans;
1207
1208     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1209         if (span->coverage == 255) {
1210             fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len);
1211         } else {
1212             fillFetchLinear(fill, buf, span->y, span->x, span->len);
1213             auto dst = &surface->buffer[span->y * surface->stride + span->x];
1214             for (uint32_t x = 0; x < span->len; ++x) {
1215                 dst[x] = INTERPOLATE(span->coverage, buf[x], dst[x]);
1216             }
1217         }
1218     }
1219     return true;
1220 }
1221
1222
1223 static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1224 {
1225     if (!rle) return false;
1226
1227     if (_compositing(surface)) {
1228         if (surface->compositor->method == CompositeMethod::AlphaMask) {
1229             return _rasterLinearGradientMaskedRle(surface, rle, fill, _alpha);
1230         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1231             return _rasterLinearGradientMaskedRle(surface, rle, fill, _ialpha);
1232         } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1233             return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
1234         }
1235     } else {
1236         if (fill->translucent) return _rasterTranslucentLinearGradientRle(surface, rle, fill);
1237         else return _rasterSolidLinearGradientRle(surface, rle, fill);
1238     }
1239     return false;
1240 }
1241
1242
1243 /************************************************************************/
1244 /* Rect Radial Gradient                                                 */
1245 /************************************************************************/
1246
1247 static bool _rasterRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1248 {
1249     if (fill->radial.a < FLT_EPSILON) return false;
1250
1251     auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1252     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1253     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1254     auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;
1255
1256     auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1257     if (!sbuffer) return false;
1258
1259     for (uint32_t y = 0; y < h; ++y) {
1260         fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1261         auto dst = buffer;
1262         auto cmp = cbuffer;
1263         auto src = sbuffer;
1264         for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1265              auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1266              *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1267         }
1268         buffer += surface->stride;
1269         cbuffer += surface->stride;
1270     }
1271     return true;
1272 }
1273
1274
1275 static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1276 {
1277     if (fill->radial.a < FLT_EPSILON) return false;
1278
1279     auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1280     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1281     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1282
1283     auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1284     if (!sbuffer) return false;
1285
1286     for (uint32_t y = 0; y < h; ++y) {
1287         auto dst = buffer;
1288         fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1289         for (uint32_t x = 0; x < w; ++x, ++dst) {
1290             *dst = sbuffer[x] + ALPHA_BLEND(*dst, _ialpha(sbuffer[x]));
1291         }
1292         buffer += surface->stride;
1293     }
1294     return true;
1295 }
1296
1297
1298 static bool _rasterSolidRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1299 {
1300     if (fill->radial.a < FLT_EPSILON) return false;
1301
1302     auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1303     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1304     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1305
1306     for (uint32_t y = 0; y < h; ++y) {
1307         auto dst = &buffer[y * surface->stride];
1308         fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w);
1309     }
1310     return true;
1311 }
1312
1313
1314 static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1315 {
1316     if (_compositing(surface)) {
1317         if (surface->compositor->method == CompositeMethod::AlphaMask) {
1318             return _rasterRadialGradientMaskedRect(surface, region, fill, _alpha);
1319         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1320             return _rasterRadialGradientMaskedRect(surface, region, fill, _ialpha);
1321         } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1322             return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
1323         }
1324     } else {
1325         if (fill->translucent) return _rasterTranslucentRadialGradientRect(surface, region, fill);
1326         else return _rasterSolidRadialGradientRect(surface, region, fill);
1327     }
1328     return false;
1329 }
1330
1331
1332 /************************************************************************/
1333 /* RLE Radial Gradient                                                  */
1334 /************************************************************************/
1335
1336 static bool _rasterRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1337 {
1338     if (fill->radial.a < FLT_EPSILON) return false;
1339
1340     auto span = rle->spans;
1341     auto cbuffer = surface->compositor->image.data;
1342     auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1343     if (!buffer) return false;
1344
1345     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1346         fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1347         auto dst = &surface->buffer[span->y * surface->stride + span->x];
1348         auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
1349         auto src = buffer;
1350         if (span->coverage == 255) {
1351             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1352                 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1353                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1354             }
1355         } else {
1356             for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1357                 auto tmp = INTERPOLATE(span->coverage, ALPHA_BLEND(*src, blendMethod(*cmp)), *dst);
1358                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1359             }
1360         }
1361     }
1362     return true;
1363 }
1364
1365
1366 static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1367 {
1368     if (fill->radial.a < FLT_EPSILON) return false;
1369
1370     auto span = rle->spans;
1371     auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1372     if (!buffer) return false;
1373
1374     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1375         auto dst = &surface->buffer[span->y * surface->stride + span->x];
1376         fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1377         if (span->coverage == 255) {
1378             for (uint32_t x = 0; x < span->len; ++x, ++dst) {
1379                 *dst = buffer[x] + ALPHA_BLEND(*dst, _ialpha(buffer[x]));
1380             }
1381         } else {
1382            for (uint32_t x = 0; x < span->len; ++x, ++dst) {
1383                 auto tmp = ALPHA_BLEND(buffer[x], span->coverage);
1384                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1385             }
1386         }
1387     }
1388     return true;
1389 }
1390
1391
1392 static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1393 {
1394     if (fill->radial.a < FLT_EPSILON) return false;
1395
1396     auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1397     if (!buf) return false;
1398
1399     auto span = rle->spans;
1400
1401     for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1402         auto dst = &surface->buffer[span->y * surface->stride + span->x];
1403         if (span->coverage == 255) {
1404             fillFetchRadial(fill, dst, span->y, span->x, span->len);
1405         } else {
1406             fillFetchRadial(fill, buf, span->y, span->x, span->len);
1407             auto ialpha = 255 - span->coverage;
1408             for (uint32_t x = 0; x < span->len; ++x, ++dst) {
1409                 *dst = ALPHA_BLEND(buf[x], span->coverage) + ALPHA_BLEND(*dst, ialpha);
1410             }
1411         }
1412     }
1413     return true;
1414 }
1415
1416
1417 static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1418 {
1419     if (!rle) return false;
1420
1421     if (_compositing(surface)) {
1422         if (surface->compositor->method == CompositeMethod::AlphaMask) {
1423             return _rasterRadialGradientMaskedRle(surface, rle, fill, _alpha);
1424         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1425             return _rasterRadialGradientMaskedRle(surface, rle, fill, _ialpha);
1426         } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1427             return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
1428         }
1429     } else {
1430         if (fill->translucent) _rasterTranslucentRadialGradientRle(surface, rle, fill);
1431         else return _rasterSolidRadialGradientRle(surface, rle, fill);
1432     }
1433     return false;
1434 }
1435
1436
1437 /************************************************************************/
1438 /* External Class Implementation                                        */
1439 /************************************************************************/
1440
1441 void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
1442 {
1443 #if defined(THORVG_AVX_VECTOR_SUPPORT)
1444     avxRasterRGBA32(dst, val, offset, len);
1445 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
1446     neonRasterRGBA32(dst, val, offset, len);
1447 #else
1448     cRasterRGBA32(dst, val, offset, len);
1449 #endif
1450 }
1451
1452
1453 bool rasterCompositor(SwSurface* surface)
1454 {
1455     if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
1456         surface->blender.join = _abgrJoin;
1457         surface->blender.lumaValue = _abgrLumaValue;
1458     } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
1459         surface->blender.join = _argbJoin;
1460         surface->blender.lumaValue = _argbLumaValue;
1461     } else {
1462         //What Color Space ???
1463         return false;
1464     }
1465     return true;
1466 }
1467
1468
1469 bool rasterClear(SwSurface* surface)
1470 {
1471     if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false;
1472
1473     if (surface->w == surface->stride) {
1474         rasterRGBA32(surface->buffer, 0x00000000, 0, surface->w * surface->h);
1475     } else {
1476         for (uint32_t i = 0; i < surface->h; i++) {
1477             rasterRGBA32(surface->buffer + surface->stride * i, 0x00000000, 0, surface->w);
1478         }
1479     }
1480     return true;
1481 }
1482
1483
1484 void rasterUnpremultiply(SwSurface* surface)
1485 {
1486     //OPTIMIZE_ME: +SIMD
1487     for (uint32_t y = 0; y < surface->h; y++) {
1488         auto buffer = surface->buffer + surface->stride * y;
1489         for (uint32_t x = 0; x < surface->w; ++x) {
1490             uint8_t a = buffer[x] >> 24;
1491             if (a == 255) {
1492                 continue;
1493             } else if (a == 0) {
1494                 buffer[x] = 0x00ffffff;
1495             } else {
1496                 uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
1497                 uint16_t g = ((buffer[x]) & 0xff00) / a;
1498                 uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
1499                 if (r > 0xff) r = 0xff;
1500                 if (g > 0xff) g = 0xff;
1501                 if (b > 0xff) b = 0xff;
1502                 buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
1503             }
1504         }
1505     }
1506 }
1507
1508
1509 bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
1510 {
1511     if (!shape->fill) return false;
1512
1513     if (shape->fastTrack) {
1514         if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill);
1515         else if (id == TVG_CLASS_ID_RADIAL)return _rasterRadialGradientRect(surface, shape->bbox, shape->fill);
1516     } else {
1517         if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->rle, shape->fill);
1518         else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->rle, shape->fill);
1519     }
1520     return false;
1521 }
1522
1523
1524 bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
1525 {
1526     if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
1527
1528     if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1529     else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1530
1531     return false;
1532 }
1533
1534
1535 bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1536 {
1537     if (a < 255) {
1538         r = _multiplyAlpha(r, a);
1539         g = _multiplyAlpha(g, a);
1540         b = _multiplyAlpha(b, a);
1541     }
1542
1543     auto color = surface->blender.join(r, g, b, a);
1544
1545     if (shape->fastTrack) return _rasterRect(surface, shape->bbox, color, a);
1546     else return _rasterRle(surface, shape->rle, color, a);
1547 }
1548
1549
1550 bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1551 {
1552     if (a < 255) {
1553         r = _multiplyAlpha(r, a);
1554         g = _multiplyAlpha(g, a);
1555         b = _multiplyAlpha(b, a);
1556     }
1557
1558     auto color = surface->blender.join(r, g, b, a);
1559
1560     return _rasterRle(surface, shape->strokeRle, color, a);
1561 }
1562
1563
1564 bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
1565 {
1566     //Verify Boundary
1567     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 false;
1568
1569     //TOOD: switch (image->format)
1570     //TODO: case: _rasterRGBImage()
1571     //TODO: case: _rasterGrayscaleImage()
1572     //TODO: case: _rasterAlphaImage()
1573     return _rasterRGBAImage(surface, image, transform, bbox, opacity);
1574 }
1575
1576 bool rasterImageMesh(SwSurface* surface, SwImage* image, const Polygon* triangles, const uint32_t count, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
1577 {
1578     //Verify Boundary
1579     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 false;
1580
1581     //TOOD: switch (image->format)
1582     //TODO: case: _rasterRGBImageMesh()
1583     //TODO: case: _rasterGrayscaleImageMesh()
1584     //TODO: case: _rasterAlphaImageMesh()
1585     return _transformedRGBAImageMesh(surface, image, triangles, count, transform, &bbox, opacity);
1586 }