/* 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();
}