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 /************************************************************************/
33 static uint32_t _colorAlpha(uint32_t c)
39 static uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
41 return (a << 24 | b << 16 | g << 8 | r);
45 static uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
47 return (a << 24 | r << 16 | g << 8 | b);
51 static bool _translucent(const SwSurface* surface, uint8_t a)
53 if (a < 255) return true;
54 if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false;
59 static uint32_t _applyBilinearInterpolation(const uint32_t *img, uint32_t w, uint32_t h, float fX, float fY)
61 auto rX = static_cast<uint32_t>(fX);
62 auto rY = static_cast<uint32_t>(fY);
64 auto dX = static_cast<uint32_t>((fX - rX) * 255.0);
65 auto dY = static_cast<uint32_t>((fY - rY) * 255.0);
67 auto c1 = img[rX + (rY * w)];
68 auto c2 = img[(rX + 1) + (rY * w)];
69 auto c3 = img[(rX + 1) + ((rY + 1) * w)];
70 auto c4 = img[rX + ((rY + 1) * w)];
72 if (c1 == c2 && c1 == c3 && c1 == c4) return img[rX + (rY * w)];
73 return COLOR_INTERPOLATE(COLOR_INTERPOLATE(c1, 255 - dX, c2, dX), 255 - dY, COLOR_INTERPOLATE(c4, 255 - dX, c3, dX), dY);
76 static uint32_t _average2Nx2NPixel(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t rX, uint32_t rY, uint32_t n)
78 uint32_t c[4] = { 0 };
80 auto source = img + rX - n + (rY - n) * w;
81 for (auto y = rY - n; y < rY + n; ++y) {
83 for (auto x = rX - n; x < rX + n; ++x, ++src) {
85 c[1] += (*src >> 16) & 0xff;
86 c[2] += (*src >> 8) & 0xff;
91 for (auto i = 0; i < 4; ++i) {
92 c[i] = (c[i] >> 2) / n2;
94 return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
97 /************************************************************************/
99 /************************************************************************/
101 static bool _translucentRectAlphaMask(SwSurface* surface, const SwBBox& region, uint32_t color)
103 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
104 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
105 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
107 TVGLOG("SW_ENGINE", "Rectangle Alpha Mask Composition");
109 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
111 for (uint32_t y = 0; y < h; ++y) {
112 auto dst = &buffer[y * surface->stride];
113 auto cmp = &cbuffer[y * surface->stride];
114 for (uint32_t x = 0; x < w; ++x) {
115 auto tmp = ALPHA_BLEND(color, surface->blender.alpha(*cmp));
116 dst[x] = tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmp));
123 static bool _translucentRectInvAlphaMask(SwSurface* surface, const SwBBox& region, uint32_t color)
125 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
126 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
127 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
129 TVGLOG("SW_ENGINE", "Rectangle Inverse Alpha Mask Composition");
131 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
133 for (uint32_t y = 0; y < h; ++y) {
134 auto dst = &buffer[y * surface->stride];
135 auto cmp = &cbuffer[y * surface->stride];
136 for (uint32_t x = 0; x < w; ++x) {
137 auto tmp = ALPHA_BLEND(color, 255 - surface->blender.alpha(*cmp));
138 dst[x] = tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmp));
145 static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color)
147 if (surface->compositor) {
148 if (surface->compositor->method == CompositeMethod::AlphaMask) {
149 return _translucentRectAlphaMask(surface, region, color);
151 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
152 return _translucentRectInvAlphaMask(surface, region, color);
156 #if defined(THORVG_AVX_VECTOR_SUPPORT)
157 return avxRasterTranslucentRect(surface, region, color);
158 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
159 return neonRasterTranslucentRect(surface, region, color);
161 return cRasterTranslucentRect(surface, region, color);
166 static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color)
168 auto buffer = surface->buffer + (region.min.y * surface->stride);
169 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
170 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
172 for (uint32_t y = 0; y < h; ++y) {
173 rasterRGBA32(buffer + y * surface->stride, color, region.min.x, w);
179 /************************************************************************/
181 /************************************************************************/
184 static bool _translucentRleAlphaMask(SwSurface* surface, const SwRleData* rle, uint32_t color)
186 TVGLOG("SW_ENGINE", "Rle Alpha Mask Composition");
188 auto span = rle->spans;
190 auto cbuffer = surface->compositor->image.data;
192 for (uint32_t i = 0; i < rle->size; ++i) {
193 auto dst = &surface->buffer[span->y * surface->stride + span->x];
194 auto cmp = &cbuffer[span->y * surface->stride + span->x];
195 if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
197 for (uint32_t x = 0; x < span->len; ++x) {
198 auto tmp = ALPHA_BLEND(src, surface->blender.alpha(*cmp));
199 dst[x] = tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmp));
207 static bool _translucentRleInvAlphaMask(SwSurface* surface, SwRleData* rle, uint32_t color)
209 TVGLOG("SW_ENGINE", "Rle Inverse Alpha Mask Composition");
211 auto span = rle->spans;
213 auto cbuffer = surface->compositor->image.data;
215 for (uint32_t i = 0; i < rle->size; ++i) {
216 auto dst = &surface->buffer[span->y * surface->stride + span->x];
217 auto cmp = &cbuffer[span->y * surface->stride + span->x];
218 if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
220 for (uint32_t x = 0; x < span->len; ++x) {
221 auto tmp = ALPHA_BLEND(src, 255 - surface->blender.alpha(*cmp));
222 dst[x] = tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmp));
230 static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t color)
232 if (!rle) return false;
234 if (surface->compositor) {
235 if (surface->compositor->method == CompositeMethod::AlphaMask) {
236 return _translucentRleAlphaMask(surface, rle, color);
238 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
239 return _translucentRleInvAlphaMask(surface, rle, color);
243 #if defined(THORVG_NEON_VECTOR_SUPPORT)
244 return neonRasterTranslucentRle(surface, rle, color);
246 return cRasterTranslucentRle(surface, rle, color);
251 static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint32_t color)
253 if (!rle) return false;
255 auto span = rle->spans;
257 for (uint32_t i = 0; i < rle->size; ++i) {
258 if (span->coverage == 255) {
259 rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len);
261 auto dst = &surface->buffer[span->y * surface->stride + span->x];
262 auto src = ALPHA_BLEND(color, span->coverage);
263 auto ialpha = 255 - span->coverage;
264 for (uint32_t i = 0; i < span->len; ++i) {
265 dst[i] = src + ALPHA_BLEND(dst[i], ialpha);
274 /************************************************************************/
276 /************************************************************************/
278 static bool _translucentImageRle(SwSurface* surface, const SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity)
280 auto span = rle->spans;
282 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
283 auto dst = &surface->buffer[span->y * surface->stride + span->x];
284 auto src = img + span->x + span->y * w; //TODO: need to use image's stride
285 auto alpha = ALPHA_MULTIPLY(span->coverage, opacity);
286 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++src) {
287 *src = ALPHA_BLEND(*src, alpha);
288 *dst = *src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(*src));
295 static bool _rasterTranslucentImageRle(SwSurface* surface, const SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity)
297 if (surface->compositor) {
298 if (surface->compositor->method == CompositeMethod::AlphaMask) {
299 TVGERR("Missing Implementation _translucentImageRleAlphaMask()");
300 // return _translucentImageRleAlphaMask(surface, rle, img, w, h, opacity);
302 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
303 TVGERR("Missing Implementation _translucentImageRleInvAlphaMask()");
304 // return _translucentImageRleInvAlphaMask(surface, rle, img, w, h, opacity);
307 return _translucentImageRle(surface, rle, img, w, h, opacity);
311 static bool _translucentImageRle(SwSurface* surface, const SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const Matrix* invTransform)
313 auto span = rle->spans;
315 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
316 auto ey1 = span->y * invTransform->e12 + invTransform->e13;
317 auto ey2 = span->y * invTransform->e22 + invTransform->e23;
318 auto dst = &surface->buffer[span->y * surface->stride + span->x];
319 auto alpha = ALPHA_MULTIPLY(span->coverage, opacity);
320 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
321 auto rX = static_cast<uint32_t>(roundf((span->x + x) * invTransform->e11 + ey1));
322 auto rY = static_cast<uint32_t>(roundf((span->x + x) * invTransform->e21 + ey2));
323 if (rX >= w || rY >= h) continue;
324 auto src = ALPHA_BLEND(img[rY * w + rX], alpha); //TODO: need to use image's stride
325 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
332 static bool _rasterTranslucentImageRle(SwSurface* surface, const SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const Matrix* invTransform)
334 if (surface->compositor) {
335 if (surface->compositor->method == CompositeMethod::AlphaMask) {
336 TVGERR("Missing Implementation _translucentImageRleAlphaMask()");
337 // return _translucentImageRleAlphaMask(surface, rle, img, w, h, opacity, invTransform);
339 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
340 TVGERR("Missing Implementation _translucentImageRleInvAlphaMask()");
341 // return _translucentImageRleInvAlphaMask(surface, rle, img, w, h, opacity, invTransform);
344 return _translucentImageRle(surface, rle, img, w, h, opacity, invTransform);
348 static bool _translucentUpScaleImageRle(SwSurface* surface, const SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const Matrix* invTransform)
350 auto span = rle->spans;
351 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
352 auto ey1 = span->y * invTransform->e12 + invTransform->e13;
353 auto ey2 = span->y * invTransform->e22 + invTransform->e23;
354 auto dst = &surface->buffer[span->y * surface->stride + span->x];
355 auto alpha = ALPHA_MULTIPLY(span->coverage, opacity);
356 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
357 auto fX = (span->x + x) * invTransform->e11 + ey1;
358 auto fY = (span->x + x) * invTransform->e21 + ey2;
359 auto rX = static_cast<uint32_t>(roundf(fX));
360 auto rY = static_cast<uint32_t>(roundf(fY));
361 if (rX >= w || rY >= h) continue;
363 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * w + rX], alpha); //TODO: need to use image's stride
364 else src = ALPHA_BLEND(_applyBilinearInterpolation(img, w, h, fX, fY), alpha); //TODO: need to use image's stride
365 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
372 static bool _rasterTranslucentUpScaleImageRle(SwSurface* surface, const SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const Matrix* invTransform)
374 if (surface->compositor) {
375 if (surface->compositor->method == CompositeMethod::AlphaMask) {
376 TVGERR("Missing Implementation _translucentUpScaleImageRleAlphaMask()");
377 // return _translucentUpScaleImageRleAlphaMask(surface, rle, img, w, h, opacity, invTransform);
379 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
380 TVGERR("Missing Implementation _translucentUpScaleImageRleInvAlphaMask()");
381 // return _translucentUpScaleImageRleInvAlphaMask(surface, rle, img, w, h, opacity, invTransform);
384 return _translucentUpScaleImageRle(surface, rle, img, w, h, opacity, invTransform);
388 static bool _translucentDownScaleImageRle(SwSurface* surface, const SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const Matrix* invTransform, float scaling)
390 uint32_t halfScaling = static_cast<uint32_t>(0.5f / scaling);
391 if (halfScaling == 0) halfScaling = 1;
392 auto span = rle->spans;
393 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
394 auto ey1 = span->y * invTransform->e12 + invTransform->e13;
395 auto ey2 = span->y * invTransform->e22 + invTransform->e23;
396 auto dst = &surface->buffer[span->y * surface->stride + span->x];
397 auto alpha = ALPHA_MULTIPLY(span->coverage, opacity);
398 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
399 auto rX = static_cast<uint32_t>(roundf((span->x + x) * invTransform->e11 + ey1));
400 auto rY = static_cast<uint32_t>(roundf((span->x + x) * invTransform->e21 + ey2));
401 if (rX >= w || rY >= h) continue;
403 if (rX < halfScaling || rY < halfScaling || rX >= w - halfScaling || rY >= h - halfScaling) src = ALPHA_BLEND(img[rY * w + rX], alpha); //TODO: need to use image's stride
404 else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, w, h, rX, rY, halfScaling), alpha); //TODO: need to use image's stride
405 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
412 static bool _rasterTranslucentDownScaleImageRle(SwSurface* surface, const SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const Matrix* invTransform, float scaling)
414 if (surface->compositor) {
415 if (surface->compositor->method == CompositeMethod::AlphaMask) {
416 TVGERR("Missing Implementation _translucentDownScaleImageRleAlphaMask()");
417 // return _translucentDownScaleImageRleAlphaMask(surface, rle, img, w, h, opacity, invTransform, scaling);
419 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
420 TVGERR("Missing Implementation _translucentDownScaleImageRleInvAlphaMask()");
421 // return _translucentDownScaleImageRleInvAlphaMask(surface, rle, img, w, h, opacity, invTransform, scaling);
424 return _translucentDownScaleImageRle(surface, rle, img, w, h, opacity, invTransform, scaling);
428 static bool _rasterImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h)
430 auto span = rle->spans;
432 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
433 auto dst = &surface->buffer[span->y * surface->stride + span->x];
434 auto src = img + span->x + span->y * w; //TODO: need to use image's stride
435 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++src) {
436 *src = ALPHA_BLEND(*src, span->coverage);
437 *dst = *src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(*src));
444 static bool _rasterImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, const Matrix* invTransform)
446 auto span = rle->spans;
448 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
449 auto ey1 = span->y * invTransform->e12 + invTransform->e13;
450 auto ey2 = span->y * invTransform->e22 + invTransform->e23;
451 auto dst = &surface->buffer[span->y * surface->stride + span->x];
452 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
453 auto rX = static_cast<uint32_t>(roundf((span->x + x) * invTransform->e11 + ey1));
454 auto rY = static_cast<uint32_t>(roundf((span->x + x) * invTransform->e21 + ey2));
455 if (rX >= w || rY >= h) continue;
456 auto src = ALPHA_BLEND(img[rY * w + rX], span->coverage); //TODO: need to use image's stride
457 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
464 static bool _rasterUpScaleImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, const Matrix* invTransform)
466 auto span = rle->spans;
468 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
469 auto ey1 = span->y * invTransform->e12 + invTransform->e13;
470 auto ey2 = span->y * invTransform->e22 + invTransform->e23;
471 auto dst = &surface->buffer[span->y * surface->stride + span->x];
472 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
473 auto fX = (span->x + x) * invTransform->e11 + ey1;
474 auto fY = (span->x + x) * invTransform->e21 + ey2;
475 auto rX = static_cast<uint32_t>(roundf(fX));
476 auto rY = static_cast<uint32_t>(roundf(fY));
477 if (rX >= w || rY >= h) continue;
479 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * w + rX], span->coverage); //TODO: need to use image's stride
480 else src = ALPHA_BLEND(_applyBilinearInterpolation(img, w, h, fX, fY), span->coverage); //TODO: need to use image's stride
481 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
488 static bool _rasterDownScaleImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, const Matrix* invTransform, float scaling)
490 uint32_t halfScaling = static_cast<uint32_t>(0.5f / scaling);
491 if (halfScaling == 0) halfScaling = 1;
492 auto span = rle->spans;
494 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
495 auto ey1 = span->y * invTransform->e12 + invTransform->e13;
496 auto ey2 = span->y * invTransform->e22 + invTransform->e23;
497 auto dst = &surface->buffer[span->y * surface->stride + span->x];
498 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
499 auto rX = static_cast<uint32_t>(roundf((span->x + x) * invTransform->e11 + ey1));
500 auto rY = static_cast<uint32_t>(roundf((span->x + x) * invTransform->e21 + ey2));
501 if (rX >= w || rY >= h) continue;
503 if (rX < halfScaling || rY < halfScaling || rX >= w - halfScaling || rY >= h - halfScaling) src = ALPHA_BLEND(img[rY * w + rX], span->coverage); //TODO: need to use image's stride
504 else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, w, h, rX, rY, halfScaling), span->coverage); //TODO: need to use image's stride
505 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
512 static bool _translucentImage(SwSurface* surface, const uint32_t *img, uint32_t w, TVG_UNUSED uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
514 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
516 for (auto y = region.min.y; y < region.max.y; ++y) {
518 auto ey1 = y * invTransform->e12 + invTransform->e13;
519 auto ey2 = y * invTransform->e22 + invTransform->e23;
520 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
521 auto rX = static_cast<uint32_t>(roundf(x * invTransform->e11 + ey1));
522 auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
523 if (rX >= w || rY >= h) continue;
524 auto src = ALPHA_BLEND(img[rX + (rY * w)], opacity); //TODO: need to use image's stride
525 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
527 dbuffer += surface->stride;
533 static bool _translucentImageAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, TVG_UNUSED uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
535 TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask Composition");
537 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
538 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
540 for (auto y = region.min.y; y < region.max.y; ++y) {
543 float ey1 = y * invTransform->e12 + invTransform->e13;
544 float ey2 = y * invTransform->e22 + invTransform->e23;
545 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
546 auto rX = static_cast<uint32_t>(roundf(x * invTransform->e11 + ey1));
547 auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
548 if (rX >= w || rY >= h) continue;
549 auto src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride
550 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
552 dbuffer += surface->stride;
553 cbuffer += surface->stride;
558 static bool _translucentImageInvAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
560 TVGLOG("SW_ENGINE", "Transformed Image Inverse Alpha Mask Composition");
562 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
563 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
565 for (auto y = region.min.y; y < region.max.y; ++y) {
568 float ey1 = y * invTransform->e12 + invTransform->e13;
569 float ey2 = y * invTransform->e22 + invTransform->e23;
570 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
571 auto rX = static_cast<uint32_t>(roundf(x * invTransform->e11 + ey1));
572 auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
573 if (rX >= w || rY >= h) continue;
574 auto src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp))); //TODO: need to use image's stride
575 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
577 dbuffer += surface->stride;
578 cbuffer += surface->stride;
584 static bool _rasterTranslucentImage(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
586 if (surface->compositor) {
587 if (surface->compositor->method == CompositeMethod::AlphaMask) {
588 return _translucentImageAlphaMask(surface, img, w, h, opacity, region, invTransform);
590 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
591 return _translucentImageInvAlphaMask(surface, img, w, h, opacity, region, invTransform);
594 return _translucentImage(surface, img, w, h, opacity, region, invTransform);
598 static bool _translucentUpScaleImage(SwSurface* surface, const uint32_t *img, uint32_t w, TVG_UNUSED uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
600 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
602 for (auto y = region.min.y; y < region.max.y; ++y) {
604 auto ey1 = y * invTransform->e12 + invTransform->e13;
605 auto ey2 = y * invTransform->e22 + invTransform->e23;
606 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
607 auto fX = x * invTransform->e11 + ey1;
608 auto fY = x * invTransform->e21 + ey2;
609 auto rX = static_cast<uint32_t>(roundf(fX));
610 auto rY = static_cast<uint32_t>(roundf(fY));
611 if (rX >= w || rY >= h) continue;
613 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * w)], opacity); //TODO: need to use image's stride
614 else src = ALPHA_BLEND(_applyBilinearInterpolation(img, w, h, fX, fY), opacity); //TODO: need to use image's stride
615 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
617 dbuffer += surface->stride;
623 static bool _translucentUpScaleImageAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, TVG_UNUSED uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
625 TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask Composition");
627 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
628 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
630 for (auto y = region.min.y; y < region.max.y; ++y) {
633 float ey1 = y * invTransform->e12 + invTransform->e13;
634 float ey2 = y * invTransform->e22 + invTransform->e23;
635 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
636 auto fX = x * invTransform->e11 + ey1;
637 auto fY = x * invTransform->e21 + ey2;
638 auto rX = static_cast<uint32_t>(roundf(fX));
639 auto rY = static_cast<uint32_t>(roundf(fY));
640 if (rX >= w || rY >= h) continue;
642 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride
643 else src = ALPHA_BLEND(_applyBilinearInterpolation(img, w, h, fX, fY), ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride
644 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
646 dbuffer += surface->stride;
647 cbuffer += surface->stride;
653 static bool _translucentUpScaleImageInvAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
655 TVGLOG("SW_ENGINE", "Transformed Image Inverse Alpha Mask Composition");
657 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
658 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
660 for (auto y = region.min.y; y < region.max.y; ++y) {
663 float ey1 = y * invTransform->e12 + invTransform->e13;
664 float ey2 = y * invTransform->e22 + invTransform->e23;
665 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
666 auto fX = x * invTransform->e11 + ey1;
667 auto fY = x * invTransform->e21 + ey2;
668 auto rX = static_cast<uint32_t>(roundf(fX));
669 auto rY = static_cast<uint32_t>(roundf(fY));
670 if (rX >= w || rY >= h) continue;
672 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp))); //TODO: need to use image's stride
673 else src = ALPHA_BLEND(_applyBilinearInterpolation(img, w, h, fX, fY), ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp))); //TODO: need to use image's stride
674 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
676 dbuffer += surface->stride;
677 cbuffer += surface->stride;
683 static bool _rasterTranslucentUpScaleImage(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
685 if (surface->compositor) {
686 if (surface->compositor->method == CompositeMethod::AlphaMask) {
687 return _translucentUpScaleImageAlphaMask(surface, img, w, h, opacity, region, invTransform);
689 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
690 return _translucentUpScaleImageInvAlphaMask(surface, img, w, h, opacity, region, invTransform);
693 return _translucentUpScaleImage(surface, img, w, h, opacity, region, invTransform);
697 static bool _translucentDownScaleImage(SwSurface* surface, const uint32_t *img, uint32_t w, TVG_UNUSED uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform, float scaling)
699 uint32_t halfScaling = static_cast<uint32_t>(0.5f / scaling);
700 if (halfScaling == 0) halfScaling = 1;
701 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
703 for (auto y = region.min.y; y < region.max.y; ++y) {
705 auto ey1 = y * invTransform->e12 + invTransform->e13;
706 auto ey2 = y * invTransform->e22 + invTransform->e23;
707 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
708 auto rX = static_cast<uint32_t>(roundf(x * invTransform->e11 + ey1));
709 auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
710 if (rX >= w || rY >= h) continue;
712 if (rX < halfScaling || rY < halfScaling || rX >= w - halfScaling || rY >= h - halfScaling) src = ALPHA_BLEND(img[rX + (rY * w)], opacity);
713 else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, w, h, rX, rY, halfScaling), opacity);
714 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
716 dbuffer += surface->stride;
722 static bool _translucentDownScaleImageAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, TVG_UNUSED uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform, float scaling)
724 TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask Composition");
725 uint32_t halfScaling = static_cast<uint32_t>(0.5f / scaling);
726 if (halfScaling == 0) halfScaling = 1;
728 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
729 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
731 for (auto y = region.min.y; y < region.max.y; ++y) {
734 float ey1 = y * invTransform->e12 + invTransform->e13;
735 float ey2 = y * invTransform->e22 + invTransform->e23;
736 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
737 auto rX = static_cast<uint32_t>(roundf(x * invTransform->e11 + ey1));
738 auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
739 if (rX >= w || rY >= h) continue;
741 if (rX < halfScaling || rY < halfScaling || rX >= w - halfScaling || rY >= h - halfScaling) src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride
742 else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, w, h, rX, rY, halfScaling), ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride
743 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
745 dbuffer += surface->stride;
746 cbuffer += surface->stride;
752 static bool _translucentDownScaleImageInvAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform, float scaling)
754 TVGLOG("SW_ENGINE", "Transformed Image Inverse Alpha Mask Composition");
755 uint32_t halfScaling = static_cast<uint32_t>(0.5f / scaling);
756 if (halfScaling == 0) halfScaling = 1;
758 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
759 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
761 for (auto y = region.min.y; y < region.max.y; ++y) {
764 float ey1 = y * invTransform->e12 + invTransform->e13;
765 float ey2 = y * invTransform->e22 + invTransform->e23;
766 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
767 auto rX = static_cast<uint32_t>(roundf(x * invTransform->e11 + ey1));
768 auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
769 if (rX >= w || rY >= h) continue;
771 if (rX < halfScaling || rY < halfScaling || rX >= w - halfScaling || rY >= h - halfScaling) src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp))); //TODO: need to use image's stride
772 else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, w, h, rX, rY, halfScaling), ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp))); //TODO: need to use image's stride
773 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
775 dbuffer += surface->stride;
776 cbuffer += surface->stride;
782 static bool _rasterTranslucentDownScaleImage(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform, float scaling)
784 if (surface->compositor) {
785 if (surface->compositor->method == CompositeMethod::AlphaMask) {
786 return _translucentDownScaleImageAlphaMask(surface, img, w, h, opacity, region, invTransform, scaling);
788 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
789 return _translucentDownScaleImageInvAlphaMask(surface, img, w, h, opacity, region, invTransform, scaling);
792 return _translucentDownScaleImage(surface, img, w, h, opacity, region, invTransform, scaling);
796 static bool _translucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region)
798 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
799 auto sbuffer = img + region.min.x + region.min.y * w; //TODO: need to use image's stride
801 for (auto y = region.min.y; y < region.max.y; ++y) {
804 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
805 auto p = ALPHA_BLEND(*src, opacity);
806 *dst = p + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(p));
808 dbuffer += surface->stride;
809 sbuffer += w; //TODO: need to use image's stride
815 static bool _translucentImageAlphaMask(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region)
817 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
818 auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
819 auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
821 TVGLOG("SW_ENGINE", "Image Alpha Mask Composition");
823 auto sbuffer = img + (region.min.y * w) + region.min.x;
824 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
826 for (uint32_t y = 0; y < h2; ++y) {
830 for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
831 auto tmp = ALPHA_BLEND(*src, ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp)));
832 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
834 buffer += surface->stride;
835 cbuffer += surface->stride;
836 sbuffer += w; //TODO: need to use image's stride
842 static bool _translucentImageInvAlphaMask(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region)
844 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
845 auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
846 auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
848 TVGLOG("SW_ENGINE", "Image Inverse Alpha Mask Composition");
850 auto sbuffer = img + (region.min.y * w) + region.min.x;
851 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
853 for (uint32_t y = 0; y < h2; ++y) {
857 for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
858 auto tmp = ALPHA_BLEND(*src, ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp)));
859 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
861 buffer += surface->stride;
862 cbuffer += surface->stride;
863 sbuffer += w; //TODO: need to use image's stride
869 static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region)
871 if (surface->compositor) {
872 if (surface->compositor->method == CompositeMethod::AlphaMask) {
873 return _translucentImageAlphaMask(surface, img, w, h, opacity, region);
875 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
876 return _translucentImageInvAlphaMask(surface, img, w, h, opacity, region);
879 return _translucentImage(surface, img, w, h, opacity, region);
883 static bool _rasterImage(SwSurface* surface, uint32_t *img, uint32_t w, TVG_UNUSED uint32_t h, const SwBBox& region)
885 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
886 auto sbuffer = img + region.min.x + region.min.y * w; //TODO: need to use image's stride
888 for (auto y = region.min.y; y < region.max.y; ++y) {
891 for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
892 *dst = *src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(*src));
894 dbuffer += surface->stride;
895 sbuffer += w; //TODO: need to use image's stride
901 static bool _rasterImage(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, const SwBBox& region, const Matrix* invTransform)
903 for (auto y = region.min.y; y < region.max.y; ++y) {
904 auto dst = &surface->buffer[y * surface->stride + region.min.x];
905 auto ey1 = y * invTransform->e12 + invTransform->e13;
906 auto ey2 = y * invTransform->e22 + invTransform->e23;
907 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
908 auto rX = static_cast<uint32_t>(roundf(x * invTransform->e11 + ey1));
909 auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
910 if (rX >= w || rY >= h) continue;
911 auto src = img[rX + (rY * w)]; //TODO: need to use image's stride
912 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
919 static bool _rasterUpScaleImage(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, const SwBBox& region, const Matrix* invTransform)
921 for (auto y = region.min.y; y < region.max.y; ++y) {
922 auto dst = &surface->buffer[y * surface->stride + region.min.x];
923 auto ey1 = y * invTransform->e12 + invTransform->e13;
924 auto ey2 = y * invTransform->e22 + invTransform->e23;
925 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
926 auto fX = x * invTransform->e11 + ey1;
927 auto fY = x * invTransform->e21 + ey2;
928 auto rX = static_cast<uint32_t>(roundf(fX));
929 auto rY = static_cast<uint32_t>(roundf(fY));
930 if (rX >= w || rY >= h) continue;
932 if (rX == w - 1 || rY == h - 1) src = img[rX + (rY * w)];
933 else src = _applyBilinearInterpolation(img, w, h, fX, fY);
934 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
941 static bool _rasterDownScaleImage(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, const SwBBox& region, const Matrix* invTransform, float scaling)
943 uint32_t halfScaling = static_cast<uint32_t>(0.5f / scaling);
945 if (halfScaling == 0) halfScaling = 1;
946 for (auto y = region.min.y; y < region.max.y; ++y) {
947 auto dst = &surface->buffer[y * surface->stride + region.min.x];
948 auto ey1 = y * invTransform->e12 + invTransform->e13;
949 auto ey2 = y * invTransform->e22 + invTransform->e23;
950 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
951 auto rX = static_cast<uint32_t>(roundf(x * invTransform->e11 + ey1));
952 auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
953 if (rX >= w || rY >= h) continue;
955 if (rX < halfScaling || rY < halfScaling || rX >= w - halfScaling || rY >= h - halfScaling) src = img[rX + (rY * w)];
956 else src = _average2Nx2NPixel(surface, img, w, h, rX, rY, halfScaling);
957 *dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
964 /************************************************************************/
966 /************************************************************************/
968 static bool _translucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
970 if (fill->linear.len < FLT_EPSILON) return false;
972 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
973 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
974 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
976 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
977 if (!sbuffer) return false;
980 for (uint32_t y = 0; y < h; ++y) {
981 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
982 for (uint32_t x = 0; x < w; ++x) {
983 dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(sbuffer[x]));
985 dst += surface->stride;
991 static bool _translucentLinearGradientRectAlphaMask(SwSurface* surface, const SwBBox& region, const SwFill* fill)
993 if (fill->linear.len < FLT_EPSILON) return false;
995 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
996 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
997 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
998 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
1000 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1001 if (!sbuffer) return false;
1003 for (uint32_t y = 0; y < h; ++y) {
1004 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1008 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1009 auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
1010 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1012 buffer += surface->stride;
1013 cbuffer += surface->stride;
1019 static bool _translucentLinearGradientRectInvAlphaMask(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1021 if (fill->linear.len < FLT_EPSILON) return false;
1023 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1024 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1025 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1026 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
1028 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1029 if (!sbuffer) return false;
1031 for (uint32_t y = 0; y < h; ++y) {
1032 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1036 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1037 auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
1038 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1040 buffer += surface->stride;
1041 cbuffer += surface->stride;
1047 static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1049 if (surface->compositor) {
1050 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1051 return _translucentLinearGradientRectAlphaMask(surface, region, fill);
1053 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1054 return _translucentLinearGradientRectInvAlphaMask(surface, region, fill);
1057 return _translucentLinearGradientRect(surface, region, fill);
1061 static bool _rasterOpaqueLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1063 if (fill->linear.len < FLT_EPSILON) return false;
1065 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1066 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1067 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1069 for (uint32_t y = 0; y < h; ++y) {
1070 fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w);
1076 static bool _translucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1078 if (fill->radial.a < FLT_EPSILON) return false;
1080 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1081 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1082 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1084 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1085 if (!sbuffer) return false;
1088 for (uint32_t y = 0; y < h; ++y) {
1089 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1090 for (uint32_t x = 0; x < w; ++x) {
1091 dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(sbuffer[x]));
1093 dst += surface->stride;
1099 static bool _translucentRadialGradientRectAlphaMask(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1101 if (fill->radial.a < FLT_EPSILON) return false;
1103 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1104 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1105 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1106 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
1108 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1109 if (!sbuffer) return false;
1111 for (uint32_t y = 0; y < h; ++y) {
1112 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1116 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1117 auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
1118 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1120 buffer += surface->stride;
1121 cbuffer += surface->stride;
1127 static bool _translucentRadialGradientRectInvAlphaMask(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1129 if (fill->radial.a < FLT_EPSILON) return false;
1131 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1132 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1133 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1134 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
1136 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1137 if (!sbuffer) return false;
1139 for (uint32_t y = 0; y < h; ++y) {
1140 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1144 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1145 auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
1146 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1148 buffer += surface->stride;
1149 cbuffer += surface->stride;
1155 static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1157 if (surface->compositor) {
1158 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1159 return _translucentRadialGradientRectAlphaMask(surface, region, fill);
1161 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1162 return _translucentRadialGradientRectInvAlphaMask(surface, region, fill);
1165 return _translucentRadialGradientRect(surface, region, fill);
1169 static bool _rasterOpaqueRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1171 if (fill->radial.a < FLT_EPSILON) return false;
1173 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1174 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1175 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1177 for (uint32_t y = 0; y < h; ++y) {
1178 auto dst = &buffer[y * surface->stride];
1179 fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w);
1185 static bool _translucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1187 if (fill->linear.len < FLT_EPSILON) return false;
1189 auto span = rle->spans;
1190 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1191 if (!buffer) return false;
1193 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1194 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1195 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1196 if (span->coverage == 255) {
1197 for (uint32_t i = 0; i < span->len; ++i) {
1198 dst[i] = buffer[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buffer[i]));
1201 for (uint32_t i = 0; i < span->len; ++i) {
1202 auto tmp = ALPHA_BLEND(buffer[i], span->coverage);
1203 dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp));
1211 static bool _translucentLinearGradientRleAlphaMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1213 if (fill->linear.len < FLT_EPSILON) return false;
1215 auto span = rle->spans;
1216 auto cbuffer = surface->compositor->image.data;
1217 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1218 if (!buffer) return false;
1220 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1221 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1222 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1223 auto cmp = &cbuffer[span->y * surface->stride + span->x];
1225 if (span->coverage == 255) {
1226 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1227 auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
1228 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1231 auto ialpha = 255 - span->coverage;
1232 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1233 auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
1234 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1235 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1243 static bool _translucentLinearGradientRleInvAlphaMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1245 if (fill->linear.len < FLT_EPSILON) return false;
1247 auto span = rle->spans;
1248 auto cbuffer = surface->compositor->image.data;
1249 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1250 if (!buffer) return false;
1252 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1253 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1254 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1255 auto cmp = &cbuffer[span->y * surface->stride + span->x];
1257 if (span->coverage == 255) {
1258 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1259 auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
1260 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1263 auto ialpha = 255 - span->coverage;
1264 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1265 auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
1266 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1267 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1275 static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1277 if (!rle) return false;
1279 if (surface->compositor) {
1280 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1281 return _translucentLinearGradientRleAlphaMask(surface, rle, fill);
1283 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1284 return _translucentLinearGradientRleInvAlphaMask(surface, rle, fill);
1287 return _translucentLinearGradientRle(surface, rle, fill);
1291 static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1293 if (fill->linear.len < FLT_EPSILON) return false;
1295 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1296 if (!buf) return false;
1298 auto span = rle->spans;
1300 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1301 if (span->coverage == 255) {
1302 fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len);
1304 fillFetchLinear(fill, buf, span->y, span->x, span->len);
1305 auto ialpha = 255 - span->coverage;
1306 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1307 for (uint32_t i = 0; i < span->len; ++i) {
1308 dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
1316 static bool _translucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1318 if (fill->radial.a < FLT_EPSILON) return false;
1320 auto span = rle->spans;
1321 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1322 if (!buffer) return false;
1324 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1325 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1326 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1327 if (span->coverage == 255) {
1328 for (uint32_t i = 0; i < span->len; ++i) {
1329 dst[i] = buffer[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buffer[i]));
1332 for (uint32_t i = 0; i < span->len; ++i) {
1333 auto tmp = ALPHA_BLEND(buffer[i], span->coverage);
1334 dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp));
1342 static bool _translucentRadialGradientRleAlphaMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1344 if (fill->radial.a < FLT_EPSILON) return false;
1346 auto span = rle->spans;
1347 auto cbuffer = surface->compositor->image.data;
1348 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1349 if (!buffer) return false;
1351 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1352 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1353 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1354 auto cmp = &cbuffer[span->y * surface->stride + span->x];
1356 if (span->coverage == 255) {
1357 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1358 auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
1359 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1362 auto ialpha = 255 - span->coverage;
1363 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1364 auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
1365 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1366 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1374 static bool _translucentRadialGradientRleInvAlphaMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1376 if (fill->radial.a < FLT_EPSILON) return false;
1378 auto span = rle->spans;
1379 auto cbuffer = surface->compositor->image.data;
1380 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1381 if (!buffer) return false;
1383 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1384 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1385 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1386 auto cmp = &cbuffer[span->y * surface->stride + span->x];
1388 if (span->coverage == 255) {
1389 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1390 auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
1391 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1394 auto ialpha = 255 - span->coverage;
1395 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1396 auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
1397 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1398 *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
1406 static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1408 if (!rle) return false;
1410 if (surface->compositor) {
1411 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1412 return _translucentRadialGradientRleAlphaMask(surface, rle, fill);
1414 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1415 return _translucentRadialGradientRleInvAlphaMask(surface, rle, fill);
1418 return _translucentRadialGradientRle(surface, rle, fill);
1422 static bool _rasterOpaqueRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1424 if (fill->radial.a < FLT_EPSILON) return false;
1426 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1427 if (!buf) return false;
1429 auto span = rle->spans;
1431 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1432 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1433 if (span->coverage == 255) {
1434 fillFetchRadial(fill, dst, span->y, span->x, span->len);
1436 fillFetchRadial(fill, buf, span->y, span->x, span->len);
1437 auto ialpha = 255 - span->coverage;
1438 for (uint32_t i = 0; i < span->len; ++i) {
1439 dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
1447 /************************************************************************/
1448 /* External Class Implementation */
1449 /************************************************************************/
1451 void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
1453 #if defined(THORVG_AVX_VECTOR_SUPPORT)
1454 avxRasterRGBA32(dst, val, offset, len);
1455 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
1456 neonRasterRGBA32(dst, val, offset, len);
1458 cRasterRGBA32(dst, val, offset, len);
1463 bool rasterCompositor(SwSurface* surface)
1465 if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
1466 surface->blender.alpha = _colorAlpha;
1467 surface->blender.join = _abgrJoin;
1468 } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
1469 surface->blender.alpha = _colorAlpha;
1470 surface->blender.join = _argbJoin;
1472 //What Color Space ???
1480 bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
1482 if (!shape->fill) return false;
1484 auto translucent = shape->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None);
1487 if (shape->fastTrack) {
1488 if (id == TVG_CLASS_ID_LINEAR) {
1489 if (translucent) return _rasterTranslucentLinearGradientRect(surface, shape->bbox, shape->fill);
1490 return _rasterOpaqueLinearGradientRect(surface, shape->bbox, shape->fill);
1492 if (translucent) return _rasterTranslucentRadialGradientRect(surface, shape->bbox, shape->fill);
1493 return _rasterOpaqueRadialGradientRect(surface, shape->bbox, shape->fill);
1496 if (!shape->rle) return false;
1497 if (id == TVG_CLASS_ID_LINEAR) {
1498 if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->rle, shape->fill);
1499 return _rasterOpaqueLinearGradientRle(surface, shape->rle, shape->fill);
1501 if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->rle, shape->fill);
1502 return _rasterOpaqueRadialGradientRle(surface, shape->rle, shape->fill);
1509 bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1512 r = ALPHA_MULTIPLY(r, a);
1513 g = ALPHA_MULTIPLY(g, a);
1514 b = ALPHA_MULTIPLY(b, a);
1517 auto color = surface->blender.join(r, g, b, a);
1518 auto translucent = _translucent(surface, a);
1521 if (shape->fastTrack) {
1522 if (translucent) return _rasterTranslucentRect(surface, shape->bbox, color);
1523 return _rasterSolidRect(surface, shape->bbox, color);
1526 return _rasterTranslucentRle(surface, shape->rle, color);
1528 return _rasterSolidRle(surface, shape->rle, color);
1532 bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1535 r = ALPHA_MULTIPLY(r, a);
1536 g = ALPHA_MULTIPLY(g, a);
1537 b = ALPHA_MULTIPLY(b, a);
1540 auto color = surface->blender.join(r, g, b, a);
1541 auto translucent = _translucent(surface, a);
1543 if (translucent) return _rasterTranslucentRle(surface, shape->strokeRle, color);
1544 return _rasterSolidRle(surface, shape->strokeRle, color);
1548 bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
1550 if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
1552 auto translucent = shape->stroke->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None);
1554 if (id == TVG_CLASS_ID_LINEAR) {
1555 if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1556 return _rasterOpaqueLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1558 if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1559 return _rasterOpaqueRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1566 bool rasterClear(SwSurface* surface)
1568 if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false;
1570 if (surface->w == surface->stride) {
1571 rasterRGBA32(surface->buffer, 0x00000000, 0, surface->w * surface->h);
1573 for (uint32_t i = 0; i < surface->h; i++) {
1574 rasterRGBA32(surface->buffer + surface->stride * i, 0x00000000, 0, surface->w);
1581 void rasterUnpremultiply(SwSurface* surface)
1583 //TODO: Create simd avx and neon version
1584 for (uint32_t y = 0; y < surface->h; y++) {
1585 auto buffer = surface->buffer + surface->stride * y;
1586 for (uint32_t x = 0; x < surface->w; ++x) {
1587 uint8_t a = buffer[x] >> 24;
1590 } else if (a == 0) {
1591 buffer[x] = 0x00ffffff;
1593 uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
1594 uint16_t g = ((buffer[x]) & 0xff00) / a;
1595 uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
1596 if (r > 0xff) r = 0xff;
1597 if (g > 0xff) g = 0xff;
1598 if (b > 0xff) b = 0xff;
1599 buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
1606 bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
1608 Matrix invTransform;
1609 float scaling = 1.0f;
1612 if (!mathInverse(transform, &invTransform)) return false;
1613 scaling = sqrtf((transform->e11 * transform->e11) + (transform->e21 * transform->e21));
1614 auto scalingY = sqrtf((transform->e22 * transform->e22) + (transform->e12 * transform->e12));
1615 //TODO:If the x and y axis scaling is different, a separate algorithm for each axis should be applied.
1616 if (scaling != scalingY) scaling = 1.0f;
1618 else invTransform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
1620 auto translucent = _translucent(surface, opacity);
1621 const float downScalingFactor = 0.5f;
1625 if (mathIdentity(transform)) {
1626 //OPTIMIZE ME: Support non transformed image. Only shifted image can use these routines.
1627 if (translucent) return _rasterTranslucentImageRle(surface, image->rle, image->data, image->w, image->h, opacity);
1628 return _rasterImageRle(surface, image->rle, image->data, image->w, image->h);
1631 if (fabsf(scaling - 1.0f) <= FLT_EPSILON) return _rasterTranslucentImageRle(surface, image->rle, image->data, image->w, image->h, opacity, &invTransform);
1632 else if (scaling < downScalingFactor) return _rasterTranslucentDownScaleImageRle(surface, image->rle, image->data, image->w, image->h, opacity, &invTransform, scaling);
1633 else return _rasterTranslucentUpScaleImageRle(surface, image->rle, image->data, image->w, image->h, opacity, &invTransform);
1635 if (fabsf(scaling - 1.0f) <= FLT_EPSILON) return _rasterImageRle(surface, image->rle, image->data, image->w, image->h, &invTransform);
1636 else if (scaling < downScalingFactor) return _rasterDownScaleImageRle(surface, image->rle, image->data, image->w, image->h, &invTransform, scaling);
1637 else return _rasterUpScaleImageRle(surface, image->rle, image->data, image->w, image->h, &invTransform);
1642 if (mathIdentity(transform)) {
1643 //OPTIMIZE ME: Support non transformed image. Only shifted image can use these routines.
1644 if (translucent) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox);
1645 return _rasterImage(surface, image->data, image->w, image->h, bbox);
1648 if (fabsf(scaling - 1.0f) <= FLT_EPSILON) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox, &invTransform);
1649 else if (scaling < downScalingFactor) return _rasterTranslucentDownScaleImage(surface, image->data, image->w, image->h, opacity, bbox, &invTransform, scaling);
1650 else return _rasterTranslucentUpScaleImage(surface, image->data, image->w, image->h, opacity, bbox, &invTransform);
1652 if (fabsf(scaling - 1.0f) <= FLT_EPSILON) return _rasterImage(surface, image->data, image->w, image->h, bbox, &invTransform);
1653 else if (scaling < downScalingFactor) return _rasterDownScaleImage(surface, image->data, image->w, image->h, bbox, &invTransform, scaling);
1654 else return _rasterUpScaleImage(surface, image->data, image->w, image->h, bbox, &invTransform);