• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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