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, SkPoint* step)
     32 {
     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     }
     41     else {
     42         step->scale(SkScalarDiv(radius, dist));
     43         return true;
     44     }
     45 }
     46 
     47 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
     48 {
     49     if (fRadius == 0)
     50         return false;
     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             }
     78             else {
     79                 dst->moveTo(pts[0]);
     80                 prevIsValid = true;
     81             }
     82             break;
     83         case SkPath::kLine_Verb:
     84             {
     85                 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
     86                 // prev corner
     87                 if (!prevIsValid) {
     88                     dst->moveTo(moveTo + step);
     89                     prevIsValid = true;
     90                 }
     91                 else {
     92                     dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, pts[0].fY + step.fY);
     93                 }
     94                 if (drawSegment) {
     95                     dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
     96                 }
     97                 lastCorner = pts[1];
     98                 prevIsValid = true;
     99             }
    100             break;
    101         case SkPath::kQuad_Verb:
    102             // TBD - just replicate the curve for now
    103             if (!prevIsValid)
    104             {
    105                 dst->moveTo(pts[0]);
    106                 prevIsValid = true;
    107             }
    108             dst->quadTo(pts[1], pts[2]);
    109             lastCorner = pts[2];
    110             firstStep.set(0, 0);
    111             break;
    112         case SkPath::kCubic_Verb:
    113             if (!prevIsValid)
    114             {
    115                 dst->moveTo(pts[0]);
    116                 prevIsValid = true;
    117             }
    118             // TBD - just replicate the curve for now
    119             dst->cubicTo(pts[1], pts[2], pts[3]);
    120             lastCorner = pts[3];
    121             firstStep.set(0, 0);
    122             break;
    123         case SkPath::kClose_Verb:
    124             if (firstStep.fX || firstStep.fY)
    125                 dst->quadTo(lastCorner.fX, lastCorner.fY,
    126                             lastCorner.fX + firstStep.fX,
    127                             lastCorner.fY + firstStep.fY);
    128             dst->close();
    129             break;
    130         case SkPath::kDone_Verb:
    131             goto DONE;
    132         }
    133 
    134         if (SkPath::kMove_Verb == prevVerb)
    135             firstStep = step;
    136         prevVerb = verb;
    137     }
    138 DONE:
    139     return true;
    140 }
    141 
    142 SkFlattenable::Factory SkCornerPathEffect::getFactory()
    143 {
    144     return CreateProc;
    145 }
    146 
    147 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer)
    148 {
    149     buffer.writeScalar(fRadius);
    150 }
    151 
    152 SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer)
    153 {
    154     return SkNEW_ARGS(SkCornerPathEffect, (buffer));
    155 }
    156 
    157 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer)
    158 {
    159     fRadius = buffer.readScalar();
    160 }
    161 
    162