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

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: fix 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
« gm/hairlines.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 hairconic(SkPoint pts[4], const SkRegion* clip, SkBlitter* blitter,
352 SkScalar weight, SkScan::HairRgnProc lineproc) {
353 SkAutoConicToQuads converter;
354 // how close should the quads be to the original conic?
355 const SkScalar tol = SK_Scalar1 / 4;
356 const SkPoint* quadPts = converter.computeQuads(pts, weight, tol);
357 for (int i = 0; i < converter.countQuads(); ++i) {
358 int level = compute_quad_level(quadPts);
359 hairquad(quadPts, clip, blitter, level, lineproc);
360 quadPts += 2;
361 }
362 }
363
364 /* Extend the points in the direction of the starting or ending tangent by 1/2 u nit to
365 account for a round or square cap. If there's no distance between the end poi nt and
366 the control point, use the next control point to create a tangent. If the cur ve
367 is degenerate, move the cap out 1/2 unit horizontally. */
368 static void extend_pts(SkPath::Verb prevVerb, SkPath::Verb nextVerb, SkPoint* pt s, int ptCount) {
369 if (SkPath::kMove_Verb == prevVerb) {
370 SkPoint* first = pts;
371 SkPoint* ctrl = first;
372 int controls = ptCount - 1;
373 SkVector tangent;
374 do {
375 tangent = *first - *++ctrl;
376 } while (tangent.isZero() && --controls > 0);
377 if (tangent.isZero()) {
378 tangent.set(1, 0);
379 } else {
380 tangent.normalize();
381 }
382 first->fX += tangent.fX * 0.5f;
383 first->fY += tangent.fY * 0.5f;
384 }
385 if (SkPath::kMove_Verb == nextVerb || SkPath::kDone_Verb == nextVerb) {
386 SkPoint* last = &pts[ptCount - 1];
387 SkPoint* ctrl = last;
388 int controls = ptCount - 1;
389 SkVector tangent;
390 do {
391 tangent = *last - *--ctrl;
392 } while (tangent.isZero() && --controls > 0);
393 if (tangent.isZero()) {
394 tangent.set(-1, 0);
395 } else {
396 tangent.normalize();
397 }
398 last->fX += tangent.fX * 0.5f;
399 last->fY += tangent.fY * 0.5f;
400 }
401 }
402
403 enum ExtendEnds {
404 kNo_ExtendEnds,
405 kCaps_ExtendEnds,
406 };
407
351 static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter, 408 static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter,
352 SkScan::HairRgnProc lineproc) { 409 SkScan::HairRgnProc lineproc, ExtendEnds extendForCaps) {
353 if (path.isEmpty()) { 410 if (path.isEmpty()) {
354 return; 411 return;
355 } 412 }
356 413
357 SkAAClipBlitterWrapper wrap; 414 SkAAClipBlitterWrapper wrap;
358 const SkRegion* clip = nullptr; 415 const SkRegion* clip = nullptr;
359 416
360 { 417 {
361 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1); 418 const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1);
362 419
363 if (rclip.quickReject(ibounds)) { 420 if (rclip.quickReject(ibounds)) {
364 return; 421 return;
365 } 422 }
366 if (!rclip.quickContains(ibounds)) { 423 if (!rclip.quickContains(ibounds)) {
367 if (rclip.isBW()) { 424 if (rclip.isBW()) {
368 clip = &rclip.bwRgn(); 425 clip = &rclip.bwRgn();
369 } else { 426 } else {
370 wrap.init(rclip, blitter); 427 wrap.init(rclip, blitter);
371 blitter = wrap.getBlitter(); 428 blitter = wrap.getBlitter();
372 clip = &wrap.getRgn(); 429 clip = &wrap.getRgn();
373 } 430 }
374 } 431 }
375 } 432 }
376 433
377 SkPath::Iter iter(path, false); 434 SkPath::Iter iter(path, false);
378 SkPoint pts[4]; 435 SkPoint pts[4];
379 SkPath::Verb verb; 436 SkPath::Verb verb;
380 SkAutoConicToQuads converter;
381 437
382 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) { 438 if (kNo_ExtendEnds == extendForCaps) {
383 switch (verb) { 439 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
384 case SkPath::kMove_Verb: 440 switch (verb) {
441 case SkPath::kMove_Verb:
442 break;
443 case SkPath::kLine_Verb:
444 lineproc(pts, 2, clip, blitter);
445 break;
446 case SkPath::kQuad_Verb:
447 hairquad(pts, clip, blitter, compute_quad_level(pts), linepr oc);
448 break;
449 case SkPath::kConic_Verb:
450 hairconic(pts, clip, blitter, iter.conicWeight(), lineproc);
451 break;
452 case SkPath::kCubic_Verb:
453 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, linep roc);
385 break; 454 break;
386 case SkPath::kLine_Verb: 455 case SkPath::kClose_Verb:
387 lineproc(pts, 2, clip, blitter); 456 break;
457 case SkPath::kDone_Verb:
458 break;
459 }
460 }
461 } else {
462 /* If the caps require extending the haircurve, use the previous and fol lowing verbs
463 to determine if the curve is at the start or end of the contour. If t he curve is
464 preceeded by a move verb, or followed by a move verb or a done verb, extend the curve. */
465 SkASSERT(kCaps_ExtendEnds == extendForCaps);
466 SkPath::Verb prevVerb;
467 verb = SkPath::kDone_Verb;
468 SkScalar weight SK_INIT_TO_AVOID_WARNING;
469 do {
470 SkPoint nextPts[4];
471 SkPath::Verb nextVerb = iter.next(nextPts, false);
472 switch (verb) {
473 case SkPath::kMove_Verb:
474 break;
475 case SkPath::kLine_Verb:
476 extend_pts(prevVerb, nextVerb, pts, 2);
477 lineproc(pts, 2, clip, blitter);
478 break;
479 case SkPath::kQuad_Verb:
480 extend_pts(prevVerb, nextVerb, pts, 3);
481 hairquad(pts, clip, blitter, compute_quad_level(pts), linepr oc);
482 break;
483 case SkPath::kConic_Verb:
484 extend_pts(prevVerb, nextVerb, pts, 3);
485 hairconic(pts, clip, blitter, weight, lineproc);
486 break;
487 case SkPath::kCubic_Verb:
488 extend_pts(prevVerb, nextVerb, pts, 4);
489 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, linep roc);
388 break; 490 break;
389 case SkPath::kQuad_Verb: 491 case SkPath::kClose_Verb:
390 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc); 492 break;
391 break; 493 case SkPath::kDone_Verb:
392 case SkPath::kConic_Verb: { 494 break;
393 // how close should the quads be to the original conic? 495 }
394 const SkScalar tol = SK_Scalar1 / 4; 496 if (SkPath::kDone_Verb == nextVerb) {
395 const SkPoint* quadPts = converter.computeQuads(pts,
396 iter.conicWeight(), tol);
397 for (int i = 0; i < converter.countQuads(); ++i) {
398 int level = compute_quad_level(quadPts);
399 hairquad(quadPts, clip, blitter, level, lineproc);
400 quadPts += 2;
401 }
402 break; 497 break;
403 } 498 }
404 case SkPath::kCubic_Verb: { 499 if (SkPath::kConic_Verb == nextVerb) {
405 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc) ; 500 weight = iter.conicWeight();
406 } break; 501 }
407 case SkPath::kClose_Verb: 502 memcpy(pts, nextPts, sizeof(pts));
408 break; 503 prevVerb = verb;
409 case SkPath::kDone_Verb: 504 verb = nextVerb;
410 break; 505 } while (true);
411 }
412 } 506 }
413 } 507 }
414 508
415 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b litter) { 509 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* b litter) {
416 hair_path(path, clip, blitter, SkScan::HairLineRgn); 510 hair_path(path, clip, blitter, SkScan::HairLineRgn, kNo_ExtendEnds);
417 } 511 }
418 512
419 void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip, SkBlitte r* blitter) { 513 void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip, SkBlitte r* blitter) {
420 hair_path(path, clip, blitter, SkScan::AntiHairLineRgn); 514 hair_path(path, clip, blitter, SkScan::AntiHairLineRgn, kNo_ExtendEnds);
515 }
516
517 void SkScan::HairCapPath(const SkPath& path, const SkRasterClip& clip, SkBlitter * blitter) {
518 hair_path(path, clip, blitter, SkScan::HairLineRgn, kCaps_ExtendEnds);
519 }
520
521 void SkScan::AntiHairCapPath(const SkPath& path, const SkRasterClip& clip, SkBli tter* blitter) {
522 hair_path(path, clip, blitter, SkScan::AntiHairLineRgn, kCaps_ExtendEnds);
421 } 523 }
422 524
423 /////////////////////////////////////////////////////////////////////////////// 525 ///////////////////////////////////////////////////////////////////////////////
424 526
425 void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize, 527 void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize,
426 const SkRasterClip& clip, SkBlitter* blitter) { 528 const SkRasterClip& clip, SkBlitter* blitter) {
427 SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0); 529 SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
428 530
429 if (strokeSize.fX < 0 || strokeSize.fY < 0) { 531 if (strokeSize.fX < 0 || strokeSize.fY < 0) {
430 return; 532 return;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 592
491 SkAAClipBlitterWrapper wrap; 593 SkAAClipBlitterWrapper wrap;
492 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) { 594 if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) {
493 wrap.init(clip, blitter); 595 wrap.init(clip, blitter);
494 blitter = wrap.getBlitter(); 596 blitter = wrap.getBlitter();
495 clipRgn = &wrap.getRgn(); 597 clipRgn = &wrap.getRgn();
496 } 598 }
497 AntiHairLineRgn(pts, count, clipRgn, blitter); 599 AntiHairLineRgn(pts, count, clipRgn, blitter);
498 } 600 }
499 } 601 }
OLDNEW
« gm/hairlines.cpp ('K') | « src/core/SkScan.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698