513 static final class PathClipFilter implements DPathConsumer2D {
514
515 private DPathConsumer2D out;
516
517 // Bounds of the drawing region, at pixel precision.
518 private final double[] clipRect;
519
520 private final double[] corners = new double[8];
521 private boolean init_corners = false;
522
523 private final IndexStack stack;
524
525 // the current outcode of the current sub path
526 private int cOutCode = 0;
527
528 // the cumulated (and) outcode of the complete path
529 private int gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
530
531 private boolean outside = false;
532
533 // The current point (TODO stupid repeated info)
534 private double cx0, cy0;
535
536 // The current point OUTSIDE
537 private double cox0, coy0;
538
539 private boolean subdivide = MarlinConst.DO_CLIP_SUBDIVIDER;
540 private final CurveClipSplitter curveSplitter;
541
542 PathClipFilter(final DRendererContext rdrCtx) {
543 this.clipRect = rdrCtx.clipRect;
544 this.curveSplitter = rdrCtx.curveClipSplitter;
545
546 this.stack = (rdrCtx.stats != null) ?
547 new IndexStack(rdrCtx,
548 rdrCtx.stats.stat_pcf_idxstack_indices,
549 rdrCtx.stats.hist_pcf_idxstack_indices,
550 rdrCtx.stats.stat_array_pcf_idxstack_indices)
551 : new IndexStack(rdrCtx);
552 }
613 this.cx0 = cox0;
614 this.cy0 = coy0;
615 }
616
617 @Override
618 public void pathDone() {
619 finishPath();
620
621 out.pathDone();
622
623 // TODO: fix possible leak if exception happened
624 // Dispose this instance:
625 dispose();
626 }
627
628 @Override
629 public void closePath() {
630 finishPath();
631
632 out.closePath();
633 }
634
635 @Override
636 public void moveTo(final double x0, final double y0) {
637 finishPath();
638
639 this.cOutCode = DHelpers.outcode(x0, y0, clipRect);
640 this.outside = false;
641 out.moveTo(x0, y0);
642 this.cx0 = x0;
643 this.cy0 = y0;
644 }
645
646 @Override
647 public void lineTo(final double xe, final double ye) {
648 final int outcode0 = this.cOutCode;
649 final int outcode1 = DHelpers.outcode(xe, ye, clipRect);
650
651 // Should clip
652 final int orCode = (outcode0 | outcode1);
653 if (orCode != 0) {
654 final int sideCode = (outcode0 & outcode1);
655
656 // basic rejection criteria:
657 if (sideCode == 0) {
658 // ovelap clip:
659 if (subdivide) {
660 // avoid reentrance
661 subdivide = false;
662 boolean ret;
663 // subdivide curve => callback with subdivided parts:
664 if (outside) {
665 ret = curveSplitter.splitLine(cox0, coy0, xe, ye,
666 orCode, this);
667 } else {
668 ret = curveSplitter.splitLine(cx0, cy0, xe, ye,
669 orCode, this);
670 }
671 // reentrance is done:
672 subdivide = true;
673 if (ret) {
674 return;
675 }
676 }
677 // already subdivided so render it
678 } else {
737 }
738 }
739
740 @Override
741 public void curveTo(final double x1, final double y1,
742 final double x2, final double y2,
743 final double xe, final double ye)
744 {
745 final int outcode0 = this.cOutCode;
746 final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
747 final int outcode2 = DHelpers.outcode(x2, y2, clipRect);
748 final int outcode3 = DHelpers.outcode(xe, ye, clipRect);
749
750 // Should clip
751 final int orCode = (outcode0 | outcode1 | outcode2 | outcode3);
752 if (orCode != 0) {
753 final int sideCode = outcode0 & outcode1 & outcode2 & outcode3;
754
755 // basic rejection criteria:
756 if (sideCode == 0) {
757 // ovelap clip:
758 if (subdivide) {
759 // avoid reentrance
760 subdivide = false;
761 // subdivide curve => callback with subdivided parts:
762 boolean ret;
763 if (outside) {
764 ret = curveSplitter.splitCurve(cox0, coy0, x1, y1,
765 x2, y2, xe, ye,
766 orCode, this);
767 } else {
768 ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
769 x2, y2, xe, ye,
770 orCode, this);
771 }
772 // reentrance is done:
773 subdivide = true;
774 if (ret) {
775 return;
776 }
777 }
799 out.curveTo(x1, y1, x2, y2, xe, ye);
800 this.cx0 = xe;
801 this.cy0 = ye;
802 }
803
804 @Override
805 public void quadTo(final double x1, final double y1,
806 final double xe, final double ye)
807 {
808 final int outcode0 = this.cOutCode;
809 final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
810 final int outcode2 = DHelpers.outcode(xe, ye, clipRect);
811
812 // Should clip
813 final int orCode = (outcode0 | outcode1 | outcode2);
814 if (orCode != 0) {
815 final int sideCode = outcode0 & outcode1 & outcode2;
816
817 // basic rejection criteria:
818 if (sideCode == 0) {
819 // ovelap clip:
820 if (subdivide) {
821 // avoid reentrance
822 subdivide = false;
823 // subdivide curve => callback with subdivided parts:
824 boolean ret;
825 if (outside) {
826 ret = curveSplitter.splitQuad(cox0, coy0, x1, y1,
827 xe, ye, orCode, this);
828 } else {
829 ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
830 xe, ye, orCode, this);
831 }
832 // reentrance is done:
833 subdivide = true;
834 if (ret) {
835 return;
836 }
837 }
838 // already subdivided so render it
839 } else {
1136 this.nbSplits = nSplits;
1137 return this;
1138 }
1139 }
1140
1141 static final class PathTracer implements DPathConsumer2D {
1142 private final String prefix;
1143 private DPathConsumer2D out;
1144
1145 PathTracer(String name) {
1146 this.prefix = name + ": ";
1147 }
1148
1149 PathTracer init(DPathConsumer2D out) {
1150 this.out = out;
1151 return this; // fluent API
1152 }
1153
1154 @Override
1155 public void moveTo(double x0, double y0) {
1156 log("moveTo (" + x0 + ", " + y0 + ')');
1157 out.moveTo(x0, y0);
1158 }
1159
1160 @Override
1161 public void lineTo(double x1, double y1) {
1162 log("lineTo (" + x1 + ", " + y1 + ')');
1163 out.lineTo(x1, y1);
1164 }
1165
1166 @Override
1167 public void curveTo(double x1, double y1,
1168 double x2, double y2,
1169 double x3, double y3)
1170 {
1171 log("curveTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ')');
1172 out.curveTo(x1, y1, x2, y2, x3, y3);
1173 }
1174
1175 @Override
1176 public void quadTo(double x1, double y1, double x2, double y2) {
1177 log("quadTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ')');
1178 out.quadTo(x1, y1, x2, y2);
1179 }
1180
1181 @Override
1182 public void closePath() {
1183 log("closePath");
1184 out.closePath();
1185 }
1186
1187 @Override
1188 public void pathDone() {
1189 log("pathDone");
1190 out.pathDone();
1191 }
1192
1193 private void log(final String message) {
1194 MarlinUtils.logInfo(prefix + message);
1195 }
1196
1197 @Override
1198 public long getNativeConsumer() {
1199 throw new InternalError("Not using a native peer");
1200 }
1201 }
1202 }
|
513 static final class PathClipFilter implements DPathConsumer2D {
514
515 private DPathConsumer2D out;
516
517 // Bounds of the drawing region, at pixel precision.
518 private final double[] clipRect;
519
520 private final double[] corners = new double[8];
521 private boolean init_corners = false;
522
523 private final IndexStack stack;
524
525 // the current outcode of the current sub path
526 private int cOutCode = 0;
527
528 // the cumulated (and) outcode of the complete path
529 private int gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
530
531 private boolean outside = false;
532
533 // The starting point of the path
534 private double sx0, sy0;
535
536 // The current point (TODO stupid repeated info)
537 private double cx0, cy0;
538
539 // The current point OUTSIDE
540 private double cox0, coy0;
541
542 private boolean subdivide = MarlinConst.DO_CLIP_SUBDIVIDER;
543 private final CurveClipSplitter curveSplitter;
544
545 PathClipFilter(final DRendererContext rdrCtx) {
546 this.clipRect = rdrCtx.clipRect;
547 this.curveSplitter = rdrCtx.curveClipSplitter;
548
549 this.stack = (rdrCtx.stats != null) ?
550 new IndexStack(rdrCtx,
551 rdrCtx.stats.stat_pcf_idxstack_indices,
552 rdrCtx.stats.hist_pcf_idxstack_indices,
553 rdrCtx.stats.stat_array_pcf_idxstack_indices)
554 : new IndexStack(rdrCtx);
555 }
616 this.cx0 = cox0;
617 this.cy0 = coy0;
618 }
619
620 @Override
621 public void pathDone() {
622 finishPath();
623
624 out.pathDone();
625
626 // TODO: fix possible leak if exception happened
627 // Dispose this instance:
628 dispose();
629 }
630
631 @Override
632 public void closePath() {
633 finishPath();
634
635 out.closePath();
636
637 // back to starting point:
638 this.cOutCode = DHelpers.outcode(sx0, sy0, clipRect);
639 this.cx0 = sx0;
640 this.cy0 = sy0;
641 }
642
643 @Override
644 public void moveTo(final double x0, final double y0) {
645 finishPath();
646
647 out.moveTo(x0, y0);
648
649 // update starting point:
650 this.cOutCode = DHelpers.outcode(x0, y0, clipRect);
651 this.cx0 = x0;
652 this.cy0 = y0;
653
654 this.sx0 = x0;
655 this.sy0 = y0;
656 }
657
658 @Override
659 public void lineTo(final double xe, final double ye) {
660 final int outcode0 = this.cOutCode;
661 final int outcode1 = DHelpers.outcode(xe, ye, clipRect);
662
663 // Should clip
664 final int orCode = (outcode0 | outcode1);
665 if (orCode != 0) {
666 final int sideCode = (outcode0 & outcode1);
667
668 // basic rejection criteria:
669 if (sideCode == 0) {
670 // overlap clip:
671 if (subdivide) {
672 // avoid reentrance
673 subdivide = false;
674 boolean ret;
675 // subdivide curve => callback with subdivided parts:
676 if (outside) {
677 ret = curveSplitter.splitLine(cox0, coy0, xe, ye,
678 orCode, this);
679 } else {
680 ret = curveSplitter.splitLine(cx0, cy0, xe, ye,
681 orCode, this);
682 }
683 // reentrance is done:
684 subdivide = true;
685 if (ret) {
686 return;
687 }
688 }
689 // already subdivided so render it
690 } else {
749 }
750 }
751
752 @Override
753 public void curveTo(final double x1, final double y1,
754 final double x2, final double y2,
755 final double xe, final double ye)
756 {
757 final int outcode0 = this.cOutCode;
758 final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
759 final int outcode2 = DHelpers.outcode(x2, y2, clipRect);
760 final int outcode3 = DHelpers.outcode(xe, ye, clipRect);
761
762 // Should clip
763 final int orCode = (outcode0 | outcode1 | outcode2 | outcode3);
764 if (orCode != 0) {
765 final int sideCode = outcode0 & outcode1 & outcode2 & outcode3;
766
767 // basic rejection criteria:
768 if (sideCode == 0) {
769 // overlap clip:
770 if (subdivide) {
771 // avoid reentrance
772 subdivide = false;
773 // subdivide curve => callback with subdivided parts:
774 boolean ret;
775 if (outside) {
776 ret = curveSplitter.splitCurve(cox0, coy0, x1, y1,
777 x2, y2, xe, ye,
778 orCode, this);
779 } else {
780 ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
781 x2, y2, xe, ye,
782 orCode, this);
783 }
784 // reentrance is done:
785 subdivide = true;
786 if (ret) {
787 return;
788 }
789 }
811 out.curveTo(x1, y1, x2, y2, xe, ye);
812 this.cx0 = xe;
813 this.cy0 = ye;
814 }
815
816 @Override
817 public void quadTo(final double x1, final double y1,
818 final double xe, final double ye)
819 {
820 final int outcode0 = this.cOutCode;
821 final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
822 final int outcode2 = DHelpers.outcode(xe, ye, clipRect);
823
824 // Should clip
825 final int orCode = (outcode0 | outcode1 | outcode2);
826 if (orCode != 0) {
827 final int sideCode = outcode0 & outcode1 & outcode2;
828
829 // basic rejection criteria:
830 if (sideCode == 0) {
831 // overlap clip:
832 if (subdivide) {
833 // avoid reentrance
834 subdivide = false;
835 // subdivide curve => callback with subdivided parts:
836 boolean ret;
837 if (outside) {
838 ret = curveSplitter.splitQuad(cox0, coy0, x1, y1,
839 xe, ye, orCode, this);
840 } else {
841 ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
842 xe, ye, orCode, this);
843 }
844 // reentrance is done:
845 subdivide = true;
846 if (ret) {
847 return;
848 }
849 }
850 // already subdivided so render it
851 } else {
1148 this.nbSplits = nSplits;
1149 return this;
1150 }
1151 }
1152
1153 static final class PathTracer implements DPathConsumer2D {
1154 private final String prefix;
1155 private DPathConsumer2D out;
1156
1157 PathTracer(String name) {
1158 this.prefix = name + ": ";
1159 }
1160
1161 PathTracer init(DPathConsumer2D out) {
1162 this.out = out;
1163 return this; // fluent API
1164 }
1165
1166 @Override
1167 public void moveTo(double x0, double y0) {
1168 log("p.moveTo(" + x0 + ", " + y0 + ");");
1169 out.moveTo(x0, y0);
1170 }
1171
1172 @Override
1173 public void lineTo(double x1, double y1) {
1174 log("p.lineTo(" + x1 + ", " + y1 + ");");
1175 out.lineTo(x1, y1);
1176 }
1177
1178 @Override
1179 public void curveTo(double x1, double y1,
1180 double x2, double y2,
1181 double x3, double y3)
1182 {
1183 log("p.curveTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ", " + x3 + ", " + y3 + ");");
1184 out.curveTo(x1, y1, x2, y2, x3, y3);
1185 }
1186
1187 @Override
1188 public void quadTo(double x1, double y1,
1189 double x2, double y2) {
1190 log("p.quadTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ");");
1191 out.quadTo(x1, y1, x2, y2);
1192 }
1193
1194 @Override
1195 public void closePath() {
1196 log("p.closePath();");
1197 out.closePath();
1198 }
1199
1200 @Override
1201 public void pathDone() {
1202 log("p.pathDone();");
1203 out.pathDone();
1204 }
1205
1206 private void log(final String message) {
1207 MarlinUtils.logInfo(prefix + message);
1208 }
1209
1210 @Override
1211 public long getNativeConsumer() {
1212 throw new InternalError("Not using a native peer");
1213 }
1214 }
1215 }
|