Chromium Code Reviews| 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 |