blob: 77a6ec6b4472e120123aecf7d7f3ba87d2a37027 [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"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000012#include "SkFlattenableBuffers.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkPathMeasure.h"
14#include "SkRandom.h"
15
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000016static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000017 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
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000029bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src,
reed@google.comfd4be262012-05-25 01:04:12 +000030 SkStrokeRec* rec) {
31 bool doFill = rec->isFillStyle();
reed@android.com8a1c16f2008-12-17 15:59:43 +000032
33 SkPathMeasure meas(src, doFill);
34 uint32_t seed = SkScalarRound(meas.getLength());
35 SkRandom 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
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000043 if (fSegLength * (2 + doFill) > length) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 meas.getSegment(0, length, dst, true); // to short for us to mangle
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000045 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 int n = SkScalarRound(SkScalarDiv(length, fSegLength));
47 SkScalar delta = length / n;
48 SkScalar distance = 0;
49
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000050 if (meas.isClosed()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 n -= 1;
52 distance += delta/2;
53 }
reed@google.comf3edf9f2012-04-12 19:44:38 +000054
55 if (meas.getPosTan(distance, &p, &v)) {
56 Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
57 dst->moveTo(p);
58 }
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000059 while (--n >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 distance += delta;
reed@google.comf3edf9f2012-04-12 19:44:38 +000061 if (meas.getPosTan(distance, &p, &v)) {
62 Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
63 dst->lineTo(p);
64 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 }
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000066 if (meas.isClosed()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 dst->close();
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000068 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000069 }
70 } while (meas.nextContour());
71 return true;
72}
73
djsollen@google.com54924242012-03-29 15:18:04 +000074void SkDiscretePathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
75 this->INHERITED::flatten(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 buffer.writeScalar(fSegLength);
77 buffer.writeScalar(fPerterb);
78}
79
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000080SkDiscretePathEffect::SkDiscretePathEffect(SkFlattenableReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 fSegLength = buffer.readScalar();
82 fPerterb = buffer.readScalar();
83}
84
reed@google.com6bac9472011-06-21 19:24:00 +000085///////////////////////////////////////////////////////////////////////////////
86
caryclark@google.comd26147a2011-12-15 14:16:43 +000087SK_DEFINE_FLATTENABLE_REGISTRAR(SkDiscretePathEffect)
reed@google.com6bac9472011-06-21 19:24:00 +000088