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