OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |