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 "SkRandom.h"
15
16static 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
23SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength,
24                                           SkScalar deviation,
25                                           uint32_t seedAssist)
26    : fSegLength(segLength), fPerterb(deviation), fSeedAssist(seedAssist)
27{
28}
29
30bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src,
31                                      SkStrokeRec* rec, const SkRect*) const {
32    bool doFill = rec->isFillStyle();
33
34    SkPathMeasure   meas(src, doFill);
35
36    /* Caller may supply their own seed assist, which by default is 0 */
37    uint32_t seed = fSeedAssist ^ SkScalarRoundToInt(meas.getLength());
38
39    SkLCGRandom     rand(seed ^ ((seed << 16) | (seed >> 16)));
40    SkScalar        scale = fPerterb;
41    SkPoint         p;
42    SkVector        v;
43
44    do {
45        SkScalar    length = meas.getLength();
46
47        if (fSegLength * (2 + doFill) > length) {
48            meas.getSegment(0, length, dst, true);  // to short for us to mangle
49        } else {
50            int         n = SkScalarRoundToInt(length / fSegLength);
51            SkScalar    delta = length / n;
52            SkScalar    distance = 0;
53
54            if (meas.isClosed()) {
55                n -= 1;
56                distance += delta/2;
57            }
58
59            if (meas.getPosTan(distance, &p, &v)) {
60                Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
61                dst->moveTo(p);
62            }
63            while (--n >= 0) {
64                distance += delta;
65                if (meas.getPosTan(distance, &p, &v)) {
66                    Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
67                    dst->lineTo(p);
68                }
69            }
70            if (meas.isClosed()) {
71                dst->close();
72            }
73        }
74    } while (meas.nextContour());
75    return true;
76}
77
78void SkDiscretePathEffect::flatten(SkWriteBuffer& buffer) const {
79    this->INHERITED::flatten(buffer);
80    buffer.writeScalar(fSegLength);
81    buffer.writeScalar(fPerterb);
82    buffer.writeUInt(fSeedAssist);
83}
84
85SkDiscretePathEffect::SkDiscretePathEffect(SkReadBuffer& buffer) {
86    fSegLength = buffer.readScalar();
87    fPerterb = buffer.readScalar();
88    fSeedAssist = buffer.readUInt();
89}
90