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, ®ion, 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