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 "SkCornerPathEffect.h"
     11 #include "SkPath.h"
     12 #include "SkPoint.h"
     13 #include "SkFlattenableBuffers.h"
     14 
     15 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {}
     16 SkCornerPathEffect::~SkCornerPathEffect() {}
     17 
     18 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
     19                         SkPoint* step) {
     20     SkScalar dist = SkPoint::Distance(a, b);
     21 
     22     step->set(b.fX - a.fX, b.fY - a.fY);
     23 
     24     if (dist <= radius * 2) {
     25         step->scale(SK_ScalarHalf);
     26         return false;
     27     } else {
     28         step->scale(SkScalarDiv(radius, dist));
     29         return true;
     30     }
     31 }
     32 
     33 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
     34                                     SkStrokeRec*, const SkRect*) const {
     35     if (0 == fRadius) {
     36         return false;
     37     }
     38 
     39     SkPath::Iter    iter(src, false);
     40     SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
     41     SkPoint         pts[4];
     42 
     43     bool        closed;
     44     SkPoint     moveTo, lastCorner;
     45     SkVector    firstStep, step;
     46     bool        prevIsValid = true;
     47 
     48     // to avoid warnings
     49     moveTo.set(0, 0);
     50     firstStep.set(0, 0);
     51     lastCorner.set(0, 0);
     52 
     53     for (;;) {
     54         switch (verb = iter.next(pts, false)) {
     55             case SkPath::kMove_Verb:
     56                     // close out the previous (open) contour
     57                 if (SkPath::kLine_Verb == prevVerb) {
     58                     dst->lineTo(lastCorner);
     59                 }
     60                 closed = iter.isClosedContour();
     61                 if (closed) {
     62                     moveTo = pts[0];
     63                     prevIsValid = false;
     64                 } else {
     65                     dst->moveTo(pts[0]);
     66                     prevIsValid = true;
     67                 }
     68                 break;
     69             case SkPath::kLine_Verb: {
     70                 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
     71                 // prev corner
     72                 if (!prevIsValid) {
     73                     dst->moveTo(moveTo + step);
     74                     prevIsValid = true;
     75                 } else {
     76                     dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
     77                                 pts[0].fY + step.fY);
     78                 }
     79                 if (drawSegment) {
     80                     dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
     81                 }
     82                 lastCorner = pts[1];
     83                 prevIsValid = true;
     84                 break;
     85             }
     86             case SkPath::kQuad_Verb:
     87                 // TBD - just replicate the curve for now
     88                 if (!prevIsValid) {
     89                     dst->moveTo(pts[0]);
     90                     prevIsValid = true;
     91                 }
     92                 dst->quadTo(pts[1], pts[2]);
     93                 lastCorner = pts[2];
     94                 firstStep.set(0, 0);
     95                 break;
     96             case SkPath::kCubic_Verb:
     97                 if (!prevIsValid) {
     98                     dst->moveTo(pts[0]);
     99                     prevIsValid = true;
    100                 }
    101                 // TBD - just replicate the curve for now
    102                 dst->cubicTo(pts[1], pts[2], pts[3]);
    103                 lastCorner = pts[3];
    104                 firstStep.set(0, 0);
    105                 break;
    106             case SkPath::kClose_Verb:
    107                 if (firstStep.fX || firstStep.fY) {
    108                     dst->quadTo(lastCorner.fX, lastCorner.fY,
    109                                 lastCorner.fX + firstStep.fX,
    110                                 lastCorner.fY + firstStep.fY);
    111                     }
    112                 dst->close();
    113                 break;
    114             case SkPath::kConic_Verb:
    115                 SkASSERT(0);
    116                 break;
    117             case SkPath::kDone_Verb:
    118                 goto DONE;
    119         }
    120 
    121         if (SkPath::kMove_Verb == prevVerb) {
    122             firstStep = step;
    123         }
    124         prevVerb = verb;
    125     }
    126 DONE:
    127     return true;
    128 }
    129 
    130 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
    131     this->INHERITED::flatten(buffer);
    132     buffer.writeScalar(fRadius);
    133 }
    134 
    135 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
    136     fRadius = buffer.readScalar();
    137 }
    138