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, SkPoint* step) 32 { 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 } 41 else { 42 step->scale(SkScalarDiv(radius, dist)); 43 return true; 44 } 45 } 46 47 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) 48 { 49 if (fRadius == 0) 50 return false; 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 } 78 else { 79 dst->moveTo(pts[0]); 80 prevIsValid = true; 81 } 82 break; 83 case SkPath::kLine_Verb: 84 { 85 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step); 86 // prev corner 87 if (!prevIsValid) { 88 dst->moveTo(moveTo + step); 89 prevIsValid = true; 90 } 91 else { 92 dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, pts[0].fY + step.fY); 93 } 94 if (drawSegment) { 95 dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY); 96 } 97 lastCorner = pts[1]; 98 prevIsValid = true; 99 } 100 break; 101 case SkPath::kQuad_Verb: 102 // TBD - just replicate the curve for now 103 if (!prevIsValid) 104 { 105 dst->moveTo(pts[0]); 106 prevIsValid = true; 107 } 108 dst->quadTo(pts[1], pts[2]); 109 lastCorner = pts[2]; 110 firstStep.set(0, 0); 111 break; 112 case SkPath::kCubic_Verb: 113 if (!prevIsValid) 114 { 115 dst->moveTo(pts[0]); 116 prevIsValid = true; 117 } 118 // TBD - just replicate the curve for now 119 dst->cubicTo(pts[1], pts[2], pts[3]); 120 lastCorner = pts[3]; 121 firstStep.set(0, 0); 122 break; 123 case SkPath::kClose_Verb: 124 if (firstStep.fX || firstStep.fY) 125 dst->quadTo(lastCorner.fX, lastCorner.fY, 126 lastCorner.fX + firstStep.fX, 127 lastCorner.fY + firstStep.fY); 128 dst->close(); 129 break; 130 case SkPath::kDone_Verb: 131 goto DONE; 132 } 133 134 if (SkPath::kMove_Verb == prevVerb) 135 firstStep = step; 136 prevVerb = verb; 137 } 138 DONE: 139 return true; 140 } 141 142 SkFlattenable::Factory SkCornerPathEffect::getFactory() 143 { 144 return CreateProc; 145 } 146 147 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) 148 { 149 buffer.writeScalar(fRadius); 150 } 151 152 SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) 153 { 154 return SkNEW_ARGS(SkCornerPathEffect, (buffer)); 155 } 156 157 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) 158 { 159 fRadius = buffer.readScalar(); 160 } 161 162