2 * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
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:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
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
25 #elif defined(__linux__)
32 #include "tvgRender.h"
33 #include "tvgSwCommon.h"
35 /************************************************************************/
36 /* Internal Class Implementation */
37 /************************************************************************/
38 constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
41 static inline uint32_t _multiplyAlpha(uint32_t c, uint32_t a)
43 return ((c * a + 0xff) >> 8);
47 static inline uint32_t _alpha(uint32_t c)
53 static inline uint32_t _ialpha(uint32_t c)
59 static inline uint32_t _abgrLumaValue(uint32_t c)
61 return ((((c&0xff)*54) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*19))) >> 8; //0.2125*R + 0.7154*G + 0.0721*B
65 static inline uint32_t _argbLumaValue(uint32_t c)
67 return ((((c&0xff)*19) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*54))) >> 8; //0.0721*B + 0.7154*G + 0.2125*R
71 static inline uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
73 return (a << 24 | b << 16 | g << 8 | r);
77 static inline uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
79 return (a << 24 | r << 16 | g << 8 | b);
83 #include "tvgSwRasterTexmap.h"
84 #include "tvgSwRasterC.h"
85 #include "tvgSwRasterAvx.h"
86 #include "tvgSwRasterNeon.h"
89 static inline bool _compositing(const SwSurface* surface)
91 if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false;
96 static inline uint32_t _halfScale(float scale)
98 auto halfScale = static_cast<uint32_t>(0.5f / scale);
99 if (halfScale == 0) halfScale = 1;
103 //Bilinear Interpolation
104 static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, float sx, float sy)
106 auto rx = (uint32_t)(sx);
107 auto ry = (uint32_t)(sy);
109 if (rx2 >= w) rx2 = w - 1;
111 if (ry2 >= h) ry2 = h - 1;
113 auto dx = static_cast<uint32_t>((sx - rx) * 255.0f);
114 auto dy = static_cast<uint32_t>((sy - ry) * 255.0f);
116 auto c1 = img[rx + ry * w];
117 auto c2 = img[rx2 + ry * w];
118 auto c3 = img[rx2 + ry2 * w];
119 auto c4 = img[rx + ry2 * w];
121 return INTERPOLATE(dy, INTERPOLATE(dx, c3, c4), INTERPOLATE(dx, c2, c1));
125 //2n x 2n Mean Kernel
126 static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, uint32_t rx, uint32_t ry, uint32_t n)
128 uint32_t c[4] = {0, 0, 0, 0};
130 auto src = img + rx - n + (ry - n) * stride;
132 for (auto y = ry - n; y < ry + n; ++y) {
133 if (y >= h) continue;
135 for (auto x = rx - n; x < rx + n; ++x, ++p) {
136 if (x >= w) continue;
138 c[1] += (*p >> 16) & 0xff;
139 c[2] += (*p >> 8) & 0xff;
144 for (auto i = 0; i < 4; ++i) {
145 c[i] = (c[i] >> 2) / n2;
147 return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
151 /************************************************************************/
153 /************************************************************************/
155 static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t))
157 TVGLOG("SW_ENGINE", "Masked Rect");
159 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
160 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
161 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
163 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
165 for (uint32_t y = 0; y < h; ++y) {
166 auto dst = &buffer[y * surface->stride];
167 auto cmp = &cbuffer[y * surface->stride];
168 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp) {
169 auto tmp = ALPHA_BLEND(color, blendMethod(*cmp));
170 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
177 static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color)
179 auto buffer = surface->buffer + (region.min.y * surface->stride);
180 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
181 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
183 for (uint32_t y = 0; y < h; ++y) {
184 rasterRGBA32(buffer + y * surface->stride, color, region.min.x, w);
190 static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint8_t opacity)
192 if (_compositing(surface)) {
193 if (surface->compositor->method == CompositeMethod::AlphaMask) {
194 return _rasterMaskedRect(surface, region, color, _alpha);
195 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
196 return _rasterMaskedRect(surface, region, color, _ialpha);
197 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
198 return _rasterMaskedRect(surface, region, color, surface->blender.lumaValue);
201 if (opacity == 255) {
202 return _rasterSolidRect(surface, region, color);
204 #if defined(THORVG_AVX_VECTOR_SUPPORT)
205 return avxRasterTranslucentRect(surface, region, color);
206 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
207 return neonRasterTranslucentRect(surface, region, color);
209 return cRasterTranslucentRect(surface, region, color);
217 /************************************************************************/
219 /************************************************************************/
221 static bool _rasterMaskedRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t))
223 TVGLOG("SW_ENGINE", "Masked Rle");
225 auto span = rle->spans;
227 auto cbuffer = surface->compositor->image.data;
229 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
230 auto dst = &surface->buffer[span->y * surface->stride + span->x];
231 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
232 if (span->coverage == 255) src = color;
233 else src = ALPHA_BLEND(color, span->coverage);
234 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
235 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
236 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
243 static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint32_t color)
245 auto span = rle->spans;
247 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
248 if (span->coverage == 255) {
249 rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len);
251 auto dst = &surface->buffer[span->y * surface->stride + span->x];
252 auto src = ALPHA_BLEND(color, span->coverage);
253 auto ialpha = 255 - span->coverage;
254 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
255 *dst = src + ALPHA_BLEND(*dst, ialpha);
263 static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint8_t opacity)
265 if (!rle) return false;
267 if (_compositing(surface)) {
268 if (surface->compositor->method == CompositeMethod::AlphaMask) {
269 return _rasterMaskedRle(surface, rle, color, _alpha);
270 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
271 return _rasterMaskedRle(surface, rle, color, _ialpha);
272 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
273 return _rasterMaskedRle(surface, rle, color, surface->blender.lumaValue);
276 if (opacity == 255) {
277 return _rasterSolidRle(surface, rle, color);
279 #if defined(THORVG_AVX_VECTOR_SUPPORT)
280 return avxRasterTranslucentRle(surface, rle, color);
281 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
282 return neonRasterTranslucentRle(surface, rle, color);
284 return cRasterTranslucentRle(surface, rle, color);
292 /************************************************************************/
293 /* RLE Transformed RGBA Image */
294 /************************************************************************/
296 static bool _transformedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, uint32_t opacity)
298 if (_compositing(surface)) {
299 if (surface->compositor->method == CompositeMethod::AlphaMask) {
300 return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _alpha);
301 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
302 return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _ialpha);
303 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
304 return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, surface->blender.lumaValue);
307 return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, nullptr);
312 /************************************************************************/
313 /* RLE Scaled RGBA Image */
314 /************************************************************************/
316 static bool _rasterScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
318 TVGLOG("SW_ENGINE", "Scaled Masked Translucent Rle Image");
320 auto span = image->rle->spans;
322 //Center (Down-Scaled)
323 if (image->scale < DOWN_SCALE_TOLERANCE) {
324 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
325 auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
326 if (sy >= image->h) continue;
327 auto dst = &surface->buffer[span->y * surface->stride + span->x];
328 auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
329 auto alpha = _multiplyAlpha(span->coverage, opacity);
330 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
331 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
332 if (sx >= image->w) continue;
333 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
334 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
335 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
340 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
341 auto sy = span->y * itransform->e22 + itransform->e23;
342 if ((uint32_t)sy >= image->h) continue;
343 auto dst = &surface->buffer[span->y * surface->stride + span->x];
344 auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
345 auto alpha = _multiplyAlpha(span->coverage, opacity);
346 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
347 auto sx = x * itransform->e11 + itransform->e13;
348 if ((uint32_t)sx >= image->w) continue;
349 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
350 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
351 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
359 static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
361 TVGLOG("SW_ENGINE", "Scaled Masked Rle Image");
363 auto span = image->rle->spans;
365 //Center (Down-Scaled)
366 if (image->scale < DOWN_SCALE_TOLERANCE) {
367 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
368 auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
369 if (sy >= image->h) continue;
370 auto dst = &surface->buffer[span->y * surface->stride + span->x];
371 auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
372 if (span->coverage == 255) {
373 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
374 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
375 if (sx >= image->w) continue;
376 auto tmp = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
377 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
380 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
381 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
382 if (sx >= image->w) continue;
383 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), span->coverage);
384 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
385 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
391 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
392 auto sy = span->y * itransform->e22 + itransform->e23;
393 if ((uint32_t)sy >= image->h) continue;
394 auto dst = &surface->buffer[span->y * surface->stride + span->x];
395 auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
396 if (span->coverage == 255) {
397 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
398 auto sx = x * itransform->e11 + itransform->e13;
399 if ((uint32_t)sx >= image->w) continue;
400 auto tmp = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
401 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
404 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
405 auto sx = x * itransform->e11 + itransform->e13;
406 if ((uint32_t)sx >= image->w) continue;
407 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
408 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
409 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
418 static bool _rasterScaledTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
420 auto span = image->rle->spans;
422 //Center (Down-Scaled)
423 if (image->scale < DOWN_SCALE_TOLERANCE) {
424 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
425 auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
426 if (sy >= image->h) continue;
427 auto dst = &surface->buffer[span->y * surface->stride + span->x];
428 auto alpha = _multiplyAlpha(span->coverage, opacity);
429 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
430 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
431 if (sx >= image->w) continue;
432 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
433 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
438 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
439 auto sy = span->y * itransform->e22 + itransform->e23;
440 if ((uint32_t)sy >= image->h) continue;
441 auto dst = &surface->buffer[span->y * surface->stride + span->x];
442 auto alpha = _multiplyAlpha(span->coverage, opacity);
443 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
444 auto sx = x * itransform->e11 + itransform->e13;
445 if ((uint32_t)sx >= image->w) continue;
446 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
447 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
455 static bool _rasterScaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
457 auto span = image->rle->spans;
459 //Center (Down-Scaled)
460 if (image->scale < DOWN_SCALE_TOLERANCE) {
461 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
462 auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
463 if (sy >= image->h) continue;
464 auto dst = &surface->buffer[span->y * surface->stride + span->x];
465 if (span->coverage == 255) {
466 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
467 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
468 if (sx >= image->w) continue;
469 auto src = _interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale);
470 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
473 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
474 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
475 if (sx >= image->w) continue;
476 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), span->coverage);
477 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
483 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
484 auto sy = span->y * itransform->e22 + itransform->e23;
485 if ((uint32_t)sy >= image->h) continue;
486 auto dst = &surface->buffer[span->y * surface->stride + span->x];
487 if (span->coverage == 255) {
488 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
489 auto sx = x * itransform->e11 + itransform->e13;
490 if ((uint32_t)sx >= image->w) continue;
491 auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
492 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
495 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
496 auto sx = x * itransform->e11 + itransform->e13;
497 if ((uint32_t)sx >= image->w) continue;
498 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
499 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
508 static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
513 if (!mathInverse(transform, &itransform)) return false;
514 } else mathIdentity(&itransform);
516 auto halfScale = _halfScale(image->scale);
518 if (_compositing(surface)) {
519 if (opacity == 255) {
520 if (surface->compositor->method == CompositeMethod::AlphaMask) {
521 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _alpha);
522 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
523 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
524 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
525 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
528 if (surface->compositor->method == CompositeMethod::AlphaMask) {
529 return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha);
530 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
531 return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
532 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
533 return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
537 if (opacity == 255) return _rasterScaledRleRGBAImage(surface, image, &itransform, region, opacity, halfScale);
538 else return _rasterScaledTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale);
544 /************************************************************************/
545 /* RLE Direct RGBA Image */
546 /************************************************************************/
548 static bool _rasterDirectMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
550 TVGLOG("SW_ENGINE", "Direct Masked Rle Image");
552 auto span = image->rle->spans;
553 auto cbuffer = surface->compositor->image.data;
555 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
556 auto dst = &surface->buffer[span->y * surface->stride + span->x];
557 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
558 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
559 auto alpha = _multiplyAlpha(span->coverage, opacity);
561 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
562 auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp));
563 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
566 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
567 auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(alpha, blendMethod(*cmp)));
568 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
576 static bool _rasterDirectMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t (*blendMethod)(uint32_t))
578 TVGLOG("SW_ENGINE", "Direct Masked Rle Image");
580 auto span = image->rle->spans;
581 auto cbuffer = surface->compositor->image.data;
583 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
584 auto dst = &surface->buffer[span->y * surface->stride + span->x];
585 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
586 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
587 if (span->coverage == 255) {
588 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
589 auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp));
590 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
593 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
594 auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(span->coverage, blendMethod(*cmp)));
595 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
603 static bool _rasterDirectTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity)
605 auto span = image->rle->spans;
607 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
608 auto dst = &surface->buffer[span->y * surface->stride + span->x];
609 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
610 auto alpha = _multiplyAlpha(span->coverage, opacity);
611 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
612 auto src = ALPHA_BLEND(*img, alpha);
613 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
620 static bool _rasterDirectRleRGBAImage(SwSurface* surface, const SwImage* image)
622 auto span = image->rle->spans;
624 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
625 auto dst = &surface->buffer[span->y * surface->stride + span->x];
626 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
627 if (span->coverage == 255) {
628 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
629 *dst = *img + ALPHA_BLEND(*dst, _ialpha(*img));
632 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
633 auto src = ALPHA_BLEND(*img, span->coverage);
634 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
642 static bool _directRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity)
644 if (_compositing(surface)) {
645 if (opacity == 255) {
646 if (surface->compositor->method == CompositeMethod::AlphaMask) {
647 return _rasterDirectMaskedRleRGBAImage(surface, image, _alpha);
648 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
649 return _rasterDirectMaskedRleRGBAImage(surface, image, _ialpha);
650 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
651 return _rasterDirectMaskedRleRGBAImage(surface, image, surface->blender.lumaValue);
654 if (surface->compositor->method == CompositeMethod::AlphaMask) {
655 return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _alpha);
656 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
657 return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _ialpha);
658 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
659 return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, surface->blender.lumaValue);
663 if (opacity == 255) return _rasterDirectRleRGBAImage(surface, image);
664 else return _rasterDirectTranslucentRleRGBAImage(surface, image, opacity);
670 /************************************************************************/
671 /* Transformed RGBA Image */
672 /************************************************************************/
674 static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
676 if (_compositing(surface)) {
677 if (surface->compositor->method == CompositeMethod::AlphaMask) {
678 return _rasterTexmapPolygon(surface, image, transform, ®ion, opacity, _alpha);
679 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
680 return _rasterTexmapPolygon(surface, image, transform, ®ion, opacity, _ialpha);
681 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
682 return _rasterTexmapPolygon(surface, image, transform, ®ion, opacity, surface->blender.lumaValue);
685 return _rasterTexmapPolygon(surface, image, transform, ®ion, opacity, nullptr);
690 static bool _transformedRGBAImageMesh(SwSurface* surface, const SwImage* image, const Polygon* triangles, const uint32_t count, const Matrix* transform, const SwBBox* region, uint32_t opacity)
692 if (_compositing(surface)) {
693 if (surface->compositor->method == CompositeMethod::AlphaMask) {
694 return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, _alpha);
695 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
696 return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, _ialpha);
697 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
698 return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, surface->blender.lumaValue);
701 return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, nullptr);
707 /************************************************************************/
708 /*Scaled RGBA Image */
709 /************************************************************************/
712 static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
714 TVGLOG("SW_ENGINE", "Scaled Masked Image");
716 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
717 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x);
720 if (image->scale < DOWN_SCALE_TOLERANCE) {
721 for (auto y = region.min.y; y < region.max.y; ++y) {
722 auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
723 if (sy >= image->h) continue;
726 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
727 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
728 if (sx >= image->w) continue;
729 auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp));
730 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
731 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
733 dbuffer += surface->stride;
734 cbuffer += surface->compositor->image.stride;
738 for (auto y = region.min.y; y < region.max.y; ++y) {
739 auto sy = y * itransform->e22 + itransform->e23;
740 if ((uint32_t)sy >= image->h) continue;
743 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
744 auto sx = x * itransform->e11 + itransform->e13;
745 if ((uint32_t)sx >= image->w) continue;
746 auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp));
747 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
748 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
750 dbuffer += surface->stride;
751 cbuffer += surface->compositor->image.stride;
758 static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
760 TVGLOG("SW_ENGINE", "Scaled Masked Image");
762 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
763 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x);
766 if (image->scale < DOWN_SCALE_TOLERANCE) {
767 for (auto y = region.min.y; y < region.max.y; ++y) {
768 auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
769 if (sy >= image->h) continue;
772 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
773 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
774 if (sx >= image->w) continue;
775 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
776 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
778 dbuffer += surface->stride;
779 cbuffer += surface->compositor->image.stride;
783 for (auto y = region.min.y; y < region.max.y; ++y) {
784 auto sy = y * itransform->e22 + itransform->e23;
785 if ((uint32_t)sy >= image->h) continue;
788 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
789 auto sx = x * itransform->e11 + itransform->e13;
790 if ((uint32_t)sx >= image->w) continue;
791 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
792 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
794 dbuffer += surface->stride;
795 cbuffer += surface->compositor->image.stride;
802 static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
804 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
807 if (image->scale < DOWN_SCALE_TOLERANCE) {
808 for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
809 auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
810 if (sy >= image->h) continue;
812 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
813 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
814 if (sx >= image->w) continue;
815 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), opacity);
816 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
821 for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
822 auto sy = fabsf(y * itransform->e22 + itransform->e23);
823 if (sy >= image->h) continue;
825 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
826 auto sx = x * itransform->e11 + itransform->e13;
827 if ((uint32_t)sx >= image->w) continue;
828 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), opacity);
829 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
837 static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale)
839 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
842 if (image->scale < DOWN_SCALE_TOLERANCE) {
843 for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
844 auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
845 if (sy >= image->h) continue;
847 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
848 auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
849 if (sx >= image->w) continue;
850 auto src = _interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale);
851 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
856 for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
857 auto sy = y * itransform->e22 + itransform->e23;
858 if ((uint32_t)sy >= image->h) continue;
860 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
861 auto sx = x * itransform->e11 + itransform->e13;
862 if ((uint32_t)sx >= image->w) continue;
863 auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
864 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
872 static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
877 if (!mathInverse(transform, &itransform)) return false;
878 } else mathIdentity(&itransform);
880 auto halfScale = _halfScale(image->scale);
882 if (_compositing(surface)) {
883 if (opacity == 255) {
884 if (surface->compositor->method == CompositeMethod::AlphaMask) {
885 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _alpha);
886 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
887 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
888 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
889 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
892 if (surface->compositor->method == CompositeMethod::AlphaMask) {
893 return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha);
894 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
895 return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
896 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
897 return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
901 if (opacity == 255) return _rasterScaledRGBAImage(surface, image, &itransform, region, halfScale);
902 else return _rasterScaledTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale);
908 /************************************************************************/
909 /* Direct RGBA Image */
910 /************************************************************************/
912 static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t (*blendMethod)(uint32_t))
914 TVGLOG("SW_ENGINE", "Direct Masked Image");
916 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
917 auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
918 auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
920 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
921 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
923 for (uint32_t y = 0; y < h2; ++y) {
927 for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
928 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
929 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
931 buffer += surface->stride;
932 cbuffer += surface->compositor->image.stride;
933 sbuffer += image->stride;
939 static bool _rasterDirectMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
941 TVGLOG("SW_ENGINE", "Direct Masked Translucent Image");
943 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
944 auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
945 auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
947 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
948 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
950 for (uint32_t y = 0; y < h2; ++y) {
954 for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
955 auto tmp = ALPHA_BLEND(*src, _multiplyAlpha(opacity, blendMethod(*cmp)));
956 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
958 buffer += surface->stride;
959 cbuffer += surface->compositor->image.stride;
960 sbuffer += image->stride;
966 static bool _rasterDirectTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity)
968 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
969 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
971 for (auto y = region.min.y; y < region.max.y; ++y) {
974 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
975 auto tmp = ALPHA_BLEND(*src, opacity);
976 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
978 dbuffer += surface->stride;
979 sbuffer += image->stride;
985 static bool _rasterDirectRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region)
987 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
988 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
990 for (auto y = region.min.y; y < region.max.y; ++y) {
993 for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
994 *dst = *src + ALPHA_BLEND(*dst, _ialpha(*src));
996 dbuffer += surface->stride;
997 sbuffer += image->stride;
1003 //Blenders for the following scenarios: [Composition / Non-Composition] * [Opaque / Translucent]
1004 static bool _directRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity)
1006 if (_compositing(surface)) {
1007 if (opacity == 255) {
1008 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1009 return _rasterDirectMaskedRGBAImage(surface, image, region, _alpha);
1010 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1011 return _rasterDirectMaskedRGBAImage(surface, image, region, _ialpha);
1012 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1013 return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.lumaValue);
1016 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1017 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _alpha);
1018 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1019 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _ialpha);
1020 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1021 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.lumaValue);
1025 if (opacity == 255) return _rasterDirectRGBAImage(surface, image, region);
1026 else return _rasterDirectTranslucentRGBAImage(surface, image, region, opacity);
1032 //Blenders for the following scenarios: [RLE / Whole] * [Direct / Scaled / Transformed]
1033 static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
1037 if (image->direct) return _directRleRGBAImage(surface, image, opacity);
1038 else if (image->scaled) return _scaledRleRGBAImage(surface, image, transform, region, opacity);
1039 else return _transformedRleRGBAImage(surface, image, transform, opacity);
1042 if (image->direct) return _directRGBAImage(surface, image, region, opacity);
1043 else if (image->scaled) return _scaledRGBAImage(surface, image, transform, region, opacity);
1044 else return _transformedRGBAImage(surface, image, transform, region, opacity);
1049 /************************************************************************/
1050 /* Rect Linear Gradient */
1051 /************************************************************************/
1053 static bool _rasterLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1055 if (fill->linear.len < FLT_EPSILON) return false;
1057 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1058 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1059 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1060 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;
1062 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1063 if (!sbuffer) return false;
1065 for (uint32_t y = 0; y < h; ++y) {
1066 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1070 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1071 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1072 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1074 buffer += surface->stride;
1075 cbuffer += surface->stride;
1081 static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1083 if (fill->linear.len < FLT_EPSILON) return false;
1085 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1086 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1087 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1089 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1090 if (!sbuffer) return false;
1092 for (uint32_t y = 0; y < h; ++y) {
1094 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1095 for (uint32_t x = 0; x < w; ++x, ++dst) {
1096 *dst = sbuffer[x] + ALPHA_BLEND(*dst, _ialpha(sbuffer[x]));
1098 buffer += surface->stride;
1104 static bool _rasterSolidLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1106 if (fill->linear.len < FLT_EPSILON) return false;
1108 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1109 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1110 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1112 for (uint32_t y = 0; y < h; ++y) {
1113 fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w);
1119 static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1121 if (_compositing(surface)) {
1122 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1123 return _rasterLinearGradientMaskedRect(surface, region, fill, _alpha);
1124 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1125 return _rasterLinearGradientMaskedRect(surface, region, fill, _ialpha);
1126 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1127 return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
1130 if (fill->translucent) return _rasterTranslucentLinearGradientRect(surface, region, fill);
1131 else _rasterSolidLinearGradientRect(surface, region, fill);
1137 /************************************************************************/
1138 /* Rle Linear Gradient */
1139 /************************************************************************/
1141 static bool _rasterLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1143 if (fill->linear.len < FLT_EPSILON) return false;
1145 auto span = rle->spans;
1146 auto cbuffer = surface->compositor->image.data;
1147 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1148 if (!buffer) return false;
1150 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1151 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1152 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1153 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
1155 if (span->coverage == 255) {
1156 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1157 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1158 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1161 auto ialpha = 255 - span->coverage;
1162 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1163 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1164 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1165 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1173 static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1175 if (fill->linear.len < FLT_EPSILON) return false;
1177 auto span = rle->spans;
1178 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1179 if (!buffer) return false;
1181 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1182 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1183 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1184 if (span->coverage == 255) {
1185 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
1186 *dst = buffer[x] + ALPHA_BLEND(*dst, _ialpha(buffer[x]));
1189 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
1190 auto tmp = ALPHA_BLEND(buffer[x], span->coverage);
1191 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1199 static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1201 if (fill->linear.len < FLT_EPSILON) return false;
1203 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1204 if (!buf) return false;
1206 auto span = rle->spans;
1208 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1209 if (span->coverage == 255) {
1210 fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len);
1212 fillFetchLinear(fill, buf, span->y, span->x, span->len);
1213 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1214 for (uint32_t x = 0; x < span->len; ++x) {
1215 dst[x] = INTERPOLATE(span->coverage, buf[x], dst[x]);
1223 static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1225 if (!rle) return false;
1227 if (_compositing(surface)) {
1228 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1229 return _rasterLinearGradientMaskedRle(surface, rle, fill, _alpha);
1230 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1231 return _rasterLinearGradientMaskedRle(surface, rle, fill, _ialpha);
1232 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1233 return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
1236 if (fill->translucent) return _rasterTranslucentLinearGradientRle(surface, rle, fill);
1237 else return _rasterSolidLinearGradientRle(surface, rle, fill);
1243 /************************************************************************/
1244 /* Rect Radial Gradient */
1245 /************************************************************************/
1247 static bool _rasterRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1249 if (fill->radial.a < FLT_EPSILON) return false;
1251 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1252 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1253 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1254 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;
1256 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1257 if (!sbuffer) return false;
1259 for (uint32_t y = 0; y < h; ++y) {
1260 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1264 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1265 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1266 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1268 buffer += surface->stride;
1269 cbuffer += surface->stride;
1275 static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1277 if (fill->radial.a < FLT_EPSILON) return false;
1279 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1280 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1281 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1283 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1284 if (!sbuffer) return false;
1286 for (uint32_t y = 0; y < h; ++y) {
1288 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1289 for (uint32_t x = 0; x < w; ++x, ++dst) {
1290 *dst = sbuffer[x] + ALPHA_BLEND(*dst, _ialpha(sbuffer[x]));
1292 buffer += surface->stride;
1298 static bool _rasterSolidRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1300 if (fill->radial.a < FLT_EPSILON) return false;
1302 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1303 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1304 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1306 for (uint32_t y = 0; y < h; ++y) {
1307 auto dst = &buffer[y * surface->stride];
1308 fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w);
1314 static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1316 if (_compositing(surface)) {
1317 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1318 return _rasterRadialGradientMaskedRect(surface, region, fill, _alpha);
1319 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1320 return _rasterRadialGradientMaskedRect(surface, region, fill, _ialpha);
1321 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1322 return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
1325 if (fill->translucent) return _rasterTranslucentRadialGradientRect(surface, region, fill);
1326 else return _rasterSolidRadialGradientRect(surface, region, fill);
1332 /************************************************************************/
1333 /* RLE Radial Gradient */
1334 /************************************************************************/
1336 static bool _rasterRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1338 if (fill->radial.a < FLT_EPSILON) return false;
1340 auto span = rle->spans;
1341 auto cbuffer = surface->compositor->image.data;
1342 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1343 if (!buffer) return false;
1345 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1346 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1347 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1348 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
1350 if (span->coverage == 255) {
1351 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1352 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1353 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1356 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1357 auto tmp = INTERPOLATE(span->coverage, ALPHA_BLEND(*src, blendMethod(*cmp)), *dst);
1358 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1366 static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1368 if (fill->radial.a < FLT_EPSILON) return false;
1370 auto span = rle->spans;
1371 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1372 if (!buffer) return false;
1374 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1375 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1376 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1377 if (span->coverage == 255) {
1378 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
1379 *dst = buffer[x] + ALPHA_BLEND(*dst, _ialpha(buffer[x]));
1382 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
1383 auto tmp = ALPHA_BLEND(buffer[x], span->coverage);
1384 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
1392 static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1394 if (fill->radial.a < FLT_EPSILON) return false;
1396 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1397 if (!buf) return false;
1399 auto span = rle->spans;
1401 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1402 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1403 if (span->coverage == 255) {
1404 fillFetchRadial(fill, dst, span->y, span->x, span->len);
1406 fillFetchRadial(fill, buf, span->y, span->x, span->len);
1407 auto ialpha = 255 - span->coverage;
1408 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
1409 *dst = ALPHA_BLEND(buf[x], span->coverage) + ALPHA_BLEND(*dst, ialpha);
1417 static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1419 if (!rle) return false;
1421 if (_compositing(surface)) {
1422 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1423 return _rasterRadialGradientMaskedRle(surface, rle, fill, _alpha);
1424 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1425 return _rasterRadialGradientMaskedRle(surface, rle, fill, _ialpha);
1426 } else if (surface->compositor->method == CompositeMethod::LumaMask) {
1427 return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
1430 if (fill->translucent) _rasterTranslucentRadialGradientRle(surface, rle, fill);
1431 else return _rasterSolidRadialGradientRle(surface, rle, fill);
1437 /************************************************************************/
1438 /* External Class Implementation */
1439 /************************************************************************/
1441 void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
1443 #if defined(THORVG_AVX_VECTOR_SUPPORT)
1444 avxRasterRGBA32(dst, val, offset, len);
1445 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
1446 neonRasterRGBA32(dst, val, offset, len);
1448 cRasterRGBA32(dst, val, offset, len);
1453 bool rasterCompositor(SwSurface* surface)
1455 if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
1456 surface->blender.join = _abgrJoin;
1457 surface->blender.lumaValue = _abgrLumaValue;
1458 } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
1459 surface->blender.join = _argbJoin;
1460 surface->blender.lumaValue = _argbLumaValue;
1462 //What Color Space ???
1469 bool rasterClear(SwSurface* surface)
1471 if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false;
1473 if (surface->w == surface->stride) {
1474 rasterRGBA32(surface->buffer, 0x00000000, 0, surface->w * surface->h);
1476 for (uint32_t i = 0; i < surface->h; i++) {
1477 rasterRGBA32(surface->buffer + surface->stride * i, 0x00000000, 0, surface->w);
1484 void rasterUnpremultiply(SwSurface* surface)
1486 //OPTIMIZE_ME: +SIMD
1487 for (uint32_t y = 0; y < surface->h; y++) {
1488 auto buffer = surface->buffer + surface->stride * y;
1489 for (uint32_t x = 0; x < surface->w; ++x) {
1490 uint8_t a = buffer[x] >> 24;
1493 } else if (a == 0) {
1494 buffer[x] = 0x00ffffff;
1496 uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
1497 uint16_t g = ((buffer[x]) & 0xff00) / a;
1498 uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
1499 if (r > 0xff) r = 0xff;
1500 if (g > 0xff) g = 0xff;
1501 if (b > 0xff) b = 0xff;
1502 buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
1509 bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
1511 if (!shape->fill) return false;
1513 if (shape->fastTrack) {
1514 if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill);
1515 else if (id == TVG_CLASS_ID_RADIAL)return _rasterRadialGradientRect(surface, shape->bbox, shape->fill);
1517 if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->rle, shape->fill);
1518 else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->rle, shape->fill);
1524 bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
1526 if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
1528 if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1529 else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1535 bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1538 r = _multiplyAlpha(r, a);
1539 g = _multiplyAlpha(g, a);
1540 b = _multiplyAlpha(b, a);
1543 auto color = surface->blender.join(r, g, b, a);
1545 if (shape->fastTrack) return _rasterRect(surface, shape->bbox, color, a);
1546 else return _rasterRle(surface, shape->rle, color, a);
1550 bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1553 r = _multiplyAlpha(r, a);
1554 g = _multiplyAlpha(g, a);
1555 b = _multiplyAlpha(b, a);
1558 auto color = surface->blender.join(r, g, b, a);
1560 return _rasterRle(surface, shape->strokeRle, color, a);
1564 bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
1567 if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= static_cast<SwCoord>(surface->w) || bbox.min.y >= static_cast<SwCoord>(surface->h)) return false;
1569 //TOOD: switch (image->format)
1570 //TODO: case: _rasterRGBImage()
1571 //TODO: case: _rasterGrayscaleImage()
1572 //TODO: case: _rasterAlphaImage()
1573 return _rasterRGBAImage(surface, image, transform, bbox, opacity);
1576 bool rasterImageMesh(SwSurface* surface, SwImage* image, const Polygon* triangles, const uint32_t count, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
1579 if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= static_cast<SwCoord>(surface->w) || bbox.min.y >= static_cast<SwCoord>(surface->h)) return false;
1581 //TOOD: switch (image->format)
1582 //TODO: case: _rasterRGBImageMesh()
1583 //TODO: case: _rasterGrayscaleImageMesh()
1584 //TODO: case: _rasterAlphaImageMesh()
1585 return _transformedRGBAImageMesh(surface, image, triangles, count, transform, &bbox, opacity);