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
Make(SkScalar segLength,SkScalar deviation,uint32_t seedAssist)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
Perterb(SkPoint * p,const SkVector & tangent,SkScalar scale)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
SkDiscretePathEffect(SkScalar segLength,SkScalar deviation,uint32_t seedAssist)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:
LCGRandom(uint32_t seed)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 */
nextSScalar1()59 SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); }
60
61 private:
62 /** Return the next pseudo random number as an unsigned 32bit value.
63 */
nextU()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 */
nextS()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 */
nextSFixed1()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
filterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect *) const83 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
CreateProc(SkReadBuffer & buffer)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
flatten(SkWriteBuffer & buffer) const138 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
toString(SkString * str) const145 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