2 * Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. 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
23 #include "tvgRender.h"
24 #include "tvgSwCommon.h"
25 #include "tvgSwRasterC.h"
26 #include "tvgSwRasterAvx.h"
27 #include "tvgSwRasterNeon.h"
29 /************************************************************************/
30 /* Internal Class Implementation */
31 /************************************************************************/
32 constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
35 static inline uint32_t _multiplyAlpha(uint32_t c, uint32_t a)
37 return ((c * a + 0xff) >> 8);
41 static uint32_t _colorAlpha(uint32_t c)
47 static uint32_t _colorInvAlpha(uint32_t c)
53 static uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
55 return (a << 24 | b << 16 | g << 8 | r);
59 static uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
61 return (a << 24 | r << 16 | g << 8 | b);
65 static bool _translucent(const SwSurface* surface, uint8_t a)
67 if (a < 255) return true;
68 if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false;
73 //Bilinear Interpolation
74 static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, float sx, float sy)
76 auto rx = static_cast<uint32_t>(sx);
77 auto ry = static_cast<uint32_t>(sy);
79 auto dx = static_cast<uint32_t>((sx - rx) * 255.0f);
80 auto dy = static_cast<uint32_t>((sy - ry) * 255.0f);
82 auto c1 = img[rx + (ry * w)];
83 auto c2 = img[(rx + 1) + (ry * w)];
84 auto c3 = img[(rx + 1) + ((ry + 1) * w)];
85 auto c4 = img[rx + ((ry + 1) * w)];
87 return COLOR_INTERPOLATE(COLOR_INTERPOLATE(c1, 255 - dx, c2, dx), 255 - dy, COLOR_INTERPOLATE(c4, 255 - dx, c3, dx), dy);
92 static uint32_t _interpDownScaler(const uint32_t *img, uint32_t w, uint32_t h, uint32_t rX, uint32_t rY, uint32_t n)
94 uint32_t c[4] = { 0 };
96 auto src = img + rX - n + (rY - n) * w;
97 for (auto y = rY - n; y < rY + n; ++y) {
99 for (auto x = rX - n; x < rX + n; ++x, ++p) {
101 c[1] += (*p >> 16) & 0xff;
102 c[2] += (*p >> 8) & 0xff;
107 for (auto i = 0; i < 4; ++i) {
108 c[i] = (c[i] >> 2) / n2;
110 return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
114 /************************************************************************/
116 /************************************************************************/
118 static bool _rasterTranslucentMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t))
120 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
121 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
122 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
124 TVGLOG("SW_ENGINE", "Translucent Masked Rect");
126 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
128 for (uint32_t y = 0; y < h; ++y) {
129 auto dst = &buffer[y * surface->stride];
130 auto cmp = &cbuffer[y * surface->stride];
131 for (uint32_t x = 0; x < w; ++x) {
132 auto tmp = ALPHA_BLEND(color, blendMethod(*cmp));
133 dst[x] = tmp + ALPHA_BLEND(dst[x], surface->blender.ialpha(tmp));
140 static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color)
142 if (surface->compositor) {
143 if (surface->compositor->method == CompositeMethod::AlphaMask) {
144 return _rasterTranslucentMaskedRect(surface, region, color, surface->blender.alpha);
146 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
147 return _rasterTranslucentMaskedRect(surface, region, color, surface->blender.ialpha);
151 #if defined(THORVG_AVX_VECTOR_SUPPORT)
152 return avxRasterTranslucentRect(surface, region, color);
153 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
154 return neonRasterTranslucentRect(surface, region, color);
156 return cRasterTranslucentRect(surface, region, color);
161 static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color)
163 auto buffer = surface->buffer + (region.min.y * surface->stride);
164 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
165 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
167 for (uint32_t y = 0; y < h; ++y) {
168 rasterRGBA32(buffer + y * surface->stride, color, region.min.x, w);
174 /************************************************************************/
176 /************************************************************************/
178 static bool _rasterTranslucentMaskedRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t))
180 TVGLOG("SW_ENGINE", "Translucent Masked Rle");
182 auto span = rle->spans;
184 auto cbuffer = surface->compositor->image.data;
186 for (uint32_t i = 0; i < rle->size; ++i) {
187 auto dst = &surface->buffer[span->y * surface->stride + span->x];
188 auto cmp = &cbuffer[span->y * surface->stride + span->x];
189 if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
191 for (uint32_t x = 0; x < span->len; ++x) {
192 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
193 dst[x] = tmp + ALPHA_BLEND(dst[x], surface->blender.ialpha(tmp));
201 static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t color)
203 if (!rle) return false;
205 if (surface->compositor) {
206 if (surface->compositor->method == CompositeMethod::AlphaMask) {
207 return _rasterTranslucentMaskedRle(surface, rle, color, surface->blender.alpha);
209 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
210 return _rasterTranslucentMaskedRle(surface, rle, color, surface->blender.ialpha);
214 #if defined(THORVG_AVX_VECTOR_SUPPORT)
215 return avxRasterTranslucentRle(surface, rle, color);
216 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
217 return neonRasterTranslucentRle(surface, rle, color);
219 return cRasterTranslucentRle(surface, rle, color);
224 static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint32_t color)
226 if (!rle) return false;
228 auto span = rle->spans;
230 for (uint32_t i = 0; i < rle->size; ++i) {
231 if (span->coverage == 255) {
232 rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len);
234 auto dst = &surface->buffer[span->y * surface->stride + span->x];
235 auto src = ALPHA_BLEND(color, span->coverage);
236 auto ialpha = 255 - span->coverage;
237 for (uint32_t i = 0; i < span->len; ++i) {
238 dst[i] = src + ALPHA_BLEND(dst[i], ialpha);
247 /************************************************************************/
248 /* RLE Transformed Translucent Image */
249 /************************************************************************/
251 static bool _rasterTransformedMaskedRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t))
253 TVGLOG("SW_ENGINE", "Transformed Masked Rle Image");
255 auto span = image->rle->spans;
256 auto img = image->data;
259 auto cbuffer = surface->compositor->image.data;
261 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
262 auto ey1 = span->y * itransform->e12 + itransform->e13;
263 auto ey2 = span->y * itransform->e22 + itransform->e23;
264 auto dst = &surface->buffer[span->y * surface->stride + span->x];
265 auto cmp = &cbuffer[span->y * surface->stride + span->x];
266 auto alpha = _multiplyAlpha(span->coverage, opacity);
268 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
269 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
270 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
271 if (rX >= w || rY >= h) continue;
272 auto tmp = ALPHA_BLEND(img[rY * image->stride + rX], blendMethod(*cmp));
273 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
276 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
277 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
278 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
279 if (rX >= w || rY >= h) continue;
280 auto src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
281 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
282 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
290 static bool _rasterTransformedTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform)
292 auto span = image->rle->spans;
293 auto img = image->data;
297 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
298 auto ey1 = span->y * itransform->e12 + itransform->e13;
299 auto ey2 = span->y * itransform->e22 + itransform->e23;
300 auto dst = &surface->buffer[span->y * surface->stride + span->x];
301 auto alpha = _multiplyAlpha(span->coverage, opacity);
302 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
303 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
304 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
305 if (rX >= w || rY >= h) continue;
306 auto src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
307 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
314 static bool _rasterDownScaledMaskedRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
316 TVGLOG("SW_ENGINE", "Down Scaled Masked Rle Image");
318 auto span = image->rle->spans;
319 auto img = image->data;
322 auto cbuffer = surface->compositor->image.data;
324 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
325 auto ey1 = span->y * itransform->e12 + itransform->e13;
326 auto ey2 = span->y * itransform->e22 + itransform->e23;
327 auto dst = &surface->buffer[span->y * surface->stride + span->x];
328 auto cmp = &cbuffer[span->y * surface->stride + span->x];
329 auto alpha = _multiplyAlpha(span->coverage, opacity);
332 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
333 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
334 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
335 if (rX >= w || rY >= h) continue;
337 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
338 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), alpha);
339 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
340 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
343 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
344 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
345 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
346 if (rX >= w || rY >= h) continue;
348 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
349 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), alpha);
350 auto tmp = ALPHA_BLEND(src, _multiplyAlpha(alpha, blendMethod(*cmp)));
351 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
359 static bool _rasterDownScaledTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t halfScale)
361 auto span = image->rle->spans;
362 auto img = image->data;
366 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
367 auto ey1 = span->y * itransform->e12 + itransform->e13;
368 auto ey2 = span->y * itransform->e22 + itransform->e23;
369 auto dst = &surface->buffer[span->y * surface->stride + span->x];
370 auto alpha = _multiplyAlpha(span->coverage, opacity);
371 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
372 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
373 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
374 if (rX >= w || rY >= h) continue;
376 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
377 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), alpha);
378 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
385 static bool _rasterUpScaledMaskedRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t))
387 TVGLOG("SW_ENGINE", "Up Scaled Masked Rle Image");
389 auto span = image->rle->spans;
390 auto img = image->data;
393 auto cbuffer = surface->compositor->image.data;
395 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
396 auto ey1 = span->y * itransform->e12 + itransform->e13;
397 auto ey2 = span->y * itransform->e22 + itransform->e23;
398 auto dst = &surface->buffer[span->y * surface->stride + span->x];
399 auto cmp = &cbuffer[span->y * surface->stride + span->x];
400 auto alpha = _multiplyAlpha(span->coverage, opacity);
402 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
403 auto fX = (span->x + x) * itransform->e11 + ey1;
404 auto fY = (span->x + x) * itransform->e21 + ey2;
405 auto rX = static_cast<uint32_t>(roundf(fX));
406 auto rY = static_cast<uint32_t>(roundf(fY));
407 if (rX >= w || rY >= h) continue;
409 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
410 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), alpha);
411 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
412 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
415 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
416 auto fX = (span->x + x) * itransform->e11 + ey1;
417 auto fY = (span->x + x) * itransform->e21 + ey2;
418 auto rX = static_cast<uint32_t>(roundf(fX));
419 auto rY = static_cast<uint32_t>(roundf(fY));
420 if (rX >= w || rY >= h) continue;
422 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
423 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), alpha);
424 auto tmp = ALPHA_BLEND(src, _multiplyAlpha(alpha, blendMethod(*cmp)));
425 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
433 static bool _rasterUpScaledTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform)
435 auto span = image->rle->spans;
436 auto img = image->data;
440 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
441 auto ey1 = span->y * itransform->e12 + itransform->e13;
442 auto ey2 = span->y * itransform->e22 + itransform->e23;
443 auto dst = &surface->buffer[span->y * surface->stride + span->x];
444 auto alpha = _multiplyAlpha(span->coverage, opacity);
445 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
446 auto fX = (span->x + x) * itransform->e11 + ey1;
447 auto fY = (span->x + x) * itransform->e21 + ey2;
448 auto rX = static_cast<uint32_t>(roundf(fX));
449 auto rY = static_cast<uint32_t>(roundf(fY));
450 if (rX >= w || rY >= h) continue;
452 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
453 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), alpha);
454 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
461 static bool _rasterTransformedTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t halfScale)
464 if (mathEqual(image->scale, 1.0f)) {
465 if (surface->compositor) {
466 if (surface->compositor->method == CompositeMethod::AlphaMask) {
467 return _rasterTransformedMaskedRleImage(surface, image, opacity, itransform, surface->blender.alpha);
468 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
469 return _rasterTransformedMaskedRleImage(surface, image, opacity, itransform, surface->blender.ialpha);
472 return _rasterTransformedTranslucentRleImage(surface, image, opacity, itransform);
473 //Transformed + Down Scaled
474 } else if (image->scale < DOWN_SCALE_TOLERANCE) {
475 if (surface->compositor) {
476 if (surface->compositor->method == CompositeMethod::AlphaMask) {
477 return _rasterDownScaledMaskedRleImage(surface, image, opacity, itransform, halfScale, surface->blender.alpha);
478 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
479 return _rasterDownScaledMaskedRleImage(surface, image, opacity, itransform, halfScale, surface->blender.ialpha);
482 return _rasterDownScaledTranslucentRleImage(surface, image, opacity, itransform, halfScale);
483 //Transformed + Up Scaled
485 if (surface->compositor) {
486 if (surface->compositor->method == CompositeMethod::AlphaMask) {
487 return _rasterUpScaledMaskedRleImage(surface, image, opacity, itransform, surface->blender.alpha);
488 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
489 return _rasterUpScaledMaskedRleImage(surface, image, opacity, itransform, surface->blender.ialpha);
492 return _rasterUpScaledTranslucentRleImage(surface, image, opacity, itransform);
497 /************************************************************************/
498 /* RLE Transformed Solid Image */
499 /************************************************************************/
501 static bool _rasterSolidRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform)
503 auto span = image->rle->spans;
504 auto img = image->data;
508 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
509 auto ey1 = span->y * itransform->e12 + itransform->e13;
510 auto ey2 = span->y * itransform->e22 + itransform->e23;
511 auto dst = &surface->buffer[span->y * surface->stride + span->x];
513 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
514 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
515 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
516 if (rX >= w || rY >= h) continue;
517 auto src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage);
518 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
525 static bool _rasterDownScaledSolidRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t halfScale)
527 auto span = image->rle->spans;
528 auto img = image->data;
532 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
533 auto ey1 = span->y * itransform->e12 + itransform->e13;
534 auto ey2 = span->y * itransform->e22 + itransform->e23;
535 auto dst = &surface->buffer[span->y * surface->stride + span->x];
536 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
537 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
538 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
539 if (rX >= w || rY >= h) continue;
542 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage);
543 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), span->coverage);
544 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
551 static bool _rasterUpScaledSolidRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform)
553 auto span = image->rle->spans;
554 auto img = image->data;
558 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
559 auto ey1 = span->y * itransform->e12 + itransform->e13;
560 auto ey2 = span->y * itransform->e22 + itransform->e23;
561 auto dst = &surface->buffer[span->y * surface->stride + span->x];
562 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
563 auto fX = (span->x + x) * itransform->e11 + ey1;
564 auto fY = (span->x + x) * itransform->e21 + ey2;
565 auto rX = static_cast<uint32_t>(roundf(fX));
566 auto rY = static_cast<uint32_t>(roundf(fY));
567 if (rX >= w || rY >= h) continue;
569 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage);
570 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), span->coverage);
571 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
578 static bool _rasterTransformedSolidRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t halfScale)
580 if (mathEqual(image->scale, 1.0f)) return _rasterSolidRleImage(surface, image, itransform);
581 else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledSolidRleImage(surface, image, itransform, halfScale);
582 else return _rasterUpScaledSolidRleImage(surface, image, itransform);
586 /************************************************************************/
587 /* RLE Direct (Solid + Translucent) Image */
588 /************************************************************************/
590 static bool _rasterDirectMaskedRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
592 TVGLOG("SW_ENGINE", "Direct Masked Rle Image");
594 auto span = image->rle->spans;
595 auto cbuffer = surface->compositor->image.data;
597 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
598 auto dst = &surface->buffer[span->y * surface->stride + span->x];
599 auto cmp = &cbuffer[span->y * surface->stride + span->x];
600 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
601 auto alpha = _multiplyAlpha(span->coverage, opacity);
603 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
604 auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp));
605 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
608 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
609 auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(alpha, blendMethod(*cmp)));
610 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
618 static bool __rasterDirectTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity)
620 auto span = image->rle->spans;
622 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
623 auto dst = &surface->buffer[span->y * surface->stride + span->x];
624 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
625 auto alpha = _multiplyAlpha(span->coverage, opacity);
626 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
627 auto src = ALPHA_BLEND(*img, alpha);
628 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
635 static bool _rasterDirectTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity)
637 if (surface->compositor) {
638 if (surface->compositor->method == CompositeMethod::AlphaMask) {
639 return _rasterDirectMaskedRleImage(surface, image, opacity, surface->blender.alpha);
640 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
641 return _rasterDirectMaskedRleImage(surface, image, opacity, surface->blender.ialpha);
644 return __rasterDirectTranslucentRleImage(surface, image, opacity);
648 static bool _rasterDirectSolidRleImage(SwSurface* surface, const SwImage* image)
650 auto span = image->rle->spans;
652 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
653 auto dst = &surface->buffer[span->y * surface->stride + span->x];
654 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
655 if (span->coverage == 255) {
656 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
660 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
661 auto src = ALPHA_BLEND(*img, span->coverage);
662 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
670 /************************************************************************/
671 /* Whole Transformed Translucent Image */
672 /************************************************************************/
674 static bool _rasterTransformedMaskedImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t))
676 TVGLOG("SW_ENGINE", "Transformed Masked Image");
678 auto img = image->data;
681 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
682 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
684 for (auto y = region.min.y; y < region.max.y; ++y) {
687 float ey1 = y * itransform->e12 + itransform->e13;
688 float ey2 = y * itransform->e22 + itransform->e23;
689 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
690 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
691 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
692 if (rX >= w || rY >= h) continue;
693 auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp)));
694 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
696 dbuffer += surface->stride;
697 cbuffer += surface->stride;
703 static bool _rasterTransformedTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform)
705 auto img = image->data;
708 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
710 for (auto y = region.min.y; y < region.max.y; ++y) {
712 auto ey1 = y * itransform->e12 + itransform->e13;
713 auto ey2 = y * itransform->e22 + itransform->e23;
714 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
715 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
716 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
717 if (rX >= w || rY >= h) continue;
719 auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], opacity);
720 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
722 dbuffer += surface->stride;
728 static bool _rasterDownScaledMaskedImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
730 TVGLOG("SW_ENGINE", "Down Scaled Masked Image");
732 auto img = image->data;
735 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
736 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
738 for (auto y = region.min.y; y < region.max.y; ++y) {
741 float ey1 = y * itransform->e12 + itransform->e13;
742 float ey2 = y * itransform->e22 + itransform->e23;
743 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
744 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
745 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
746 if (rX >= w || rY >= h) continue;
748 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) {
749 src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp)));
751 src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), _multiplyAlpha(opacity, blendMethod(*cmp)));
753 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
755 dbuffer += surface->stride;
756 cbuffer += surface->stride;
762 static bool _rasterDownScaledTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale)
764 auto img = image->data;
767 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
769 for (auto y = region.min.y; y < region.max.y; ++y) {
771 auto ey1 = y * itransform->e12 + itransform->e13;
772 auto ey2 = y * itransform->e22 + itransform->e23;
773 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
774 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
775 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
776 if (rX >= w || rY >= h) continue;
778 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rX + (rY * w)], opacity);
779 else src = ALPHA_BLEND(_interpDownScaler(img, w, h, rX, rY, halfScale), opacity);
780 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
782 dbuffer += surface->stride;
788 static bool _rasterUpScaledMaskedImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t))
790 TVGLOG("SW_ENGINE", "Up Scaled Masked Image");
792 auto img = image->data;
795 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
796 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
798 for (auto y = region.min.y; y < region.max.y; ++y) {
801 float ey1 = y * itransform->e12 + itransform->e13;
802 float ey2 = y * itransform->e22 + itransform->e23;
803 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
804 auto fX = x * itransform->e11 + ey1;
805 auto fY = x * itransform->e21 + ey2;
806 auto rX = static_cast<uint32_t>(roundf(fX));
807 auto rY = static_cast<uint32_t>(roundf(fY));
808 if (rX >= w || rY >= h) continue;
810 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp)));
811 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), _multiplyAlpha(opacity, blendMethod(*cmp)));
812 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
814 dbuffer += surface->stride;
815 cbuffer += surface->stride;
821 static bool _rasterUpScaledTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform)
823 auto img = image->data;
826 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
828 for (auto y = region.min.y; y < region.max.y; ++y) {
830 auto ey1 = y * itransform->e12 + itransform->e13;
831 auto ey2 = y * itransform->e22 + itransform->e23;
832 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
833 auto fX = x * itransform->e11 + ey1;
834 auto fY = x * itransform->e21 + ey2;
835 auto rX = static_cast<uint32_t>(roundf(fX));
836 auto rY = static_cast<uint32_t>(roundf(fY));
837 if (rX >= w || rY >= h) continue;
839 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], opacity);
840 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), opacity);
841 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
843 dbuffer += surface->stride;
849 static bool _rasterTransformedTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale)
852 if (mathEqual(image->scale, 1.0f)) {
853 if (surface->compositor) {
854 if (surface->compositor->method == CompositeMethod::AlphaMask) {
855 return _rasterTransformedMaskedImage(surface, image, opacity, region, itransform, surface->blender.alpha);
857 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
858 return _rasterTransformedMaskedImage(surface, image, opacity, region, itransform, surface->blender.ialpha);
861 return _rasterTransformedTranslucentImage(surface, image, opacity, region, itransform);
862 //Transformed + DownScaled
863 } else if (image->scale < DOWN_SCALE_TOLERANCE) {
864 if (surface->compositor) {
865 if (surface->compositor->method == CompositeMethod::AlphaMask) {
866 return _rasterDownScaledMaskedImage(surface, image, opacity, region, itransform, halfScale, surface->blender.alpha);
867 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
868 return _rasterDownScaledMaskedImage(surface, image, opacity, region, itransform, halfScale, surface->blender.ialpha);
871 return _rasterDownScaledTranslucentImage(surface, image, opacity, region, itransform, halfScale);
872 //Transformed + UpScaled
874 if (surface->compositor) {
875 if (surface->compositor->method == CompositeMethod::AlphaMask) {
876 return _rasterUpScaledMaskedImage(surface, image, opacity, region, itransform, surface->blender.alpha);
877 }else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
878 return _rasterUpScaledMaskedImage(surface, image, opacity, region, itransform, surface->blender.ialpha);
881 return _rasterUpScaledTranslucentImage(surface, image, opacity, region, itransform);
886 /************************************************************************/
887 /* Whole Transformed Solid Image */
888 /************************************************************************/
890 static bool _rasterTransformedSolidImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform)
892 auto img = image->data;
896 for (auto y = region.min.y; y < region.max.y; ++y) {
897 auto dst = &surface->buffer[y * surface->stride + region.min.x];
898 auto ey1 = y * itransform->e12 + itransform->e13;
899 auto ey2 = y * itransform->e22 + itransform->e23;
900 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
901 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
902 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
903 if (rX >= w || rY >= h) continue;
904 *dst = img[rX + (rY * image->stride)];
911 static bool _rasterDownScaledSolidImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform, uint32_t halfScale)
913 auto img = image->data;
917 for (auto y = region.min.y; y < region.max.y; ++y) {
918 auto dst = &surface->buffer[y * surface->stride + region.min.x];
919 auto ey1 = y * itransform->e12 + itransform->e13;
920 auto ey2 = y * itransform->e22 + itransform->e23;
921 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
922 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
923 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
924 if (rX >= w || rY >= h) continue;
926 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = img[rX + (rY * w)];
927 else src = _interpDownScaler(img, w, h, rX, rY, halfScale);
935 static bool _rasterUpScaledSolidImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform)
937 auto img = image->data;
941 for (auto y = region.min.y; y < region.max.y; ++y) {
942 auto dst = &surface->buffer[y * surface->stride + region.min.x];
943 auto ey1 = y * itransform->e12 + itransform->e13;
944 auto ey2 = y * itransform->e22 + itransform->e23;
945 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
946 auto fX = x * itransform->e11 + ey1;
947 auto fY = x * itransform->e21 + ey2;
948 auto rX = static_cast<uint32_t>(roundf(fX));
949 auto rY = static_cast<uint32_t>(roundf(fY));
950 if (rX >= w || rY >= h) continue;
952 if (rX == w - 1 || rY == h - 1) src = img[rX + (rY * w)];
953 else src = _interpUpScaler(img, w, h, fX, fY);
961 static bool _rasterTransformedSolidImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform, uint32_t halfScale)
963 if (mathEqual(image->scale, 1.0f)) return _rasterTransformedSolidImage(surface, image, region, itransform);
964 else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledSolidImage(surface, image, region, itransform, halfScale);
965 else return _rasterUpScaledSolidImage(surface, image, region, itransform);
969 /************************************************************************/
970 /* Whole Scaled RGBA Image */
971 /************************************************************************/
973 static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
975 TVGLOG("SW_ENGINE", "Scaled Masked Image");
978 SwCoord ys[2] = {region.min.y, region.max.y - 1};
980 for (auto i = 0; i < 2; ++i) {
982 auto dst = surface->buffer + (y * surface->stride + region.min.x);
983 auto cmp = surface->compositor->image.data + (y * surface->stride + region.min.x);
984 auto img = image->data + static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride;
985 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
986 auto src = ALPHA_BLEND(img[static_cast<uint32_t>(x * itransform->e11 + itransform->e13)], _multiplyAlpha(opacity, blendMethod(*cmp)));
987 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
991 SwCoord xs[2] = {region.min.x, region.max.x - 1};
993 for (auto i = 0; i < 2; ++i) {
995 auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x);
996 auto cmp = surface->compositor->image.data + ((region.min.y + 1) * surface->stride + x);
997 auto img = image->data + static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
998 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride, cmp += surface->stride) {
999 auto src = ALPHA_BLEND(img[static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride], _multiplyAlpha(opacity, blendMethod(*cmp)));
1000 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1003 //Center (Down-Scaled)
1004 if (image->scale < DOWN_SCALE_TOLERANCE) {
1005 auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
1006 auto cbuffer = surface->compositor->image.data + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
1007 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y) {
1010 auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
1011 for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst, ++cmp) {
1012 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1013 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), _multiplyAlpha(opacity, blendMethod(*cmp)));
1014 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1016 dbuffer += surface->stride;
1017 cbuffer += surface->compositor->image.stride;
1019 //Center (Up-Scaled)
1021 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
1022 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride + region.min.x);
1023 for (auto y = region.min.y; y < region.max.y - 1; ++y) {
1026 auto sy = y * itransform->e22 + itransform->e23;
1027 for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst, ++cmp) {
1028 auto sx = x * itransform->e11 + itransform->e13;
1029 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), _multiplyAlpha(opacity, blendMethod(*cmp)));
1030 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1032 dbuffer += surface->stride;
1033 cbuffer += surface->compositor->image.stride;
1040 static bool __rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale)
1043 SwCoord ys[2] = {region.min.y, region.max.y - 1};
1045 for (auto i = 0; i < 2; ++i) {
1047 auto dst = surface->buffer + (y * surface->stride + region.min.x);
1048 auto img = image->data + static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride;
1049 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1050 auto src = ALPHA_BLEND(img[static_cast<uint32_t>(x * itransform->e11 + itransform->e13)], opacity);
1051 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1055 SwCoord xs[2] = {region.min.x, region.max.x - 1};
1057 for (auto i = 0; i < 2; ++i) {
1059 auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x);
1060 auto img = image->data + static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1061 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride) {
1062 auto src = ALPHA_BLEND(img[static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride], opacity);
1063 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1066 //Center (Down-Scaled)
1067 if (image->scale < DOWN_SCALE_TOLERANCE) {
1068 auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
1069 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
1070 auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
1072 for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst) {
1073 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1074 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), opacity);
1075 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1078 //Center (Up-Scaled)
1080 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
1081 for (auto y = region.min.y; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
1082 auto sy = y * itransform->e22 + itransform->e23;
1084 for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst) {
1085 auto sx = x * itransform->e11 + itransform->e13;
1086 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), opacity);
1087 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1095 static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale)
1097 if (surface->compositor) {
1098 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1099 return _rasterScaledMaskedRGBAImage(surface, image, opacity, region, itransform, halfScale, surface->blender.alpha);
1100 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1101 return _rasterScaledMaskedRGBAImage(surface, image, opacity, region, itransform, halfScale, surface->blender.ialpha);
1104 return __rasterScaledTranslucentRGBAImage(surface, image, opacity, region, itransform, halfScale);
1108 static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform, uint32_t halfScale)
1111 SwCoord ys[2] = {region.min.y, region.max.y - 1};
1113 for (auto i = 0; i < 2; ++i) {
1115 auto dst = surface->buffer + (y * surface->stride + region.min.x);
1116 auto img = image->data + static_cast<uint32_t>((y * itransform->e22 + itransform->e23)) * image->stride;
1117 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1118 auto src = img[static_cast<uint32_t>(x * itransform->e11 + itransform->e13)];
1119 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1123 SwCoord xs[2] = {region.min.x, region.max.x - 1};
1125 for (auto i = 0; i < 2; ++i) {
1127 auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x);
1128 auto img = image->data + static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1129 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride) {
1130 auto src = img[static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride];
1131 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1134 //Center (Down-Scaled)
1135 if (image->scale < DOWN_SCALE_TOLERANCE) {
1136 auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
1137 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
1138 auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
1140 for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst) {
1141 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1142 auto src = _interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale);
1143 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1146 //Center (Up-Scaled)
1148 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
1149 for (auto y = region.min.y; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
1150 auto sy = y * itransform->e22 + itransform->e23;
1152 for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst) {
1153 auto sx = x * itransform->e11 + itransform->e13;
1154 auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
1155 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1163 /************************************************************************/
1164 /* Whole Direct RGBA Image */
1165 /************************************************************************/
1167 static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, uint32_t (*blendMethod)(uint32_t))
1169 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1170 auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
1171 auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
1173 TVGLOG("SW_ENGINE", "Direct Masked Image");
1175 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1176 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
1178 for (uint32_t y = 0; y < h2; ++y) {
1182 for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
1183 auto tmp = ALPHA_BLEND(*src, _multiplyAlpha(opacity, blendMethod(*cmp)));
1184 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1186 buffer += surface->stride;
1187 cbuffer += surface->stride;
1188 sbuffer += image->stride;
1194 static bool __rasterDirectTranslucentRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region)
1196 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
1197 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1199 for (auto y = region.min.y; y < region.max.y; ++y) {
1202 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
1203 auto p = ALPHA_BLEND(*src, opacity);
1204 *dst = p + ALPHA_BLEND(*dst, surface->blender.ialpha(p));
1206 dbuffer += surface->stride;
1207 sbuffer += image->stride;
1213 static bool _rasterDirectTranslucentRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region)
1215 if (surface->compositor) {
1216 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1217 return _rasterDirectMaskedRGBAImage(surface, image, opacity, region, surface->blender.alpha);
1218 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1219 return _rasterDirectMaskedRGBAImage(surface, image, opacity, region, surface->blender.ialpha);
1222 return __rasterDirectTranslucentRGBAImage(surface, image, opacity, region);
1226 static bool _rasterDirectRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region)
1228 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
1229 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1231 for (auto y = region.min.y; y < region.max.y; ++y) {
1234 for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
1235 *dst = *src + ALPHA_BLEND(*dst, surface->blender.ialpha(*src));
1237 dbuffer += surface->stride;
1238 sbuffer += image->stride;
1244 /************************************************************************/
1245 /* Rect Linear Gradient */
1246 /************************************************************************/
1248 static bool _rasterTranslucentLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1250 if (fill->linear.len < FLT_EPSILON) return false;
1252 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1253 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1254 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1255 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
1257 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1258 if (!sbuffer) return false;
1260 for (uint32_t y = 0; y < h; ++y) {
1261 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1265 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1266 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1267 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1269 buffer += surface->stride;
1270 cbuffer += surface->stride;
1276 static bool __rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1278 if (fill->linear.len < FLT_EPSILON) return false;
1280 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1281 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1282 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1284 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1285 if (!sbuffer) return false;
1288 for (uint32_t y = 0; y < h; ++y) {
1289 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1290 for (uint32_t x = 0; x < w; ++x) {
1291 dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x]));
1293 dst += surface->stride;
1299 static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1301 if (surface->compositor) {
1302 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1303 return _rasterTranslucentLinearGradientMaskedRect(surface, region, fill, surface->blender.alpha);
1305 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1306 return _rasterTranslucentLinearGradientMaskedRect(surface, region, fill, surface->blender.ialpha);
1309 return __rasterTranslucentLinearGradientRect(surface, region, fill);
1313 static bool _rasterSolidLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1315 if (fill->linear.len < FLT_EPSILON) return false;
1317 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1318 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1319 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1321 for (uint32_t y = 0; y < h; ++y) {
1322 fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w);
1328 /************************************************************************/
1329 /* Rle Linear Gradient */
1330 /************************************************************************/
1333 static bool _rasterTranslucentLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1335 if (fill->linear.len < FLT_EPSILON) return false;
1337 auto span = rle->spans;
1338 auto cbuffer = surface->compositor->image.data;
1339 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1340 if (!buffer) return false;
1342 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1343 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1344 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1345 auto cmp = &cbuffer[span->y * surface->stride + span->x];
1347 if (span->coverage == 255) {
1348 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1349 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1350 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1353 auto ialpha = 255 - span->coverage;
1354 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1355 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1356 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1357 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1365 static bool __rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1367 if (fill->linear.len < FLT_EPSILON) return false;
1369 auto span = rle->spans;
1370 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1371 if (!buffer) return false;
1373 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1374 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1375 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1376 if (span->coverage == 255) {
1377 for (uint32_t i = 0; i < span->len; ++i) {
1378 dst[i] = buffer[i] + ALPHA_BLEND(dst[i], surface->blender.ialpha(buffer[i]));
1381 for (uint32_t i = 0; i < span->len; ++i) {
1382 auto tmp = ALPHA_BLEND(buffer[i], span->coverage);
1383 dst[i] = tmp + ALPHA_BLEND(dst[i], surface->blender.ialpha(tmp));
1391 static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1393 if (!rle) return false;
1395 if (surface->compositor) {
1396 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1397 return _rasterTranslucentLinearGradientMaskedRle(surface, rle, fill, surface->blender.alpha);
1398 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1399 return _rasterTranslucentLinearGradientMaskedRle(surface, rle, fill, surface->blender.ialpha);
1402 return __rasterTranslucentLinearGradientRle(surface, rle, fill);
1406 static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1408 if (fill->linear.len < FLT_EPSILON) return false;
1410 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1411 if (!buf) return false;
1413 auto span = rle->spans;
1415 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1416 if (span->coverage == 255) {
1417 fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len);
1419 fillFetchLinear(fill, buf, span->y, span->x, span->len);
1420 auto ialpha = 255 - span->coverage;
1421 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1422 for (uint32_t i = 0; i < span->len; ++i) {
1423 dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
1431 /************************************************************************/
1432 /* Rect Radial Gradient */
1433 /************************************************************************/
1435 static bool _rasterTranslucentRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1437 if (fill->radial.a < FLT_EPSILON) return false;
1439 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1440 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1441 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1442 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
1444 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1445 if (!sbuffer) return false;
1447 for (uint32_t y = 0; y < h; ++y) {
1448 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1452 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1453 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1454 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1456 buffer += surface->stride;
1457 cbuffer += surface->stride;
1463 static bool __rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1465 if (fill->radial.a < FLT_EPSILON) return false;
1467 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1468 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1469 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1471 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1472 if (!sbuffer) return false;
1475 for (uint32_t y = 0; y < h; ++y) {
1476 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1477 for (uint32_t x = 0; x < w; ++x) {
1478 dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x]));
1480 dst += surface->stride;
1486 static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1488 if (surface->compositor) {
1489 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1490 return _rasterTranslucentRadialGradientMaskedRect(surface, region, fill, surface->blender.alpha);
1491 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1492 return _rasterTranslucentRadialGradientMaskedRect(surface, region, fill, surface->blender.ialpha);
1495 return __rasterTranslucentRadialGradientRect(surface, region, fill);
1499 static bool _rasterSolidRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1501 if (fill->radial.a < FLT_EPSILON) return false;
1503 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1504 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1505 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1507 for (uint32_t y = 0; y < h; ++y) {
1508 auto dst = &buffer[y * surface->stride];
1509 fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w);
1515 /************************************************************************/
1516 /* RLE Radial Gradient */
1517 /************************************************************************/
1520 static bool _rasterTranslucentRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1522 if (fill->radial.a < FLT_EPSILON) return false;
1524 auto span = rle->spans;
1525 auto cbuffer = surface->compositor->image.data;
1526 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1527 if (!buffer) return false;
1529 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1530 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1531 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1532 auto cmp = &cbuffer[span->y * surface->stride + span->x];
1534 if (span->coverage == 255) {
1535 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1536 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1537 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1540 auto ialpha = 255 - span->coverage;
1541 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1542 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1543 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1544 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1552 static bool __rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1554 if (fill->radial.a < FLT_EPSILON) return false;
1556 auto span = rle->spans;
1557 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1558 if (!buffer) return false;
1560 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1561 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1562 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1563 if (span->coverage == 255) {
1564 for (uint32_t i = 0; i < span->len; ++i) {
1565 dst[i] = buffer[i] + ALPHA_BLEND(dst[i], surface->blender.ialpha(buffer[i]));
1568 for (uint32_t i = 0; i < span->len; ++i) {
1569 auto tmp = ALPHA_BLEND(buffer[i], span->coverage);
1570 dst[i] = tmp + ALPHA_BLEND(dst[i], surface->blender.ialpha(tmp));
1578 static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1580 if (!rle) return false;
1582 if (surface->compositor) {
1583 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1584 return _rasterTranslucentRadialGradientMaskedRle(surface, rle, fill, surface->blender.alpha);
1585 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1586 return _rasterTranslucentRadialGradientMaskedRle(surface, rle, fill, surface->blender.ialpha);
1589 return __rasterTranslucentRadialGradientRle(surface, rle, fill);
1593 static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1595 if (fill->radial.a < FLT_EPSILON) return false;
1597 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1598 if (!buf) return false;
1600 auto span = rle->spans;
1602 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1603 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1604 if (span->coverage == 255) {
1605 fillFetchRadial(fill, dst, span->y, span->x, span->len);
1607 fillFetchRadial(fill, buf, span->y, span->x, span->len);
1608 auto ialpha = 255 - span->coverage;
1609 for (uint32_t i = 0; i < span->len; ++i) {
1610 dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
1618 /************************************************************************/
1619 /* External Class Implementation */
1620 /************************************************************************/
1622 void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
1624 #if defined(THORVG_AVX_VECTOR_SUPPORT)
1625 avxRasterRGBA32(dst, val, offset, len);
1626 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
1627 neonRasterRGBA32(dst, val, offset, len);
1629 cRasterRGBA32(dst, val, offset, len);
1634 bool rasterCompositor(SwSurface* surface)
1636 if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
1637 surface->blender.join = _abgrJoin;
1638 } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
1639 surface->blender.join = _argbJoin;
1641 //What Color Space ???
1644 surface->blender.alpha = _colorAlpha;
1645 surface->blender.ialpha = _colorInvAlpha;
1651 bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
1653 if (!shape->fill) return false;
1655 auto translucent = shape->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None);
1658 if (shape->fastTrack) {
1659 if (id == TVG_CLASS_ID_LINEAR) {
1660 if (translucent) return _rasterTranslucentLinearGradientRect(surface, shape->bbox, shape->fill);
1661 return _rasterSolidLinearGradientRect(surface, shape->bbox, shape->fill);
1663 if (translucent) return _rasterTranslucentRadialGradientRect(surface, shape->bbox, shape->fill);
1664 return _rasterSolidRadialGradientRect(surface, shape->bbox, shape->fill);
1667 if (!shape->rle) return false;
1668 if (id == TVG_CLASS_ID_LINEAR) {
1669 if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->rle, shape->fill);
1670 return _rasterSolidLinearGradientRle(surface, shape->rle, shape->fill);
1672 if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->rle, shape->fill);
1673 return _rasterSolidRadialGradientRle(surface, shape->rle, shape->fill);
1680 bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1683 r = _multiplyAlpha(r, a);
1684 g = _multiplyAlpha(g, a);
1685 b = _multiplyAlpha(b, a);
1688 auto color = surface->blender.join(r, g, b, a);
1689 auto translucent = _translucent(surface, a);
1692 if (shape->fastTrack) {
1693 if (translucent) return _rasterTranslucentRect(surface, shape->bbox, color);
1694 return _rasterSolidRect(surface, shape->bbox, color);
1697 return _rasterTranslucentRle(surface, shape->rle, color);
1699 return _rasterSolidRle(surface, shape->rle, color);
1703 bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1706 r = _multiplyAlpha(r, a);
1707 g = _multiplyAlpha(g, a);
1708 b = _multiplyAlpha(b, a);
1711 auto color = surface->blender.join(r, g, b, a);
1712 auto translucent = _translucent(surface, a);
1714 if (translucent) return _rasterTranslucentRle(surface, shape->strokeRle, color);
1715 return _rasterSolidRle(surface, shape->strokeRle, color);
1719 bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
1721 if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
1723 auto translucent = shape->stroke->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None);
1725 if (id == TVG_CLASS_ID_LINEAR) {
1726 if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1727 return _rasterSolidLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1729 if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1730 return _rasterSolidRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1737 bool rasterClear(SwSurface* surface)
1739 if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false;
1741 if (surface->w == surface->stride) {
1742 rasterRGBA32(surface->buffer, 0x00000000, 0, surface->w * surface->h);
1744 for (uint32_t i = 0; i < surface->h; i++) {
1745 rasterRGBA32(surface->buffer + surface->stride * i, 0x00000000, 0, surface->w);
1752 void rasterUnpremultiply(SwSurface* surface)
1754 //TODO: Create simd avx and neon version
1755 for (uint32_t y = 0; y < surface->h; y++) {
1756 auto buffer = surface->buffer + surface->stride * y;
1757 for (uint32_t x = 0; x < surface->w; ++x) {
1758 uint8_t a = buffer[x] >> 24;
1761 } else if (a == 0) {
1762 buffer[x] = 0x00ffffff;
1764 uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
1765 uint16_t g = ((buffer[x]) & 0xff00) / a;
1766 uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
1767 if (r > 0xff) r = 0xff;
1768 if (g > 0xff) g = 0xff;
1769 if (b > 0xff) b = 0xff;
1770 buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
1776 /* FIXME: Current SolidImage assumes always be RGBA.
1777 Applying Blenders for the following scenarios:
1779 - [Direct / Scaled / Transformed]
1781 - [None / Opacity / Composition / Opacity + Composition] */
1782 bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
1785 if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= surface->w || bbox.min.y >= surface->h) return false;
1788 if (transform && !mathInverse(transform, &itransform)) return false;
1790 auto halfScale = static_cast<uint32_t>(0.5f / image->scale);
1791 if (halfScale == 0) halfScale = 1;
1793 //OPTIMIZE_ME: we can split the condition: Opacity & Composition!
1794 auto translucent = _translucent(surface, opacity);
1798 if (image->direct) {
1799 if (translucent) return _rasterDirectTranslucentRleImage(surface, image, opacity);
1800 else return _rasterDirectSolidRleImage(surface, image);
1802 if (translucent) return _rasterTransformedTranslucentRleImage(surface, image, opacity, &itransform, halfScale);
1803 else return _rasterTransformedSolidRleImage(surface, image, &itransform, halfScale);
1807 if (image->direct) {
1808 if (translucent) return _rasterDirectTranslucentRGBAImage(surface, image, opacity, bbox);
1809 else return _rasterDirectRGBAImage(surface, image, bbox);
1810 } else if (image->scaled) {
1811 if (translucent) return _rasterScaledTranslucentRGBAImage(surface, image, opacity, bbox, &itransform, halfScale);
1812 else return _rasterScaledRGBAImage(surface, image, bbox, &itransform, halfScale);
1814 //OPTIMIZE_ME: Replace with the TexMap Rasterizer
1815 if (translucent) return _rasterTransformedTranslucentImage(surface, image, opacity, bbox, &itransform, halfScale);
1816 else return _rasterTransformedSolidImage(surface, image, bbox, &itransform, halfScale);