xref: /third_party/skia/src/core/SkEdge.h (revision cb93a386)
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 "include/core/SkMath.h"
12#include "include/core/SkRect.h"
13#include "include/private/SkTo.h"
14#include "src/core/SkFDot6.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
21struct 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
67struct 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
78struct 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
90int 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