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