| OLD | NEW |
| (Empty) |
| 1 /* libs/graphics/sgl/SkStrokerPriv.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 "SkStrokerPriv.h" | |
| 19 #include "SkGeometry.h" | |
| 20 #include "SkPath.h" | |
| 21 | |
| 22 static void ButtCapper(SkPath* path, const SkPoint& pivot, | |
| 23 const SkVector& normal, const SkPoint& stop, | |
| 24 SkPath*) | |
| 25 { | |
| 26 path->lineTo(stop.fX, stop.fY); | |
| 27 } | |
| 28 | |
| 29 static void RoundCapper(SkPath* path, const SkPoint& pivot, | |
| 30 const SkVector& normal, const SkPoint& stop, | |
| 31 SkPath*) | |
| 32 { | |
| 33 SkScalar px = pivot.fX; | |
| 34 SkScalar py = pivot.fY; | |
| 35 SkScalar nx = normal.fX; | |
| 36 SkScalar ny = normal.fY; | |
| 37 SkScalar sx = SkScalarMul(nx, CUBIC_ARC_FACTOR); | |
| 38 SkScalar sy = SkScalarMul(ny, CUBIC_ARC_FACTOR); | |
| 39 | |
| 40 path->cubicTo(px + nx + CWX(sx, sy), py + ny + CWY(sx, sy), | |
| 41 px + CWX(nx, ny) + sx, py + CWY(nx, ny) + sy, | |
| 42 px + CWX(nx, ny), py + CWY(nx, ny)); | |
| 43 path->cubicTo(px + CWX(nx, ny) - sx, py + CWY(nx, ny) - sy, | |
| 44 px - nx + CWX(sx, sy), py - ny + CWY(sx, sy), | |
| 45 stop.fX, stop.fY); | |
| 46 } | |
| 47 | |
| 48 static void SquareCapper(SkPath* path, const SkPoint& pivot, | |
| 49 const SkVector& normal, const SkPoint& stop, | |
| 50 SkPath* otherPath) | |
| 51 { | |
| 52 SkVector parallel; | |
| 53 normal.rotateCW(¶llel); | |
| 54 | |
| 55 if (otherPath) | |
| 56 { | |
| 57 path->setLastPt(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY
+ parallel.fY); | |
| 58 path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY +
parallel.fY); | |
| 59 } | |
| 60 else | |
| 61 { | |
| 62 path->lineTo(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY +
parallel.fY); | |
| 63 path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY +
parallel.fY); | |
| 64 path->lineTo(stop.fX, stop.fY); | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 ///////////////////////////////////////////////////////////////////////////// | |
| 69 | |
| 70 static bool is_clockwise(const SkVector& before, const SkVector& after) | |
| 71 { | |
| 72 return SkScalarMul(before.fX, after.fY) - SkScalarMul(before.fY, after.fX) >
0; | |
| 73 } | |
| 74 | |
| 75 enum AngleType { | |
| 76 kNearly180_AngleType, | |
| 77 kSharp_AngleType, | |
| 78 kShallow_AngleType, | |
| 79 kNearlyLine_AngleType | |
| 80 }; | |
| 81 | |
| 82 static AngleType Dot2AngleType(SkScalar dot) | |
| 83 { | |
| 84 // need more precise fixed normalization | |
| 85 // SkASSERT(SkScalarAbs(dot) <= SK_Scalar1 + SK_ScalarNearlyZero); | |
| 86 | |
| 87 if (dot >= 0) // shallow or line | |
| 88 return SkScalarNearlyZero(SK_Scalar1 - dot) ? kNearlyLine_AngleType : kS
hallow_AngleType; | |
| 89 else // sharp or 180 | |
| 90 return SkScalarNearlyZero(SK_Scalar1 + dot) ? kNearly180_AngleType : kSh
arp_AngleType; | |
| 91 } | |
| 92 | |
| 93 static void HandleInnerJoin(SkPath* inner, const SkPoint& pivot, const SkVector&
after) | |
| 94 { | |
| 95 #if 1 | |
| 96 /* In the degenerate case that the stroke radius is larger than our segment
s | |
| 97 just connecting the two inner segments may "show through" as a funny | |
| 98 diagonal. To pseudo-fix this, we go through the pivot point. This adds | |
| 99 an extra point/edge, but I can't see a cheap way to know when this is | |
| 100 not needed :( | |
| 101 */ | |
| 102 inner->lineTo(pivot.fX, pivot.fY); | |
| 103 #endif | |
| 104 | |
| 105 inner->lineTo(pivot.fX - after.fX, pivot.fY - after.fY); | |
| 106 } | |
| 107 | |
| 108 static void BluntJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnit
Normal, | |
| 109 const SkPoint& pivot, const SkVector& afterUnitNormal, | |
| 110 SkScalar radius, SkScalar invMiterLimit, bool, bool) | |
| 111 { | |
| 112 SkVector after; | |
| 113 afterUnitNormal.scale(radius, &after); | |
| 114 | |
| 115 if (!is_clockwise(beforeUnitNormal, afterUnitNormal)) | |
| 116 { | |
| 117 SkTSwap<SkPath*>(outer, inner); | |
| 118 after.negate(); | |
| 119 } | |
| 120 | |
| 121 outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY); | |
| 122 HandleInnerJoin(inner, pivot, after); | |
| 123 } | |
| 124 | |
| 125 static void RoundJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnit
Normal, | |
| 126 const SkPoint& pivot, const SkVector& afterUnitNormal, | |
| 127 SkScalar radius, SkScalar invMiterLimit, bool, bool) | |
| 128 { | |
| 129 SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal)
; | |
| 130 AngleType angleType = Dot2AngleType(dotProd); | |
| 131 | |
| 132 if (angleType == kNearlyLine_AngleType) | |
| 133 return; | |
| 134 | |
| 135 SkVector before = beforeUnitNormal; | |
| 136 SkVector after = afterUnitNormal; | |
| 137 SkRotationDirection dir = kCW_SkRotationDirection; | |
| 138 | |
| 139 if (!is_clockwise(before, after)) | |
| 140 { | |
| 141 SkTSwap<SkPath*>(outer, inner); | |
| 142 before.negate(); | |
| 143 after.negate(); | |
| 144 dir = kCCW_SkRotationDirection; | |
| 145 } | |
| 146 | |
| 147 SkPoint pts[kSkBuildQuadArcStorage]; | |
| 148 SkMatrix matrix; | |
| 149 matrix.setScale(radius, radius); | |
| 150 matrix.postTranslate(pivot.fX, pivot.fY); | |
| 151 int count = SkBuildQuadArc(before, after, dir, &matrix, pts); | |
| 152 SkASSERT((count & 1) == 1); | |
| 153 | |
| 154 if (count > 1) | |
| 155 { | |
| 156 for (int i = 1; i < count; i += 2) | |
| 157 outer->quadTo(pts[i].fX, pts[i].fY, pts[i+1].fX, pts[i+1].fY); | |
| 158 | |
| 159 after.scale(radius); | |
| 160 HandleInnerJoin(inner, pivot, after); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 #ifdef SK_SCALAR_IS_FLOAT | |
| 165 #define kOneOverSqrt2 (0.707106781f) | |
| 166 #else | |
| 167 #define kOneOverSqrt2 (46341) | |
| 168 #endif | |
| 169 | |
| 170 static void MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnit
Normal, | |
| 171 const SkPoint& pivot, const SkVector& afterUnitNormal, | |
| 172 SkScalar radius, SkScalar invMiterLimit, | |
| 173 bool prevIsLine, bool currIsLine) | |
| 174 { | |
| 175 // negate the dot since we're using normals instead of tangents | |
| 176 SkScalar dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal)
; | |
| 177 AngleType angleType = Dot2AngleType(dotProd); | |
| 178 SkVector before = beforeUnitNormal; | |
| 179 SkVector after = afterUnitNormal; | |
| 180 SkVector mid; | |
| 181 SkScalar sinHalfAngle; | |
| 182 bool ccw; | |
| 183 | |
| 184 if (angleType == kNearlyLine_AngleType) | |
| 185 return; | |
| 186 if (angleType == kNearly180_AngleType) | |
| 187 { | |
| 188 currIsLine = false; | |
| 189 goto DO_BLUNT; | |
| 190 } | |
| 191 | |
| 192 ccw = !is_clockwise(before, after); | |
| 193 if (ccw) | |
| 194 { | |
| 195 SkTSwap<SkPath*>(outer, inner); | |
| 196 before.negate(); | |
| 197 after.negate(); | |
| 198 } | |
| 199 | |
| 200 /* Before we enter the world of square-roots and divides, | |
| 201 check if we're trying to join an upright right angle | |
| 202 (common case for stroking rectangles). If so, special case | |
| 203 that (for speed an accuracy). | |
| 204 Note: we only need to check one normal if dot==0 | |
| 205 */ | |
| 206 if (0 == dotProd && invMiterLimit <= kOneOverSqrt2) | |
| 207 { | |
| 208 mid.set(SkScalarMul(before.fX + after.fX, radius), | |
| 209 SkScalarMul(before.fY + after.fY, radius)); | |
| 210 goto DO_MITER; | |
| 211 } | |
| 212 | |
| 213 /* midLength = radius / sinHalfAngle | |
| 214 if (midLength > miterLimit * radius) abort | |
| 215 if (radius / sinHalf > miterLimit * radius) abort | |
| 216 if (1 / sinHalf > miterLimit) abort | |
| 217 if (1 / miterLimit > sinHalf) abort | |
| 218 My dotProd is opposite sign, since it is built from normals and not tang
ents | |
| 219 hence 1 + dot instead of 1 - dot in the formula | |
| 220 */ | |
| 221 sinHalfAngle = SkScalarSqrt(SkScalarHalf(SK_Scalar1 + dotProd)); | |
| 222 if (sinHalfAngle < invMiterLimit) | |
| 223 { | |
| 224 currIsLine = false; | |
| 225 goto DO_BLUNT; | |
| 226 } | |
| 227 | |
| 228 // choose the most accurate way to form the initial mid-vector | |
| 229 if (angleType == kSharp_AngleType) | |
| 230 { | |
| 231 mid.set(after.fY - before.fY, before.fX - after.fX); | |
| 232 if (ccw) | |
| 233 mid.negate(); | |
| 234 } | |
| 235 else | |
| 236 mid.set(before.fX + after.fX, before.fY + after.fY); | |
| 237 | |
| 238 mid.setLength(SkScalarDiv(radius, sinHalfAngle)); | |
| 239 DO_MITER: | |
| 240 if (prevIsLine) | |
| 241 outer->setLastPt(pivot.fX + mid.fX, pivot.fY + mid.fY); | |
| 242 else | |
| 243 outer->lineTo(pivot.fX + mid.fX, pivot.fY + mid.fY); | |
| 244 | |
| 245 DO_BLUNT: | |
| 246 after.scale(radius); | |
| 247 if (!currIsLine) | |
| 248 outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY); | |
| 249 HandleInnerJoin(inner, pivot, after); | |
| 250 } | |
| 251 | |
| 252 ///////////////////////////////////////////////////////////////////////////// | |
| 253 | |
| 254 SkStrokerPriv::CapProc SkStrokerPriv::CapFactory(SkPaint::Cap cap) | |
| 255 { | |
| 256 static const SkStrokerPriv::CapProc gCappers[] = { | |
| 257 ButtCapper, RoundCapper, SquareCapper | |
| 258 }; | |
| 259 | |
| 260 SkASSERT((unsigned)cap < SkPaint::kCapCount); | |
| 261 return gCappers[cap]; | |
| 262 } | |
| 263 | |
| 264 SkStrokerPriv::JoinProc SkStrokerPriv::JoinFactory(SkPaint::Join join) | |
| 265 { | |
| 266 static const SkStrokerPriv::JoinProc gJoiners[] = { | |
| 267 MiterJoiner, RoundJoiner, BluntJoiner | |
| 268 }; | |
| 269 | |
| 270 SkASSERT((unsigned)join < SkPaint::kJoinCount); | |
| 271 return gJoiners[join]; | |
| 272 } | |
| 273 | |
| 274 | |
| 275 | |
| OLD | NEW |