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 "SkMatrix.h"
12 #include "SkNx.h"
13 #include "SkPointPriv.h"
14 
15 class SkMatrixPriv {
16 public:
17     enum {
18         // writeTo/readFromMemory will never return a value larger than this
19         kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t),
20     };
21 
WriteToMemory(const SkMatrix & matrix,void * buffer)22     static size_t WriteToMemory(const SkMatrix& matrix, void* buffer) {
23         return matrix.writeToMemory(buffer);
24     }
25 
ReadFromMemory(SkMatrix * matrix,const void * buffer,size_t length)26     static size_t ReadFromMemory(SkMatrix* matrix, const void* buffer, size_t length) {
27         return matrix->readFromMemory(buffer, length);
28     }
29 
30     typedef SkMatrix::MapXYProc MapXYProc;
31     typedef SkMatrix::MapPtsProc MapPtsProc;
32 
33 
GetMapPtsProc(const SkMatrix & matrix)34     static MapPtsProc GetMapPtsProc(const SkMatrix& matrix) {
35         return SkMatrix::GetMapPtsProc(matrix.getType());
36     }
37 
GetMapXYProc(const SkMatrix & matrix)38     static MapXYProc GetMapXYProc(const SkMatrix& matrix) {
39         return SkMatrix::GetMapXYProc(matrix.getType());
40     }
41 
42     /**
43      *  Attempt to map the rect through the inverse of the matrix. If it is not invertible,
44      *  then this returns false and dst is unchanged.
45      */
InverseMapRect(const SkMatrix & mx,SkRect * dst,const SkRect & src)46     static bool SK_WARN_UNUSED_RESULT InverseMapRect(const SkMatrix& mx,
47                                                      SkRect* dst, const SkRect& src) {
48         if (mx.getType() <= SkMatrix::kTranslate_Mask) {
49             SkScalar tx = mx.getTranslateX();
50             SkScalar ty = mx.getTranslateY();
51             Sk4f trans(tx, ty, tx, ty);
52             (Sk4f::Load(&src.fLeft) - trans).store(&dst->fLeft);
53             return true;
54         }
55         // Insert other special-cases here (e.g. scale+translate)
56 
57         // general case
58         SkMatrix inverse;
59         if (mx.invert(&inverse)) {
60             inverse.mapRect(dst, src);
61             return true;
62         }
63         return false;
64     }
65 
66     /** Maps count pts, skipping stride bytes to advance from one SkPoint to the next.
67         Points are mapped by multiplying each SkPoint by SkMatrix. Given:
68 
69                      | A B C |        | x |
70             Matrix = | D E F |,  pt = | y |
71                      | G H I |        | 1 |
72 
73         each resulting pts SkPoint is computed as:
74 
75                           |A B C| |x|                               Ax+By+C   Dx+Ey+F
76             Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
77                           |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
78 
79         @param mx      matrix used to map the points
80         @param pts     storage for mapped points
81         @param stride  size of record starting with SkPoint, in bytes
82         @param count   number of points to transform
83     */
MapPointsWithStride(const SkMatrix & mx,SkPoint pts[],size_t stride,int count)84     static void MapPointsWithStride(const SkMatrix& mx, SkPoint pts[], size_t stride, int count) {
85         SkASSERT(stride >= sizeof(SkPoint));
86         SkASSERT(0 == stride % sizeof(SkScalar));
87 
88         SkMatrix::TypeMask tm = mx.getType();
89 
90         if (SkMatrix::kIdentity_Mask == tm) {
91             return;
92         }
93         if (SkMatrix::kTranslate_Mask == tm) {
94             const SkScalar tx = mx.getTranslateX();
95             const SkScalar ty = mx.getTranslateY();
96             Sk2s trans(tx, ty);
97             for (int i = 0; i < count; ++i) {
98                 (Sk2s::Load(&pts->fX) + trans).store(&pts->fX);
99                 pts = (SkPoint*)((intptr_t)pts + stride);
100             }
101             return;
102         }
103         // Insert other special-cases here (e.g. scale+translate)
104 
105         // general case
106         SkMatrix::MapXYProc proc = mx.getMapXYProc();
107         for (int i = 0; i < count; ++i) {
108             proc(mx, pts->fX, pts->fY, pts);
109             pts = (SkPoint*)((intptr_t)pts + stride);
110         }
111     }
112 
113     /** Maps src SkPoint array of length count to dst SkPoint array, skipping stride bytes
114         to advance from one SkPoint to the next.
115         Points are mapped by multiplying each SkPoint by SkMatrix. Given:
116 
117                      | A B C |         | x |
118             Matrix = | D E F |,  src = | y |
119                      | G H I |         | 1 |
120 
121         each resulting dst SkPoint is computed as:
122 
123                           |A B C| |x|                               Ax+By+C   Dx+Ey+F
124             Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
125                           |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
126 
127         @param mx      matrix used to map the points
128         @param dst     storage for mapped points
129         @param src     points to transform
130         @param stride  size of record starting with SkPoint, in bytes
131         @param count   number of points to transform
132     */
MapPointsWithStride(const SkMatrix & mx,SkPoint dst[],size_t dstStride,const SkPoint src[],size_t srcStride,int count)133     static void MapPointsWithStride(const SkMatrix& mx, SkPoint dst[], size_t dstStride,
134                                     const SkPoint src[], size_t srcStride, int count) {
135         SkASSERT(srcStride >= sizeof(SkPoint));
136         SkASSERT(dstStride >= sizeof(SkPoint));
137         SkASSERT(0 == srcStride % sizeof(SkScalar));
138         SkASSERT(0 == dstStride % sizeof(SkScalar));
139         for (int i = 0; i < count; ++i) {
140             mx.mapPoints(dst, src, 1);
141             src = (SkPoint*)((intptr_t)src + srcStride);
142             dst = (SkPoint*)((intptr_t)dst + dstStride);
143         }
144     }
145 
146     static void MapHomogeneousPointsWithStride(const SkMatrix& mx, SkPoint3 dst[], size_t dstStride,
147                                                const SkPoint3 src[], size_t srcStride, int count);
148 
SetMappedRectTriStrip(const SkMatrix & mx,const SkRect & rect,SkPoint quad[4])149     static void SetMappedRectTriStrip(const SkMatrix& mx, const SkRect& rect, SkPoint quad[4]) {
150         SkMatrix::TypeMask tm = mx.getType();
151         SkScalar l = rect.fLeft;
152         SkScalar t = rect.fTop;
153         SkScalar r = rect.fRight;
154         SkScalar b = rect.fBottom;
155         if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
156             const SkScalar tx = mx.getTranslateX();
157             const SkScalar ty = mx.getTranslateY();
158             if (tm <= SkMatrix::kTranslate_Mask) {
159                 l += tx;
160                 t += ty;
161                 r += tx;
162                 b += ty;
163             } else {
164                 const SkScalar sx = mx.getScaleX();
165                 const SkScalar sy = mx.getScaleY();
166                 l = sx * l + tx;
167                 t = sy * t + ty;
168                 r = sx * r + tx;
169                 b = sy * b + ty;
170             }
171            SkPointPriv::SetRectTriStrip(quad, l, t, r, b, sizeof(SkPoint));
172         } else {
173             SkPointPriv::SetRectTriStrip(quad, l, t, r, b, sizeof(SkPoint));
174             mx.mapPoints(quad, quad, 4);
175         }
176     }
177 };
178 
179 #endif
180