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