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/************************************************************************/
38constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
39
40struct FillLinear
41{
42 void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
43 {
44 fillLinear(fill, dst, y, x, len, op, a);
45 }
46
47 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)
48 {
49 fillLinear(fill, dst, y, x, len, cmp, alpha, csize, opacity);
50 }
51
52 void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a)
53 {
54 fillLinear(fill, dst, y, x, len, op, op2, a);
55 }
56
57};
58
59struct FillRadial
60{
61 void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
62 {
63 fillRadial(fill, dst, y, x, len, op, a);
64 }
65
66 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)
67 {
68 fillRadial(fill, dst, y, x, len, cmp, alpha, csize, opacity);
69 }
70
71 void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a)
72 {
73 fillRadial(fill, dst, y, x, len, op, op2, a);
74 }
75};
76
77
78static bool _rasterDirectImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity = 255);
79
80
81static inline uint8_t _alpha(uint8_t* a)
82{
83 return *a;
84}
85
86
87static inline uint8_t _ialpha(uint8_t* a)
88{
89 return ~(*a);
90}
91
92
93static inline uint8_t _abgrLuma(uint8_t* c)
94{
95 auto v = *(uint32_t*)c;
96 return ((((v&0xff)*54) + (((v>>8)&0xff)*183) + (((v>>16)&0xff)*19))) >> 8; //0.2125*R + 0.7154*G + 0.0721*B
97}
98
99
100static inline uint8_t _argbLuma(uint8_t* c)
101{
102 auto v = *(uint32_t*)c;
103 return ((((v&0xff)*19) + (((v>>8)&0xff)*183) + (((v>>16)&0xff)*54))) >> 8; //0.0721*B + 0.7154*G + 0.2125*R
104}
105
106
107static inline uint8_t _abgrInvLuma(uint8_t* c)
108{
109 return ~_abgrLuma(c);
110}
111
112
113static inline uint8_t _argbInvLuma(uint8_t* c)
114{
115 return ~_argbLuma(c);
116}
117
118
119static inline uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
120{
121 return (a << 24 | b << 16 | g << 8 | r);
122}
123
124
125static inline uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
126{
127 return (a << 24 | r << 16 | g << 8 | b);
128}
129
130static inline bool _blending(const SwSurface* surface)
131{
132 return (surface->blender) ? true : false;
133}
134
135
136/* OPTIMIZE_ME: Probably, we can separate masking(8bits) / composition(32bits)
137 This would help to enhance the performance by avoiding the unnecessary matting from the composition */
138static inline bool _compositing(const SwSurface* surface)
139{
140 if (!surface->compositor || (int)surface->compositor->method <= (int)CompositeMethod::ClipPath) return false;
141 return true;
142}
143
144
145static inline bool _matting(const SwSurface* surface)
146{
147 if ((int)surface->compositor->method < (int)CompositeMethod::AddMask) return true;
148 else return false;
149}
150
151
152static inline bool _masking(const SwSurface* surface)
153{
154 if ((int)surface->compositor->method >= (int)CompositeMethod::AddMask) return true;
155 else return false;
156}
157
158
159static inline uint32_t _opMaskAdd(uint32_t s, uint32_t d, uint8_t a)
160{
161 return s + ALPHA_BLEND(d, a);
162}
163
164
165static inline uint32_t _opMaskSubtract(TVG_UNUSED uint32_t s, uint32_t d, uint8_t a)
166{
167 return ALPHA_BLEND(d, a);
168}
169
170
171static inline uint32_t _opMaskDifference(uint32_t s, uint32_t d, uint8_t a)
172{
173 return ALPHA_BLEND(s, IA(d)) + ALPHA_BLEND(d, a);
174}
175
176
177static inline uint32_t _opAMaskAdd(uint32_t s, uint32_t d, uint8_t a)
178{
179 return INTERPOLATE(s, d, a);
180}
181
182
183static inline uint32_t _opAMaskSubtract(TVG_UNUSED uint32_t s, uint32_t d, uint8_t a)
184{
185 return ALPHA_BLEND(d, IA(ALPHA_BLEND(s, a)));
186}
187
188
189static inline uint32_t _opAMaskDifference(uint32_t s, uint32_t d, uint8_t a)
190{
191 auto t = ALPHA_BLEND(s, a);
192 return ALPHA_BLEND(t, IA(d)) + ALPHA_BLEND(d, IA(t));
193}
194
195
196static inline SwBlender _getMaskOp(CompositeMethod method)
197{
198 switch (method) {
199 case CompositeMethod::AddMask: return _opMaskAdd;
200 case CompositeMethod::SubtractMask: return _opMaskSubtract;
201 case CompositeMethod::DifferenceMask: return _opMaskDifference;
202 default: return nullptr;
203 }
204}
205
206
207static inline SwBlender _getAMaskOp(CompositeMethod method)
208{
209 switch (method) {
210 case CompositeMethod::AddMask: return _opAMaskAdd;
211 case CompositeMethod::SubtractMask: return _opAMaskSubtract;
212 case CompositeMethod::DifferenceMask: return _opAMaskDifference;
213 default: return nullptr;
214 }
215}
216
217
218#include "tvgSwRasterTexmap.h"
219#include "tvgSwRasterC.h"
220#include "tvgSwRasterAvx.h"
221#include "tvgSwRasterNeon.h"
222
223
224static inline uint32_t _sampleSize(float scale)
225{
226 auto sampleSize = static_cast<uint32_t>(0.5f / scale);
227 if (sampleSize == 0) sampleSize = 1;
228 return sampleSize;
229}
230
231
232//Bilinear Interpolation
233//OPTIMIZE_ME: Skip the function pointer access
234static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, TVG_UNUSED uint32_t n, TVG_UNUSED uint32_t n2)
235{
236 auto rx = (uint32_t)(sx);
237 auto ry = (uint32_t)(sy);
238 auto rx2 = rx + 1;
239 if (rx2 >= w) rx2 = w - 1;
240 auto ry2 = ry + 1;
241 if (ry2 >= h) ry2 = h - 1;
242
243 auto dx = static_cast<uint32_t>((sx - rx) * 255.0f);
244 auto dy = static_cast<uint32_t>((sy - ry) * 255.0f);
245
246 auto c1 = img[rx + ry * w];
247 auto c2 = img[rx2 + ry * w];
248 auto c3 = img[rx2 + ry2 * w];
249 auto c4 = img[rx + ry2 * w];
250
251 return INTERPOLATE(INTERPOLATE(c3, c4, dx), INTERPOLATE(c2, c1, dx), dy);
252}
253
254
255//2n x 2n Mean Kernel
256//OPTIMIZE_ME: Skip the function pointer access
257static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, uint32_t n, uint32_t n2)
258{
259 uint32_t rx = lroundf(sx);
260 uint32_t ry = lroundf(sy);
261 uint32_t c[4] = {0, 0, 0, 0};
262 auto src = img + rx - n + (ry - n) * stride;
263
264 for (auto y = ry - n; y < ry + n; ++y) {
265 if (y >= h) continue;
266 auto p = src;
267 for (auto x = rx - n; x < rx + n; ++x, ++p) {
268 if (x >= w) continue;
269 c[0] += *p >> 24;
270 c[1] += (*p >> 16) & 0xff;
271 c[2] += (*p >> 8) & 0xff;
272 c[3] += *p & 0xff;
273 }
274 src += stride;
275 }
276 for (auto i = 0; i < 4; ++i) {
277 c[i] = (c[i] >> 2) / n2;
278 }
279 return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
280}
281
282
283/************************************************************************/
284/* Rect */
285/************************************************************************/
286
287static void _rasterMaskedRectDup(SwSurface* surface, const SwBBox& region, SwBlender opMask, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
288{
289 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
290 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
291 auto cbuffer = surface->compositor->image.buf32 + (region.min.y * surface->compositor->image.stride + region.min.x); //compositor buffer
292 auto cstride = surface->compositor->image.stride;
293 auto color = surface->join(r, g, b, a);
294 auto ialpha = 255 - a;
295
296 for (uint32_t y = 0; y < h; ++y) {
297 auto cmp = cbuffer;
298 for (uint32_t x = 0; x < w; ++x, ++cmp) {
299 *cmp = opMask(color, *cmp, ialpha);
300 }
301 cbuffer += cstride;
302 }
303}
304
305
306static void _rasterMaskedRectInt(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
307{
308 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
309 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
310 auto cstride = surface->compositor->image.stride;
311
312 for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) {
313 auto cmp = surface->compositor->image.buf32 + (y * cstride + surface->compositor->bbox.min.x);
314 if (y == region.min.y) {
315 for (auto y2 = y; y2 < region.max.y; ++y2) {
316 auto tmp = cmp;
317 auto x = surface->compositor->bbox.min.x;
318 while (x < surface->compositor->bbox.max.x) {
319 if (x == region.min.x) {
320 for (uint32_t i = 0; i < w; ++i, ++tmp) {
321 *tmp = ALPHA_BLEND(*tmp, a);
322 }
323 x += w;
324 } else {
325 *tmp = 0;
326 ++tmp;
327 ++x;
328 }
329 }
330 cmp += cstride;
331 }
332 y += (h - 1);
333 } else {
334 rasterPixel32(cmp, 0x00000000, 0, w);
335 cmp += cstride;
336 }
337 }
338}
339
340
341static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
342{
343 //32bit channels composition
344 if (surface->channelSize != sizeof(uint32_t)) return false;
345
346 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.max.y, region.min.y);
347
348 if (surface->compositor->method == CompositeMethod::IntersectMask) {
349 _rasterMaskedRectInt(surface, region, r, g, b, a);
350 } else if (auto opMask = _getMaskOp(surface->compositor->method)) {
351 //Other Masking operations: Add, Subtract, Difference ...
352 _rasterMaskedRectDup(surface, region, opMask, r, g, b, a);
353 } else {
354 return false;
355 }
356
357 //Masking Composition
358 return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox);
359}
360
361
362static bool _rasterMattedRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
363{
364 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
365 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
366 auto csize = surface->compositor->image.channelSize;
367 auto cbuffer = surface->compositor->image.buf8 + ((region.min.y * surface->compositor->image.stride + region.min.x) * csize); //compositor buffer
368 auto alpha = surface->alpha(surface->compositor->method);
369
370 TVGLOG("SW_ENGINE", "Matted(%d) Rect [Region: %lu %lu %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h);
371
372 //32bits channels
373 if (surface->channelSize == sizeof(uint32_t)) {
374 auto color = surface->join(r, g, b, a);
375 auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
376 for (uint32_t y = 0; y < h; ++y) {
377 auto dst = &buffer[y * surface->stride];
378 auto cmp = &cbuffer[y * surface->compositor->image.stride * csize];
379 for (uint32_t x = 0; x < w; ++x, ++dst, cmp += csize) {
380 *dst = INTERPOLATE(color, *dst, alpha(cmp));
381 }
382 }
383 //8bits grayscale
384 } else if (surface->channelSize == sizeof(uint8_t)) {
385 auto buffer = surface->buf8 + (region.min.y * surface->stride) + region.min.x;
386 for (uint32_t y = 0; y < h; ++y) {
387 auto dst = &buffer[y * surface->stride];
388 auto cmp = &cbuffer[y * surface->compositor->image.stride * csize];
389 for (uint32_t x = 0; x < w; ++x, ++dst, cmp += csize) {
390 *dst = INTERPOLATE8(a, *dst, alpha(cmp));
391 }
392 }
393 }
394 return true;
395}
396
397
398static bool _rasterBlendingRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
399{
400 if (surface->channelSize != sizeof(uint32_t)) return false;
401
402 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
403 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
404 auto color = surface->join(r, g, b, a);
405 auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
406 auto ialpha = 255 - a;
407
408 for (uint32_t y = 0; y < h; ++y) {
409 auto dst = &buffer[y * surface->stride];
410 for (uint32_t x = 0; x < w; ++x, ++dst) {
411 *dst = surface->blender(color, *dst, ialpha);
412 }
413 }
414 return true;
415}
416
417
418static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
419{
420#if defined(THORVG_AVX_VECTOR_SUPPORT)
421 return avxRasterTranslucentRect(surface, region, r, g, b, a);
422#elif defined(THORVG_NEON_VECTOR_SUPPORT)
423 return neonRasterTranslucentRect(surface, region, r, g, b, a);
424#else
425 return cRasterTranslucentRect(surface, region, r, g, b, a);
426#endif
427}
428
429
430static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b)
431{
432 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
433 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
434
435 //32bits channels
436 if (surface->channelSize == sizeof(uint32_t)) {
437 auto color = surface->join(r, g, b, 255);
438 auto buffer = surface->buf32 + (region.min.y * surface->stride);
439 for (uint32_t y = 0; y < h; ++y) {
440 rasterPixel32(buffer + y * surface->stride, color, region.min.x, w);
441 }
442 return true;
443 }
444 //8bits grayscale
445 if (surface->channelSize == sizeof(uint8_t)) {
446 for (uint32_t y = 0; y < h; ++y) {
447 rasterGrayscale8(surface->buf8, 255, region.min.y * surface->stride + region.min.x, w);
448 }
449 return true;
450 }
451 return false;
452}
453
454
455static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
456{
457 if (_compositing(surface)) {
458 if (_matting(surface)) return _rasterMattedRect(surface, region, r, g, b, a);
459 else return _rasterMaskedRect(surface, region, r, g, b, a);
460 } else if (_blending(surface)) {
461 return _rasterBlendingRect(surface, region, r, g, b, a);
462 } else {
463 if (a == 255) return _rasterSolidRect(surface, region, r, g, b);
464 else return _rasterTranslucentRect(surface, region, r, g, b, a);
465 }
466 return false;
467}
468
469
470/************************************************************************/
471/* Rle */
472/************************************************************************/
473
474static void _rasterMaskedRleDup(SwSurface* surface, SwRleData* rle, SwBlender maskOp, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
475{
476 auto span = rle->spans;
477 auto cbuffer = surface->compositor->image.buf32;
478 auto cstride = surface->compositor->image.stride;
479 auto color = surface->join(r, g, b, a);
480 uint32_t src;
481
482 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
483 auto cmp = &cbuffer[span->y * cstride + span->x];
484 if (span->coverage == 255) src = color;
485 else src = ALPHA_BLEND(color, span->coverage);
486 auto ialpha = IA(src);
487 for (auto x = 0; x < span->len; ++x, ++cmp) {
488 *cmp = maskOp(src, *cmp, ialpha);
489 }
490 }
491}
492
493
494static void _rasterMaskedRleInt(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
495{
496 auto span = rle->spans;
497 auto cbuffer = surface->compositor->image.buf32;
498 auto cstride = surface->compositor->image.stride;
499 auto color = surface->join(r, g, b, a);
500 uint32_t src;
501
502 for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) {
503 auto cmp = &cbuffer[y * cstride];
504 auto x = surface->compositor->bbox.min.x;
505 while (x < surface->compositor->bbox.max.x) {
506 if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) {
507 if (span->coverage == 255) src = color;
508 else src = ALPHA_BLEND(color, span->coverage);
509 auto alpha = A(src);
510 for (uint32_t i = 0; i < span->len; ++i) {
511 cmp[x + i] = ALPHA_BLEND(cmp[x + i], alpha);
512 }
513 x += span->len;
514 ++span;
515 } else {
516 cmp[x] = 0;
517 ++x;
518 }
519 }
520 }
521}
522
523
524static bool _rasterMaskedRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
525{
526 TVGLOG("SW_ENGINE", "Masked(%d) Rle", (int)surface->compositor->method);
527
528 //32bit channels composition
529 if (surface->channelSize != sizeof(uint32_t)) return false;
530
531 if (surface->compositor->method == CompositeMethod::IntersectMask) {
532 _rasterMaskedRleInt(surface, rle, r, g, b, a);
533 } else if (auto opMask = _getMaskOp(surface->compositor->method)) {
534 //Other Masking operations: Add, Subtract, Difference ...
535 _rasterMaskedRleDup(surface, rle, opMask, r, g, b, a);
536 } else {
537 return false;
538 }
539
540 //Masking Composition
541 return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox);
542}
543
544
545static bool _rasterMattedRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
546{
547 TVGLOG("SW_ENGINE", "Matted(%d) Rle", (int)surface->compositor->method);
548
549 auto span = rle->spans;
550 auto cbuffer = surface->compositor->image.buf8;
551 auto csize = surface->compositor->image.channelSize;
552 auto alpha = surface->alpha(surface->compositor->method);
553
554 //32bit channels
555 if (surface->channelSize == sizeof(uint32_t)) {
556 uint32_t src;
557 auto color = surface->join(r, g, b, a);
558 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
559 auto dst = &surface->buf32[span->y * surface->stride + span->x];
560 auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
561 if (span->coverage == 255) src = color;
562 else src = ALPHA_BLEND(color, span->coverage);
563 for (uint32_t x = 0; x < span->len; ++x, ++dst, cmp += csize) {
564 auto tmp = ALPHA_BLEND(src, alpha(cmp));
565 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
566 }
567 }
568 return true;
569 }
570 //8bit grayscale
571 if (surface->channelSize == sizeof(uint8_t)) {
572 uint8_t src;
573 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
574 auto dst = &surface->buf8[span->y * surface->stride + span->x];
575 auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
576 if (span->coverage == 255) src = a;
577 else src = MULTIPLY(a, span->coverage);
578 for (uint32_t x = 0; x < span->len; ++x, ++dst, cmp += csize) {
579 *dst = INTERPOLATE8(src, *dst, alpha(cmp));
580 }
581 }
582 return true;
583 }
584 return false;
585}
586
587
588static bool _rasterBlendingRle(SwSurface* surface, const SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
589{
590 if (surface->channelSize != sizeof(uint32_t)) return false;
591
592 auto span = rle->spans;
593 auto color = surface->join(r, g, b, a);
594 auto ialpha = 255 - a;
595
596 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
597 auto dst = &surface->buf32[span->y * surface->stride + span->x];
598 if (span->coverage == 255) {
599 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
600 *dst = surface->blender(color, *dst, ialpha);
601 }
602 } else {
603 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
604 auto tmp = surface->blender(color, *dst, ialpha);
605 *dst = INTERPOLATE(tmp, *dst, span->coverage);
606 }
607 }
608 }
609 return true;
610}
611
612
613static bool _rasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
614{
615#if defined(THORVG_AVX_VECTOR_SUPPORT)
616 return avxRasterTranslucentRle(surface, rle, r, g, b, a);
617#elif defined(THORVG_NEON_VECTOR_SUPPORT)
618 return neonRasterTranslucentRle(surface, rle, r, g, b, a);
619#else
620 return cRasterTranslucentRle(surface, rle, r, g, b, a);
621#endif
622}
623
624
625static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint8_t r, uint8_t g, uint8_t b)
626{
627 auto span = rle->spans;
628
629 //32bit channels
630 if (surface->channelSize == sizeof(uint32_t)) {
631 auto color = surface->join(r, g, b, 255);
632 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
633 if (span->coverage == 255) {
634 rasterPixel32(surface->buf32 + span->y * surface->stride, color, span->x, span->len);
635 } else {
636 auto dst = &surface->buf32[span->y * surface->stride + span->x];
637 auto src = ALPHA_BLEND(color, span->coverage);
638 auto ialpha = 255 - span->coverage;
639 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
640 *dst = src + ALPHA_BLEND(*dst, ialpha);
641 }
642 }
643 }
644 //8bit grayscale
645 } else if (surface->channelSize == sizeof(uint8_t)) {
646 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
647 rasterGrayscale8(surface->buf8, span->coverage, span->y * surface->stride + span->x, span->len);
648 }
649 }
650 return true;
651}
652
653
654static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
655{
656 if (!rle) return false;
657
658 if (_compositing(surface)) {
659 if (_matting(surface)) return _rasterMattedRle(surface, rle, r, g, b, a);
660 else return _rasterMaskedRle(surface, rle, r, g, b, a);
661 } else if (_blending(surface)) {
662 return _rasterBlendingRle(surface, rle, r, g, b, a);
663 } else {
664 if (a == 255) return _rasterSolidRle(surface, rle, r, g, b);
665 else return _rasterTranslucentRle(surface, rle, r, g, b, a);
666 }
667 return false;
668}
669
670
671/************************************************************************/
672/* RLE Transformed Image */
673/************************************************************************/
674
675static bool _transformedRleImage(SwSurface* surface, const SwImage* image, const Matrix* transform, uint8_t opacity)
676{
677 auto ret = _rasterTexmapPolygon(surface, image, transform, nullptr, opacity);
678
679 //Masking Composition
680 if (_compositing(surface) && _masking(surface)) {
681 return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox);
682 }
683
684 return ret;
685
686}
687
688
689/************************************************************************/
690/* RLE Scaled Image */
691/************************************************************************/
692
693static void _rasterScaledMaskedRleImageDup(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity)
694{
695 auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
696 auto sampleSize = _sampleSize(image->scale);
697 auto sampleSize2 = sampleSize * sampleSize;
698 auto span = image->rle->spans;
699
700 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
701 auto sy = span->y * itransform->e22 + itransform->e23;
702 if ((uint32_t)sy >= image->h) continue;
703 auto cmp = &surface->compositor->image.buf32[span->y * surface->compositor->image.stride + span->x];
704 auto a = MULTIPLY(span->coverage, opacity);
705 if (a == 255) {
706 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp) {
707 auto sx = x * itransform->e11 + itransform->e13;
708 if ((uint32_t)sx >= image->w) continue;
709 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
710 *cmp = maskOp(src, *cmp, 255);
711 }
712 } else {
713 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp) {
714 auto sx = x * itransform->e11 + itransform->e13;
715 if ((uint32_t)sx >= image->w) continue;
716 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
717 *cmp = amaskOp(src, *cmp, a);
718 }
719 }
720 }
721}
722
723
724static void _rasterScaledMaskedRleImageInt(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
725{
726 auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
727 auto sampleSize = _sampleSize(image->scale);
728 auto sampleSize2 = sampleSize * sampleSize;
729 auto span = image->rle->spans;
730 auto cbuffer = surface->compositor->image.buf32;
731 auto cstride = surface->compositor->image.stride;
732
733 for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) {
734 auto cmp = &cbuffer[y * cstride];
735 for (auto x = surface->compositor->bbox.min.x; x < surface->compositor->bbox.max.x; ++x) {
736 if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) {
737 auto sy = span->y * itransform->e22 + itransform->e23;
738 if ((uint32_t)sy >= image->h) continue;
739 auto alpha = MULTIPLY(span->coverage, opacity);
740 if (alpha == 255) {
741 for (uint32_t i = 0; i < span->len; ++i) {
742 auto sx = (x + i) * itransform->e11 + itransform->e13;
743 if ((uint32_t)sx >= image->w) continue;
744 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
745 cmp[x + i] = ALPHA_BLEND(cmp[x + i], A(src));
746 }
747 } else {
748 for (uint32_t i = 0; i < span->len; ++i) {
749 auto sx = (x + i) * itransform->e11 + itransform->e13;
750 if ((uint32_t)sx >= image->w) continue;
751 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
752 cmp[x + i] = ALPHA_BLEND(cmp[x + i], A(ALPHA_BLEND(src, alpha)));
753 }
754 }
755 x += span->len - 1;
756 ++span;
757 } else {
758 cmp[x] = 0;
759 }
760 }
761 }
762}
763
764
765static bool _rasterScaledMaskedRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
766{
767 TVGLOG("SW_ENGINE", "Scaled Masked(%d) Rle Image", (int)surface->compositor->method);
768
769 if (surface->compositor->method == CompositeMethod::IntersectMask) {
770 _rasterScaledMaskedRleImageInt(surface, image, itransform, region, opacity);
771 } else if (auto opMask = _getMaskOp(surface->compositor->method)) {
772 //Other Masking operations: Add, Subtract, Difference ...
773 _rasterScaledMaskedRleImageDup(surface, image, itransform, region, opMask, _getAMaskOp(surface->compositor->method), opacity);
774 } else {
775 return false;
776 }
777 //Masking Composition
778 return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox);
779}
780
781
782static bool _rasterScaledMattedRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
783{
784 TVGLOG("SW_ENGINE", "Scaled Matted(%d) Rle Image", (int)surface->compositor->method);
785
786 auto span = image->rle->spans;
787 auto csize = surface->compositor->image.channelSize;
788 auto alpha = surface->alpha(surface->compositor->method);
789
790 auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
791 auto sampleSize = _sampleSize(image->scale);
792 auto sampleSize2 = sampleSize * sampleSize;
793
794 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
795 auto sy = span->y * itransform->e22 + itransform->e23;
796 if ((uint32_t)sy >= image->h) continue;
797 auto dst = &surface->buf32[span->y * surface->stride + span->x];
798 auto cmp = &surface->compositor->image.buf8[(span->y * surface->compositor->image.stride + span->x) * csize];
799 auto a = MULTIPLY(span->coverage, opacity);
800 if (a == 255) {
801 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
802 auto sx = x * itransform->e11 + itransform->e13;
803 if ((uint32_t)sx >= image->w) continue;
804 auto tmp = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), alpha(cmp));
805 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
806 }
807 } else {
808 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
809 auto sx = x * itransform->e11 + itransform->e13;
810 if ((uint32_t)sx >= image->w) continue;
811 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
812 auto tmp = ALPHA_BLEND(src, MULTIPLY(alpha(cmp), a));
813 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
814 }
815 }
816 }
817
818 return true;
819}
820
821
822static bool _rasterScaledBlendingRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
823{
824 auto span = image->rle->spans;
825 auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
826 auto sampleSize = _sampleSize(image->scale);
827 auto sampleSize2 = sampleSize * sampleSize;
828
829 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
830 auto sy = span->y * itransform->e22 + itransform->e23;
831 if ((uint32_t)sy >= image->h) continue;
832 auto dst = &surface->buf32[span->y * surface->stride + span->x];
833 auto alpha = MULTIPLY(span->coverage, opacity);
834 if (alpha == 255) {
835 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
836 auto sx = x * itransform->e11 + itransform->e13;
837 if ((uint32_t)sx >= image->w) continue;
838 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
839 auto tmp = surface->blender(src, *dst, 255);
840 *dst = INTERPOLATE(tmp, *dst, A(src));
841 }
842 } else if (opacity == 255) {
843 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
844 auto sx = x * itransform->e11 + itransform->e13;
845 if ((uint32_t)sx >= image->w) continue;
846 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
847 auto tmp = surface->blender(src, *dst, 255);
848 *dst = INTERPOLATE(tmp, *dst, MULTIPLY(span->coverage, A(src)));
849 }
850 } else {
851 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
852 auto sx = x * itransform->e11 + itransform->e13;
853 if ((uint32_t)sx >= image->w) continue;
854 auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity);
855 auto tmp = surface->blender(src, *dst, 255);
856 *dst = INTERPOLATE(tmp, *dst, MULTIPLY(span->coverage, A(src)));
857 }
858 }
859 }
860 return true;
861}
862
863
864static bool _rasterScaledRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
865{
866 auto span = image->rle->spans;
867 auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
868 auto sampleSize = _sampleSize(image->scale);
869 auto sampleSize2 = sampleSize * sampleSize;
870
871 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
872 auto sy = span->y * itransform->e22 + itransform->e23;
873 if ((uint32_t)sy >= image->h) continue;
874 auto dst = &surface->buf32[span->y * surface->stride + span->x];
875 auto alpha = MULTIPLY(span->coverage, opacity);
876 if (alpha == 255) {
877 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
878 auto sx = x * itransform->e11 + itransform->e13;
879 if ((uint32_t)sx >= image->w) continue;
880 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
881 *dst = src + ALPHA_BLEND(*dst, IA(src));
882 }
883 } else {
884 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
885 auto sx = x * itransform->e11 + itransform->e13;
886 if ((uint32_t)sx >= image->w) continue;
887 auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), alpha);
888 *dst = src + ALPHA_BLEND(*dst, IA(src));
889 }
890 }
891 }
892 return true;
893}
894
895
896static bool _scaledRleImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity)
897{
898 Matrix itransform;
899
900 if (transform) {
901 if (!mathInverse(transform, &itransform)) return false;
902 } else mathIdentity(&itransform);
903
904 if (_compositing(surface)) {
905 if (_matting(surface)) return _rasterScaledMattedRleImage(surface, image, &itransform, region, opacity);
906 else return _rasterScaledMaskedRleImage(surface, image, &itransform, region, opacity);
907 } else if (_blending(surface)) {
908 return _rasterScaledBlendingRleImage(surface, image, &itransform, region, opacity);
909 } else {
910 return _rasterScaledRleImage(surface, image, &itransform, region, opacity);
911 }
912 return false;
913}
914
915
916/************************************************************************/
917/* RLE Direct Image */
918/************************************************************************/
919
920static void _rasterDirectMaskedRleImageDup(SwSurface* surface, const SwImage* image, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity)
921{
922 auto span = image->rle->spans;
923 auto cbuffer = surface->compositor->image.buf32;
924 auto ctride = surface->compositor->image.stride;
925
926 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
927 auto src = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
928 auto cmp = &cbuffer[span->y * ctride + span->x];
929 auto alpha = MULTIPLY(span->coverage, opacity);
930 if (alpha == 255) {
931 for (uint32_t x = 0; x < span->len; ++x, ++src, ++cmp) {
932 *cmp = maskOp(*src, *cmp, IA(*src));
933 }
934 } else {
935 for (uint32_t x = 0; x < span->len; ++x, ++src, ++cmp) {
936 *cmp = amaskOp(*src, *cmp, alpha);
937 }
938 }
939 }
940}
941
942
943static void _rasterDirectMaskedRleImageInt(SwSurface* surface, const SwImage* image, uint8_t opacity)
944{
945 auto span = image->rle->spans;
946 auto cbuffer = surface->compositor->image.buf32;
947 auto ctride = surface->compositor->image.stride;
948
949 for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) {
950 auto cmp = &cbuffer[y * ctride];
951 auto x = surface->compositor->bbox.min.x;
952 while (x < surface->compositor->bbox.max.x) {
953 if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) {
954 auto alpha = MULTIPLY(span->coverage, opacity);
955 auto src = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
956 if (alpha == 255) {
957 for (uint32_t i = 0; i < span->len; ++i, ++src) {
958 cmp[x + i] = ALPHA_BLEND(cmp[x + i], A(*src));
959 }
960 } else {
961 for (uint32_t i = 0; i < span->len; ++i, ++src) {
962 auto t = ALPHA_BLEND(*src, alpha);
963 cmp[x + i] = ALPHA_BLEND(cmp[x + i], A(t));
964 }
965 }
966 x += span->len;
967 ++span;
968 } else {
969 cmp[x] = 0;
970 ++x;
971 }
972 }
973 }
974}
975
976
977static bool _rasterDirectMaskedRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
978{
979 TVGLOG("SW_ENGINE", "Direct Masked(%d) Rle Image", (int)surface->compositor->method);
980
981 if (surface->compositor->method == CompositeMethod::IntersectMask) {
982 _rasterDirectMaskedRleImageInt(surface, image, opacity);
983 } else if (auto opMask = _getMaskOp(surface->compositor->method)) {
984 //Other Masking operations: Add, Subtract, Difference ...
985 _rasterDirectMaskedRleImageDup(surface, image, opMask, _getAMaskOp(surface->compositor->method), opacity);
986 } else {
987 return false;
988 }
989
990 //Masking Composition
991 return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox);
992}
993
994
995static bool _rasterDirectMattedRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
996{
997 TVGLOG("SW_ENGINE", "Direct Matted(%d) Rle Image", (int)surface->compositor->method);
998
999 auto span = image->rle->spans;
1000 auto csize = surface->compositor->image.channelSize;
1001 auto cbuffer = surface->compositor->image.buf8;
1002 auto alpha = surface->alpha(surface->compositor->method);
1003
1004 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
1005 auto dst = &surface->buf32[span->y * surface->stride + span->x];
1006 auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
1007 auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
1008 auto a = MULTIPLY(span->coverage, opacity);
1009 if (a == 255) {
1010 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img, cmp += csize) {
1011 auto tmp = ALPHA_BLEND(*img, alpha(cmp));
1012 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
1013 }
1014 } else {
1015 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img, cmp += csize) {
1016 auto tmp = ALPHA_BLEND(*img, MULTIPLY(a, alpha(cmp)));
1017 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
1018 }
1019 }
1020 }
1021 return true;
1022}
1023
1024
1025static bool _rasterDirectBlendingRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
1026{
1027 auto span = image->rle->spans;
1028
1029 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
1030 auto dst = &surface->buf32[span->y * surface->stride + span->x];
1031 auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
1032 auto alpha = MULTIPLY(span->coverage, opacity);
1033 if (alpha == 255) {
1034 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
1035 *dst = surface->blender(*img, *dst, IA(*img));
1036 }
1037 } else if (opacity == 255) {
1038 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
1039 auto tmp = surface->blender(*img, *dst, 255);
1040 *dst = INTERPOLATE(tmp, *dst, MULTIPLY(span->coverage, A(*img)));
1041 }
1042 } else {
1043 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
1044 auto src = ALPHA_BLEND(*img, opacity);
1045 auto tmp = surface->blender(src, *dst, IA(src));
1046 *dst = INTERPOLATE(tmp, *dst, MULTIPLY(span->coverage, A(src)));
1047 }
1048 }
1049 }
1050 return true;
1051}
1052
1053
1054static bool _rasterDirectRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
1055{
1056 auto span = image->rle->spans;
1057
1058 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
1059 auto dst = &surface->buf32[span->y * surface->stride + span->x];
1060 auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
1061 auto alpha = MULTIPLY(span->coverage, opacity);
1062 if (alpha == 255) {
1063 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
1064 *dst = *img + ALPHA_BLEND(*dst, IA(*img));
1065 }
1066 } else {
1067 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
1068 auto src = ALPHA_BLEND(*img, alpha);
1069 *dst = src + ALPHA_BLEND(*dst, IA(src));
1070 }
1071 }
1072 }
1073 return true;
1074}
1075
1076
1077static bool _directRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
1078{
1079 if (_compositing(surface)) {
1080 if (_matting(surface)) return _rasterDirectMattedRleImage(surface, image, opacity);
1081 else return _rasterDirectMaskedRleImage(surface, image, opacity);
1082 } else if (_blending(surface)) {
1083 return _rasterDirectBlendingRleImage(surface, image, opacity);
1084 } else {
1085 return _rasterDirectRleImage(surface, image, opacity);
1086 }
1087 return false;
1088}
1089
1090
1091/************************************************************************/
1092/* Transformed Image */
1093/************************************************************************/
1094
1095static bool _transformedImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity)
1096{
1097 auto ret = _rasterTexmapPolygon(surface, image, transform, &region, opacity);
1098
1099 //Masking Composition
1100 if (_compositing(surface) && _masking(surface)) {
1101 return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox);
1102 }
1103
1104 return ret;
1105}
1106
1107
1108static bool _transformedImageMesh(SwSurface* surface, const SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox* region, uint8_t opacity)
1109{
1110 //TODO: Not completed for all cases.
1111 return _rasterTexmapPolygonMesh(surface, image, mesh, transform, region, opacity);
1112}
1113
1114
1115/************************************************************************/
1116/*Scaled Image */
1117/************************************************************************/
1118
1119static void _rasterScaledMaskedImageDup(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity)
1120{
1121 auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
1122 auto sampleSize = _sampleSize(image->scale);
1123 auto sampleSize2 = sampleSize * sampleSize;
1124 auto cstride = surface->compositor->image.stride;
1125 auto cbuffer = surface->compositor->image.buf32 + (region.min.y * cstride + region.min.x);
1126
1127 for (auto y = region.min.y; y < region.max.y; ++y) {
1128 auto sy = y * itransform->e22 + itransform->e23;
1129 if ((uint32_t)sy >= image->h) continue;
1130 auto cmp = cbuffer;
1131 if (opacity == 255) {
1132 for (auto x = region.min.x; x < region.max.x; ++x, ++cmp) {
1133 auto sx = x * itransform->e11 + itransform->e13;
1134 if ((uint32_t)sx >= image->w) continue;
1135 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
1136 *cmp = maskOp(src, *cmp, IA(src));
1137 }
1138 } else {
1139 for (auto x = region.min.x; x < region.max.x; ++x, ++cmp) {
1140 auto sx = x * itransform->e11 + itransform->e13;
1141 if ((uint32_t)sx >= image->w) continue;
1142 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
1143 *cmp = amaskOp(src, *cmp, opacity);
1144 }
1145 }
1146 cbuffer += cstride;
1147 }
1148}
1149
1150static void _rasterScaledMaskedImageInt(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
1151{
1152 auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
1153 auto sampleSize = _sampleSize(image->scale);
1154 auto sampleSize2 = sampleSize * sampleSize;
1155 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1156 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1157 auto cstride = surface->compositor->image.stride;
1158 auto cbuffer = surface->compositor->image.buf32 + (surface->compositor->bbox.min.y * cstride + surface->compositor->bbox.min.x);
1159
1160 for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) {
1161 if (y == region.min.y) {
1162 auto cbuffer2 = cbuffer;
1163 for (auto y2 = y; y2 < region.max.y; ++y2) {
1164 auto sy = y2 * itransform->e22 + itransform->e23;
1165 if ((uint32_t)sy >= image->h) continue;
1166 auto tmp = cbuffer2;
1167 auto x = surface->compositor->bbox.min.x;
1168 while (x < surface->compositor->bbox.max.x) {
1169 if (x == region.min.x) {
1170 if (opacity == 255) {
1171 for (uint32_t i = 0; i < w; ++i, ++tmp) {
1172 auto sx = (x + i) * itransform->e11 + itransform->e13;
1173 if ((uint32_t)sx >= image->w) continue;
1174 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
1175 *tmp = ALPHA_BLEND(*tmp, A(src));
1176 }
1177 } else {
1178 for (uint32_t i = 0; i < w; ++i, ++tmp) {
1179 auto sx = (x + i) * itransform->e11 + itransform->e13;
1180 if ((uint32_t)sx >= image->w) continue;
1181 auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity);
1182 *tmp = ALPHA_BLEND(*tmp, A(src));
1183 }
1184 }
1185 x += w;
1186 } else {
1187 *tmp = 0;
1188 ++tmp;
1189 ++x;
1190 }
1191 }
1192 cbuffer2 += cstride;
1193 }
1194 y += (h - 1);
1195 } else {
1196 auto tmp = cbuffer;
1197 for (auto x = surface->compositor->bbox.min.x; x < surface->compositor->bbox.max.x; ++x, ++tmp) {
1198 *tmp = 0;
1199 }
1200 }
1201 cbuffer += cstride;
1202 }
1203}
1204
1205
1206static bool _rasterScaledMaskedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
1207{
1208 TVGLOG("SW_ENGINE", "Scaled Masked(%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);
1209
1210 if (surface->compositor->method == CompositeMethod::IntersectMask) {
1211 _rasterScaledMaskedImageInt(surface, image, itransform, region, opacity);
1212 } else if (auto opMask = _getMaskOp(surface->compositor->method)) {
1213 //Other Masking operations: Add, Subtract, Difference ...
1214 _rasterScaledMaskedImageDup(surface, image, itransform, region, opMask, _getAMaskOp(surface->compositor->method), opacity);
1215 } else {
1216 return false;
1217 }
1218
1219 //Masking Composition
1220 return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox);
1221}
1222
1223
1224static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
1225{
1226 auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
1227 auto csize = surface->compositor->image.channelSize;
1228 auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
1229 auto alpha = surface->alpha(surface->compositor->method);
1230
1231 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);
1232
1233 auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
1234 auto sampleSize = _sampleSize(image->scale);
1235 auto sampleSize2 = sampleSize * sampleSize;
1236
1237 for (auto y = region.min.y; y < region.max.y; ++y) {
1238 auto sy = y * itransform->e22 + itransform->e23;
1239 if ((uint32_t)sy >= image->h) continue;
1240 auto dst = dbuffer;
1241 auto cmp = cbuffer;
1242 if (opacity == 255) {
1243 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) {
1244 auto sx = x * itransform->e11 + itransform->e13;
1245 if ((uint32_t)sx >= image->w) continue;
1246 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
1247 auto temp = ALPHA_BLEND(src, alpha(cmp));
1248 *dst = temp + ALPHA_BLEND(*dst, IA(temp));
1249 }
1250 } else {
1251 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) {
1252 auto sx = x * itransform->e11 + itransform->e13;
1253 if ((uint32_t)sx >= image->w) continue;
1254 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
1255 auto temp = ALPHA_BLEND(src, MULTIPLY(opacity, alpha(cmp)));
1256 *dst = temp + ALPHA_BLEND(*dst, IA(temp));
1257 }
1258 }
1259 dbuffer += surface->stride;
1260 cbuffer += surface->compositor->image.stride * csize;
1261 }
1262 return true;
1263}
1264
1265
1266static bool _rasterScaledBlendingImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
1267{
1268 auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
1269 auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
1270 auto sampleSize = _sampleSize(image->scale);
1271 auto sampleSize2 = sampleSize * sampleSize;
1272
1273 for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
1274 auto sy = y * itransform->e22 + itransform->e23;
1275 if ((uint32_t)sy >= image->h) continue;
1276 auto dst = dbuffer;
1277 if (opacity == 255) {
1278 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1279 auto sx = x * itransform->e11 + itransform->e13;
1280 if ((uint32_t)sx >= image->w) continue;
1281 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
1282 auto tmp = surface->blender(src, *dst, 255);
1283 *dst = INTERPOLATE(tmp, *dst, A(src));
1284 }
1285 } else {
1286 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1287 auto sx = x * itransform->e11 + itransform->e13;
1288 if ((uint32_t)sx >= image->w) continue;
1289 auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity);
1290 auto tmp = surface->blender(src, *dst, 255);
1291 *dst = INTERPOLATE(tmp, *dst, A(src));
1292 }
1293 }
1294 }
1295 return true;
1296}
1297
1298
1299static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
1300{
1301 auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
1302 auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
1303 auto sampleSize = _sampleSize(image->scale);
1304 auto sampleSize2 = sampleSize * sampleSize;
1305
1306 for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
1307 auto sy = y * itransform->e22 + itransform->e23;
1308 if ((uint32_t)sy >= image->h) continue;
1309 auto dst = dbuffer;
1310 if (opacity == 255) {
1311 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1312 auto sx = x * itransform->e11 + itransform->e13;
1313 if ((uint32_t)sx >= image->w) continue;
1314 auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
1315 *dst = src + ALPHA_BLEND(*dst, IA(src));
1316 }
1317 } else {
1318 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1319 auto sx = x * itransform->e11 + itransform->e13;
1320 if ((uint32_t)sx >= image->w) continue;
1321 auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity);
1322 *dst = src + ALPHA_BLEND(*dst, IA(src));
1323 }
1324 }
1325 }
1326 return true;
1327}
1328
1329
1330static bool _scaledImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity)
1331{
1332 Matrix itransform;
1333
1334 if (transform) {
1335 if (!mathInverse(transform, &itransform)) return false;
1336 } else mathIdentity(&itransform);
1337
1338 if (_compositing(surface)) {
1339 if (_matting(surface)) return _rasterScaledMattedImage(surface, image, &itransform, region, opacity);
1340 else return _rasterScaledMaskedImage(surface, image, &itransform, region, opacity);
1341 } else if (_blending(surface)) {
1342 return _rasterScaledBlendingImage(surface, image, &itransform, region, opacity);
1343 } else {
1344 return _rasterScaledImage(surface, image, &itransform, region, opacity);
1345 }
1346 return false;
1347}
1348
1349
1350/************************************************************************/
1351/* Direct Image */
1352/************************************************************************/
1353
1354static void _rasterDirectMaskedImageDup(SwSurface* surface, const SwImage* image, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity)
1355{
1356 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1357 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1358 auto cstride = surface->compositor->image.stride;
1359
1360 auto cbuffer = surface->compositor->image.buf32 + (region.min.y * cstride + region.min.x); //compositor buffer
1361 auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1362
1363 for (uint32_t y = 0; y < h; ++y) {
1364 auto cmp = cbuffer;
1365 auto src = sbuffer;
1366 if (opacity == 255) {
1367 for (uint32_t x = 0; x < w; ++x, ++src, ++cmp) {
1368 *cmp = maskOp(*src, *cmp, IA(*src));
1369 }
1370 } else {
1371 for (uint32_t x = 0; x < w; ++x, ++src, ++cmp) {
1372 *cmp = amaskOp(*src, *cmp, opacity);
1373 }
1374 }
1375 cbuffer += cstride;
1376 sbuffer += image->stride;
1377 }
1378}
1379
1380
1381static void _rasterDirectMaskedImageInt(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1382{
1383 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1384 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1385 auto cstride = surface->compositor->image.stride;
1386 auto cbuffer = surface->compositor->image.buf32 + (surface->compositor->bbox.min.y * cstride + surface->compositor->bbox.min.x);
1387
1388 for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) {
1389 if (y == region.min.y) {
1390 auto cbuffer2 = cbuffer;
1391 for (auto y2 = y; y2 < region.max.y; ++y2) {
1392 auto tmp = cbuffer2;
1393 auto x = surface->compositor->bbox.min.x;
1394 while (x < surface->compositor->bbox.max.x) {
1395 if (x == region.min.x) {
1396 auto src = &image->buf32[(y2 + image->oy) * image->stride + (x + image->ox)];
1397 if (opacity == 255) {
1398 for (uint32_t i = 0; i < w; ++i, ++tmp, ++src) {
1399 *tmp = ALPHA_BLEND(*tmp, A(*src));
1400 }
1401 } else {
1402 for (uint32_t i = 0; i < w; ++i, ++tmp, ++src) {
1403 auto t = ALPHA_BLEND(*src, opacity);
1404 *tmp = ALPHA_BLEND(*tmp, A(t));
1405 }
1406 }
1407 x += w;
1408 } else {
1409 *tmp = 0;
1410 ++tmp;
1411 ++x;
1412 }
1413 }
1414 cbuffer2 += cstride;
1415 }
1416 y += (h - 1);
1417 } else {
1418 rasterPixel32(cbuffer, 0x00000000, 0, surface->compositor->bbox.max.x - surface->compositor->bbox.min.x);
1419 }
1420 cbuffer += cstride;
1421 }
1422}
1423
1424
1425static bool _rasterDirectMaskedImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1426{
1427 TVGLOG("SW_ENGINE", "Direct Masked(%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);
1428
1429 if (surface->compositor->method == CompositeMethod::IntersectMask) {
1430 _rasterDirectMaskedImageInt(surface, image, region, opacity);
1431 } else if (auto opMask = _getMaskOp(surface->compositor->method)) {
1432 //Other Masking operations: Add, Subtract, Difference ...
1433 _rasterDirectMaskedImageDup(surface, image, region, opMask, _getAMaskOp(surface->compositor->method), opacity);
1434 } else {
1435 return false;
1436 }
1437 //Masking Composition
1438 return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox);
1439}
1440
1441
1442static bool _rasterDirectMattedImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1443{
1444 auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1445 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1446 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1447 auto csize = surface->compositor->image.channelSize;
1448 auto alpha = surface->alpha(surface->compositor->method);
1449
1450 TVGLOG("SW_ENGINE", "Direct Matted(%d) Image [Region: %lu %lu %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h);
1451
1452 auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1453 auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize; //compositor buffer
1454
1455 for (uint32_t y = 0; y < h; ++y) {
1456 auto dst = buffer;
1457 auto cmp = cbuffer;
1458 auto src = sbuffer;
1459 if (opacity == 255) {
1460 for (uint32_t x = 0; x < w; ++x, ++dst, ++src, cmp += csize) {
1461 auto tmp = ALPHA_BLEND(*src, alpha(cmp));
1462 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
1463 }
1464 } else {
1465 for (uint32_t x = 0; x < w; ++x, ++dst, ++src, cmp += csize) {
1466 auto tmp = ALPHA_BLEND(*src, MULTIPLY(opacity, alpha(cmp)));
1467 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
1468 }
1469 }
1470 buffer += surface->stride;
1471 cbuffer += surface->compositor->image.stride * csize;
1472 sbuffer += image->stride;
1473 }
1474 return true;
1475}
1476
1477
1478static bool _rasterDirectBlendingImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1479{
1480 auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x];
1481 auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1482
1483 for (auto y = region.min.y; y < region.max.y; ++y) {
1484 auto dst = dbuffer;
1485 auto src = sbuffer;
1486 if (opacity == 255) {
1487 for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
1488 auto tmp = surface->blender(*src, *dst, 255);
1489 *dst = INTERPOLATE(tmp, *dst, A(*src));
1490 }
1491 } else {
1492 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
1493 auto tmp = ALPHA_BLEND(*src, opacity);
1494 auto tmp2 = surface->blender(tmp, *dst, 255);
1495 *dst = INTERPOLATE(tmp2, *dst, A(tmp));
1496 }
1497 }
1498 dbuffer += surface->stride;
1499 sbuffer += image->stride;
1500 }
1501 return true;
1502}
1503
1504
1505static bool _rasterDirectImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1506{
1507 auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x];
1508 auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1509
1510 for (auto y = region.min.y; y < region.max.y; ++y) {
1511 auto dst = dbuffer;
1512 auto src = sbuffer;
1513 if (opacity == 255) {
1514 for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
1515 *dst = *src + ALPHA_BLEND(*dst, IA(*src));
1516 }
1517 } else {
1518 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
1519 auto tmp = ALPHA_BLEND(*src, opacity);
1520 *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
1521 }
1522 }
1523 dbuffer += surface->stride;
1524 sbuffer += image->stride;
1525 }
1526 return true;
1527}
1528
1529
1530//Blenders for the following scenarios: [Composition / Non-Composition] * [Opaque / Translucent]
1531static bool _directImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
1532{
1533 if (_compositing(surface)) {
1534 if (_matting(surface)) return _rasterDirectMattedImage(surface, image, region, opacity);
1535 else return _rasterDirectMaskedImage(surface, image, region, opacity);
1536 } else if (_blending(surface)) {
1537 return _rasterDirectBlendingImage(surface, image, region, opacity);
1538 } else {
1539 return _rasterDirectImage(surface, image, region, opacity);
1540 }
1541 return false;
1542}
1543
1544
1545//Blenders for the following scenarios: [RLE / Whole] * [Direct / Scaled / Transformed]
1546static bool _rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity)
1547{
1548 //RLE Image
1549 if (image->rle) {
1550 if (image->direct) return _directRleImage(surface, image, opacity);
1551 else if (image->scaled) return _scaledRleImage(surface, image, transform, region, opacity);
1552 else return _transformedRleImage(surface, image, transform, opacity);
1553 //Whole Image
1554 } else {
1555 if (image->direct) return _directImage(surface, image, region, opacity);
1556 else if (image->scaled) return _scaledImage(surface, image, transform, region, opacity);
1557 else return _transformedImage(surface, image, transform, region, opacity);
1558 }
1559}
1560
1561
1562/************************************************************************/
1563/* Rect Gradient */
1564/************************************************************************/
1565
1566template<typename fillMethod>
1567static void _rasterGradientMaskedRectDup(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlender maskOp)
1568{
1569 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1570 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1571 auto cstride = surface->compositor->image.stride;
1572 auto cbuffer = surface->compositor->image.buf32 + (region.min.y * cstride + region.min.x);
1573
1574 for (uint32_t y = 0; y < h; ++y) {
1575 fillMethod()(fill, cbuffer, region.min.y + y, region.min.x, w, maskOp, 255);
1576 cbuffer += surface->stride;
1577 }
1578}
1579
1580
1581template<typename fillMethod>
1582static void _rasterGradientMaskedRectInt(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1583{
1584 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1585 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1586 auto cstride = surface->compositor->image.stride;
1587
1588 for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) {
1589 auto cmp = surface->compositor->image.buf32 + (y * cstride + surface->compositor->bbox.min.x);
1590 if (y == region.min.y) {
1591 for (auto y2 = y; y2 < region.max.y; ++y2) {
1592 auto tmp = cmp;
1593 auto x = surface->compositor->bbox.min.x;
1594 while (x < surface->compositor->bbox.max.x) {
1595 if (x == region.min.x) {
1596 fillMethod()(fill, tmp, y2, x, w, opMaskPreIntersect, 255);
1597 x += w;
1598 tmp += w;
1599 } else {
1600 *tmp = 0;
1601 ++tmp;
1602 ++x;
1603 }
1604 }
1605 cmp += cstride;
1606 }
1607 y += (h - 1);
1608 } else {
1609 rasterPixel32(cmp, 0x00000000, 0, surface->compositor->bbox.max.x -surface->compositor->bbox.min.x);
1610 cmp += cstride;
1611 }
1612 }
1613}
1614
1615
1616template<typename fillMethod>
1617static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1618{
1619 auto method = surface->compositor->method;
1620
1621 TVGLOG("SW_ENGINE", "Masked(%d) Gradient [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);
1622
1623 if (method == CompositeMethod::AddMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opMaskPreAdd);
1624 else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opMaskPreSubtract);
1625 else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opMaskPreDifference);
1626 else if (method == CompositeMethod::IntersectMask) _rasterGradientMaskedRectInt<fillMethod>(surface, region, fill);
1627 else return false;
1628
1629 //Masking Composition
1630 return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox, 255);
1631}
1632
1633
1634template<typename fillMethod>
1635static bool _rasterGradientMattedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1636{
1637 auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1638 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1639 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1640 auto csize = surface->compositor->image.channelSize;
1641 auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
1642 auto alpha = surface->alpha(surface->compositor->method);
1643
1644 TVGLOG("SW_ENGINE", "Matted(%d) Gradient [Region: %lu %lu %u %u]", (int)surface->compositor->method, region.min.x, region.min.y, w, h);
1645
1646 for (uint32_t y = 0; y < h; ++y) {
1647 fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, cbuffer, alpha, csize, 255);
1648 buffer += surface->stride;
1649 cbuffer += surface->stride * csize;
1650 }
1651 return true;
1652}
1653
1654
1655template<typename fillMethod>
1656static bool _rasterBlendingGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1657{
1658 auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1659 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1660 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1661
1662 if (fill->translucent) {
1663 for (uint32_t y = 0; y < h; ++y) {
1664 fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opBlendPreNormal, surface->blender, 255);
1665 }
1666 } else {
1667 for (uint32_t y = 0; y < h; ++y) {
1668 fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opBlendSrcOver, surface->blender, 255);
1669 }
1670 }
1671 return true;
1672}
1673
1674template<typename fillMethod>
1675static bool _rasterTranslucentGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1676{
1677 auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1678 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1679 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1680
1681 for (uint32_t y = 0; y < h; ++y) {
1682 fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, opBlendPreNormal, 255);
1683 buffer += surface->stride;
1684 }
1685 return true;
1686}
1687
1688
1689template<typename fillMethod>
1690static bool _rasterSolidGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1691{
1692 auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
1693 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1694 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1695
1696 for (uint32_t y = 0; y < h; ++y) {
1697 fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opBlendSrcOver, 255);
1698 }
1699 return true;
1700}
1701
1702
1703static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1704{
1705 if (fill->linear.len < FLT_EPSILON) return false;
1706
1707 if (_compositing(surface)) {
1708 if (_matting(surface)) return _rasterGradientMattedRect<FillLinear>(surface, region, fill);
1709 else return _rasterGradientMaskedRect<FillLinear>(surface, region, fill);
1710 } else if (_blending(surface)) {
1711 return _rasterBlendingGradientRect<FillLinear>(surface, region, fill);
1712 } else {
1713 if (fill->translucent) return _rasterTranslucentGradientRect<FillLinear>(surface, region, fill);
1714 else _rasterSolidGradientRect<FillLinear>(surface, region, fill);
1715 }
1716 return false;
1717}
1718
1719
1720static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1721{
1722 if (fill->radial.a < FLT_EPSILON) return false;
1723
1724 if (_compositing(surface)) {
1725 if (_matting(surface)) return _rasterGradientMattedRect<FillRadial>(surface, region, fill);
1726 else return _rasterGradientMaskedRect<FillRadial>(surface, region, fill);
1727 } else if (_blending(surface)) {
1728 return _rasterBlendingGradientRect<FillRadial>(surface, region, fill);
1729 } else {
1730 if (fill->translucent) return _rasterTranslucentGradientRect<FillRadial>(surface, region, fill);
1731 else _rasterSolidGradientRect<FillRadial>(surface, region, fill);
1732 }
1733 return false;
1734}
1735
1736
1737
1738/************************************************************************/
1739/* Rle Gradient */
1740/************************************************************************/
1741
1742template<typename fillMethod>
1743static void _rasterGradientMaskedRleDup(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlender maskOp)
1744{
1745 auto span = rle->spans;
1746 auto cstride = surface->compositor->image.stride;
1747 auto cbuffer = surface->compositor->image.buf32;
1748
1749 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1750 auto cmp = &cbuffer[span->y * cstride + span->x];
1751 fillMethod()(fill, cmp, span->y, span->x, span->len, maskOp, span->coverage);
1752 }
1753}
1754
1755
1756template<typename fillMethod>
1757static void _rasterGradientMaskedRleInt(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1758{
1759 auto span = rle->spans;
1760 auto cstride = surface->compositor->image.stride;
1761 auto cbuffer = surface->compositor->image.buf32;
1762
1763 for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) {
1764 auto cmp = &cbuffer[y * cstride];
1765 auto x = surface->compositor->bbox.min.x;
1766 while (x < surface->compositor->bbox.max.x) {
1767 if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) {
1768 fillMethod()(fill, cmp, span->y, span->x, span->len, opMaskIntersect, span->coverage);
1769 x += span->len;
1770 ++span;
1771 } else {
1772 cmp[x] = 0;
1773 ++x;
1774 }
1775 }
1776 }
1777}
1778
1779
1780template<typename fillMethod>
1781static bool _rasterGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1782{
1783 TVGLOG("SW_ENGINE", "Masked(%d) Rle Linear Gradient", (int)surface->compositor->method);
1784
1785 auto method = surface->compositor->method;
1786
1787 if (method == CompositeMethod::AddMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opMaskAdd);
1788 else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opMaskSubtract);
1789 else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opMaskDifference);
1790 else if (method == CompositeMethod::IntersectMask) _rasterGradientMaskedRleInt<fillMethod>(surface, rle, fill);
1791 else return false;
1792
1793 //Masking Composition
1794 return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox, 255);
1795}
1796
1797
1798template<typename fillMethod>
1799static bool _rasterGradientMattedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1800{
1801 TVGLOG("SW_ENGINE", "Matted(%d) Rle Linear Gradient", (int)surface->compositor->method);
1802
1803 auto span = rle->spans;
1804 auto csize = surface->compositor->image.channelSize;
1805 auto cbuffer = surface->compositor->image.buf8;
1806 auto alpha = surface->alpha(surface->compositor->method);
1807
1808 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1809 auto dst = &surface->buf32[span->y * surface->stride + span->x];
1810 auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
1811 fillMethod()(fill, dst, span->y, span->x, span->len, cmp, alpha, csize, span->coverage);
1812 }
1813 return true;
1814}
1815
1816
1817template<typename fillMethod>
1818static bool _rasterBlendingGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1819{
1820 auto span = rle->spans;
1821
1822 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1823 auto dst = &surface->buf32[span->y * surface->stride + span->x];
1824 fillMethod()(fill, dst, span->y, span->x, span->len, opBlendPreNormal, surface->blender, span->coverage);
1825 }
1826 return true;
1827}
1828
1829
1830template<typename fillMethod>
1831static bool _rasterTranslucentGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1832{
1833 auto span = rle->spans;
1834
1835 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1836 auto dst = &surface->buf32[span->y * surface->stride + span->x];
1837 if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendPreNormal, 255);
1838 else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendNormal, span->coverage);
1839 }
1840 return true;
1841}
1842
1843
1844template<typename fillMethod>
1845static bool _rasterSolidGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1846{
1847 auto span = rle->spans;
1848
1849 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1850 auto dst = &surface->buf32[span->y * surface->stride + span->x];
1851 if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendSrcOver, 255);
1852 else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendInterp, span->coverage);
1853 }
1854 return true;
1855}
1856
1857
1858static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1859{
1860 if (!rle || fill->linear.len < FLT_EPSILON) return false;
1861
1862 if (_compositing(surface)) {
1863 if (_matting(surface)) return _rasterGradientMattedRle<FillLinear>(surface, rle, fill);
1864 else return _rasterGradientMaskedRle<FillLinear>(surface, rle, fill);
1865 } else if (_blending(surface)) {
1866 return _rasterBlendingGradientRle<FillLinear>(surface, rle, fill);
1867 } else {
1868 if (fill->translucent) return _rasterTranslucentGradientRle<FillLinear>(surface, rle, fill);
1869 else return _rasterSolidGradientRle<FillLinear>(surface, rle, fill);
1870 }
1871 return false;
1872}
1873
1874
1875static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1876{
1877 if (!rle || fill->radial.a < FLT_EPSILON) return false;
1878
1879 if (_compositing(surface)) {
1880 if (_matting(surface)) return _rasterGradientMattedRle<FillRadial>(surface, rle, fill);
1881 else return _rasterGradientMaskedRle<FillRadial>(surface, rle, fill);
1882 } else if (_blending(surface)) {
1883 _rasterBlendingGradientRle<FillRadial>(surface, rle, fill);
1884 } else {
1885 if (fill->translucent) _rasterTranslucentGradientRle<FillRadial>(surface, rle, fill);
1886 else return _rasterSolidGradientRle<FillRadial>(surface, rle, fill);
1887 }
1888 return false;
1889}
1890
1891
1892/************************************************************************/
1893/* External Class Implementation */
1894/************************************************************************/
1895
1896
1897void rasterGrayscale8(uint8_t *dst, uint8_t val, uint32_t offset, int32_t len)
1898{
1899 //OPTIMIZE_ME: Support SIMD
1900 cRasterPixels(dst, val, offset, len);
1901}
1902
1903
1904void rasterPixel32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
1905{
1906#if defined(THORVG_AVX_VECTOR_SUPPORT)
1907 avxRasterPixel32(dst, val, offset, len);
1908#elif defined(THORVG_NEON_VECTOR_SUPPORT)
1909 neonRasterPixel32(dst, val, offset, len);
1910#else
1911 cRasterPixels(dst, val, offset, len);
1912#endif
1913}
1914
1915
1916bool rasterCompositor(SwSurface* surface)
1917{
1918 //See CompositeMethod, Alpha:3, InvAlpha:4, Luma:5, InvLuma:6
1919 surface->alphas[0] = _alpha;
1920 surface->alphas[1] = _ialpha;
1921
1922 if (surface->cs == ColorSpace::ABGR8888 || surface->cs == ColorSpace::ABGR8888S) {
1923 surface->join = _abgrJoin;
1924 surface->alphas[2] = _abgrLuma;
1925 surface->alphas[3] = _abgrInvLuma;
1926 } else if (surface->cs == ColorSpace::ARGB8888 || surface->cs == ColorSpace::ARGB8888S) {
1927 surface->join = _argbJoin;
1928 surface->alphas[2] = _argbLuma;
1929 surface->alphas[3] = _argbInvLuma;
1930 } else {
1931 TVGERR("SW_ENGINE", "Unsupported Colorspace(%d) is expected!", surface->cs);
1932 return false;
1933 }
1934 return true;
1935}
1936
1937
1938bool rasterClear(SwSurface* surface, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
1939{
1940 if (!surface || !surface->buf32 || surface->stride == 0 || surface->w == 0 || surface->h == 0) return false;
1941
1942 //32 bits
1943 if (surface->channelSize == sizeof(uint32_t)) {
1944 //full clear
1945 if (w == surface->stride) {
1946 rasterPixel32(surface->buf32, 0x00000000, surface->stride * y, w * h);
1947 //partial clear
1948 } else {
1949 for (uint32_t i = 0; i < h; i++) {
1950 rasterPixel32(surface->buf32, 0x00000000, (surface->stride * y + x) + (surface->stride * i), w);
1951 }
1952 }
1953 //8 bits
1954 } else if (surface->channelSize == sizeof(uint8_t)) {
1955 //full clear
1956 if (w == surface->stride) {
1957 rasterGrayscale8(surface->buf8, 0x00, surface->stride * y, w * h);
1958 //partial clear
1959 } else {
1960 for (uint32_t i = 0; i < h; i++) {
1961 rasterGrayscale8(surface->buf8, 0x00, (surface->stride * y + x) + (surface->stride * i), w);
1962 }
1963 }
1964 }
1965 return true;
1966}
1967
1968
1969void rasterUnpremultiply(Surface* surface)
1970{
1971 if (surface->channelSize != sizeof(uint32_t)) return;
1972
1973 TVGLOG("SW_ENGINE", "Unpremultiply [Size: %d x %d]", surface->w, surface->h);
1974
1975 //OPTIMIZE_ME: +SIMD
1976 for (uint32_t y = 0; y < surface->h; y++) {
1977 auto buffer = surface->buf32 + surface->stride * y;
1978 for (uint32_t x = 0; x < surface->w; ++x) {
1979 uint8_t a = buffer[x] >> 24;
1980 if (a == 255) {
1981 continue;
1982 } else if (a == 0) {
1983 buffer[x] = 0x00ffffff;
1984 } else {
1985 uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
1986 uint16_t g = ((buffer[x]) & 0xff00) / a;
1987 uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
1988 if (r > 0xff) r = 0xff;
1989 if (g > 0xff) g = 0xff;
1990 if (b > 0xff) b = 0xff;
1991 buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
1992 }
1993 }
1994 }
1995 surface->premultiplied = false;
1996}
1997
1998
1999void rasterPremultiply(Surface* surface)
2000{
2001 if (surface->channelSize != sizeof(uint32_t)) return;
2002
2003 TVGLOG("SW_ENGINE", "Premultiply [Size: %d x %d]", surface->w, surface->h);
2004
2005 //OPTIMIZE_ME: +SIMD
2006 auto buffer = surface->buf32;
2007 for (uint32_t y = 0; y < surface->h; ++y, buffer += surface->stride) {
2008 auto dst = buffer;
2009 for (uint32_t x = 0; x < surface->w; ++x, ++dst) {
2010 auto c = *dst;
2011 auto a = (c >> 24);
2012 *dst = (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff);
2013 }
2014 }
2015 surface->premultiplied = true;
2016}
2017
2018
2019bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
2020{
2021 if (surface->channelSize == sizeof(uint8_t)) {
2022 TVGERR("SW_ENGINE", "Not supported grayscale gradient!");
2023 return false;
2024 }
2025
2026 if (!shape->fill) return false;
2027
2028 if (shape->fastTrack) {
2029 if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill);
2030 else if (id == TVG_CLASS_ID_RADIAL)return _rasterRadialGradientRect(surface, shape->bbox, shape->fill);
2031 } else {
2032 if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->rle, shape->fill);
2033 else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->rle, shape->fill);
2034 }
2035 return false;
2036}
2037
2038
2039bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
2040{
2041 if (surface->channelSize == sizeof(uint8_t)) {
2042 TVGERR("SW_ENGINE", "Not supported grayscale gradient!");
2043 return false;
2044 }
2045
2046 if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
2047
2048 if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
2049 else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
2050
2051 return false;
2052}
2053
2054
2055bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
2056{
2057 if (a < 255) {
2058 r = MULTIPLY(r, a);
2059 g = MULTIPLY(g, a);
2060 b = MULTIPLY(b, a);
2061 }
2062
2063 if (shape->fastTrack) return _rasterRect(surface, shape->bbox, r, g, b, a);
2064 else return _rasterRle(surface, shape->rle, r, g, b, a);
2065}
2066
2067
2068bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
2069{
2070 if (a < 255) {
2071 r = MULTIPLY(r, a);
2072 g = MULTIPLY(g, a);
2073 b = MULTIPLY(b, a);
2074 }
2075
2076 return _rasterRle(surface, shape->strokeRle, r, g, b, a);
2077}
2078
2079
2080bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& bbox, uint8_t opacity)
2081{
2082 if (surface->channelSize == sizeof(uint8_t)) {
2083 TVGERR("SW_ENGINE", "Not supported grayscale image!");
2084 return false;
2085 }
2086
2087 //Verify Boundary
2088 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;
2089
2090 //TOOD: switch (image->format)
2091 //TODO: case: _rasterRGBImageMesh()
2092 //TODO: case: _rasterGrayscaleImageMesh()
2093 //TODO: case: _rasterAlphaImageMesh()
2094 if (mesh && mesh->triangleCnt > 0) return _transformedImageMesh(surface, image, mesh, transform, &bbox, opacity);
2095 else return _rasterImage(surface, image, transform, bbox, opacity);
2096}
2097
2098
2099bool rasterConvertCS(Surface* surface, ColorSpace to)
2100{
2101 //TOOD: Support SIMD accelerations
2102 auto from = surface->cs;
2103
2104 if ((from == ColorSpace::ABGR8888 && to == ColorSpace::ARGB8888) || (from == ColorSpace::ABGR8888S && to == ColorSpace::ARGB8888S)) {
2105 surface->cs = to;
2106 return cRasterABGRtoARGB(surface);
2107 }
2108 if ((from == ColorSpace::ARGB8888 && to == ColorSpace::ABGR8888) || (from == ColorSpace::ARGB8888S && to == ColorSpace::ABGR8888S)) {
2109 surface->cs = to;
2110 return cRasterARGBtoABGR(surface);
2111 }
2112
2113 return false;
2114}
2115