From ce3c11838c212315670441838aa3ab7fe46a51e4 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Mon, 4 Sep 2023 16:14:33 +0900 Subject: [PATCH] renderer/sw_engine: support the focal property in the radial gradient. @Issue: https://github.com/thorvg/thorvg/issues/1558 --- src/renderer/meson.build | 2 - src/renderer/sw_engine/tvgSwCommon.h | 9 +- src/renderer/sw_engine/tvgSwFill.cpp | 304 +++++++++++++++++-------- src/renderer/sw_engine/tvgSwRaster.cpp | 5 +- src/renderer/tvgFill.cpp | 134 +++++++++++ src/renderer/tvgFill.h | 23 ++ src/renderer/tvgLinearGradient.cpp | 100 -------- src/renderer/tvgRadialGradient.cpp | 98 -------- 8 files changed, 369 insertions(+), 306 deletions(-) delete mode 100644 src/renderer/tvgLinearGradient.cpp delete mode 100644 src/renderer/tvgRadialGradient.cpp diff --git a/src/renderer/meson.build b/src/renderer/meson.build index 521b3a1a..d982291e 100644 --- a/src/renderer/meson.build +++ b/src/renderer/meson.build @@ -29,11 +29,9 @@ source_file = [ 'tvgFill.cpp', 'tvgGlCanvas.cpp', 'tvgInitializer.cpp', - 'tvgLinearGradient.cpp', 'tvgLoader.cpp', 'tvgPaint.cpp', 'tvgPicture.cpp', - 'tvgRadialGradient.cpp', 'tvgRender.cpp', 'tvgSaver.cpp', 'tvgScene.cpp', diff --git a/src/renderer/sw_engine/tvgSwCommon.h b/src/renderer/sw_engine/tvgSwCommon.h index c8a615fb..7d246688 100644 --- a/src/renderer/sw_engine/tvgSwCommon.h +++ b/src/renderer/sw_engine/tvgSwCommon.h @@ -139,10 +139,11 @@ struct SwFill }; struct SwRadial { - float a11, a12, shiftX; - float a21, a22, shiftY; - float detSecDeriv; - float a; + float a11, a12, a13; + float a21, a22, a23; + float fx, fy, fr; + float dx, dy, dr; + float invA, a; }; union { diff --git a/src/renderer/sw_engine/tvgSwFill.cpp b/src/renderer/sw_engine/tvgSwFill.cpp index ca4116a3..94ea7cbb 100644 --- a/src/renderer/sw_engine/tvgSwFill.cpp +++ b/src/renderer/sw_engine/tvgSwFill.cpp @@ -22,7 +22,7 @@ #include "tvgMath.h" #include "tvgSwCommon.h" - +#include "tvgFill.h" /************************************************************************/ /* Internal Class Implementation */ @@ -32,6 +32,35 @@ #define FIXPT_BITS 8 #define FIXPT_SIZE (1<radial.a + * B = 2 * (dr * fr + rx * dx + ry * dy) + * C = fr^2 - rx^2 - ry^2 + * Derivatives are computed with respect to dx. + * This procedure aims to optimize and eliminate the need to calculate all values from the beginning + * for consecutive x values with a constant y. The Taylor series expansions are computed as long as + * its terms are non-zero. + */ +static void _calculateCoefficients(const SwFill* fill, uint32_t x, uint32_t y, float& b, float& deltaB, float& det, float& deltaDet, float& deltaDeltaDet) +{ + auto radial = &fill->radial; + + auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx; + auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy; + + b = (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy) * radial->invA; + deltaB = (radial->a11 * radial->dx + radial->a21 * radial->dy) * radial->invA; + + auto rr = rx * rx + ry * ry; + auto deltaRr = 2.0f * (rx * radial->a11 + ry * radial->a21) * radial->invA; + auto deltaDeltaRr = 2.0f * (radial->a11 * radial->a11 + radial->a21 * radial->a21) * radial->invA; + + det = b * b + (rr - radial->fr * radial->fr) * radial->invA; + deltaDet = 2.0f * b * deltaB + deltaB * deltaB + deltaRr + deltaDeltaRr; + deltaDeltaDet = 2.0f * deltaB * deltaB + deltaDeltaRr; +} + static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* surface, uint8_t opacity) { @@ -146,14 +175,36 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* transform) { - float radius, cx, cy; - if (radial->radial(&cx, &cy, &radius) != Result::Success) return false; - if (radius < FLT_EPSILON) return true; + auto cx = P(radial)->cx; + auto cy = P(radial)->cy; + auto r = P(radial)->r; + auto fx = P(radial)->fx; + auto fy = P(radial)->fy; + auto fr = P(radial)->fr; - float invR = 1.0f / radius; - fill->radial.shiftX = -cx; - fill->radial.shiftY = -cy; - fill->radial.a = radius; + if (r < FLT_EPSILON) return true; + + fill->radial.dr = r - fr; + fill->radial.dx = cx - fx; + fill->radial.dy = cy - fy; + fill->radial.fr = fr; + fill->radial.fx = fx; + fill->radial.fy = fy; + fill->radial.a = fill->radial.dr * fill->radial.dr - fill->radial.dx * fill->radial.dx - fill->radial.dy * fill->radial.dy; + + //This condition fulfills the SVG 1.1 std: + //the focal point, if outside the end circle, is moved to be on the end circle + //See: the SVG 2 std requirements: https://www.w3.org/TR/SVG2/pservers.html#RadialGradientNotes + if (fill->radial.a < 0) { + auto dist = sqrtf(fill->radial.dx * fill->radial.dx + fill->radial.dy * fill->radial.dy); + fill->radial.fx = cx + r * (fx - cx) / dist; + fill->radial.fy = cy + r * (fy - cy) / dist; + fill->radial.dx = cx - fill->radial.fx; + fill->radial.dy = cy - fill->radial.fy; + fill->radial.a = fill->radial.dr * fill->radial.dr - fill->radial.dx * fill->radial.dx - fill->radial.dy * fill->radial.dy; + } + + if (fill->radial.a > FLT_EPSILON) fill->radial.invA = 1.0f / fill->radial.a; auto gradTransform = radial->transform(); bool isTransformation = !mathIdentity((const Matrix*)(&gradTransform)); @@ -169,22 +220,17 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr Matrix invTransform; if (!mathInverse(&gradTransform, &invTransform)) return false; - fill->radial.a11 = invTransform.e11 * invR; - fill->radial.a12 = invTransform.e12 * invR; - fill->radial.shiftX += invTransform.e13; - fill->radial.a21 = invTransform.e21 * invR; - fill->radial.a22 = invTransform.e22 * invR; - fill->radial.shiftY += invTransform.e23; - fill->radial.detSecDeriv = 2.0f * fill->radial.a11 * fill->radial.a11 + 2 * fill->radial.a21 * fill->radial.a21; - - fill->radial.a *= sqrt(pow(invTransform.e11, 2) + pow(invTransform.e21, 2)); + fill->radial.a11 = invTransform.e11; + fill->radial.a12 = invTransform.e12; + fill->radial.a13 = invTransform.e13; + fill->radial.a21 = invTransform.e21; + fill->radial.a22 = invTransform.e22; + fill->radial.a23 = invTransform.e23; } else { - fill->radial.a11 = fill->radial.a22 = invR; - fill->radial.a12 = fill->radial.a21 = 0.0f; - fill->radial.detSecDeriv = 2.0f * invR * invR; + fill->radial.a11 = fill->radial.a22 = 1.0f; + fill->radial.a12 = fill->radial.a13 = 0.0f; + fill->radial.a21 = fill->radial.a23 = 0.0f; } - fill->radial.shiftX *= invR; - fill->radial.shiftY *= invR; return true; } @@ -235,26 +281,45 @@ static inline uint32_t _pixel(const SwFill* fill, float pos) void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity) { - auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX; - auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY; + //edge case + if (fill->radial.a < FLT_EPSILON) { + auto radial = &fill->radial; + auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx; + auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy; - // detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx - auto detSecondDerivative = fill->radial.detSecDeriv; - // detFirstDerivative = d(det)/dx - auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative; - auto det = rx * rx + ry * ry; - - if (opacity == 255) { - for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) { - *dst = opBlendNormal(_pixel(fill, sqrtf(det)), *dst, alpha(cmp)); - det += detFirstDerivative; - detFirstDerivative += detSecondDerivative; + if (opacity == 255) { + for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) { + auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy); + *dst = opBlendNormal(_pixel(fill, x0), *dst, alpha(cmp)); + rx += radial->a11; + ry += radial->a21; + } + } else { + for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) { + auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy); + *dst = opBlendNormal(_pixel(fill, x0), *dst, MULTIPLY(opacity, alpha(cmp))); + rx += radial->a11; + ry += radial->a21; + } } } else { - for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) { - *dst = opBlendNormal(_pixel(fill, sqrtf(det)), *dst, MULTIPLY(opacity, alpha(cmp))); - det += detFirstDerivative; - detFirstDerivative += detSecondDerivative; + float b, deltaB, det, deltaDet, deltaDeltaDet; + _calculateCoefficients(fill, x, y, b, deltaB, det, deltaDet, deltaDeltaDet); + + if (opacity == 255) { + for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) { + *dst = opBlendNormal(_pixel(fill, sqrtf(det) - b), *dst, alpha(cmp)); + det += deltaDet; + deltaDet += deltaDeltaDet; + b += deltaB; + } + } else { + for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) { + *dst = opBlendNormal(_pixel(fill, sqrtf(det) - b), *dst, MULTIPLY(opacity, alpha(cmp))); + det += deltaDet; + deltaDet += deltaDeltaDet; + b += deltaB; + } } } } @@ -262,89 +327,132 @@ void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a) { - auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX; - auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY; + if (fill->radial.a < FLT_EPSILON) { + auto radial = &fill->radial; + auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx; + auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy; + for (uint32_t i = 0; i < len; ++i, ++dst) { + auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy); + *dst = op(_pixel(fill, x0), *dst, a); + rx += radial->a11; + ry += radial->a21; + } + } else { + float b, deltaB, det, deltaDet, deltaDeltaDet; + _calculateCoefficients(fill, x, y, b, deltaB, det, deltaDet, deltaDeltaDet); - // detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx - auto detSecondDerivative = fill->radial.detSecDeriv; - // detFirstDerivative = d(det)/dx - auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative; - auto det = rx * rx + ry * ry; - - for (uint32_t i = 0 ; i < len ; ++i, ++dst) { - *dst = op(_pixel(fill, sqrtf(det)), *dst, a); - det += detFirstDerivative; - detFirstDerivative += detSecondDerivative; + for (uint32_t i = 0; i < len; ++i, ++dst) { + *dst = op(_pixel(fill, sqrtf(det) - b), *dst, a); + det += deltaDet; + deltaDet += deltaDeltaDet; + b += deltaB; + } } } void fillRadial(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, SwMask maskOp, uint8_t a) { - auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX; - auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY; + if (fill->radial.a < FLT_EPSILON) { + auto radial = &fill->radial; + auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx; + auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy; + for (uint32_t i = 0 ; i < len ; ++i, ++dst) { + auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy); + auto src = MULTIPLY(a, A(_pixel(fill, x0))); + *dst = maskOp(src, *dst, ~src); + rx += radial->a11; + ry += radial->a21; + } + } else { + float b, deltaB, det, deltaDet, deltaDeltaDet; + _calculateCoefficients(fill, x, y, b, deltaB, det, deltaDet, deltaDeltaDet); - // detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx - auto detSecondDerivative = fill->radial.detSecDeriv; - // detFirstDerivative = d(det)/dx - auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative; - auto det = rx * rx + ry * ry; - - for (uint32_t i = 0 ; i < len ; ++i, ++dst) { - auto src = MULTIPLY(a, A(_pixel(fill, sqrtf(det)))); - *dst = maskOp(src, *dst, ~src); - det += detFirstDerivative; - detFirstDerivative += detSecondDerivative; + for (uint32_t i = 0 ; i < len ; ++i, ++dst) { + auto src = MULTIPLY(a, A(_pixel(fill, sqrtf(det) - b))); + *dst = maskOp(src, *dst, ~src); + det += deltaDet; + deltaDet += deltaDeltaDet; + b += deltaB; + } } } void fillRadial(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwMask maskOp, uint8_t a) { - auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX; - auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY; + if (fill->radial.a < FLT_EPSILON) { + auto radial = &fill->radial; + auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx; + auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy; + for (uint32_t i = 0 ; i < len ; ++i, ++dst, ++cmp) { + auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy); + auto src = MULTIPLY(A(A(_pixel(fill, x0))), a); + auto tmp = maskOp(src, *cmp, 0); + *dst = tmp + MULTIPLY(*dst, ~tmp); + rx += radial->a11; + ry += radial->a21; + } + } else { + float b, deltaB, det, deltaDet, deltaDeltaDet; + _calculateCoefficients(fill, x, y, b, deltaB, det, deltaDet, deltaDeltaDet); - // detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx - auto detSecondDerivative = fill->radial.detSecDeriv; - // detFirstDerivative = d(det)/dx - auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative; - auto det = rx * rx + ry * ry; - - for (uint32_t i = 0 ; i < len ; ++i, ++dst, ++cmp) { - auto src = MULTIPLY(A(_pixel(fill, sqrtf(det))), a); - auto tmp = maskOp(src, *cmp, 0); - *dst = tmp + MULTIPLY(*dst, ~tmp); - det += detFirstDerivative; - detFirstDerivative += detSecondDerivative; + for (uint32_t i = 0 ; i < len ; ++i, ++dst, ++cmp) { + auto src = MULTIPLY(A(_pixel(fill, sqrtf(det))), a); + auto tmp = maskOp(src, *cmp, 0); + *dst = tmp + MULTIPLY(*dst, ~tmp); + deltaDet += deltaDeltaDet; + b += deltaB; + } } } void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a) { - auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX; - auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY; + if (fill->radial.a < FLT_EPSILON) { + auto radial = &fill->radial; + auto rx = (x + 0.5f) * radial->a11 + (y + 0.5f) * radial->a12 + radial->a13 - radial->fx; + auto ry = (x + 0.5f) * radial->a21 + (y + 0.5f) * radial->a22 + radial->a23 - radial->fy; - // detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx - auto detSecondDerivative = fill->radial.detSecDeriv; - // detFirstDerivative = d(det)/dx - auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative; - auto det = rx * rx + ry * ry; - - if (a == 255) { - for (uint32_t i = 0 ; i < len ; ++i, ++dst) { - auto tmp = op(_pixel(fill, sqrtf(det)), *dst, 255); - *dst = op2(tmp, *dst, 255); - det += detFirstDerivative; - detFirstDerivative += detSecondDerivative; + if (a == 255) { + for (uint32_t i = 0; i < len; ++i, ++dst) { + auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy); + auto tmp = op(_pixel(fill, x0), *dst, 255); + *dst = op2(tmp, *dst, 255); + rx += radial->a11; + ry += radial->a21; + } + } else { + for (uint32_t i = 0; i < len; ++i, ++dst) { + auto x0 = 0.5f * (rx * rx + ry * ry - radial->fr * radial->fr) / (radial->dr * radial->fr + rx * radial->dx + ry * radial->dy); + auto tmp = op(_pixel(fill, x0), *dst, 255); + auto tmp2 = op2(tmp, *dst, 255); + *dst = INTERPOLATE(tmp2, *dst, a); + rx += radial->a11; + ry += radial->a21; + } } } else { - for (uint32_t i = 0 ; i < len ; ++i, ++dst) { - auto tmp = op(_pixel(fill, sqrtf(det)), *dst, 255); - auto tmp2 = op2(tmp, *dst, 255); - *dst = INTERPOLATE(tmp2, *dst, a); - det += detFirstDerivative; - detFirstDerivative += detSecondDerivative; + float b, deltaB, det, deltaDet, deltaDeltaDet; + _calculateCoefficients(fill, x, y, b, deltaB, det, deltaDet, deltaDeltaDet); + if (a == 255) { + for (uint32_t i = 0 ; i < len ; ++i, ++dst) { + auto tmp = op(_pixel(fill, sqrtf(det) - b), *dst, 255); + *dst = op2(tmp, *dst, 255); + det += deltaDet; + deltaDet += deltaDeltaDet; + b += deltaB; + } + } else { + for (uint32_t i = 0 ; i < len ; ++i, ++dst) { + auto tmp = op(_pixel(fill, sqrtf(det) - b), *dst, 255); + auto tmp2 = op2(tmp, *dst, 255); + *dst = INTERPOLATE(tmp2, *dst, a); + det += deltaDet; + deltaDet += deltaDeltaDet; + b += deltaB; + } } } } diff --git a/src/renderer/sw_engine/tvgSwRaster.cpp b/src/renderer/sw_engine/tvgSwRaster.cpp index 2a440fb2..60054d42 100644 --- a/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/src/renderer/sw_engine/tvgSwRaster.cpp @@ -1595,8 +1595,6 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { - if (fill->radial.a < FLT_EPSILON) return false; - if (_compositing(surface)) { if (_matting(surface)) return _rasterGradientMattedRect(surface, region, fill); else return _rasterGradientMaskedRect(surface, region, fill); @@ -1610,7 +1608,6 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, } - /************************************************************************/ /* Rle Gradient */ /************************************************************************/ @@ -1741,7 +1738,7 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { - if (!rle || fill->radial.a < FLT_EPSILON) return false; + if (!rle) return false; if (_compositing(surface)) { if (_matting(surface)) return _rasterGradientMattedRle(surface, rle, fill); diff --git a/src/renderer/tvgFill.cpp b/src/renderer/tvgFill.cpp index cc7e1cca..9215882c 100644 --- a/src/renderer/tvgFill.cpp +++ b/src/renderer/tvgFill.cpp @@ -26,6 +26,50 @@ /* Internal Class Implementation */ /************************************************************************/ +Fill* RadialGradient::Impl::duplicate() +{ + auto ret = RadialGradient::gen(); + if (!ret) return nullptr; + + ret->pImpl->cx = cx; + ret->pImpl->cy = cy; + ret->pImpl->r = r; + ret->pImpl->fx = fx; + ret->pImpl->fy = fy; + ret->pImpl->fr = fr; + + return ret.release(); +} + + +Result RadialGradient::Impl::radial(float cx, float cy, float r, float fx, float fy, float fr) +{ + if (r < 0 || fr < 0) return Result::InvalidArguments; + + this->cx = cx; + this->cy = cy; + this->r = r; + this->fx = fx; + this->fy = fy; + this->fr = fr; + + return Result::Success; +}; + + +Fill* LinearGradient::Impl::duplicate() +{ + auto ret = LinearGradient::gen(); + if (!ret) return nullptr; + + ret->pImpl->x1 = x1; + ret->pImpl->y1 = y1; + ret->pImpl->x2 = x2; + ret->pImpl->y2 = y2; + + return ret.release(); +}; + /************************************************************************/ /* External Class Implementation */ @@ -110,7 +154,97 @@ Fill* Fill::duplicate() const noexcept return pImpl->duplicate(); } + uint32_t Fill::identifier() const noexcept { return pImpl->id; } + + +RadialGradient::RadialGradient():pImpl(new Impl()) +{ + Fill::pImpl->id = TVG_CLASS_ID_RADIAL; + Fill::pImpl->method(new FillDup(pImpl)); +} + + +RadialGradient::~RadialGradient() +{ + delete(pImpl); +} + + +Result RadialGradient::radial(float cx, float cy, float r) noexcept +{ + return pImpl->radial(cx, cy, r, cx, cy, 0.0f); +} + + +Result RadialGradient::radial(float* cx, float* cy, float* r) const noexcept +{ + if (cx) *cx = pImpl->cx; + if (cy) *cy = pImpl->cy; + if (r) *r = pImpl->r; + + return Result::Success; +} + + +unique_ptr RadialGradient::gen() noexcept +{ + return unique_ptr(new RadialGradient); +} + + +uint32_t RadialGradient::identifier() noexcept +{ + return TVG_CLASS_ID_RADIAL; +} + + +LinearGradient::LinearGradient():pImpl(new Impl()) +{ + Fill::pImpl->id = TVG_CLASS_ID_LINEAR; + Fill::pImpl->method(new FillDup(pImpl)); +} + + +LinearGradient::~LinearGradient() +{ + delete(pImpl); +} + + +Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept +{ + pImpl->x1 = x1; + pImpl->y1 = y1; + pImpl->x2 = x2; + pImpl->y2 = y2; + + return Result::Success; +} + + +Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const noexcept +{ + if (x1) *x1 = pImpl->x1; + if (x2) *x2 = pImpl->x2; + if (y1) *y1 = pImpl->y1; + if (y2) *y2 = pImpl->y2; + + return Result::Success; +} + + +unique_ptr LinearGradient::gen() noexcept +{ + return unique_ptr(new LinearGradient); +} + + +uint32_t LinearGradient::identifier() noexcept +{ + return TVG_CLASS_ID_LINEAR; +} + diff --git a/src/renderer/tvgFill.h b/src/renderer/tvgFill.h index 20603b73..ff3dd48c 100644 --- a/src/renderer/tvgFill.h +++ b/src/renderer/tvgFill.h @@ -86,4 +86,27 @@ struct Fill::Impl } }; + +struct RadialGradient::Impl +{ + float cx = 0.0f, cy = 0.0f; + float fx = 0.0f, fy = 0.0f; + float r = 0.0f, fr = 0.0f; + + Fill* duplicate(); + Result radial(float cx, float cy, float r, float fx, float fy, float fr); +}; + + +struct LinearGradient::Impl +{ + float x1 = 0.0f; + float y1 = 0.0f; + float x2 = 0.0f; + float y2 = 0.0f; + + Fill* duplicate(); +}; + + #endif //_TVG_FILL_H_ diff --git a/src/renderer/tvgLinearGradient.cpp b/src/renderer/tvgLinearGradient.cpp deleted file mode 100644 index 3e040c08..00000000 --- a/src/renderer/tvgLinearGradient.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include "tvgFill.h" - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -struct LinearGradient::Impl -{ - float x1 = 0; - float y1 = 0; - float x2 = 0; - float y2 = 0; - - Fill* duplicate() - { - auto ret = LinearGradient::gen(); - if (!ret) return nullptr; - - ret->pImpl->x1 = x1; - ret->pImpl->y1 = y1; - ret->pImpl->x2 = x2; - ret->pImpl->y2 = y2; - - return ret.release(); - } -}; - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -LinearGradient::LinearGradient():pImpl(new Impl()) -{ - Fill::pImpl->id = TVG_CLASS_ID_LINEAR; - Fill::pImpl->method(new FillDup(pImpl)); -} - - -LinearGradient::~LinearGradient() -{ - delete(pImpl); -} - - -Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept -{ - pImpl->x1 = x1; - pImpl->y1 = y1; - pImpl->x2 = x2; - pImpl->y2 = y2; - - return Result::Success; -} - - -Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const noexcept -{ - if (x1) *x1 = pImpl->x1; - if (x2) *x2 = pImpl->x2; - if (y1) *y1 = pImpl->y1; - if (y2) *y2 = pImpl->y2; - - return Result::Success; -} - - -unique_ptr LinearGradient::gen() noexcept -{ - return unique_ptr(new LinearGradient); -} - - -uint32_t LinearGradient::identifier() noexcept -{ - return TVG_CLASS_ID_LINEAR; -} diff --git a/src/renderer/tvgRadialGradient.cpp b/src/renderer/tvgRadialGradient.cpp deleted file mode 100644 index a85f60e5..00000000 --- a/src/renderer/tvgRadialGradient.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include "tvgFill.h" - -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -struct RadialGradient::Impl -{ - float cx = 0; - float cy = 0; - float radius = 0; - - Fill* duplicate() - { - auto ret = RadialGradient::gen(); - if (!ret) return nullptr; - - ret->pImpl->cx = cx; - ret->pImpl->cy = cy; - ret->pImpl->radius = radius; - - return ret.release(); - } -}; - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -RadialGradient::RadialGradient():pImpl(new Impl()) -{ - Fill::pImpl->id = TVG_CLASS_ID_RADIAL; - Fill::pImpl->method(new FillDup(pImpl)); -} - - -RadialGradient::~RadialGradient() -{ - delete(pImpl); -} - - -Result RadialGradient::radial(float cx, float cy, float radius) noexcept -{ - if (radius < 0) return Result::InvalidArguments; - - pImpl->cx = cx; - pImpl->cy = cy; - pImpl->radius = radius; - - return Result::Success; -} - - -Result RadialGradient::radial(float* cx, float* cy, float* radius) const noexcept -{ - if (cx) *cx = pImpl->cx; - if (cy) *cy = pImpl->cy; - if (radius) *radius = pImpl->radius; - - return Result::Success; -} - - -unique_ptr RadialGradient::gen() noexcept -{ - return unique_ptr(new RadialGradient); -} - - -uint32_t RadialGradient::identifier() noexcept -{ - return TVG_CLASS_ID_RADIAL; -}