SkAnalyticEdge.h revision 197bde9c606dbd22eafa02509bf4ea3ce7a0c69b
1/* 2 * Copyright 2006 The Android Open Source Project 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 SkAnalyticEdge_DEFINED 9#define SkAnalyticEdge_DEFINED 10 11#include "SkEdge.h" 12 13// Use this to check that we successfully guard the change against Chromium layout tests 14#ifndef SK_SUPPORT_LEGACY_AAA 15# define SK_SUPPORT_LEGACY_AAA 16#endif 17 18struct SkAnalyticEdge { 19 // Similar to SkEdge, the conic edges will be converted to quadratic edges 20 enum Type { 21 kLine_Type, 22 kQuad_Type, 23 kCubic_Type 24 }; 25 26 SkAnalyticEdge* fNext; 27 SkAnalyticEdge* fPrev; 28 29 // During aaa_walk_edges, if this edge is a left edge, 30 // then fRiteE is its corresponding right edge. Otherwise it's nullptr. 31 SkAnalyticEdge* fRiteE; 32 33 SkFixed fX; 34 SkFixed fDX; 35 SkFixed fUpperX; // The x value when y = fUpperY 36 SkFixed fY; // The current y 37 SkFixed fUpperY; // The upper bound of y (our edge is from y = fUpperY to y = fLowerY) 38 SkFixed fLowerY; // The lower bound of y (our edge is from y = fUpperY to y = fLowerY) 39 SkFixed fDY; // abs(1/fDX); may be SK_MaxS32 when fDX is close to 0. 40 // fDY is only used for blitting trapezoids. 41 42 SkFixed fSavedX; // For deferred blitting 43 SkFixed fSavedY; // For deferred blitting 44 SkFixed fSavedDY; // For deferred blitting 45 46 int8_t fCurveCount; // only used by kQuad(+) and kCubic(-) 47 uint8_t fCurveShift; // appled to all Dx/DDx/DDDx except for fCubicDShift exception 48 uint8_t fCubicDShift; // applied to fCDx and fCDy only in cubic 49 int8_t fWinding; // 1 or -1 50 51 static const int kDefaultAccuracy = 2; // default accuracy for snapping 52 53 static inline SkFixed SnapY(SkFixed y) { 54 const int accuracy = kDefaultAccuracy; 55 // This approach is safer than left shift, round, then right shift 56 return ((unsigned)y + (SK_Fixed1 >> (accuracy + 1))) >> (16 - accuracy) << (16 - accuracy); 57 } 58 59 // Update fX, fY of this edge so fY = y 60 inline void goY(SkFixed y) { 61 if (y == fY + SK_Fixed1) { 62 fX = fX + fDX; 63 fY = y; 64 } else if (y != fY) { 65 // Drop lower digits as our alpha only has 8 bits 66 // (fDX and y - fUpperY may be greater than SK_Fixed1) 67 fX = fUpperX + SkFixedMul(fDX, y - fUpperY); 68 fY = y; 69 } 70 } 71 72 inline void goY(SkFixed y, int yShift) { 73 SkASSERT(yShift >= 0 && yShift <= kDefaultAccuracy); 74 SkASSERT(fDX == 0 || y - fY == SK_Fixed1 >> yShift); 75 fY = y; 76 fX += fDX >> yShift; 77 } 78 79 inline void saveXY(SkFixed x, SkFixed y, SkFixed dY) { 80 fSavedX = x; 81 fSavedY = y; 82 fSavedDY = dY; 83 } 84 85 inline bool setLine(const SkPoint& p0, const SkPoint& p1); 86 inline bool updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by, SkFixed slope); 87 88#ifdef SK_DEBUG 89 void dump() const { 90 SkDebugf("edge: upperY:%d lowerY:%d y:%g x:%g dx:%g w:%d\n", 91 fUpperY, fLowerY, SkFixedToFloat(fY), SkFixedToFloat(fX), 92 SkFixedToFloat(fDX), fWinding); 93 } 94 95 void validate() const { 96 SkASSERT(fPrev && fNext); 97 SkASSERT(fPrev->fNext == this); 98 SkASSERT(fNext->fPrev == this); 99 100 SkASSERT(fUpperY < fLowerY); 101 SkASSERT(SkAbs32(fWinding) == 1); 102 } 103#endif 104}; 105 106struct SkAnalyticQuadraticEdge : public SkAnalyticEdge { 107 SkQuadraticEdge fQEdge; 108 109 // snap y to integer points in the middle of the curve to accelerate AAA path filling 110 SkFixed fSnappedX, fSnappedY; 111 112 bool setQuadratic(const SkPoint pts[3]); 113 bool updateQuadratic(); 114 inline void keepContinuous() { 115 // We use fX as the starting x to ensure the continuouty. 116 // Without it, we may break the sorted edge list. 117 SkASSERT(SkAbs32(fX - SkFixedMul(fY - fSnappedY, fDX) - fSnappedX) < SK_Fixed1); 118 SkASSERT(SkAbs32(fY - fSnappedY) < SK_Fixed1); // This may differ due to smooth jump 119 fSnappedX = fX; 120 fSnappedY = fY; 121 } 122}; 123 124struct SkAnalyticCubicEdge : public SkAnalyticEdge { 125 SkCubicEdge fCEdge; 126 127 SkFixed fSnappedY; // to make sure that y is increasing with smooth jump and snapping 128 129 bool setCubic(const SkPoint pts[4]); 130 bool updateCubic(); 131 inline void keepContinuous() { 132 SkASSERT(SkAbs32(fX - SkFixedMul(fDX, fY - SnapY(fCEdge.fCy)) - fCEdge.fCx) < SK_Fixed1); 133 fCEdge.fCx = fX; 134 fSnappedY = fY; 135 } 136}; 137 138bool SkAnalyticEdge::setLine(const SkPoint& p0, const SkPoint& p1) { 139 fRiteE = nullptr; 140 141 // We must set X/Y using the same way (e.g., times 4, to FDot6, then to Fixed) as Quads/Cubics. 142 // Otherwise the order of the edge might be wrong due to precision limit. 143 const int accuracy = kDefaultAccuracy; 144 const int multiplier = (1 << kDefaultAccuracy); 145 SkFixed x0 = SkFDot6ToFixed(SkScalarToFDot6(p0.fX * multiplier)) >> accuracy; 146 SkFixed y0 = SnapY(SkFDot6ToFixed(SkScalarToFDot6(p0.fY * multiplier)) >> accuracy); 147 SkFixed x1 = SkFDot6ToFixed(SkScalarToFDot6(p1.fX * multiplier)) >> accuracy; 148 SkFixed y1 = SnapY(SkFDot6ToFixed(SkScalarToFDot6(p1.fY * multiplier)) >> accuracy); 149 150 // are we a zero-height line? 151 if (y0 == y1) { 152 return false; 153 } 154 155 int winding = 1; 156 157 if (y0 > y1) { 158 SkTSwap(x0, x1); 159 SkTSwap(y0, y1); 160 winding = -1; 161 } 162 163#ifdef SK_SUPPORT_LEGACY_AAA 164 SkFixed slope = SkFixedDiv(x1 - x0, y1 - y0); 165#else 166 SkFDot6 dy = SkFixedToFDot6(y1 - y0); 167 SkFDot6 dx = SkFixedToFDot6(x1 - x0); 168 SkFixed slope = dy ? QuickSkFDot6Div(dx, dy) : SK_MaxS32; 169 SkASSERT(dx == 0 || slope != 0); 170 SkFixed absSlope = SkAbs32(slope); 171#endif 172 173 fX = x0; 174 fDX = slope; 175 fUpperX = x0; 176 fY = y0; 177 fUpperY = y0; 178 fLowerY = y1; 179#ifdef SK_SUPPORT_LEGACY_AAA 180 fDY = x1 != x0 ? SkAbs32(SkFixedDiv(y1 - y0, x1 - x0)) : SK_MaxS32; 181#else 182 fDY = dx == 0 ? SK_MaxS32 : absSlope < kInverseTableSize 183 ? QuickFDot6Inverse::Lookup(absSlope) 184 : SkAbs32(QuickSkFDot6Div(dy, dx)); 185#endif 186 fCurveCount = 0; 187 fWinding = SkToS8(winding); 188 fCurveShift = 0; 189 190 return true; 191} 192 193#endif 194