sw_engine raster: ++safety of the scaled image rasterization 92/288392/1 accepted/tizen/unified/20230220.174433
authorHermet Park <chuneon.park@samsung.com>
Fri, 17 Dec 2021 03:43:49 +0000 (12:43 +0900)
committerjykeon <jykeon@samsung.com>
Thu, 16 Feb 2023 05:31:14 +0000 (14:31 +0900)
Prevent out of buffer boundary access.

@Issues: https://github.com/Samsung/thorvg/pull/1119

Change-Id: I9d007b00f4193448fe2fd05194621190144ad7ce

src/lib/sw_engine/tvgSwRaster.cpp
src/lib/sw_engine/tvgSwRasterTexmapInternal.h

index 9ef4cc0..56bc2f7 100644 (file)
@@ -82,8 +82,8 @@ static inline uint32_t _halfScale(float scale)
 //Bilinear Interpolation
 static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, float sx, float sy)
 {
-    auto rx = static_cast<uint32_t>(sx);
-    auto ry = static_cast<uint32_t>(sy);
+    auto rx = (uint32_t)(sx);
+    auto ry = (uint32_t)(sy);
     auto rx2 = rx + 1;
     if (rx2 >= w) rx2 = w - 1;
     auto ry2 = ry + 1;
@@ -102,20 +102,23 @@ static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, flo
 
 
 //2n x 2n Mean Kernel
-static uint32_t _interpDownScaler(const uint32_t *img, uint32_t w, uint32_t h, uint32_t rX, uint32_t rY, uint32_t n)
+static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, uint32_t rx, uint32_t ry, uint32_t n)
 {
-    uint32_t c[4] = { 0 };
+    uint32_t c[4] = {0, 0, 0, 0};
     auto n2 = n * n;
-    auto src = img + rX - n + (rY - n) * w;
-    for (auto y = rY - n; y < rY + n; ++y) {
+    auto src = img + rx - n + (ry - n) * stride;
+
+    for (auto y = ry - n; y < ry + n; ++y) {
+        if (y >= h) continue;
         auto p = src;
-        for (auto x = rX - n; x < rX + n; ++x, ++p) {
+        for (auto x = rx - n; x < rx + n; ++x, ++p) {
+            if (x >= w) continue;
             c[0] += *p >> 24;
             c[1] += (*p >> 16) & 0xff;
             c[2] += (*p >> 8) & 0xff;
             c[3] += *p & 0xff;
         }
-        src += w;
+        src += stride;
     }
     for (auto i = 0; i < 4; ++i) {
         c[i] = (c[i] >> 2) / n2;
@@ -292,15 +295,15 @@ static bool _rasterScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const
     //Center (Down-Scaled)
     if (image->scale < DOWN_SCALE_TOLERANCE) {
         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
-            auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
+            auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
             if (sy >= image->h) continue;
             auto dst = &surface->buffer[span->y * surface->stride + span->x];
             auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
             auto alpha = _multiplyAlpha(span->coverage, opacity);
             for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
-                auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+                auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
                 if (sx >= image->w) continue;
-                auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), alpha);
+                auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
                 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
             }
@@ -308,14 +311,14 @@ static bool _rasterScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const
     //Center (Up-Scaled)
     } else {
         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
-            auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
-            if (sy >= image->h) continue;
+            auto sy = span->y * itransform->e22 + itransform->e23;
+            if ((uint32_t)sy >= image->h) continue;
             auto dst = &surface->buffer[span->y * surface->stride + span->x];
             auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
             auto alpha = _multiplyAlpha(span->coverage, opacity);
             for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
-                auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
-                if (sx >= image->w) continue;
+                auto sx = x * itransform->e11 + itransform->e13;
+                if ((uint32_t)sx >= image->w) continue;
                 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
                 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
                 *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
@@ -335,22 +338,22 @@ static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* i
     //Center (Down-Scaled)
     if (image->scale < DOWN_SCALE_TOLERANCE) {
         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
-            auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
+            auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
             if (sy >= image->h) continue;
             auto dst = &surface->buffer[span->y * surface->stride + span->x];
             auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
             if (span->coverage == 255) {
                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
-                    auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+                    auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
                     if (sx >= image->w) continue;
-                    auto tmp = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
+                    auto tmp = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
                     *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
                 }
             } else {
                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
-                    auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+                    auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
                     if (sx >= image->w) continue;
-                    auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), span->coverage);
+                    auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), span->coverage);
                     auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
                     *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
                 }
