Home | History | Annotate | Download | only in effects
      1 
      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 
      9 
     10 #include "SkDiscretePathEffect.h"
     11 #include "SkReadBuffer.h"
     12 #include "SkWriteBuffer.h"
     13 #include "SkPathMeasure.h"
     14 #include "SkRandom.h"
     15 
     16 static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) {
     17     SkVector normal = tangent;
     18     normal.rotateCCW();
     19     normal.setLength(scale);
     20     *p += normal;
     21 }
     22 
     23 SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength,
     24                                            SkScalar deviation,
     25                                            uint32_t seedAssist)
     26     : fSegLength(segLength), fPerterb(deviation), fSeedAssist(seedAssist)
     27 {
     28 }
     29 
     30 bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src,
     31                                       SkStrokeRec* rec, const SkRect*) const {
     32     bool doFill = rec->isFillStyle();
     33 
     34     SkPathMeasure   meas(src, doFill);
     35 
     36     /* Caller may supply their own seed assist, which by default is 0 */
     37     uint32_t seed = fSeedAssist ^ SkScalarRoundToInt(meas.getLength());
     38 
     39     SkLCGRandom     rand(seed ^ ((seed << 16) | (seed >> 16)));
     40     SkScalar        scale = fPerterb;
     41     SkPoint         p;
     42     SkVector        v;
     43 
     44     do {
     45         SkScalar    length = meas.getLength();
     46 
     47         if (fSegLength * (2 + doFill) > length) {
     48             meas.getSegment(0, length, dst, true);  // to short for us to mangle
     49         } else {
     50             int         n = SkScalarRoundToInt(length / fSegLength);
     51             SkScalar    delta = length / n;
     52             SkScalar    distance = 0;
     53 
     54             if (meas.isClosed()) {
     55                 n -= 1;
     56                 distance += delta/2;
     57             }
     58 
     59             if (meas.getPosTan(distance, &p, &v)) {
     60                 Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
     61                 dst->moveTo(p);
     62             }
     63             while (--n >= 0) {
     64                 distance += delta;
     65                 if (meas.getPosTan(distance, &p, &v)) {
     66                     Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
     67                     dst->lineTo(p);
     68                 }
     69             }
     70             if (meas.isClosed()) {
     71                 dst->close();
     72             }
     73         }
     74     } while (meas.nextContour());
     75     return true;
     76 }
     77 
     78 void SkDiscretePathEffect::flatten(SkWriteBuffer& buffer) const {
     79     this->INHERITED::flatten(buffer);
     80     buffer.writeScalar(fSegLength);
     81     buffer.writeScalar(fPerterb);
     82     buffer.writeUInt(fSeedAssist);
     83 }
     84 
     85 SkDiscretePathEffect::SkDiscretePathEffect(SkReadBuffer& buffer) {
     86     fSegLength = buffer.readScalar();
     87     fPerterb = buffer.readScalar();
     88     fSeedAssist = buffer.readUInt();
     89 }
     90