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 15SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) 16{ 17} 18 19SkCornerPathEffect::~SkCornerPathEffect() 20{ 21} 22 23static 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 38bool 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 } 128DONE: 129 return true; 130} 131 132SkFlattenable::Factory SkCornerPathEffect::getFactory() { 133 return CreateProc; 134} 135 136void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) { 137 buffer.writeScalar(fRadius); 138} 139 140SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) { 141 return SkNEW_ARGS(SkCornerPathEffect, (buffer)); 142} 143 144SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) { 145 fRadius = buffer.readScalar(); 146} 147 148SK_DEFINE_FLATTENABLE_REGISTRAR(SkCornerPathEffect) 149 150