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