• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkMatrixPriv_DEFINE
9 #define SkMatrixPriv_DEFINE
10 
11 #include "include/core/SkM44.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkPoint.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkScalar.h"
16 #include "include/core/SkTypes.h"
17 #include "src/base/SkVx.h"
18 
19 #include <cstdint>
20 #include <cstring>
21 struct SkPoint3;
22 
23 class SkMatrixPriv {
24 public:
25     enum {
26         // writeTo/readFromMemory will never return a value larger than this
27         kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t),
28     };
29 
WriteToMemory(const SkMatrix & matrix,void * buffer)30     static size_t WriteToMemory(const SkMatrix& matrix, void* buffer) {
31         return matrix.writeToMemory(buffer);
32     }
33 
ReadFromMemory(SkMatrix * matrix,const void * buffer,size_t length)34     static size_t ReadFromMemory(SkMatrix* matrix, const void* buffer, size_t length) {
35         return matrix->readFromMemory(buffer, length);
36     }
37 
38     typedef SkMatrix::MapXYProc MapXYProc;
39     typedef SkMatrix::MapPtsProc MapPtsProc;
40 
41 
GetMapPtsProc(const SkMatrix & matrix)42     static MapPtsProc GetMapPtsProc(const SkMatrix& matrix) {
43         return SkMatrix::GetMapPtsProc(matrix.getType());
44     }
45 
GetMapXYProc(const SkMatrix & matrix)46     static MapXYProc GetMapXYProc(const SkMatrix& matrix) {
47         return SkMatrix::GetMapXYProc(matrix.getType());
48     }
49 
50     /**
51      *  Attempt to map the rect through the inverse of the matrix. If it is not invertible,
52      *  then this returns false and dst is unchanged.
53      */
InverseMapRect(const SkMatrix & mx,SkRect * dst,const SkRect & src)54     static bool SK_WARN_UNUSED_RESULT InverseMapRect(const SkMatrix& mx,
55                                                      SkRect* dst, const SkRect& src) {
56         if (mx.getType() <= SkMatrix::kTranslate_Mask) {
57             SkScalar tx = mx.getTranslateX();
58             SkScalar ty = mx.getTranslateY();
59             skvx::float4 trans(tx, ty, tx, ty);
60             (skvx::float4::Load(&src.fLeft) - trans).store(&dst->fLeft);
61             return true;
62         }
63         // Insert other special-cases here (e.g. scale+translate)
64 
65         // general case
66         SkMatrix inverse;
67         if (mx.invert(&inverse)) {
68             inverse.mapRect(dst, src);
69             return true;
70         }
71         return false;
72     }
73 
74     /** Maps count pts, skipping stride bytes to advance from one SkPoint to the next.
75         Points are mapped by multiplying each SkPoint by SkMatrix. Given:
76 
77                      | A B C |        | x |
78             Matrix = | D E F |,  pt = | y |
79                      | G H I |        | 1 |
80 
81         each resulting pts SkPoint is computed as:
82 
83                           |A B C| |x|                               Ax+By+C   Dx+Ey+F
84             Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
85                           |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
86 
87         @param mx      matrix used to map the points
88         @param pts     storage for mapped points
89         @param stride  size of record starting with SkPoint, in bytes
90         @param count   number of points to transform
91     */
MapPointsWithStride(const SkMatrix & mx,SkPoint pts[],size_t stride,int count)92     static void MapPointsWithStride(const SkMatrix& mx, SkPoint pts[], size_t stride, int count) {
93         SkASSERT(stride >= sizeof(SkPoint));
94         SkASSERT(0 == stride % sizeof(SkScalar));
95 
96         SkMatrix::TypeMask tm = mx.getType();
97 
98         if (SkMatrix::kIdentity_Mask == tm) {
99             return;
100         }
101         if (SkMatrix::kTranslate_Mask == tm) {
102             const SkScalar tx = mx.getTranslateX();
103             const SkScalar ty = mx.getTranslateY();
104             skvx::float2 trans(tx, ty);
105             for (int i = 0; i < count; ++i) {
106                 (skvx::float2::Load(&pts->fX) + trans).store(&pts->fX);
107                 pts = (SkPoint*)((intptr_t)pts + stride);
108             }
109             return;
110         }
111         // Insert other special-cases here (e.g. scale+translate)
112 
113         // general case
114         SkMatrix::MapXYProc proc = mx.getMapXYProc();
115         for (int i = 0; i < count; ++i) {
116             proc(mx, pts->fX, pts->fY, pts);
117             pts = (SkPoint*)((intptr_t)pts + stride);
118         }
119     }
120 
121     /** Maps src SkPoint array of length count to dst SkPoint array, skipping stride bytes
122         to advance from one SkPoint to the next.
123         Points are mapped by multiplying each SkPoint by SkMatrix. Given:
124 
125                      | A B C |         | x |
126             Matrix = | D E F |,  src = | y |
127                      | G H I |         | 1 |
128 
129         each resulting dst SkPoint is computed as:
130 
131                           |A B C| |x|                               Ax+By+C   Dx+Ey+F
132             Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
133                           |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
134 
135         @param mx      matrix used to map the points
136         @param dst     storage for mapped points
137         @param src     points to transform
138         @param stride  size of record starting with SkPoint, in bytes
139         @param count   number of points to transform
140     */
MapPointsWithStride(const SkMatrix & mx,SkPoint dst[],size_t dstStride,const SkPoint src[],size_t srcStride,int count)141     static void MapPointsWithStride(const SkMatrix& mx, SkPoint dst[], size_t dstStride,
142                                     const SkPoint src[], size_t srcStride, int count) {
143         SkASSERT(srcStride >= sizeof(SkPoint));
144         SkASSERT(dstStride >= sizeof(SkPoint));
145         SkASSERT(0 == srcStride % sizeof(SkScalar));
146         SkASSERT(0 == dstStride % sizeof(SkScalar));
147         for (int i = 0; i < count; ++i) {
148             mx.mapPoints(dst, src, 1);
149             src = (SkPoint*)((intptr_t)src + srcStride);
150             dst = (SkPoint*)((intptr_t)dst + dstStride);
151         }
152     }
153 
154     static void MapHomogeneousPointsWithStride(const SkMatrix& mx, SkPoint3 dst[], size_t dstStride,
155                                                const SkPoint3 src[], size_t srcStride, int count);
156 
PostIDiv(SkMatrix * matrix,int divx,int divy)157     static bool PostIDiv(SkMatrix* matrix, int divx, int divy) {
158         return matrix->postIDiv(divx, divy);
159     }
160 
CheapEqual(const SkMatrix & a,const SkMatrix & b)161     static bool CheapEqual(const SkMatrix& a, const SkMatrix& b) {
162         return &a == &b || 0 == memcmp(a.fMat, b.fMat, sizeof(a.fMat));
163     }
164 
M44ColMajor(const SkM44 & m)165     static const SkScalar* M44ColMajor(const SkM44& m) { return m.fMat; }
166 
167     // This is legacy functionality that only checks the 3x3 portion. The matrix could have Z-based
168     // shear, or other complex behavior. Only use this if you're planning to use the information
169     // to accelerate some purely 2D operation.
IsScaleTranslateAsM33(const SkM44 & m)170     static bool IsScaleTranslateAsM33(const SkM44& m) {
171         return m.rc(1,0) == 0 && m.rc(3,0) == 0 &&
172                m.rc(0,1) == 0 && m.rc(3,1) == 0 &&
173                m.rc(3,3) == 1;
174 
175     }
176 
177     // Map the four corners of 'r' and return the bounding box of those points. The four corners of
178     // 'r' are assumed to have z = 0 and w = 1. If the matrix has perspective, the returned
179     // rectangle will be the bounding box of the projected points after being clipped to w > 0.
180     static SkRect MapRect(const SkM44& m, const SkRect& r);
181 
182     // Returns the differential area scale factor for a local point 'p' that will be transformed
183     // by 'm' (which may have perspective). If 'm' does not have perspective, this scale factor is
184     // constant regardless of 'p'; when it does have perspective, it is specific to that point.
185     //
186     // This can be crudely thought of as "device pixel area" / "local pixel area" at 'p'.
187     //
188     // Returns positive infinity if the transformed homogeneous point has w <= 0.
189     static SkScalar DifferentialAreaScale(const SkMatrix& m, const SkPoint& p);
190 
191     // Determines if the transformation m applied to the bounds can be approximated by
192     // an affine transformation, i.e., the perspective part of the transformation has little
193     // visible effect.
194     static bool NearlyAffine(const SkMatrix& m,
195                              const SkRect& bounds,
196                              SkScalar tolerance = SK_ScalarNearlyZero);
197 
198     static SkScalar ComputeResScaleForStroking(const SkMatrix& matrix);
199 };
200 
201 #endif
202