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 for (int y = rect.fTop; y < rect.fBottom; ++y) {
86 this->nextSpan(rect.fLeft, y, rect.width(), dst);
87 }
88 }
89
90 this->end(dst);
91 }
92 return true;
93 }
94
95 private:
96 SkMatrix fMatrix, fInverse;
97 bool fMatrixIsInvertible;
98
99 // For simplicity, assume fast bounds cannot be computed
computeFastBounds(SkRect *) const100 bool computeFastBounds(SkRect*) const override { return false; }
101
102 friend class Sk2DPathEffectBlitter;
103 using INHERITED = SkPathEffect;
104 };
105
106 ///////////////////////////////////////////////////////////////////////////////
107
108 class SkLine2DPathEffectImpl : public Sk2DPathEffect {
109 public:
SkLine2DPathEffectImpl(SkScalar width,const SkMatrix & matrix)110 SkLine2DPathEffectImpl(SkScalar width, const SkMatrix& matrix)
111 : Sk2DPathEffect(matrix)
112 , fWidth(width)
113 {
114 SkASSERT(width >= 0);
115 }
116
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * cullRect,const SkMatrix & ctm) const117 bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
118 const SkRect* cullRect, const SkMatrix& ctm) const override {
119 if (this->INHERITED::onFilterPath(dst, src, rec, cullRect, ctm)) {
120 rec->setStrokeStyle(fWidth);
121 return true;
122 }
123 return false;
124 }
125
nextSpan(int u,int v,int ucount,SkPath * dst) const126 void nextSpan(int u, int v, int ucount, SkPath* dst) const override {
127 if (ucount > 1) {
128 SkPoint src[2], dstP[2];
129
130 src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
131 src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
132 this->getMatrix().mapPoints(dstP, src, 2);
133
134 dst->moveTo(dstP[0]);
135 dst->lineTo(dstP[1]);
136 }
137 }
138
CreateProc(SkReadBuffer & buffer)139 static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
140 SkMatrix matrix;
141 buffer.readMatrix(&matrix);
142 SkScalar width = buffer.readScalar();
143 return SkLine2DPathEffect::Make(width, matrix);
144 }
145
flatten(SkWriteBuffer & buffer) const146 void flatten(SkWriteBuffer &buffer) const override {
147 buffer.writeMatrix(this->getMatrix());
148 buffer.writeScalar(fWidth);
149 }
150
getFactory() const151 Factory getFactory() const override { return CreateProc; }
getTypeName() const152 const char* getTypeName() const override { return "SkLine2DPathEffect"; }
153
154 private:
155 SkScalar fWidth;
156
157 using INHERITED = Sk2DPathEffect;
158 };
159
160 /////////////////////////////////////////////////////////////////////////////////////////////////
161
162 class SK_API SkPath2DPathEffectImpl : public Sk2DPathEffect {
163 public:
SkPath2DPathEffectImpl(const SkMatrix & m,const SkPath & p)164 SkPath2DPathEffectImpl(const SkMatrix& m, const SkPath& p) : INHERITED(m), fPath(p) {}
165
next(const SkPoint & loc,int u,int v,SkPath * dst) const166 void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
167 dst->addPath(fPath, loc.fX, loc.fY);
168 }
169
CreateProc(SkReadBuffer & buffer)170 static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
171 SkMatrix matrix;
172 buffer.readMatrix(&matrix);
173 SkPath path;
174 buffer.readPath(&path);
175 return SkPath2DPathEffect::Make(matrix, path);
176 }
177
flatten(SkWriteBuffer & buffer) const178 void flatten(SkWriteBuffer& buffer) const override {
179 buffer.writeMatrix(this->getMatrix());
180 buffer.writePath(fPath);
181 }
182
getFactory() const183 Factory getFactory() const override { return CreateProc; }
getTypeName() const184 const char* getTypeName() const override { return "SkPath2DPathEffect"; }
185
186 private:
187 SkPath fPath;
188
189 using INHERITED = Sk2DPathEffect;
190 };
191
192 //////////////////////////////////////////////////////////////////////////////////////////////////
193
Make(SkScalar width,const SkMatrix & matrix)194 sk_sp<SkPathEffect> SkLine2DPathEffect::Make(SkScalar width, const SkMatrix& matrix) {
195 if (!(width >= 0)) {
196 return nullptr;
197 }
198 return sk_sp<SkPathEffect>(new SkLine2DPathEffectImpl(width, matrix));
199 }
200
Make(const SkMatrix & matrix,const SkPath & path)201 sk_sp<SkPathEffect> SkPath2DPathEffect::Make(const SkMatrix& matrix, const SkPath& path) {
202 return sk_sp<SkPathEffect>(new SkPath2DPathEffectImpl(matrix, path));
203 }
204
RegisterFlattenables()205 void SkLine2DPathEffect::RegisterFlattenables() {
206 SK_REGISTER_FLATTENABLE(SkLine2DPathEffectImpl);
207 }
208
RegisterFlattenables()209 void SkPath2DPathEffect::RegisterFlattenables() {
210 SK_REGISTER_FLATTENABLE(SkPath2DPathEffectImpl);
211 }
212