sw_engine: proper linear gradient transformation

In the case of any shape transformation, the gradient fill
was not correct.
This commit is contained in:
Mira Grudzinska 2021-09-18 00:33:32 +02:00 committed by Hermet Park
parent 664e95859c
commit 7b778cd878
4 changed files with 42 additions and 36 deletions

View file

@ -299,6 +299,7 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw
SwFixed mathMean(SwFixed angle1, SwFixed angle2);
SwPoint mathTransform(const Point* to, const Matrix* transform);
bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion);
bool mathInverse(const Matrix* m, Matrix* invM);
void shapeReset(SwShape* shape);
bool shapePrepare(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);

View file

@ -106,15 +106,6 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr
float x1, x2, y1, y2;
if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false;
if (transform) {
auto t1 = x1;
x1 = t1 * transform->e11 + y1 * transform->e12 + transform->e13;
y1 = t1 * transform->e21 + y1 * transform->e22 + transform->e23;
auto t2 = x2;
x2 = t2 * transform->e11 + y2 * transform->e12 + transform->e13;
y2 = t2 * transform->e21 + y2 * transform->e22 + transform->e23;
}
fill->linear.dx = x2 - x1;
fill->linear.dy = y2 - y1;
fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy;
@ -123,7 +114,21 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr
fill->linear.dx /= fill->linear.len;
fill->linear.dy /= fill->linear.len;
fill->linear.offset = -fill->linear.dx * x1 -fill->linear.dy * y1;
fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1;
if (transform) {
Matrix invTransform;
if (!mathInverse(transform, &invTransform)) return false;
fill->linear.offset += fill->linear.dx * invTransform.e13 + fill->linear.dy * invTransform.e23;
auto dx = fill->linear.dx;
fill->linear.dx = dx * invTransform.e11 + fill->linear.dy * invTransform.e21;
fill->linear.dy = dx * invTransform.e12 + fill->linear.dy * invTransform.e22;
fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy;
if (fill->linear.len < FLT_EPSILON) return true;
}
return true;
}

View file

@ -20,6 +20,7 @@
* SOFTWARE.
*/
#include <math.h>
#include <float.h>
#include "tvgSwCommon.h"
@ -485,3 +486,27 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S
return true;
}
bool mathInverse(const Matrix* m, Matrix* invM)
{
auto det = m->e11 * (m->e22 * m->e33 - m->e32 * m->e23) -
m->e12 * (m->e21 * m->e33 - m->e23 * m->e31) +
m->e13 * (m->e21 * m->e32 - m->e22 * m->e31);
if (fabsf(det) < FLT_EPSILON) return false;
auto invDet = 1 / det;
invM->e11 = (m->e22 * m->e33 - m->e32 * m->e23) * invDet;
invM->e12 = (m->e13 * m->e32 - m->e12 * m->e33) * invDet;
invM->e13 = (m->e12 * m->e23 - m->e13 * m->e22) * invDet;
invM->e21 = (m->e23 * m->e31 - m->e21 * m->e33) * invDet;
invM->e22 = (m->e11 * m->e33 - m->e13 * m->e31) * invDet;
invM->e23 = (m->e21 * m->e13 - m->e11 * m->e23) * invDet;
invM->e31 = (m->e21 * m->e32 - m->e31 * m->e22) * invDet;
invM->e32 = (m->e31 * m->e12 - m->e11 * m->e32) * invDet;
invM->e33 = (m->e11 * m->e22 - m->e21 * m->e12) * invDet;
return true;
}

View file

@ -49,31 +49,6 @@ static uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
}
static bool _inverse(const Matrix* transform, Matrix* invM)
{
//computes the inverse of a matrix m
auto det = transform->e11 * (transform->e22 * transform->e33 - transform->e32 * transform->e23) -
transform->e12 * (transform->e21 * transform->e33 - transform->e23 * transform->e31) +
transform->e13 * (transform->e21 * transform->e32 - transform->e22 * transform->e31);
if (fabsf(det) < FLT_EPSILON) return false;
auto invDet = 1 / det;
invM->e11 = (transform->e22 * transform->e33 - transform->e32 * transform->e23) * invDet;
invM->e12 = (transform->e13 * transform->e32 - transform->e12 * transform->e33) * invDet;
invM->e13 = (transform->e12 * transform->e23 - transform->e13 * transform->e22) * invDet;
invM->e21 = (transform->e23 * transform->e31 - transform->e21 * transform->e33) * invDet;
invM->e22 = (transform->e11 * transform->e33 - transform->e13 * transform->e31) * invDet;
invM->e23 = (transform->e21 * transform->e13 - transform->e11 * transform->e23) * invDet;
invM->e31 = (transform->e21 * transform->e32 - transform->e31 * transform->e22) * invDet;
invM->e32 = (transform->e31 * transform->e12 - transform->e11 * transform->e32) * invDet;
invM->e33 = (transform->e11 * transform->e22 - transform->e21 * transform->e12) * invDet;
return true;
}
static bool _identify(const Matrix* transform)
{
if (transform) {
@ -1560,7 +1535,7 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, co
float scaling = 1.0f;
if (transform) {
if (!_inverse(transform, &invTransform)) return false;
if (!mathInverse(transform, &invTransform)) return false;
scaling = sqrtf((transform->e11 * transform->e11) + (transform->e21 * transform->e21));
auto scalingY = sqrtf((transform->e22 * transform->e22) + (transform->e12 * transform->e12));
//TODO:If the x and y axis scaling is different, a separate algorithm for each axis should be applied.