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