#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint3.h"
#include "include/private/SkFloatBits.h"
#include "include/private/SkNx.h"
#include "include/private/SkTo.h"
#include "src/core/SkMathPriv.h"
#include "src/core/SkMatrixPriv.h"
#include "src/core/SkPathPriv.h"
#include <cstddef>
#include <utility>
namespace pk {
#define PK_LEGACY_MATRIX_MATH_ORDER
SkMatrix& SkMatrix::reset() { *this = SkMatrix(); return *this; }
SkMatrix& SkMatrix::set9(const SkScalar buffer[]) {
memcpy(fMat, buffer, 9 * sizeof(SkScalar));
this->setTypeMask(kUnknown_Mask);
return *this;
}
enum {
kTranslate_Shift,
kScale_Shift,
kAffine_Shift,
kPerspective_Shift,
kRectStaysRect_Shift
};
static const int32_t kScalar1Int = 0x3f800000;
uint8_t SkMatrix::computePerspectiveTypeMask() const {
if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
return SkToU8(kORableMasks);
}
return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask);
}
uint8_t SkMatrix::computeTypeMask() const {
unsigned mask = 0;
if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
return SkToU8(kORableMasks);
}
if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) {
mask |= kTranslate_Mask;
}
int m00 = PkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
int m01 = PkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
int m10 = PkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
int m11 = PkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
if (m01 | m10) {
mask |= kAffine_Mask | kScale_Mask;
m01 = m01 != 0;
m10 = m10 != 0;
int dp0 = 0 == (m00 | m11) ; int ds1 = m01 & m10;
mask |= (dp0 & ds1) << kRectStaysRect_Shift;
} else {
if ((m00 ^ kScalar1Int) | (m11 ^ kScalar1Int)) {
mask |= kScale_Mask;
}
m00 = m00 != 0;
m11 = m11 != 0;
mask |= (m00 & m11) << kRectStaysRect_Shift;
}
return SkToU8(mask);
}
bool operator==(const SkMatrix& a, const SkMatrix& b) {
const SkScalar* PK_RESTRICT ma = a.fMat;
const SkScalar* PK_RESTRICT mb = b.fMat;
return ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] &&
ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] &&
ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
}
static inline bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX,
SkScalar skewY, SkScalar scaleY) {
SkScalar perp_dot = scaleX*scaleY - skewX*skewY;
return SkScalarNearlyZero(perp_dot, PK_ScalarNearlyZero*PK_ScalarNearlyZero);
}
static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
return a * b + c * d;
}
static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d,
SkScalar e, SkScalar f) {
return a * b + c * d + e * f;
}
static inline SkScalar scross(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
return a * b - c * d;
}
SkMatrix& SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
*this = SkMatrix(1, 0, dx,
0, 1, dy,
0, 0, 1,
(dx != 0 || dy != 0) ? kTranslate_Mask | kRectStaysRect_Mask
: kIdentity_Mask | kRectStaysRect_Mask);
return *this;
}
SkMatrix& SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
const unsigned mask = this->getType();
if (mask <= kTranslate_Mask) {
fMat[kMTransX] += dx;
fMat[kMTransY] += dy;
} else if (mask & kPerspective_Mask) {
SkMatrix m;
m.setTranslate(dx, dy);
return this->preConcat(m);
} else {
fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy);
fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy);
}
this->updateTranslateMask();
return *this;
}
SkMatrix& SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
if (this->hasPerspective()) {
SkMatrix m;
m.setTranslate(dx, dy);
this->postConcat(m);
} else {
fMat[kMTransX] += dx;
fMat[kMTransY] += dy;
this->updateTranslateMask();
}
return *this;
}
SkMatrix& SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
if (1 == sx && 1 == sy) {
this->reset();
} else {
this->setScaleTranslate(sx, sy, px - sx * px, py - sy * py);
}
return *this;
}
SkMatrix& SkMatrix::setScale(SkScalar sx, SkScalar sy) {
*this = SkMatrix(sx, 0, 0,
0, sy, 0,
0, 0, 1,
(sx == 1 && sy == 1) ? kIdentity_Mask | kRectStaysRect_Mask
: kScale_Mask | kRectStaysRect_Mask);
return *this;
}
SkMatrix& SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
if (1 == sx && 1 == sy) {
return *this;
}
SkMatrix m;
m.setScale(sx, sy, px, py);
return this->preConcat(m);
}
SkMatrix& SkMatrix::preScale(SkScalar sx, SkScalar sy) {
if (1 == sx && 1 == sy) {
return *this;
}
fMat[kMScaleX] *= sx;
fMat[kMSkewY] *= sx;
fMat[kMPersp0] *= sx;
fMat[kMSkewX] *= sy;
fMat[kMScaleY] *= sy;
fMat[kMPersp1] *= sy;
if (fMat[kMScaleX] == 1 && fMat[kMScaleY] == 1
&& !(fTypeMask & (kPerspective_Mask | kAffine_Mask))) {
this->clearTypeMask(kScale_Mask);
} else {
this->orTypeMask(kScale_Mask);
}
return *this;
}
SkMatrix& SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
if (1 == sx && 1 == sy) {
return *this;
}
SkMatrix m;
m.setScale(sx, sy, px, py);
return this->postConcat(m);
}
SkMatrix& SkMatrix::postScale(SkScalar sx, SkScalar sy) {
if (1 == sx && 1 == sy) {
return *this;
}
SkMatrix m;
m.setScale(sx, sy);
return this->postConcat(m);
}
bool SkMatrix::postIDiv(int divx, int divy) {
if (divx == 0 || divy == 0) {
return false;
}
const float invX = 1.f / divx;
const float invY = 1.f / divy;
fMat[kMScaleX] *= invX;
fMat[kMSkewX] *= invX;
fMat[kMTransX] *= invX;
fMat[kMScaleY] *= invY;
fMat[kMSkewY] *= invY;
fMat[kMTransY] *= invY;
this->setTypeMask(kUnknown_Mask);
return true;
}
SkMatrix& SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV, SkScalar px, SkScalar py) {
const SkScalar oneMinusCosV = 1 - cosV;
fMat[kMScaleX] = cosV;
fMat[kMSkewX] = -sinV;
fMat[kMTransX] = sdot(sinV, py, oneMinusCosV, px);
fMat[kMSkewY] = sinV;
fMat[kMScaleY] = cosV;
fMat[kMTransY] = sdot(-sinV, px, oneMinusCosV, py);
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = 1;
this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
return *this;
}
SkMatrix& SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
fMat[kMScaleX] = cosV;
fMat[kMSkewX] = -sinV;
fMat[kMTransX] = 0;
fMat[kMSkewY] = sinV;
fMat[kMScaleY] = cosV;
fMat[kMTransY] = 0;
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = 1;
this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
return *this;
}
SkMatrix& SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
SkScalar rad = PkDegreesToRadians(degrees);
return this->setSinCos(SkScalarSinSnapToZero(rad), SkScalarCosSnapToZero(rad), px, py);
}
SkMatrix& SkMatrix::setRotate(SkScalar degrees) {
SkScalar rad = PkDegreesToRadians(degrees);
return this->setSinCos(SkScalarSinSnapToZero(rad), SkScalarCosSnapToZero(rad));
}
SkMatrix& SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
SkMatrix m;
m.setRotate(degrees, px, py);
return this->preConcat(m);
}
SkMatrix& SkMatrix::preRotate(SkScalar degrees) {
SkMatrix m;
m.setRotate(degrees);
return this->preConcat(m);
}
SkMatrix& SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
SkMatrix m;
m.setRotate(degrees, px, py);
return this->postConcat(m);
}
SkMatrix& SkMatrix::postRotate(SkScalar degrees) {
SkMatrix m;
m.setRotate(degrees);
return this->postConcat(m);
}
SkMatrix& SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
*this = SkMatrix(1, sx, -sx * py,
sy, 1, -sy * px,
0, 0, 1,
kUnknown_Mask | kOnlyPerspectiveValid_Mask);
return *this;
}
SkMatrix& SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
fMat[kMScaleX] = 1;
fMat[kMSkewX] = sx;
fMat[kMTransX] = 0;
fMat[kMSkewY] = sy;
fMat[kMScaleY] = 1;
fMat[kMTransY] = 0;
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = 1;
this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
return *this;
}
SkMatrix& SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
SkMatrix m;
m.setSkew(sx, sy, px, py);
return this->preConcat(m);
}
SkMatrix& SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
SkMatrix m;
m.setSkew(sx, sy);
return this->preConcat(m);
}
SkMatrix& SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
SkMatrix m;
m.setSkew(sx, sy, px, py);
return this->postConcat(m);
}
SkMatrix& SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
SkMatrix m;
m.setSkew(sx, sy);
return this->postConcat(m);
}
bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit align) {
if (src.isEmpty()) {
this->reset();
return false;
}
if (dst.isEmpty()) {
sk_bzero(fMat, 8 * sizeof(SkScalar));
fMat[kMPersp2] = 1;
this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
} else {
SkScalar tx, sx = dst.width() / src.width();
SkScalar ty, sy = dst.height() / src.height();
bool xLarger = false;
if (align != kFill_ScaleToFit) {
if (sx > sy) {
xLarger = true;
sx = sy;
} else {
sy = sx;
}
}
tx = dst.fLeft - src.fLeft * sx;
ty = dst.fTop - src.fTop * sy;
if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
SkScalar diff;
if (xLarger) {
diff = dst.width() - src.width() * sy;
} else {
diff = dst.height() - src.height() * sy;
}
if (align == kCenter_ScaleToFit) {
diff = PkScalarHalf(diff);
}
if (xLarger) {
tx += diff;
} else {
ty += diff;
}
}
this->setScaleTranslate(sx, sy, tx, ty);
}
return true;
}
static inline float muladdmul(float a, float b, float c, float d) {
return pk_double_to_float((double)a * b + (double)c * d);
}
static inline float rowcol3(const float row[], const float col[]) {
return row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
}
static bool only_scale_and_translate(unsigned mask) {
return 0 == (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask));
}
SkMatrix& SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
TypeMask aType = a.getType();
TypeMask bType = b.getType();
if (a.isTriviallyIdentity()) {
*this = b;
} else if (b.isTriviallyIdentity()) {
*this = a;
} else if (only_scale_and_translate(aType | bType)) {
this->setScaleTranslate(a.fMat[kMScaleX] * b.fMat[kMScaleX],
a.fMat[kMScaleY] * b.fMat[kMScaleY],
a.fMat[kMScaleX] * b.fMat[kMTransX] + a.fMat[kMTransX],
a.fMat[kMScaleY] * b.fMat[kMTransY] + a.fMat[kMTransY]);
} else {
SkMatrix tmp;
if ((aType | bType) & kPerspective_Mask) {
tmp.fMat[kMScaleX] = rowcol3(&a.fMat[0], &b.fMat[0]);
tmp.fMat[kMSkewX] = rowcol3(&a.fMat[0], &b.fMat[1]);
tmp.fMat[kMTransX] = rowcol3(&a.fMat[0], &b.fMat[2]);
tmp.fMat[kMSkewY] = rowcol3(&a.fMat[3], &b.fMat[0]);
tmp.fMat[kMScaleY] = rowcol3(&a.fMat[3], &b.fMat[1]);
tmp.fMat[kMTransY] = rowcol3(&a.fMat[3], &b.fMat[2]);
tmp.fMat[kMPersp0] = rowcol3(&a.fMat[6], &b.fMat[0]);
tmp.fMat[kMPersp1] = rowcol3(&a.fMat[6], &b.fMat[1]);
tmp.fMat[kMPersp2] = rowcol3(&a.fMat[6], &b.fMat[2]);
tmp.setTypeMask(kUnknown_Mask);
} else {
tmp.fMat[kMScaleX] = muladdmul(a.fMat[kMScaleX],
b.fMat[kMScaleX],
a.fMat[kMSkewX],
b.fMat[kMSkewY]);
tmp.fMat[kMSkewX] = muladdmul(a.fMat[kMScaleX],
b.fMat[kMSkewX],
a.fMat[kMSkewX],
b.fMat[kMScaleY]);
tmp.fMat[kMTransX] = muladdmul(a.fMat[kMScaleX],
b.fMat[kMTransX],
a.fMat[kMSkewX],
b.fMat[kMTransY]) + a.fMat[kMTransX];
tmp.fMat[kMSkewY] = muladdmul(a.fMat[kMSkewY],
b.fMat[kMScaleX],
a.fMat[kMScaleY],
b.fMat[kMSkewY]);
tmp.fMat[kMScaleY] = muladdmul(a.fMat[kMSkewY],
b.fMat[kMSkewX],
a.fMat[kMScaleY],
b.fMat[kMScaleY]);
tmp.fMat[kMTransY] = muladdmul(a.fMat[kMSkewY],
b.fMat[kMTransX],
a.fMat[kMScaleY],
b.fMat[kMTransY]) + a.fMat[kMTransY];
tmp.fMat[kMPersp0] = 0;
tmp.fMat[kMPersp1] = 0;
tmp.fMat[kMPersp2] = 1;
tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
*this = tmp;
}
return *this;
}
SkMatrix& SkMatrix::preConcat(const SkMatrix& mat) {
if(!mat.isIdentity()) {
this->setConcat(*this, mat);
}
return *this;
}
SkMatrix& SkMatrix::postConcat(const SkMatrix& mat) {
if (!mat.isIdentity()) {
this->setConcat(mat, *this);
}
return *this;
}
static inline SkScalar scross_dscale(SkScalar a, SkScalar b,
SkScalar c, SkScalar d, double scale) {
return PkDoubleToScalar(scross(a, b, c, d) * scale);
}
static inline double dcross(double a, double b, double c, double d) {
return a * b - c * d;
}
static inline SkScalar dcross_dscale(double a, double b,
double c, double d, double scale) {
return PkDoubleToScalar(dcross(a, b, c, d) * scale);
}
static double sk_determinant(const float mat[9], int isPerspective) {
if (isPerspective) {
return mat[SkMatrix::kMScaleX] *
dcross(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2],
mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1])
+
mat[SkMatrix::kMSkewX] *
dcross(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0],
mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2])
+
mat[SkMatrix::kMTransX] *
dcross(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1],
mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]);
} else {
return dcross(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY],
mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
}
}
static double sk_inv_determinant(const float mat[9], int isPerspective) {
double det = sk_determinant(mat, isPerspective);
if (SkScalarNearlyZero(pk_double_to_float(det),
PK_ScalarNearlyZero * PK_ScalarNearlyZero * PK_ScalarNearlyZero)) {
return 0;
}
return 1.0 / det;
}
void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
this->getMapPtsProc()(*this, dst, src, count);
}
void SkMatrix::mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
this->getMapXYProc()(*this, x, y, result);
}
void SkMatrix::ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp) {
if (isPersp) {
dst[kMScaleX] = scross_dscale(src[kMScaleY], src[kMPersp2], src[kMTransY], src[kMPersp1], invDet);
dst[kMSkewX] = scross_dscale(src[kMTransX], src[kMPersp1], src[kMSkewX], src[kMPersp2], invDet);
dst[kMTransX] = scross_dscale(src[kMSkewX], src[kMTransY], src[kMTransX], src[kMScaleY], invDet);
dst[kMSkewY] = scross_dscale(src[kMTransY], src[kMPersp0], src[kMSkewY], src[kMPersp2], invDet);
dst[kMScaleY] = scross_dscale(src[kMScaleX], src[kMPersp2], src[kMTransX], src[kMPersp0], invDet);
dst[kMTransY] = scross_dscale(src[kMTransX], src[kMSkewY], src[kMScaleX], src[kMTransY], invDet);
dst[kMPersp0] = scross_dscale(src[kMSkewY], src[kMPersp1], src[kMScaleY], src[kMPersp0], invDet);
dst[kMPersp1] = scross_dscale(src[kMSkewX], src[kMPersp0], src[kMScaleX], src[kMPersp1], invDet);
dst[kMPersp2] = scross_dscale(src[kMScaleX], src[kMScaleY], src[kMSkewX], src[kMSkewY], invDet);
} else { dst[kMScaleX] = PkDoubleToScalar(src[kMScaleY] * invDet);
dst[kMSkewX] = PkDoubleToScalar(-src[kMSkewX] * invDet);
dst[kMTransX] = dcross_dscale(src[kMSkewX], src[kMTransY], src[kMScaleY], src[kMTransX], invDet);
dst[kMSkewY] = PkDoubleToScalar(-src[kMSkewY] * invDet);
dst[kMScaleY] = PkDoubleToScalar(src[kMScaleX] * invDet);
dst[kMTransY] = dcross_dscale(src[kMSkewY], src[kMTransX], src[kMScaleX], src[kMTransY], invDet);
dst[kMPersp0] = 0;
dst[kMPersp1] = 0;
dst[kMPersp2] = 1;
}
}
bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
TypeMask mask = this->getType();
if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) {
bool invertible = true;
if (inv) {
if (mask & kScale_Mask) {
SkScalar invX = fMat[kMScaleX];
SkScalar invY = fMat[kMScaleY];
if (0 == invX || 0 == invY) {
return false;
}
invX = PkScalarInvert(invX);
invY = PkScalarInvert(invY);
inv->fMat[kMSkewX] = inv->fMat[kMSkewY] =
inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0;
inv->fMat[kMScaleX] = invX;
inv->fMat[kMScaleY] = invY;
inv->fMat[kMPersp2] = 1;
inv->fMat[kMTransX] = -fMat[kMTransX] * invX;
inv->fMat[kMTransY] = -fMat[kMTransY] * invY;
inv->setTypeMask(mask | kRectStaysRect_Mask);
} else {
inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
}
} else { if (!fMat[kMScaleX] || !fMat[kMScaleY]) {
invertible = false;
}
}
return invertible;
}
int isPersp = mask & kPerspective_Mask;
double invDet = sk_inv_determinant(fMat, isPersp);
if (invDet == 0) { return false;
}
bool applyingInPlace = (inv == this);
SkMatrix* tmp = inv;
SkMatrix storage;
if (applyingInPlace || nullptr == tmp) {
tmp = &storage; }
ComputeInv(tmp->fMat, fMat, invDet, isPersp);
if (!tmp->isFinite()) {
return false;
}
tmp->setTypeMask(fTypeMask);
if (applyingInPlace) {
*inv = storage; }
return true;
}
void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
if (dst != src && count > 0) {
memcpy(dst, src, count * sizeof(SkPoint));
}
}
void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
if (count > 0) {
SkScalar tx = m.getTranslateX();
SkScalar ty = m.getTranslateY();
if (count & 1) {
dst->fX = src->fX + tx;
dst->fY = src->fY + ty;
src += 1;
dst += 1;
}
Sk4s trans4(tx, ty, tx, ty);
count >>= 1;
if (count & 1) {
(Sk4s::Load(src) + trans4).store(dst);
src += 2;
dst += 2;
}
count >>= 1;
for (int i = 0; i < count; ++i) {
(Sk4s::Load(src+0) + trans4).store(dst+0);
(Sk4s::Load(src+2) + trans4).store(dst+2);
src += 4;
dst += 4;
}
}
}
void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
if (count > 0) {
SkScalar tx = m.getTranslateX();
SkScalar ty = m.getTranslateY();
SkScalar sx = m.getScaleX();
SkScalar sy = m.getScaleY();
if (count & 1) {
dst->fX = src->fX * sx + tx;
dst->fY = src->fY * sy + ty;
src += 1;
dst += 1;
}
Sk4s trans4(tx, ty, tx, ty);
Sk4s scale4(sx, sy, sx, sy);
count >>= 1;
if (count & 1) {
(Sk4s::Load(src) * scale4 + trans4).store(dst);
src += 2;
dst += 2;
}
count >>= 1;
for (int i = 0; i < count; ++i) {
(Sk4s::Load(src+0) * scale4 + trans4).store(dst+0);
(Sk4s::Load(src+2) * scale4 + trans4).store(dst+2);
src += 4;
dst += 4;
}
}
}
void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
const SkPoint src[], int count) {
if (count > 0) {
do {
SkScalar sy = src->fY;
SkScalar sx = src->fX;
src += 1;
SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
#ifdef PK_LEGACY_MATRIX_MATH_ORDER
SkScalar z = sx * m.fMat[kMPersp0] + (sy * m.fMat[kMPersp1] + m.fMat[kMPersp2]);
#else
SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
#endif
if (z) {
z = 1 / z;
}
dst->fY = y * z;
dst->fX = x * z;
dst += 1;
} while (--count);
}
}
void SkMatrix::Affine_vpts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
if (count > 0) {
SkScalar tx = m.getTranslateX();
SkScalar ty = m.getTranslateY();
SkScalar sx = m.getScaleX();
SkScalar sy = m.getScaleY();
SkScalar kx = m.getSkewX();
SkScalar ky = m.getSkewY();
if (count & 1) {
dst->set(src->fX * sx + src->fY * kx + tx,
src->fX * ky + src->fY * sy + ty);
src += 1;
dst += 1;
}
Sk4s trans4(tx, ty, tx, ty);
Sk4s scale4(sx, sy, sx, sy);
Sk4s skew4(kx, ky, kx, ky); count >>= 1;
for (int i = 0; i < count; ++i) {
Sk4s src4 = Sk4s::Load(src);
Sk4s swz4 = SkNx_shuffle<1,0,3,2>(src4); (src4 * scale4 + swz4 * skew4 + trans4).store(dst);
src += 2;
dst += 2;
}
}
}
const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
SkMatrix::Identity_pts, SkMatrix::Trans_pts,
SkMatrix::Scale_pts, SkMatrix::Scale_pts,
SkMatrix::Affine_vpts, SkMatrix::Affine_vpts,
SkMatrix::Affine_vpts, SkMatrix::Affine_vpts,
SkMatrix::Persp_pts, SkMatrix::Persp_pts,
SkMatrix::Persp_pts, SkMatrix::Persp_pts,
SkMatrix::Persp_pts, SkMatrix::Persp_pts,
SkMatrix::Persp_pts, SkMatrix::Persp_pts
};
void SkMatrixPriv::MapHomogeneousPointsWithStride(const SkMatrix& mx, SkPoint3 dst[],
size_t dstStride, const SkPoint3 src[],
size_t srcStride, int count) {
if (count > 0) {
if (mx.isIdentity()) {
if (src != dst) {
if (srcStride == sizeof(SkPoint3) && dstStride == sizeof(SkPoint3)) {
memcpy(dst, src, count * sizeof(SkPoint3));
} else {
for (int i = 0; i < count; ++i) {
*dst = *src;
dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + dstStride);
src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) +
srcStride);
}
}
}
return;
}
do {
SkScalar sx = src->fX;
SkScalar sy = src->fY;
SkScalar sw = src->fZ;
src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) + srcStride);
const SkScalar* mat = mx.fMat;
typedef SkMatrix M;
SkScalar x = sdot(sx, mat[M::kMScaleX], sy, mat[M::kMSkewX], sw, mat[M::kMTransX]);
SkScalar y = sdot(sx, mat[M::kMSkewY], sy, mat[M::kMScaleY], sw, mat[M::kMTransY]);
SkScalar w = sdot(sx, mat[M::kMPersp0], sy, mat[M::kMPersp1], sw, mat[M::kMPersp2]);
dst->set(x, y, w);
dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + dstStride);
} while (--count);
}
}
void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const {
SkMatrixPriv::MapHomogeneousPointsWithStride(*this, dst, sizeof(SkPoint3), src,
sizeof(SkPoint3), count);
}
void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint src[], int count) const {
if (this->isIdentity()) {
for (int i = 0; i < count; ++i) {
dst[i] = { src[i].fX, src[i].fY, 1 };
}
} else if (this->hasPerspective()) {
for (int i = 0; i < count; ++i) {
dst[i] = {
fMat[0] * src[i].fX + fMat[1] * src[i].fY + fMat[2],
fMat[3] * src[i].fX + fMat[4] * src[i].fY + fMat[5],
fMat[6] * src[i].fX + fMat[7] * src[i].fY + fMat[8],
};
}
} else { for (int i = 0; i < count; ++i) {
dst[i] = {
fMat[0] * src[i].fX + fMat[1] * src[i].fY + fMat[2],
fMat[3] * src[i].fX + fMat[4] * src[i].fY + fMat[5],
1,
};
}
}
}
static Sk4f sort_as_rect(const Sk4f& ltrb) {
Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
Sk4f min = Sk4f::Min(ltrb, rblt);
Sk4f max = Sk4f::Max(ltrb, rblt);
return Sk4f(min[2], min[3], max[0], max[1]);
}
void SkMatrix::mapRectScaleTranslate(SkRect* dst, const SkRect& src) const {
SkScalar sx = fMat[kMScaleX];
SkScalar sy = fMat[kMScaleY];
SkScalar tx = fMat[kMTransX];
SkScalar ty = fMat[kMTransY];
Sk4f scale(sx, sy, sx, sy);
Sk4f trans(tx, ty, tx, ty);
sort_as_rect(Sk4f::Load(&src.fLeft) * scale + trans).store(&dst->fLeft);
}
bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
if (this->getType() <= kTranslate_Mask) {
SkScalar tx = fMat[kMTransX];
SkScalar ty = fMat[kMTransY];
Sk4f trans(tx, ty, tx, ty);
sort_as_rect(Sk4f::Load(&src.fLeft) + trans).store(&dst->fLeft);
return true;
}
if (this->isScaleTranslate()) {
this->mapRectScaleTranslate(dst, src);
return true;
} else {
SkPoint quad[4];
src.toQuad(quad);
this->mapPoints(quad, quad, 4);
dst->setBoundsNoCheck(quad, 4);
return this->rectStaysRect(); }
}
void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
SkPoint* pt) {
SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
if (z) {
z = 1 / z;
}
pt->fX = x * z;
pt->fY = y * z;
}
void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
SkPoint* pt) {
#ifdef PK_LEGACY_MATRIX_MATH_ORDER
pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]);
pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
#else
pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
#endif
}
void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
SkPoint* pt) {
#ifdef PK_LEGACY_MATRIX_MATH_ORDER
pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]);
pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
#else
pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
#endif
}
void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
SkPoint* pt) {
pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX];
pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY];
}
void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
SkPoint* pt) {
pt->fX = sx * m.fMat[kMScaleX];
pt->fY = sy * m.fMat[kMScaleY];
}
void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
SkPoint* pt) {
pt->fX = sx + m.fMat[kMTransX];
pt->fY = sy + m.fMat[kMTransY];
}
void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
SkPoint* pt) {
pt->fX = sx;
pt->fY = sy;
}
const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
SkMatrix::Identity_xy, SkMatrix::Trans_xy,
SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy,
SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
SkMatrix::Persp_xy, SkMatrix::Persp_xy,
SkMatrix::Persp_xy, SkMatrix::Persp_xy,
SkMatrix::Persp_xy, SkMatrix::Persp_xy,
SkMatrix::Persp_xy, SkMatrix::Persp_xy
};
static inline bool checkForZero(float x) {
return x*x == 0;
}
bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst) {
dst->fMat[kMScaleX] = srcPt[1].fY - srcPt[0].fY;
dst->fMat[kMSkewY] = srcPt[0].fX - srcPt[1].fX;
dst->fMat[kMPersp0] = 0;
dst->fMat[kMSkewX] = srcPt[1].fX - srcPt[0].fX;
dst->fMat[kMScaleY] = srcPt[1].fY - srcPt[0].fY;
dst->fMat[kMPersp1] = 0;
dst->fMat[kMTransX] = srcPt[0].fX;
dst->fMat[kMTransY] = srcPt[0].fY;
dst->fMat[kMPersp2] = 1;
dst->setTypeMask(kUnknown_Mask);
return true;
}
bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst) {
dst->fMat[kMScaleX] = srcPt[2].fX - srcPt[0].fX;
dst->fMat[kMSkewY] = srcPt[2].fY - srcPt[0].fY;
dst->fMat[kMPersp0] = 0;
dst->fMat[kMSkewX] = srcPt[1].fX - srcPt[0].fX;
dst->fMat[kMScaleY] = srcPt[1].fY - srcPt[0].fY;
dst->fMat[kMPersp1] = 0;
dst->fMat[kMTransX] = srcPt[0].fX;
dst->fMat[kMTransY] = srcPt[0].fY;
dst->fMat[kMPersp2] = 1;
dst->setTypeMask(kUnknown_Mask);
return true;
}
bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst) {
float a1, a2;
float x0, y0, x1, y1, x2, y2;
x0 = srcPt[2].fX - srcPt[0].fX;
y0 = srcPt[2].fY - srcPt[0].fY;
x1 = srcPt[2].fX - srcPt[1].fX;
y1 = srcPt[2].fY - srcPt[1].fY;
x2 = srcPt[2].fX - srcPt[3].fX;
y2 = srcPt[2].fY - srcPt[3].fY;
if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
float denom = sk_ieee_float_divide(x1 * y2, x2) - y1;
if (checkForZero(denom)) {
return false;
}
a1 = (((x0 - x1) * y2 / x2) - y0 + y1) / denom;
} else {
float denom = x1 - sk_ieee_float_divide(y1 * x2, y2);
if (checkForZero(denom)) {
return false;
}
a1 = (x0 - x1 - sk_ieee_float_divide((y0 - y1) * x2, y2)) / denom;
}
if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
float denom = y2 - sk_ieee_float_divide(x2 * y1, x1);
if (checkForZero(denom)) {
return false;
}
a2 = (y0 - y2 - sk_ieee_float_divide((x0 - x2) * y1, x1)) / denom;
} else {
float denom = sk_ieee_float_divide(y2 * x1, y1) - x2;
if (checkForZero(denom)) {
return false;
}
a2 = (sk_ieee_float_divide((y0 - y2) * x1, y1) - x0 + x2) / denom;
}
dst->fMat[kMScaleX] = a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX;
dst->fMat[kMSkewY] = a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY;
dst->fMat[kMPersp0] = a2;
dst->fMat[kMSkewX] = a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX;
dst->fMat[kMScaleY] = a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY;
dst->fMat[kMPersp1] = a1;
dst->fMat[kMTransX] = srcPt[0].fX;
dst->fMat[kMTransY] = srcPt[0].fY;
dst->fMat[kMPersp2] = 1;
dst->setTypeMask(kUnknown_Mask);
return true;
}
enum MinMaxOrBoth {
kMin_MinMaxOrBoth,
kMax_MinMaxOrBoth,
kBoth_MinMaxOrBoth
};
template <MinMaxOrBoth MIN_MAX_OR_BOTH> bool get_scale_factor(SkMatrix::TypeMask typeMask,
const SkScalar m[9],
SkScalar results[]) {
if (typeMask & SkMatrix::kPerspective_Mask) {
return false;
}
if (SkMatrix::kIdentity_Mask == typeMask) {
results[0] = PK_Scalar1;
if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[1] = PK_Scalar1;
}
return true;
}
if (!(typeMask & SkMatrix::kAffine_Mask)) {
if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[0] = std::min(PkScalarAbs(m[SkMatrix::kMScaleX]),
PkScalarAbs(m[SkMatrix::kMScaleY]));
} else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[0] = std::max(PkScalarAbs(m[SkMatrix::kMScaleX]),
PkScalarAbs(m[SkMatrix::kMScaleY]));
} else {
results[0] = PkScalarAbs(m[SkMatrix::kMScaleX]);
results[1] = PkScalarAbs(m[SkMatrix::kMScaleY]);
if (results[0] > results[1]) {
using std::swap;
swap(results[0], results[1]);
}
}
return true;
}
SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX],
m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]);
SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX],
m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
SkScalar c = sdot(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX],
m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
SkScalar bSqd = b * b;
if (bSqd <= PK_ScalarNearlyZero*PK_ScalarNearlyZero) {
if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[0] = std::min(a, c);
} else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[0] = std::max(a, c);
} else {
results[0] = a;
results[1] = c;
if (results[0] > results[1]) {
using std::swap;
swap(results[0], results[1]);
}
}
} else {
SkScalar aminusc = a - c;
SkScalar apluscdiv2 = PkScalarHalf(a + c);
SkScalar x = PkScalarHalf(PkScalarSqrt(aminusc * aminusc + 4 * bSqd));
if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[0] = apluscdiv2 - x;
} else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[0] = apluscdiv2 + x;
} else {
results[0] = apluscdiv2 - x;
results[1] = apluscdiv2 + x;
}
}
if (!SkScalarIsFinite(results[0])) {
return false;
}
if (results[0] < 0) {
results[0] = 0;
}
results[0] = PkScalarSqrt(results[0]);
if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
if (!SkScalarIsFinite(results[1])) {
return false;
}
if (results[1] < 0) {
results[1] = 0;
}
results[1] = PkScalarSqrt(results[1]);
}
return true;
}
SkScalar SkMatrix::getMinScale() const {
SkScalar factor;
if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
return factor;
} else {
return -1;
}
}
SkScalar SkMatrix::getMaxScale() const {
SkScalar factor;
if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
return factor;
} else {
return -1;
}
}
bool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
}
const SkMatrix& SkMatrix::I() {
static constexpr SkMatrix identity;
return identity;
}
const SkMatrix& SkMatrix::InvalidMatrix() {
static constexpr SkMatrix invalid(PK_ScalarMax, PK_ScalarMax, PK_ScalarMax,
PK_ScalarMax, PK_ScalarMax, PK_ScalarMax,
PK_ScalarMax, PK_ScalarMax, PK_ScalarMax,
kTranslate_Mask | kScale_Mask |
kAffine_Mask | kPerspective_Mask);
return invalid;
}
size_t SkMatrix::writeToMemory(void* buffer) const {
static const size_t sizeInMemory = 9 * sizeof(SkScalar);
if (buffer) {
memcpy(buffer, fMat, sizeInMemory);
}
return sizeInMemory;
}
size_t SkMatrix::readFromMemory(const void* buffer, size_t length) {
static const size_t sizeInMemory = 9 * sizeof(SkScalar);
if (length < sizeInMemory) {
return 0;
}
memcpy(fMat, buffer, sizeInMemory);
this->setTypeMask(kUnknown_Mask);
(void)this->getType();
return sizeInMemory;
}
bool SkDecomposeUpper2x2(const SkMatrix& matrix,
SkPoint* rotation1,
SkPoint* scale,
SkPoint* rotation2) {
SkScalar A = matrix[SkMatrix::kMScaleX];
SkScalar B = matrix[SkMatrix::kMSkewX];
SkScalar C = matrix[SkMatrix::kMSkewY];
SkScalar D = matrix[SkMatrix::kMScaleY];
if (is_degenerate_2x2(A, B, C, D)) {
return false;
}
double w1, w2;
SkScalar cos1, sin1;
SkScalar cos2, sin2;
SkScalar cosQ, sinQ;
double Sa, Sb, Sd;
if (SkScalarNearlyEqual(B, C)) {
cosQ = 1;
sinQ = 0;
Sa = A;
Sb = B;
Sd = D;
} else {
cosQ = A + D;
sinQ = C - B;
SkScalar reciplen = PkScalarInvert(PkScalarSqrt(cosQ*cosQ + sinQ*sinQ));
cosQ *= reciplen;
sinQ *= reciplen;
Sa = A*cosQ + C*sinQ;
Sb = B*cosQ + D*sinQ;
Sd = -B*sinQ + D*cosQ;
}
if (SkScalarNearlyZero(PkDoubleToScalar(Sb))) {
cos1 = 1;
sin1 = 0;
w1 = Sa;
w2 = Sd;
cos2 = cosQ;
sin2 = sinQ;
} else {
double diff = Sa - Sd;
double discriminant = sqrt(diff*diff + 4.0*Sb*Sb);
double trace = Sa + Sd;
if (diff > 0) {
w1 = 0.5*(trace + discriminant);
w2 = 0.5*(trace - discriminant);
} else {
w1 = 0.5*(trace - discriminant);
w2 = 0.5*(trace + discriminant);
}
cos1 = PkDoubleToScalar(Sb); sin1 = PkDoubleToScalar(w1 - Sa);
SkScalar reciplen = PkScalarInvert(PkScalarSqrt(cos1*cos1 + sin1*sin1));
cos1 *= reciplen;
sin1 *= reciplen;
cos2 = cos1*cosQ - sin1*sinQ;
sin2 = sin1*cosQ + cos1*sinQ;
sin1 = -sin1;
}
if (scale) {
scale->fX = PkDoubleToScalar(w1);
scale->fY = PkDoubleToScalar(w2);
}
if (rotation1) {
rotation1->fX = cos1;
rotation1->fY = sin1;
}
if (rotation2) {
rotation2->fX = cos2;
rotation2->fY = sin2;
}
return true;
}
SkScalar SkMatrixPriv::DifferentialAreaScale(const SkMatrix& m, const SkPoint& p) {
SkPoint3 xyw;
m.mapHomogeneousPoints(&xyw, &p, 1);
if (xyw.fZ < PK_ScalarNearlyZero) {
return PK_ScalarInfinity;
}
SkMatrix jacobian = SkMatrix::MakeAll(xyw.fX, xyw.fY, xyw.fZ,
m.getScaleX(), m.getSkewY(), m.getPerspX(),
m.getSkewX(), m.getScaleY(), m.getPerspY());
double denom = 1.0 / xyw.fZ; denom = denom * denom * denom; return PkScalarAbs(PkDoubleToScalar(sk_determinant(jacobian.fMat, true) * denom));
}
}