d0f6e0ef64d4494d59ee3ea226bbf240765fb189
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrAAConvexPathRenderer.cpp
1
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 "GrDrawTargetCaps.h"
14 #include "GrEffect.h"
15 #include "GrPathUtils.h"
16 #include "GrTBackendEffectFactory.h"
17 #include "SkString.h"
18 #include "SkStrokeRec.h"
19 #include "SkTraceEvent.h"
20
21 #include "gl/GrGLEffect.h"
22 #include "gl/GrGLSL.h"
23 #include "gl/GrGLVertexEffect.h"
24
25 #include "effects/GrVertexEffect.h"
26
27 GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
28 }
29
30 struct Segment {
31     enum {
32         // These enum values are assumed in member functions below.
33         kLine = 0,
34         kQuad = 1,
35     } fType;
36
37     // line uses one pt, quad uses 2 pts
38     SkPoint fPts[2];
39     // normal to edge ending at each pt
40     SkVector fNorms[2];
41     // is the corner where the previous segment meets this segment
42     // sharp. If so, fMid is a normalized bisector facing outward.
43     SkVector fMid;
44
45     int countPoints() {
46         GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
47         return fType + 1;
48     }
49     const SkPoint& endPt() const {
50         GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
51         return fPts[fType];
52     };
53     const SkPoint& endNorm() const {
54         GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
55         return fNorms[fType];
56     };
57 };
58
59 typedef SkTArray<Segment, true> SegmentArray;
60
61 static void center_of_mass(const SegmentArray& segments, SkPoint* c) {
62     SkScalar area = 0;
63     SkPoint center = {0, 0};
64     int count = segments.count();
65     SkPoint p0 = {0, 0};
66     if (count > 2) {
67         // We translate the polygon so that the first point is at the origin.
68         // This avoids some precision issues with small area polygons far away
69         // from the origin.
70         p0 = segments[0].endPt();
71         SkPoint pi;
72         SkPoint pj;
73         // the first and last iteration of the below loop would compute
74         // zeros since the starting / ending point is (0,0). So instead we start
75         // at i=1 and make the last iteration i=count-2.
76         pj = segments[1].endPt() - p0;
77         for (int i = 1; i < count - 1; ++i) {
78             pi = pj;
79             const SkPoint pj = segments[i + 1].endPt() - p0;
80
81             SkScalar t = SkScalarMul(pi.fX, pj.fY) - SkScalarMul(pj.fX, pi.fY);
82             area += t;
83             center.fX += (pi.fX + pj.fX) * t;
84             center.fY += (pi.fY + pj.fY) * t;
85
86         }
87     }
88     // If the poly has no area then we instead return the average of
89     // its points.
90     if (SkScalarNearlyZero(area)) {
91         SkPoint avg;
92         avg.set(0, 0);
93         for (int i = 0; i < count; ++i) {
94             const SkPoint& pt = segments[i].endPt();
95             avg.fX += pt.fX;
96             avg.fY += pt.fY;
97         }
98         SkScalar denom = SK_Scalar1 / count;
99         avg.scale(denom);
100         *c = avg;
101     } else {
102         area *= 3;
103         area = SkScalarDiv(SK_Scalar1, area);
104         center.fX = SkScalarMul(center.fX, area);
105         center.fY = SkScalarMul(center.fY, area);
106         // undo the translate of p0 to the origin.
107         *c = center + p0;
108     }
109     SkASSERT(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY));
110 }
111
112 static void compute_vectors(SegmentArray* segments,
113                             SkPoint* fanPt,
114                             SkPath::Direction dir,
115                             int* vCount,
116                             int* iCount) {
117     center_of_mass(*segments, fanPt);
118     int count = segments->count();
119
120     // Make the normals point towards the outside
121     SkPoint::Side normSide;
122     if (dir == SkPath::kCCW_Direction) {
123         normSide = SkPoint::kRight_Side;
124     } else {
125         normSide = SkPoint::kLeft_Side;
126     }
127
128     *vCount = 0;
129     *iCount = 0;
130     // compute normals at all points
131     for (int a = 0; a < count; ++a) {
132         Segment& sega = (*segments)[a];
133         int b = (a + 1) % count;
134         Segment& segb = (*segments)[b];
135
136         const SkPoint* prevPt = &sega.endPt();
137         int n = segb.countPoints();
138         for (int p = 0; p < n; ++p) {
139             segb.fNorms[p] = segb.fPts[p] - *prevPt;
140             segb.fNorms[p].normalize();
141             segb.fNorms[p].setOrthog(segb.fNorms[p], normSide);
142             prevPt = &segb.fPts[p];
143         }
144         if (Segment::kLine == segb.fType) {
145             *vCount += 5;
146             *iCount += 9;
147         } else {
148             *vCount += 6;
149             *iCount += 12;
150         }
151     }
152
153     // compute mid-vectors where segments meet. TODO: Detect shallow corners
154     // and leave out the wedges and close gaps by stitching segments together.
155     for (int a = 0; a < count; ++a) {
156         const Segment& sega = (*segments)[a];
157         int b = (a + 1) % count;
158         Segment& segb = (*segments)[b];
159         segb.fMid = segb.fNorms[0] + sega.endNorm();
160         segb.fMid.normalize();
161         // corner wedges
162         *vCount += 4;
163         *iCount += 6;
164     }
165 }
166
167 struct DegenerateTestData {
168     DegenerateTestData() { fStage = kInitial; }
169     bool isDegenerate() const { return kNonDegenerate != fStage; }
170     enum {
171         kInitial,
172         kPoint,
173         kLine,
174         kNonDegenerate
175     }           fStage;
176     SkPoint     fFirstPoint;
177     SkVector    fLineNormal;
178     SkScalar    fLineC;
179 };
180
181 static const SkScalar kClose = (SK_Scalar1 / 16);
182 static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
183
184 static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) {
185     switch (data->fStage) {
186         case DegenerateTestData::kInitial:
187             data->fFirstPoint = pt;
188             data->fStage = DegenerateTestData::kPoint;
189             break;
190         case DegenerateTestData::kPoint:
191             if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) {
192                 data->fLineNormal = pt - data->fFirstPoint;
193                 data->fLineNormal.normalize();
194                 data->fLineNormal.setOrthog(data->fLineNormal);
195                 data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
196                 data->fStage = DegenerateTestData::kLine;
197             }
198             break;
199         case DegenerateTestData::kLine:
200             if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) {
201                 data->fStage = DegenerateTestData::kNonDegenerate;
202             }
203         case DegenerateTestData::kNonDegenerate:
204             break;
205         default:
206             SkFAIL("Unexpected degenerate test stage.");
207     }
208 }
209
210 static inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::Direction* dir) {
211     if (!path.cheapComputeDirection(dir)) {
212         return false;
213     }
214     // check whether m reverses the orientation
215     SkASSERT(!m.hasPerspective());
216     SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) -
217                       SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY));
218     if (det2x2 < 0) {
219         *dir = SkPath::OppositeDirection(*dir);
220     }
221     return true;
222 }
223
224 static inline void add_line_to_segment(const SkPoint& pt,
225                                        SegmentArray* segments,
226                                        SkRect* devBounds) {
227     segments->push_back();
228     segments->back().fType = Segment::kLine;
229     segments->back().fPts[0] = pt;
230     devBounds->growToInclude(pt.fX, pt.fY);
231 }
232
233 #ifdef SK_DEBUG
234 static inline bool contains_inclusive(const SkRect& rect, const SkPoint& p) {
235     return p.fX >= rect.fLeft && p.fX <= rect.fRight && p.fY >= rect.fTop && p.fY <= rect.fBottom;
236 }
237 #endif
238
239 static inline void add_quad_segment(const SkPoint pts[3],
240                                     SegmentArray* segments,
241                                     SkRect* devBounds) {
242     if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) {
243         if (pts[0] != pts[2]) {
244             add_line_to_segment(pts[2], segments, devBounds);
245         }
246     } else {
247         segments->push_back();
248         segments->back().fType = Segment::kQuad;
249         segments->back().fPts[0] = pts[1];
250         segments->back().fPts[1] = pts[2];
251         SkASSERT(contains_inclusive(*devBounds, pts[0]));
252         devBounds->growToInclude(pts + 1, 2);
253     }
254 }
255
256 static inline void add_cubic_segments(const SkPoint pts[4],
257                                       SkPath::Direction dir,
258                                       SegmentArray* segments,
259                                       SkRect* devBounds) {
260     SkSTArray<15, SkPoint, true> quads;
261     GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads);
262     int count = quads.count();
263     for (int q = 0; q < count; q += 3) {
264         add_quad_segment(&quads[q], segments, devBounds);
265     }
266 }
267
268 static bool get_segments(const SkPath& path,
269                          const SkMatrix& m,
270                          SegmentArray* segments,
271                          SkPoint* fanPt,
272                          int* vCount,
273                          int* iCount,
274                          SkRect* devBounds) {
275     SkPath::Iter iter(path, true);
276     // This renderer over-emphasizes very thin path regions. We use the distance
277     // to the path from the sample to compute coverage. Every pixel intersected
278     // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
279     // notice that the sample may be close to a very thin area of the path and
280     // thus should be very light. This is particularly egregious for degenerate
281     // line paths. We detect paths that are very close to a line (zero area) and
282     // draw nothing.
283     DegenerateTestData degenerateData;
284     SkPath::Direction dir;
285     // get_direction can fail for some degenerate paths.
286     if (!get_direction(path, m, &dir)) {
287         return false;
288     }
289
290     for (;;) {
291         SkPoint pts[4];
292         SkPath::Verb verb = iter.next(pts);
293         switch (verb) {
294             case SkPath::kMove_Verb:
295                 m.mapPoints(pts, 1);
296                 update_degenerate_test(&degenerateData, pts[0]);
297                 devBounds->set(pts->fX, pts->fY, pts->fX, pts->fY);
298                 break;
299             case SkPath::kLine_Verb: {
300                 m.mapPoints(&pts[1], 1);
301                 update_degenerate_test(&degenerateData, pts[1]);
302                 add_line_to_segment(pts[1], segments, devBounds);
303                 break;
304             }
305             case SkPath::kQuad_Verb:
306                 m.mapPoints(pts, 3);
307                 update_degenerate_test(&degenerateData, pts[1]);
308                 update_degenerate_test(&degenerateData, pts[2]);
309                 add_quad_segment(pts, segments, devBounds);
310                 break;
311             case SkPath::kCubic_Verb: {
312                 m.mapPoints(pts, 4);
313                 update_degenerate_test(&degenerateData, pts[1]);
314                 update_degenerate_test(&degenerateData, pts[2]);
315                 update_degenerate_test(&degenerateData, pts[3]);
316                 add_cubic_segments(pts, dir, segments, devBounds);
317                 break;
318             };
319             case SkPath::kDone_Verb:
320                 if (degenerateData.isDegenerate()) {
321                     return false;
322                 } else {
323                     compute_vectors(segments, fanPt, dir, vCount, iCount);
324                     return true;
325                 }
326             default:
327                 break;
328         }
329     }
330 }
331
332 struct QuadVertex {
333     SkPoint  fPos;
334     SkPoint  fUV;
335     SkScalar fD0;
336     SkScalar fD1;
337 };
338
339 struct Draw {
340     Draw() : fVertexCnt(0), fIndexCnt(0) {}
341     int fVertexCnt;
342     int fIndexCnt;
343 };
344
345 typedef SkTArray<Draw, true> DrawArray;
346
347 static void create_vertices(const SegmentArray&  segments,
348                             const SkPoint& fanPt,
349                             DrawArray*     draws,
350                             QuadVertex*    verts,
351                             uint16_t*      idxs) {
352     Draw* draw = &draws->push_back();
353     // alias just to make vert/index assignments easier to read.
354     int* v = &draw->fVertexCnt;
355     int* i = &draw->fIndexCnt;
356
357     int count = segments.count();
358     for (int a = 0; a < count; ++a) {
359         const Segment& sega = segments[a];
360         int b = (a + 1) % count;
361         const Segment& segb = segments[b];
362
363         // Check whether adding the verts for this segment to the current draw would cause index
364         // values to overflow.
365         int vCount = 4;
366         if (Segment::kLine == segb.fType) {
367             vCount += 5;
368         } else {
369             vCount += 6;
370         }
371         if (draw->fVertexCnt + vCount > (1 << 16)) {
372             verts += *v;
373             idxs += *i;
374             draw = &draws->push_back();
375             v = &draw->fVertexCnt;
376             i = &draw->fIndexCnt;
377         }
378
379         // FIXME: These tris are inset in the 1 unit arc around the corner
380         verts[*v + 0].fPos = sega.endPt();
381         verts[*v + 1].fPos = verts[*v + 0].fPos + sega.endNorm();
382         verts[*v + 2].fPos = verts[*v + 0].fPos + segb.fMid;
383         verts[*v + 3].fPos = verts[*v + 0].fPos + segb.fNorms[0];
384         verts[*v + 0].fUV.set(0,0);
385         verts[*v + 1].fUV.set(0,-SK_Scalar1);
386         verts[*v + 2].fUV.set(0,-SK_Scalar1);
387         verts[*v + 3].fUV.set(0,-SK_Scalar1);
388         verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
389         verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
390         verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
391         verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
392
393         idxs[*i + 0] = *v + 0;
394         idxs[*i + 1] = *v + 2;
395         idxs[*i + 2] = *v + 1;
396         idxs[*i + 3] = *v + 0;
397         idxs[*i + 4] = *v + 3;
398         idxs[*i + 5] = *v + 2;
399
400         *v += 4;
401         *i += 6;
402
403         if (Segment::kLine == segb.fType) {
404             verts[*v + 0].fPos = fanPt;
405             verts[*v + 1].fPos = sega.endPt();
406             verts[*v + 2].fPos = segb.fPts[0];
407
408             verts[*v + 3].fPos = verts[*v + 1].fPos + segb.fNorms[0];
409             verts[*v + 4].fPos = verts[*v + 2].fPos + segb.fNorms[0];
410
411             // we draw the line edge as a degenerate quad (u is 0, v is the
412             // signed distance to the edge)
413             SkScalar dist = fanPt.distanceToLineBetween(verts[*v + 1].fPos,
414                                                         verts[*v + 2].fPos);
415             verts[*v + 0].fUV.set(0, dist);
416             verts[*v + 1].fUV.set(0, 0);
417             verts[*v + 2].fUV.set(0, 0);
418             verts[*v + 3].fUV.set(0, -SK_Scalar1);
419             verts[*v + 4].fUV.set(0, -SK_Scalar1);
420
421             verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
422             verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
423             verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
424             verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
425             verts[*v + 4].fD0 = verts[*v + 4].fD1 = -SK_Scalar1;
426
427             idxs[*i + 0] = *v + 0;
428             idxs[*i + 1] = *v + 2;
429             idxs[*i + 2] = *v + 1;
430
431             idxs[*i + 3] = *v + 3;
432             idxs[*i + 4] = *v + 1;
433             idxs[*i + 5] = *v + 2;
434
435             idxs[*i + 6] = *v + 4;
436             idxs[*i + 7] = *v + 3;
437             idxs[*i + 8] = *v + 2;
438
439             *v += 5;
440             *i += 9;
441         } else {
442             SkPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
443
444             SkVector midVec = segb.fNorms[0] + segb.fNorms[1];
445             midVec.normalize();
446
447             verts[*v + 0].fPos = fanPt;
448             verts[*v + 1].fPos = qpts[0];
449             verts[*v + 2].fPos = qpts[2];
450             verts[*v + 3].fPos = qpts[0] + segb.fNorms[0];
451             verts[*v + 4].fPos = qpts[2] + segb.fNorms[1];
452             verts[*v + 5].fPos = qpts[1] + midVec;
453
454             SkScalar c = segb.fNorms[0].dot(qpts[0]);
455             verts[*v + 0].fD0 =  -segb.fNorms[0].dot(fanPt) + c;
456             verts[*v + 1].fD0 =  0.f;
457             verts[*v + 2].fD0 =  -segb.fNorms[0].dot(qpts[2]) + c;
458             verts[*v + 3].fD0 = -SK_ScalarMax/100;
459             verts[*v + 4].fD0 = -SK_ScalarMax/100;
460             verts[*v + 5].fD0 = -SK_ScalarMax/100;
461
462             c = segb.fNorms[1].dot(qpts[2]);
463             verts[*v + 0].fD1 =  -segb.fNorms[1].dot(fanPt) + c;
464             verts[*v + 1].fD1 =  -segb.fNorms[1].dot(qpts[0]) + c;
465             verts[*v + 2].fD1 =  0.f;
466             verts[*v + 3].fD1 = -SK_ScalarMax/100;
467             verts[*v + 4].fD1 = -SK_ScalarMax/100;
468             verts[*v + 5].fD1 = -SK_ScalarMax/100;
469
470             GrPathUtils::QuadUVMatrix toUV(qpts);
471             toUV.apply<6, sizeof(QuadVertex), sizeof(SkPoint)>(verts + *v);
472
473             idxs[*i + 0] = *v + 3;
474             idxs[*i + 1] = *v + 1;
475             idxs[*i + 2] = *v + 2;
476             idxs[*i + 3] = *v + 4;
477             idxs[*i + 4] = *v + 3;
478             idxs[*i + 5] = *v + 2;
479
480             idxs[*i + 6] = *v + 5;
481             idxs[*i + 7] = *v + 3;
482             idxs[*i + 8] = *v + 4;
483
484             idxs[*i +  9] = *v + 0;
485             idxs[*i + 10] = *v + 2;
486             idxs[*i + 11] = *v + 1;
487
488             *v += 6;
489             *i += 12;
490         }
491     }
492 }
493
494 ///////////////////////////////////////////////////////////////////////////////
495
496 /*
497  * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
498  * two components of the vertex attribute. Coverage is based on signed
499  * distance with negative being inside, positive outside. The edge is specified in
500  * window space (y-down). If either the third or fourth component of the interpolated
501  * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
502  * attempt to trim to a portion of the infinite quad.
503  * Requires shader derivative instruction support.
504  */
505
506 class QuadEdgeEffect : public GrVertexEffect {
507 public:
508
509     static GrEffectRef* Create() {
510         GR_CREATE_STATIC_EFFECT(gQuadEdgeEffect, QuadEdgeEffect, ());
511         gQuadEdgeEffect->ref();
512         return gQuadEdgeEffect;
513     }
514
515     virtual ~QuadEdgeEffect() {}
516
517     static const char* Name() { return "QuadEdge"; }
518
519     virtual void getConstantColorComponents(GrColor* color,
520                                             uint32_t* validFlags) const SK_OVERRIDE {
521         *validFlags = 0;
522     }
523
524     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
525         return GrTBackendEffectFactory<QuadEdgeEffect>::getInstance();
526     }
527
528     class GLEffect : public GrGLVertexEffect {
529     public:
530         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
531             : INHERITED (factory) {}
532
533         virtual void emitCode(GrGLFullShaderBuilder* builder,
534                               const GrDrawEffect& drawEffect,
535                               EffectKey key,
536                               const char* outputColor,
537                               const char* inputColor,
538                               const TransformedCoordsArray&,
539                               const TextureSamplerArray& samplers) SK_OVERRIDE {
540             const char *vsName, *fsName;
541             const SkString* attrName =
542                 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
543             builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
544
545             SkAssertResult(builder->enableFeature(
546                                               GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
547             builder->addVarying(kVec4f_GrSLType, "QuadEdge", &vsName, &fsName);
548
549             // keep the derivative instructions outside the conditional
550             builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
551             builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
552             builder->fsCodeAppendf("\t\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
553             // today we know z and w are in device space. We could use derivatives
554             builder->fsCodeAppendf("\t\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
555                                     fsName);
556             builder->fsCodeAppendf ("\t\t} else {\n");
557             builder->fsCodeAppendf("\t\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
558                                    "\t\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
559                                    fsName, fsName);
560             builder->fsCodeAppendf("\t\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
561                                     fsName);
562             builder->fsCodeAppendf("\t\t\tedgeAlpha = "
563                                    "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n\t\t}\n");
564
565
566             builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
567                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
568
569             builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
570         }
571
572         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
573             return 0x0;
574         }
575
576         virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
577
578     private:
579         typedef GrGLVertexEffect INHERITED;
580     };
581
582 private:
583     QuadEdgeEffect() {
584         this->addVertexAttrib(kVec4f_GrSLType);
585     }
586
587     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
588         return true;
589     }
590
591     GR_DECLARE_EFFECT_TEST;
592
593     typedef GrVertexEffect INHERITED;
594 };
595
596 GR_DEFINE_EFFECT_TEST(QuadEdgeEffect);
597
598 GrEffectRef* QuadEdgeEffect::TestCreate(SkRandom* random,
599                                         GrContext*,
600                                         const GrDrawTargetCaps& caps,
601                                         GrTexture*[]) {
602     // Doesn't work without derivative instructions.
603     return caps.shaderDerivativeSupport() ? QuadEdgeEffect::Create() : NULL;
604 }
605
606 ///////////////////////////////////////////////////////////////////////////////
607
608 bool GrAAConvexPathRenderer::canDrawPath(const SkPath& path,
609                                          const SkStrokeRec& stroke,
610                                          const GrDrawTarget* target,
611                                          bool antiAlias) const {
612     return (target->caps()->shaderDerivativeSupport() && antiAlias &&
613             stroke.isFillStyle() && !path.isInverseFillType() && path.isConvex());
614 }
615
616 namespace {
617
618 // position + edge
619 extern const GrVertexAttrib gPathAttribs[] = {
620     {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
621     {kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding}
622 };
623
624 };
625
626 bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath,
627                                         const SkStrokeRec&,
628                                         GrDrawTarget* target,
629                                         bool antiAlias) {
630
631     const SkPath* path = &origPath;
632     if (path->isEmpty()) {
633         return true;
634     }
635
636     SkMatrix viewMatrix = target->getDrawState().getViewMatrix();
637     GrDrawTarget::AutoStateRestore asr;
638     if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) {
639         return false;
640     }
641     GrDrawState* drawState = target->drawState();
642
643     // We use the fact that SkPath::transform path does subdivision based on
644     // perspective. Otherwise, we apply the view matrix when copying to the
645     // segment representation.
646     SkPath tmpPath;
647     if (viewMatrix.hasPerspective()) {
648         origPath.transform(viewMatrix, &tmpPath);
649         path = &tmpPath;
650         viewMatrix = SkMatrix::I();
651     }
652
653     QuadVertex *verts;
654     uint16_t* idxs;
655
656     int vCount;
657     int iCount;
658     enum {
659         kPreallocSegmentCnt = 512 / sizeof(Segment),
660         kPreallocDrawCnt = 4,
661     };
662     SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
663     SkPoint fanPt;
664
665     // We can't simply use the path bounds because we may degenerate cubics to quads which produces
666     // new control points outside the original convex hull.
667     SkRect devBounds;
668     if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount, &devBounds)) {
669         return false;
670     }
671
672     // Our computed verts should all be within one pixel of the segment control points.
673     devBounds.outset(SK_Scalar1, SK_Scalar1);
674
675     drawState->setVertexAttribs<gPathAttribs>(SK_ARRAY_COUNT(gPathAttribs));
676
677     static const int kEdgeAttrIndex = 1;
678     GrEffectRef* quadEffect = QuadEdgeEffect::Create();
679     drawState->addCoverageEffect(quadEffect, kEdgeAttrIndex)->unref();
680
681     GrDrawTarget::AutoReleaseGeometry arg(target, vCount, iCount);
682     if (!arg.succeeded()) {
683         return false;
684     }
685     SkASSERT(sizeof(QuadVertex) == drawState->getVertexSize());
686     verts = reinterpret_cast<QuadVertex*>(arg.vertices());
687     idxs = reinterpret_cast<uint16_t*>(arg.indices());
688
689     SkSTArray<kPreallocDrawCnt, Draw, true> draws;
690     create_vertices(segments, fanPt, &draws, verts, idxs);
691
692     // Check devBounds
693 #ifdef SK_DEBUG
694     SkRect tolDevBounds = devBounds;
695     tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000);
696     SkRect actualBounds;
697     actualBounds.set(verts[0].fPos, verts[1].fPos);
698     for (int i = 2; i < vCount; ++i) {
699         actualBounds.growToInclude(verts[i].fPos.fX, verts[i].fPos.fY);
700     }
701     SkASSERT(tolDevBounds.contains(actualBounds));
702 #endif
703
704     int vOffset = 0;
705     for (int i = 0; i < draws.count(); ++i) {
706         const Draw& draw = draws[i];
707         target->drawIndexed(kTriangles_GrPrimitiveType,
708                             vOffset,  // start vertex
709                             0,        // start index
710                             draw.fVertexCnt,
711                             draw.fIndexCnt,
712                             &devBounds);
713         vOffset += draw.fVertexCnt;
714     }
715
716     return true;
717 }