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