SkDiscretePathEffect.cpp revision 6bac947cd5bc460dd9166ada6310d678fd2e39f8
1/* libs/graphics/effects/SkDiscretePathEffect.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkDiscretePathEffect.h"
19#include "SkBuffer.h"
20#include "SkPathMeasure.h"
21#include "SkRandom.h"
22
23static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) {
24    SkVector normal = tangent;
25    normal.rotateCCW();
26    normal.setLength(scale);
27    *p += normal;
28}
29
30
31SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength, SkScalar deviation)
32    : fSegLength(segLength), fPerterb(deviation)
33{
34}
35
36bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src,
37                                      SkScalar* width) {
38    bool doFill = *width < 0;
39
40    SkPathMeasure   meas(src, doFill);
41    uint32_t        seed = SkScalarRound(meas.getLength());
42    SkRandom        rand(seed ^ ((seed << 16) | (seed >> 16)));
43    SkScalar        scale = fPerterb;
44    SkPoint         p;
45    SkVector        v;
46
47    do {
48        SkScalar    length = meas.getLength();
49
50        if (fSegLength * (2 + doFill) > length) {
51            meas.getSegment(0, length, dst, true);  // to short for us to mangle
52        } else {
53            int         n = SkScalarRound(SkScalarDiv(length, fSegLength));
54            SkScalar    delta = length / n;
55            SkScalar    distance = 0;
56
57            if (meas.isClosed()) {
58                n -= 1;
59                distance += delta/2;
60            }
61            meas.getPosTan(distance, &p, &v);
62            Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
63            dst->moveTo(p);
64            while (--n >= 0) {
65                distance += delta;
66                meas.getPosTan(distance, &p, &v);
67                Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
68                dst->lineTo(p);
69            }
70            if (meas.isClosed()) {
71                dst->close();
72            }
73        }
74    } while (meas.nextContour());
75    return true;
76}
77
78SkFlattenable::Factory SkDiscretePathEffect::getFactory() {
79    return CreateProc;
80}
81
82SkFlattenable* SkDiscretePathEffect::CreateProc(SkFlattenableReadBuffer& buffer) {
83    return SkNEW_ARGS(SkDiscretePathEffect, (buffer));
84}
85
86void SkDiscretePathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
87    buffer.writeScalar(fSegLength);
88    buffer.writeScalar(fPerterb);
89}
90
91SkDiscretePathEffect::SkDiscretePathEffect(SkFlattenableReadBuffer& buffer) {
92    fSegLength = buffer.readScalar();
93    fPerterb = buffer.readScalar();
94}
95
96///////////////////////////////////////////////////////////////////////////////
97
98static SkFlattenable::Registrar gReg("SkDiscretePathEffect",
99                                     SkDiscretePathEffect::CreateProc);
100
101