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

Side by Side Diff: src/core/SkEdge.cpp

Issue 2221103002: Analytic AntiAlias for Convex Shapes (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Make alpha computation cleaner and faster Created 4 years, 4 months 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
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 8
9 #include "SkEdge.h" 9 #include "SkEdge.h"
10 #include "SkFDot6.h" 10 #include "SkFDot6.h"
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 success = this->updateLine(oldx, oldy, newx, newy); 470 success = this->updateLine(oldx, oldy, newx, newy);
471 oldx = newx; 471 oldx = newx;
472 oldy = newy; 472 oldy = newy;
473 } while (count < 0 && !success); 473 } while (count < 0 && !success);
474 474
475 fCx = newx; 475 fCx = newx;
476 fCy = newy; 476 fCy = newy;
477 fCurveCount = SkToS8(count); 477 fCurveCount = SkToS8(count);
478 return success; 478 return success;
479 } 479 }
480
481 ///////////////////Analytic Edges///////////////////////////////
482
483 int SkAnalyticEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip) {
caryclark 2016/08/10 13:08:09 Since this shares so much code with the other setL
liyuqian 2016/08/16 13:22:05 Done. I removed the other method and make clip hav
484 SkFixed x0, y0, x1, y1;
485
486 x0 = SkScalarToFixed(p0.fX);
caryclark 2016/08/10 13:08:10 SkFixed x0 = ...
liyuqian 2016/08/16 13:22:05 Done.
487 y0 = snapY(SkScalarToFixed(p0.fY));
488 x1 = SkScalarToFixed(p1.fX);
489 y1 = snapY(SkScalarToFixed(p1.fY));
490
491 int winding = 1;
492
493 if (y0 > y1) {
494 SkTSwap(x0, x1);
495 SkTSwap(y0, y1);
496 winding = -1;
497 }
498
499 int top = SkFixedFloorToInt(y0);
500 int bot = SkFixedCeilToInt(y1);
501
502 // are we a zero-height line?
503 if (y0 == y1) {
caryclark 2016/08/10 13:08:10 move test before top, bot
liyuqian 2016/08/16 13:22:05 Done.
504 return 0;
505 }
506 // are we completely above or below the clip?
507 if (clip && (top >= clip->fBottom || bot <= clip->fTop)) {
508 return 0;
509 }
510
511 SkFixed slope = SkFixedDiv(x1 - x0, y1 - y0);
512
513 fX = x0;
514 fDX = slope;
515 fUpperX = x0;
516 fY = y0;
517 fUpperY = y0;
518 fLowerY = y1;
519 fDY = x1 - x0 != 0 ? SkAbs32(SkFixedDiv(y1 - y0, x1 - x0)) : SK_MaxS 32;
caryclark 2016/08/10 13:08:09 x1 == x0 ?
liyuqian 2016/08/16 13:22:05 Done.
520 fCurveCount = 0;
521 fWinding = SkToS8(winding);
522 fCurveShift = 0;
523
524 if (clip) {
525 this->chopLineWithClip(*clip);
526 }
527 return 1;
528 }
529
530 int SkAnalyticEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1)
531 {
532 y0 = snapY(y0);
533 y1 = snapY(y1);
534 SkASSERT(fWinding == 1 || fWinding == -1);
535 SkASSERT(fCurveCount != 0);
536
537 SkASSERT(y0 <= y1);
538
539 // are we a zero-height line?
540 if (y0 == y1)
caryclark 2016/08/10 13:08:10 add braces around if
liyuqian 2016/08/16 13:22:05 Done.
541 return 0;
542
543 SkFixed slope = SkFixedDiv(x1 - x0, y1 - y0);
544
545 fX = x0;
546 fDX = slope;
547 fUpperX = x0;
548 fY = y0;
549 fUpperY = y0;
550 fLowerY = y1;
551 fDY = x1 - x0 != 0 ? SkAbs32(SkFixedDiv(y1 - y0, x1 - x0)) : SK_MaxS 32;
caryclark 2016/08/10 13:08:09 this also shares a lot of code with setline. Can t
liyuqian 2016/08/16 13:22:05 In my new CL, this probably is not the case as I h
552
553 return 1;
554 }
555
556 void SkAnalyticEdge::chopLineWithClip(const SkIRect& clip)
557 {
558 int top = SkFixedFloorToInt(fUpperY);
559
560 SkASSERT(top < clip.fBottom);
561
562 // clip the line to the clip top
563 if (top < clip.fTop)
564 {
caryclark 2016/08/10 13:08:09 brace on same line as if
liyuqian 2016/08/16 13:22:05 Done.
565 SkASSERT(SkFixedCeilToInt(fLowerY) > clip.fTop);
566 SkFixed newY = SkIntToFixed(clip.fTop);
567 this->goY(newY);
568 fUpperY = newY;
569 }
570 }
571
572 int SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3])
573 {
574 SkFDot6 x0, y0, x1, y1, x2, y2;
575
576 x0 = SkScalarToFixed(pts[0].fX);
caryclark 2016/08/10 13:08:09 SkFDot6 x0 = ...
liyuqian 2016/08/16 13:22:05 Done.
577 y0 = SkScalarToFixed(pts[0].fY);
578 x1 = SkScalarToFixed(pts[1].fX);
579 y1 = SkScalarToFixed(pts[1].fY);
580 x2 = SkScalarToFixed(pts[2].fX);
581 y2 = SkScalarToFixed(pts[2].fY);
582
583 int winding = 1;
584 if (y0 > y2)
585 {
586 SkTSwap(x0, x2);
587 SkTSwap(y0, y2);
588 winding = -1;
589 }
590 SkASSERT(y0 <= y1 && y1 <= y2);
591
592 int top = SkFixedFloorToInt(y0);
593 int bot = SkFixedCeilToInt(y2);
594
595 // are we a zero-height quad (line)?
596 if (top == bot)
caryclark 2016/08/10 13:08:09 add braces
liyuqian 2016/08/16 13:22:05 Done.
597 return 0;
598
599 int shift;
600 // compute number of steps needed (1 << shift)
601 {
602 // The dx, dy here are 4 times larger so we get the right shift
603 // from 4x4 supersampling's diff_to_shift function
604 SkFDot6 dx = SkFixedToFDot6((SkLeftShift(x1, 1) - x0 - x2));
605 SkFDot6 dy = SkFixedToFDot6((SkLeftShift(y1, 1) - y0 - y2));
606 shift = diff_to_shift(dx, dy);
607 SkASSERT(shift >= 0);
608 }
609 // need at least 1 subdivision for our bias trick
610 if (shift == 0) {
611 shift = 1;
612 } else if (shift > MAX_COEFF_SHIFT) {
613 shift = MAX_COEFF_SHIFT;
614 }
caryclark 2016/08/10 13:08:09 Out of curiosity, is this any less efficient and m
liyuqian 2016/08/16 13:22:05 I'm not sure. Maybe shift = SkTPin(shift, 1, MAX_C
615
616 fWinding = SkToS8(winding);
617 //fCubicDShift only set for cubics
618 fCurveCount = SkToS8(1 << shift);
619
620 /*
621 * We want to reformulate into polynomial form, to make it clear how we
622 * should forward-difference.
623 *
624 * p0 (1 - t)^2 + p1 t(1 - t) + p2 t^2 ==> At^2 + Bt + C
625 *
626 * A = p0 - 2p1 + p2
627 * B = 2(p1 - p0)
628 * C = p0
629 *
630 * Our caller must have constrained our inputs (p0..p2) to all fit into
631 * 16.16. However, as seen above, we sometimes compute values that can be
632 * larger (e.g. B = 2*(p1 - p0)). To guard against overflow, we will store
633 * A and B at 1/2 of their actual value, and just apply a 2x scale during
634 * application in updateQuadratic(). Hence we store (shift - 1) in
635 * fCurveShift.
636 */
637
638 fCurveShift = SkToU8(shift - 1);
639
640 SkFixed A = (x0 - x1 - x1 + x2) >> 1; // 1/2 the real value
641 SkFixed B = x1 - x0; // 1/2 the real value
642
643 fQx = x0;
644 fQDx = B + (A >> shift); // biased by shift
645 fQDDx = A >> (shift - 1); // biased by shift
646
647 A = (y0 - y1 - y1 + y2) >> 1; // 1/2 the real value
648 B = y1 - y0; // 1/2 the real value
649
650 fQy = y0;
651 fQDy = B + (A >> shift); // biased by shift
652 fQDDy = A >> (shift - 1); // biased by shift
653
654 fQLastX = x2;
655 fQLastY = y2;
656
657 fSnappedX = fQx;
658 fSnappedY = fQy;
659
660 return this->updateQuadratic();
661 }
662
663 int SkAnalyticQuadraticEdge::updateQuadratic()
664 {
665 int success = 0; // initialize to fail!
666 int count = fCurveCount;
667 SkFixed oldx = fQx;
668 SkFixed oldy = fQy;
669 SkFixed dx = fQDx;
670 SkFixed dy = fQDy;
671 SkFixed newx, newy, newSnappedX, newSnappedY;
672 int shift = fCurveShift;
673
674 SkASSERT(count > 0);
675
676 do {
677 if (--count > 0)
678 {
679 newx = oldx + (dx >> shift);
680 dx += fQDDx;
681 newy = oldy + (dy >> shift);
682 dy += fQDDy;
683 if (SkAbs32(dy) >= SK_Fixed1 * 2) { // only snap when dy is large en ough
684 newSnappedY = SkTMin<SkFixed>(fQLastY, SkFixedRoundToFixed(newy) );
685 newSnappedX = newx + SkFixedMul(SkFixedDiv(dx, dy), newSnappedY - newy);
686 } else {
687 newSnappedY = newy;
688 newSnappedX = newx;
689 }
690 }
691 else // last segment
692 {
693 newx = fQLastX;
694 newy = fQLastY;
695 newSnappedY = newy;
696 newSnappedX = newx;
697 }
698 if (newSnappedY > fSnappedY) {
699 success = this->updateLine(fSnappedX, fSnappedY, newSnappedX, newSna ppedY);
700 }
701 oldx = newx;
702 oldy = newy;
703 } while (count > 0 && !success);
704
705 SkASSERT(newSnappedY <= fQLastY);
706
707 fQx = newx;
708 fQy = newy;
709 fQDx = dx;
710 fQDy = dy;
711 fSnappedX = newSnappedX;
712 fSnappedY = newSnappedY;
713 fCurveCount = SkToS8(count);
714 return success;
715 }
716
717 int SkAnalyticCubicEdge::setCubic(const SkPoint pts[4]) {
718 SkFixed x0, y0, x1, y1, x2, y2, x3, y3;
719
720 x0 = SkScalarToFixed(pts[0].fX);
721 y0 = SkScalarToFixed(pts[0].fY);
722 x1 = SkScalarToFixed(pts[1].fX);
723 y1 = SkScalarToFixed(pts[1].fY);
724 x2 = SkScalarToFixed(pts[2].fX);
725 y2 = SkScalarToFixed(pts[2].fY);
726 x3 = SkScalarToFixed(pts[3].fX);
727 y3 = SkScalarToFixed(pts[3].fY);
728
729 int winding = 1;
730 if (y0 > y3)
731 {
732 SkTSwap(x0, x3);
733 SkTSwap(x1, x2);
734 SkTSwap(y0, y3);
735 SkTSwap(y1, y2);
736 winding = -1;
737 }
738
739 int top = SkFixedFloorToInt(y0);
740 int bot = SkFixedCeilToInt(y3);
741
742 // are we a zero-height cubic (line)?
743 if (top == bot)
744 return 0;
745
746 int shift;
747 // compute number of steps needed (1 << shift)
748 {
749 // The dx, dy here are 4 times larger so we get the right shift
750 // from 4x4 supersampling's diff_to_shift function
751
752 // Can't use (center of curve - center of baseline), since center-of-cur ve
753 // need not be the max delta from the baseline (it could even be coincid ent)
754 // so we try just looking at the two off-curve points
755 SkFDot6 dx = cubic_delta_from_line(SkFixedToFDot6(x0 << 2),SkFixedToFDot 6(x1 << 2),
756 SkFixedToFDot6(x2 << 2), SkFixedToFDo t6(x3 << 2));
757 SkFDot6 dy = cubic_delta_from_line(SkFixedToFDot6(y0 << 2), SkFixedToFDo t6(y1 << 2),
758 SkFixedToFDot6(y2 << 2), SkFixedToFDo t6(y3 << 2));
759 // add 1 (by observation)
760 shift = diff_to_shift(dx, dy) + 1;
761 }
762 // need at least 1 subdivision for our bias trick
763 SkASSERT(shift > 0);
764 if (shift > MAX_COEFF_SHIFT) {
765 shift = MAX_COEFF_SHIFT;
766 }
767
768 /* Since our in coming data is initially shifted down by 10 (or 8 in
769 antialias). That means the most we can shift up is 8. However, we
770 compute coefficients with a 3*, so the safest upshift is really 6
771 */
772 int upShift = 6; // largest safe value
773 int downShift = shift + upShift - 10;
774 if (downShift < 0) {
775 downShift = 0;
776 upShift = 10 - shift;
777 }
778
779 fWinding = SkToS8(winding);
780 fCurveCount = SkToS8(SkLeftShift(-1, shift));
781 fCurveShift = SkToU8(shift);
782 fCubicDShift = SkToU8(downShift);
783
784 SkFixed B = SkFDot6UpShift(SkFixedToFDot6(3 * (x1 - x0)), upShift);
785 SkFixed C = SkFDot6UpShift(SkFixedToFDot6(3 * (x0 - x1 - x1 + x2)), upShift) ;
786 SkFixed D = SkFDot6UpShift(SkFixedToFDot6(x3 + 3 * (x1 - x2) - x0), upShift) ;
787
788 fCx = x0;
789 fCDx = B + (C >> shift) + (D >> 2*shift); // biased by shift
790 fCDDx = 2*C + (3*D >> (shift - 1)); // biased by 2*shift
791 fCDDDx = 3*D >> (shift - 1); // biased by 2*shift
792
793 B = SkFDot6UpShift(SkFixedToFDot6(3 * (y1 - y0)), upShift);
794 C = SkFDot6UpShift(SkFixedToFDot6(3 * (y0 - y1 - y1 + y2)), upShift);
795 D = SkFDot6UpShift(SkFixedToFDot6(y3 + 3 * (y1 - y2) - y0), upShift);
796
797 fCy = y0;
798 fCDy = B + (C >> shift) + (D >> 2*shift); // biased by shift
799 fCDDy = 2*C + (3*D >> (shift - 1)); // biased by 2*shift
800 fCDDDy = 3*D >> (shift - 1); // biased by 2*shift
801
802 fCLastX = x3;
803 fCLastY = y3;
804
805 return this->updateCubic();
806 }
807
808 int SkAnalyticCubicEdge::updateCubic()
809 {
810 int success;
811 int count = fCurveCount;
812 SkFixed oldx = fCx;
813 SkFixed oldy = fCy;
814 SkFixed newx, newy;
815 const int ddshift = fCurveShift;
816 const int dshift = fCubicDShift;
817
818 SkASSERT(count < 0);
819
820 do {
821 if (++count < 0)
822 {
823 newx = oldx + (fCDx >> dshift);
824 fCDx += fCDDx >> ddshift;
825 fCDDx += fCDDDx;
826
827 newy = oldy + (fCDy >> dshift);
828 fCDy += fCDDy >> ddshift;
829 fCDDy += fCDDDy;
830 }
831 else // last segment
832 {
833 // SkDebugf("LastX err=%d, LastY err=%d\n", (oldx + (fCDx >> shift) - f LastX), (oldy + (fCDy >> shift) - fLastY));
834 newx = fCLastX;
835 newy = fCLastY;
836 }
837
838 // we want to say SkASSERT(oldy <= newy), but our finite fixedpoint
839 // doesn't always achieve that, so we have to explicitly pin it here.
840 if (newy < oldy) {
841 newy = oldy;
842 }
843
844 success = this->updateLine(oldx, oldy, newx, newy);
845 oldx = newx;
846 oldy = newy;
847 } while (count < 0 && !success);
848
849 fCx = newx;
850 fCy = newy;
851 fCurveCount = SkToS8(count);
852 return success;
853 }
OLDNEW
« src/core/SkEdge.h ('K') | « src/core/SkEdge.h ('k') | src/core/SkEdgeBuilder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698