SkEdgeBuilder.cpp revision c8d640b1788822a8697816b645c327383a1d1f20
1
2/*
3 * Copyright 2011 Google Inc.
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#include "SkEdgeBuilder.h"
9#include "SkPath.h"
10#include "SkEdge.h"
11#include "SkEdgeClipper.h"
12#include "SkLineClipper.h"
13#include "SkGeometry.h"
14
15template <typename T> static T* typedAllocThrow(SkChunkAlloc& alloc) {
16    return static_cast<T*>(alloc.allocThrow(sizeof(T)));
17}
18
19///////////////////////////////////////////////////////////////////////////////
20
21SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) {
22    fEdgeList = NULL;
23}
24
25void SkEdgeBuilder::addLine(const SkPoint pts[]) {
26    SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc);
27    if (edge->setLine(pts[0], pts[1], NULL, fShiftUp)) {
28        fList.push(edge);
29    } else {
30        // TODO: unallocate edge from storage...
31    }
32}
33
34void SkEdgeBuilder::addQuad(const SkPoint pts[]) {
35    SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc);
36    if (edge->setQuadratic(pts, fShiftUp)) {
37        fList.push(edge);
38    } else {
39        // TODO: unallocate edge from storage...
40    }
41}
42
43void SkEdgeBuilder::addCubic(const SkPoint pts[]) {
44    SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc);
45    if (edge->setCubic(pts, NULL, fShiftUp)) {
46        fList.push(edge);
47    } else {
48        // TODO: unallocate edge from storage...
49    }
50}
51
52void SkEdgeBuilder::addClipper(SkEdgeClipper* clipper) {
53    SkPoint      pts[4];
54    SkPath::Verb verb;
55
56    while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
57        switch (verb) {
58            case SkPath::kLine_Verb:
59                this->addLine(pts);
60                break;
61            case SkPath::kQuad_Verb:
62                this->addQuad(pts);
63                break;
64            case SkPath::kCubic_Verb:
65                this->addCubic(pts);
66                break;
67            default:
68                break;
69        }
70    }
71}
72
73///////////////////////////////////////////////////////////////////////////////
74
75static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) {
76    dst->set(SkIntToScalar(src.fLeft >> shift),
77             SkIntToScalar(src.fTop >> shift),
78             SkIntToScalar(src.fRight >> shift),
79             SkIntToScalar(src.fBottom >> shift));
80}
81
82int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip,
83                             int shiftUp) {
84    SkPath::Iter    iter(path, true);
85    SkPoint         pts[4];
86    SkPath::Verb    verb;
87
88    int maxEdgeCount = path.countPoints();
89    if (iclip) {
90        // clipping can turn 1 line into (up to) kMaxClippedLineSegments, since
91        // we turn portions that are clipped out on the left/right into vertical
92        // segments.
93        maxEdgeCount *= SkLineClipper::kMaxClippedLineSegments;
94    }
95    size_t maxEdgeSize = maxEdgeCount * sizeof(SkEdge);
96    size_t maxEdgePtrSize = maxEdgeCount * sizeof(SkEdge*);
97
98    // lets store the edges and their pointers in the same block
99    char* storage = (char*)fAlloc.allocThrow(maxEdgeSize + maxEdgePtrSize);
100    SkEdge* edge = reinterpret_cast<SkEdge*>(storage);
101    SkEdge** edgePtr = reinterpret_cast<SkEdge**>(storage + maxEdgeSize);
102    // Record the beginning of our pointers, so we can return them to the caller
103    fEdgeList = edgePtr;
104
105    if (iclip) {
106        SkRect clip;
107        setShiftedClip(&clip, *iclip, shiftUp);
108
109        while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
110            switch (verb) {
111                case SkPath::kMove_Verb:
112                case SkPath::kClose_Verb:
113                    // we ignore these, and just get the whole segment from
114                    // the corresponding line/quad/cubic verbs
115                    break;
116                case SkPath::kLine_Verb: {
117                    SkPoint lines[SkLineClipper::kMaxPoints];
118                    int lineCount = SkLineClipper::ClipLine(pts, clip, lines);
119                    SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments);
120                    for (int i = 0; i < lineCount; i++) {
121                        if (edge->setLine(lines[i], lines[i + 1], NULL, shiftUp)) {
122                            *edgePtr++ = edge++;
123                        }
124                    }
125                    break;
126                }
127                default:
128                    SkDEBUGFAIL("unexpected verb");
129                    break;
130            }
131        }
132    } else {
133        while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
134            switch (verb) {
135                case SkPath::kMove_Verb:
136                case SkPath::kClose_Verb:
137                    // we ignore these, and just get the whole segment from
138                    // the corresponding line/quad/cubic verbs
139                    break;
140                case SkPath::kLine_Verb:
141                    if (edge->setLine(pts[0], pts[1], NULL, shiftUp)) {
142                        *edgePtr++ = edge++;
143                    }
144                    break;
145                default:
146                    SkDEBUGFAIL("unexpected verb");
147                    break;
148            }
149        }
150    }
151    SkASSERT((char*)edge <= (char*)fEdgeList);
152    SkASSERT(edgePtr - fEdgeList <= maxEdgeCount);
153    return edgePtr - fEdgeList;
154}
155
156int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
157                         int shiftUp) {
158    fAlloc.reset();
159    fList.reset();
160    fShiftUp = shiftUp;
161
162    if (SkPath::kLine_SegmentMask == path.getSegmentMasks()) {
163        return this->buildPoly(path, iclip, shiftUp);
164    }
165
166    SkPath::Iter    iter(path, true);
167    SkPoint         pts[4];
168    SkPath::Verb    verb;
169
170    if (iclip) {
171        SkRect clip;
172        setShiftedClip(&clip, *iclip, shiftUp);
173        SkEdgeClipper clipper;
174
175        while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
176            switch (verb) {
177                case SkPath::kMove_Verb:
178                case SkPath::kClose_Verb:
179                    // we ignore these, and just get the whole segment from
180                    // the corresponding line/quad/cubic verbs
181                    break;
182                case SkPath::kLine_Verb: {
183                    SkPoint lines[SkLineClipper::kMaxPoints];
184                    int lineCount = SkLineClipper::ClipLine(pts, clip, lines);
185                    for (int i = 0; i < lineCount; i++) {
186                        this->addLine(&lines[i]);
187                    }
188                    break;
189                }
190                case SkPath::kQuad_Verb:
191                    if (clipper.clipQuad(pts, clip)) {
192                        this->addClipper(&clipper);
193                    }
194                    break;
195                case SkPath::kCubic_Verb:
196                    if (clipper.clipCubic(pts, clip)) {
197                        this->addClipper(&clipper);
198                    }
199                    break;
200                default:
201                    SkDEBUGFAIL("unexpected verb");
202                    break;
203            }
204        }
205    } else {
206        while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
207            switch (verb) {
208                case SkPath::kMove_Verb:
209                case SkPath::kClose_Verb:
210                    // we ignore these, and just get the whole segment from
211                    // the corresponding line/quad/cubic verbs
212                    break;
213                case SkPath::kLine_Verb:
214                    this->addLine(pts);
215                    break;
216                case SkPath::kQuad_Verb: {
217                    SkPoint monoX[5];
218                    int n = SkChopQuadAtYExtrema(pts, monoX);
219                    for (int i = 0; i <= n; i++) {
220                        this->addQuad(&monoX[i * 2]);
221                    }
222                    break;
223                }
224                case SkPath::kCubic_Verb: {
225                    SkPoint monoY[10];
226                    int n = SkChopCubicAtYExtrema(pts, monoY);
227                    for (int i = 0; i <= n; i++) {
228                        this->addCubic(&monoY[i * 3]);
229                    }
230                    break;
231                }
232                default:
233                    SkDEBUGFAIL("unexpected verb");
234                    break;
235            }
236        }
237    }
238    fEdgeList = fList.begin();
239    return fList.count();
240}
241
242