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 "SkReadBuffer.h" 14 #include "SkWriteBuffer.h" 15 16 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {} 17 SkCornerPathEffect::~SkCornerPathEffect() {} 18 19 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, 20 SkPoint* step) { 21 SkScalar dist = SkPoint::Distance(a, b); 22 23 *step = b - a; 24 if (dist <= radius * 2) { 25 *step *= SK_ScalarHalf; 26 return false; 27 } else { 28 *step *= 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 step.set(0, 0); 50 moveTo.set(0, 0); 51 firstStep.set(0, 0); 52 lastCorner.set(0, 0); 53 54 for (;;) { 55 switch (verb = iter.next(pts, false)) { 56 case SkPath::kMove_Verb: 57 // close out the previous (open) contour 58 if (SkPath::kLine_Verb == prevVerb) { 59 dst->lineTo(lastCorner); 60 } 61 closed = iter.isClosedContour(); 62 if (closed) { 63 moveTo = pts[0]; 64 prevIsValid = false; 65 } else { 66 dst->moveTo(pts[0]); 67 prevIsValid = true; 68 } 69 break; 70 case SkPath::kLine_Verb: { 71 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step); 72 // prev corner 73 if (!prevIsValid) { 74 dst->moveTo(moveTo + step); 75 prevIsValid = true; 76 } else { 77 dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, 78 pts[0].fY + step.fY); 79 } 80 if (drawSegment) { 81 dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY); 82 } 83 lastCorner = pts[1]; 84 prevIsValid = true; 85 break; 86 } 87 case SkPath::kQuad_Verb: 88 // TBD - just replicate the curve for now 89 if (!prevIsValid) { 90 dst->moveTo(pts[0]); 91 prevIsValid = true; 92 } 93 dst->quadTo(pts[1], pts[2]); 94 lastCorner = pts[2]; 95 firstStep.set(0, 0); 96 break; 97 case SkPath::kConic_Verb: 98 // TBD - just replicate the curve for now 99 if (!prevIsValid) { 100 dst->moveTo(pts[0]); 101 prevIsValid = true; 102 } 103 dst->conicTo(pts[1], pts[2], iter.conicWeight()); 104 lastCorner = pts[2]; 105 firstStep.set(0, 0); 106 break; 107 case SkPath::kCubic_Verb: 108 if (!prevIsValid) { 109 dst->moveTo(pts[0]); 110 prevIsValid = true; 111 } 112 // TBD - just replicate the curve for now 113 dst->cubicTo(pts[1], pts[2], pts[3]); 114 lastCorner = pts[3]; 115 firstStep.set(0, 0); 116 break; 117 case SkPath::kClose_Verb: 118 if (firstStep.fX || firstStep.fY) { 119 dst->quadTo(lastCorner.fX, lastCorner.fY, 120 lastCorner.fX + firstStep.fX, 121 lastCorner.fY + firstStep.fY); 122 } 123 dst->close(); 124 prevIsValid = false; 125 break; 126 case SkPath::kDone_Verb: 127 if (prevIsValid) { 128 dst->lineTo(lastCorner); 129 } 130 goto DONE; 131 } 132 133 if (SkPath::kMove_Verb == prevVerb) { 134 firstStep = step; 135 } 136 prevVerb = verb; 137 } 138 DONE: 139 return true; 140 } 141 142 SkFlattenable* SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) { 143 return SkCornerPathEffect::Create(buffer.readScalar()); 144 } 145 146 void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const { 147 buffer.writeScalar(fRadius); 148 } 149 150 #ifndef SK_IGNORE_TO_STRING 151 void SkCornerPathEffect::toString(SkString* str) const { 152 str->appendf("SkCornerPathEffect: ("); 153 str->appendf("radius: %.2f", fRadius); 154 str->appendf(")"); 155 } 156 #endif 157