michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkDiscretePathEffect.h" michael@0: #include "SkReadBuffer.h" michael@0: #include "SkWriteBuffer.h" michael@0: #include "SkPathMeasure.h" michael@0: #include "SkRandom.h" michael@0: michael@0: static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) { michael@0: SkVector normal = tangent; michael@0: normal.rotateCCW(); michael@0: normal.setLength(scale); michael@0: *p += normal; michael@0: } michael@0: michael@0: michael@0: SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength, SkScalar deviation) michael@0: : fSegLength(segLength), fPerterb(deviation) michael@0: { michael@0: } michael@0: michael@0: bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src, michael@0: SkStrokeRec* rec, const SkRect*) const { michael@0: bool doFill = rec->isFillStyle(); michael@0: michael@0: SkPathMeasure meas(src, doFill); michael@0: uint32_t seed = SkScalarRoundToInt(meas.getLength()); michael@0: SkLCGRandom rand(seed ^ ((seed << 16) | (seed >> 16))); michael@0: SkScalar scale = fPerterb; michael@0: SkPoint p; michael@0: SkVector v; michael@0: michael@0: do { michael@0: SkScalar length = meas.getLength(); michael@0: michael@0: if (fSegLength * (2 + doFill) > length) { michael@0: meas.getSegment(0, length, dst, true); // to short for us to mangle michael@0: } else { michael@0: int n = SkScalarRoundToInt(length / fSegLength); michael@0: SkScalar delta = length / n; michael@0: SkScalar distance = 0; michael@0: michael@0: if (meas.isClosed()) { michael@0: n -= 1; michael@0: distance += delta/2; michael@0: } michael@0: michael@0: if (meas.getPosTan(distance, &p, &v)) { michael@0: Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale)); michael@0: dst->moveTo(p); michael@0: } michael@0: while (--n >= 0) { michael@0: distance += delta; michael@0: if (meas.getPosTan(distance, &p, &v)) { michael@0: Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale)); michael@0: dst->lineTo(p); michael@0: } michael@0: } michael@0: if (meas.isClosed()) { michael@0: dst->close(); michael@0: } michael@0: } michael@0: } while (meas.nextContour()); michael@0: return true; michael@0: } michael@0: michael@0: void SkDiscretePathEffect::flatten(SkWriteBuffer& buffer) const { michael@0: this->INHERITED::flatten(buffer); michael@0: buffer.writeScalar(fSegLength); michael@0: buffer.writeScalar(fPerterb); michael@0: } michael@0: michael@0: SkDiscretePathEffect::SkDiscretePathEffect(SkReadBuffer& buffer) { michael@0: fSegLength = buffer.readScalar(); michael@0: fPerterb = buffer.readScalar(); michael@0: }