Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(356)

Side by Side Diff: src/core/SkStroke.cpp

Issue 2275243003: Ignore fill when stroke & filling convex line-only paths (Closed)
Patch Set: Fix mistake Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gm/convex_all_line_paths.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « gm/convex_all_line_paths.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698