123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800 |
- /*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "include/core/SkMatrix.h"
- #include "include/core/SkPaint.h"
- #include "include/core/SkPoint3.h"
- #include "include/core/SkRSXform.h"
- #include "include/core/SkString.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 <cstddef>
- #include <utility>
- static void normalize_perspective(SkScalar mat[9]) {
- // If it was interesting to never store the last element, we could divide all 8 other
- // elements here by the 9th, making it 1.0...
- //
- // When SkScalar was SkFixed, we would sometimes rescale the entire matrix to keep its
- // component values from getting too large. This is not a concern when using floats/doubles,
- // so we do nothing now.
- // Disable this for now, but it could be enabled.
- #if 0
- if (0 == mat[SkMatrix::kMPersp0] && 0 == mat[SkMatrix::kMPersp1]) {
- SkScalar p2 = mat[SkMatrix::kMPersp2];
- if (p2 != 0 && p2 != 1) {
- double inv = 1.0 / p2;
- for (int i = 0; i < 6; ++i) {
- mat[i] = SkDoubleToScalar(mat[i] * inv);
- }
- mat[SkMatrix::kMPersp2] = 1;
- }
- }
- #endif
- }
- // In a few places, we performed the following
- // a * b + c * d + e
- // as
- // a * b + (c * d + e)
- //
- // sdot and scross are indended to capture these compound operations into a
- // function, with an eye toward considering upscaling the intermediates to
- // doubles for more precision (as we do in concat and invert).
- //
- // However, these few lines that performed the last add before the "dot", cause
- // tiny image differences, so we guard that change until we see the impact on
- // chrome's layouttests.
- //
- #define SK_LEGACY_MATRIX_MATH_ORDER
- /* [scale-x skew-x trans-x] [X] [X']
- [skew-y scale-y trans-y] * [Y] = [Y']
- [persp-0 persp-1 persp-2] [1] [1 ]
- */
- SkMatrix& SkMatrix::reset() { *this = SkMatrix(); return *this; }
- SkMatrix& SkMatrix::set9(const SkScalar buffer[]) {
- memcpy(fMat, buffer, 9 * sizeof(SkScalar));
- normalize_perspective(fMat);
- this->setTypeMask(kUnknown_Mask);
- return *this;
- }
- SkMatrix& SkMatrix::setAffine(const SkScalar buffer[]) {
- fMat[kMScaleX] = buffer[kAScaleX];
- fMat[kMSkewX] = buffer[kASkewX];
- fMat[kMTransX] = buffer[kATransX];
- fMat[kMSkewY] = buffer[kASkewY];
- fMat[kMScaleY] = buffer[kAScaleY];
- fMat[kMTransY] = buffer[kATransY];
- fMat[kMPersp0] = 0;
- fMat[kMPersp1] = 0;
- fMat[kMPersp2] = 1;
- this->setTypeMask(kUnknown_Mask);
- return *this;
- }
- // this guy aligns with the masks, so we can compute a mask from a varaible 0/1
- enum {
- kTranslate_Shift,
- kScale_Shift,
- kAffine_Shift,
- kPerspective_Shift,
- kRectStaysRect_Shift
- };
- static const int32_t kScalar1Int = 0x3f800000;
- uint8_t SkMatrix::computePerspectiveTypeMask() const {
- // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment
- // is a win, but replacing those below is not. We don't yet understand
- // that result.
- if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
- // If this is a perspective transform, we return true for all other
- // transform flags - this does not disable any optimizations, respects
- // the rule that the type mask must be conservative, and speeds up
- // type mask computation.
- 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) {
- // Once it is determined that that this is a perspective transform,
- // all other flags are moot as far as optimizations are concerned.
- 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) {
- // The skew components may be scale-inducing, unless we are dealing
- // with a pure rotation. Testing for a pure rotation is expensive,
- // so we opt for being conservative by always setting the scale bit.
- // along with affine.
- // By doing this, we are also ensuring that matrices have the same
- // type masks as their inverses.
- mask |= kAffine_Mask | kScale_Mask;
- // For rectStaysRect, in the affine case, we only need check that
- // the primary diagonal is all zeros and that the secondary diagonal
- // is all non-zero.
- // map non-zero to 1
- m01 = m01 != 0;
- m10 = m10 != 0;
- int dp0 = 0 == (m00 | m11) ; // true if both are 0
- int ds1 = m01 & m10; // true if both are 1
- mask |= (dp0 & ds1) << kRectStaysRect_Shift;
- } else {
- // Only test for scale explicitly if not affine, since affine sets the
- // scale bit.
- if ((m00 ^ kScalar1Int) | (m11 ^ kScalar1Int)) {
- mask |= kScale_Mask;
- }
- // Not affine, therefore we already know secondary diagonal is
- // all zeros, so we just need to check that primary diagonal is
- // all non-zero.
- // map non-zero to 1
- m00 = m00 != 0;
- m11 = m11 != 0;
- // record if the (p)rimary diagonal is all non-zero
- 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];
- }
- ///////////////////////////////////////////////////////////////////////////////
- // helper function to determine if upper-left 2x2 of matrix is degenerate
- 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 {
- // if identity or translate matrix
- 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 no skew, can just compare scale factors
- 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;
- }
- // upper 2x2 is rotation/reflection + uniform scale if basis vectors
- // are 90 degree rotations of each other
- return (SkScalarNearlyEqual(mx, my, tol) && SkScalarNearlyEqual(sx, -sy, tol))
- || (SkScalarNearlyEqual(mx, -my, tol) && SkScalarNearlyEqual(sx, sy, tol));
- }
- bool SkMatrix::preservesRightAngles(SkScalar tol) const {
- TypeMask mask = this->getType();
- if (mask <= kTranslate_Mask) {
- // identity, translate and/or scale
- return true;
- }
- if (mask & kPerspective_Mask) {
- return false;
- }
- SkASSERT(mask & (kAffine_Mask | kScale_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;
- }
- // upper 2x2 is scale + rotation/reflection if basis vectors are orthogonal
- SkVector vec[2];
- vec[0].set(mx, sy);
- vec[1].set(sx, my);
- return SkScalarNearlyZero(vec[0].dot(vec[1]), 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;
- }
- 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;
- }
- // the assumption is that these multiplies are very cheap, and that
- // a full concat and/or just computing the matrix type is more expensive.
- // Also, the fixed-point case checks for overflow, but the float doesn't,
- // so we can get away with these blind multiplies.
- fMat[kMScaleX] *= sx;
- fMat[kMSkewY] *= sx;
- fMat[kMPersp0] *= sx;
- fMat[kMSkewX] *= sy;
- fMat[kMScaleY] *= sy;
- fMat[kMPersp1] *= sy;
- // Attempt to simplify our type when applying an inverse scale.
- // TODO: The persp/affine preconditions are in place to keep the mask consistent with
- // what computeTypeMask() would produce (persp/skew always implies kScale).
- // We should investigate whether these flag dependencies are truly needed.
- 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);
- }
- // this guy perhaps can go away, if we have a fract/high-precision way to
- // scale matrices
- 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::setRSXform(const SkRSXform& xform) {
- fMat[kMScaleX] = xform.fSCos;
- fMat[kMSkewX] = -xform.fSSin;
- fMat[kMTransX] = xform.fTx;
- fMat[kMSkewY] = xform.fSSin;
- fMat[kMScaleY] = xform.fSCos;
- fMat[kMTransY] = xform.fTy;
- 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 = SkDegreesToRadians(degrees);
- return this->setSinCos(SkScalarSinSnapToZero(rad), SkScalarCosSnapToZero(rad), px, py);
- }
- SkMatrix& SkMatrix::setRotate(SkScalar degrees) {
- SkScalar rad = SkDegreesToRadians(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 = SkScalarHalf(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 sk_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]);
- 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]) + 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;
- //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
- //SkASSERT(!(tmp.getType() & kPerspective_Mask));
- tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
- }
- *this = tmp;
- }
- return *this;
- }
- SkMatrix& SkMatrix::preConcat(const SkMatrix& mat) {
- // check for identity first, so we don't do a needless copy of ourselves
- // to ourselves inside setConcat()
- if(!mat.isIdentity()) {
- this->setConcat(*this, mat);
- }
- return *this;
- }
- SkMatrix& SkMatrix::postConcat(const SkMatrix& mat) {
- // check for identity first, so we don't do a needless copy of ourselves
- // to ourselves inside setConcat()
- if (!mat.isIdentity()) {
- this->setConcat(mat, *this);
- }
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- /* Matrix inversion is very expensive, but also the place where keeping
- precision may be most important (here and matrix concat). Hence to avoid
- bitmap blitting artifacts when walking the inverse, we use doubles for
- the intermediate math, even though we know that is more expensive.
- */
- 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]);
- }
- // Since the determinant is on the order of the cube of the matrix members,
- // compare to the cube of the default nearly-zero constant (although an
- // estimate of the condition number would be better if it wasn't so expensive).
- if (SkScalarNearlyZero(sk_double_to_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;
- }
- void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
- SkASSERT((dst && src && count > 0) || 0 == count);
- // no partial overlap
- SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
- this->getMapPtsProc()(*this, dst, src, count);
- }
- void SkMatrix::mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
- SkASSERT(result);
- this->getMapXYProc()(*this, x, y, result);
- }
- void SkMatrix::ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp) {
- SkASSERT(src != dst);
- SkASSERT(src && dst);
- 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 { // not perspective
- dst[kMScaleX] = SkDoubleToScalar(src[kMScaleY] * invDet);
- dst[kMSkewX] = SkDoubleToScalar(-src[kMSkewX] * invDet);
- dst[kMTransX] = dcross_dscale(src[kMSkewX], src[kMTransY], src[kMScaleY], src[kMTransX], invDet);
- dst[kMSkewY] = SkDoubleToScalar(-src[kMSkewY] * invDet);
- dst[kMScaleY] = SkDoubleToScalar(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 {
- 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);
- // Must be careful when writing to inv, since it may be the
- // same memory as this.
- 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 {
- // translate only
- inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
- }
- } else { // inv is nullptr, just check if we're invertible
- if (!fMat[kMScaleX] || !fMat[kMScaleY]) {
- invertible = false;
- }
- }
- return invertible;
- }
- int isPersp = mask & kPerspective_Mask;
- double invDet = sk_inv_determinant(fMat, isPersp);
- if (invDet == 0) { // underflow
- return false;
- }
- bool applyingInPlace = (inv == this);
- SkMatrix* tmp = inv;
- SkMatrix storage;
- if (applyingInPlace || nullptr == tmp) {
- tmp = &storage; // we either need to avoid trampling memory or have no memory
- }
- ComputeInv(tmp->fMat, fMat, invDet, isPersp);
- if (!tmp->isFinite()) {
- return false;
- }
- tmp->setTypeMask(fTypeMask);
- if (applyingInPlace) {
- *inv = storage; // need to copy answer back
- }
- 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() <= SkMatrix::kTranslate_Mask);
- 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) {
- SkASSERT(m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask));
- 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) {
- 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 = 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) {
- SkASSERT(m.getType() != SkMatrix::kPerspective_Mask);
- 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); // applied to swizzle of src4
- count >>= 1;
- for (int i = 0; i < count; ++i) {
- Sk4s src4 = Sk4s::Load(src);
- Sk4s swz4 = SkNx_shuffle<1,0,3,2>(src4); // y0 x0, y1 x1
- (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,
- // repeat the persp proc 8 times
- 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) {
- SkASSERT((dst && src && count > 0) || 0 == count);
- // no partial overlap
- SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
- 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::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);
- }
- }
- 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);
- // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
- // ARM this sequence generates the fastest (a single instruction).
- return Sk4f(min[2], min[3], max[0], max[1]);
- }
- void SkMatrix::mapRectScaleTranslate(SkRect* dst, const SkRect& src) const {
- SkASSERT(dst);
- SkASSERT(this->isScaleTranslate());
- 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 {
- SkASSERT(dst);
- 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(); // might still return true if rotated by 90, etc.
- }
- }
- 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 geometric mean
- 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 = 1 / 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,
- // repeat the persp proc 8 times
- SkMatrix::Persp_xy, SkMatrix::Persp_xy,
- SkMatrix::Persp_xy, SkMatrix::Persp_xy,
- SkMatrix::Persp_xy, SkMatrix::Persp_xy,
- SkMatrix::Persp_xy, SkMatrix::Persp_xy
- };
- ///////////////////////////////////////////////////////////////////////////////
- // if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
- #define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26)))
- bool SkMatrix::isFixedStepInX() const {
- return PerspNearlyZero(fMat[kMPersp0]);
- }
- SkVector SkMatrix::fixedStepInX(SkScalar y) const {
- SkASSERT(PerspNearlyZero(fMat[kMPersp0]));
- if (PerspNearlyZero(fMat[kMPersp1]) &&
- PerspNearlyZero(fMat[kMPersp2] - 1)) {
- return SkVector::Make(fMat[kMScaleX], fMat[kMSkewY]);
- } else {
- SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2];
- return SkVector::Make(fMat[kMScaleX] / z, fMat[kMSkewY] / z);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- 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;
- /* check if abs(x2) > abs(y2) */
- 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;
- }
- /* check if abs(x1) > abs(y1) */
- 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;
- }
- typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*);
- /* Adapted from Rob Johnson's original sample code in QuickDraw GX
- */
- 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;
- }
- const PolyMapProc gPolyMapProcs[] = {
- SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
- };
- PolyMapProc proc = gPolyMapProcs[count - 2];
- SkMatrix tempMap, result;
- if (!proc(src, &tempMap)) {
- return false;
- }
- if (!tempMap.invert(&result)) {
- return false;
- }
- if (!proc(dst, &tempMap)) {
- 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[/*1 or 2*/]) {
- 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]) {
- using std::swap;
- swap(results[0], results[1]);
- }
- }
- return true;
- }
- // ignore the translation part of the matrix, just look at 2x2 portion.
- // compute singular values, take largest or smallest abs value.
- // [a b; b c] = A^T*A
- 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]);
- // eigenvalues of A^T*A are the squared singular values of A.
- // characteristic equation is det((A^T*A) - l*I) = 0
- // l^2 - (a + c)l + (ac-b^2)
- // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
- // and roots are guaranteed to be pos and real).
- SkScalar bSqd = b * b;
- // if upper left 2x2 is orthogonal save some math
- 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]) {
- using std::swap;
- swap(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;
- }
- }
- if (!SkScalarIsFinite(results[0])) {
- return false;
- }
- // Due to the floating point inaccuracy, there might be an error in a, b, c
- // calculated by sdot, further deepened by subsequent arithmetic operations
- // on them. Therefore, we allow and cap the nearly-zero negative values.
- SkASSERT(results[0] >= -SK_ScalarNearlyZero);
- if (results[0] < 0) {
- results[0] = 0;
- }
- results[0] = SkScalarSqrt(results[0]);
- if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
- if (!SkScalarIsFinite(results[1])) {
- return false;
- }
- SkASSERT(results[1] >= -SK_ScalarNearlyZero);
- if (results[1] < 0) {
- 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);
- }
- const SkMatrix& SkMatrix::I() {
- static constexpr SkMatrix identity;
- SkASSERT(identity.isIdentity());
- return identity;
- }
- const SkMatrix& SkMatrix::InvalidMatrix() {
- static constexpr SkMatrix 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;
- }
- bool SkMatrix::decomposeScale(SkSize* scale, SkMatrix* remaining) const {
- if (this->hasPerspective()) {
- return false;
- }
- const SkScalar sx = SkVector::Length(this->getScaleX(), this->getSkewY());
- const SkScalar sy = SkVector::Length(this->getSkewX(), this->getScaleY());
- if (!SkScalarIsFinite(sx) || !SkScalarIsFinite(sy) ||
- SkScalarNearlyZero(sx) || SkScalarNearlyZero(sy)) {
- return false;
- }
- if (scale) {
- scale->set(sx, sy);
- }
- if (remaining) {
- *remaining = *this;
- remaining->preScale(SkScalarInvert(sx), SkScalarInvert(sy));
- }
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////
- size_t SkMatrix::writeToMemory(void* buffer) const {
- // TODO write less for simple matrices
- 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);
- return sizeInMemory;
- }
- void SkMatrix::dump() const {
- SkString str;
- 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]);
- SkDebugf("%s\n", str.c_str());
- }
- ///////////////////////////////////////////////////////////////////////////////
- #include "src/core/SkMatrixUtils.h"
- bool SkTreatAsSprite(const SkMatrix& mat, const SkISize& size, const SkPaint& paint) {
- // Our path aa is 2-bits, and our rect aa is 8, so we could use 8,
- // but in practice 4 seems enough (still looks smooth) and allows
- // more slightly fractional cases to fall into the fast (sprite) case.
- static const unsigned kAntiAliasSubpixelBits = 4;
- const unsigned subpixelBits = paint.isAntiAlias() ? kAntiAliasSubpixelBits : 0;
- // quick reject on affine or perspective
- if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
- return false;
- }
- // quick success check
- if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
- return true;
- }
- // mapRect supports negative scales, so we eliminate those first
- if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
- return false;
- }
- SkRect dst;
- SkIRect isrc = SkIRect::MakeSize(size);
- {
- SkRect src;
- src.set(isrc);
- mat.mapRect(&dst, src);
- }
- // just apply the translate to isrc
- isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
- SkScalarRoundToInt(mat.getTranslateY()));
- if (subpixelBits) {
- isrc.fLeft = SkLeftShift(isrc.fLeft, subpixelBits);
- isrc.fTop = SkLeftShift(isrc.fTop, subpixelBits);
- isrc.fRight = SkLeftShift(isrc.fRight, subpixelBits);
- isrc.fBottom = SkLeftShift(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;
- }
- // A square matrix M can be decomposed (via polar decomposition) into two matrices --
- // an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T,
- // where U is another orthogonal matrix and W is a scale matrix. These can be recombined
- // to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix.
- //
- // The one wrinkle is that traditionally Q may contain a reflection -- the
- // calculation has been rejiggered to put that reflection into W.
- 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;
- // do polar decomposition (M = Q*S)
- SkScalar cosQ, sinQ;
- double Sa, Sb, Sd;
- // if M is already symmetric (i.e., M = I*S)
- 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;
- // S = Q^-1*M
- // we don't calc Sc since it's symmetric
- Sa = A*cosQ + C*sinQ;
- Sb = B*cosQ + D*sinQ;
- Sd = -B*sinQ + D*cosQ;
- }
- // Now we need to compute eigenvalues of S (our scale factors)
- // and eigenvectors (bases for our rotation)
- // From this, should be able to reconstruct S as U*W*U^T
- if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) {
- // already diagonalized
- 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;
- // rotation 2 is composition of Q and U
- cos2 = cos1*cosQ - sin1*sinQ;
- sin2 = sin1*cosQ + cos1*sinQ;
- // rotation 1 is U^T
- sin1 = -sin1;
- }
- if (scale) {
- scale->fX = SkDoubleToScalar(w1);
- scale->fY = SkDoubleToScalar(w2);
- }
- if (rotation1) {
- rotation1->fX = cos1;
- rotation1->fY = sin1;
- }
- if (rotation2) {
- rotation2->fX = cos2;
- rotation2->fY = sin2;
- }
- return true;
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////
- void SkRSXform::toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const {
- #if 0
- // This is the slow way, but it documents what we're doing
- quad[0].set(0, 0);
- quad[1].set(width, 0);
- quad[2].set(width, height);
- quad[3].set(0, height);
- SkMatrix m;
- m.setRSXform(*this).mapPoints(quad, quad, 4);
- #else
- const SkScalar m00 = fSCos;
- const SkScalar m01 = -fSSin;
- const SkScalar m02 = fTx;
- const SkScalar m10 = -m01;
- const SkScalar m11 = m00;
- const SkScalar m12 = fTy;
- quad[0].set(m02, m12);
- quad[1].set(m00 * width + m02, m10 * width + m12);
- quad[2].set(m00 * width + m01 * height + m02, m10 * width + m11 * height + m12);
- quad[3].set(m01 * height + m02, m11 * height + m12);
- #endif
- }
- void SkRSXform::toTriStrip(SkScalar width, SkScalar height, SkPoint strip[4]) const {
- const SkScalar m00 = fSCos;
- const SkScalar m01 = -fSSin;
- const SkScalar m02 = fTx;
- const SkScalar m10 = -m01;
- const SkScalar m11 = m00;
- const SkScalar m12 = fTy;
- strip[0].set(m02, m12);
- strip[1].set(m01 * height + m02, m11 * height + m12);
- strip[2].set(m00 * width + m02, m10 * width + m12);
- strip[3].set(m00 * width + m01 * height + m02, m10 * width + m11 * height + m12);
- }
|