• 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 "SkLine2DPathEffectImpl"; }
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 "SkPath2DPathEffectImpl"; }
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