• 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                 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