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