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