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 1022 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1359 this->strokeRect(rect, dst, dir); | 1371 this->strokeRect(rect, dst, dir); |
1360 // our answer should preserve the inverseness of the src | 1372 // our answer should preserve the inverseness of the src |
1361 if (src.isInverseFillType()) { | 1373 if (src.isInverseFillType()) { |
1362 SkASSERT(!dst->isInverseFillType()); | 1374 SkASSERT(!dst->isInverseFillType()); |
1363 dst->toggleInverseFillType(); | 1375 dst->toggleInverseFillType(); |
1364 } | 1376 } |
1365 return; | 1377 return; |
1366 } | 1378 } |
1367 } | 1379 } |
1368 | 1380 |
1369 SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJ
oin(), fResScale); | 1381 // We can always ignore centers for stroke and fill convex line-only paths |
| 1382 // TODO: remove the line-only restriction |
| 1383 bool ignoreCenter = fDoFill && (src.getSegmentMasks() == SkPath::kLine_Segme
ntMask) && |
| 1384 src.isLastContourClosed() && src.isConvex(); |
| 1385 |
| 1386 SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJ
oin(), |
| 1387 fResScale, ignoreCenter); |
1370 SkPath::Iter iter(src, false); | 1388 SkPath::Iter iter(src, false); |
1371 SkPath::Verb lastSegment = SkPath::kMove_Verb; | 1389 SkPath::Verb lastSegment = SkPath::kMove_Verb; |
1372 | 1390 |
1373 for (;;) { | 1391 for (;;) { |
1374 SkPoint pts[4]; | 1392 SkPoint pts[4]; |
1375 switch (iter.next(pts, false)) { | 1393 switch (iter.next(pts, false)) { |
1376 case SkPath::kMove_Verb: | 1394 case SkPath::kMove_Verb: |
1377 stroker.moveTo(pts[0]); | 1395 stroker.moveTo(pts[0]); |
1378 break; | 1396 break; |
1379 case SkPath::kLine_Verb: | 1397 case SkPath::kLine_Verb: |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1413 } | 1431 } |
1414 stroker.close(lastSegment == SkPath::kLine_Verb); | 1432 stroker.close(lastSegment == SkPath::kLine_Verb); |
1415 break; | 1433 break; |
1416 case SkPath::kDone_Verb: | 1434 case SkPath::kDone_Verb: |
1417 goto DONE; | 1435 goto DONE; |
1418 } | 1436 } |
1419 } | 1437 } |
1420 DONE: | 1438 DONE: |
1421 stroker.done(dst, lastSegment == SkPath::kLine_Verb); | 1439 stroker.done(dst, lastSegment == SkPath::kLine_Verb); |
1422 | 1440 |
1423 if (fDoFill) { | 1441 if (fDoFill && !ignoreCenter) { |
1424 if (SkPathPriv::CheapIsFirstDirection(src, SkPathPriv::kCCW_FirstDirecti
on)) { | 1442 if (SkPathPriv::CheapIsFirstDirection(src, SkPathPriv::kCCW_FirstDirecti
on)) { |
1425 dst->reverseAddPath(src); | 1443 dst->reverseAddPath(src); |
1426 } else { | 1444 } else { |
1427 dst->addPath(src); | 1445 dst->addPath(src); |
1428 } | 1446 } |
1429 } else { | 1447 } else { |
1430 // Seems like we can assume that a 2-point src would always result in | 1448 // Seems like we can assume that a 2-point src would always result in |
1431 // a convex stroke, but testing has proved otherwise. | 1449 // a convex stroke, but testing has proved otherwise. |
1432 // TODO: fix the stroker to make this assumption true (without making | 1450 // TODO: fix the stroker to make this assumption true (without making |
1433 // it slower that the work that will be done in computeConvexity()) | 1451 // 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: | 1545 default: |
1528 break; | 1546 break; |
1529 } | 1547 } |
1530 | 1548 |
1531 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { | 1549 if (fWidth < SkMinScalar(rw, rh) && !fDoFill) { |
1532 r = rect; | 1550 r = rect; |
1533 r.inset(radius, radius); | 1551 r.inset(radius, radius); |
1534 dst->addRect(r, reverse_direction(dir)); | 1552 dst->addRect(r, reverse_direction(dir)); |
1535 } | 1553 } |
1536 } | 1554 } |
OLD | NEW |