/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Sk2DPathEffect.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
#include "SkPath.h"
#include "SkRegion.h"
#include "SkStrokeRec.h"
Sk2DPathEffect::Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
// Calling invert will set the type mask on both matrices, making them thread safe.
fMatrixIsInvertible = fMatrix.invert(&fInverse);
}
bool Sk2DPathEffect::onFilterPath(SkPath* dst, const SkPath& src,
SkStrokeRec*, const SkRect*) const {
if (!fMatrixIsInvertible) {
return false;
}
SkPath tmp;
SkIRect ir;
src.transform(fInverse, &tmp);
tmp.getBounds().round(&ir);
if (!ir.isEmpty()) {
this->begin(ir, dst);
SkRegion rgn;
rgn.setPath(tmp, SkRegion(ir));
SkRegion::Iterator iter(rgn);
for (; !iter.done(); iter.next()) {
const SkIRect& rect = iter.rect();
for (int y = rect.fTop; y < rect.fBottom; ++y) {
this->nextSpan(rect.fLeft, y, rect.width(), dst);
}
}
this->end(dst);
}
return true;
}
void Sk2DPathEffect::nextSpan(int x, int y, int count, SkPath* path) const {
if (!fMatrixIsInvertible) {
return;
}
const SkMatrix& mat = this->getMatrix();
SkPoint src, dst;
src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
do {
mat.mapPoints(&dst, &src, 1);
this->next(dst, x++, y, path);
src.fX += SK_Scalar1;
} while (--count > 0);
}
void Sk2DPathEffect::begin(const SkIRect& uvBounds, SkPath* dst) const {}
void Sk2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) const {}
void Sk2DPathEffect::end(SkPath* dst) const {}
///////////////////////////////////////////////////////////////////////////////
void Sk2DPathEffect::flatten(SkWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
buffer.writeMatrix(fMatrix);
}
///////////////////////////////////////////////////////////////////////////////
bool SkLine2DPathEffect::onFilterPath(SkPath* dst, const SkPath& src,
SkStrokeRec* rec, const SkRect* cullRect) const {
if (this->INHERITED::onFilterPath(dst, src, rec, cullRect)) {
rec->setStrokeStyle(fWidth);
return true;
}
return false;
}
void SkLine2DPathEffect::nextSpan(int u, int v, int ucount, SkPath* dst) const {
if (ucount > 1) {
SkPoint src[2], dstP[2];
src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
this->getMatrix().mapPoints(dstP, src, 2);
dst->moveTo(dstP[0]);
dst->lineTo(dstP[1]);
}
}
sk_sp<SkFlattenable> SkLine2DPathEffect::CreateProc(SkReadBuffer& buffer) {
SkMatrix matrix;
buffer.readMatrix(&matrix);
SkScalar width = buffer.readScalar();
return SkLine2DPathEffect::Make(width, matrix);
}
void SkLine2DPathEffect::flatten(SkWriteBuffer &buffer) const {
buffer.writeMatrix(this->getMatrix());
buffer.writeScalar(fWidth);
}
///////////////////////////////////////////////////////////////////////////////
SkPath2DPathEffect::SkPath2DPathEffect(const SkMatrix& m, const SkPath& p)
: INHERITED(m), fPath(p) {
}
sk_sp<SkFlattenable> SkPath2DPathEffect::CreateProc(SkReadBuffer& buffer) {
SkMatrix matrix;
buffer.readMatrix(&matrix);
SkPath path;
buffer.readPath(&path);
return SkPath2DPathEffect::Make(matrix, path);
}
void SkPath2DPathEffect::flatten(SkWriteBuffer& buffer) const {
buffer.writeMatrix(this->getMatrix());
buffer.writePath(fPath);
}
void SkPath2DPathEffect::next(const SkPoint& loc, int u, int v,
SkPath* dst) const {
dst->addPath(fPath, loc.fX, loc.fY);
}