#include "SkMatrix.h"
#include "SkFloatBits.h"
#include "SkString.h"
#include <stddef.h>
#define SK_LEGACY_MATRIX_MATH_ORDER
static inline float SkDoubleToFloat(double x) {
return static_cast<float>(x);
}
void SkMatrix::reset() {
fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1;
fMat[kMSkewX] = fMat[kMSkewY] =
fMat[kMTransX] = fMat[kMTransY] =
fMat[kMPersp0] = fMat[kMPersp1] = 0;
this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
}
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 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
int m11 = SkScalarAs2sCompliment(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* SK_RESTRICT ma = a.fMat;
const SkScalar* SK_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, SK_ScalarNearlyZero*SK_ScalarNearlyZero);
}
bool SkMatrix::isSimilarity(SkScalar tol) const {
TypeMask mask = this->getType();
if (mask <= kTranslate_Mask) {
return true;
}
if (mask & kPerspective_Mask) {
return false;
}
SkScalar mx = fMat[kMScaleX];
SkScalar my = fMat[kMScaleY];
if (!(mask & kAffine_Mask)) {
return !SkScalarNearlyZero(mx) && SkScalarNearlyEqual(SkScalarAbs(mx), SkScalarAbs(my));
}
SkScalar sx = fMat[kMSkewX];
SkScalar sy = fMat[kMSkewY];
if (is_degenerate_2x2(mx, sx, sy, my)) {
return false;
}
SkVector vec[2];
vec[0].set(mx, sx);
vec[1].set(sy, my);
return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
SkScalarSquare(tol));
}
bool SkMatrix::preservesRightAngles(SkScalar tol) const {
TypeMask mask = this->getType();
if (mask <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
return true;
}
if (mask & kPerspective_Mask) {
return false;
}
SkASSERT(mask & kAffine_Mask);
SkScalar mx = fMat[kMScaleX];
SkScalar my = fMat[kMScaleY];
SkScalar sx = fMat[kMSkewX];
SkScalar sy = fMat[kMSkewY];
if (is_degenerate_2x2(mx, sx, sy, my)) {
return false;
}
SkVector vec[2];
vec[0].set(mx, sx);
vec[1].set(sy, my);
return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
SkScalarSquare(tol));
}
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;
}
void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
if (dx || dy) {
fMat[kMTransX] = dx;
fMat[kMTransY] = dy;
fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1;
fMat[kMSkewX] = fMat[kMSkewY] =
fMat[kMPersp0] = fMat[kMPersp1] = 0;
this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
} else {
this->reset();
}
}
void SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
if (!dx && !dy) {
return;
}
if (this->hasPerspective()) {
SkMatrix m;
m.setTranslate(dx, dy);
this->preConcat(m);
} else {
fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy);
fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy);
this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
}
void SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
if (!dx && !dy) {
return;
}
if (this->hasPerspective()) {
SkMatrix m;
m.setTranslate(dx, dy);
this->postConcat(m);
} else {
fMat[kMTransX] += dx;
fMat[kMTransY] += dy;
this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
}
void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
if (1 == sx && 1 == sy) {
this->reset();
} else {
fMat[kMScaleX] = sx;
fMat[kMScaleY] = sy;
fMat[kMTransX] = px - sx * px;
fMat[kMTransY] = py - sy * py;
fMat[kMPersp2] = 1;
fMat[kMSkewX] = fMat[kMSkewY] =
fMat[kMPersp0] = fMat[kMPersp1] = 0;
this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
}
}
void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
if (1 == sx && 1 == sy) {
this->reset();
} else {
fMat[kMScaleX] = sx;
fMat[kMScaleY] = sy;
fMat[kMPersp2] = 1;
fMat[kMTransX] = fMat[kMTransY] =
fMat[kMSkewX] = fMat[kMSkewY] =
fMat[kMPersp0] = fMat[kMPersp1] = 0;
this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
}
}
bool SkMatrix::setIDiv(int divx, int divy) {
if (!divx || !divy) {
return false;
}
this->setScale(SkScalarInvert(divx), SkScalarInvert(divy));
return true;
}
void SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
if (1 == sx && 1 == sy) {
return;
}
SkMatrix m;
m.setScale(sx, sy, px, py);
this->preConcat(m);
}
void SkMatrix::preScale(SkScalar sx, SkScalar sy) {
if (1 == sx && 1 == sy) {
return;
}
fMat[kMScaleX] *= sx;
fMat[kMSkewY] *= sx;
fMat[kMPersp0] *= sx;
fMat[kMSkewX] *= sy;
fMat[kMScaleY] *= sy;
fMat[kMPersp1] *= sy;
this->orTypeMask(kScale_Mask);
}
void SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
if (1 == sx && 1 == sy) {
return;
}
SkMatrix m;
m.setScale(sx, sy, px, py);
this->postConcat(m);
}
void SkMatrix::postScale(SkScalar sx, SkScalar sy) {
if (1 == sx && 1 == sy) {
return;
}
SkMatrix m;
m.setScale(sx, sy);
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;
}
void 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);
}
void 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);
}
void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
SkScalar sinV, cosV;
sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
this->setSinCos(sinV, cosV, px, py);
}
void SkMatrix::setRotate(SkScalar degrees) {
SkScalar sinV, cosV;
sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
this->setSinCos(sinV, cosV);
}
void SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
SkMatrix m;
m.setRotate(degrees, px, py);
this->preConcat(m);
}
void SkMatrix::preRotate(SkScalar degrees) {
SkMatrix m;
m.setRotate(degrees);
this->preConcat(m);
}
void SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
SkMatrix m;
m.setRotate(degrees, px, py);
this->postConcat(m);
}
void SkMatrix::postRotate(SkScalar degrees) {
SkMatrix m;
m.setRotate(degrees);
this->postConcat(m);
}
void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
fMat[kMScaleX] = 1;
fMat[kMSkewX] = sx;
fMat[kMTransX] = -sx * py;
fMat[kMSkewY] = sy;
fMat[kMScaleY] = 1;
fMat[kMTransY] = -sy * px;
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = 1;
this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
void 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);
}
void SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
SkMatrix m;
m.setSkew(sx, sy, px, py);
this->preConcat(m);
}
void SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
SkMatrix m;
m.setSkew(sx, sy);
this->preConcat(m);
}
void SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
SkMatrix m;
m.setSkew(sx, sy, px, py);
this->postConcat(m);
}
void SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
SkMatrix m;
m.setSkew(sx, sy);
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));
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 = SkScalarHalf(diff);
}
if (xLarger) {
tx += diff;
} else {
ty += diff;
}
}
fMat[kMScaleX] = sx;
fMat[kMScaleY] = sy;
fMat[kMTransX] = tx;
fMat[kMTransY] = ty;
fMat[kMSkewX] = fMat[kMSkewY] =
fMat[kMPersp0] = fMat[kMPersp1] = 0;
unsigned mask = kRectStaysRect_Mask;
if (sx != 1 || sy != 1) {
mask |= kScale_Mask;
}
if (tx || ty) {
mask |= kTranslate_Mask;
}
this->setTypeMask(mask);
}
fMat[kMPersp2] = 1;
return true;
}
static inline float muladdmul(float a, float b, float c, float d) {
return SkDoubleToFloat((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 void normalize_perspective(SkScalar mat[9]) {
if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > 1) {
for (int i = 0; i < 9; i++)
mat[i] = SkScalarHalf(mat[i]);
}
}
void SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
TypeMask aType = a.getPerspectiveTypeMaskOnly();
TypeMask bType = b.getPerspectiveTypeMaskOnly();
if (a.isTriviallyIdentity()) {
*this = b;
} else if (b.isTriviallyIdentity()) {
*this = a;
} 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]);
normalize_perspective(tmp.fMat);
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]);
tmp.fMat[kMTransX] += 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]);
tmp.fMat[kMTransY] += a.fMat[kMTransY];
tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
tmp.fMat[kMPersp2] = 1;
tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
*this = tmp;
}
}
void SkMatrix::preConcat(const SkMatrix& mat) {
if(!mat.isIdentity()) {
this->setConcat(*this, mat);
}
}
void SkMatrix::postConcat(const SkMatrix& mat) {
if (!mat.isIdentity()) {
this->setConcat(mat, *this);
}
}
static inline SkScalar scross_dscale(SkScalar a, SkScalar b,
SkScalar c, SkScalar d, double scale) {
return SkDoubleToScalar(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 SkDoubleToScalar(dcross(a, b, c, d) * scale);
}
static double sk_inv_determinant(const float mat[9], int isPerspective) {
double det;
if (isPerspective) {
det = 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 {
det = dcross(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY],
mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
}
if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
return 0;
}
return 1.0 / det;
}
void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
affine[kAScaleX] = 1;
affine[kASkewY] = 0;
affine[kASkewX] = 0;
affine[kAScaleY] = 1;
affine[kATransX] = 0;
affine[kATransY] = 0;
}
bool SkMatrix::asAffine(SkScalar affine[6]) const {
if (this->hasPerspective()) {
return false;
}
if (affine) {
affine[kAScaleX] = this->fMat[kMScaleX];
affine[kASkewY] = this->fMat[kMSkewY];
affine[kASkewX] = this->fMat[kMSkewX];
affine[kAScaleY] = this->fMat[kMScaleY];
affine[kATransX] = this->fMat[kMTransX];
affine[kATransY] = this->fMat[kMTransY];
}
return true;
}
bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
SkASSERT(!this->isIdentity());
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 = SkScalarInvert(invX);
invY = SkScalarInvert(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 scale = sk_inv_determinant(fMat, isPersp);
if (scale == 0) { return false;
}
if (inv) {
SkMatrix tmp;
if (inv == this) {
inv = &tmp;
}
if (isPersp) {
inv->fMat[kMScaleX] = scross_dscale(fMat[kMScaleY], fMat[kMPersp2], fMat[kMTransY], fMat[kMPersp1], scale);
inv->fMat[kMSkewX] = scross_dscale(fMat[kMTransX], fMat[kMPersp1], fMat[kMSkewX], fMat[kMPersp2], scale);
inv->fMat[kMTransX] = scross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMTransX], fMat[kMScaleY], scale);
inv->fMat[kMSkewY] = scross_dscale(fMat[kMTransY], fMat[kMPersp0], fMat[kMSkewY], fMat[kMPersp2], scale);
inv->fMat[kMScaleY] = scross_dscale(fMat[kMScaleX], fMat[kMPersp2], fMat[kMTransX], fMat[kMPersp0], scale);
inv->fMat[kMTransY] = scross_dscale(fMat[kMTransX], fMat[kMSkewY], fMat[kMScaleX], fMat[kMTransY], scale);
inv->fMat[kMPersp0] = scross_dscale(fMat[kMSkewY], fMat[kMPersp1], fMat[kMScaleY], fMat[kMPersp0], scale);
inv->fMat[kMPersp1] = scross_dscale(fMat[kMSkewX], fMat[kMPersp0], fMat[kMScaleX], fMat[kMPersp1], scale);
inv->fMat[kMPersp2] = scross_dscale(fMat[kMScaleX], fMat[kMScaleY], fMat[kMSkewX], fMat[kMSkewY], scale);
} else { inv->fMat[kMScaleX] = SkDoubleToScalar(fMat[kMScaleY] * scale);
inv->fMat[kMSkewX] = SkDoubleToScalar(-fMat[kMSkewX] * scale);
inv->fMat[kMTransX] = dcross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMScaleY], fMat[kMTransX], scale);
inv->fMat[kMSkewY] = SkDoubleToScalar(-fMat[kMSkewY] * scale);
inv->fMat[kMScaleY] = SkDoubleToScalar(fMat[kMScaleX] * scale);
inv->fMat[kMTransY] = dcross_dscale(fMat[kMSkewY], fMat[kMTransX], fMat[kMScaleX], fMat[kMTransY], scale);
inv->fMat[kMPersp0] = 0;
inv->fMat[kMPersp1] = 0;
inv->fMat[kMPersp2] = 1;
}
inv->setTypeMask(fTypeMask);
if (inv == &tmp) {
*(SkMatrix*)this = tmp;
}
}
return true;
}
void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[],
const SkPoint src[], int count) {
SkASSERT(m.getType() == 0);
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) {
SkASSERT(m.getType() == kTranslate_Mask);
if (count > 0) {
SkScalar tx = m.fMat[kMTransX];
SkScalar ty = m.fMat[kMTransY];
do {
dst->fY = src->fY + ty;
dst->fX = src->fX + tx;
src += 1;
dst += 1;
} while (--count);
}
}
void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[],
const SkPoint src[], int count) {
SkASSERT(m.getType() == kScale_Mask);
if (count > 0) {
SkScalar mx = m.fMat[kMScaleX];
SkScalar my = m.fMat[kMScaleY];
do {
dst->fY = src->fY * my;
dst->fX = src->fX * mx;
src += 1;
dst += 1;
} while (--count);
}
}
void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[],
const SkPoint src[], int count) {
SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask));
if (count > 0) {
SkScalar mx = m.fMat[kMScaleX];
SkScalar my = m.fMat[kMScaleY];
SkScalar tx = m.fMat[kMTransX];
SkScalar ty = m.fMat[kMTransY];
do {
dst->fY = src->fY * my + ty;
dst->fX = src->fX * mx + tx;
src += 1;
dst += 1;
} while (--count);
}
}
void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[],
const SkPoint src[], int count) {
SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0);
if (count > 0) {
SkScalar mx = m.fMat[kMScaleX];
SkScalar my = m.fMat[kMScaleY];
SkScalar kx = m.fMat[kMSkewX];
SkScalar ky = m.fMat[kMSkewY];
do {
SkScalar sy = src->fY;
SkScalar sx = src->fX;
src += 1;
dst->fY = sdot(sx, ky, sy, my);
dst->fX = sdot(sx, mx, sy, kx);
dst += 1;
} while (--count);
}
}
void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[],
const SkPoint src[], int count) {
SkASSERT(!m.hasPerspective());
if (count > 0) {
SkScalar mx = m.fMat[kMScaleX];
SkScalar my = m.fMat[kMScaleY];
SkScalar kx = m.fMat[kMSkewX];
SkScalar ky = m.fMat[kMSkewY];
SkScalar tx = m.fMat[kMTransX];
SkScalar ty = m.fMat[kMTransY];
do {
SkScalar sy = src->fY;
SkScalar sx = src->fX;
src += 1;
#ifdef SK_LEGACY_MATRIX_MATH_ORDER
dst->fY = sx * ky + (sy * my + ty);
dst->fX = sx * mx + (sy * kx + tx);
#else
dst->fY = sdot(sx, ky, sy, my) + ty;
dst->fX = sdot(sx, mx, sy, kx) + tx;
#endif
dst += 1;
} while (--count);
}
}
void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
const SkPoint src[], int count) {
SkASSERT(m.hasPerspective());
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 SK_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 = SkScalarFastInvert(z);
}
dst->fY = y * z;
dst->fX = x * z;
dst += 1;
} while (--count);
}
}
const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
SkMatrix::Identity_pts, SkMatrix::Trans_pts,
SkMatrix::Scale_pts, SkMatrix::ScaleTrans_pts,
SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
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 SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
SkASSERT((dst && src && count > 0) || 0 == count);
SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
this->getMapPtsProc()(*this, dst, src, count);
}
void SkMatrix::mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const {
SkASSERT((dst && src && count > 0) || 0 == count);
SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= 3*count);
if (count > 0) {
if (this->isIdentity()) {
memcpy(dst, src, 3*count*sizeof(SkScalar));
return;
}
do {
SkScalar sx = src[0];
SkScalar sy = src[1];
SkScalar sw = src[2];
src += 3;
SkScalar x = sdot(sx, fMat[kMScaleX], sy, fMat[kMSkewX], sw, fMat[kMTransX]);
SkScalar y = sdot(sx, fMat[kMSkewY], sy, fMat[kMScaleY], sw, fMat[kMTransY]);
SkScalar w = sdot(sx, fMat[kMPersp0], sy, fMat[kMPersp1], sw, fMat[kMPersp2]);
dst[0] = x;
dst[1] = y;
dst[2] = w;
dst += 3;
} while (--count);
}
}
void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
if (this->hasPerspective()) {
SkPoint origin;
MapXYProc proc = this->getMapXYProc();
proc(*this, 0, 0, &origin);
for (int i = count - 1; i >= 0; --i) {
SkPoint tmp;
proc(*this, src[i].fX, src[i].fY, &tmp);
dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
}
} else {
SkMatrix tmp = *this;
tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
tmp.clearTypeMask(kTranslate_Mask);
tmp.mapPoints(dst, src, count);
}
}
bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
SkASSERT(dst && &src);
if (this->rectStaysRect()) {
this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
dst->sort();
return true;
} else {
SkPoint quad[4];
src.toQuad(quad);
this->mapPoints(quad, quad, 4);
dst->set(quad, 4);
return false;
}
}
SkScalar SkMatrix::mapRadius(SkScalar radius) const {
SkVector vec[2];
vec[0].set(radius, 0);
vec[1].set(0, radius);
this->mapVectors(vec, 2);
SkScalar d0 = vec[0].length();
SkScalar d1 = vec[1].length();
return SkScalarSqrt(d0 * d1);
}
void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
SkPoint* pt) {
SkASSERT(m.hasPerspective());
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 = SkScalarFastInvert(z);
}
pt->fX = x * z;
pt->fY = y * z;
}
void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
SkPoint* pt) {
SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
#ifdef SK_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) {
SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
SkASSERT(0 == m.fMat[kMTransX]);
SkASSERT(0 == m.fMat[kMTransY]);
#ifdef SK_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) {
SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
== kScale_Mask);
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) {
SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
== kScale_Mask);
SkASSERT(0 == m.fMat[kMTransX]);
SkASSERT(0 == m.fMat[kMTransY]);
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) {
SkASSERT(m.getType() == kTranslate_Mask);
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) {
SkASSERT(0 == m.getType());
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
};
#define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26)))
bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const {
if (PerspNearlyZero(fMat[kMPersp0])) {
if (stepX || stepY) {
if (PerspNearlyZero(fMat[kMPersp1]) &&
PerspNearlyZero(fMat[kMPersp2] - 1)) {
if (stepX) {
*stepX = SkScalarToFixed(fMat[kMScaleX]);
}
if (stepY) {
*stepY = SkScalarToFixed(fMat[kMSkewY]);
}
} else {
SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2];
if (stepX) {
*stepX = SkScalarToFixed(fMat[kMScaleX] / z);
}
if (stepY) {
*stepY = SkScalarToFixed(fMat[kMSkewY] / z);
}
}
}
return true;
}
return false;
}
#include "SkPerspIter.h"
SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count)
: fMatrix(m), fSX(x0), fSY(y0), fCount(count) {
SkPoint pt;
SkMatrix::Persp_xy(m, x0, y0, &pt);
fX = SkScalarToFixed(pt.fX);
fY = SkScalarToFixed(pt.fY);
}
int SkPerspIter::next() {
int n = fCount;
if (0 == n) {
return 0;
}
SkPoint pt;
SkFixed x = fX;
SkFixed y = fY;
SkFixed dx, dy;
if (n >= kCount) {
n = kCount;
fSX += SkIntToScalar(kCount);
SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
fX = SkScalarToFixed(pt.fX);
fY = SkScalarToFixed(pt.fY);
dx = (fX - x) >> kShift;
dy = (fY - y) >> kShift;
} else {
fSX += SkIntToScalar(n);
SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
fX = SkScalarToFixed(pt.fX);
fY = SkScalarToFixed(pt.fY);
dx = (fX - x) / n;
dy = (fY - y) / n;
}
SkFixed* p = fStorage;
for (int i = 0; i < n; i++) {
*p++ = x; x += dx;
*p++ = y; y += dy;
}
fCount -= n;
return n;
}
static inline bool checkForZero(float x) {
return x*x == 0;
}
static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
float x = 1, y = 1;
SkPoint pt1, pt2;
if (count > 1) {
pt1.fX = poly[1].fX - poly[0].fX;
pt1.fY = poly[1].fY - poly[0].fY;
y = SkPoint::Length(pt1.fX, pt1.fY);
if (checkForZero(y)) {
return false;
}
switch (count) {
case 2:
break;
case 3:
pt2.fX = poly[0].fY - poly[2].fY;
pt2.fY = poly[2].fX - poly[0].fX;
goto CALC_X;
default:
pt2.fX = poly[0].fY - poly[3].fY;
pt2.fY = poly[3].fX - poly[0].fX;
CALC_X:
x = sdot(pt1.fX, pt2.fX, pt1.fY, pt2.fY) / y;
break;
}
}
pt->set(x, y);
return true;
}
bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
const SkPoint& scale) {
float invScale = 1 / scale.fY;
dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
dst->fMat[kMPersp0] = 0;
dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
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,
const SkPoint& scale) {
float invScale = 1 / scale.fX;
dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
dst->fMat[kMPersp0] = 0;
invScale = 1 / scale.fY;
dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
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,
const SkPoint& scale) {
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 = SkScalarMulDiv(x1, y2, x2) - y1;
if (checkForZero(denom)) {
return false;
}
a1 = (SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1) / denom;
} else {
float denom = x1 - SkScalarMulDiv(y1, x2, y2);
if (checkForZero(denom)) {
return false;
}
a1 = (x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2)) / denom;
}
if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
float denom = y2 - SkScalarMulDiv(x2, y1, x1);
if (checkForZero(denom)) {
return false;
}
a2 = (y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1)) / denom;
} else {
float denom = SkScalarMulDiv(y2, x1, y1) - x2;
if (checkForZero(denom)) {
return false;
}
a2 = (SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2) / denom;
}
float invScale = SkScalarInvert(scale.fX);
dst->fMat[kMScaleX] = (a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX) * invScale;
dst->fMat[kMSkewY] = (a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY) * invScale;
dst->fMat[kMPersp0] = a2 * invScale;
invScale = SkScalarInvert(scale.fY);
dst->fMat[kMSkewX] = (a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX) * invScale;
dst->fMat[kMScaleY] = (a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY) * invScale;
dst->fMat[kMPersp1] = a1 * invScale;
dst->fMat[kMTransX] = srcPt[0].fX;
dst->fMat[kMTransY] = srcPt[0].fY;
dst->fMat[kMPersp2] = 1;
dst->setTypeMask(kUnknown_Mask);
return true;
}
typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&);
bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
int count) {
if ((unsigned)count > 4) {
SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
return false;
}
if (0 == count) {
this->reset();
return true;
}
if (1 == count) {
this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
return true;
}
SkPoint scale;
if (!poly_to_point(&scale, src, count) ||
SkScalarNearlyZero(scale.fX) ||
SkScalarNearlyZero(scale.fY)) {
return false;
}
static const PolyMapProc gPolyMapProcs[] = {
SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
};
PolyMapProc proc = gPolyMapProcs[count - 2];
SkMatrix tempMap, result;
tempMap.setTypeMask(kUnknown_Mask);
if (!proc(src, &tempMap, scale)) {
return false;
}
if (!tempMap.invert(&result)) {
return false;
}
if (!proc(dst, &tempMap, scale)) {
return false;
}
this->setConcat(tempMap, result);
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] = SK_Scalar1;
if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[1] = SK_Scalar1;
}
return true;
}
if (!(typeMask & SkMatrix::kAffine_Mask)) {
if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[0] = SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
SkScalarAbs(m[SkMatrix::kMScaleY]));
} else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[0] = SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
SkScalarAbs(m[SkMatrix::kMScaleY]));
} else {
results[0] = SkScalarAbs(m[SkMatrix::kMScaleX]);
results[1] = SkScalarAbs(m[SkMatrix::kMScaleY]);
if (results[0] > results[1]) {
SkTSwap(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 <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[0] = SkMinScalar(a, c);
} else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
results[0] = SkMaxScalar(a, c);
} else {
results[0] = a;
results[1] = c;
if (results[0] > results[1]) {
SkTSwap(results[0], results[1]);
}
}
} else {
SkScalar aminusc = a - c;
SkScalar apluscdiv2 = SkScalarHalf(a + c);
SkScalar x = SkScalarHalf(SkScalarSqrt(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;
}
}
SkASSERT(results[0] >= 0);
results[0] = SkScalarSqrt(results[0]);
if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
SkASSERT(results[1] >= 0);
results[1] = SkScalarSqrt(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);
}
namespace {
struct PODMatrix {
SkScalar matrix[9];
uint32_t typemask;
const SkMatrix& asSkMatrix() const { return *reinterpret_cast<const SkMatrix*>(this); }
};
SK_COMPILE_ASSERT(sizeof(PODMatrix) == sizeof(SkMatrix), PODMatrixSizeMismatch);
}
const SkMatrix& SkMatrix::I() {
SK_COMPILE_ASSERT(offsetof(SkMatrix, fMat) == offsetof(PODMatrix, matrix), BadfMat);
SK_COMPILE_ASSERT(offsetof(SkMatrix, fTypeMask) == offsetof(PODMatrix, typemask), BadfTypeMask);
static const PODMatrix identity = { {SK_Scalar1, 0, 0,
0, SK_Scalar1, 0,
0, 0, SK_Scalar1 },
kIdentity_Mask | kRectStaysRect_Mask};
SkASSERT(identity.asSkMatrix().isIdentity());
return identity.asSkMatrix();
}
const SkMatrix& SkMatrix::InvalidMatrix() {
SK_COMPILE_ASSERT(offsetof(SkMatrix, fMat) == offsetof(PODMatrix, matrix), BadfMat);
SK_COMPILE_ASSERT(offsetof(SkMatrix, fTypeMask) == offsetof(PODMatrix, typemask), BadfTypeMask);
static const PODMatrix invalid =
{ {SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
SK_ScalarMax, SK_ScalarMax, SK_ScalarMax },
kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask };
return invalid.asSkMatrix();
}
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;
}
if (buffer) {
memcpy(fMat, buffer, sizeInMemory);
this->setTypeMask(kUnknown_Mask);
}
return sizeInMemory;
}
#ifdef SK_DEVELOPER
void SkMatrix::dump() const {
SkString str;
this->toString(&str);
SkDebugf("%s\n", str.c_str());
}
#endif
#ifndef SK_IGNORE_TO_STRING
void SkMatrix::toString(SkString* str) const {
str->appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
fMat[6], fMat[7], fMat[8]);
}
#endif
#include "SkMatrixUtils.h"
bool SkTreatAsSprite(const SkMatrix& mat, int width, int height,
unsigned subpixelBits) {
if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
return false;
}
if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
return true;
}
if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
return false;
}
SkRect dst;
SkIRect isrc = { 0, 0, width, height };
{
SkRect src;
src.set(isrc);
mat.mapRect(&dst, src);
}
isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
SkScalarRoundToInt(mat.getTranslateY()));
if (subpixelBits) {
isrc.fLeft <<= subpixelBits;
isrc.fTop <<= subpixelBits;
isrc.fRight <<= subpixelBits;
isrc.fBottom <<= subpixelBits;
const float scale = 1 << subpixelBits;
dst.fLeft *= scale;
dst.fTop *= scale;
dst.fRight *= scale;
dst.fBottom *= scale;
}
SkIRect idst;
dst.round(&idst);
return isrc == idst;
}
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 = SkScalarInvert(SkScalarSqrt(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(SkDoubleToScalar(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 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa);
SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cos1*cos1 + sin1*sin1));
cos1 *= reciplen;
sin1 *= reciplen;
cos2 = cos1*cosQ - sin1*sinQ;
sin2 = sin1*cosQ + cos1*sinQ;
sin1 = -sin1;
}
if (NULL != scale) {
scale->fX = SkDoubleToScalar(w1);
scale->fY = SkDoubleToScalar(w2);
}
if (NULL != rotation1) {
rotation1->fX = cos1;
rotation1->fY = sin1;
}
if (NULL != rotation2) {
rotation2->fX = cos2;
rotation2->fY = sin2;
}
return true;
}