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
SkEdgeBuilder()15 SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) {}
16
typedAllocThrow(SkChunkAlloc & alloc)17 template <typename T> static T* typedAllocThrow(SkChunkAlloc& alloc) {
18 return static_cast<T*>(alloc.allocThrow(sizeof(T)));
19 }
20
21 ///////////////////////////////////////////////////////////////////////////////
22
addLine(const SkPoint pts[])23 void 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
addQuad(const SkPoint pts[])32 void 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
addCubic(const SkPoint pts[])41 void 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
addClipper(SkEdgeClipper * clipper)50 void 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
setShiftedClip(SkRect * dst,const SkIRect & src,int shift)73 static 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
build(const SkPath & path,const SkIRect * iclip,int shiftUp)80 int 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)) != 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)) != 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