1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 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#include "src/gpu/geometry/GrQuad.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h" 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ciusing V4f = skvx::Vec<4, float>; 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_cistatic bool aa_affects_rect(float ql, float qt, float qr, float qb) { 15cb93a386Sopenharmony_ci return !SkScalarIsInt(ql) || !SkScalarIsInt(qr) || !SkScalarIsInt(qt) || !SkScalarIsInt(qb); 16cb93a386Sopenharmony_ci} 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_cistatic void map_rect_translate_scale(const SkRect& rect, const SkMatrix& m, 19cb93a386Sopenharmony_ci V4f* xs, V4f* ys) { 20cb93a386Sopenharmony_ci SkMatrix::TypeMask tm = m.getType(); 21cb93a386Sopenharmony_ci SkASSERT(tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)); 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci V4f r = V4f::Load(&rect); 24cb93a386Sopenharmony_ci if (tm > SkMatrix::kIdentity_Mask) { 25cb93a386Sopenharmony_ci const V4f t{m.getTranslateX(), m.getTranslateY(), m.getTranslateX(), m.getTranslateY()}; 26cb93a386Sopenharmony_ci if (tm <= SkMatrix::kTranslate_Mask) { 27cb93a386Sopenharmony_ci r += t; 28cb93a386Sopenharmony_ci } else { 29cb93a386Sopenharmony_ci const V4f s{m.getScaleX(), m.getScaleY(), m.getScaleX(), m.getScaleY()}; 30cb93a386Sopenharmony_ci r = r * s + t; 31cb93a386Sopenharmony_ci } 32cb93a386Sopenharmony_ci } 33cb93a386Sopenharmony_ci *xs = skvx::shuffle<0, 0, 2, 2>(r); 34cb93a386Sopenharmony_ci *ys = skvx::shuffle<1, 3, 1, 3>(r); 35cb93a386Sopenharmony_ci} 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_cistatic void map_quad_general(const V4f& qx, const V4f& qy, const SkMatrix& m, 38cb93a386Sopenharmony_ci V4f* xs, V4f* ys, V4f* ws) { 39cb93a386Sopenharmony_ci *xs = m.getScaleX() * qx + (m.getSkewX() * qy + m.getTranslateX()); 40cb93a386Sopenharmony_ci *ys = m.getSkewY() * qx + (m.getScaleY() * qy + m.getTranslateY()); 41cb93a386Sopenharmony_ci if (m.hasPerspective()) { 42cb93a386Sopenharmony_ci V4f w = m.getPerspX() * qx + (m.getPerspY() * qy + m.get(SkMatrix::kMPersp2)); 43cb93a386Sopenharmony_ci if (ws) { 44cb93a386Sopenharmony_ci // Output the calculated w coordinates 45cb93a386Sopenharmony_ci *ws = w; 46cb93a386Sopenharmony_ci } else { 47cb93a386Sopenharmony_ci // Apply perspective division immediately 48cb93a386Sopenharmony_ci V4f iw = 1.f / w; 49cb93a386Sopenharmony_ci *xs *= iw; 50cb93a386Sopenharmony_ci *ys *= iw; 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci } else if (ws) { 53cb93a386Sopenharmony_ci *ws = 1.f; 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci} 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_cistatic void map_rect_general(const SkRect& rect, const SkMatrix& matrix, 58cb93a386Sopenharmony_ci V4f* xs, V4f* ys, V4f* ws) { 59cb93a386Sopenharmony_ci V4f rx{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight}; 60cb93a386Sopenharmony_ci V4f ry{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom}; 61cb93a386Sopenharmony_ci map_quad_general(rx, ry, matrix, xs, ys, ws); 62cb93a386Sopenharmony_ci} 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci// Rearranges (top-left, top-right, bottom-right, bottom-left) ordered skQuadPts into xs and ys 65cb93a386Sopenharmony_ci// ordered (top-left, bottom-left, top-right, bottom-right) 66cb93a386Sopenharmony_cistatic void rearrange_sk_to_gr_points(const SkPoint skQuadPts[4], V4f* xs, V4f* ys) { 67cb93a386Sopenharmony_ci *xs = V4f{skQuadPts[0].fX, skQuadPts[3].fX, skQuadPts[1].fX, skQuadPts[2].fX}; 68cb93a386Sopenharmony_ci *ys = V4f{skQuadPts[0].fY, skQuadPts[3].fY, skQuadPts[1].fY, skQuadPts[2].fY}; 69cb93a386Sopenharmony_ci} 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci// If an SkRect is transformed by this matrix, what class of quad is required to represent it. 72cb93a386Sopenharmony_cistatic GrQuad::Type quad_type_for_transformed_rect(const SkMatrix& matrix) { 73cb93a386Sopenharmony_ci if (matrix.rectStaysRect()) { 74cb93a386Sopenharmony_ci return GrQuad::Type::kAxisAligned; 75cb93a386Sopenharmony_ci } else if (matrix.preservesRightAngles()) { 76cb93a386Sopenharmony_ci return GrQuad::Type::kRectilinear; 77cb93a386Sopenharmony_ci } else if (matrix.hasPerspective()) { 78cb93a386Sopenharmony_ci return GrQuad::Type::kPerspective; 79cb93a386Sopenharmony_ci } else { 80cb93a386Sopenharmony_ci return GrQuad::Type::kGeneral; 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci} 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci// Perform minimal analysis of 'pts' (which are suitable for MakeFromSkQuad), and determine a 85cb93a386Sopenharmony_ci// quad type that will be as minimally general as possible. 86cb93a386Sopenharmony_cistatic GrQuad::Type quad_type_for_points(const SkPoint pts[4], const SkMatrix& matrix) { 87cb93a386Sopenharmony_ci if (matrix.hasPerspective()) { 88cb93a386Sopenharmony_ci return GrQuad::Type::kPerspective; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci // If 'pts' was formed by SkRect::toQuad() and not transformed further, it is safe to use the 91cb93a386Sopenharmony_ci // quad type derived from 'matrix'. Otherwise don't waste any more time and assume kStandard 92cb93a386Sopenharmony_ci // (most general 2D quad). 93cb93a386Sopenharmony_ci if ((pts[0].fX == pts[3].fX && pts[1].fX == pts[2].fX) && 94cb93a386Sopenharmony_ci (pts[0].fY == pts[1].fY && pts[2].fY == pts[3].fY)) { 95cb93a386Sopenharmony_ci return quad_type_for_transformed_rect(matrix); 96cb93a386Sopenharmony_ci } else { 97cb93a386Sopenharmony_ci return GrQuad::Type::kGeneral; 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci} 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ciGrQuad GrQuad::MakeFromRect(const SkRect& rect, const SkMatrix& m) { 102cb93a386Sopenharmony_ci V4f x, y, w; 103cb93a386Sopenharmony_ci SkMatrix::TypeMask tm = m.getType(); 104cb93a386Sopenharmony_ci Type type; 105cb93a386Sopenharmony_ci if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) { 106cb93a386Sopenharmony_ci map_rect_translate_scale(rect, m, &x, &y); 107cb93a386Sopenharmony_ci w = 1.f; 108cb93a386Sopenharmony_ci type = Type::kAxisAligned; 109cb93a386Sopenharmony_ci } else { 110cb93a386Sopenharmony_ci map_rect_general(rect, m, &x, &y, &w); 111cb93a386Sopenharmony_ci type = quad_type_for_transformed_rect(m); 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci return GrQuad(x, y, w, type); 114cb93a386Sopenharmony_ci} 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ciGrQuad GrQuad::MakeFromSkQuad(const SkPoint pts[4], const SkMatrix& matrix) { 117cb93a386Sopenharmony_ci V4f xs, ys; 118cb93a386Sopenharmony_ci rearrange_sk_to_gr_points(pts, &xs, &ys); 119cb93a386Sopenharmony_ci Type type = quad_type_for_points(pts, matrix); 120cb93a386Sopenharmony_ci if (matrix.isIdentity()) { 121cb93a386Sopenharmony_ci return GrQuad(xs, ys, 1.f, type); 122cb93a386Sopenharmony_ci } else { 123cb93a386Sopenharmony_ci V4f mx, my, mw; 124cb93a386Sopenharmony_ci map_quad_general(xs, ys, matrix, &mx, &my, &mw); 125cb93a386Sopenharmony_ci return GrQuad(mx, my, mw, type); 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_ci} 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_cibool GrQuad::aaHasEffectOnRect() const { 130cb93a386Sopenharmony_ci SkASSERT(this->quadType() == Type::kAxisAligned); 131cb93a386Sopenharmony_ci // If rect, ws must all be 1s so no need to divide 132cb93a386Sopenharmony_ci return aa_affects_rect(fX[0], fY[0], fX[3], fY[3]); 133cb93a386Sopenharmony_ci} 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_cibool GrQuad::asRect(SkRect* rect) const { 136cb93a386Sopenharmony_ci if (this->quadType() != Type::kAxisAligned) { 137cb93a386Sopenharmony_ci return false; 138cb93a386Sopenharmony_ci } 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci *rect = this->bounds(); 141cb93a386Sopenharmony_ci // v0 at the geometric top-left is unique amongst axis-aligned vertex orders 142cb93a386Sopenharmony_ci // (90, 180, 270 rotations or axis flips all move v0). 143cb93a386Sopenharmony_ci return fX[0] == rect->fLeft && fY[0] == rect->fTop; 144cb93a386Sopenharmony_ci} 145