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
27GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
28}
29
30struct 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
59typedef SkTArray<Segment, true> SegmentArray;
60
61static 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
112static 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
167struct 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
181static const SkScalar kClose = (SK_Scalar1 / 16);
182static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
183
184static 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
210static 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
224static 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
234static 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
239static 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
256static 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
268static 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
332struct QuadVertex {
333    SkPoint  fPos;
334    SkPoint  fUV;
335    SkScalar fD0;
336    SkScalar fD1;
337};
338
339struct Draw {
340    Draw() : fVertexCnt(0), fIndexCnt(0) {}
341    int fVertexCnt;
342    int fIndexCnt;
343};
344
345typedef SkTArray<Draw, true> DrawArray;
346
347static 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
506class QuadEdgeEffect : public GrVertexEffect {
507public:
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
582private:
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
596GR_DEFINE_EFFECT_TEST(QuadEdgeEffect);
597
598GrEffectRef* 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
608bool 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
616namespace {
617
618// position + edge
619extern const GrVertexAttrib gPathAttribs[] = {
620    {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
621    {kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding}
622};
623
624};
625
626bool 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}
718