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 "SkFlattenableBuffers.h"
     12 #include "SkPathMeasure.h"
     13 #include "SkRandom.h"
     14 
     15 static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) {
     16     SkVector normal = tangent;
     17     normal.rotateCCW();
     18     normal.setLength(scale);
     19     *p += normal;
     20 }
     21 
     22 
     23 SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength, SkScalar deviation)
     24     : fSegLength(segLength), fPerterb(deviation)
     25 {
     26 }
     27 
     28 bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src,
     29                                       SkStrokeRec* rec, const SkRect*) const {
     30     bool doFill = rec->isFillStyle();
     31 
     32     SkPathMeasure   meas(src, doFill);
     33     uint32_t        seed = SkScalarRound(meas.getLength());
     34     SkLCGRandom     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 
     42         if (fSegLength * (2 + doFill) > length) {
     43             meas.getSegment(0, length, dst, true);  // to short for us to mangle
     44         } else {
     45             int         n = SkScalarRound(SkScalarDiv(length, fSegLength));
     46             SkScalar    delta = length / n;
     47             SkScalar    distance = 0;
     48 
     49             if (meas.isClosed()) {
     50                 n -= 1;
     51                 distance += delta/2;
     52             }
     53 
     54             if (meas.getPosTan(distance, &p, &v)) {
     55                 Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
     56                 dst->moveTo(p);
     57             }
     58             while (--n >= 0) {
     59                 distance += delta;
     60                 if (meas.getPosTan(distance, &p, &v)) {
     61                     Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
     62                     dst->lineTo(p);
     63                 }
     64             }
     65             if (meas.isClosed()) {
     66                 dst->close();
     67             }
     68         }
     69     } while (meas.nextContour());
     70     return true;
     71 }
     72 
     73 void SkDiscretePathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
     74     this->INHERITED::flatten(buffer);
     75     buffer.writeScalar(fSegLength);
     76     buffer.writeScalar(fPerterb);
     77 }
     78 
     79 SkDiscretePathEffect::SkDiscretePathEffect(SkFlattenableReadBuffer& buffer) {
     80     fSegLength = buffer.readScalar();
     81     fPerterb = buffer.readScalar();
     82 }
     83