michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkCornerPathEffect.h" michael@0: #include "SkPath.h" michael@0: #include "SkPoint.h" michael@0: #include "SkReadBuffer.h" michael@0: #include "SkWriteBuffer.h" michael@0: michael@0: SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {} michael@0: SkCornerPathEffect::~SkCornerPathEffect() {} michael@0: michael@0: static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, michael@0: SkPoint* step) { michael@0: SkScalar dist = SkPoint::Distance(a, b); michael@0: michael@0: step->set(b.fX - a.fX, b.fY - a.fY); michael@0: michael@0: if (dist <= radius * 2) { michael@0: step->scale(SK_ScalarHalf); michael@0: return false; michael@0: } else { michael@0: step->scale(SkScalarDiv(radius, dist)); michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, michael@0: SkStrokeRec*, const SkRect*) const { michael@0: if (0 == fRadius) { michael@0: return false; michael@0: } michael@0: michael@0: SkPath::Iter iter(src, false); michael@0: SkPath::Verb verb, prevVerb = (SkPath::Verb)-1; michael@0: SkPoint pts[4]; michael@0: michael@0: bool closed; michael@0: SkPoint moveTo, lastCorner; michael@0: SkVector firstStep, step; michael@0: bool prevIsValid = true; michael@0: michael@0: // to avoid warnings michael@0: moveTo.set(0, 0); michael@0: firstStep.set(0, 0); michael@0: lastCorner.set(0, 0); michael@0: michael@0: for (;;) { michael@0: switch (verb = iter.next(pts, false)) { michael@0: case SkPath::kMove_Verb: michael@0: // close out the previous (open) contour michael@0: if (SkPath::kLine_Verb == prevVerb) { michael@0: dst->lineTo(lastCorner); michael@0: } michael@0: closed = iter.isClosedContour(); michael@0: if (closed) { michael@0: moveTo = pts[0]; michael@0: prevIsValid = false; michael@0: } else { michael@0: dst->moveTo(pts[0]); michael@0: prevIsValid = true; michael@0: } michael@0: break; michael@0: case SkPath::kLine_Verb: { michael@0: bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step); michael@0: // prev corner michael@0: if (!prevIsValid) { michael@0: dst->moveTo(moveTo + step); michael@0: prevIsValid = true; michael@0: } else { michael@0: dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, michael@0: pts[0].fY + step.fY); michael@0: } michael@0: if (drawSegment) { michael@0: dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY); michael@0: } michael@0: lastCorner = pts[1]; michael@0: prevIsValid = true; michael@0: break; michael@0: } michael@0: case SkPath::kQuad_Verb: michael@0: // TBD - just replicate the curve for now michael@0: if (!prevIsValid) { michael@0: dst->moveTo(pts[0]); michael@0: prevIsValid = true; michael@0: } michael@0: dst->quadTo(pts[1], pts[2]); michael@0: lastCorner = pts[2]; michael@0: firstStep.set(0, 0); michael@0: break; michael@0: case SkPath::kCubic_Verb: michael@0: if (!prevIsValid) { michael@0: dst->moveTo(pts[0]); michael@0: prevIsValid = true; michael@0: } michael@0: // TBD - just replicate the curve for now michael@0: dst->cubicTo(pts[1], pts[2], pts[3]); michael@0: lastCorner = pts[3]; michael@0: firstStep.set(0, 0); michael@0: break; michael@0: case SkPath::kClose_Verb: michael@0: if (firstStep.fX || firstStep.fY) { michael@0: dst->quadTo(lastCorner.fX, lastCorner.fY, michael@0: lastCorner.fX + firstStep.fX, michael@0: lastCorner.fY + firstStep.fY); michael@0: } michael@0: dst->close(); michael@0: break; michael@0: case SkPath::kConic_Verb: michael@0: SkASSERT(0); michael@0: break; michael@0: case SkPath::kDone_Verb: michael@0: goto DONE; michael@0: } michael@0: michael@0: if (SkPath::kMove_Verb == prevVerb) { michael@0: firstStep = step; michael@0: } michael@0: prevVerb = verb; michael@0: } michael@0: DONE: michael@0: return true; michael@0: } michael@0: michael@0: void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const { michael@0: this->INHERITED::flatten(buffer); michael@0: buffer.writeScalar(fRadius); michael@0: } michael@0: michael@0: SkCornerPathEffect::SkCornerPathEffect(SkReadBuffer& buffer) { michael@0: fRadius = buffer.readScalar(); michael@0: }