1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2006 The Android Open Source Project
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/Sk2DPathEffect.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFlattenable.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathEffect.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRegion.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStrokeRec.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPathEffectBase.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkReadBuffer.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkWriteBuffer.h"
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker class Sk2DPathEffect : public SkPathEffectBase {
26*c8dee2aaSAndroid Build Coastguard Worker public:
Sk2DPathEffect(const SkMatrix & mat)27*c8dee2aaSAndroid Build Coastguard Worker Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
28*c8dee2aaSAndroid Build Coastguard Worker // Calling invert will set the type mask on both matrices, making them thread safe.
29*c8dee2aaSAndroid Build Coastguard Worker fMatrixIsInvertible = fMatrix.invert(&fInverse);
30*c8dee2aaSAndroid Build Coastguard Worker }
31*c8dee2aaSAndroid Build Coastguard Worker
32*c8dee2aaSAndroid Build Coastguard Worker protected:
33*c8dee2aaSAndroid Build Coastguard Worker /** New virtual, to be overridden by subclasses.
34*c8dee2aaSAndroid Build Coastguard Worker This is called once from filterPath, and provides the
35*c8dee2aaSAndroid Build Coastguard Worker uv parameter bounds for the path. Subsequent calls to
36*c8dee2aaSAndroid Build Coastguard Worker next() will receive u and v values within these bounds,
37*c8dee2aaSAndroid Build Coastguard Worker and then a call to end() will signal the end of processing.
38*c8dee2aaSAndroid Build Coastguard Worker */
begin(const SkIRect & uvBounds,SkPath * dst) const39*c8dee2aaSAndroid Build Coastguard Worker virtual void begin(const SkIRect& uvBounds, SkPath* dst) const {}
next(const SkPoint & loc,int u,int v,SkPath * dst) const40*c8dee2aaSAndroid Build Coastguard Worker virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const {}
end(SkPath * dst) const41*c8dee2aaSAndroid Build Coastguard Worker virtual void end(SkPath* dst) const {}
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker /** Low-level virtual called per span of locations in the u-direction.
44*c8dee2aaSAndroid Build Coastguard Worker The default implementation calls next() repeatedly with each
45*c8dee2aaSAndroid Build Coastguard Worker location.
46*c8dee2aaSAndroid Build Coastguard Worker */
nextSpan(int x,int y,int ucount,SkPath * path) const47*c8dee2aaSAndroid Build Coastguard Worker virtual void nextSpan(int x, int y, int ucount, SkPath* path) const {
48*c8dee2aaSAndroid Build Coastguard Worker if (!fMatrixIsInvertible) {
49*c8dee2aaSAndroid Build Coastguard Worker return;
50*c8dee2aaSAndroid Build Coastguard Worker }
51*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_BUILD_FOR_FUZZER)
52*c8dee2aaSAndroid Build Coastguard Worker if (ucount > 100) {
53*c8dee2aaSAndroid Build Coastguard Worker return;
54*c8dee2aaSAndroid Build Coastguard Worker }
55*c8dee2aaSAndroid Build Coastguard Worker #endif
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& mat = this->getMatrix();
58*c8dee2aaSAndroid Build Coastguard Worker SkPoint src, dst;
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
61*c8dee2aaSAndroid Build Coastguard Worker do {
62*c8dee2aaSAndroid Build Coastguard Worker mat.mapPoints(&dst, &src, 1);
63*c8dee2aaSAndroid Build Coastguard Worker this->next(dst, x++, y, path);
64*c8dee2aaSAndroid Build Coastguard Worker src.fX += SK_Scalar1;
65*c8dee2aaSAndroid Build Coastguard Worker } while (--ucount > 0);
66*c8dee2aaSAndroid Build Coastguard Worker }
67*c8dee2aaSAndroid Build Coastguard Worker
getMatrix() const68*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& getMatrix() const { return fMatrix; }
69*c8dee2aaSAndroid Build Coastguard Worker
flatten(SkWriteBuffer & buffer) const70*c8dee2aaSAndroid Build Coastguard Worker void flatten(SkWriteBuffer& buffer) const override {
71*c8dee2aaSAndroid Build Coastguard Worker buffer.writeMatrix(fMatrix);
72*c8dee2aaSAndroid Build Coastguard Worker }
73*c8dee2aaSAndroid Build Coastguard Worker
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * cullRect,const SkMatrix &) const74*c8dee2aaSAndroid Build Coastguard Worker bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
75*c8dee2aaSAndroid Build Coastguard Worker const SkRect* cullRect, const SkMatrix&) const override {
76*c8dee2aaSAndroid Build Coastguard Worker if (!fMatrixIsInvertible) {
77*c8dee2aaSAndroid Build Coastguard Worker return false;
78*c8dee2aaSAndroid Build Coastguard Worker }
79*c8dee2aaSAndroid Build Coastguard Worker
80*c8dee2aaSAndroid Build Coastguard Worker SkPath tmp;
81*c8dee2aaSAndroid Build Coastguard Worker SkIRect ir;
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker src.transform(fInverse, &tmp);
84*c8dee2aaSAndroid Build Coastguard Worker tmp.getBounds().round(&ir);
85*c8dee2aaSAndroid Build Coastguard Worker if (!ir.isEmpty()) {
86*c8dee2aaSAndroid Build Coastguard Worker this->begin(ir, dst);
87*c8dee2aaSAndroid Build Coastguard Worker
88*c8dee2aaSAndroid Build Coastguard Worker SkRegion rgn;
89*c8dee2aaSAndroid Build Coastguard Worker rgn.setPath(tmp, SkRegion(ir));
90*c8dee2aaSAndroid Build Coastguard Worker SkRegion::Iterator iter(rgn);
91*c8dee2aaSAndroid Build Coastguard Worker for (; !iter.done(); iter.next()) {
92*c8dee2aaSAndroid Build Coastguard Worker const SkIRect& rect = iter.rect();
93*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_BUILD_FOR_FUZZER)
94*c8dee2aaSAndroid Build Coastguard Worker if (rect.height() > 100) {
95*c8dee2aaSAndroid Build Coastguard Worker continue;
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker #endif
98*c8dee2aaSAndroid Build Coastguard Worker for (int y = rect.fTop; y < rect.fBottom; ++y) {
99*c8dee2aaSAndroid Build Coastguard Worker this->nextSpan(rect.fLeft, y, rect.width(), dst);
100*c8dee2aaSAndroid Build Coastguard Worker }
101*c8dee2aaSAndroid Build Coastguard Worker }
102*c8dee2aaSAndroid Build Coastguard Worker
103*c8dee2aaSAndroid Build Coastguard Worker this->end(dst);
104*c8dee2aaSAndroid Build Coastguard Worker }
105*c8dee2aaSAndroid Build Coastguard Worker return true;
106*c8dee2aaSAndroid Build Coastguard Worker }
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker private:
109*c8dee2aaSAndroid Build Coastguard Worker SkMatrix fMatrix, fInverse;
110*c8dee2aaSAndroid Build Coastguard Worker bool fMatrixIsInvertible;
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker // For simplicity, assume fast bounds cannot be computed
computeFastBounds(SkRect *) const113*c8dee2aaSAndroid Build Coastguard Worker bool computeFastBounds(SkRect*) const override { return false; }
114*c8dee2aaSAndroid Build Coastguard Worker
115*c8dee2aaSAndroid Build Coastguard Worker friend class Sk2DPathEffectBlitter;
116*c8dee2aaSAndroid Build Coastguard Worker };
117*c8dee2aaSAndroid Build Coastguard Worker
118*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
119*c8dee2aaSAndroid Build Coastguard Worker
120*c8dee2aaSAndroid Build Coastguard Worker class SkLine2DPathEffectImpl : public Sk2DPathEffect {
121*c8dee2aaSAndroid Build Coastguard Worker public:
SkLine2DPathEffectImpl(SkScalar width,const SkMatrix & matrix)122*c8dee2aaSAndroid Build Coastguard Worker SkLine2DPathEffectImpl(SkScalar width, const SkMatrix& matrix)
123*c8dee2aaSAndroid Build Coastguard Worker : Sk2DPathEffect(matrix)
124*c8dee2aaSAndroid Build Coastguard Worker , fWidth(width)
125*c8dee2aaSAndroid Build Coastguard Worker {
126*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(width >= 0);
127*c8dee2aaSAndroid Build Coastguard Worker }
128*c8dee2aaSAndroid Build Coastguard Worker
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * cullRect,const SkMatrix & ctm) const129*c8dee2aaSAndroid Build Coastguard Worker bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
130*c8dee2aaSAndroid Build Coastguard Worker const SkRect* cullRect, const SkMatrix& ctm) const override {
131*c8dee2aaSAndroid Build Coastguard Worker if (this->INHERITED::onFilterPath(dst, src, rec, cullRect, ctm)) {
132*c8dee2aaSAndroid Build Coastguard Worker rec->setStrokeStyle(fWidth);
133*c8dee2aaSAndroid Build Coastguard Worker return true;
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker return false;
136*c8dee2aaSAndroid Build Coastguard Worker }
137*c8dee2aaSAndroid Build Coastguard Worker
nextSpan(int u,int v,int ucount,SkPath * dst) const138*c8dee2aaSAndroid Build Coastguard Worker void nextSpan(int u, int v, int ucount, SkPath* dst) const override {
139*c8dee2aaSAndroid Build Coastguard Worker if (ucount > 1) {
140*c8dee2aaSAndroid Build Coastguard Worker SkPoint src[2], dstP[2];
141*c8dee2aaSAndroid Build Coastguard Worker
142*c8dee2aaSAndroid Build Coastguard Worker src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
143*c8dee2aaSAndroid Build Coastguard Worker src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
144*c8dee2aaSAndroid Build Coastguard Worker this->getMatrix().mapPoints(dstP, src, 2);
145*c8dee2aaSAndroid Build Coastguard Worker
146*c8dee2aaSAndroid Build Coastguard Worker dst->moveTo(dstP[0]);
147*c8dee2aaSAndroid Build Coastguard Worker dst->lineTo(dstP[1]);
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker }
150*c8dee2aaSAndroid Build Coastguard Worker
CreateProc(SkReadBuffer & buffer)151*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
152*c8dee2aaSAndroid Build Coastguard Worker SkMatrix matrix;
153*c8dee2aaSAndroid Build Coastguard Worker buffer.readMatrix(&matrix);
154*c8dee2aaSAndroid Build Coastguard Worker SkScalar width = buffer.readScalar();
155*c8dee2aaSAndroid Build Coastguard Worker return SkLine2DPathEffect::Make(width, matrix);
156*c8dee2aaSAndroid Build Coastguard Worker }
157*c8dee2aaSAndroid Build Coastguard Worker
flatten(SkWriteBuffer & buffer) const158*c8dee2aaSAndroid Build Coastguard Worker void flatten(SkWriteBuffer &buffer) const override {
159*c8dee2aaSAndroid Build Coastguard Worker buffer.writeMatrix(this->getMatrix());
160*c8dee2aaSAndroid Build Coastguard Worker buffer.writeScalar(fWidth);
161*c8dee2aaSAndroid Build Coastguard Worker }
162*c8dee2aaSAndroid Build Coastguard Worker
getFactory() const163*c8dee2aaSAndroid Build Coastguard Worker Factory getFactory() const override { return CreateProc; }
getTypeName() const164*c8dee2aaSAndroid Build Coastguard Worker const char* getTypeName() const override { return "SkLine2DPathEffect"; }
165*c8dee2aaSAndroid Build Coastguard Worker
166*c8dee2aaSAndroid Build Coastguard Worker private:
167*c8dee2aaSAndroid Build Coastguard Worker SkScalar fWidth;
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = Sk2DPathEffect;
170*c8dee2aaSAndroid Build Coastguard Worker };
171*c8dee2aaSAndroid Build Coastguard Worker
172*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////////////////////////
173*c8dee2aaSAndroid Build Coastguard Worker
174*c8dee2aaSAndroid Build Coastguard Worker class SkPath2DPathEffectImpl : public Sk2DPathEffect {
175*c8dee2aaSAndroid Build Coastguard Worker public:
SkPath2DPathEffectImpl(const SkMatrix & m,const SkPath & p)176*c8dee2aaSAndroid Build Coastguard Worker SkPath2DPathEffectImpl(const SkMatrix& m, const SkPath& p) : INHERITED(m), fPath(p) {}
177*c8dee2aaSAndroid Build Coastguard Worker
next(const SkPoint & loc,int u,int v,SkPath * dst) const178*c8dee2aaSAndroid Build Coastguard Worker void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
179*c8dee2aaSAndroid Build Coastguard Worker dst->addPath(fPath, loc.fX, loc.fY);
180*c8dee2aaSAndroid Build Coastguard Worker }
181*c8dee2aaSAndroid Build Coastguard Worker
CreateProc(SkReadBuffer & buffer)182*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
183*c8dee2aaSAndroid Build Coastguard Worker SkMatrix matrix;
184*c8dee2aaSAndroid Build Coastguard Worker buffer.readMatrix(&matrix);
185*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
186*c8dee2aaSAndroid Build Coastguard Worker buffer.readPath(&path);
187*c8dee2aaSAndroid Build Coastguard Worker return SkPath2DPathEffect::Make(matrix, path);
188*c8dee2aaSAndroid Build Coastguard Worker }
189*c8dee2aaSAndroid Build Coastguard Worker
flatten(SkWriteBuffer & buffer) const190*c8dee2aaSAndroid Build Coastguard Worker void flatten(SkWriteBuffer& buffer) const override {
191*c8dee2aaSAndroid Build Coastguard Worker buffer.writeMatrix(this->getMatrix());
192*c8dee2aaSAndroid Build Coastguard Worker buffer.writePath(fPath);
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker
getFactory() const195*c8dee2aaSAndroid Build Coastguard Worker Factory getFactory() const override { return CreateProc; }
getTypeName() const196*c8dee2aaSAndroid Build Coastguard Worker const char* getTypeName() const override { return "SkPath2DPathEffect"; }
197*c8dee2aaSAndroid Build Coastguard Worker
198*c8dee2aaSAndroid Build Coastguard Worker private:
199*c8dee2aaSAndroid Build Coastguard Worker SkPath fPath;
200*c8dee2aaSAndroid Build Coastguard Worker
201*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = Sk2DPathEffect;
202*c8dee2aaSAndroid Build Coastguard Worker };
203*c8dee2aaSAndroid Build Coastguard Worker
204*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////////////////////////
205*c8dee2aaSAndroid Build Coastguard Worker
Make(SkScalar width,const SkMatrix & matrix)206*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPathEffect> SkLine2DPathEffect::Make(SkScalar width, const SkMatrix& matrix) {
207*c8dee2aaSAndroid Build Coastguard Worker if (!(width >= 0)) {
208*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
209*c8dee2aaSAndroid Build Coastguard Worker }
210*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<SkPathEffect>(new SkLine2DPathEffectImpl(width, matrix));
211*c8dee2aaSAndroid Build Coastguard Worker }
212*c8dee2aaSAndroid Build Coastguard Worker
Make(const SkMatrix & matrix,const SkPath & path)213*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPathEffect> SkPath2DPathEffect::Make(const SkMatrix& matrix, const SkPath& path) {
214*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<SkPathEffect>(new SkPath2DPathEffectImpl(matrix, path));
215*c8dee2aaSAndroid Build Coastguard Worker }
216*c8dee2aaSAndroid Build Coastguard Worker
RegisterFlattenables()217*c8dee2aaSAndroid Build Coastguard Worker void SkLine2DPathEffect::RegisterFlattenables() {
218*c8dee2aaSAndroid Build Coastguard Worker SK_REGISTER_FLATTENABLE(SkLine2DPathEffectImpl);
219*c8dee2aaSAndroid Build Coastguard Worker }
220*c8dee2aaSAndroid Build Coastguard Worker
RegisterFlattenables()221*c8dee2aaSAndroid Build Coastguard Worker void SkPath2DPathEffect::RegisterFlattenables() {
222*c8dee2aaSAndroid Build Coastguard Worker SK_REGISTER_FLATTENABLE(SkPath2DPathEffectImpl);
223*c8dee2aaSAndroid Build Coastguard Worker }
224