@@ -359,21 +362,21 @@ static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* i
     //Center (Up-Scaled)
     } else {
         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
-            auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
-            if (sy >= image->h) continue;
+            auto sy = span->y * itransform->e22 + itransform->e23;
+            if ((uint32_t)sy >= image->h) continue;
             auto dst = &surface->buffer[span->y * surface->stride + span->x];
             auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
             if (span->coverage == 255) {
                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
-                    auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
-                    if (sx >= image->w) continue;
+                    auto sx = x * itransform->e11 + itransform->e13;
+                    if ((uint32_t)sx >= image->w) continue;
                     auto tmp = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
                     *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
                 }
             } else {
                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, ++cmp) {
-                    auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
-                    if (sx >= image->w) continue;
+                    auto sx = x * itransform->e11 + itransform->e13;
+                    if ((uint32_t)sx >= image->w) continue;
                     auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
                     auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
                     *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp));
@@ -392,27 +395,27 @@ static bool _rasterScaledTranslucentRleRGBAImage(SwSurface* surface, const SwIma
     //Center (Down-Scaled)
     if (image->scale < DOWN_SCALE_TOLERANCE) {
         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
-            auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
+            auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
             if (sy >= image->h) continue;
             auto dst = &surface->buffer[span->y * surface->stride + span->x];
             auto alpha = _multiplyAlpha(span->coverage, opacity);
             for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
-                auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+                auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
                 if (sx >= image->w) continue;
-                auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), alpha);
+                auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
             }
         }
     //Center (Up-Scaled)
     } else {
         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
-            auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
-            if (sy >= image->h) continue;
+            auto sy = span->y * itransform->e22 + itransform->e23;
+            if ((uint32_t)sy >= image->h) continue;
             auto dst = &surface->buffer[span->y * surface->stride + span->x];
             auto alpha = _multiplyAlpha(span->coverage, opacity);
             for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
-                auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
-                if (sx >= image->w) continue;
+                auto sx = x * itransform->e11 + itransform->e13;
+                if ((uint32_t)sx >= image->w) continue;
                 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
             }
@@ -429,21 +432,21 @@ static bool _rasterScaledRleRGBAImage(SwSurface* surface, const SwImage* image,
     //Center (Down-Scaled)
     if (image->scale < DOWN_SCALE_TOLERANCE) {
         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
-            auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
+            auto sy = (uint32_t)(span->y * itransform->e22 + itransform->e23);
             if (sy >= image->h) continue;
             auto dst = &surface->buffer[span->y * surface->stride + span->x];
             if (span->coverage == 255) {
                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
-                    auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+                    auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
                     if (sx >= image->w) continue;
-                    auto src = _interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale);
+                    auto src = _interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale);
                     *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
                 }
             } else {
                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
-                    auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
+                    auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
                     if (sx >= image->w) continue;
-                    auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), span->coverage);
+                    auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), span->coverage);
                     *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
                 }
             }
@@ -451,20 +454,20 @@ static bool _rasterScaledRleRGBAImage(SwSurface* surface, const SwImage* image,
     //Center (Up-Scaled)
     } else {
         for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
-            auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
-            if (sy >= image->h) continue;
+            auto sy = span->y * itransform->e22 + itransform->e23;
+            if ((uint32_t)sy >= image->h) continue;
             auto dst = &surface->buffer[span->y * surface->stride + span->x];
             if (span->coverage == 255) {
                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
-                    auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
-                    if (sx >= image->w) continue;
+                    auto sx = x * itransform->e11 + itransform->e13;
+                    if ((uint32_t)sx >= image->w) continue;
                     auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
                     *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
                 }
             } else {
                 for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
-                    auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
-                    if (sx >= image->w) continue;
+                    auto sx = x * itransform->e11 + itransform->e13;
+                    if ((uint32_t)sx >= image->w) continue;
                     auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
                     *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
                 }
@@ -663,13 +666,15 @@ static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const Sw
     // Down-Scaled
     if (image->scale < DOWN_SCALE_TOLERANCE) {
         for (auto y = region.min.y; y < region.max.y; ++y) {
+            auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
+            if (sy >= image->h) continue;
             auto dst = dbuffer;
             auto cmp = cbuffer;
-            auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
             for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
+                auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
+                if (sx >= image->w) continue;
                 auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp));
