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