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