diff options
Diffstat (limited to 'src/effects/SkCornerPathEffect.cpp')
-rw-r--r-- | src/effects/SkCornerPathEffect.cpp | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/effects/SkCornerPathEffect.cpp b/src/effects/SkCornerPathEffect.cpp new file mode 100644 index 0000000..43d571a --- /dev/null +++ b/src/effects/SkCornerPathEffect.cpp @@ -0,0 +1,157 @@ +/* libs/graphics/effects/SkCornerPathEffect.cpp +** +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include "SkCornerPathEffect.h" +#include "SkPath.h" +#include "SkPoint.h" +#include "SkBuffer.h" + +SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) +{ +} + +SkCornerPathEffect::~SkCornerPathEffect() +{ +} + +static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, SkPoint* step) +{ + SkScalar dist = SkPoint::Distance(a, b); + + step->set(b.fX - a.fX, b.fY - a.fY); + + if (dist <= radius * 2) { + step->scale(SK_ScalarHalf); + return false; + } + else { + step->scale(SkScalarDiv(radius, dist)); + return true; + } +} + +bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) +{ + if (fRadius == 0) + return false; + + SkPath::Iter iter(src, false); + SkPath::Verb verb, prevVerb = (SkPath::Verb)-1; + SkPoint pts[4]; + + bool closed; + SkPoint moveTo, lastCorner; + SkVector firstStep, step; + bool prevIsValid = true; + + // to avoid warnings + moveTo.set(0, 0); + firstStep.set(0, 0); + lastCorner.set(0, 0); + + for (;;) { + switch (verb = iter.next(pts)) { + case SkPath::kMove_Verb: + closed = iter.isClosedContour(); + if (closed) { + moveTo = pts[0]; + prevIsValid = false; + } + else { + dst->moveTo(pts[0]); + prevIsValid = true; + } + break; + case SkPath::kLine_Verb: + { + bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step); + // prev corner + if (!prevIsValid) { + dst->moveTo(moveTo + step); + prevIsValid = true; + } + else { + dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, pts[0].fY + step.fY); + } + if (drawSegment) { + dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY); + } + lastCorner = pts[1]; + prevIsValid = true; + } + break; + case SkPath::kQuad_Verb: + // TBD - just replicate the curve for now + if (!prevIsValid) + { + dst->moveTo(pts[0]); + prevIsValid = true; + } + dst->quadTo(pts[1], pts[2]); + lastCorner = pts[2]; + firstStep.set(0, 0); + break; + case SkPath::kCubic_Verb: + if (!prevIsValid) + { + dst->moveTo(pts[0]); + prevIsValid = true; + } + // TBD - just replicate the curve for now + dst->cubicTo(pts[1], pts[2], pts[3]); + lastCorner = pts[3]; + firstStep.set(0, 0); + break; + case SkPath::kClose_Verb: + if (firstStep.fX || firstStep.fY) + dst->quadTo(lastCorner.fX, lastCorner.fY, + lastCorner.fX + firstStep.fX, + lastCorner.fY + firstStep.fY); + dst->close(); + break; + case SkPath::kDone_Verb: + goto DONE; + } + + if (SkPath::kMove_Verb == prevVerb) + firstStep = step; + prevVerb = verb; + } +DONE: + return true; +} + +SkFlattenable::Factory SkCornerPathEffect::getFactory() +{ + return CreateProc; +} + +void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) +{ + buffer.writeScalar(fRadius); +} + +SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) +{ + return SkNEW_ARGS(SkCornerPathEffect, (buffer)); +} + +SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) +{ + fRadius = buffer.readScalar(); +} + |