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 fX, float fY)
76 auto rX = static_cast<uint32_t>(fX);
77 auto rY = static_cast<uint32_t>(fY);
79 auto dX = static_cast<uint32_t>((fX - rX) * 255.0f);
80 auto dY = static_cast<uint32_t>((fY - 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 (Solid + Translucent) Direct Image */
971 /************************************************************************/
973 static bool _rasterDirectMaskedImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, uint32_t (*blendMethod)(uint32_t))
975 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
976 auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
977 auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
979 TVGLOG("SW_ENGINE", "Direct Masked Image");
981 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
982 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
984 for (uint32_t y = 0; y < h2; ++y) {
988 for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
989 auto tmp = ALPHA_BLEND(*src, _multiplyAlpha(opacity, blendMethod(*cmp)));
990 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
992 buffer += surface->stride;
993 cbuffer += surface->stride;
994 sbuffer += image->stride;
1000 static bool __rasterDirectTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region)
1002 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
1003 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1005 for (auto y = region.min.y; y < region.max.y; ++y) {
1008 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
1009 auto p = ALPHA_BLEND(*src, opacity);
1010 *dst = p + ALPHA_BLEND(*dst, surface->blender.ialpha(p));
1012 dbuffer += surface->stride;
1013 sbuffer += image->stride;
1019 static bool _rasterDirectTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region)
1021 if (surface->compositor) {
1022 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1023 return _rasterDirectMaskedImage(surface, image, opacity, region, surface->blender.alpha);
1024 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1025 return _rasterDirectMaskedImage(surface, image, opacity, region, surface->blender.ialpha);
1028 return __rasterDirectTranslucentImage(surface, image, opacity, region);
1032 static bool _rasterDirectSolidImage(SwSurface* surface, const SwImage* image, const SwBBox& region)
1034 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
1035 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1037 for (auto y = region.min.y; y < region.max.y; ++y) {
1040 for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
1043 dbuffer += surface->stride;
1044 sbuffer += image->stride;
1050 /************************************************************************/
1051 /* Rect Linear Gradient */
1052 /************************************************************************/
1054 static bool _rasterTranslucentLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1056 if (fill->linear.len < FLT_EPSILON) return false;
1058 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1059 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1060 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1061 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
1063 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1064 if (!sbuffer) return false;
1066 for (uint32_t y = 0; y < h; ++y) {
1067 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1071 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1072 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1073 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1075 buffer += surface->stride;
1076 cbuffer += surface->stride;
1082 static bool __rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1084 if (fill->linear.len < FLT_EPSILON) return false;
1086 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1087 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1088 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1090 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1091 if (!sbuffer) return false;
1094 for (uint32_t y = 0; y < h; ++y) {
1095 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1096 for (uint32_t x = 0; x < w; ++x) {
1097 dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x]));
1099 dst += surface->stride;
1105 static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1107 if (surface->compositor) {
1108 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1109 return _rasterTranslucentLinearGradientMaskedRect(surface, region, fill, surface->blender.alpha);
1111 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1112 return _rasterTranslucentLinearGradientMaskedRect(surface, region, fill, surface->blender.ialpha);
1115 return __rasterTranslucentLinearGradientRect(surface, region, fill);
1119 static bool _rasterSolidLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1121 if (fill->linear.len < FLT_EPSILON) return false;
1123 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1124 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1125 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1127 for (uint32_t y = 0; y < h; ++y) {
1128 fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w);
1134 /************************************************************************/
1135 /* Rle Linear Gradient */
1136 /************************************************************************/
1139 static bool _rasterTranslucentLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1141 if (fill->linear.len < FLT_EPSILON) return false;
1143 auto span = rle->spans;
1144 auto cbuffer = surface->compositor->image.data;
1145 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1146 if (!buffer) return false;
1148 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1149 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1150 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1151 auto cmp = &cbuffer[span->y * surface->stride + span->x];
1153 if (span->coverage == 255) {
1154 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1155 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1156 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1159 auto ialpha = 255 - span->coverage;
1160 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1161 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1162 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1163 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1171 static bool __rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1173 if (fill->linear.len < FLT_EPSILON) return false;
1175 auto span = rle->spans;
1176 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1177 if (!buffer) return false;
1179 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1180 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1181 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1182 if (span->coverage == 255) {
1183 for (uint32_t i = 0; i < span->len; ++i) {
1184 dst[i] = buffer[i] + ALPHA_BLEND(dst[i], surface->blender.ialpha(buffer[i]));
1187 for (uint32_t i = 0; i < span->len; ++i) {
1188 auto tmp = ALPHA_BLEND(buffer[i], span->coverage);
1189 dst[i] = tmp + ALPHA_BLEND(dst[i], surface->blender.ialpha(tmp));
1197 static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1199 if (!rle) return false;
1201 if (surface->compositor) {
1202 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1203 return _rasterTranslucentLinearGradientMaskedRle(surface, rle, fill, surface->blender.alpha);
1204 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1205 return _rasterTranslucentLinearGradientMaskedRle(surface, rle, fill, surface->blender.ialpha);
1208 return __rasterTranslucentLinearGradientRle(surface, rle, fill);
1212 static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1214 if (fill->linear.len < FLT_EPSILON) return false;
1216 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1217 if (!buf) return false;
1219 auto span = rle->spans;
1221 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1222 if (span->coverage == 255) {
1223 fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len);
1225 fillFetchLinear(fill, buf, span->y, span->x, span->len);
1226 auto ialpha = 255 - span->coverage;
1227 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1228 for (uint32_t i = 0; i < span->len; ++i) {
1229 dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
1237 /************************************************************************/
1238 /* Rect Radial Gradient */
1239 /************************************************************************/
1241 static bool _rasterTranslucentRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1243 if (fill->radial.a < FLT_EPSILON) return false;
1245 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1246 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1247 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1248 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
1250 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1251 if (!sbuffer) return false;
1253 for (uint32_t y = 0; y < h; ++y) {
1254 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1258 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1259 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1260 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1262 buffer += surface->stride;
1263 cbuffer += surface->stride;
1269 static bool __rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1271 if (fill->radial.a < FLT_EPSILON) return false;
1273 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1274 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1275 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1277 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1278 if (!sbuffer) return false;
1281 for (uint32_t y = 0; y < h; ++y) {
1282 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1283 for (uint32_t x = 0; x < w; ++x) {
1284 dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x]));
1286 dst += surface->stride;
1292 static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1294 if (surface->compositor) {
1295 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1296 return _rasterTranslucentRadialGradientMaskedRect(surface, region, fill, surface->blender.alpha);
1297 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1298 return _rasterTranslucentRadialGradientMaskedRect(surface, region, fill, surface->blender.ialpha);
1301 return __rasterTranslucentRadialGradientRect(surface, region, fill);
1305 static bool _rasterSolidRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1307 if (fill->radial.a < FLT_EPSILON) return false;
1309 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1310 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1311 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1313 for (uint32_t y = 0; y < h; ++y) {
1314 auto dst = &buffer[y * surface->stride];
1315 fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w);
1321 /************************************************************************/
1322 /* RLE Radial Gradient */
1323 /************************************************************************/
1326 static bool _rasterTranslucentRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1328 if (fill->radial.a < FLT_EPSILON) return false;
1330 auto span = rle->spans;
1331 auto cbuffer = surface->compositor->image.data;
1332 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1333 if (!buffer) return false;
1335 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1336 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1337 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1338 auto cmp = &cbuffer[span->y * surface->stride + span->x];
1340 if (span->coverage == 255) {
1341 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1342 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1343 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1346 auto ialpha = 255 - span->coverage;
1347 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1348 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1349 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1350 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1358 static bool __rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1360 if (fill->radial.a < FLT_EPSILON) return false;
1362 auto span = rle->spans;
1363 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1364 if (!buffer) return false;
1366 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1367 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1368 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1369 if (span->coverage == 255) {
1370 for (uint32_t i = 0; i < span->len; ++i) {
1371 dst[i] = buffer[i] + ALPHA_BLEND(dst[i], surface->blender.ialpha(buffer[i]));
1374 for (uint32_t i = 0; i < span->len; ++i) {
1375 auto tmp = ALPHA_BLEND(buffer[i], span->coverage);
1376 dst[i] = tmp + ALPHA_BLEND(dst[i], surface->blender.ialpha(tmp));
1384 static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1386 if (!rle) return false;
1388 if (surface->compositor) {
1389 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1390 return _rasterTranslucentRadialGradientMaskedRle(surface, rle, fill, surface->blender.alpha);
1391 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1392 return _rasterTranslucentRadialGradientMaskedRle(surface, rle, fill, surface->blender.ialpha);
1395 return __rasterTranslucentRadialGradientRle(surface, rle, fill);
1399 static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1401 if (fill->radial.a < FLT_EPSILON) return false;
1403 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1404 if (!buf) return false;
1406 auto span = rle->spans;
1408 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1409 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1410 if (span->coverage == 255) {
1411 fillFetchRadial(fill, dst, span->y, span->x, span->len);
1413 fillFetchRadial(fill, buf, span->y, span->x, span->len);
1414 auto ialpha = 255 - span->coverage;
1415 for (uint32_t i = 0; i < span->len; ++i) {
1416 dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
1424 /************************************************************************/
1425 /* External Class Implementation */
1426 /************************************************************************/
1428 void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
1430 #if defined(THORVG_AVX_VECTOR_SUPPORT)
1431 avxRasterRGBA32(dst, val, offset, len);
1432 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
1433 neonRasterRGBA32(dst, val, offset, len);
1435 cRasterRGBA32(dst, val, offset, len);
1440 bool rasterCompositor(SwSurface* surface)
1442 if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
1443 surface->blender.join = _abgrJoin;
1444 } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
1445 surface->blender.join = _argbJoin;
1447 //What Color Space ???
1450 surface->blender.alpha = _colorAlpha;
1451 surface->blender.ialpha = _colorInvAlpha;
1457 bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
1459 if (!shape->fill) return false;
1461 auto translucent = shape->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None);
1464 if (shape->fastTrack) {
1465 if (id == TVG_CLASS_ID_LINEAR) {
1466 if (translucent) return _rasterTranslucentLinearGradientRect(surface, shape->bbox, shape->fill);
1467 return _rasterSolidLinearGradientRect(surface, shape->bbox, shape->fill);
1469 if (translucent) return _rasterTranslucentRadialGradientRect(surface, shape->bbox, shape->fill);
1470 return _rasterSolidRadialGradientRect(surface, shape->bbox, shape->fill);
1473 if (!shape->rle) return false;
1474 if (id == TVG_CLASS_ID_LINEAR) {
1475 if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->rle, shape->fill);
1476 return _rasterSolidLinearGradientRle(surface, shape->rle, shape->fill);
1478 if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->rle, shape->fill);
1479 return _rasterSolidRadialGradientRle(surface, shape->rle, shape->fill);
1486 bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1489 r = _multiplyAlpha(r, a);
1490 g = _multiplyAlpha(g, a);
1491 b = _multiplyAlpha(b, a);
1494 auto color = surface->blender.join(r, g, b, a);
1495 auto translucent = _translucent(surface, a);
1498 if (shape->fastTrack) {
1499 if (translucent) return _rasterTranslucentRect(surface, shape->bbox, color);
1500 return _rasterSolidRect(surface, shape->bbox, color);
1503 return _rasterTranslucentRle(surface, shape->rle, color);
1505 return _rasterSolidRle(surface, shape->rle, color);
1509 bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1512 r = _multiplyAlpha(r, a);
1513 g = _multiplyAlpha(g, a);
1514 b = _multiplyAlpha(b, a);
1517 auto color = surface->blender.join(r, g, b, a);
1518 auto translucent = _translucent(surface, a);
1520 if (translucent) return _rasterTranslucentRle(surface, shape->strokeRle, color);
1521 return _rasterSolidRle(surface, shape->strokeRle, color);
1525 bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
1527 if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
1529 auto translucent = shape->stroke->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None);
1531 if (id == TVG_CLASS_ID_LINEAR) {
1532 if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1533 return _rasterSolidLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1535 if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1536 return _rasterSolidRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1543 bool rasterClear(SwSurface* surface)
1545 if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false;
1547 if (surface->w == surface->stride) {
1548 rasterRGBA32(surface->buffer, 0x00000000, 0, surface->w * surface->h);
1550 for (uint32_t i = 0; i < surface->h; i++) {
1551 rasterRGBA32(surface->buffer + surface->stride * i, 0x00000000, 0, surface->w);
1558 void rasterUnpremultiply(SwSurface* surface)
1560 //TODO: Create simd avx and neon version
1561 for (uint32_t y = 0; y < surface->h; y++) {
1562 auto buffer = surface->buffer + surface->stride * y;
1563 for (uint32_t x = 0; x < surface->w; ++x) {
1564 uint8_t a = buffer[x] >> 24;
1567 } else if (a == 0) {
1568 buffer[x] = 0x00ffffff;
1570 uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
1571 uint16_t g = ((buffer[x]) & 0xff00) / a;
1572 uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
1573 if (r > 0xff) r = 0xff;
1574 if (g > 0xff) g = 0xff;
1575 if (b > 0xff) b = 0xff;
1576 buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
1583 bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
1586 if (transform && !mathInverse(transform, &itransform)) return false;
1588 auto halfScale = static_cast<uint32_t>(0.5f / image->scale);
1589 if (halfScale == 0) halfScale = 1;
1591 auto translucent = _translucent(surface, opacity);
1595 if (image->direct) {
1596 if (translucent) return _rasterDirectTranslucentRleImage(surface, image, opacity);
1597 else return _rasterDirectSolidRleImage(surface, image);
1599 if (translucent) return _rasterTransformedTranslucentRleImage(surface, image, opacity, &itransform, halfScale);
1600 else return _rasterTransformedSolidRleImage(surface, image, &itransform, halfScale);
1604 if (image->direct) {
1605 if (translucent) return _rasterDirectTranslucentImage(surface, image, opacity, bbox);
1606 else return _rasterDirectSolidImage(surface, image, bbox);
1608 if (translucent) return _rasterTransformedTranslucentImage(surface, image, opacity, bbox, &itransform, halfScale);
1609 else return _rasterTransformedSolidImage(surface, image, bbox, &itransform, halfScale);