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