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