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