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