Home | History | Annotate | Download | only in effects
      1 /* libs/graphics/effects/SkCornerPathEffect.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #include "SkCornerPathEffect.h"
     19 #include "SkPath.h"
     20 #include "SkPoint.h"
     21 #include "SkBuffer.h"
     22 
     23 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius)
     24 {
     25 }
     26 
     27 SkCornerPathEffect::~SkCornerPathEffect()
     28 {
     29 }
     30 
     31 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
     32                         SkPoint* step) {
     33     SkScalar dist = SkPoint::Distance(a, b);
     34 
     35     step->set(b.fX - a.fX, b.fY - a.fY);
     36 
     37     if (dist <= radius * 2) {
     38         step->scale(SK_ScalarHalf);
     39         return false;
     40     } else {
     41         step->scale(SkScalarDiv(radius, dist));
     42         return true;
     43     }
     44 }
     45 
     46 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
     47                                     SkScalar* width) {
     48     if (fRadius == 0) {
     49         return false;
     50     }
     51 
     52     SkPath::Iter    iter(src, false);
     53     SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
     54     SkPoint         pts[4];
     55 
     56     bool        closed;
     57     SkPoint     moveTo, lastCorner;
     58     SkVector    firstStep, step;
     59     bool        prevIsValid = true;
     60 
     61     // to avoid warnings
     62     moveTo.set(0, 0);
     63     firstStep.set(0, 0);
     64     lastCorner.set(0, 0);
     65 
     66     for (;;) {
     67         switch (verb = iter.next(pts)) {
     68             case SkPath::kMove_Verb:
     69                     // close out the previous (open) contour
     70                 if (SkPath::kLine_Verb == prevVerb) {
     71                     dst->lineTo(lastCorner);
     72                 }
     73                 closed = iter.isClosedContour();
     74                 if (closed) {
     75                     moveTo = pts[0];
     76                     prevIsValid = false;
     77                 } else {
     78                     dst->moveTo(pts[0]);
     79                     prevIsValid = true;
     80                 }
     81                 break;
     82             case SkPath::kLine_Verb: {
     83                 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
     84                 // prev corner
     85                 if (!prevIsValid) {
     86                     dst->moveTo(moveTo + step);
     87                     prevIsValid = true;
     88                 } else {
     89                     dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
     90                                 pts[0].fY + step.fY);
     91                 }
     92                 if (drawSegment) {
     93                     dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
     94                 }
     95                 lastCorner = pts[1];
     96                 prevIsValid = true;
     97                 break;
     98             }
     99             case SkPath::kQuad_Verb:
    100                 // TBD - just replicate the curve for now
    101                 if (!prevIsValid) {
    102                     dst->moveTo(pts[0]);
    103                     prevIsValid = true;
    104                 }
    105                 dst->quadTo(pts[1], pts[2]);
    106                 lastCorner = pts[2];
    107                 firstStep.set(0, 0);
    108                 break;
    109             case SkPath::kCubic_Verb:
    110                 if (!prevIsValid) {
    111                     dst->moveTo(pts[0]);
    112                     prevIsValid = true;
    113                 }
    114                 // TBD - just replicate the curve for now
    115                 dst->cubicTo(pts[1], pts[2], pts[3]);
    116                 lastCorner = pts[3];
    117                 firstStep.set(0, 0);
    118                 break;
    119             case SkPath::kClose_Verb:
    120                 if (firstStep.fX || firstStep.fY) {
    121                     dst->quadTo(lastCorner.fX, lastCorner.fY,
    122                                 lastCorner.fX + firstStep.fX,
    123                                 lastCorner.fY + firstStep.fY);
    124                     }
    125                 dst->close();
    126                 break;
    127             case SkPath::kDone_Verb:
    128                 goto DONE;
    129         }
    130 
    131         if (SkPath::kMove_Verb == prevVerb) {
    132             firstStep = step;
    133         }
    134         prevVerb = verb;
    135     }
    136 DONE:
    137     return true;
    138 }
    139 
    140 SkFlattenable::Factory SkCornerPathEffect::getFactory() {
    141     return CreateProc;
    142 }
    143 
    144 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
    145     buffer.writeScalar(fRadius);
    146 }
    147 
    148 SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) {
    149     return SkNEW_ARGS(SkCornerPathEffect, (buffer));
    150 }
    151 
    152 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
    153     fRadius = buffer.readScalar();
    154 }
    155 
    156