diff options
Diffstat (limited to 'gfx/skia/skia/src/effects/Sk2DPathEffect.cpp')
-rw-r--r-- | gfx/skia/skia/src/effects/Sk2DPathEffect.cpp | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/effects/Sk2DPathEffect.cpp b/gfx/skia/skia/src/effects/Sk2DPathEffect.cpp new file mode 100644 index 0000000000..5cb41549d3 --- /dev/null +++ b/gfx/skia/skia/src/effects/Sk2DPathEffect.cpp @@ -0,0 +1,223 @@ +/* + * 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 "include/effects/Sk2DPathEffect.h" + +#include "include/core/SkFlattenable.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkPath.h" +#include "include/core/SkPathEffect.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkRegion.h" +#include "include/core/SkScalar.h" +#include "include/core/SkStrokeRec.h" +#include "include/core/SkTypes.h" +#include "src/core/SkPathEffectBase.h" +#include "src/core/SkReadBuffer.h" +#include "src/core/SkWriteBuffer.h" + +class Sk2DPathEffect : public SkPathEffectBase { +public: + Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) { + // Calling invert will set the type mask on both matrices, making them thread safe. + fMatrixIsInvertible = fMatrix.invert(&fInverse); + } + +protected: + /** New virtual, to be overridden by subclasses. + This is called once from filterPath, and provides the + uv parameter bounds for the path. Subsequent calls to + next() will receive u and v values within these bounds, + and then a call to end() will signal the end of processing. + */ + virtual void begin(const SkIRect& uvBounds, SkPath* dst) const {} + virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const {} + virtual void end(SkPath* dst) const {} + + /** Low-level virtual called per span of locations in the u-direction. + The default implementation calls next() repeatedly with each + location. + */ + virtual void nextSpan(int x, int y, int ucount, SkPath* path) const { + if (!fMatrixIsInvertible) { + return; + } + #if defined(SK_BUILD_FOR_FUZZER) + if (ucount > 100) { + return; + } + #endif + + 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 (--ucount > 0); + } + + const SkMatrix& getMatrix() const { return fMatrix; } + + void flatten(SkWriteBuffer& buffer) const override { + buffer.writeMatrix(fMatrix); + } + + bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec, + const SkRect* cullRect, const SkMatrix&) const override { + 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(); +#if defined(SK_BUILD_FOR_FUZZER) + if (rect.height() > 100) { + continue; + } +#endif + for (int y = rect.fTop; y < rect.fBottom; ++y) { + this->nextSpan(rect.fLeft, y, rect.width(), dst); + } + } + + this->end(dst); + } + return true; + } + +private: + SkMatrix fMatrix, fInverse; + bool fMatrixIsInvertible; + + // For simplicity, assume fast bounds cannot be computed + bool computeFastBounds(SkRect*) const override { return false; } + + friend class Sk2DPathEffectBlitter; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SkLine2DPathEffectImpl : public Sk2DPathEffect { +public: + SkLine2DPathEffectImpl(SkScalar width, const SkMatrix& matrix) + : Sk2DPathEffect(matrix) + , fWidth(width) + { + SkASSERT(width >= 0); + } + + bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec, + const SkRect* cullRect, const SkMatrix& ctm) const override { + if (this->INHERITED::onFilterPath(dst, src, rec, cullRect, ctm)) { + rec->setStrokeStyle(fWidth); + return true; + } + return false; + } + + void nextSpan(int u, int v, int ucount, SkPath* dst) const override { + 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]); + } + } + + static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { + SkMatrix matrix; + buffer.readMatrix(&matrix); + SkScalar width = buffer.readScalar(); + return SkLine2DPathEffect::Make(width, matrix); + } + + void flatten(SkWriteBuffer &buffer) const override { + buffer.writeMatrix(this->getMatrix()); + buffer.writeScalar(fWidth); + } + + Factory getFactory() const override { return CreateProc; } + const char* getTypeName() const override { return "SkLine2DPathEffect"; } + +private: + SkScalar fWidth; + + using INHERITED = Sk2DPathEffect; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +class SK_API SkPath2DPathEffectImpl : public Sk2DPathEffect { +public: + SkPath2DPathEffectImpl(const SkMatrix& m, const SkPath& p) : INHERITED(m), fPath(p) {} + + void next(const SkPoint& loc, int u, int v, SkPath* dst) const override { + dst->addPath(fPath, loc.fX, loc.fY); + } + + static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { + SkMatrix matrix; + buffer.readMatrix(&matrix); + SkPath path; + buffer.readPath(&path); + return SkPath2DPathEffect::Make(matrix, path); + } + + void flatten(SkWriteBuffer& buffer) const override { + buffer.writeMatrix(this->getMatrix()); + buffer.writePath(fPath); + } + + Factory getFactory() const override { return CreateProc; } + const char* getTypeName() const override { return "SkPath2DPathEffect"; } + +private: + SkPath fPath; + + using INHERITED = Sk2DPathEffect; +}; + +////////////////////////////////////////////////////////////////////////////////////////////////// + +sk_sp<SkPathEffect> SkLine2DPathEffect::Make(SkScalar width, const SkMatrix& matrix) { + if (!(width >= 0)) { + return nullptr; + } + return sk_sp<SkPathEffect>(new SkLine2DPathEffectImpl(width, matrix)); +} + +sk_sp<SkPathEffect> SkPath2DPathEffect::Make(const SkMatrix& matrix, const SkPath& path) { + return sk_sp<SkPathEffect>(new SkPath2DPathEffectImpl(matrix, path)); +} + +void SkLine2DPathEffect::RegisterFlattenables() { + SK_REGISTER_FLATTENABLE(SkLine2DPathEffectImpl); +} + +void SkPath2DPathEffect::RegisterFlattenables() { + SK_REGISTER_FLATTENABLE(SkPath2DPathEffectImpl); +} |