| Index: src/gpu/effects/GrDashingEffect.cpp | 
| diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp | 
| index 34e03011b2aced46670e3747f87f909164a61fa9..a33d604668912cf6b5588671400a336e800006c9 100644 | 
| --- a/src/gpu/effects/GrDashingEffect.cpp | 
| +++ b/src/gpu/effects/GrDashingEffect.cpp | 
| @@ -67,6 +67,15 @@ namespace { | 
| struct DashLineVertex { | 
| SkPoint fPos; | 
| SkPoint fDashPos; | 
| +    SkScalar fIntervalLength; | 
| +    SkRect fRect; | 
| +}; | 
| +struct DashCircleVertex { | 
| +    SkPoint fPos; | 
| +    SkPoint fDashPos; | 
| +    SkScalar fIntervalLength; | 
| +    SkScalar fRadius; | 
| +    SkScalar fCenterX; | 
| }; | 
| }; | 
|  | 
| @@ -138,21 +147,73 @@ static SkScalar calc_end_adjustment(const SkPathEffect::DashInfo& info, const Sk | 
| return 0; | 
| } | 
|  | 
| -static void setup_dashed_rect(const SkRect& rect, DashLineVertex* verts, int idx, const SkMatrix& matrix, | 
| -                       SkScalar offset, SkScalar bloat, SkScalar len, SkScalar stroke) { | 
| -        SkScalar startDashX = offset - bloat; | 
| -        SkScalar endDashX = offset + len + bloat; | 
| -        SkScalar startDashY = -stroke - bloat; | 
| -        SkScalar endDashY = stroke + bloat; | 
| -        verts[idx].fDashPos = SkPoint::Make(startDashX , startDashY); | 
| -        verts[idx + 1].fDashPos = SkPoint::Make(startDashX, endDashY); | 
| -        verts[idx + 2].fDashPos = SkPoint::Make(endDashX, endDashY); | 
| -        verts[idx + 3].fDashPos = SkPoint::Make(endDashX, startDashY); | 
| -        verts[idx].fPos = SkPoint::Make(rect.fLeft, rect.fTop); | 
| -        verts[idx + 1].fPos = SkPoint::Make(rect.fLeft, rect.fBottom); | 
| -        verts[idx + 2].fPos = SkPoint::Make(rect.fRight, rect.fBottom); | 
| -        verts[idx + 3].fPos = SkPoint::Make(rect.fRight, rect.fTop); | 
| -        matrix.mapPointsWithStride(&verts[idx].fPos, sizeof(DashLineVertex), 4); | 
| +enum DashCap { | 
| +    kRound_DashCap, | 
| +    kNonRound_DashCap, | 
| +}; | 
| + | 
| +static int kDashVertices = 4; | 
| + | 
| +template <typename T> | 
| +void setup_dashed_rect_common(const SkRect& rect, const SkMatrix& matrix, T* vertices, int idx, | 
| +                              SkScalar offset, SkScalar bloat, SkScalar len, SkScalar stroke) { | 
| +    SkScalar startDashX = offset - bloat; | 
| +    SkScalar endDashX = offset + len + bloat; | 
| +    SkScalar startDashY = -stroke - bloat; | 
| +    SkScalar endDashY = stroke + bloat; | 
| +    vertices[idx].fDashPos = SkPoint::Make(startDashX , startDashY); | 
| +    vertices[idx + 1].fDashPos = SkPoint::Make(startDashX, endDashY); | 
| +    vertices[idx + 2].fDashPos = SkPoint::Make(endDashX, endDashY); | 
| +    vertices[idx + 3].fDashPos = SkPoint::Make(endDashX, startDashY); | 
| + | 
| +    vertices[idx].fPos = SkPoint::Make(rect.fLeft, rect.fTop); | 
| +    vertices[idx + 1].fPos = SkPoint::Make(rect.fLeft, rect.fBottom); | 
| +    vertices[idx + 2].fPos = SkPoint::Make(rect.fRight, rect.fBottom); | 
| +    vertices[idx + 3].fPos = SkPoint::Make(rect.fRight, rect.fTop); | 
| + | 
| +    matrix.mapPointsWithStride(&vertices[idx].fPos, sizeof(T), 4); | 
| +} | 
| + | 
| +static void setup_dashed_rect(const SkRect& rect, void* vertices, int idx, | 
| +                              const SkMatrix& matrix, SkScalar offset, SkScalar bloat, | 
| +                              SkScalar len, SkScalar stroke, SkScalar startInterval, | 
| +                              SkScalar endInterval, SkScalar strokeWidth, DashCap cap, | 
| +                              const size_t vertexStride) { | 
| +    SkScalar intervalLength = startInterval + endInterval; | 
| + | 
| +    if (kRound_DashCap == cap) { | 
| +        SkASSERT(vertexStride == sizeof(DashCircleVertex)); | 
| +        DashCircleVertex* verts = reinterpret_cast<DashCircleVertex*>(vertices); | 
| + | 
| +        setup_dashed_rect_common<DashCircleVertex>(rect, matrix, verts, idx, offset, bloat, len, | 
| +                                                   stroke); | 
| + | 
| +        SkScalar radius = SkScalarHalf(strokeWidth) - 0.5f; | 
| +        SkScalar centerX = SkScalarHalf(endInterval); | 
| + | 
| +        for (int i = 0; i < kDashVertices; i++) { | 
| +            verts[idx + i].fIntervalLength = intervalLength; | 
| +            verts[idx + i].fRadius = radius; | 
| +            verts[idx + i].fCenterX = centerX; | 
| +        } | 
| + | 
| +    } else { | 
| +        SkASSERT(kNonRound_DashCap == cap && vertexStride == sizeof(DashLineVertex)); | 
| +        DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(vertices); | 
| + | 
| +        setup_dashed_rect_common<DashLineVertex>(rect, matrix, verts, idx, offset, bloat, len, | 
| +                                                 stroke); | 
| + | 
| +        SkScalar halfOffLen = SkScalarHalf(endInterval); | 
| +        SkScalar halfStroke = SkScalarHalf(strokeWidth); | 
| +        SkRect rectParam; | 
| +        rectParam.set(halfOffLen + 0.5f, -halfStroke + 0.5f, | 
| +                      halfOffLen + startInterval - 0.5f, halfStroke - 0.5f); | 
| +        for (int i = 0; i < kDashVertices; i++) { | 
| +            verts[idx + i].fIntervalLength = intervalLength; | 
| +            verts[idx + i].fRect = rectParam; | 
| +        } | 
| +    } | 
| } | 
|  | 
| static void setup_dashed_rect_pos(const SkRect& rect, int idx, const SkMatrix& matrix, | 
| @@ -164,6 +225,18 @@ static void setup_dashed_rect_pos(const SkRect& rect, int idx, const SkMatrix& m | 
| matrix.mapPoints(&verts[idx], 4); | 
| } | 
|  | 
| + | 
| +/** | 
| + * An GrGeometryProcessor that renders a dashed line. | 
| + * This GrGeometryProcessor is meant for dashed lines that only have a single on/off interval pair. | 
| + * Bounding geometry is rendered and the effect computes coverage based on the fragment's | 
| + * position relative to the dashed line. | 
| + */ | 
| +static GrGeometryProcessor* create_dash_gp(GrColor, | 
| +                                           GrPrimitiveEdgeType edgeType, | 
| +                                           DashCap cap, | 
| +                                           const SkMatrix& localMatrix); | 
| + | 
| bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, | 
| GrPipelineBuilder* pipelineBuilder, GrColor color, | 
| const SkMatrix& viewMatrix, const SkPoint pts[2], | 
| @@ -342,6 +415,9 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, | 
| return false; | 
| } | 
|  | 
| +    bool isRoundCap = SkPaint::kRound_Cap == cap; | 
| +    DashCap capType = isRoundCap ? kRound_DashCap : kNonRound_DashCap; | 
| + | 
| SkAutoTUnref<const GrGeometryProcessor> gp; | 
| bool fullDash = devIntervals[1] > 0.f || useAA; | 
| if (fullDash) { | 
| @@ -349,12 +425,9 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, | 
| devInfo.fPhase = devPhase; | 
| devInfo.fCount = 2; | 
| devInfo.fIntervals = devIntervals; | 
| -        GrPrimitiveEdgeType edgeType= useAA ? kFillAA_GrProcessorEdgeType : | 
| +        GrPrimitiveEdgeType edgeType = useAA ? kFillAA_GrProcessorEdgeType : | 
| kFillBW_GrProcessorEdgeType; | 
| -        bool isRoundCap = SkPaint::kRound_Cap == cap; | 
| -        GrDashingEffect::DashCap capType = isRoundCap ? GrDashingEffect::kRound_DashCap : | 
| -                                                        GrDashingEffect::kNonRound_DashCap; | 
| -        gp.reset(GrDashingEffect::Create(color, edgeType, devInfo, strokeWidth, capType, invert)); | 
| +        gp.reset(create_dash_gp(color, edgeType, capType, invert)); | 
| } else { | 
| // Set up the vertex data for the line and start/end dashes | 
| gp.reset(GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType, | 
| @@ -397,10 +470,9 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, | 
| bounds.set(ptsRot[0].fX, ptsRot[0].fY, ptsRot[1].fX, ptsRot[1].fY); | 
| bounds.outset(bloatX + strokeAdj, bloatY + halfSrcStroke); | 
| if (fullDash) { | 
| -            DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(geo.vertices()); | 
| -            SkASSERT(gp->getVertexStride() == sizeof(DashLineVertex)); | 
| -            setup_dashed_rect(bounds, verts, curVIdx, combinedMatrix, startOffset, devBloat, | 
| -                                      lineLength, halfDevStroke); | 
| +            setup_dashed_rect(bounds, geo.vertices(), curVIdx, combinedMatrix, startOffset, | 
| +                              devBloat, lineLength, halfDevStroke, devIntervals[0], devIntervals[1], | 
| +                              strokeWidth, capType, gp->getVertexStride()); | 
| } else { | 
| SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices()); | 
| SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); | 
| @@ -413,10 +485,9 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, | 
| SkASSERT(useAA);  // so that we know bloatX and bloatY have been set | 
| startRect.outset(bloatX, bloatY); | 
| if (fullDash) { | 
| -            DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(geo.vertices()); | 
| -            SkASSERT(gp->getVertexStride() == sizeof(DashLineVertex)); | 
| -            setup_dashed_rect(startRect, verts, curVIdx, combinedMatrix, startOffset, devBloat, | 
| -                              devIntervals[0], halfDevStroke); | 
| +            setup_dashed_rect(startRect, geo.vertices(), curVIdx, combinedMatrix, startOffset, | 
| +                              devBloat, devIntervals[0], halfDevStroke, devIntervals[0], | 
| +                              devIntervals[1], strokeWidth, capType, gp->getVertexStride()); | 
| } else { | 
| SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices()); | 
| SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); | 
| @@ -430,10 +501,9 @@ bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, | 
| SkASSERT(useAA);  // so that we know bloatX and bloatY have been set | 
| endRect.outset(bloatX, bloatY); | 
| if (fullDash) { | 
| -            DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(geo.vertices()); | 
| -            SkASSERT(gp->getVertexStride() == sizeof(DashLineVertex)); | 
| -            setup_dashed_rect(endRect, verts, curVIdx, combinedMatrix, startOffset, devBloat, | 
| -                              devIntervals[0], halfDevStroke); | 
| +            setup_dashed_rect(endRect, geo.vertices(), curVIdx, combinedMatrix, startOffset, | 
| +                              devBloat, devIntervals[0], halfDevStroke, devIntervals[0], | 
| +                              devIntervals[1], strokeWidth, capType, gp->getVertexStride()); | 
| } else { | 
| SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices()); | 
| SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); | 
| @@ -474,8 +544,6 @@ public: | 
|  | 
| static GrGeometryProcessor* Create(GrColor, | 
| GrPrimitiveEdgeType edgeType, | 
| -                                       const DashInfo& info, | 
| -                                       SkScalar radius, | 
| const SkMatrix& localMatrix); | 
|  | 
| virtual ~DashingCircleEffect(); | 
| @@ -484,15 +552,11 @@ public: | 
|  | 
| const Attribute* inPosition() const { return fInPosition; } | 
|  | 
| -    const Attribute* inCoord() const { return fInCoord; } | 
| - | 
| -    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } | 
| - | 
| -    SkScalar getRadius() const { return fRadius; } | 
| +    const Attribute* inDashParams() const { return fInDashParams; } | 
|  | 
| -    SkScalar getCenterX() const { return fCenterX; } | 
| +    const Attribute* inCircleParams() const { return fInCircleParams; } | 
|  | 
| -    SkScalar getIntervalLength() const { return fIntervalLength; } | 
| +    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } | 
|  | 
| virtual void getGLProcessorKey(const GrBatchTracker&, | 
| const GrGLCaps&, | 
| @@ -508,19 +572,16 @@ public: | 
| const GrBatchTracker&) const SK_OVERRIDE; | 
|  | 
| private: | 
| -    DashingCircleEffect(GrColor, GrPrimitiveEdgeType edgeType, const DashInfo& info, | 
| -                        SkScalar radius, const SkMatrix& localMatrix); | 
| +    DashingCircleEffect(GrColor, GrPrimitiveEdgeType edgeType, const SkMatrix& localMatrix); | 
|  | 
| bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE; | 
|  | 
| void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE; | 
|  | 
| GrPrimitiveEdgeType fEdgeType; | 
| -    const Attribute*  fInPosition; | 
| -    const Attribute*  fInCoord; | 
| -    SkScalar            fIntervalLength; | 
| -    SkScalar            fRadius; | 
| -    SkScalar            fCenterX; | 
| +    const Attribute*    fInPosition; | 
| +    const Attribute*    fInDashParams; | 
| +    const Attribute*    fInCircleParams; | 
|  | 
| GR_DECLARE_GEOMETRY_PROCESSOR_TEST; | 
|  | 
| @@ -566,21 +627,20 @@ void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { | 
| const DashingCircleEffect& dce = args.fGP.cast<DashingCircleEffect>(); | 
| const DashingCircleBatchTracker local = args.fBT.cast<DashingCircleBatchTracker>(); | 
| GrGLGPBuilder* pb = args.fPB; | 
| -    const char *paramName; | 
| -    // The param uniforms, xyz, refer to circle radius - 0.5, cicles center x coord, and | 
| -    // the total interval length of the dash. | 
| -    fParamUniform = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, | 
| -                                         kVec3f_GrSLType, kDefault_GrSLPrecision, | 
| -                                         "params", ¶mName); | 
| - | 
| GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); | 
|  | 
| // emit attributes | 
| vsBuilder->emitAttributes(dce); | 
|  | 
| -    GrGLVertToFrag v(kVec2f_GrSLType); | 
| -    args.fPB->addVarying("Coord", &v); | 
| -    vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dce.inCoord()->fName); | 
| +    // XY are dashPos, Z is dashInterval | 
| +    GrGLVertToFrag dashParams(kVec3f_GrSLType); | 
| +    args.fPB->addVarying("DashParam", &dashParams); | 
| +    vsBuilder->codeAppendf("%s = %s;", dashParams.vsOut(), dce.inDashParams()->fName); | 
| + | 
| +    // xy, refer to circle radius - 0.5, z refers to cicles center x coord | 
| +    GrGLVertToFrag circleParams(kVec2f_GrSLType); | 
| +    args.fPB->addVarying("CircleParams", &circleParams); | 
| +    vsBuilder->codeAppendf("%s = %s;", circleParams.vsOut(), dce.inCircleParams()->fName); | 
|  | 
| // Setup pass through color | 
| this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, &fColorUniform); | 
| @@ -597,18 +657,19 @@ void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { | 
|  | 
| // transforms all points so that we can compare them to our test circle | 
| GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); | 
| -    fsBuilder->codeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s.z) * %s.z;\n", | 
| -                           v.fsIn(), v.fsIn(), paramName, paramName); | 
| -    fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", v.fsIn()); | 
| -    fsBuilder->codeAppendf("\t\tvec2 center = vec2(%s.y, 0.0);\n", paramName); | 
| -    fsBuilder->codeAppend("\t\tfloat dist = length(center - fragPosShifted);\n"); | 
| +    fsBuilder->codeAppendf("float xShifted = %s.x - floor(%s.x / %s.z) * %s.z;", | 
| +                           dashParams.fsIn(), dashParams.fsIn(), dashParams.fsIn(), | 
| +                           dashParams.fsIn()); | 
| +    fsBuilder->codeAppendf("vec2 fragPosShifted = vec2(xShifted, %s.y);", dashParams.fsIn()); | 
| +    fsBuilder->codeAppendf("vec2 center = vec2(%s.y, 0.0);", circleParams.fsIn()); | 
| +    fsBuilder->codeAppend("float dist = length(center - fragPosShifted);"); | 
| if (GrProcessorEdgeTypeIsAA(dce.getEdgeType())) { | 
| -        fsBuilder->codeAppendf("\t\tfloat diff = dist - %s.x;\n", paramName); | 
| -        fsBuilder->codeAppend("\t\tdiff = 1.0 - diff;\n"); | 
| -        fsBuilder->codeAppend("\t\tfloat alpha = clamp(diff, 0.0, 1.0);\n"); | 
| +        fsBuilder->codeAppendf("float diff = dist - %s.x;", circleParams.fsIn()); | 
| +        fsBuilder->codeAppend("diff = 1.0 - diff;"); | 
| +        fsBuilder->codeAppend("float alpha = clamp(diff, 0.0, 1.0);"); | 
| } else { | 
| -        fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n"); | 
| -        fsBuilder->codeAppendf("\t\talpha *=  dist < %s.x + 0.5 ? 1.0 : 0.0;\n", paramName); | 
| +        fsBuilder->codeAppendf("float alpha = 1.0;"); | 
| +        fsBuilder->codeAppendf("alpha *=  dist < %s.x + 0.5 ? 1.0 : 0.0;", circleParams.fsIn()); | 
| } | 
| fsBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage); | 
| } | 
| @@ -618,17 +679,6 @@ void GLDashingCircleEffect::setData(const GrGLProgramDataManager& pdman, | 
| const GrBatchTracker& bt) { | 
| this->setUniformViewMatrix(pdman, processor.viewMatrix()); | 
|  | 
| -    const DashingCircleEffect& dce = processor.cast<DashingCircleEffect>(); | 
| -    SkScalar radius = dce.getRadius(); | 
| -    SkScalar centerX = dce.getCenterX(); | 
| -    SkScalar intervalLength = dce.getIntervalLength(); | 
| -    if (radius != fPrevRadius || centerX != fPrevCenterX || intervalLength != fPrevIntervalLength) { | 
| -        pdman.set3f(fParamUniform, radius - 0.5f, centerX, intervalLength); | 
| -        fPrevRadius = radius; | 
| -        fPrevCenterX = centerX; | 
| -        fPrevIntervalLength = intervalLength; | 
| -    } | 
| - | 
| const DashingCircleBatchTracker& local = bt.cast<DashingCircleBatchTracker>(); | 
| if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) { | 
| GrGLfloat c[4]; | 
| @@ -655,14 +705,8 @@ void GLDashingCircleEffect::GenKey(const GrGeometryProcessor& gp, | 
|  | 
| GrGeometryProcessor* DashingCircleEffect::Create(GrColor color, | 
| GrPrimitiveEdgeType edgeType, | 
| -                                                 const DashInfo& info, | 
| -                                                 SkScalar radius, | 
| const SkMatrix& localMatrix) { | 
| -    if (info.fCount != 2 || info.fIntervals[0] != 0) { | 
| -        return NULL; | 
| -    } | 
| - | 
| -    return SkNEW_ARGS(DashingCircleEffect, (color, edgeType, info, radius, localMatrix)); | 
| +    return SkNEW_ARGS(DashingCircleEffect, (color, edgeType, localMatrix)); | 
| } | 
|  | 
| DashingCircleEffect::~DashingCircleEffect() {} | 
| @@ -684,26 +728,18 @@ GrGLPrimitiveProcessor* DashingCircleEffect::createGLInstance(const GrBatchTrack | 
|  | 
| DashingCircleEffect::DashingCircleEffect(GrColor color, | 
| GrPrimitiveEdgeType edgeType, | 
| -                                         const DashInfo& info, | 
| -                                         SkScalar radius, | 
| const SkMatrix& localMatrix) | 
| : INHERITED(color, SkMatrix::I(), localMatrix), fEdgeType(edgeType) { | 
| this->initClassID<DashingCircleEffect>(); | 
| fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType)); | 
| -    fInCoord = &this->addVertexAttrib(Attribute("inCoord", kVec2f_GrVertexAttribType)); | 
| -    SkScalar onLen = info.fIntervals[0]; | 
| -    SkScalar offLen = info.fIntervals[1]; | 
| -    fIntervalLength = onLen + offLen; | 
| -    fRadius = radius; | 
| -    fCenterX = SkScalarHalf(offLen); | 
| +    fInDashParams = &this->addVertexAttrib(Attribute("inDashParams", kVec3f_GrVertexAttribType)); | 
| +    fInCircleParams = &this->addVertexAttrib(Attribute("inCircleParams", | 
| +                                                       kVec2f_GrVertexAttribType)); | 
| } | 
|  | 
| bool DashingCircleEffect::onIsEqual(const GrGeometryProcessor& other) const { | 
| const DashingCircleEffect& dce = other.cast<DashingCircleEffect>(); | 
| -    return (fEdgeType == dce.fEdgeType && | 
| -            fIntervalLength == dce.fIntervalLength && | 
| -            fRadius == dce.fRadius && | 
| -            fCenterX == dce.fCenterX); | 
| +    return fEdgeType == dce.fEdgeType; | 
| } | 
|  | 
| void DashingCircleEffect::initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const { | 
| @@ -731,18 +767,8 @@ GrGeometryProcessor* DashingCircleEffect::TestCreate(SkRandom* random, | 
| GrTexture*[]) { | 
| GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(random->nextULessThan( | 
| kGrProcessorEdgeTypeCnt)); | 
| -    SkScalar strokeWidth = random->nextRangeScalar(0, 100.f); | 
| -    DashInfo info; | 
| -    info.fCount = 2; | 
| -    SkAutoTArray<SkScalar> intervals(info.fCount); | 
| -    info.fIntervals = intervals.get(); | 
| -    info.fIntervals[0] = 0; | 
| -    info.fIntervals[1] = random->nextRangeScalar(0, 10.f); | 
| -    info.fPhase = random->nextRangeScalar(0, info.fIntervals[1]); | 
| - | 
| return DashingCircleEffect::Create(GrRandomColor(random), | 
| -                                       edgeType, info, strokeWidth, | 
| -                                       GrProcessorUnitTest::TestMatrix(random)); | 
| +                                       edgeType, GrProcessorUnitTest::TestMatrix(random)); | 
| } | 
|  | 
| ////////////////////////////////////////////////////////////////////////////// | 
| @@ -770,8 +796,6 @@ public: | 
|  | 
| static GrGeometryProcessor* Create(GrColor, | 
| GrPrimitiveEdgeType edgeType, | 
| -                                       const DashInfo& info, | 
| -                                       SkScalar strokeWidth, | 
| const SkMatrix& localMatrix); | 
|  | 
| virtual ~DashingLineEffect(); | 
| @@ -780,13 +804,11 @@ public: | 
|  | 
| const Attribute* inPosition() const { return fInPosition; } | 
|  | 
| -    const Attribute* inCoord() const { return fInCoord; } | 
| - | 
| -    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } | 
| +    const Attribute* inDashParams() const { return fInDashParams; } | 
|  | 
| -    const SkRect& getRect() const { return fRect; } | 
| +    const Attribute* inRectParams() const { return fInRectParams; } | 
|  | 
| -    SkScalar getIntervalLength() const { return fIntervalLength; } | 
| +    GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } | 
|  | 
| virtual void getGLProcessorKey(const GrBatchTracker& bt, | 
| const GrGLCaps& caps, | 
| @@ -802,18 +824,16 @@ public: | 
| const GrBatchTracker&) const SK_OVERRIDE; | 
|  | 
| private: | 
| -    DashingLineEffect(GrColor, GrPrimitiveEdgeType edgeType, const DashInfo& info, | 
| -                      SkScalar strokeWidth, const SkMatrix& localMatrix); | 
| +    DashingLineEffect(GrColor, GrPrimitiveEdgeType edgeType, const SkMatrix& localMatrix); | 
|  | 
| bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE; | 
|  | 
| void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE; | 
|  | 
| GrPrimitiveEdgeType fEdgeType; | 
| -    const Attribute*  fInPosition; | 
| -    const Attribute*  fInCoord; | 
| -    SkRect              fRect; | 
| -    SkScalar            fIntervalLength; | 
| +    const Attribute*    fInPosition; | 
| +    const Attribute*    fInDashParams; | 
| +    const Attribute*    fInRectParams; | 
|  | 
| GR_DECLARE_GEOMETRY_PROCESSOR_TEST; | 
|  | 
| @@ -839,48 +859,35 @@ public: | 
|  | 
| private: | 
| GrColor       fColor; | 
| -    UniformHandle fRectUniform; | 
| -    UniformHandle fIntervalUniform; | 
| UniformHandle fColorUniform; | 
| -    SkRect        fPrevRect; | 
| -    SkScalar      fPrevIntervalLength; | 
| typedef GrGLGeometryProcessor INHERITED; | 
| }; | 
|  | 
| GLDashingLineEffect::GLDashingLineEffect(const GrGeometryProcessor&, | 
| const GrBatchTracker&) { | 
| fColor = GrColor_ILLEGAL; | 
| -    fPrevRect.fLeft = SK_ScalarNaN; | 
| -    fPrevIntervalLength = SK_ScalarMax; | 
| } | 
|  | 
| void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { | 
| const DashingLineEffect& de = args.fGP.cast<DashingLineEffect>(); | 
| const DashingLineBatchTracker& local = args.fBT.cast<DashingLineBatchTracker>(); | 
| GrGLGPBuilder* pb = args.fPB; | 
| -    const char *rectName; | 
| -    // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5), | 
| -    // respectively. | 
| -    fRectUniform = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, | 
| -                                       kVec4f_GrSLType, kDefault_GrSLPrecision, | 
| -                                       "rect", | 
| -                                       &rectName); | 
| -    const char *intervalName; | 
| -    // The interval uniform's refers to the total length of the interval (on + off) | 
| -    fIntervalUniform = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, | 
| -                                            kFloat_GrSLType, kDefault_GrSLPrecision, | 
| -                                            "interval", | 
| -                                            &intervalName); | 
| - | 
|  | 
| GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); | 
|  | 
| // emit attributes | 
| vsBuilder->emitAttributes(de); | 
|  | 
| -    GrGLVertToFrag v(kVec2f_GrSLType); | 
| -    args.fPB->addVarying("Coord", &v); | 
| -    vsBuilder->codeAppendf("%s = %s;", v.vsOut(), de.inCoord()->fName); | 
| +    // XY refers to dashPos, Z is the dash interval length | 
| +    GrGLVertToFrag inDashParams(kVec3f_GrSLType); | 
| +    args.fPB->addVarying("DashParams", &inDashParams); | 
| +    vsBuilder->codeAppendf("%s = %s;", inDashParams.vsOut(), de.inDashParams()->fName); | 
| + | 
| +    // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5), | 
| +    // respectively. | 
| +    GrGLVertToFrag inRectParams(kVec4f_GrSLType); | 
| +    args.fPB->addVarying("RectParams", &inRectParams); | 
| +    vsBuilder->codeAppendf("%s = %s;", inRectParams.vsOut(), de.inRectParams()->fName); | 
|  | 
| // Setup pass through color | 
| this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, &fColorUniform); | 
| @@ -897,25 +904,28 @@ void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { | 
|  | 
| // transforms all points so that we can compare them to our test rect | 
| GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); | 
| -    fsBuilder->codeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s) * %s;\n", | 
| -                           v.fsIn(), v.fsIn(), intervalName, intervalName); | 
| -    fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", v.fsIn()); | 
| +    fsBuilder->codeAppendf("float xShifted = %s.x - floor(%s.x / %s.z) * %s.z;", | 
| +                           inDashParams.fsIn(), inDashParams.fsIn(), inDashParams.fsIn(), | 
| +                           inDashParams.fsIn()); | 
| +    fsBuilder->codeAppendf("vec2 fragPosShifted = vec2(xShifted, %s.y);", inDashParams.fsIn()); | 
| if (GrProcessorEdgeTypeIsAA(de.getEdgeType())) { | 
| // The amount of coverage removed in x and y by the edges is computed as a pair of negative | 
| // numbers, xSub and ySub. | 
| -        fsBuilder->codeAppend("\t\tfloat xSub, ySub;\n"); | 
| -        fsBuilder->codeAppendf("\t\txSub = min(fragPosShifted.x - %s.x, 0.0);\n", rectName); | 
| -        fsBuilder->codeAppendf("\t\txSub += min(%s.z - fragPosShifted.x, 0.0);\n", rectName); | 
| -        fsBuilder->codeAppendf("\t\tySub = min(fragPosShifted.y - %s.y, 0.0);\n", rectName); | 
| -        fsBuilder->codeAppendf("\t\tySub += min(%s.w - fragPosShifted.y, 0.0);\n", rectName); | 
| +        fsBuilder->codeAppend("float xSub, ySub;"); | 
| +        fsBuilder->codeAppendf("xSub = min(fragPosShifted.x - %s.x, 0.0);", inRectParams.fsIn()); | 
| +        fsBuilder->codeAppendf("xSub += min(%s.z - fragPosShifted.x, 0.0);", inRectParams.fsIn()); | 
| +        fsBuilder->codeAppendf("ySub = min(fragPosShifted.y - %s.y, 0.0);", inRectParams.fsIn()); | 
| +        fsBuilder->codeAppendf("ySub += min(%s.w - fragPosShifted.y, 0.0);", inRectParams.fsIn()); | 
| // Now compute coverage in x and y and multiply them to get the fraction of the pixel | 
| // covered. | 
| -        fsBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n"); | 
| +        fsBuilder->codeAppendf("float alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));"); | 
| } else { | 
| // Assuming the bounding geometry is tight so no need to check y values | 
| -        fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n"); | 
| -        fsBuilder->codeAppendf("\t\talpha *= (fragPosShifted.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName); | 
| -        fsBuilder->codeAppendf("\t\talpha *= (%s.z - fragPosShifted.x) >= -0.5 ? 1.0 : 0.0;\n", rectName); | 
| +        fsBuilder->codeAppendf("float alpha = 1.0;"); | 
| +        fsBuilder->codeAppendf("alpha *= (fragPosShifted.x - %s.x) > -0.5 ? 1.0 : 0.0;", | 
| +                               inRectParams.fsIn()); | 
| +        fsBuilder->codeAppendf("alpha *= (%s.z - fragPosShifted.x) >= -0.5 ? 1.0 : 0.0;", | 
| +                               inRectParams.fsIn()); | 
| } | 
| fsBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage); | 
| } | 
| @@ -925,17 +935,6 @@ void GLDashingLineEffect::setData(const GrGLProgramDataManager& pdman, | 
| const GrBatchTracker& bt) { | 
| this->setUniformViewMatrix(pdman, processor.viewMatrix()); | 
|  | 
| -    const DashingLineEffect& de = processor.cast<DashingLineEffect>(); | 
| -    const SkRect& rect = de.getRect(); | 
| -    SkScalar intervalLength = de.getIntervalLength(); | 
| -    if (rect != fPrevRect || intervalLength != fPrevIntervalLength) { | 
| -        pdman.set4f(fRectUniform, rect.fLeft + 0.5f, rect.fTop + 0.5f, | 
| -                    rect.fRight - 0.5f, rect.fBottom - 0.5f); | 
| -        pdman.set1f(fIntervalUniform, intervalLength); | 
| -        fPrevRect = rect; | 
| -        fPrevIntervalLength = intervalLength; | 
| -    } | 
| - | 
| const DashingLineBatchTracker& local = bt.cast<DashingLineBatchTracker>(); | 
| if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) { | 
| GrGLfloat c[4]; | 
| @@ -962,14 +961,8 @@ void GLDashingLineEffect::GenKey(const GrGeometryProcessor& gp, | 
|  | 
| GrGeometryProcessor* DashingLineEffect::Create(GrColor color, | 
| GrPrimitiveEdgeType edgeType, | 
| -                                               const DashInfo& info, | 
| -                                               SkScalar strokeWidth, | 
| const SkMatrix& localMatrix) { | 
| -    if (info.fCount != 2) { | 
| -        return NULL; | 
| -    } | 
| - | 
| -    return SkNEW_ARGS(DashingLineEffect, (color, edgeType, info, strokeWidth, localMatrix)); | 
| +    return SkNEW_ARGS(DashingLineEffect, (color, edgeType, localMatrix)); | 
| } | 
|  | 
| DashingLineEffect::~DashingLineEffect() {} | 
| @@ -991,26 +984,17 @@ GrGLPrimitiveProcessor* DashingLineEffect::createGLInstance(const GrBatchTracker | 
|  | 
| DashingLineEffect::DashingLineEffect(GrColor color, | 
| GrPrimitiveEdgeType edgeType, | 
| -                                     const DashInfo& info, | 
| -                                     SkScalar strokeWidth, | 
| const SkMatrix& localMatrix) | 
| : INHERITED(color, SkMatrix::I(), localMatrix), fEdgeType(edgeType) { | 
| this->initClassID<DashingLineEffect>(); | 
| fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType)); | 
| -    fInCoord = &this->addVertexAttrib(Attribute("inCoord", kVec2f_GrVertexAttribType)); | 
| -    SkScalar onLen = info.fIntervals[0]; | 
| -    SkScalar offLen = info.fIntervals[1]; | 
| -    SkScalar halfOffLen = SkScalarHalf(offLen); | 
| -    SkScalar halfStroke = SkScalarHalf(strokeWidth); | 
| -    fIntervalLength = onLen + offLen; | 
| -    fRect.set(halfOffLen, -halfStroke, halfOffLen + onLen, halfStroke); | 
| +    fInDashParams = &this->addVertexAttrib(Attribute("inDashParams", kVec3f_GrVertexAttribType)); | 
| +    fInRectParams = &this->addVertexAttrib(Attribute("inRect", kVec4f_GrVertexAttribType)); | 
| } | 
|  | 
| bool DashingLineEffect::onIsEqual(const GrGeometryProcessor& other) const { | 
| const DashingLineEffect& de = other.cast<DashingLineEffect>(); | 
| -    return (fEdgeType == de.fEdgeType && | 
| -            fRect == de.fRect && | 
| -            fIntervalLength == de.fIntervalLength); | 
| +    return fEdgeType == de.fEdgeType; | 
| } | 
|  | 
| void DashingLineEffect::initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const { | 
| @@ -1038,35 +1022,22 @@ GrGeometryProcessor* DashingLineEffect::TestCreate(SkRandom* random, | 
| GrTexture*[]) { | 
| GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(random->nextULessThan( | 
| kGrProcessorEdgeTypeCnt)); | 
| -    SkScalar strokeWidth = random->nextRangeScalar(0, 100.f); | 
| -    DashInfo info; | 
| -    info.fCount = 2; | 
| -    SkAutoTArray<SkScalar> intervals(info.fCount); | 
| -    info.fIntervals = intervals.get(); | 
| -    info.fIntervals[0] = random->nextRangeScalar(0, 10.f); | 
| -    info.fIntervals[1] = random->nextRangeScalar(0, 10.f); | 
| -    info.fPhase = random->nextRangeScalar(0, info.fIntervals[0] + info.fIntervals[1]); | 
|  | 
| return DashingLineEffect::Create(GrRandomColor(random), | 
| -                                     edgeType, info, strokeWidth, | 
| -                                     GrProcessorUnitTest::TestMatrix(random)); | 
| +                                     edgeType, GrProcessorUnitTest::TestMatrix(random)); | 
| } | 
|  | 
| ////////////////////////////////////////////////////////////////////////////// | 
|  | 
| -GrGeometryProcessor* GrDashingEffect::Create(GrColor color, | 
| -                                             GrPrimitiveEdgeType edgeType, | 
| -                                             const SkPathEffect::DashInfo& info, | 
| -                                             SkScalar strokeWidth, | 
| -                                             GrDashingEffect::DashCap cap, | 
| -                                             const SkMatrix& localMatrix) { | 
| +static GrGeometryProcessor* create_dash_gp(GrColor color, | 
| +                                           GrPrimitiveEdgeType edgeType, | 
| +                                           DashCap cap, | 
| +                                           const SkMatrix& localMatrix) { | 
| switch (cap) { | 
| -        case GrDashingEffect::kRound_DashCap: | 
| -            return DashingCircleEffect::Create(color, edgeType, info, | 
| -                                               SkScalarHalf(strokeWidth), | 
| -                                               localMatrix); | 
| -        case GrDashingEffect::kNonRound_DashCap: | 
| -            return DashingLineEffect::Create(color, edgeType, info, strokeWidth, localMatrix); | 
| +        case kRound_DashCap: | 
| +            return DashingCircleEffect::Create(color, edgeType, localMatrix); | 
| +        case kNonRound_DashCap: | 
| +            return DashingLineEffect::Create(color, edgeType, localMatrix); | 
| default: | 
| SkFAIL("Unexpected dashed cap."); | 
| } | 
|  |