xref: /aosp_15_r20/external/skia/src/effects/Sk2DPathEffect.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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