OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2008 The Android Open Source Project | 2 * Copyright 2008 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkStrokerPriv.h" | 8 #include "SkStrokerPriv.h" |
9 #include "SkGeometry.h" | 9 #include "SkGeometry.h" |
10 #include "SkPathPriv.h" | 10 #include "SkPathPriv.h" |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 return true; | 114 return true; |
115 } | 115 } |
116 }; | 116 }; |
117 | 117 |
118 class SkPathStroker { | 118 class SkPathStroker { |
119 public: | 119 public: |
120 SkPathStroker(const SkPath& src, | 120 SkPathStroker(const SkPath& src, |
121 SkScalar radius, SkScalar miterLimit, SkPaint::Cap, | 121 SkScalar radius, SkScalar miterLimit, SkPaint::Cap, |
122 SkPaint::Join, SkScalar resScale); | 122 SkPaint::Join, SkScalar resScale); |
123 | 123 |
| 124 bool hasOnlyMoveTo() const { return 0 == fSegmentCount; } |
| 125 SkPoint moveToPt() const { return fFirstPt; } |
| 126 |
124 void moveTo(const SkPoint&); | 127 void moveTo(const SkPoint&); |
125 void lineTo(const SkPoint&); | 128 void lineTo(const SkPoint&); |
126 void quadTo(const SkPoint&, const SkPoint&); | 129 void quadTo(const SkPoint&, const SkPoint&); |
127 void conicTo(const SkPoint&, const SkPoint&, SkScalar weight); | 130 void conicTo(const SkPoint&, const SkPoint&, SkScalar weight); |
128 void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); | 131 void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); |
129 void close(bool isLine) { this->finishContour(true, isLine); } | 132 void close(bool isLine) { this->finishContour(true, isLine); } |
130 | 133 |
131 void done(SkPath* dst, bool isLine) { | 134 void done(SkPath* dst, bool isLine) { |
132 this->finishContour(false, isLine); | 135 this->finishContour(false, isLine); |
133 fOuter.addPath(fExtra); | 136 fOuter.addPath(fExtra); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 /////////////////////////////////////////////////////////////////////////////// | 238 /////////////////////////////////////////////////////////////////////////////// |
236 | 239 |
237 bool SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal, | 240 bool SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal, |
238 SkVector* unitNormal, bool currIsLine) { | 241 SkVector* unitNormal, bool currIsLine) { |
239 SkASSERT(fSegmentCount >= 0); | 242 SkASSERT(fSegmentCount >= 0); |
240 | 243 |
241 SkScalar prevX = fPrevPt.fX; | 244 SkScalar prevX = fPrevPt.fX; |
242 SkScalar prevY = fPrevPt.fY; | 245 SkScalar prevY = fPrevPt.fY; |
243 | 246 |
244 if (!set_normal_unitnormal(fPrevPt, currPt, fRadius, normal, unitNormal)) { | 247 if (!set_normal_unitnormal(fPrevPt, currPt, fRadius, normal, unitNormal)) { |
245 return false; | 248 if (SkStrokerPriv::CapFactory(SkPaint::kButt_Cap) == fCapper) { |
| 249 return false; |
| 250 } |
| 251 /* Square caps and round caps draw even if the segment length is zero. |
| 252 Since the zero length segment has no direction, set the orientation |
| 253 to upright as the default orientation */ |
| 254 normal->set(fRadius, 0); |
| 255 unitNormal->set(1, 0); |
246 } | 256 } |
247 | 257 |
248 if (fSegmentCount == 0) { | 258 if (fSegmentCount == 0) { |
249 fFirstNormal = *normal; | 259 fFirstNormal = *normal; |
250 fFirstUnitNormal = *unitNormal; | 260 fFirstUnitNormal = *unitNormal; |
251 fFirstOuterPt.set(prevX + normal->fX, prevY + normal->fY); | 261 fFirstOuterPt.set(prevX + normal->fX, prevY + normal->fY); |
252 | 262 |
253 fOuter.moveTo(fFirstOuterPt.fX, fFirstOuterPt.fY); | 263 fOuter.moveTo(fFirstOuterPt.fX, fFirstOuterPt.fY); |
254 fInner.moveTo(prevX - normal->fX, prevY - normal->fY); | 264 fInner.moveTo(prevX - normal->fX, prevY - normal->fY); |
255 } else { // we have a previous segment | 265 } else { // we have a previous segment |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 fSegmentCount = 0; | 359 fSegmentCount = 0; |
350 fFirstPt = fPrevPt = pt; | 360 fFirstPt = fPrevPt = pt; |
351 } | 361 } |
352 | 362 |
353 void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { | 363 void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { |
354 fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY); | 364 fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY); |
355 fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY); | 365 fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY); |
356 } | 366 } |
357 | 367 |
358 void SkPathStroker::lineTo(const SkPoint& currPt) { | 368 void SkPathStroker::lineTo(const SkPoint& currPt) { |
359 if (SkPath::IsLineDegenerate(fPrevPt, currPt, false)) { | 369 if (SkStrokerPriv::CapFactory(SkPaint::kButt_Cap) == fCapper |
| 370 && SkPath::IsLineDegenerate(fPrevPt, currPt, false)) { |
360 return; | 371 return; |
361 } | 372 } |
362 SkVector normal, unitNormal; | 373 SkVector normal, unitNormal; |
363 | 374 |
364 if (!this->preJoinTo(currPt, &normal, &unitNormal, true)) { | 375 if (!this->preJoinTo(currPt, &normal, &unitNormal, true)) { |
365 return; | 376 return; |
366 } | 377 } |
367 this->line_to(currPt, normal); | 378 this->line_to(currPt, normal); |
368 this->postJoinTo(currPt, normal, unitNormal); | 379 this->postJoinTo(currPt, normal, unitNormal); |
369 } | 380 } |
(...skipping 957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1327 case SkPath::kConic_Verb: { | 1338 case SkPath::kConic_Verb: { |
1328 stroker.conicTo(pts[1], pts[2], iter.conicWeight()); | 1339 stroker.conicTo(pts[1], pts[2], iter.conicWeight()); |
1329 lastSegment = SkPath::kConic_Verb; | 1340 lastSegment = SkPath::kConic_Verb; |
1330 break; | 1341 break; |
1331 } break; | 1342 } break; |
1332 case SkPath::kCubic_Verb: | 1343 case SkPath::kCubic_Verb: |
1333 stroker.cubicTo(pts[1], pts[2], pts[3]); | 1344 stroker.cubicTo(pts[1], pts[2], pts[3]); |
1334 lastSegment = SkPath::kCubic_Verb; | 1345 lastSegment = SkPath::kCubic_Verb; |
1335 break; | 1346 break; |
1336 case SkPath::kClose_Verb: | 1347 case SkPath::kClose_Verb: |
| 1348 if (stroker.hasOnlyMoveTo() && SkPaint::kButt_Cap != this->getCa
p()) { |
| 1349 /* If the stroke consists of a moveTo followed by a close, t
reat it |
| 1350 as if it were followed by a zero-length line. Lines witho
ut length |
| 1351 can have square and round end caps. */ |
| 1352 stroker.lineTo(stroker.moveToPt()); |
| 1353 lastSegment = SkPath::kLine_Verb; |
| 1354 break; |
| 1355 } |
1337 stroker.close(lastSegment == SkPath::kLine_Verb); | 1356 stroker.close(lastSegment == SkPath::kLine_Verb); |
1338 break; | 1357 break; |
1339 case SkPath::kDone_Verb: | 1358 case SkPath::kDone_Verb: |
1340 goto DONE; | 1359 goto DONE; |
1341 } | 1360 } |
1342 } | 1361 } |
1343 DONE: | 1362 DONE: |
1344 stroker.done(dst, lastSegment == SkPath::kLine_Verb); | 1363 stroker.done(dst, lastSegment == SkPath::kLine_Verb); |
1345 | 1364 |
1346 if (fDoFill) { | 1365 if (fDoFill) { |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1450 default: | 1469 default: |
1451 break; | 1470 break; |
1452 } | 1471 } |
1453 | 1472 |
1454 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { | 1473 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { |
1455 r = rect; | 1474 r = rect; |
1456 r.inset(radius, radius); | 1475 r.inset(radius, radius); |
1457 dst->addRect(r, reverse_direction(dir)); | 1476 dst->addRect(r, reverse_direction(dir)); |
1458 } | 1477 } |
1459 } | 1478 } |
OLD | NEW |