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 "SkScanPriv.h" | 8 #include "SkScanPriv.h" |
9 #include "SkBlitter.h" | 9 #include "SkBlitter.h" |
10 #include "SkEdge.h" | 10 #include "SkEdge.h" |
(...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 tmp.fBottom = cr.fBottom; | 538 tmp.fBottom = cr.fBottom; |
539 if (!tmp.isEmpty()) { | 539 if (!tmp.isEmpty()) { |
540 blitter->blitRectRegion(tmp, clip); | 540 blitter->blitRectRegion(tmp, clip); |
541 } | 541 } |
542 } | 542 } |
543 | 543 |
544 /////////////////////////////////////////////////////////////////////////////// | 544 /////////////////////////////////////////////////////////////////////////////// |
545 | 545 |
546 /** | 546 /** |
547 * If the caller is drawing an inverse-fill path, then it pass true for | 547 * If the caller is drawing an inverse-fill path, then it pass true for |
548 * skipRejectTest, so we don't abort drawing just because the src bounds (ir) | 548 * skipRejectTest, so we don't abort drawing just because the src bounds |
549 * is outside of the clip. | 549 * is outside of the clip. |
550 */ | 550 */ |
551 SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip, | 551 SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip, |
552 const SkIRect& ir, bool skipRejectTest) { | 552 const SkIRect& bounds, bool skipRejectTest, bool bo
undsIsTruncated) { |
553 fBlitter = nullptr; // null means blit nothing | 553 fBlitter = nullptr; // null means blit nothing |
554 fClipRect = nullptr; | 554 fClipRect = nullptr; |
555 | 555 |
556 if (clip) { | 556 if (clip) { |
557 fClipRect = &clip->getBounds(); | 557 fClipRect = &clip->getBounds(); |
558 if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, ir)) { // comple
tely clipped out | 558 if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, bounds)) { // co
mpletely clipped out |
559 return; | 559 return; |
560 } | 560 } |
561 | 561 |
562 if (clip->isRect()) { | 562 if (clip->isRect()) { |
563 if (fClipRect->contains(ir)) { | 563 if (!boundsIsTruncated && fClipRect->contains(bounds)) { |
564 fClipRect = nullptr; | 564 fClipRect = nullptr; |
565 } else { | 565 } else { |
566 // only need a wrapper blitter if we're horizontally clipped | 566 // only need a wrapper blitter if we're horizontally clipped |
567 if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight
) { | 567 if (boundsIsTruncated || |
| 568 fClipRect->fLeft > bounds.fLeft || fClipRect->fRight < bound
s.fRight) { |
568 fRectBlitter.init(blitter, *fClipRect); | 569 fRectBlitter.init(blitter, *fClipRect); |
569 blitter = &fRectBlitter; | 570 blitter = &fRectBlitter; |
570 } | 571 } |
571 } | 572 } |
572 } else { | 573 } else { |
573 fRgnBlitter.init(blitter, clip); | 574 fRgnBlitter.init(blitter, clip); |
574 blitter = &fRgnBlitter; | 575 blitter = &fRgnBlitter; |
575 } | 576 } |
576 } | 577 } |
577 fBlitter = blitter; | 578 fBlitter = blitter; |
(...skipping 24 matching lines...) Expand all Loading... |
602 double floorXX = floor(xx); | 603 double floorXX = floor(xx); |
603 return (int)floorXX - (xx == floorXX); | 604 return (int)floorXX - (xx == floorXX); |
604 } | 605 } |
605 | 606 |
606 /** | 607 /** |
607 * Variant of SkRect::round() that explicitly performs the rounding step (i.e.
floor(x + 0.5)) | 608 * Variant of SkRect::round() that explicitly performs the rounding step (i.e.
floor(x + 0.5)) |
608 * using double instead of SkScalar (float). It does this by calling SkDScalar
RoundToInt(), | 609 * using double instead of SkScalar (float). It does this by calling SkDScalar
RoundToInt(), |
609 * which may be slower than calling SkScalarRountToInt(), but gives slightly m
ore accurate | 610 * which may be slower than calling SkScalarRountToInt(), but gives slightly m
ore accurate |
610 * results. Also rounds top and left using double, flooring when the fraction
is exactly 0.5f. | 611 * results. Also rounds top and left using double, flooring when the fraction
is exactly 0.5f. |
611 * | 612 * |
| 613 * When src has huge coordinates, clips dst by clip and returns true. |
| 614 * |
612 * e.g. | 615 * e.g. |
613 * SkScalar left = 0.5f; | 616 * SkScalar left = 0.5f; |
614 * int ileft = SkScalarRoundToInt(left); | 617 * int ileft = SkScalarRoundToInt(left); |
615 * SkASSERT(0 == ileft); // <--- fails | 618 * SkASSERT(0 == ileft); // <--- fails |
616 * int ileft = round_down_to_int(left); | 619 * int ileft = round_down_to_int(left); |
617 * SkASSERT(0 == ileft); // <--- succeeds | 620 * SkASSERT(0 == ileft); // <--- succeeds |
618 * SkScalar right = 0.49999997f; | 621 * SkScalar right = 0.49999997f; |
619 * int iright = SkScalarRoundToInt(right); | 622 * int iright = SkScalarRoundToInt(right); |
620 * SkASSERT(0 == iright); // <--- fails | 623 * SkASSERT(0 == iright); // <--- fails |
621 * iright = SkDScalarRoundToInt(right); | 624 * iright = SkDScalarRoundToInt(right); |
622 * SkASSERT(0 == iright); // <--- succeeds | 625 * SkASSERT(0 == iright); // <--- succeeds |
623 */ | 626 */ |
624 static void round_asymmetric_to_int(const SkRect& src, SkIRect* dst) { | 627 static bool round_asymmetric_to_int(const SkRect& src, const SkIRect& clip, SkIR
ect* dst) { |
625 SkASSERT(dst); | 628 SkASSERT(dst); |
626 dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop), | 629 static const int32_t kLimit = 32767; |
627 SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom)); | 630 const SkIRect max = SkIRect::MakeLTRB(-kLimit, -kLimit, kLimit, kLimit); |
| 631 if (max.contains(src)) { |
| 632 dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop), |
| 633 SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBotto
m)); |
| 634 return false; |
| 635 } |
| 636 SkRect clipped; |
| 637 if (clipped.intersect(src, SkRect::Make(clip))) { |
| 638 dst->set(round_down_to_int(clipped.fLeft), round_down_to_int(clipped.fTo
p), |
| 639 SkDScalarRoundToInt(clipped.fRight), SkDScalarRoundToInt(clippe
d.fBottom)); |
| 640 } else { |
| 641 dst->setEmpty(); |
| 642 } |
| 643 return true; |
628 } | 644 } |
629 | 645 |
630 void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, | 646 void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, |
631 SkBlitter* blitter) { | 647 SkBlitter* blitter) { |
632 if (origClip.isEmpty()) { | 648 if (origClip.isEmpty()) { |
633 return; | 649 return; |
634 } | 650 } |
635 | 651 |
636 // Our edges are fixed-point, and don't like the bounds of the clip to | 652 // Our edges are fixed-point, and don't like the bounds of the clip to |
637 // exceed that. Here we trim the clip just so we don't overflow later on | 653 // exceed that. Here we trim the clip just so we don't overflow later on |
638 const SkRegion* clipPtr = &origClip; | 654 const SkRegion* clipPtr = &origClip; |
639 SkRegion finiteClip; | 655 SkRegion finiteClip; |
640 if (clip_to_limit(origClip, &finiteClip)) { | 656 if (clip_to_limit(origClip, &finiteClip)) { |
641 if (finiteClip.isEmpty()) { | 657 if (finiteClip.isEmpty()) { |
642 return; | 658 return; |
643 } | 659 } |
644 clipPtr = &finiteClip; | 660 clipPtr = &finiteClip; |
645 } | 661 } |
646 // don't reference "origClip" any more, just use clipPtr | 662 // don't reference "origClip" any more, just use clipPtr |
647 | 663 |
648 SkIRect ir; | 664 SkIRect ir; |
649 // We deliberately call round_asymmetric_to_int() instead of round(), since
we can't afford | 665 // We deliberately call round_asymmetric_to_int() instead of round(), since
we can't afford |
650 // to generate a bounds that is tighter than the corresponding SkEdges. The
edge code basically | 666 // to generate a bounds that is tighter than the corresponding SkEdges. The
edge code basically |
651 // converts the floats to fixed, and then "rounds". If we called round() ins
tead of | 667 // converts the floats to fixed, and then "rounds". If we called round() ins
tead of |
652 // round_asymmetric_to_int() here, we could generate the wrong ir for values
like 0.4999997. | 668 // round_asymmetric_to_int() here, we could generate the wrong ir for values
like 0.4999997. |
653 round_asymmetric_to_int(path.getBounds(), &ir); | 669 bool irIsClipped = round_asymmetric_to_int(path.getBounds(), clipPtr->getBou
nds(), &ir); |
654 if (ir.isEmpty()) { | 670 if (ir.isEmpty()) { |
655 if (path.isInverseFillType()) { | 671 if (path.isInverseFillType()) { |
656 blitter->blitRegion(*clipPtr); | 672 blitter->blitRegion(*clipPtr); |
657 } | 673 } |
658 return; | 674 return; |
659 } | 675 } |
660 | 676 |
661 SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType()); | 677 SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType(), irIsCl
ipped); |
662 | 678 |
663 blitter = clipper.getBlitter(); | 679 blitter = clipper.getBlitter(); |
664 if (blitter) { | 680 if (blitter) { |
665 // we have to keep our calls to blitter in sorted order, so we | 681 // we have to keep our calls to blitter in sorted order, so we |
666 // must blit the above section first, then the middle, then the bottom. | 682 // must blit the above section first, then the middle, then the bottom. |
667 if (path.isInverseFillType()) { | 683 if (path.isInverseFillType()) { |
668 sk_blit_above(blitter, ir, *clipPtr); | 684 sk_blit_above(blitter, ir, *clipPtr); |
669 } | 685 } |
670 sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom, | 686 sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom, |
671 0, *clipPtr); | 687 0, *clipPtr); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
768 clipRgn = &wrap.getRgn(); | 784 clipRgn = &wrap.getRgn(); |
769 blitter = wrap.getBlitter(); | 785 blitter = wrap.getBlitter(); |
770 } | 786 } |
771 | 787 |
772 SkScanClipper clipper(blitter, clipRgn, ir); | 788 SkScanClipper clipper(blitter, clipRgn, ir); |
773 blitter = clipper.getBlitter(); | 789 blitter = clipper.getBlitter(); |
774 if (blitter) { | 790 if (blitter) { |
775 sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir); | 791 sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir); |
776 } | 792 } |
777 } | 793 } |
OLD | NEW |