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 9 #include "SkDiscretePathEffect.h" 10 #include "SkFixed.h" 11 #include "SkPathMeasure.h" 12 #include "SkReadBuffer.h" 13 #include "SkStrokeRec.h" 14 #include "SkWriteBuffer.h" 15 16 sk_sp<SkPathEffect> SkDiscretePathEffect::Make(SkScalar segLength, SkScalar deviation, 17 uint32_t seedAssist) { 18 if (!SkScalarIsFinite(segLength) || !SkScalarIsFinite(deviation)) { 19 return nullptr; 20 } 21 if (segLength <= SK_ScalarNearlyZero) { 22 return nullptr; 23 } 24 return sk_sp<SkPathEffect>(new SkDiscretePathEffect(segLength, deviation, seedAssist)); 25 } 26 27 static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) { 28 SkVector normal = tangent; 29 normal.rotateCCW(); 30 normal.setLength(scale); 31 *p += normal; 32 } 33 34 SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength, 35 SkScalar deviation, 36 uint32_t seedAssist) 37 : fSegLength(segLength), fPerterb(deviation), fSeedAssist(seedAssist) 38 { 39 } 40 41 /** \class LCGRandom 42 43 Utility class that implements pseudo random 32bit numbers using a fast 44 linear equation. Unlike rand(), this class holds its own seed (initially 45 set to 0), so that multiple instances can be used with no side-effects. 46 47 Copied from the original implementation of SkRandom. Only contains the 48 methods used by SkDiscretePathEffect::filterPath, with methods that were 49 not called directly moved to private. 50 */ 51 52 class LCGRandom { 53 public: 54 LCGRandom(uint32_t seed) : fSeed(seed) {} 55 56 /** Return the next pseudo random number expressed as a SkScalar 57 in the range [-SK_Scalar1..SK_Scalar1). 58 */ 59 SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); } 60 61 private: 62 /** Return the next pseudo random number as an unsigned 32bit value. 63 */ 64 uint32_t nextU() { uint32_t r = fSeed * kMul + kAdd; fSeed = r; return r; } 65 66 /** Return the next pseudo random number as a signed 32bit value. 67 */ 68 int32_t nextS() { return (int32_t)this->nextU(); } 69 70 /** Return the next pseudo random number expressed as a signed SkFixed 71 in the range [-SK_Fixed1..SK_Fixed1). 72 */ 73 SkFixed nextSFixed1() { return this->nextS() >> 15; } 74 75 // See "Numerical Recipes in C", 1992 page 284 for these constants 76 enum { 77 kMul = 1664525, 78 kAdd = 1013904223 79 }; 80 uint32_t fSeed; 81 }; 82 83 bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src, 84 SkStrokeRec* rec, const SkRect*) const { 85 bool doFill = rec->isFillStyle(); 86 87 SkPathMeasure meas(src, doFill); 88 89 /* Caller may supply their own seed assist, which by default is 0 */ 90 uint32_t seed = fSeedAssist ^ SkScalarRoundToInt(meas.getLength()); 91 92 LCGRandom rand(seed ^ ((seed << 16) | (seed >> 16))); 93 SkScalar scale = fPerterb; 94 SkPoint p; 95 SkVector v; 96 97 do { 98 SkScalar length = meas.getLength(); 99 100 if (fSegLength * (2 + doFill) > length) { 101 meas.getSegment(0, length, dst, true); // to short for us to mangle 102 } else { 103 int n = SkScalarRoundToInt(length / fSegLength); 104 SkScalar delta = length / n; 105 SkScalar distance = 0; 106 107 if (meas.isClosed()) { 108 n -= 1; 109 distance += delta/2; 110 } 111 112 if (meas.getPosTan(distance, &p, &v)) { 113 Perterb(&p, v, rand.nextSScalar1() * scale); 114 dst->moveTo(p); 115 } 116 while (--n >= 0) { 117 distance += delta; 118 if (meas.getPosTan(distance, &p, &v)) { 119 Perterb(&p, v, rand.nextSScalar1() * scale); 120 dst->lineTo(p); 121 } 122 } 123 if (meas.isClosed()) { 124 dst->close(); 125 } 126 } 127 } while (meas.nextContour()); 128 return true; 129 } 130 131 sk_sp<SkFlattenable> SkDiscretePathEffect::CreateProc(SkReadBuffer& buffer) { 132 SkScalar segLength = buffer.readScalar(); 133 SkScalar perterb = buffer.readScalar(); 134 uint32_t seed = buffer.readUInt(); 135 return Make(segLength, perterb, seed); 136 } 137 138 void SkDiscretePathEffect::flatten(SkWriteBuffer& buffer) const { 139 buffer.writeScalar(fSegLength); 140 buffer.writeScalar(fPerterb); 141 buffer.writeUInt(fSeedAssist); 142 } 143 144 #ifndef SK_IGNORE_TO_STRING 145 void SkDiscretePathEffect::toString(SkString* str) const { 146 str->appendf("SkDiscretePathEffect: ("); 147 str->appendf("segLength: %.2f deviation: %.2f seed %d", fSegLength, fPerterb, fSeedAssist); 148 str->append(")"); 149 } 150 #endif 151