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