diff options
Diffstat (limited to 'skia/include/corecg/SkMatrix.h')
-rw-r--r-- | skia/include/corecg/SkMatrix.h | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/skia/include/corecg/SkMatrix.h b/skia/include/corecg/SkMatrix.h new file mode 100644 index 0000000..60fdd42 --- /dev/null +++ b/skia/include/corecg/SkMatrix.h @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2006-2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkMatrix_DEFINED +#define SkMatrix_DEFINED + +#include "SkRect.h" + +/** \class SkMatrix + + The SkMatrix class holds a 3x3 matrix for transforming coordinates. + SkMatrix does not have a constructor, so it must be explicitly initialized + using either reset() - to construct an identity matrix, or one of the set + functions (e.g. setTranslate, setRotate, etc.). +*/ +class SkMatrix { +public: + /** Enum of bit fields for the mask return by getType(). + Use this to identify the complexity of the matrix. + */ + enum TypeMask { + kIdentity_Mask = 0, + kTranslate_Mask = 0x01, //!< set if the matrix has translation + kScale_Mask = 0x02, //!< set if the matrix has X or Y scale + kAffine_Mask = 0x04, //!< set if the matrix skews or rotates + kPerspective_Mask = 0x08 //!< set if the matrix is in perspective + }; + + /** Returns a mask bitfield describing the types of transformations + that the matrix will perform. This information is used by routines + like mapPoints, to optimize its inner loops to only perform as much + arithmetic as is necessary. + */ + TypeMask getType() const { + if (fTypeMask & kUnknown_Mask) { + fTypeMask = this->computeTypeMask(); + } + // only return the public masks + return (TypeMask)(fTypeMask & 0xF); + } + + /** Returns true if the matrix is identity. + */ + bool isIdentity() const { + return this->getType() == 0; + } + + /** Returns true if will map a rectangle to another rectangle. This can be + true if the matrix is identity, scale-only, or rotates a multiple of + 90 degrees. + */ + bool rectStaysRect() const { + if (fTypeMask & kUnknown_Mask) { + fTypeMask = this->computeTypeMask(); + } + return (fTypeMask & kRectStaysRect_Mask) != 0; + } + + enum { + kMScaleX, + kMSkewX, + kMTransX, + kMSkewY, + kMScaleY, + kMTransY, + kMPersp0, + kMPersp1, + kMPersp2 + }; + + SkScalar operator[](int index) const { + SkASSERT((unsigned)index < 9); + return fMat[index]; + } + + SkScalar get(int index) const { + SkASSERT((unsigned)index < 9); + return fMat[index]; + } + + SkScalar getScaleX() const { return fMat[kMScaleX]; } + SkScalar getScaleY() const { return fMat[kMScaleY]; } + SkScalar getSkewY() const { return fMat[kMSkewY]; } + SkScalar getSkewX() const { return fMat[kMSkewX]; } + SkScalar getTranslateX() const { return fMat[kMTransX]; } + SkScalar getTranslateY() const { return fMat[kMTransY]; } + SkScalar getPerspX() const { return fMat[kMPersp0]; } + SkScalar getPerspY() const { return fMat[kMPersp1]; } + + void set(int index, SkScalar value) { + SkASSERT((unsigned)index < 9); + fMat[index] = value; + this->setTypeMask(kUnknown_Mask); + } + + void setScaleX(SkScalar v) { this->set(kMScaleX, v); } + void setScaleY(SkScalar v) { this->set(kMScaleY, v); } + void setSkewY(SkScalar v) { this->set(kMSkewY, v); } + void setSkewX(SkScalar v) { this->set(kMSkewX, v); } + void setTranslateX(SkScalar v) { this->set(kMTransX, v); } + void setTranslateY(SkScalar v) { this->set(kMTransY, v); } + void setPerspX(SkScalar v) { this->set(kMPersp0, v); } + void setPerspY(SkScalar v) { this->set(kMPersp1, v); } + + /** Set the matrix to identity + */ + void reset(); + + /** Set the matrix to translate by (dx, dy). + */ + void setTranslate(SkScalar dx, SkScalar dy); + /** Set the matrix to scale by sx and sy, with a pivot point at (px, py). + The pivot point is the coordinate that should remain unchanged by the + specified transformation. + */ + void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + /** Set the matrix to scale by sx and sy. + */ + void setScale(SkScalar sx, SkScalar sy); + /** Set the matrix to rotate by the specified number of degrees, with a + pivot point at (px, py). The pivot point is the coordinate that should + remain unchanged by the specified transformation. + */ + void setRotate(SkScalar degrees, SkScalar px, SkScalar py); + /** Set the matrix to rotate about (0,0) by the specified number of degrees. + */ + void setRotate(SkScalar degrees); + /** Set the matrix to rotate by the specified sine and cosine values, with + a pivot point at (px, py). The pivot point is the coordinate that + should remain unchanged by the specified transformation. + */ + void setSinCos(SkScalar sinValue, SkScalar cosValue, + SkScalar px, SkScalar py); + /** Set the matrix to rotate by the specified sine and cosine values. + */ + void setSinCos(SkScalar sinValue, SkScalar cosValue); + /** Set the matrix to skew by sx and sy, with a pivot point at (px, py). + The pivot point is the coordinate that should remain unchanged by the + specified transformation. + */ + void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + /** Set the matrix to skew by sx and sy. + */ + void setSkew(SkScalar kx, SkScalar ky); + /** Set the matrix to the concatenation of the two specified matrices, + returning true if the the result can be represented. Either of the + two matrices may also be the target matrix. *this = a * b; + */ + bool setConcat(const SkMatrix& a, const SkMatrix& b); + + /** Preconcats the matrix with the specified translation. + M' = M * T(dx, dy) + */ + bool preTranslate(SkScalar dx, SkScalar dy); + /** Preconcats the matrix with the specified scale. + M' = M * S(sx, sy, px, py) + */ + bool preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + /** Preconcats the matrix with the specified scale. + M' = M * S(sx, sy) + */ + bool preScale(SkScalar sx, SkScalar sy); + /** Preconcats the matrix with the specified rotation. + M' = M * R(degrees, px, py) + */ + bool preRotate(SkScalar degrees, SkScalar px, SkScalar py); + /** Preconcats the matrix with the specified rotation. + M' = M * R(degrees) + */ + bool preRotate(SkScalar degrees); + /** Preconcats the matrix with the specified skew. + M' = M * K(kx, ky, px, py) + */ + bool preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + /** Preconcats the matrix with the specified skew. + M' = M * K(kx, ky) + */ + bool preSkew(SkScalar kx, SkScalar ky); + /** Preconcats the matrix with the specified matrix. + M' = M * other + */ + bool preConcat(const SkMatrix& other); + + /** Postconcats the matrix with the specified translation. + M' = T(dx, dy) * M + */ + bool postTranslate(SkScalar dx, SkScalar dy); + /** Postconcats the matrix with the specified scale. + M' = S(sx, sy, px, py) * M + */ + bool postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + /** Postconcats the matrix with the specified scale. + M' = S(sx, sy) * M + */ + bool postScale(SkScalar sx, SkScalar sy); + /** Postconcats the matrix by dividing it by the specified integers. + M' = S(1/divx, 1/divy, 0, 0) * M + */ + bool postIDiv(int divx, int divy); + /** Postconcats the matrix with the specified rotation. + M' = R(degrees, px, py) * M + */ + bool postRotate(SkScalar degrees, SkScalar px, SkScalar py); + /** Postconcats the matrix with the specified rotation. + M' = R(degrees) * M + */ + bool postRotate(SkScalar degrees); + /** Postconcats the matrix with the specified skew. + M' = K(kx, ky, px, py) * M + */ + bool postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + /** Postconcats the matrix with the specified skew. + M' = K(kx, ky) * M + */ + bool postSkew(SkScalar kx, SkScalar ky); + /** Postconcats the matrix with the specified matrix. + M' = other * M + */ + bool postConcat(const SkMatrix& other); + + enum ScaleToFit { + /** + * Scale in X and Y independently, so that src matches dst exactly. + * This may change the aspect ratio of the src. + */ + kFill_ScaleToFit, + /** + * Compute a scale that will maintain the original src aspect ratio, + * but will also ensure that src fits entirely inside dst. At least one + * axis (X or Y) will fit exactly. kStart aligns the result to the + * left and top edges of dst. + */ + kStart_ScaleToFit, + /** + * Compute a scale that will maintain the original src aspect ratio, + * but will also ensure that src fits entirely inside dst. At least one + * axis (X or Y) will fit exactly. The result is centered inside dst. + */ + kCenter_ScaleToFit, + /** + * Compute a scale that will maintain the original src aspect ratio, + * but will also ensure that src fits entirely inside dst. At least one + * axis (X or Y) will fit exactly. kEnd aligns the result to the + * right and bottom edges of dst. + */ + kEnd_ScaleToFit + }; + + /** Set the matrix to the scale and translate values that map the source + rectangle to the destination rectangle, returning true if the the result + can be represented. + @param src the source rectangle to map from. + @param dst the destination rectangle to map to. + @param stf the ScaleToFit option + @return true if the matrix can be represented by the rectangle mapping. + */ + bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf); + + /** Set the matrix such that the specified src points would map to the + specified dst points. count must be within [0..4]. + @param src The array of src points + @param dst The array of dst points + @param count The number of points to use for the transformation + @return true if the matrix was set to the specified transformation + */ + bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count); + + /** If this matrix can be inverted, return true and if inverse is not null, + set inverse to be the inverse of this matrix. If this matrix cannot be + inverted, ignore inverse and return false + */ + bool invert(SkMatrix* inverse) const; + + /** Apply this matrix to the array of points specified by src, and write + the transformed points into the array of points specified by dst. + dst[] = M * src[] + @param dst Where the transformed coordinates are written. It must + contain at least count entries + @param src The original coordinates that are to be transformed. It + must contain at least count entries + @param count The number of points in src to read, and then transform + into dst. + */ + void mapPoints(SkPoint dst[], const SkPoint src[], int count) const; + + /** Apply this matrix to the array of points, overwriting it with the + transformed values. + dst[] = M * pts[] + @param pts The points to be transformed. It must contain at least + count entries + @param count The number of points in pts. + */ + void mapPoints(SkPoint pts[], int count) const { + this->mapPoints(pts, pts, count); + } + + void mapXY(SkScalar x, SkScalar y, SkPoint* result) const { + SkASSERT(result); + this->getMapXYProc()(*this, x, y, result); + } + + /** Apply this matrix to the array of vectors specified by src, and write + the transformed vectors into the array of vectors specified by dst. + This is similar to mapPoints, but ignores any translation in the matrix. + @param dst Where the transformed coordinates are written. It must + contain at least count entries + @param src The original coordinates that are to be transformed. It + must contain at least count entries + @param count The number of vectors in src to read, and then transform + into dst. + */ + void mapVectors(SkVector dst[], const SkVector src[], int count) const; + + /** Apply this matrix to the array of vectors specified by src, and write + the transformed vectors into the array of vectors specified by dst. + This is similar to mapPoints, but ignores any translation in the matrix. + @param vecs The vectors to be transformed. It must contain at least + count entries + @param count The number of vectors in vecs. + */ + void mapVectors(SkVector vecs[], int count) const { + this->mapVectors(vecs, vecs, count); + } + + /** Apply this matrix to the src rectangle, and write the transformed + rectangle into dst. This is accomplished by transforming the 4 corners + of src, and then setting dst to the bounds of those points. + @param dst Where the transformed rectangle is written. + @param src The original rectangle to be transformed. + @return the result of calling rectStaysRect() + */ + bool mapRect(SkRect* dst, const SkRect& src) const; + + /** Apply this matrix to the rectangle, and write the transformed rectangle + back into it. This is accomplished by transforming the 4 corners of + rect, and then setting it to the bounds of those points + @param rect The rectangle to transform. + @return the result of calling rectStaysRect() + */ + bool mapRect(SkRect* rect) const { + return this->mapRect(rect, *rect); + } + + /** Return the mean radius of a circle after it has been mapped by + this matrix. NOTE: in perspective this value assumes the circle + has its center at the origin. + */ + SkScalar mapRadius(SkScalar radius) const; + + typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y, + SkPoint* result); + + static MapXYProc GetMapXYProc(TypeMask mask) { + SkASSERT((mask & ~kAllMasks) == 0); + return gMapXYProcs[mask & kAllMasks]; + } + + MapXYProc getMapXYProc() const { + return GetMapXYProc(this->getType()); + } + + typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[], + const SkPoint src[], int count); + + static MapPtsProc GetMapPtsProc(TypeMask mask) { + SkASSERT((mask & ~kAllMasks) == 0); + return gMapPtsProcs[mask & kAllMasks]; + } + + MapPtsProc getMapPtsProc() const { + return GetMapPtsProc(this->getType()); + } + + /** If the matrix can be stepped in X (not complex perspective) + then return true and if step[XY] is not null, return the step[XY] value. + If it cannot, return false and ignore step. + */ + bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const; + + friend bool operator==(const SkMatrix& a, const SkMatrix& b) { + return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) == 0; + } + + friend bool operator!=(const SkMatrix& a, const SkMatrix& b) { + return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) != 0; + } + + void dump() const; + +#ifdef SK_DEBUG + /** @cond UNIT_TEST */ + + static void UnitTest(); + /** @endcond */ +#endif + +private: + enum { + /** Set if the matrix will map a rectangle to another rectangle. This + can be true if the matrix is scale-only, or rotates a multiple of + 90 degrees. This bit is not set if the matrix is identity. + + This bit will be set on identity matrices + */ + kRectStaysRect_Mask = 0x10, + + kUnknown_Mask = 0x80, + + kAllMasks = kTranslate_Mask | + kScale_Mask | + kAffine_Mask | + kPerspective_Mask | + kRectStaysRect_Mask + }; + + SkScalar fMat[9]; + mutable uint8_t fTypeMask; + + uint8_t computeTypeMask() const; + + void setTypeMask(int mask) { + // allow kUnknown or a valid mask + SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask); + fTypeMask = SkToU8(mask); + } + + void clearTypeMask(int mask) { + // only allow a valid mask + SkASSERT((mask & kAllMasks) == mask); + fTypeMask &= ~mask; + } + + static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); + static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); + static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); + + static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + + static const MapXYProc gMapXYProcs[]; + + static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int); + static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], + int count); + static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], + int count); + static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + + static const MapPtsProc gMapPtsProcs[]; + + friend class SkPerspIter; +}; + +#endif + |