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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
48 #endif | 48 #endif |
49 | 49 |
50 static inline bool degenerate_vector(const SkVector& v) { | 50 static inline bool degenerate_vector(const SkVector& v) { |
51 return !SkPoint::CanNormalize(v.fX, v.fY); | 51 return !SkPoint::CanNormalize(v.fX, v.fY); |
52 } | 52 } |
53 | 53 |
54 static bool set_normal_unitnormal(const SkPoint& before, const SkPoint& after, S kScalar scale, | 54 static bool set_normal_unitnormal(const SkPoint& before, const SkPoint& after, S kScalar scale, |
55 SkScalar radius, | 55 SkScalar radius, |
56 SkVector* normal, SkVector* unitNormal) { | 56 SkVector* normal, SkVector* unitNormal) { |
57 if (!unitNormal->setNormalize((after.fX - before.fX) * scale, | 57 if (!unitNormal->setNormalize((after.fX - before.fX) * scale, |
58 (after.fY - before.fY) * scale)) { | 58 (after.fY - before.fY) * scale)) { |
59 return false; | 59 return false; |
60 } | 60 } |
61 unitNormal->rotateCCW(); | 61 unitNormal->rotateCCW(); |
62 unitNormal->scale(radius, normal); | 62 unitNormal->scale(radius, normal); |
63 return true; | 63 return true; |
64 } | 64 } |
65 | 65 |
66 static bool set_normal_unitnormal(const SkVector& vec, | 66 static bool set_normal_unitnormal(const SkVector& vec, |
67 SkScalar radius, | 67 SkScalar radius, |
68 SkVector* normal, SkVector* unitNormal) { | 68 SkVector* normal, SkVector* unitNormal) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
114 fTangentEnd = parent->fTangentEnd; | 114 fTangentEnd = parent->fTangentEnd; |
115 fEndSet = true; | 115 fEndSet = true; |
116 return true; | 116 return true; |
117 } | 117 } |
118 }; | 118 }; |
119 | 119 |
120 class SkPathStroker { | 120 class SkPathStroker { |
121 public: | 121 public: |
122 SkPathStroker(const SkPath& src, | 122 SkPathStroker(const SkPath& src, |
123 SkScalar radius, SkScalar miterLimit, SkPaint::Cap, | 123 SkScalar radius, SkScalar miterLimit, SkPaint::Cap, |
124 SkPaint::Join, SkScalar resScale); | 124 SkPaint::Join, SkScalar resScale, |
125 bool canIgnoreCenter); | |
125 | 126 |
126 bool hasOnlyMoveTo() const { return 0 == fSegmentCount; } | 127 bool hasOnlyMoveTo() const { return 0 == fSegmentCount; } |
127 SkPoint moveToPt() const { return fFirstPt; } | 128 SkPoint moveToPt() const { return fFirstPt; } |
128 | 129 |
129 void moveTo(const SkPoint&); | 130 void moveTo(const SkPoint&); |
130 void lineTo(const SkPoint&, const SkPath::Iter* iter = nullptr); | 131 void lineTo(const SkPoint&, const SkPath::Iter* iter = nullptr); |
131 void quadTo(const SkPoint&, const SkPoint&); | 132 void quadTo(const SkPoint&, const SkPoint&); |
132 void conicTo(const SkPoint&, const SkPoint&, SkScalar weight); | 133 void conicTo(const SkPoint&, const SkPoint&, SkScalar weight); |
133 void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); | 134 void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); |
134 void close(bool isLine) { this->finishContour(true, isLine); } | 135 void close(bool isLine) { this->finishContour(true, isLine); } |
(...skipping 15 matching lines...) Expand all Loading... | |
150 SkScalar fInvMiterLimit; | 151 SkScalar fInvMiterLimit; |
151 SkScalar fResScale; | 152 SkScalar fResScale; |
152 SkScalar fInvResScale; | 153 SkScalar fInvResScale; |
153 SkScalar fInvResScaleSquared; | 154 SkScalar fInvResScaleSquared; |
154 | 155 |
155 SkVector fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal; | 156 SkVector fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal; |
156 SkPoint fFirstPt, fPrevPt; // on original path | 157 SkPoint fFirstPt, fPrevPt; // on original path |
157 SkPoint fFirstOuterPt; | 158 SkPoint fFirstOuterPt; |
158 int fSegmentCount; | 159 int fSegmentCount; |
159 bool fPrevIsLine; | 160 bool fPrevIsLine; |
161 bool fCanIgnoreCenter; | |
160 | 162 |
161 SkStrokerPriv::CapProc fCapper; | 163 SkStrokerPriv::CapProc fCapper; |
162 SkStrokerPriv::JoinProc fJoiner; | 164 SkStrokerPriv::JoinProc fJoiner; |
163 | 165 |
164 SkPath fInner, fOuter; // outer is our working answer, inner is temp | 166 SkPath fInner, fOuter; // outer is our working answer, inner is temp |
165 SkPath fExtra; // added as extra complete contours | 167 SkPath fExtra; // added as extra complete contours |
166 | 168 |
167 enum StrokeType { | 169 enum StrokeType { |
168 kOuter_StrokeType = 1, // use sign-opposite values later to flip pe rpendicular axis | 170 kOuter_StrokeType = 1, // use sign-opposite values later to flip pe rpendicular axis |
169 kInner_StrokeType = -1 | 171 kInner_StrokeType = -1 |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
287 | 289 |
288 void SkPathStroker::finishContour(bool close, bool currIsLine) { | 290 void SkPathStroker::finishContour(bool close, bool currIsLine) { |
289 if (fSegmentCount > 0) { | 291 if (fSegmentCount > 0) { |
290 SkPoint pt; | 292 SkPoint pt; |
291 | 293 |
292 if (close) { | 294 if (close) { |
293 fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt, | 295 fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt, |
294 fFirstUnitNormal, fRadius, fInvMiterLimit, | 296 fFirstUnitNormal, fRadius, fInvMiterLimit, |
295 fPrevIsLine, currIsLine); | 297 fPrevIsLine, currIsLine); |
296 fOuter.close(); | 298 fOuter.close(); |
297 // now add fInner as its own contour | 299 |
298 fInner.getLastPt(&pt); | 300 if (fCanIgnoreCenter) { |
299 fOuter.moveTo(pt.fX, pt.fY); | 301 if (!fOuter.getBounds().contains(fInner.getBounds())) { |
300 fOuter.reversePathTo(fInner); | 302 SkASSERT(fInner.getBounds().contains(fOuter.getBounds())); |
301 fOuter.close(); | 303 fInner.swap(fOuter); |
304 } | |
305 } else { | |
306 // now add fInner as its own contour | |
307 fInner.getLastPt(&pt); | |
308 fOuter.moveTo(pt.fX, pt.fY); | |
309 fOuter.reversePathTo(fInner); | |
310 fOuter.close(); | |
311 } | |
302 } else { // add caps to start and end | 312 } else { // add caps to start and end |
303 // cap the end | 313 // cap the end |
304 fInner.getLastPt(&pt); | 314 fInner.getLastPt(&pt); |
305 fCapper(&fOuter, fPrevPt, fPrevNormal, pt, | 315 fCapper(&fOuter, fPrevPt, fPrevNormal, pt, |
306 currIsLine ? &fInner : nullptr); | 316 currIsLine ? &fInner : nullptr); |
307 fOuter.reversePathTo(fInner); | 317 fOuter.reversePathTo(fInner); |
308 // cap the start | 318 // cap the start |
309 fCapper(&fOuter, fFirstPt, -fFirstNormal, fFirstOuterPt, | 319 fCapper(&fOuter, fFirstPt, -fFirstNormal, fFirstOuterPt, |
310 fPrevIsLine ? &fInner : nullptr); | 320 fPrevIsLine ? &fInner : nullptr); |
311 fOuter.close(); | 321 fOuter.close(); |
312 } | 322 } |
313 } | 323 } |
314 // since we may re-use fInner, we rewind instead of reset, to save on | 324 // since we may re-use fInner, we rewind instead of reset, to save on |
315 // reallocating its internal storage. | 325 // reallocating its internal storage. |
316 fInner.rewind(); | 326 fInner.rewind(); |
317 fSegmentCount = -1; | 327 fSegmentCount = -1; |
318 } | 328 } |
319 | 329 |
320 /////////////////////////////////////////////////////////////////////////////// | 330 /////////////////////////////////////////////////////////////////////////////// |
321 | 331 |
322 SkPathStroker::SkPathStroker(const SkPath& src, | 332 SkPathStroker::SkPathStroker(const SkPath& src, |
323 SkScalar radius, SkScalar miterLimit, | 333 SkScalar radius, SkScalar miterLimit, |
324 SkPaint::Cap cap, SkPaint::Join join, SkScalar resS cale) | 334 SkPaint::Cap cap, SkPaint::Join join, SkScalar resS cale, |
335 bool canIgnoreCenter) | |
325 : fRadius(radius) | 336 : fRadius(radius) |
326 , fResScale(resScale) { | 337 , fResScale(resScale) |
338 , fCanIgnoreCenter(canIgnoreCenter) { | |
327 | 339 |
328 /* This is only used when join is miter_join, but we initialize it here | 340 /* This is only used when join is miter_join, but we initialize it here |
329 so that it is always defined, to fis valgrind warnings. | 341 so that it is always defined, to fis valgrind warnings. |
330 */ | 342 */ |
331 fInvMiterLimit = 0; | 343 fInvMiterLimit = 0; |
332 | 344 |
333 if (join == SkPaint::kMiter_Join) { | 345 if (join == SkPaint::kMiter_Join) { |
334 if (miterLimit <= SK_Scalar1) { | 346 if (miterLimit <= SK_Scalar1) { |
335 join = SkPaint::kBevel_Join; | 347 join = SkPaint::kBevel_Join; |
336 } else { | 348 } else { |
(...skipping 995 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1332 fTmpDst.swap(*const_cast<SkPath*>(&fSrc)); | 1344 fTmpDst.swap(*const_cast<SkPath*>(&fSrc)); |
1333 } | 1345 } |
1334 } | 1346 } |
1335 | 1347 |
1336 private: | 1348 private: |
1337 SkPath fTmpDst; | 1349 SkPath fTmpDst; |
1338 const SkPath& fSrc; | 1350 const SkPath& fSrc; |
1339 bool fSwapWithSrc; | 1351 bool fSwapWithSrc; |
1340 }; | 1352 }; |
1341 | 1353 |
1354 static bool lines_only(const SkPath& p) { | |
1355 return (p.getSegmentMasks() & SkPath::kLine_SegmentMask) && | |
bsalomon
2016/08/26 01:24:25
Is this different than p.getSegmentMasks() == SkPa
robertphillips
2016/08/26 11:44:32
Haha - no! Fixed.
| |
1356 !(p.getSegmentMasks() & ~SkPath::kLine_SegmentMask); | |
1357 } | |
1358 | |
1342 void SkStroke::strokePath(const SkPath& src, SkPath* dst) const { | 1359 void SkStroke::strokePath(const SkPath& src, SkPath* dst) const { |
1343 SkASSERT(dst); | 1360 SkASSERT(dst); |
1344 | 1361 |
1345 SkScalar radius = SkScalarHalf(fWidth); | 1362 SkScalar radius = SkScalarHalf(fWidth); |
1346 | 1363 |
1347 AutoTmpPath tmp(src, &dst); | 1364 AutoTmpPath tmp(src, &dst); |
1348 | 1365 |
1349 if (radius <= 0) { | 1366 if (radius <= 0) { |
1350 return; | 1367 return; |
1351 } | 1368 } |
1352 | 1369 |
1353 // If src is really a rect, call our specialty strokeRect() method | 1370 // If src is really a rect, call our specialty strokeRect() method |
1354 { | 1371 { |
1355 SkRect rect; | 1372 SkRect rect; |
1356 bool isClosed; | 1373 bool isClosed; |
1357 SkPath::Direction dir; | 1374 SkPath::Direction dir; |
1358 if (src.isRect(&rect, &isClosed, &dir) && isClosed) { | 1375 if (src.isRect(&rect, &isClosed, &dir) && isClosed) { |
1359 this->strokeRect(rect, dst, dir); | 1376 this->strokeRect(rect, dst, dir); |
1360 // our answer should preserve the inverseness of the src | 1377 // our answer should preserve the inverseness of the src |
1361 if (src.isInverseFillType()) { | 1378 if (src.isInverseFillType()) { |
1362 SkASSERT(!dst->isInverseFillType()); | 1379 SkASSERT(!dst->isInverseFillType()); |
1363 dst->toggleInverseFillType(); | 1380 dst->toggleInverseFillType(); |
1364 } | 1381 } |
1365 return; | 1382 return; |
1366 } | 1383 } |
1367 } | 1384 } |
1368 | 1385 |
1369 SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJ oin(), fResScale); | 1386 // We can always ignore centers for stroke and fill convex line-only paths |
1387 // TODO: remove the line-only restriction | |
1388 bool ignoreCenter = fDoFill && lines_only(src) && src.isLastContourClosed() && src.isConvex(); | |
1389 | |
1390 SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJ oin(), | |
1391 fResScale, ignoreCenter); | |
1370 SkPath::Iter iter(src, false); | 1392 SkPath::Iter iter(src, false); |
1371 SkPath::Verb lastSegment = SkPath::kMove_Verb; | 1393 SkPath::Verb lastSegment = SkPath::kMove_Verb; |
1372 | 1394 |
1373 for (;;) { | 1395 for (;;) { |
1374 SkPoint pts[4]; | 1396 SkPoint pts[4]; |
1375 switch (iter.next(pts, false)) { | 1397 switch (iter.next(pts, false)) { |
1376 case SkPath::kMove_Verb: | 1398 case SkPath::kMove_Verb: |
1377 stroker.moveTo(pts[0]); | 1399 stroker.moveTo(pts[0]); |
1378 break; | 1400 break; |
1379 case SkPath::kLine_Verb: | 1401 case SkPath::kLine_Verb: |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1413 } | 1435 } |
1414 stroker.close(lastSegment == SkPath::kLine_Verb); | 1436 stroker.close(lastSegment == SkPath::kLine_Verb); |
1415 break; | 1437 break; |
1416 case SkPath::kDone_Verb: | 1438 case SkPath::kDone_Verb: |
1417 goto DONE; | 1439 goto DONE; |
1418 } | 1440 } |
1419 } | 1441 } |
1420 DONE: | 1442 DONE: |
1421 stroker.done(dst, lastSegment == SkPath::kLine_Verb); | 1443 stroker.done(dst, lastSegment == SkPath::kLine_Verb); |
1422 | 1444 |
1423 if (fDoFill) { | 1445 if (fDoFill && !ignoreCenter) { |
1424 if (SkPathPriv::CheapIsFirstDirection(src, SkPathPriv::kCCW_FirstDirecti on)) { | 1446 if (SkPathPriv::CheapIsFirstDirection(src, SkPathPriv::kCCW_FirstDirecti on)) { |
1425 dst->reverseAddPath(src); | 1447 dst->reverseAddPath(src); |
1426 } else { | 1448 } else { |
1427 dst->addPath(src); | 1449 dst->addPath(src); |
1428 } | 1450 } |
1429 } else { | 1451 } else { |
1430 // Seems like we can assume that a 2-point src would always result in | 1452 // Seems like we can assume that a 2-point src would always result in |
1431 // a convex stroke, but testing has proved otherwise. | 1453 // a convex stroke, but testing has proved otherwise. |
1432 // TODO: fix the stroker to make this assumption true (without making | 1454 // TODO: fix the stroker to make this assumption true (without making |
1433 // it slower that the work that will be done in computeConvexity()) | 1455 // it slower that the work that will be done in computeConvexity()) |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1527 default: | 1549 default: |
1528 break; | 1550 break; |
1529 } | 1551 } |
1530 | 1552 |
1531 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { | 1553 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { |
1532 r = rect; | 1554 r = rect; |
1533 r.inset(radius, radius); | 1555 r.inset(radius, radius); |
1534 dst->addRect(r, reverse_direction(dir)); | 1556 dst->addRect(r, reverse_direction(dir)); |
1535 } | 1557 } |
1536 } | 1558 } |
OLD | NEW |