summaryrefslogtreecommitdiffstats
path: root/skia/include/corecg/SkMatrix.h
diff options
context:
space:
mode:
Diffstat (limited to 'skia/include/corecg/SkMatrix.h')
-rw-r--r--skia/include/corecg/SkMatrix.h476
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
+