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->set(b.fX - a.fX, b.fY - a.fY);
     24 
     25     if (dist <= radius * 2) {
     26         step->scale(SK_ScalarHalf);
     27         return false;
     28     } else {
     29         step->scale(SkScalarDiv(radius, dist));
     30         return true;
     31     }
     32 }
     33 
     34 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
     35                                     SkStrokeRec*, const SkRect*) const {
     36     if (0 == fRadius) {
     37         return false;
     38     }
     39 
     40     SkPath::Iter    iter(src, false);
     41     SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
     42     SkPoint         pts[4];
     43 
     44     bool        closed;
     45     SkPoint     moveTo, lastCorner;
     46     SkVector    firstStep, step;
     47     bool        prevIsValid = true;
     48 
     49     // to avoid warnings
     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::kCubic_Verb:
     98                 if (!prevIsValid) {
     99                     dst->moveTo(pts[0]);
    100                     prevIsValid = true;
    101                 }
    102                 // TBD - just replicate the curve for now
    103                 dst->cubicTo(pts[1], pts[2], pts[3]);
    104                 lastCorner = pts[3];
    105                 firstStep.set(0, 0);
    106                 break;
    107             case SkPath::kClose_Verb:
    108                 if (firstStep.fX || firstStep.fY) {
    109                     dst->quadTo(lastCorner.fX, lastCorner.fY,
    110                                 lastCorner.fX + firstStep.fX,
    111                                 lastCorner.fY + firstStep.fY);
    112                     }
    113                 dst->close();
    114                 break;
    115             case SkPath::kConic_Verb:
    116                 SkASSERT(0);
    117                 break;
    118             case SkPath::kDone_Verb:
    119                 goto DONE;
    120         }
    121 
    122         if (SkPath::kMove_Verb == prevVerb) {
    123             firstStep = step;
    124         }
    125         prevVerb = verb;
    126     }
    127 DONE:
    128     return true;
    129 }
    130 
    131 void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
    132     this->INHERITED::flatten(buffer);
    133     buffer.writeScalar(fRadius);
    134 }
    135 
    136 SkCornerPathEffect::SkCornerPathEffect(SkReadBuffer& buffer) {
    137     fRadius = buffer.readScalar();
    138 }
    139