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

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: suppress warning 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
« src/core/SkPathRef.cpp ('K') | « 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 const SkScalar capOutset = SkPaint::kSquare_Cap == capStyle ? 0.5f : SK_Scal arPI / 8;
reed1 2015/12/08 16:59:02 1. assert that the capStyle is either Square or Ro
caryclark 2015/12/08 19:59:39 Done.
358 if (SkPath::kMove_Verb == prevVerb) {
359 SkPoint* first = pts;
360 SkPoint* ctrl = first;
361 int controls = ptCount - 1;
362 SkVector tangent;
363 do {
364 tangent = *first - *++ctrl;
365 } while (tangent.isZero() && --controls > 0);
366 if (tangent.isZero()) {
367 tangent.set(1, 0);
368 } else {
369 tangent.normalize();
370 }
371 first->fX += tangent.fX * capOutset;
372 first->fY += tangent.fY * capOutset;
373 }
374 if (SkPath::kMove_Verb == nextVerb || SkPath::kDone_Verb == nextVerb) {
375 SkPoint* last = &pts[ptCount - 1];
376 SkPoint* ctrl = last;
377 int controls = ptCount - 1;
378 SkVector tangent;
379 do {
380 tangent = *last - *--ctrl;
381 } while (tangent.isZero() && --controls > 0);
382 if (tangent.isZero()) {
383 tangent.set(-1, 0);
384 } else {
385 tangent.normalize();
386 }
387 last->fX += tangent.fX * capOutset;
388 last->fY += tangent.fY * capOutset;
389 }
390 }
391
392 template <SkPaint::Cap capStyle>
393 void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter ,
352 SkScan::HairRgnProc lineproc) { 394 SkScan::HairRgnProc lineproc) {
353 if (path.isEmpty()) { 395 if (path.isEmpty()) {
354 return; 396 return;
355 } 397 }
356 398
357 SkAAClipBlitterWrapper wrap; 399 SkAAClipBlitterWrapper wrap;
358 const SkRegion* clip = nullptr; 400 const SkRegion* clip = nullptr;
359 401
360 { 402 {
361 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1); 403 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1);
362 404
363 if (rclip.quickReject(ibounds)) { 405 if (rclip.quickReject(ibounds)) {
364 return; 406 return;
365 } 407 }
366 if (!rclip.quickContains(ibounds)) { 408 if (!rclip.quickContains(ibounds)) {
367 if (rclip.isBW()) { 409 if (rclip.isBW()) {
368 clip = &rclip.bwRgn(); 410 clip = &rclip.bwRgn();
369 } else { 411 } else {
370 wrap.init(rclip, blitter); 412 wrap.init(rclip, blitter);
371 blitter = wrap.getBlitter(); 413 blitter = wrap.getBlitter();
372 clip = &wrap.getRgn(); 414 clip = &wrap.getRgn();
373 } 415 }
374 } 416 }
375 } 417 }
376 418
377 SkPath::RawIter iter(path); 419 SkPath::RawIter iter(path);
378 SkPoint pts[4], firstPt, lastPt; 420 SkPoint pts[4], firstPt, lastPt;
379 SkPath::Verb verb; 421 SkPath::Verb verb, prevVerb;
380 SkAutoConicToQuads converter; 422 SkAutoConicToQuads converter;
381 423
424 if (SkPaint::kButt_Cap != capStyle) {
425 prevVerb = SkPath::kDone_Verb;
426 }
382 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 427 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
383 switch (verb) { 428 switch (verb) {
384 case SkPath::kMove_Verb: 429 case SkPath::kMove_Verb:
385 firstPt = lastPt = pts[0]; 430 firstPt = lastPt = pts[0];
386 break; 431 break;
387 case SkPath::kLine_Verb: 432 case SkPath::kLine_Verb:
433 if (SkPaint::kButt_Cap != capStyle) {
434 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 2);
435 }
388 lineproc(pts, 2, clip, blitter); 436 lineproc(pts, 2, clip, blitter);
389 lastPt = pts[1]; 437 lastPt = pts[1];
390 break; 438 break;
391 case SkPath::kQuad_Verb: 439 case SkPath::kQuad_Verb:
440 if (SkPaint::kButt_Cap != capStyle) {
441 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3);
442 }
392 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc); 443 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc);
393 lastPt = pts[2]; 444 lastPt = pts[2];
394 break; 445 break;
395 case SkPath::kConic_Verb: { 446 case SkPath::kConic_Verb: {
447 if (SkPaint::kButt_Cap != capStyle) {
448 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 3);
449 }
396 // how close should the quads be to the original conic? 450 // how close should the quads be to the original conic?
397 const SkScalar tol = SK_Scalar1 / 4; 451 const SkScalar tol = SK_Scalar1 / 4;
398 const SkPoint* quadPts = converter.computeQuads(pts, 452 const SkPoint* quadPts = converter.computeQuads(pts,
399 iter.conicWeight(), tol); 453 iter.conicWeight(), tol);
400 for (int i = 0; i < converter.countQuads(); ++i) { 454 for (int i = 0; i < converter.countQuads(); ++i) {
401 int level = compute_quad_level(quadPts); 455 int level = compute_quad_level(quadPts);
402 hairquad(quadPts, clip, blitter, level, lineproc); 456 hairquad(quadPts, clip, blitter, level, lineproc);
403 quadPts += 2; 457 quadPts += 2;
404 } 458 }
405 lastPt = pts[2]; 459 lastPt = pts[2];
406 break; 460 break;
407 } 461 }
408 case SkPath::kCubic_Verb: { 462 case SkPath::kCubic_Verb: {
463 if (SkPaint::kButt_Cap != capStyle) {
464 extend_pts<capStyle>(prevVerb, iter.peek(), pts, 4);
465 }
409 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc) ; 466 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc) ;
410 lastPt = pts[3]; 467 lastPt = pts[3];
411 } break; 468 } break;
412 case SkPath::kClose_Verb: 469 case SkPath::kClose_Verb:
413 pts[0] = lastPt; 470 pts[0] = lastPt;
414 pts[1] = firstPt; 471 pts[1] = firstPt;
415 lineproc(pts, 2, clip, blitter); 472 lineproc(pts, 2, clip, blitter);
416 break; 473 break;
417 case SkPath::kDone_Verb: 474 case SkPath::kDone_Verb:
418 break; 475 break;
419 } 476 }
477 if (SkPaint::kButt_Cap != capStyle) {
478 prevVerb = verb;
479 }
420 } 480 }
421 } 481 }
422 482
423 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b litter) { 483 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b litter) {
424 hair_path(path, clip, blitter, SkScan::HairLineRgn); 484 hair_path<SkPaint::kButt_Cap>(path, clip, blitter, SkScan::HairLineRgn);
425 } 485 }
426 486
427 void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip, SkBlitte r* blitter) { 487 void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip, SkBlitte r* blitter) {
428 hair_path(path, clip, blitter, SkScan::AntiHairLineRgn); 488 hair_path<SkPaint::kButt_Cap>(path, clip, blitter, SkScan::AntiHairLineRgn);
489 }
490
491 void SkScan::HairSquarePath(const SkPath& path, const SkRasterClip& clip, SkBlit ter* blitter) {
492 hair_path<SkPaint::kSquare_Cap>(path, clip, blitter, SkScan::HairLineRgn);
493 }
494
495 void SkScan::AntiHairSquarePath(const SkPath& path, const SkRasterClip& clip, Sk Blitter* blitter) {
496 hair_path<SkPaint::kSquare_Cap>(path, clip, blitter, SkScan::AntiHairLineRgn );
497 }
498
499 void SkScan::HairRoundPath(const SkPath& path, const SkRasterClip& clip, SkBlitt er* blitter) {
500 hair_path<SkPaint::kRound_Cap>(path, clip, blitter, SkScan::HairLineRgn);
501 }
502
503 void SkScan::AntiHairRoundPath(const SkPath& path, const SkRasterClip& clip, SkB litter* blitter) {
504 hair_path<SkPaint::kRound_Cap>(path, clip, blitter, SkScan::AntiHairLineRgn) ;
429 } 505 }
430 506
431 /////////////////////////////////////////////////////////////////////////////// 507 ///////////////////////////////////////////////////////////////////////////////
432 508
433 void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize, 509 void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize,
434 const SkRasterClip& clip, SkBlitter* blitter) { 510 const SkRasterClip& clip, SkBlitter* blitter) {
435 SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0); 511 SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
436 512
437 if (strokeSize.fX < 0 || strokeSize.fY < 0) { 513 if (strokeSize.fX < 0 || strokeSize.fY < 0) {
438 return; 514 return;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 574
499 SkAAClipBlitterWrapper wrap; 575 SkAAClipBlitterWrapper wrap;
500 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { 576 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) {
501 wrap.init(clip, blitter); 577 wrap.init(clip, blitter);
502 blitter = wrap.getBlitter(); 578 blitter = wrap.getBlitter();
503 clipRgn = &wrap.getRgn(); 579 clipRgn = &wrap.getRgn();
504 } 580 }
505 AntiHairLineRgn(pts, count, clipRgn, blitter); 581 AntiHairLineRgn(pts, count, clipRgn, blitter);
506 } 582 }
507 } 583 }
OLDNEW
« src/core/SkPathRef.cpp ('K') | « src/core/SkScan.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698