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

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

Issue 1491843006: add support for capped hairlines (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: add comment Created 5 years 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 | « src/core/SkScan.h ('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 2006 The Android Open Source Project 2 * Copyright 2006 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 "SkScan.h" 8 #include "SkScan.h"
9 #include "SkBlitter.h" 9 #include "SkBlitter.h"
10 #include "SkRasterClip.h" 10 #include "SkRasterClip.h"
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 than a pixel. 341 than a pixel.
342 */ 342 */
343 int level = (33 - SkCLZ(d)) >> 1; 343 int level = (33 - SkCLZ(d)) >> 1;
344 // sanity check on level (from the previous version) 344 // sanity check on level (from the previous version)
345 if (level > kMaxQuadSubdivideLevel) { 345 if (level > kMaxQuadSubdivideLevel) {
346 level = kMaxQuadSubdivideLevel; 346 level = kMaxQuadSubdivideLevel;
347 } 347 }
348 return level; 348 return level;
349 } 349 }
350 350
351 static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter, 351 /* Extend the points in the direction of the starting or ending tangent by 1/2 u nit to
352 account for a round or square cap. If there's no distance between the end poi nt and
353 the control point, use the next control point to create a tangent. If the cur ve
354 is degenerate, move the cap out 1/2 unit horizontally. */
355 template <SkPaint::Cap capStyle>
356 void extend_pts(SkPath::Verb prevVerb, SkPath::Verb nextVerb, SkPoint* pts, int ptCount) {
357 SkASSERT(SkPaint::kSquare_Cap == capStyle || SkPaint::kRound_Cap == capStyle );
358 // The area of a circle is PI*R*R. For a unit circle, R=1/2, and the cap cov ers half of that.
359 const SkScalar capOutset = SkPaint::kSquare_Cap == capStyle ? 0.5f : SK_Scal arPI / 8;
360 if (SkPath::kMove_Verb == prevVerb) {
361 SkPoint* first = pts;
362 SkPoint* ctrl = first;
363 int controls = ptCount - 1;
364 SkVector tangent;
365 do {
366 tangent = *first - *++ctrl;
367 } while (tangent.isZero() && --controls > 0);
368 if (tangent.isZero()) {
369 tangent.set(1, 0);
370 } else {
371 tangent.normalize();
372 }
373 first->fX += tangent.fX * capOutset;
374 first->fY += tangent.fY * capOutset;
375 }
376 if (SkPath::kMove_Verb == nextVerb || SkPath::kDone_Verb == nextVerb) {
377 SkPoint* last = &pts[ptCount - 1];
378 SkPoint* ctrl = last;
379 int controls = ptCount - 1;
380 SkVector tangent;
381 do {
382 tangent = *last - *--ctrl;
383 } while (tangent.isZero() && --controls > 0);
384 if (tangent.isZero()) {
385 tangent.set(-1, 0);
386 } else {
387 tangent.normalize();
388 }
389 last->fX += tangent.fX * capOutset;
390 last->fY += tangent.fY * capOutset;
391 }
392 }
393
394 template <SkPaint::Cap capStyle>
395 void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter ,
352 SkScan::HairRgnProc lineproc) { 396 SkScan::HairRgnProc lineproc) {
353 if (path.isEmpty()) { 397 if (path.isEmpty()) {
354 return; 398 return;
355 } 399 }
356 400
357 SkAAClipBlitterWrapper wrap; 401 SkAAClipBlitterWrapper wrap;
358 const SkRegion* clip = nullptr; 402 const SkRegion* clip = nullptr;
359 403
360 { 404 {
361 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1); 405 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1);
362 406
363 if (rclip.quickReject(ibounds)) { 407 if (rclip.quickReject(ibounds)) {
364 return; 408 return;
365 } 409 }
366 if (!rclip.quickContains(ibounds)) { 410 if (!rclip.quickContains(ibounds)) {
367 if (rclip.isBW()) { 411 if (rclip.isBW()) {
368 clip = &rclip.bwRgn(); 412 clip = &rclip.bwRgn();
369 } else { 413 } else {
370 wrap.init(rclip, blitter); 414 wrap.init(rclip, blitter);
371 blitter = wrap.getBlitter(); 415 blitter = wrap.getBlitter();
372 clip = &wrap.getRgn(); 416 clip = &wrap.getRgn();
373 } 417 }
374 } 418 }
375 } 419 }
376 420
377 SkPath::RawIter iter(path); 421 SkPath::RawIter iter(path);
378 SkPoint pts[4], firstPt, lastPt; 422 SkPoint pts[4], firstPt, lastPt;
379 SkPath::Verb verb; 423 SkPath::Verb verb, prevVerb;
380 SkAutoConicToQuads converter; 424 SkAutoConicToQuads converter;
381 425
426 if (SkPaint::kButt_Cap != capStyle) {
427 prevVerb = SkPath::kDone_Verb;
428 }
382 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 429 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
383 switch (verb) { 430 switch (verb) {
384 case SkPath::kMove_Verb: 431 case SkPath::kMove_Verb:
385 firstPt = lastPt = pts[0]; 432 firstPt = lastPt = pts[0];
386 break; 433 break;
387 case SkPath::kLine_Verb: 434 case SkPath::kLine_Verb:
435 if (SkPaint::kButt_Cap != capStyle) {
436 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 2);
437 }
388 lineproc(pts, 2, clip, blitter); 438 lineproc(pts, 2, clip, blitter);
389 lastPt = pts[1]; 439 lastPt = pts[1];
390 break; 440 break;
391 case SkPath::kQuad_Verb: 441 case SkPath::kQuad_Verb:
442 if (SkPaint::kButt_Cap != capStyle) {
443 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3);
444 }
392 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc); 445 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc);
393 lastPt = pts[2]; 446 lastPt = pts[2];
394 break; 447 break;
395 case SkPath::kConic_Verb: { 448 case SkPath::kConic_Verb: {
449 if (SkPaint::kButt_Cap != capStyle) {
450 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3);
451 }
396 // how close should the quads be to the original conic? 452 // how close should the quads be to the original conic?
397 const SkScalar tol = SK_Scalar1 / 4; 453 const SkScalar tol = SK_Scalar1 / 4;
398 const SkPoint* quadPts = converter.computeQuads(pts, 454 const SkPoint* quadPts = converter.computeQuads(pts,
399 iter.conicWeight(), tol); 455 iter.conicWeight(), tol);
400 for (int i = 0; i < converter.countQuads(); ++i) { 456 for (int i = 0; i < converter.countQuads(); ++i) {
401 int level = compute_quad_level(quadPts); 457 int level = compute_quad_level(quadPts);
402 hairquad(quadPts, clip, blitter, level, lineproc); 458 hairquad(quadPts, clip, blitter, level, lineproc);
403 quadPts += 2; 459 quadPts += 2;
404 } 460 }
405 lastPt = pts[2]; 461 lastPt = pts[2];
406 break; 462 break;
407 } 463 }
408 case SkPath::kCubic_Verb: { 464 case SkPath::kCubic_Verb: {
465 if (SkPaint::kButt_Cap != capStyle) {
466 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 4);
467 }
409 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc) ; 468 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc) ;
410 lastPt = pts[3]; 469 lastPt = pts[3];
411 } break; 470 } break;
412 case SkPath::kClose_Verb: 471 case SkPath::kClose_Verb:
413 pts[0] = lastPt; 472 pts[0] = lastPt;
414 pts[1] = firstPt; 473 pts[1] = firstPt;
415 lineproc(pts, 2, clip, blitter); 474 lineproc(pts, 2, clip, blitter);
416 break; 475 break;
417 case SkPath::kDone_Verb: 476 case SkPath::kDone_Verb:
418 break; 477 break;
419 } 478 }
479 if (SkPaint::kButt_Cap != capStyle) {
480 prevVerb = verb;
481 }
420 } 482 }
421 } 483 }
422 484
423 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b litter) { 485 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b litter) {
424 hair_path(path, clip, blitter, SkScan::HairLineRgn); 486 hair_path<SkPaint::kButt_Cap>(path, clip, blitter, SkScan::HairLineRgn);
425 } 487 }
426 488
427 void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip, SkBlitte r* blitter) { 489 void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip, SkBlitte r* blitter) {
428 hair_path(path, clip, blitter, SkScan::AntiHairLineRgn); 490 hair_path<SkPaint::kButt_Cap>(path, clip, blitter, SkScan::AntiHairLineRgn);
491 }
492
493 void SkScan::HairSquarePath(const SkPath& path, const SkRasterClip& clip, SkBlit ter* blitter) {
494 hair_path<SkPaint::kSquare_Cap>(path, clip, blitter, SkScan::HairLineRgn);
495 }
496
497 void SkScan::AntiHairSquarePath(const SkPath& path, const SkRasterClip& clip, Sk Blitter* blitter) {
498 hair_path<SkPaint::kSquare_Cap>(path, clip, blitter, SkScan::AntiHairLineRgn );
499 }
500
501 void SkScan::HairRoundPath(const SkPath& path, const SkRasterClip& clip, SkBlitt er* blitter) {
502 hair_path<SkPaint::kRound_Cap>(path, clip, blitter, SkScan::HairLineRgn);
503 }
504
505 void SkScan::AntiHairRoundPath(const SkPath& path, const SkRasterClip& clip, SkB litter* blitter) {
506 hair_path<SkPaint::kRound_Cap>(path, clip, blitter, SkScan::AntiHairLineRgn) ;
429 } 507 }
430 508
431 /////////////////////////////////////////////////////////////////////////////// 509 ///////////////////////////////////////////////////////////////////////////////
432 510
433 void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize, 511 void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize,
434 const SkRasterClip& clip, SkBlitter* blitter) { 512 const SkRasterClip& clip, SkBlitter* blitter) {
435 SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0); 513 SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
436 514
437 if (strokeSize.fX < 0 || strokeSize.fY < 0) { 515 if (strokeSize.fX < 0 || strokeSize.fY < 0) {
438 return; 516 return;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 576
499 SkAAClipBlitterWrapper wrap; 577 SkAAClipBlitterWrapper wrap;
500 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { 578 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) {
501 wrap.init(clip, blitter); 579 wrap.init(clip, blitter);
502 blitter = wrap.getBlitter(); 580 blitter = wrap.getBlitter();
503 clipRgn = &wrap.getRgn(); 581 clipRgn = &wrap.getRgn();
504 } 582 }
505 AntiHairLineRgn(pts, count, clipRgn, blitter); 583 AntiHairLineRgn(pts, count, clipRgn, blitter);
506 } 584 }
507 } 585 }
OLDNEW
« no previous file with comments | « src/core/SkScan.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698