blob: 41ab2427e37e65d3f92b480bfc8ec83dcac36dca [file] [log] [blame]
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +00001
2/*
3 * Copyright 2012 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
9#include "GrAAConvexPathRenderer.h"
10
11#include "GrContext.h"
12#include "GrDrawState.h"
13#include "GrPathUtils.h"
14#include "SkString.h"
15#include "SkTrace.h"
16
17
18GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
19}
20
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000021namespace {
22
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000023struct Segment {
24 enum {
bsalomon@google.com9b1517e2012-03-05 17:58:34 +000025 // These enum values are assumed in member functions below.
26 kLine = 0,
27 kQuad = 1,
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000028 } fType;
bsalomon@google.com9b1517e2012-03-05 17:58:34 +000029
bsalomon@google.com9aed1142012-01-30 14:28:39 +000030 // line uses one pt, quad uses 2 pts
31 GrPoint fPts[2];
32 // normal to edge ending at each pt
33 GrVec fNorms[2];
34 // is the corner where the previous segment meets this segment
35 // sharp. If so, fMid is a normalized bisector facing outward.
36 GrVec fMid;
37
38 int countPoints() {
bsalomon@google.com9b1517e2012-03-05 17:58:34 +000039 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
40 return fType + 1;
bsalomon@google.com9aed1142012-01-30 14:28:39 +000041 }
42 const SkPoint& endPt() const {
bsalomon@google.com9b1517e2012-03-05 17:58:34 +000043 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
44 return fPts[fType];
bsalomon@google.com9aed1142012-01-30 14:28:39 +000045 };
46 const SkPoint& endNorm() const {
bsalomon@google.com9b1517e2012-03-05 17:58:34 +000047 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
48 return fNorms[fType];
bsalomon@google.com9aed1142012-01-30 14:28:39 +000049 };
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000050};
51
52typedef SkTArray<Segment, true> SegmentArray;
53
bsalomon@google.com9aed1142012-01-30 14:28:39 +000054void center_of_mass(const SegmentArray& segments, SkPoint* c) {
55 GrScalar area = 0;
vandebo@chromium.org6390c722012-03-28 21:03:22 +000056 SkPoint center = {0, 0};
bsalomon@google.com9aed1142012-01-30 14:28:39 +000057 int count = segments.count();
vandebo@chromium.org6390c722012-03-28 21:03:22 +000058 SkPoint p0 = {0, 0};
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +000059 if (count > 2) {
60 // We translate the polygon so that the first point is at the origin.
61 // This avoids some precision issues with small area polygons far away
62 // from the origin.
63 p0 = segments[0].endPt();
64 SkPoint pi;
65 SkPoint pj;
bsalomon@google.coma51ab842012-07-10 19:53:34 +000066 // the first and last iteration of the below loop would compute
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +000067 // zeros since the starting / ending point is (0,0). So instead we start
68 // at i=1 and make the last iteration i=count-2.
69 pj = segments[1].endPt() - p0;
70 for (int i = 1; i < count - 1; ++i) {
71 pi = pj;
72 const SkPoint pj = segments[i + 1].endPt() - p0;
73
74 GrScalar t = GrMul(pi.fX, pj.fY) - GrMul(pj.fX, pi.fY);
75 area += t;
76 center.fX += (pi.fX + pj.fX) * t;
77 center.fY += (pi.fY + pj.fY) * t;
78
79 }
bsalomon@google.com9aed1142012-01-30 14:28:39 +000080 }
bsalomon@google.com278dc692012-02-15 16:52:51 +000081 // If the poly has no area then we instead return the average of
82 // its points.
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +000083 if (SkScalarNearlyZero(area)) {
bsalomon@google.com278dc692012-02-15 16:52:51 +000084 SkPoint avg;
85 avg.set(0, 0);
86 for (int i = 0; i < count; ++i) {
87 const SkPoint& pt = segments[i].endPt();
88 avg.fX += pt.fX;
89 avg.fY += pt.fY;
90 }
91 SkScalar denom = SK_Scalar1 / count;
92 avg.scale(denom);
93 *c = avg;
94 } else {
95 area *= 3;
96 area = GrScalarDiv(GR_Scalar1, area);
97 center.fX = GrScalarMul(center.fX, area);
98 center.fY = GrScalarMul(center.fY, area);
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +000099 // undo the translate of p0 to the origin.
100 *c = center + p0;
bsalomon@google.com278dc692012-02-15 16:52:51 +0000101 }
102 GrAssert(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY));
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000103}
104
105void compute_vectors(SegmentArray* segments,
bsalomon@google.com278dc692012-02-15 16:52:51 +0000106 SkPoint* fanPt,
107 SkPath::Direction dir,
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000108 int* vCount,
109 int* iCount) {
110 center_of_mass(*segments, fanPt);
111 int count = segments->count();
112
bsalomon@google.com278dc692012-02-15 16:52:51 +0000113 // Make the normals point towards the outside
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000114 GrPoint::Side normSide;
bsalomon@google.com278dc692012-02-15 16:52:51 +0000115 if (dir == SkPath::kCCW_Direction) {
116 normSide = GrPoint::kRight_Side;
117 } else {
118 normSide = GrPoint::kLeft_Side;
119 }
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000120
121 *vCount = 0;
122 *iCount = 0;
123 // compute normals at all points
124 for (int a = 0; a < count; ++a) {
125 const Segment& sega = (*segments)[a];
126 int b = (a + 1) % count;
127 Segment& segb = (*segments)[b];
128
129 const GrPoint* prevPt = &sega.endPt();
130 int n = segb.countPoints();
131 for (int p = 0; p < n; ++p) {
132 segb.fNorms[p] = segb.fPts[p] - *prevPt;
133 segb.fNorms[p].normalize();
134 segb.fNorms[p].setOrthog(segb.fNorms[p], normSide);
135 prevPt = &segb.fPts[p];
136 }
137 if (Segment::kLine == segb.fType) {
138 *vCount += 5;
139 *iCount += 9;
140 } else {
141 *vCount += 6;
142 *iCount += 12;
143 }
144 }
145
146 // compute mid-vectors where segments meet. TODO: Detect shallow corners
147 // and leave out the wedges and close gaps by stitching segments together.
148 for (int a = 0; a < count; ++a) {
149 const Segment& sega = (*segments)[a];
150 int b = (a + 1) % count;
151 Segment& segb = (*segments)[b];
152 segb.fMid = segb.fNorms[0] + sega.endNorm();
153 segb.fMid.normalize();
154 // corner wedges
155 *vCount += 4;
156 *iCount += 6;
157 }
158}
159
bsalomon@google.com9732f622012-01-31 15:19:21 +0000160struct DegenerateTestData {
161 DegenerateTestData() { fStage = kInitial; }
162 bool isDegenerate() const { return kNonDegenerate != fStage; }
163 enum {
164 kInitial,
165 kPoint,
166 kLine,
167 kNonDegenerate
168 } fStage;
169 GrPoint fFirstPoint;
170 GrVec fLineNormal;
171 GrScalar fLineC;
172};
173
174void update_degenerate_test(DegenerateTestData* data, const GrPoint& pt) {
175 static const SkScalar TOL = (SK_Scalar1 / 16);
176 static const SkScalar TOL_SQD = SkScalarMul(TOL, TOL);
177
178 switch (data->fStage) {
179 case DegenerateTestData::kInitial:
180 data->fFirstPoint = pt;
181 data->fStage = DegenerateTestData::kPoint;
182 break;
183 case DegenerateTestData::kPoint:
184 if (pt.distanceToSqd(data->fFirstPoint) > TOL_SQD) {
185 data->fLineNormal = pt - data->fFirstPoint;
186 data->fLineNormal.normalize();
187 data->fLineNormal.setOrthog(data->fLineNormal);
188 data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
189 data->fStage = DegenerateTestData::kLine;
190 }
191 break;
192 case DegenerateTestData::kLine:
193 if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > TOL) {
194 data->fStage = DegenerateTestData::kNonDegenerate;
195 }
196 case DegenerateTestData::kNonDegenerate:
197 break;
198 default:
199 GrCrash("Unexpected degenerate test stage.");
200 }
201}
202
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000203inline bool get_direction(const SkPath& path, const GrMatrix& m, SkPath::Direction* dir) {
204 if (!path.cheapComputeDirection(dir)) {
205 return false;
206 }
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000207 // check whether m reverses the orientation
208 GrAssert(!m.hasPerspective());
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000209 GrScalar det2x2 = GrMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) -
210 GrMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY));
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000211 if (det2x2 < 0) {
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000212 GR_STATIC_ASSERT(0 == SkPath::kCW_Direction || 1 == SkPath::kCW_Direction);
213 GR_STATIC_ASSERT(0 == SkPath::kCCW_Direction || 1 == SkPath::kCCW_Direction);
214 *dir = static_cast<SkPath::Direction>(*dir ^ 0x1);
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000215 }
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000216 return true;
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000217}
218
bsalomon@google.com8d033a12012-04-27 15:52:53 +0000219bool get_segments(const SkPath& path,
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000220 const GrMatrix& m,
221 SegmentArray* segments,
222 SkPoint* fanPt,
223 int* vCount,
224 int* iCount) {
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000225 SkPath::Iter iter(path, true);
bsalomon@google.com5cc90d12012-01-17 16:28:34 +0000226 // This renderer overemphasises very thin path regions. We use the distance
227 // to the path from the sample to compute coverage. Every pixel intersected
228 // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
229 // notice that the sample may be close to a very thin area of the path and
230 // thus should be very light. This is particularly egregious for degenerate
231 // line paths. We detect paths that are very close to a line (zero area) and
232 // draw nothing.
bsalomon@google.com9732f622012-01-31 15:19:21 +0000233 DegenerateTestData degenerateData;
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000234 SkPath::Direction dir;
235 // get_direction can fail for some degenerate paths.
236 if (!get_direction(path, m, &dir)) {
237 return false;
238 }
bsalomon@google.com9732f622012-01-31 15:19:21 +0000239
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000240 for (;;) {
241 GrPoint pts[4];
242 GrPathCmd cmd = (GrPathCmd)iter.next(pts);
243 switch (cmd) {
bsalomon@google.com9732f622012-01-31 15:19:21 +0000244 case kMove_PathCmd:
bsalomon@google.com1a38d552012-03-15 14:40:46 +0000245 m.mapPoints(pts, 1);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000246 update_degenerate_test(&degenerateData, pts[0]);
247 break;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000248 case kLine_PathCmd: {
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000249 m.mapPoints(pts + 1, 1);
bsalomon@google.com1a38d552012-03-15 14:40:46 +0000250 update_degenerate_test(&degenerateData, pts[1]);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000251 segments->push_back();
252 segments->back().fType = Segment::kLine;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000253 segments->back().fPts[0] = pts[1];
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000254 break;
255 }
256 case kQuadratic_PathCmd:
bsalomon@google.com1a38d552012-03-15 14:40:46 +0000257 m.mapPoints(pts + 1, 2);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000258 update_degenerate_test(&degenerateData, pts[1]);
259 update_degenerate_test(&degenerateData, pts[2]);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000260 segments->push_back();
261 segments->back().fType = Segment::kQuad;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000262 segments->back().fPts[0] = pts[1];
263 segments->back().fPts[1] = pts[2];
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000264 break;
265 case kCubic_PathCmd: {
bsalomon@google.com1a38d552012-03-15 14:40:46 +0000266 m.mapPoints(pts, 4);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000267 update_degenerate_test(&degenerateData, pts[1]);
268 update_degenerate_test(&degenerateData, pts[2]);
269 update_degenerate_test(&degenerateData, pts[3]);
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000270 // unlike quads and lines, the pts[0] will also be read (in
271 // convertCubicToQuads).
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000272 SkSTArray<15, SkPoint, true> quads;
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000273 GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000274 int count = quads.count();
275 for (int q = 0; q < count; q += 3) {
276 segments->push_back();
277 segments->back().fType = Segment::kQuad;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000278 segments->back().fPts[0] = quads[q + 1];
279 segments->back().fPts[1] = quads[q + 2];
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000280 }
281 break;
282 };
283 case kEnd_PathCmd:
bsalomon@google.com9732f622012-01-31 15:19:21 +0000284 if (degenerateData.isDegenerate()) {
285 return false;
286 } else {
bsalomon@google.com278dc692012-02-15 16:52:51 +0000287 compute_vectors(segments, fanPt, dir, vCount, iCount);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000288 return true;
289 }
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000290 default:
291 break;
292 }
293 }
294}
295
296struct QuadVertex {
297 GrPoint fPos;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000298 GrPoint fUV;
299 GrScalar fD0;
300 GrScalar fD1;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000301};
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000302
303void create_vertices(const SegmentArray& segments,
304 const SkPoint& fanPt,
305 QuadVertex* verts,
306 uint16_t* idxs) {
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000307 int v = 0;
308 int i = 0;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000309
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000310 int count = segments.count();
311 for (int a = 0; a < count; ++a) {
312 const Segment& sega = segments[a];
313 int b = (a + 1) % count;
314 const Segment& segb = segments[b];
315
316 // FIXME: These tris are inset in the 1 unit arc around the corner
317 verts[v + 0].fPos = sega.endPt();
318 verts[v + 1].fPos = verts[v + 0].fPos + sega.endNorm();
319 verts[v + 2].fPos = verts[v + 0].fPos + segb.fMid;
320 verts[v + 3].fPos = verts[v + 0].fPos + segb.fNorms[0];
321 verts[v + 0].fUV.set(0,0);
322 verts[v + 1].fUV.set(0,-SK_Scalar1);
323 verts[v + 2].fUV.set(0,-SK_Scalar1);
324 verts[v + 3].fUV.set(0,-SK_Scalar1);
325 verts[v + 0].fD0 = verts[v + 0].fD1 = -SK_Scalar1;
326 verts[v + 1].fD0 = verts[v + 1].fD1 = -SK_Scalar1;
327 verts[v + 2].fD0 = verts[v + 2].fD1 = -SK_Scalar1;
328 verts[v + 3].fD0 = verts[v + 3].fD1 = -SK_Scalar1;
329
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000330 idxs[i + 0] = v + 0;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000331 idxs[i + 1] = v + 2;
332 idxs[i + 2] = v + 1;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000333 idxs[i + 3] = v + 0;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000334 idxs[i + 4] = v + 3;
335 idxs[i + 5] = v + 2;
336
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000337 v += 4;
338 i += 6;
339
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000340 if (Segment::kLine == segb.fType) {
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000341 verts[v + 0].fPos = fanPt;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000342 verts[v + 1].fPos = sega.endPt();
343 verts[v + 2].fPos = segb.fPts[0];
344
345 verts[v + 3].fPos = verts[v + 1].fPos + segb.fNorms[0];
346 verts[v + 4].fPos = verts[v + 2].fPos + segb.fNorms[0];
347
348 // we draw the line edge as a degenerate quad (u is 0, v is the
349 // signed distance to the edge)
350 GrScalar dist = fanPt.distanceToLineBetween(verts[v + 1].fPos,
351 verts[v + 2].fPos);
352 verts[v + 0].fUV.set(0, dist);
353 verts[v + 1].fUV.set(0, 0);
354 verts[v + 2].fUV.set(0, 0);
355 verts[v + 3].fUV.set(0, -SK_Scalar1);
356 verts[v + 4].fUV.set(0, -SK_Scalar1);
357
358 verts[v + 0].fD0 = verts[v + 0].fD1 = -SK_Scalar1;
359 verts[v + 1].fD0 = verts[v + 1].fD1 = -SK_Scalar1;
360 verts[v + 2].fD0 = verts[v + 2].fD1 = -SK_Scalar1;
361 verts[v + 3].fD0 = verts[v + 3].fD1 = -SK_Scalar1;
362 verts[v + 4].fD0 = verts[v + 4].fD1 = -SK_Scalar1;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000363
364 idxs[i + 0] = v + 0;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000365 idxs[i + 1] = v + 2;
366 idxs[i + 2] = v + 1;
367
368 idxs[i + 3] = v + 3;
369 idxs[i + 4] = v + 1;
370 idxs[i + 5] = v + 2;
371
372 idxs[i + 6] = v + 4;
373 idxs[i + 7] = v + 3;
bsalomon@google.com06809612012-01-21 15:03:39 +0000374 idxs[i + 8] = v + 2;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000375
bsalomon@google.com06809612012-01-21 15:03:39 +0000376 v += 5;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000377 i += 9;
bsalomon@google.com06809612012-01-21 15:03:39 +0000378 } else {
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000379 GrPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
bsalomon@google.com495e2102012-01-21 14:48:36 +0000380
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000381 GrVec midVec = segb.fNorms[0] + segb.fNorms[1];
382 midVec.normalize();
bsalomon@google.com06809612012-01-21 15:03:39 +0000383
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000384 verts[v + 0].fPos = fanPt;
385 verts[v + 1].fPos = qpts[0];
386 verts[v + 2].fPos = qpts[2];
387 verts[v + 3].fPos = qpts[0] + segb.fNorms[0];
388 verts[v + 4].fPos = qpts[2] + segb.fNorms[1];
389 verts[v + 5].fPos = qpts[1] + midVec;
390
391 GrScalar c = segb.fNorms[0].dot(qpts[0]);
392 verts[v + 0].fD0 = -segb.fNorms[0].dot(fanPt) + c;
393 verts[v + 1].fD0 = 0.f;
394 verts[v + 2].fD0 = -segb.fNorms[0].dot(qpts[2]) + c;
395 verts[v + 3].fD0 = -GR_ScalarMax/100;
396 verts[v + 4].fD0 = -GR_ScalarMax/100;
397 verts[v + 5].fD0 = -GR_ScalarMax/100;
398
399 c = segb.fNorms[1].dot(qpts[2]);
400 verts[v + 0].fD1 = -segb.fNorms[1].dot(fanPt) + c;
401 verts[v + 1].fD1 = -segb.fNorms[1].dot(qpts[0]) + c;
402 verts[v + 2].fD1 = 0.f;
403 verts[v + 3].fD1 = -GR_ScalarMax/100;
404 verts[v + 4].fD1 = -GR_ScalarMax/100;
405 verts[v + 5].fD1 = -GR_ScalarMax/100;
406
bsalomon@google.com19713172012-03-15 13:51:08 +0000407 GrPathUtils::QuadUVMatrix toUV(qpts);
408 toUV.apply<6, sizeof(QuadVertex), sizeof(GrPoint)>(verts + v);
bsalomon@google.com06809612012-01-21 15:03:39 +0000409
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000410 idxs[i + 0] = v + 3;
411 idxs[i + 1] = v + 1;
412 idxs[i + 2] = v + 2;
413 idxs[i + 3] = v + 4;
414 idxs[i + 4] = v + 3;
415 idxs[i + 5] = v + 2;
bsalomon@google.com06809612012-01-21 15:03:39 +0000416
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000417 idxs[i + 6] = v + 5;
418 idxs[i + 7] = v + 3;
419 idxs[i + 8] = v + 4;
420
421 idxs[i + 9] = v + 0;
422 idxs[i + 10] = v + 2;
423 idxs[i + 11] = v + 1;
424
425 v += 6;
426 i += 12;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000427 }
428 }
429}
430
431}
432
robertphillips@google.comfa662942012-05-17 12:20:22 +0000433bool GrAAConvexPathRenderer::canDrawPath(const SkPath& path,
434 GrPathFill fill,
435 const GrDrawTarget* target,
436 bool antiAlias) const {
robertphillips@google.com8a4fc402012-05-24 12:42:24 +0000437 if (!target->getCaps().fShaderDerivativeSupport || !antiAlias ||
bsalomon@google.com47059542012-06-06 20:51:20 +0000438 kHairLine_GrPathFill == fill || GrIsFillInverted(fill) ||
robertphillips@google.com8a4fc402012-05-24 12:42:24 +0000439 !path.isConvex()) {
440 return false;
441 } else {
442 return true;
443 }
robertphillips@google.comfa662942012-05-17 12:20:22 +0000444}
445
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000446bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath,
447 GrPathFill fill,
448 const GrVec* translate,
449 GrDrawTarget* target,
450 GrDrawState::StageMask stageMask,
451 bool antiAlias) {
452
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000453 const SkPath* path = &origPath;
454 if (path->isEmpty()) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000455 return true;
456 }
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000457 GrDrawTarget::AutoStateRestore asr(target,
458 GrDrawTarget::kPreserve_ASRInit);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000459 GrDrawState* drawState = target->drawState();
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000460
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000461 GrMatrix vm = drawState->getViewMatrix();
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000462 if (NULL != translate) {
463 vm.postTranslate(translate->fX, translate->fY);
464 }
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000465 GrMatrix ivm;
466 if (vm.invert(&ivm)) {
467 drawState->preConcatSamplerMatrices(stageMask, ivm);
468 }
bsalomon@google.comb3e40c02012-03-20 15:36:32 +0000469 drawState->viewMatrix()->reset();
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000470
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000471 GrVertexLayout layout = 0;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000472 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
473
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000474 // We use the fact that SkPath::transform path does subdivision based on
475 // perspective. Otherwise, we apply the view matrix when copying to the
476 // segment representation.
477 SkPath tmpPath;
478 if (vm.hasPerspective()) {
479 origPath.transform(vm, &tmpPath);
480 path = &tmpPath;
481 vm.reset();
482 }
483
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000484 QuadVertex *verts;
485 uint16_t* idxs;
486
bsalomon@google.com06809612012-01-21 15:03:39 +0000487 int vCount;
488 int iCount;
bsalomon@google.com68a5b262012-03-05 18:24:07 +0000489 enum {
490 kPreallocSegmentCnt = 512 / sizeof(Segment),
491 };
492 SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000493 SkPoint fanPt;
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000494
495 if (!get_segments(*path, vm, &segments, &fanPt, &vCount, &iCount)) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000496 return false;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000497 }
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000498
bsalomon@google.comb3729422012-03-07 19:13:28 +0000499 GrDrawTarget::AutoReleaseGeometry arg(target, layout, vCount, iCount);
500 if (!arg.succeeded()) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000501 return false;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000502 }
bsalomon@google.comb3729422012-03-07 19:13:28 +0000503 verts = reinterpret_cast<QuadVertex*>(arg.vertices());
504 idxs = reinterpret_cast<uint16_t*>(arg.indices());
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000505
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000506 create_vertices(segments, fanPt, verts, idxs);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000507
508 drawState->setVertexEdgeType(GrDrawState::kQuad_EdgeType);
bsalomon@google.com47059542012-06-06 20:51:20 +0000509 target->drawIndexed(kTriangles_GrPrimitiveType,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000510 0, // start vertex
511 0, // start index
512 vCount,
513 iCount);
514 return true;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000515}
516