void SkStroke::strokePath(const SkPath& src, SkPath* dst) const { SkASSERT(&src != NULL && dst != NULL); SkScalar radius = SkScalarHalf(fWidth); dst->reset(); if (radius <= 0) { return; } #ifdef SK_SCALAR_IS_FIXED void (*proc)(SkPoint pts[], int count) = identity_proc; if (needs_to_shrink(src)) { proc = shift_down_2_proc; radius >>= 2; if (radius == 0) { return; } } #endif SkPathStroker stroker(radius, fMiterLimit, this->getCap(), this->getJoin()); SkPath::Iter iter(src, false); SkPoint pts[4]; SkPath::Verb verb, lastSegment = SkPath::kMove_Verb; while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { switch (verb) { case SkPath::kMove_Verb: APPLY_PROC(proc, &pts[0], 1); stroker.moveTo(pts[0]); break; case SkPath::kLine_Verb: APPLY_PROC(proc, &pts[1], 1); stroker.lineTo(pts[1]); lastSegment = verb; break; case SkPath::kQuad_Verb: APPLY_PROC(proc, &pts[1], 2); stroker.quadTo(pts[1], pts[2]); lastSegment = verb; break; case SkPath::kCubic_Verb: APPLY_PROC(proc, &pts[1], 3); stroker.cubicTo(pts[1], pts[2], pts[3]); lastSegment = verb; break; case SkPath::kClose_Verb: stroker.close(lastSegment == SkPath::kLine_Verb); break; default: break; } } stroker.done(dst, lastSegment == SkPath::kLine_Verb); #ifdef SK_SCALAR_IS_FIXED // undo our previous down_shift if (shift_down_2_proc == proc) { // need a real shift methid on path. antialias paths could use this too SkMatrix matrix; matrix.setScale(SkIntToScalar(4), SkIntToScalar(4)); dst->transform(matrix); } #endif if (fDoFill) { if (src.cheapIsDirection(SkPath::kCCW_Direction)) { dst->reverseAddPath(src); } else { dst->addPath(src); } } else { // Seems like we can assume that a 2-point src would always result in // a convex stroke, but testing has proved otherwise. // TODO: fix the stroker to make this assumption true (without making // it slower that the work that will be done in computeConvexity()) #if 0 // this test results in a non-convex stroke :( static void test(SkCanvas* canvas) { SkPoint pts[] = { 146.333328, 192.333328, 300.333344, 293.333344 }; SkPaint paint; paint.setStrokeWidth(7); paint.setStrokeCap(SkPaint::kRound_Cap); canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint); } #endif #if 0 if (2 == src.countPoints()) { dst->setIsConvex(true); } #endif }
void SkStroke::strokePath(const SkPath& src, SkPath* dst) const { SkASSERT(&src != NULL && dst != NULL); SkScalar radius = SkScalarHalf(fWidth); AutoTmpPath tmp(src, &dst); if (radius <= 0) { return; } // If src is really a rect, call our specialty strokeRect() method { bool isClosed; SkPath::Direction dir; if (src.isRect(&isClosed, &dir) && isClosed) { this->strokeRect(src.getBounds(), dst, dir); // our answer should preserve the inverseness of the src if (src.isInverseFillType()) { SkASSERT(!dst->isInverseFillType()); dst->toggleInverseFillType(); } return; } } SkAutoConicToQuads converter; const SkScalar conicTol = SK_Scalar1 / 4; SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJoin()); SkPath::Iter iter(src, false); SkPath::Verb lastSegment = SkPath::kMove_Verb; for (;;) { SkPoint pts[4]; switch (iter.next(pts, false)) { case SkPath::kMove_Verb: stroker.moveTo(pts[0]); break; case SkPath::kLine_Verb: stroker.lineTo(pts[1]); lastSegment = SkPath::kLine_Verb; break; case SkPath::kQuad_Verb: stroker.quadTo(pts[1], pts[2]); lastSegment = SkPath::kQuad_Verb; break; case SkPath::kConic_Verb: { // todo: if we had maxcurvature for conics, perhaps we should // natively extrude the conic instead of converting to quads. const SkPoint* quadPts = converter.computeQuads(pts, iter.conicWeight(), conicTol); for (int i = 0; i < converter.countQuads(); ++i) { stroker.quadTo(quadPts[1], quadPts[2]); quadPts += 2; } lastSegment = SkPath::kQuad_Verb; } break; case SkPath::kCubic_Verb: stroker.cubicTo(pts[1], pts[2], pts[3]); lastSegment = SkPath::kCubic_Verb; break; case SkPath::kClose_Verb: stroker.close(lastSegment == SkPath::kLine_Verb); break; case SkPath::kDone_Verb: goto DONE; } } DONE: stroker.done(dst, lastSegment == SkPath::kLine_Verb); if (fDoFill) { if (src.cheapIsDirection(SkPath::kCCW_Direction)) { dst->reverseAddPath(src); } else { dst->addPath(src); } } else { // Seems like we can assume that a 2-point src would always result in // a convex stroke, but testing has proved otherwise. // TODO: fix the stroker to make this assumption true (without making // it slower that the work that will be done in computeConvexity()) #if 0 // this test results in a non-convex stroke :( static void test(SkCanvas* canvas) { SkPoint pts[] = { 146.333328, 192.333328, 300.333344, 293.333344 }; SkPaint paint; paint.setStrokeWidth(7); paint.setStrokeCap(SkPaint::kRound_Cap); canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint); } #endif #if 0 if (2 == src.countPoints()) { dst->setIsConvex(true); } #endif }