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 "SkReadBuffer.h"
     14 #include "SkWriteBuffer.h"
     15 
     16 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {}
     17 SkCornerPathEffect::~SkCornerPathEffect() {}
     18 
     19 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
     20                         SkPoint* step) {
     21     SkScalar dist = SkPoint::Distance(a, b);
     22 
     23     *step = b - a;
     24     if (dist <= radius * 2) {
     25         *step *= SK_ScalarHalf;
     26         return false;
     27     } else {
     28         *step *= 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     step.set(0, 0);
     50     moveTo.set(0, 0);
     51     firstStep.set(0, 0);
     52     lastCorner.set(0, 0);
     53 
     54     for (;;) {
     55         switch (verb = iter.next(pts, false)) {
     56             case SkPath::kMove_Verb:
     57                     // close out the previous (open) contour
     58                 if (SkPath::kLine_Verb == prevVerb) {
     59                     dst->lineTo(lastCorner);
     60                 }
     61                 closed = iter.isClosedContour();
     62                 if (closed) {
     63                     moveTo = pts[0];
     64                     prevIsValid = false;
     65                 } else {
     66                     dst->moveTo(pts[0]);
     67                     prevIsValid = true;
     68                 }
     69                 break;
     70             case SkPath::kLine_Verb: {
     71                 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
     72                 // prev corner
     73                 if (!prevIsValid) {
     74                     dst->moveTo(moveTo + step);
     75                     prevIsValid = true;
     76                 } else {
     77                     dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
     78                                 pts[0].fY + step.fY);
     79                 }
     80                 if (drawSegment) {
     81                     dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
     82                 }
     83                 lastCorner = pts[1];
     84                 prevIsValid = true;
     85                 break;
     86             }
     87             case SkPath::kQuad_Verb:
     88                 // TBD - just replicate the curve for now
     89                 if (!prevIsValid) {
     90                     dst->moveTo(pts[0]);
     91                     prevIsValid = true;
     92                 }
     93                 dst->quadTo(pts[1], pts[2]);
     94                 lastCorner = pts[2];
     95                 firstStep.set(0, 0);
     96                 break;
     97             case SkPath::kConic_Verb:
     98                 // TBD - just replicate the curve for now
     99                 if (!prevIsValid) {
    100                     dst->moveTo(pts[0]);
    101                     prevIsValid = true;
    102                 }
    103                 dst->conicTo(pts[1], pts[2], iter.conicWeight());
    104                 lastCorner = pts[2];
    105                 firstStep.set(0, 0);
    106                 break;
    107             case SkPath::kCubic_Verb:
    108                 if (!prevIsValid) {
    109                     dst->moveTo(pts[0]);
    110                     prevIsValid = true;
    111                 }
    112                 // TBD - just replicate the curve for now
    113                 dst->cubicTo(pts[1], pts[2], pts[3]);
    114                 lastCorner = pts[3];
    115                 firstStep.set(0, 0);
    116                 break;
    117             case SkPath::kClose_Verb:
    118                 if (firstStep.fX || firstStep.fY) {
    119                     dst->quadTo(lastCorner.fX, lastCorner.fY,
    120                                 lastCorner.fX + firstStep.fX,
    121                                 lastCorner.fY + firstStep.fY);
    122                     }
    123                 dst->close();
    124                 prevIsValid = false;
    125                 break;
    126             case SkPath::kDone_Verb:
    127                 if (prevIsValid) {
    128                     dst->lineTo(lastCorner);
    129                 }
    130                 goto DONE;
    131         }
    132 
    133         if (SkPath::kMove_Verb == prevVerb) {
    134             firstStep = step;
    135         }
    136         prevVerb = verb;
    137     }
    138 DONE:
    139     return true;
    140 }
    141 
    142 SkFlattenable* SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) {
    143     return SkCornerPathEffect::Create(buffer.readScalar());
    144 }
    145 
    146 void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
    147     buffer.writeScalar(fRadius);
    148 }
    149 
    150 #ifndef SK_IGNORE_TO_STRING
    151 void SkCornerPathEffect::toString(SkString* str) const {
    152     str->appendf("SkCornerPathEffect: (");
    153     str->appendf("radius: %.2f", fRadius);
    154     str->appendf(")");
    155 }
    156 #endif
    157