gfx/skia/trunk/src/gpu/GrAAConvexPathRenderer.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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  */
     9 #include "GrAAConvexPathRenderer.h"
    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 "SkTrace.h"
    21 #include "gl/GrGLEffect.h"
    22 #include "gl/GrGLSL.h"
    23 #include "gl/GrGLVertexEffect.h"
    25 #include "effects/GrVertexEffect.h"
    27 GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
    28 }
    30 struct Segment {
    31     enum {
    32         // These enum values are assumed in member functions below.
    33         kLine = 0,
    34         kQuad = 1,
    35     } fType;
    37     // line uses one pt, quad uses 2 pts
    38     GrPoint fPts[2];
    39     // normal to edge ending at each pt
    40     GrVec 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     GrVec fMid;
    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 };
    59 typedef SkTArray<Segment, true> SegmentArray;
    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;
    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;
    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 }
   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();
   120     // Make the normals point towards the outside
   121     GrPoint::Side normSide;
   122     if (dir == SkPath::kCCW_Direction) {
   123         normSide = GrPoint::kRight_Side;
   124     } else {
   125         normSide = GrPoint::kLeft_Side;
   126     }
   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];
   136         const GrPoint* 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     }
   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 }
   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     GrPoint     fFirstPoint;
   177     GrVec       fLineNormal;
   178     SkScalar    fLineC;
   179 };
   181 static const SkScalar kClose = (SK_Scalar1 / 16);
   182 static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
   184 static void update_degenerate_test(DegenerateTestData* data, const GrPoint& 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             GrCrash("Unexpected degenerate test stage.");
   207     }
   208 }
   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 }
   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 }
   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
   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 }
   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 }
   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     }
   290     for (;;) {
   291         GrPoint 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 }
   332 struct QuadVertex {
   333     GrPoint  fPos;
   334     GrPoint  fUV;
   335     SkScalar fD0;
   336     SkScalar fD1;
   337 };
   339 struct Draw {
   340     Draw() : fVertexCnt(0), fIndexCnt(0) {}
   341     int fVertexCnt;
   342     int fIndexCnt;
   343 };
   345 typedef SkTArray<Draw, true> DrawArray;
   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;
   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];
   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         }
   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;
   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;
   400         *v += 4;
   401         *i += 6;
   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];
   408             verts[*v + 3].fPos = verts[*v + 1].fPos + segb.fNorms[0];
   409             verts[*v + 4].fPos = verts[*v + 2].fPos + segb.fNorms[0];
   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);
   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;
   427             idxs[*i + 0] = *v + 0;
   428             idxs[*i + 1] = *v + 2;
   429             idxs[*i + 2] = *v + 1;
   431             idxs[*i + 3] = *v + 3;
   432             idxs[*i + 4] = *v + 1;
   433             idxs[*i + 5] = *v + 2;
   435             idxs[*i + 6] = *v + 4;
   436             idxs[*i + 7] = *v + 3;
   437             idxs[*i + 8] = *v + 2;
   439             *v += 5;
   440             *i += 9;
   441         } else {
   442             GrPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
   444             GrVec midVec = segb.fNorms[0] + segb.fNorms[1];
   445             midVec.normalize();
   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;
   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;
   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;
   470             GrPathUtils::QuadUVMatrix toUV(qpts);
   471             toUV.apply<6, sizeof(QuadVertex), sizeof(GrPoint)>(verts + *v);
   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;
   480             idxs[*i + 6] = *v + 5;
   481             idxs[*i + 7] = *v + 3;
   482             idxs[*i + 8] = *v + 4;
   484             idxs[*i +  9] = *v + 0;
   485             idxs[*i + 10] = *v + 2;
   486             idxs[*i + 11] = *v + 1;
   488             *v += 6;
   489             *i += 12;
   490         }
   491     }
   492 }
   494 ///////////////////////////////////////////////////////////////////////////////
   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  */
   506 class QuadEdgeEffect : public GrVertexEffect {
   507 public:
   509     static GrEffectRef* Create() {
   510         GR_CREATE_STATIC_EFFECT(gQuadEdgeEffect, QuadEdgeEffect, ());
   511         gQuadEdgeEffect->ref();
   512         return gQuadEdgeEffect;
   513     }
   515     virtual ~QuadEdgeEffect() {}
   517     static const char* Name() { return "QuadEdge"; }
   519     virtual void getConstantColorComponents(GrColor* color,
   520                                             uint32_t* validFlags) const SK_OVERRIDE {
   521         *validFlags = 0;
   522     }
   524     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
   525         return GrTBackendEffectFactory<QuadEdgeEffect>::getInstance();
   526     }
   528     class GLEffect : public GrGLVertexEffect {
   529     public:
   530         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
   531             : INHERITED (factory) {}
   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");
   545             SkAssertResult(builder->enableFeature(
   546                                               GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
   547             builder->addVarying(kVec4f_GrSLType, "QuadEdge", &vsName, &fsName);
   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");
   566             builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
   567                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
   569             builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
   570         }
   572         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
   573             return 0x0;
   574         }
   576         virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
   578     private:
   579         typedef GrGLVertexEffect INHERITED;
   580     };
   582 private:
   583     QuadEdgeEffect() {
   584         this->addVertexAttrib(kVec4f_GrSLType);
   585     }
   587     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
   588         return true;
   589     }
   591     GR_DECLARE_EFFECT_TEST;
   593     typedef GrVertexEffect INHERITED;
   594 };
   596 GR_DEFINE_EFFECT_TEST(QuadEdgeEffect);
   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 }
   606 ///////////////////////////////////////////////////////////////////////////////
   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 }
   616 namespace {
   618 // position + edge
   619 extern const GrVertexAttrib gPathAttribs[] = {
   620     {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
   621     {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
   622 };
   624 };
   626 bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath,
   627                                         const SkStrokeRec&,
   628                                         GrDrawTarget* target,
   629                                         bool antiAlias) {
   631     const SkPath* path = &origPath;
   632     if (path->isEmpty()) {
   633         return true;
   634     }
   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();
   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     }
   653     QuadVertex *verts;
   654     uint16_t* idxs;
   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;
   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     }
   672     // Our computed verts should all be within one pixel of the segment control points.
   673     devBounds.outset(SK_Scalar1, SK_Scalar1);
   675     drawState->setVertexAttribs<gPathAttribs>(SK_ARRAY_COUNT(gPathAttribs));
   677     static const int kEdgeAttrIndex = 1;
   678     GrEffectRef* quadEffect = QuadEdgeEffect::Create();
   679     drawState->addCoverageEffect(quadEffect, kEdgeAttrIndex)->unref();
   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());
   689     SkSTArray<kPreallocDrawCnt, Draw, true> draws;
   690     create_vertices(segments, fanPt, &draws, verts, idxs);
   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
   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     }
   716     return true;
   717 }

mercurial