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