-                auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
-                auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), alpha);
+                auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), alpha);
                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
             }
             dbuffer += surface->stride;
@@ -678,12 +683,14 @@ static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const Sw
     // Up-Scaled
     } else {
         for (auto y = region.min.y; y < region.max.y; ++y) {
+            auto sy = y * itransform->e22 + itransform->e23;
+            if ((uint32_t)sy >= image->h) continue;
             auto dst = dbuffer;
             auto cmp = cbuffer;
-            auto sy = fabsf(y * itransform->e22 + itransform->e23);
             for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
+                auto sx = x * itransform->e11 + itransform->e13;
+                if ((uint32_t)sx >= image->w) continue;
                 auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp));
-                auto sx = fabsf(x * itransform->e11 + itransform->e13);
                 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
             }
@@ -705,12 +712,14 @@ static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* imag
     // Down-Scaled
     if (image->scale < DOWN_SCALE_TOLERANCE) {
         for (auto y = region.min.y; y < region.max.y; ++y) {
+            auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
+            if (sy >= image->h) continue;
             auto dst = dbuffer;
             auto cmp = cbuffer;
-            auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
             for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
-                auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
-                auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
+                auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
+                if (sx >= image->w) continue;
+                auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
             }
             dbuffer += surface->stride;
@@ -719,11 +728,13 @@ static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* imag
     // Up-Scaled
     } else {
         for (auto y = region.min.y; y < region.max.y; ++y) {
+            auto sy = y * itransform->e22 + itransform->e23;
+            if ((uint32_t)sy >= image->h) continue;
             auto dst = dbuffer;
             auto cmp = cbuffer;
-            auto sy = fabsf(y * itransform->e22 + itransform->e23);
             for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
-                auto sx = fabsf(x * itransform->e11 + itransform->e13);
+                auto sx = x * itransform->e11 + itransform->e13;
+                if ((uint32_t)sx >= image->w) continue;
                 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
             }
@@ -742,11 +753,13 @@ static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage*
     // Down-Scaled
     if (image->scale < DOWN_SCALE_TOLERANCE) {
         for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
-            auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
+            auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
+            if (sy >= image->h) continue;
             auto dst = dbuffer;
             for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
-                auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
-                auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), opacity);
+                auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
+                if (sx >= image->w) continue;
+                auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale), opacity);
                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
             }
         }
@@ -754,9 +767,11 @@ static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage*
     } else {
         for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
             auto sy = fabsf(y * itransform->e22 + itransform->e23);
+            if (sy >= image->h) continue;
             auto dst = dbuffer;
             for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
-                auto sx = fabsf(x * itransform->e11 + itransform->e13);
+                auto sx = x * itransform->e11 + itransform->e13;
+                if ((uint32_t)sx >= image->w) continue;
                 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), opacity);
                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
             }
@@ -773,21 +788,25 @@ static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, con
     // Down-Scaled
     if (image->scale < DOWN_SCALE_TOLERANCE) {
         for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
-            auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
+            auto sy = (uint32_t)(y * itransform->e22 + itransform->e23);
+            if (sy >= image->h) continue;
             auto dst = dbuffer;
             for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
-                auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
-                auto src = _interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale);
+                auto sx = (uint32_t)(x * itransform->e11 + itransform->e13);
+                if (sx >= image->w) continue;
+                auto src = _interpDownScaler(image->data, image->stride, image->w, image->h, sx, sy, halfScale);
                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
             }
         }
     // Up-Scaled
     } else {
         for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
-            auto sy = fabsf(y * itransform->e22 + itransform->e23);
+            auto sy = y * itransform->e22 + itransform->e23;
+            if ((uint32_t)sy >= image->h) continue;
             auto dst = dbuffer;
             for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
-                auto sx = fabsf(x * itransform->e11 + itransform->e13);
+                auto sx = x * itransform->e11 + itransform->e13;
+                if ((uint32_t)sx >= image->w) continue;
                 auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
                 *dst = src + ALPHA_BLEND(*dst, _ialpha(src));
             }
index f7203e1..782c8f6 100644 (file)
@@ -62,7 +62,7 @@
              
         if (x1 < minx) x1 = minx;
         if (x2 > maxx) x2 = maxx;
-            
+
         //Anti-Aliasing frames
         ay = y - aaSpans->yStart;
         if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;