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 16class Sk2DPathEffect : public SkPathEffectBase { 17public: 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 23protected: 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 */ 30 virtual void begin(const SkIRect& uvBounds, SkPath* dst) const {} 31 virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const {} 32 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 */ 38 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 59 const SkMatrix& getMatrix() const { return fMatrix; } 60 61 void flatten(SkWriteBuffer& buffer) const override { 62 this->INHERITED::flatten(buffer); 63 buffer.writeMatrix(fMatrix); 64 } 65 66 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 95private: 96 SkMatrix fMatrix, fInverse; 97 bool fMatrixIsInvertible; 98 99 // For simplicity, assume fast bounds cannot be computed 100 bool computeFastBounds(SkRect*) const override { return false; } 101 102 friend class Sk2DPathEffectBlitter; 103 using INHERITED = SkPathEffect; 104}; 105 106/////////////////////////////////////////////////////////////////////////////// 107 108class SkLine2DPathEffectImpl : public Sk2DPathEffect { 109public: 110 SkLine2DPathEffectImpl(SkScalar width, const SkMatrix& matrix) 111 : Sk2DPathEffect(matrix) 112 , fWidth(width) 113 { 114 SkASSERT(width >= 0); 115 } 116 117 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 126 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 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 146 void flatten(SkWriteBuffer &buffer) const override { 147 buffer.writeMatrix(this->getMatrix()); 148 buffer.writeScalar(fWidth); 149 } 150 151 Factory getFactory() const override { return CreateProc; } 152 const char* getTypeName() const override { return "SkLine2DPathEffectImpl"; } 153 154private: 155 SkScalar fWidth; 156 157 using INHERITED = Sk2DPathEffect; 158}; 159 160///////////////////////////////////////////////////////////////////////////////////////////////// 161 162class SK_API SkPath2DPathEffectImpl : public Sk2DPathEffect { 163public: 164 SkPath2DPathEffectImpl(const SkMatrix& m, const SkPath& p) : INHERITED(m), fPath(p) {} 165 166 void next(const SkPoint& loc, int u, int v, SkPath* dst) const override { 167 dst->addPath(fPath, loc.fX, loc.fY); 168 } 169 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 178 void flatten(SkWriteBuffer& buffer) const override { 179 buffer.writeMatrix(this->getMatrix()); 180 buffer.writePath(fPath); 181 } 182 183 Factory getFactory() const override { return CreateProc; } 184 const char* getTypeName() const override { return "SkPath2DPathEffectImpl"; } 185 186private: 187 SkPath fPath; 188 189 using INHERITED = Sk2DPathEffect; 190}; 191 192////////////////////////////////////////////////////////////////////////////////////////////////// 193 194sk_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 201sk_sp<SkPathEffect> SkPath2DPathEffect::Make(const SkMatrix& matrix, const SkPath& path) { 202 return sk_sp<SkPathEffect>(new SkPath2DPathEffectImpl(matrix, path)); 203} 204 205void SkLine2DPathEffect::RegisterFlattenables() { 206 SK_REGISTER_FLATTENABLE(SkLine2DPathEffectImpl); 207} 208 209void SkPath2DPathEffect::RegisterFlattenables() { 210 SK_REGISTER_FLATTENABLE(SkPath2DPathEffectImpl); 211} 212