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 15SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {} 16SkCornerPathEffect::~SkCornerPathEffect() {} 17 18static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, 19 SkPoint* step) { 20 SkScalar dist = SkPoint::Distance(a, b); 21 22 *step = b - a; 23 if (dist <= radius * 2) { 24 *step *= SK_ScalarHalf; 25 return false; 26 } else { 27 *step *= radius / dist; 28 return true; 29 } 30} 31 32bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, 33 SkStrokeRec*, const SkRect*) const { 34 if (0 == fRadius) { 35 return false; 36 } 37 38 SkPath::Iter iter(src, false); 39 SkPath::Verb verb, prevVerb = (SkPath::Verb)-1; 40 SkPoint pts[4]; 41 42 bool closed; 43 SkPoint moveTo, lastCorner; 44 SkVector firstStep, step; 45 bool prevIsValid = true; 46 47 // to avoid warnings 48 step.set(0, 0); 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::kConic_Verb: 97 // TBD - just replicate the curve for now 98 if (!prevIsValid) { 99 dst->moveTo(pts[0]); 100 prevIsValid = true; 101 } 102 dst->conicTo(pts[1], pts[2], iter.conicWeight()); 103 lastCorner = pts[2]; 104 firstStep.set(0, 0); 105 break; 106 case SkPath::kCubic_Verb: 107 if (!prevIsValid) { 108 dst->moveTo(pts[0]); 109 prevIsValid = true; 110 } 111 // TBD - just replicate the curve for now 112 dst->cubicTo(pts[1], pts[2], pts[3]); 113 lastCorner = pts[3]; 114 firstStep.set(0, 0); 115 break; 116 case SkPath::kClose_Verb: 117 if (firstStep.fX || firstStep.fY) { 118 dst->quadTo(lastCorner.fX, lastCorner.fY, 119 lastCorner.fX + firstStep.fX, 120 lastCorner.fY + firstStep.fY); 121 } 122 dst->close(); 123 prevIsValid = false; 124 break; 125 case SkPath::kDone_Verb: 126 if (prevIsValid) { 127 dst->lineTo(lastCorner); 128 } 129 goto DONE; 130 } 131 132 if (SkPath::kMove_Verb == prevVerb) { 133 firstStep = step; 134 } 135 prevVerb = verb; 136 } 137DONE: 138 return true; 139} 140 141sk_sp<SkFlattenable> SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) { 142 return SkCornerPathEffect::Make(buffer.readScalar()); 143} 144 145void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const { 146 buffer.writeScalar(fRadius); 147} 148 149#ifndef SK_IGNORE_TO_STRING 150void SkCornerPathEffect::toString(SkString* str) const { 151 str->appendf("SkCornerPathEffect: ("); 152 str->appendf("radius: %.2f", fRadius); 153 str->appendf(")"); 154} 155#endif 156