diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-05-29 20:48:50 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-05-29 20:48:50 +0000 |
commit | 3ec68f047a1f698bec12e1a270fdf4f62aed9cdb (patch) | |
tree | e1d60873f5b5f4cc88dd07c6abb0f27970e0be40 /src/effects | |
parent | 744fabad474e3e111e7cbd8609cf7e209df17f32 (diff) |
special-case dashing a single line-segment. We can go much faster since we
can apply the stroke as we go, eliminating the generic stroker.
Review URL: https://codereview.appspot.com/6250070
git-svn-id: http://skia.googlecode.com/svn/trunk@4062 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/effects')
-rw-r--r-- | src/effects/SkDashPathEffect.cpp | 81 |
1 files changed, 79 insertions, 2 deletions
diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp index 13c19afab4..e6f6afaf07 100644 --- a/src/effects/SkDashPathEffect.cpp +++ b/src/effects/SkDashPathEffect.cpp @@ -80,6 +80,73 @@ SkDashPathEffect::~SkDashPathEffect() { sk_free(fIntervals); } +class SpecialLineRec { +public: + bool init(const SkPath& src, SkPath* dst, SkStrokeRec* rec, + SkScalar pathLength, + int intervalCount, SkScalar intervalLength) { + if (rec->isHairlineStyle() || !src.isLine(fPts)) { + return false; + } + + // can relax this in the future, if we handle square and round caps + if (SkPaint::kButt_Cap != rec->getCap()) { + return false; + } + + fTangent = fPts[1] - fPts[0]; + if (fTangent.isZero()) { + return false; + } + + fPathLength = pathLength; + fTangent.scale(SkScalarInvert(pathLength)); + fTangent.rotateCCW(&fNormal); + fNormal.scale(SkScalarHalf(rec->getWidth())); + + // now estimate how many quads will be added to the path + // resulting segments = pathLen * intervalCount / intervalLen + // resulting points = 4 * segments + + SkScalar ptCount = SkScalarMulDiv(pathLength, + SkIntToScalar(intervalCount), + intervalLength); + int n = SkScalarCeilToInt(ptCount) << 2; + dst->incReserve(n); + + // we will take care of the stroking + rec->setFillStyle(); + return true; + } + + void addSegment(SkScalar d0, SkScalar d1, SkPath* path) const { + SkASSERT(d0 < fPathLength); + // clamp the segment to our length + if (d1 > fPathLength) { + d1 = fPathLength; + } + + SkScalar x0 = fPts[0].fX + SkScalarMul(fTangent.fX, d0); + SkScalar x1 = fPts[0].fX + SkScalarMul(fTangent.fX, d1); + SkScalar y0 = fPts[0].fY + SkScalarMul(fTangent.fY, d0); + SkScalar y1 = fPts[0].fY + SkScalarMul(fTangent.fY, d1); + + SkPoint pts[4]; + pts[0].set(x0 + fNormal.fX, y0 + fNormal.fY); // moveTo + pts[1].set(x1 + fNormal.fX, y1 + fNormal.fY); // lineTo + pts[2].set(x1 - fNormal.fX, y1 - fNormal.fY); // lineTo + pts[3].set(x0 - fNormal.fX, y0 - fNormal.fY); // lineTo + + path->addPoly(pts, SK_ARRAY_COUNT(pts), false); + } + +private: + SkPoint fPts[2]; + SkVector fTangent; + SkVector fNormal; + SkScalar fPathLength; +}; + bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec) { // we do nothing if the src wants to be filled, or if our dashlength is 0 @@ -90,13 +157,17 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, SkPathMeasure meas(src, false); const SkScalar* intervals = fIntervals; + SpecialLineRec lineRec; + const bool specialLine = lineRec.init(src, dst, rec, meas.getLength(), + fCount >> 1, fIntervalLength); + do { bool skipFirstSegment = meas.isClosed(); bool addedSegment = false; SkScalar length = meas.getLength(); int index = fInitialDashIndex; SkScalar scale = SK_Scalar1; - + if (fScaleToFit) { if (fIntervalLength >= length) { scale = SkScalarDiv(length, fIntervalLength); @@ -115,7 +186,12 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, addedSegment = false; if (is_even(index) && dlen > 0 && !skipFirstSegment) { addedSegment = true; - meas.getSegment(distance, distance + dlen, dst, true); + + if (specialLine) { + lineRec.addSegment(distance, distance + dlen, dst); + } else { + meas.getSegment(distance, distance + dlen, dst, true); + } } distance += dlen; @@ -139,6 +215,7 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, meas.getSegment(0, SkScalarMul(fInitialDashLength, scale), dst, !addedSegment); } } while (meas.nextContour()); + return true; } |