1 /* libs/graphics/effects/SkCornerPathEffect.cpp 2 ** 3 ** Copyright 2006, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include "SkCornerPathEffect.h" 19 #include "SkPath.h" 20 #include "SkPoint.h" 21 #include "SkBuffer.h" 22 23 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) 24 { 25 } 26 27 SkCornerPathEffect::~SkCornerPathEffect() 28 { 29 } 30 31 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, 32 SkPoint* step) { 33 SkScalar dist = SkPoint::Distance(a, b); 34 35 step->set(b.fX - a.fX, b.fY - a.fY); 36 37 if (dist <= radius * 2) { 38 step->scale(SK_ScalarHalf); 39 return false; 40 } else { 41 step->scale(SkScalarDiv(radius, dist)); 42 return true; 43 } 44 } 45 46 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, 47 SkScalar* width) { 48 if (fRadius == 0) { 49 return false; 50 } 51 52 SkPath::Iter iter(src, false); 53 SkPath::Verb verb, prevVerb = (SkPath::Verb)-1; 54 SkPoint pts[4]; 55 56 bool closed; 57 SkPoint moveTo, lastCorner; 58 SkVector firstStep, step; 59 bool prevIsValid = true; 60 61 // to avoid warnings 62 moveTo.set(0, 0); 63 firstStep.set(0, 0); 64 lastCorner.set(0, 0); 65 66 for (;;) { 67 switch (verb = iter.next(pts)) { 68 case SkPath::kMove_Verb: 69 // close out the previous (open) contour 70 if (SkPath::kLine_Verb == prevVerb) { 71 dst->lineTo(lastCorner); 72 } 73 closed = iter.isClosedContour(); 74 if (closed) { 75 moveTo = pts[0]; 76 prevIsValid = false; 77 } else { 78 dst->moveTo(pts[0]); 79 prevIsValid = true; 80 } 81 break; 82 case SkPath::kLine_Verb: { 83 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step); 84 // prev corner 85 if (!prevIsValid) { 86 dst->moveTo(moveTo + step); 87 prevIsValid = true; 88 } else { 89 dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, 90 pts[0].fY + step.fY); 91 } 92 if (drawSegment) { 93 dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY); 94 } 95 lastCorner = pts[1]; 96 prevIsValid = true; 97 break; 98 } 99 case SkPath::kQuad_Verb: 100 // TBD - just replicate the curve for now 101 if (!prevIsValid) { 102 dst->moveTo(pts[0]); 103 prevIsValid = true; 104 } 105 dst->quadTo(pts[1], pts[2]); 106 lastCorner = pts[2]; 107 firstStep.set(0, 0); 108 break; 109 case SkPath::kCubic_Verb: 110 if (!prevIsValid) { 111 dst->moveTo(pts[0]); 112 prevIsValid = true; 113 } 114 // TBD - just replicate the curve for now 115 dst->cubicTo(pts[1], pts[2], pts[3]); 116 lastCorner = pts[3]; 117 firstStep.set(0, 0); 118 break; 119 case SkPath::kClose_Verb: 120 if (firstStep.fX || firstStep.fY) { 121 dst->quadTo(lastCorner.fX, lastCorner.fY, 122 lastCorner.fX + firstStep.fX, 123 lastCorner.fY + firstStep.fY); 124 } 125 dst->close(); 126 break; 127 case SkPath::kDone_Verb: 128 goto DONE; 129 } 130 131 if (SkPath::kMove_Verb == prevVerb) { 132 firstStep = step; 133 } 134 prevVerb = verb; 135 } 136 DONE: 137 return true; 138 } 139 140 SkFlattenable::Factory SkCornerPathEffect::getFactory() { 141 return CreateProc; 142 } 143 144 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) { 145 buffer.writeScalar(fRadius); 146 } 147 148 SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) { 149 return SkNEW_ARGS(SkCornerPathEffect, (buffer)); 150 } 151 152 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) { 153 fRadius = buffer.readScalar(); 154 } 155 156