1 /* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 9 #include "SkCornerPathEffect.h" 10 #include "SkPath.h" 11 #include "SkPoint.h" 12 #include "SkReadBuffer.h" 13 #include "SkWriteBuffer.h" 14 15 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) { 16 // check with ! to catch NaNs 17 if (!(radius > 0)) { 18 radius = 0; 19 } 20 fRadius = radius; 21 } 22 SkCornerPathEffect::~SkCornerPathEffect() {} 23 24 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, 25 SkPoint* step) { 26 SkScalar dist = SkPoint::Distance(a, b); 27 28 *step = b - a; 29 if (dist <= radius * 2) { 30 *step *= SK_ScalarHalf; 31 return false; 32 } else { 33 *step *= radius / dist; 34 return true; 35 } 36 } 37 38 bool SkCornerPathEffect::onFilterPath(SkPath* dst, const SkPath& src, 39 SkStrokeRec*, const SkRect*) const { 40 if (fRadius <= 0) { 41 return false; 42 } 43 44 SkPath::Iter iter(src, false); 45 SkPath::Verb verb, prevVerb = SkPath::kDone_Verb; 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 step.set(0, 0); 55 moveTo.set(0, 0); 56 firstStep.set(0, 0); 57 lastCorner.set(0, 0); 58 59 for (;;) { 60 switch (verb = iter.next(pts, false)) { 61 case SkPath::kMove_Verb: 62 // close out the previous (open) contour 63 if (SkPath::kLine_Verb == prevVerb) { 64 dst->lineTo(lastCorner); 65 } 66 closed = iter.isClosedContour(); 67 if (closed) { 68 moveTo = pts[0]; 69 prevIsValid = false; 70 } else { 71 dst->moveTo(pts[0]); 72 prevIsValid = true; 73 } 74 break; 75 case SkPath::kLine_Verb: { 76 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step); 77 // prev corner 78 if (!prevIsValid) { 79 dst->moveTo(moveTo + step); 80 prevIsValid = true; 81 } else { 82 dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, 83 pts[0].fY + step.fY); 84 } 85 if (drawSegment) { 86 dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY); 87 } 88 lastCorner = pts[1]; 89 prevIsValid = true; 90 break; 91 } 92 case SkPath::kQuad_Verb: 93 // TBD - just replicate the curve for now 94 if (!prevIsValid) { 95 dst->moveTo(pts[0]); 96 prevIsValid = true; 97 } 98 dst->quadTo(pts[1], pts[2]); 99 lastCorner = pts[2]; 100 firstStep.set(0, 0); 101 break; 102 case SkPath::kConic_Verb: 103 // TBD - just replicate the curve for now 104 if (!prevIsValid) { 105 dst->moveTo(pts[0]); 106 prevIsValid = true; 107 } 108 dst->conicTo(pts[1], pts[2], iter.conicWeight()); 109 lastCorner = pts[2]; 110 firstStep.set(0, 0); 111 break; 112 case SkPath::kCubic_Verb: 113 if (!prevIsValid) { 114 dst->moveTo(pts[0]); 115 prevIsValid = true; 116 } 117 // TBD - just replicate the curve for now 118 dst->cubicTo(pts[1], pts[2], pts[3]); 119 lastCorner = pts[3]; 120 firstStep.set(0, 0); 121 break; 122 case SkPath::kClose_Verb: 123 if (firstStep.fX || firstStep.fY) { 124 dst->quadTo(lastCorner.fX, lastCorner.fY, 125 lastCorner.fX + firstStep.fX, 126 lastCorner.fY + firstStep.fY); 127 } 128 dst->close(); 129 prevIsValid = false; 130 break; 131 case SkPath::kDone_Verb: 132 if (prevIsValid) { 133 dst->lineTo(lastCorner); 134 } 135 return true; 136 default: 137 SkDEBUGFAIL("default should not be reached"); 138 return false; 139 } 140 141 if (SkPath::kMove_Verb == prevVerb) { 142 firstStep = step; 143 } 144 prevVerb = verb; 145 } 146 147 return true; 148 } 149 150 sk_sp<SkFlattenable> SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) { 151 return SkCornerPathEffect::Make(buffer.readScalar()); 152 } 153 154 void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const { 155 buffer.writeScalar(fRadius); 156 } 157