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 "include/private/base/SkAssert.h" 12 #include "include/private/base/SkDebug.h" 13 #include "include/private/base/SkFixed.h" 14 #include "include/private/base/SkSafe32.h" 15 #include "src/core/SkEdge.h" 16 17 #include <cstdint> 18 19 struct SkPoint; 20 21 struct SkAnalyticEdge { 22 // Similar to SkEdge, the conic edges will be converted to quadratic edges 23 enum Type { 24 kLine_Type, 25 kQuad_Type, 26 kCubic_Type 27 }; 28 29 SkAnalyticEdge* fNext; 30 SkAnalyticEdge* fPrev; 31 32 SkFixed fX; 33 SkFixed fDX; 34 SkFixed fUpperX; // The x value when y = fUpperY 35 SkFixed fY; // The current y 36 SkFixed fUpperY; // The upper bound of y (our edge is from y = fUpperY to y = fLowerY) 37 SkFixed fLowerY; // The lower bound of y (our edge is from y = fUpperY to y = fLowerY) 38 SkFixed fDY; // abs(1/fDX); may be SK_MaxS32 when fDX is close to 0. 39 // fDY is only used for blitting trapezoids. 40 41 Type fEdgeType; // Remembers the *initial* edge type 42 43 int8_t fCurveCount; // only used by kQuad(+) and kCubic(-) 44 uint8_t fCurveShift; // appled to all Dx/DDx/DDDx except for fCubicDShift exception 45 uint8_t fCubicDShift; // applied to fCDx and fCDy only in cubic 46 int8_t fWinding; // 1 or -1 47 48 static const int kDefaultAccuracy = 2; // default accuracy for snapping 49 SnapYSkAnalyticEdge50 static inline SkFixed SnapY(SkFixed y) { 51 const int accuracy = kDefaultAccuracy; 52 // This approach is safer than left shift, round, then right shift 53 return ((unsigned)y + (SK_Fixed1 >> (accuracy + 1))) >> (16 - accuracy) << (16 - accuracy); 54 } 55 56 // Update fX, fY of this edge so fY = y goYSkAnalyticEdge57 inline void goY(SkFixed y) { 58 if (y == fY + SK_Fixed1) { 59 fX = fX + fDX; 60 fY = y; 61 } else if (y != fY) { 62 // Drop lower digits as our alpha only has 8 bits 63 // (fDX and y - fUpperY may be greater than SK_Fixed1) 64 fX = fUpperX + SkFixedMul(fDX, y - fUpperY); 65 fY = y; 66 } 67 } 68 goYSkAnalyticEdge69 inline void goY(SkFixed y, int yShift) { 70 SkASSERT(yShift >= 0 && yShift <= kDefaultAccuracy); 71 SkASSERT(fDX == 0 || y - fY == SK_Fixed1 >> yShift); 72 fY = y; 73 fX += fDX >> yShift; 74 } 75 76 bool setLine(const SkPoint& p0, const SkPoint& p1); 77 bool updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by, SkFixed slope); 78 79 // return true if we're NOT done with this edge 80 bool update(SkFixed last_y, bool sortY = true); 81 82 #ifdef SK_DEBUG dumpSkAnalyticEdge83 void dump() const { 84 SkDebugf("edge: upperY:%d lowerY:%d y:%g x:%g dx:%g w:%d\n", 85 fUpperY, fLowerY, SkFixedToFloat(fY), SkFixedToFloat(fX), 86 SkFixedToFloat(fDX), fWinding); 87 } 88 validateSkAnalyticEdge89 void validate() const { 90 SkASSERT(fPrev && fNext); 91 SkASSERT(fPrev->fNext == this); 92 SkASSERT(fNext->fPrev == this); 93 94 SkASSERT(fUpperY < fLowerY); 95 SkASSERT(SkAbs32(fWinding) == 1); 96 } 97 #endif 98 }; 99 100 struct SkAnalyticQuadraticEdge : public SkAnalyticEdge { 101 SkQuadraticEdge fQEdge; 102 103 // snap y to integer points in the middle of the curve to accelerate AAA path filling 104 SkFixed fSnappedX, fSnappedY; 105 106 bool setQuadratic(const SkPoint pts[3]); 107 bool updateQuadratic(); keepContinuousSkAnalyticQuadraticEdge108 inline void keepContinuous() { 109 // We use fX as the starting x to ensure the continuouty. 110 // Without it, we may break the sorted edge list. 111 SkASSERT(SkAbs32(fX - SkFixedMul(fY - fSnappedY, fDX) - fSnappedX) < SK_Fixed1); 112 SkASSERT(SkAbs32(fY - fSnappedY) < SK_Fixed1); // This may differ due to smooth jump 113 fSnappedX = fX; 114 fSnappedY = fY; 115 } 116 }; 117 118 struct SkAnalyticCubicEdge : public SkAnalyticEdge { 119 SkCubicEdge fCEdge; 120 121 SkFixed fSnappedY; // to make sure that y is increasing with smooth jump and snapping 122 123 bool setCubic(const SkPoint pts[4], bool sortY = true); 124 bool updateCubic(bool sortY = true); keepContinuousSkAnalyticCubicEdge125 inline void keepContinuous() { 126 SkASSERT(SkAbs32(fX - SkFixedMul(fDX, fY - SnapY(fCEdge.fCy)) - fCEdge.fCx) < SK_Fixed1); 127 fCEdge.fCx = fX; 128 fSnappedY = fY; 129 } 130 }; 131 132 #endif 133