blob: 06b9d19c688afd018aa0759188e1ef4e490c6034 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkDiscretePathEffect.h"
11#include "SkBuffer.h"
12#include "SkPathMeasure.h"
13#include "SkRandom.h"
14
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000015static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000016 SkVector normal = tangent;
17 normal.rotateCCW();
18 normal.setLength(scale);
19 *p += normal;
20}
21
22
23SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength, SkScalar deviation)
24 : fSegLength(segLength), fPerterb(deviation)
25{
26}
27
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000028bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src,
29 SkScalar* width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000030 bool doFill = *width < 0;
31
32 SkPathMeasure meas(src, doFill);
33 uint32_t seed = SkScalarRound(meas.getLength());
34 SkRandom rand(seed ^ ((seed << 16) | (seed >> 16)));
35 SkScalar scale = fPerterb;
36 SkPoint p;
37 SkVector v;
38
39 do {
40 SkScalar length = meas.getLength();
41
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000042 if (fSegLength * (2 + doFill) > length) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000043 meas.getSegment(0, length, dst, true); // to short for us to mangle
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000044 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 int n = SkScalarRound(SkScalarDiv(length, fSegLength));
46 SkScalar delta = length / n;
47 SkScalar distance = 0;
48
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000049 if (meas.isClosed()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000050 n -= 1;
51 distance += delta/2;
52 }
reed@google.comf3edf9f2012-04-12 19:44:38 +000053
54 if (meas.getPosTan(distance, &p, &v)) {
55 Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
56 dst->moveTo(p);
57 }
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000058 while (--n >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 distance += delta;
reed@google.comf3edf9f2012-04-12 19:44:38 +000060 if (meas.getPosTan(distance, &p, &v)) {
61 Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
62 dst->lineTo(p);
63 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 }
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000065 if (meas.isClosed()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 dst->close();
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000067 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000068 }
69 } while (meas.nextContour());
70 return true;
71}
72
djsollen@google.com54924242012-03-29 15:18:04 +000073void SkDiscretePathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
74 this->INHERITED::flatten(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 buffer.writeScalar(fSegLength);
76 buffer.writeScalar(fPerterb);
77}
78
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000079SkDiscretePathEffect::SkDiscretePathEffect(SkFlattenableReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 fSegLength = buffer.readScalar();
81 fPerterb = buffer.readScalar();
82}
83
reed@google.com6bac9472011-06-21 19:24:00 +000084///////////////////////////////////////////////////////////////////////////////
85
caryclark@google.comd26147a2011-12-15 14:16:43 +000086SK_DEFINE_FLATTENABLE_REGISTRAR(SkDiscretePathEffect)
reed@google.com6bac9472011-06-21 19:24:00 +000087