1#include "SkEdgeBuilder.h"
2#include "SkPath.h"
3#include "SkEdge.h"
4#include "SkEdgeClipper.h"
5#include "SkLineClipper.h"
6#include "SkGeometry.h"
7
8SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) {}
9
10template <typename T> static T* typedAllocThrow(SkChunkAlloc& alloc) {
11    return static_cast<T*>(alloc.allocThrow(sizeof(T)));
12}
13
14///////////////////////////////////////////////////////////////////////////////
15
16void SkEdgeBuilder::addLine(const SkPoint pts[]) {
17    SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc);
18    if (edge->setLine(pts[0], pts[1], NULL, fShiftUp)) {
19        fList.push(edge);
20    } else {
21        // TODO: unallocate edge from storage...
22    }
23}
24
25void SkEdgeBuilder::addQuad(const SkPoint pts[]) {
26    SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc);
27    if (edge->setQuadratic(pts, fShiftUp)) {
28        fList.push(edge);
29    } else {
30        // TODO: unallocate edge from storage...
31    }
32}
33
34void SkEdgeBuilder::addCubic(const SkPoint pts[]) {
35    SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc);
36    if (edge->setCubic(pts, NULL, fShiftUp)) {
37        fList.push(edge);
38    } else {
39        // TODO: unallocate edge from storage...
40    }
41}
42
43void SkEdgeBuilder::addClipper(SkEdgeClipper* clipper) {
44    SkPoint      pts[4];
45    SkPath::Verb verb;
46
47    while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
48        switch (verb) {
49            case SkPath::kLine_Verb:
50                this->addLine(pts);
51                break;
52            case SkPath::kQuad_Verb:
53                this->addQuad(pts);
54                break;
55            case SkPath::kCubic_Verb:
56                this->addCubic(pts);
57                break;
58            default:
59                break;
60        }
61    }
62}
63
64///////////////////////////////////////////////////////////////////////////////
65
66static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) {
67    dst->set(SkIntToScalar(src.fLeft >> shift),
68             SkIntToScalar(src.fTop >> shift),
69             SkIntToScalar(src.fRight >> shift),
70             SkIntToScalar(src.fBottom >> shift));
71}
72
73int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
74                         int shiftUp) {
75    fAlloc.reset();
76    fList.reset();
77    fShiftUp = shiftUp;
78
79    SkPath::Iter    iter(path, true);
80    SkPoint         pts[4];
81    SkPath::Verb    verb;
82
83    if (iclip) {
84        SkRect clip;
85        setShiftedClip(&clip, *iclip, shiftUp);
86        SkEdgeClipper clipper;
87
88        while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
89            switch (verb) {
90                case SkPath::kMove_Verb:
91                case SkPath::kClose_Verb:
92                    // we ignore these, and just get the whole segment from
93                    // the corresponding line/quad/cubic verbs
94                    break;
95                case SkPath::kLine_Verb: {
96                    SkPoint lines[SkLineClipper::kMaxPoints];
97                    int lineCount = SkLineClipper::ClipLine(pts, clip, lines);
98                    for (int i = 0; i < lineCount; i++) {
99                        this->addLine(&lines[i]);
100                    }
101                    break;
102                }
103                case SkPath::kQuad_Verb:
104                    if (clipper.clipQuad(pts, clip)) {
105                        this->addClipper(&clipper);
106                    }
107                    break;
108                case SkPath::kCubic_Verb:
109                    if (clipper.clipCubic(pts, clip)) {
110                        this->addClipper(&clipper);
111                    }
112                    break;
113                default:
114                    SkASSERT(!"unexpected verb");
115                    break;
116            }
117        }
118    } else {
119        while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
120            switch (verb) {
121                case SkPath::kMove_Verb:
122                case SkPath::kClose_Verb:
123                    // we ignore these, and just get the whole segment from
124                    // the corresponding line/quad/cubic verbs
125                    break;
126                case SkPath::kLine_Verb:
127                    this->addLine(pts);
128                    break;
129                case SkPath::kQuad_Verb: {
130                    SkPoint monoX[5];
131                    int n = SkChopQuadAtYExtrema(pts, monoX);
132                    for (int i = 0; i <= n; i++) {
133                        this->addQuad(&monoX[i * 2]);
134                    }
135                    break;
136                }
137                case SkPath::kCubic_Verb: {
138                    SkPoint monoY[10];
139                    int n = SkChopCubicAtYExtrema(pts, monoY);
140                    for (int i = 0; i <= n; i++) {
141                        this->addCubic(&monoY[i * 3]);
142                    }
143                    break;
144                }
145                default:
146                    SkASSERT(!"unexpected verb");
147                    break;
148            }
149        }
150    }
151    return fList.count();
152}
153
154
155