blob: 3b8d48e7b5ae63c5258c6c4bc67d9bd67f3ab7bf [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* 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
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000023static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000024 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
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000036bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src,
37 SkScalar* width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 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
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000050 if (fSegLength * (2 + doFill) > length) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 meas.getSegment(0, length, dst, true); // to short for us to mangle
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000052 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +000053 int n = SkScalarRound(SkScalarDiv(length, fSegLength));
54 SkScalar delta = length / n;
55 SkScalar distance = 0;
56
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000057 if (meas.isClosed()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 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);
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000064 while (--n >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 distance += delta;
66 meas.getPosTan(distance, &p, &v);
67 Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
68 dst->lineTo(p);
69 }
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000070 if (meas.isClosed()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000071 dst->close();
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000072 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000073 }
74 } while (meas.nextContour());
75 return true;
76}
77
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000078SkFlattenable::Factory SkDiscretePathEffect::getFactory() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 return CreateProc;
80}
81
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000082SkFlattenable* SkDiscretePathEffect::CreateProc(SkFlattenableReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000083 return SkNEW_ARGS(SkDiscretePathEffect, (buffer));
84}
85
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000086void SkDiscretePathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000087 buffer.writeScalar(fSegLength);
88 buffer.writeScalar(fPerterb);
89}
90
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000091SkDiscretePathEffect::SkDiscretePathEffect(SkFlattenableReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 fSegLength = buffer.readScalar();
93 fPerterb = buffer.readScalar();
94}
95