Home | History | Annotate | Download | only in core
      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 SkEdge_DEFINED
      9 #define SkEdge_DEFINED
     10 
     11 #include "SkFDot6.h"
     12 #include "SkMath.h"
     13 #include "SkRect.h"
     14 #include "SkTo.h"
     15 
     16 #include <utility>
     17 
     18 // This correctly favors the lower-pixel when y0 is on a 1/2 pixel boundary
     19 #define SkEdge_Compute_DY(top, y0)  (SkLeftShift(top, 6) + 32 - (y0))
     20 
     21 struct SkEdge {
     22     enum Type {
     23         kLine_Type,
     24         kQuad_Type,
     25         kCubic_Type
     26     };
     27 
     28     SkEdge* fNext;
     29     SkEdge* fPrev;
     30 
     31     SkFixed fX;
     32     SkFixed fDX;
     33     int32_t fFirstY;
     34     int32_t fLastY;
     35     int8_t fCurveCount;    // only used by kQuad(+) and kCubic(-)
     36     uint8_t fCurveShift;    // appled to all Dx/DDx/DDDx except for fCubicDShift exception
     37     uint8_t fCubicDShift;   // applied to fCDx and fCDy only in cubic
     38     int8_t  fWinding;       // 1 or -1
     39 
     40     int setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, int shiftUp);
     41     // call this version if you know you don't have a clip
     42     inline int setLine(const SkPoint& p0, const SkPoint& p1, int shiftUp);
     43     inline int updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by);
     44     void chopLineWithClip(const SkIRect& clip);
     45 
     46     inline bool intersectsClip(const SkIRect& clip) const {
     47         SkASSERT(fFirstY < clip.fBottom);
     48         return fLastY >= clip.fTop;
     49     }
     50 
     51 #ifdef SK_DEBUG
     52     void dump() const {
     53         SkDebugf("edge: firstY:%d lastY:%d x:%g dx:%g w:%d\n", fFirstY, fLastY, SkFixedToFloat(fX), SkFixedToFloat(fDX), fWinding);
     54     }
     55 
     56     void validate() const {
     57         SkASSERT(fPrev && fNext);
     58         SkASSERT(fPrev->fNext == this);
     59         SkASSERT(fNext->fPrev == this);
     60 
     61         SkASSERT(fFirstY <= fLastY);
     62         SkASSERT(SkAbs32(fWinding) == 1);
     63     }
     64 #endif
     65 };
     66 
     67 struct SkQuadraticEdge : public SkEdge {
     68     SkFixed fQx, fQy;
     69     SkFixed fQDx, fQDy;
     70     SkFixed fQDDx, fQDDy;
     71     SkFixed fQLastX, fQLastY;
     72 
     73     bool setQuadraticWithoutUpdate(const SkPoint pts[3], int shiftUp);
     74     int setQuadratic(const SkPoint pts[3], int shiftUp);
     75     int updateQuadratic();
     76 };
     77 
     78 struct SkCubicEdge : public SkEdge {
     79     SkFixed fCx, fCy;
     80     SkFixed fCDx, fCDy;
     81     SkFixed fCDDx, fCDDy;
     82     SkFixed fCDDDx, fCDDDy;
     83     SkFixed fCLastX, fCLastY;
     84 
     85     bool setCubicWithoutUpdate(const SkPoint pts[4], int shiftUp, bool sortY = true);
     86     int setCubic(const SkPoint pts[4], int shiftUp);
     87     int updateCubic();
     88 };
     89 
     90 int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, int shift) {
     91     SkFDot6 x0, y0, x1, y1;
     92 
     93     {
     94 #ifdef SK_RASTERIZE_EVEN_ROUNDING
     95         x0 = SkScalarRoundToFDot6(p0.fX, shift);
     96         y0 = SkScalarRoundToFDot6(p0.fY, shift);
     97         x1 = SkScalarRoundToFDot6(p1.fX, shift);
     98         y1 = SkScalarRoundToFDot6(p1.fY, shift);
     99 #else
    100         float scale = float(1 << (shift + 6));
    101         x0 = int(p0.fX * scale);
    102         y0 = int(p0.fY * scale);
    103         x1 = int(p1.fX * scale);
    104         y1 = int(p1.fY * scale);
    105 #endif
    106     }
    107 
    108     int winding = 1;
    109 
    110     if (y0 > y1) {
    111         using std::swap;
    112         swap(x0, x1);
    113         swap(y0, y1);
    114         winding = -1;
    115     }
    116 
    117     int top = SkFDot6Round(y0);
    118     int bot = SkFDot6Round(y1);
    119 
    120     // are we a zero-height line?
    121     if (top == bot) {
    122         return 0;
    123     }
    124 
    125     SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0);
    126     const SkFDot6 dy  = SkEdge_Compute_DY(top, y0);
    127 
    128     fX          = SkFDot6ToFixed(x0 + SkFixedMul(slope, dy));   // + SK_Fixed1/2
    129     fDX         = slope;
    130     fFirstY     = top;
    131     fLastY      = bot - 1;
    132     fCurveCount = 0;
    133     fWinding    = SkToS8(winding);
    134     fCurveShift = 0;
    135     return 1;
    136 }
    137 
    138 #endif
    139