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