< prev index next >

modules/javafx.graphics/src/main/java/com/sun/marlin/TransformingPathConsumer2D.java

Print this page




  81     public PathConsumer2D traceClosedPathDetector(PathConsumer2D out) {
  82         return tracerCPDetector.init(out);
  83     }
  84 
  85     public PathConsumer2D traceFiller(PathConsumer2D out) {
  86         return tracerFiller.init(out);
  87     }
  88 
  89     public PathConsumer2D traceStroker(PathConsumer2D out) {
  90         return tracerStroker.init(out);
  91     }
  92 
  93     public PathConsumer2D traceDasher(PathConsumer2D out) {
  94         return tracerDasher.init(out);
  95     }
  96 
  97     public PathConsumer2D detectClosedPath(PathConsumer2D out) {
  98         return cpDetector.init(out);
  99     }
 100 
 101     public PathConsumer2D pathClipper(PathConsumer2D out,
 102                                       final float rdrOffX,
 103                                       final float rdrOffY)
 104     {
 105         return pathClipper.init(out, rdrOffX, rdrOffY);
 106     }
 107 
 108     public PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
 109                                                  BaseTransform at,
 110                                                  final float rdrOffX,
 111                                                  final float rdrOffY)
 112     {
 113         if (at == null) {
 114             return out;
 115         }
 116         final float mxx = (float) at.getMxx();
 117         final float mxy = (float) at.getMxy();
 118         final float myx = (float) at.getMyx();
 119         final float myy = (float) at.getMyy();
 120 
 121         if (mxy == 0.0f && myx == 0.0f) {
 122             if (mxx == 1.0f && myy == 1.0f) {
 123                 return out;
 124             } else {
 125                 // Scale only
 126                 if (rdrCtx.doClip) {
 127                     // adjust clip rectangle (ymin, ymax, xmin, xmax):
 128                     adjustClipOffset(rdrCtx.clipRect, rdrOffX, rdrOffY);
 129                     adjustClipScale(rdrCtx.clipRect, mxx, myy);
 130                 }
 131                 return dt_DeltaScaleFilter.init(out, mxx, myy);
 132             }
 133         } else {
 134             if (rdrCtx.doClip) {
 135                 // adjust clip rectangle (ymin, ymax, xmin, xmax):
 136                 adjustClipOffset(rdrCtx.clipRect, rdrOffX, rdrOffY);
 137                 adjustClipInverseDelta(rdrCtx.clipRect, mxx, mxy, myx, myy);
 138             }
 139             return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
 140         }
 141     }
 142 
 143     private static void adjustClipOffset(final float[] clipRect,
 144                                          final float rdrOffX,
 145                                          final float rdrOffY)
 146     {
 147         clipRect[0] += rdrOffY;
 148         clipRect[1] += rdrOffY;
 149         clipRect[2] += rdrOffX;
 150         clipRect[3] += rdrOffX;
 151     }
 152 
 153     private static void adjustClipScale(final float[] clipRect,
 154                                         final float mxx, final float myy)
 155     {
 156         // Adjust the clipping rectangle (iv_DeltaScaleFilter):
 157         clipRect[0] /= myy;
 158         clipRect[1] /= myy;
 159         clipRect[2] /= mxx;
 160         clipRect[3] /= mxx;




 161     }
 162 
 163     private static void adjustClipInverseDelta(final float[] clipRect,

















 164                                                final float mxx, final float mxy,
 165                                                final float myx, final float myy)
 166     {
 167         // Adjust the clipping rectangle (iv_DeltaTransformFilter):
 168         final float det = mxx * myy - mxy * myx;
 169         final float imxx =  myy / det;
 170         final float imxy = -mxy / det;
 171         final float imyx = -myx / det;
 172         final float imyy =  mxx / det;
 173 
 174         float xmin, xmax, ymin, ymax;
 175         float x, y;
 176         // xmin, ymin:
 177         x = clipRect[2] * imxx + clipRect[0] * imxy;
 178         y = clipRect[2] * imyx + clipRect[0] * imyy;
 179 
 180         xmin = xmax = x;
 181         ymin = ymax = y;
 182 
 183         // xmax, ymin:


 188         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 189 
 190         // xmin, ymax:
 191         x = clipRect[2] * imxx + clipRect[1] * imxy;
 192         y = clipRect[2] * imyx + clipRect[1] * imyy;
 193 
 194         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 195         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 196 
 197         // xmax, ymax:
 198         x = clipRect[3] * imxx + clipRect[1] * imxy;
 199         y = clipRect[3] * imyx + clipRect[1] * imyy;
 200 
 201         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 202         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 203 
 204         clipRect[0] = ymin;
 205         clipRect[1] = ymax;
 206         clipRect[2] = xmin;
 207         clipRect[3] = xmax;










 208     }
 209 
 210     public PathConsumer2D inverseDeltaTransformConsumer(PathConsumer2D out,
 211                                                         BaseTransform at)
 212     {
 213         if (at == null) {
 214             return out;
 215         }
 216         float mxx = (float) at.getMxx();
 217         float mxy = (float) at.getMxy();
 218         float myx = (float) at.getMyx();
 219         float myy = (float) at.getMyy();
 220 
 221         if (mxy == 0.0f && myx == 0.0f) {
 222             if (mxx == 1.0f && myy == 1.0f) {
 223                 return out;
 224             } else {
 225                 return iv_DeltaScaleFilter.init(out, 1.0f/mxx, 1.0f/myy);
 226             }
 227         } else {
 228             final float det = mxx * myy - mxy * myx;
 229             return iv_DeltaTransformFilter.init(out,
 230                                                 myy / det,
 231                                                -mxy / det,
 232                                                -myx / det,
 233                                                 mxx / det);
 234         }
 235     }
 236 
 237     static final class DeltaScaleFilter implements PathConsumer2D {
 238         private PathConsumer2D out;
 239         private float sx, sy;
 240 
 241         DeltaScaleFilter() {}
 242 
 243         DeltaScaleFilter init(PathConsumer2D out,
 244                               float mxx, float myy)
 245         {


 499         private float cx0, cy0;
 500 
 501         // The current point OUTSIDE
 502         private float cox0, coy0;
 503 
 504         private boolean subdivide = MarlinConst.DO_CLIP_SUBDIVIDER;
 505         private final CurveClipSplitter curveSplitter;
 506 
 507         PathClipFilter(final RendererContext rdrCtx) {
 508             this.clipRect = rdrCtx.clipRect;
 509             this.curveSplitter = rdrCtx.curveClipSplitter;
 510 
 511             this.stack = (rdrCtx.stats != null) ?
 512                 new IndexStack(rdrCtx,
 513                         rdrCtx.stats.stat_pcf_idxstack_indices,
 514                         rdrCtx.stats.hist_pcf_idxstack_indices,
 515                         rdrCtx.stats.stat_array_pcf_idxstack_indices)
 516                 : new IndexStack(rdrCtx);
 517         }
 518 
 519         PathClipFilter init(final PathConsumer2D out,
 520                             final double rdrOffX,
 521                             final double rdrOffY)
 522         {
 523             this.out = out;
 524 
 525             // add a small rounding error:
 526             final float margin = 1e-3f;
 527 
 528             final float[] _clipRect = this.clipRect;
 529             // Adjust the clipping rectangle with the renderer offsets
 530             _clipRect[0] -= margin - rdrOffY;
 531             _clipRect[1] += margin + rdrOffY;
 532             _clipRect[2] -= margin - rdrOffX;
 533             _clipRect[3] += margin + rdrOffX;
 534 
 535             if (MarlinConst.DO_CLIP_SUBDIVIDER) {
 536                 // adjust padded clip rectangle:
 537                 curveSplitter.init();
 538             }
 539 
 540             this.init_corners = true;
 541             this.gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
 542 
 543             return this; // fluent API
 544         }
 545 
 546         /**
 547          * Disposes this instance:
 548          * clean up before reusing this instance
 549          */
 550         void dispose() {
 551             stack.dispose();
 552         }
 553 
 554         private void finishPath() {


 832 
 833             if (outside) {
 834                 finish();
 835             }
 836             // clipping disabled:
 837             out.quadTo(x1, y1, xe, ye);
 838             this.cx0 = xe;
 839             this.cy0 = ye;
 840         }
 841     }
 842 
 843     static final class CurveClipSplitter {
 844 
 845         static final float LEN_TH = MarlinProperties.getSubdividerMinLength();
 846         static final boolean DO_CHECK_LENGTH = (LEN_TH > 0.0f);
 847 
 848         private static final boolean TRACE = false;
 849 
 850         private static final int MAX_N_CURVES = 3 * 4;
 851 





 852         // clip rectangle (ymin, ymax, xmin, xmax):
 853         final float[] clipRect;
 854 
 855         // clip rectangle (ymin, ymax, xmin, xmax) including padding:
 856         final float[] clipRectPad = new float[4];
 857         private boolean init_clipRectPad = false;
 858 
 859         // This is where the curve to be processed is put. We give it
 860         // enough room to store all curves.
 861         final float[] middle = new float[MAX_N_CURVES * 8 + 2];
 862         // t values at subdivision points
 863         private final float[] subdivTs = new float[MAX_N_CURVES];
 864 
 865         // dirty curve
 866         private final Curve curve;
 867 
 868         CurveClipSplitter(final RendererContext rdrCtx) {

 869             this.clipRect = rdrCtx.clipRect;
 870             this.curve = rdrCtx.curve;
 871         }
 872 
 873         void init() {
 874             this.init_clipRectPad = true;










 875         }
 876 
 877         private void initPaddedClip() {
 878             // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
 879             // adjust padded clip rectangle (ymin, ymax, xmin, xmax):
 880             // add a rounding error (curve subdivision ~ 0.1px):
 881             final float[] _clipRect = clipRect;
 882             final float[] _clipRectPad = clipRectPad;
 883 
 884             _clipRectPad[0] = _clipRect[0] - CLIP_RECT_PADDING;
 885             _clipRectPad[1] = _clipRect[1] + CLIP_RECT_PADDING;
 886             _clipRectPad[2] = _clipRect[2] - CLIP_RECT_PADDING;
 887             _clipRectPad[3] = _clipRect[3] + CLIP_RECT_PADDING;
 888 
 889             if (TRACE) {
 890                 MarlinUtils.logInfo("clip: X [" + _clipRectPad[2] + " .. " + _clipRectPad[3] +"] "
 891                                         + "Y ["+ _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
 892             }
 893         }
 894 
 895         boolean splitLine(final float x0, final float y0,
 896                           final float x1, final float y1,
 897                           final int outCodeOR,
 898                           final PathConsumer2D out)
 899         {
 900             if (TRACE) {
 901                 MarlinUtils.logInfo("divLine P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ")");
 902             }
 903 
 904             if (DO_CHECK_LENGTH && Helpers.fastLineLen(x0, y0, x1, y1) <= LEN_TH) {
 905                 return false;
 906             }
 907 
 908             final float[] mid = middle;
 909             mid[0] = x0;  mid[1] = y0;
 910             mid[2] = x1;  mid[3] = y1;
 911 
 912             return subdivideAtIntersections(4, outCodeOR, out);
 913         }
 914 
 915         boolean splitQuad(final float x0, final float y0,
 916                           final float x1, final float y1,
 917                           final float x2, final float y2,
 918                           final int outCodeOR,
 919                           final PathConsumer2D out)
 920         {
 921             if (TRACE) {
 922                 MarlinUtils.logInfo("divQuad P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ")");
 923             }
 924 
 925             if (DO_CHECK_LENGTH && Helpers.fastQuadLen(x0, y0, x1, y1, x2, y2) <= LEN_TH) {
 926                 return false;
 927             }
 928 
 929             final float[] mid = middle;
 930             mid[0] = x0;  mid[1] = y0;
 931             mid[2] = x1;  mid[3] = y1;
 932             mid[4] = x2;  mid[5] = y2;
 933 
 934             return subdivideAtIntersections(6, outCodeOR, out);
 935         }
 936 
 937         boolean splitCurve(final float x0, final float y0,
 938                            final float x1, final float y1,
 939                            final float x2, final float y2,
 940                            final float x3, final float y3,
 941                            final int outCodeOR,
 942                            final PathConsumer2D out)
 943         {
 944             if (TRACE) {
 945                 MarlinUtils.logInfo("divCurve P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ")");
 946             }
 947 
 948             if (DO_CHECK_LENGTH && Helpers.fastCurvelen(x0, y0, x1, y1, x2, y2, x3, y3) <= LEN_TH) {
 949                 return false;
 950             }
 951 
 952             final float[] mid = middle;
 953             mid[0] = x0;  mid[1] = y0;
 954             mid[2] = x1;  mid[3] = y1;
 955             mid[4] = x2;  mid[5] = y2;
 956             mid[6] = x3;  mid[7] = y3;
 957 
 958             return subdivideAtIntersections(8, outCodeOR, out);
 959         }
 960 
 961         private boolean subdivideAtIntersections(final int type, final int outCodeOR,
 962                                                  final PathConsumer2D out)
 963         {
 964             final float[] mid = middle;
 965             final float[] subTs = subdivTs;
 966 
 967             if (init_clipRectPad) {
 968                 init_clipRectPad = false;
 969                 initPaddedClip();
 970             }
 971 
 972             final int nSplits = Helpers.findClipPoints(curve, mid, subTs, type,
 973                                                         outCodeOR, clipRectPad);
 974 
 975             if (TRACE) {
 976                 MarlinUtils.logInfo("nSplits: "+ nSplits);
 977                 MarlinUtils.logInfo("subTs: " + Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
 978             }
 979             if (nSplits == 0) {
 980                 // only curve support shortcut
 981                 return false;
 982             }
 983             float prevT = 0.0f;
 984 
 985             for (int i = 0, off = 0; i < nSplits; i++, off += type) {
 986                 final float t = subTs[i];
 987 
 988                 Helpers.subdivideAt((t - prevT) / (1.0f - prevT),
 989                                      mid, off, mid, off, type);
 990                 prevT = t;
 991             }
 992 
 993             for (int i = 0, off = 0; i <= nSplits; i++, off += type) {
 994                 if (TRACE) {
 995                     MarlinUtils.logInfo("Part Curve " + Arrays.toString(Arrays.copyOfRange(mid, off, off + type)));
 996                 }




  81     public PathConsumer2D traceClosedPathDetector(PathConsumer2D out) {
  82         return tracerCPDetector.init(out);
  83     }
  84 
  85     public PathConsumer2D traceFiller(PathConsumer2D out) {
  86         return tracerFiller.init(out);
  87     }
  88 
  89     public PathConsumer2D traceStroker(PathConsumer2D out) {
  90         return tracerStroker.init(out);
  91     }
  92 
  93     public PathConsumer2D traceDasher(PathConsumer2D out) {
  94         return tracerDasher.init(out);
  95     }
  96 
  97     public PathConsumer2D detectClosedPath(PathConsumer2D out) {
  98         return cpDetector.init(out);
  99     }
 100 
 101     public PathConsumer2D pathClipper(PathConsumer2D out) {
 102         return pathClipper.init(out);



 103     }
 104 
 105     public PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
 106                                                  BaseTransform at)


 107     {
 108         if (at == null) {
 109             return out;
 110         }
 111         final float mxx = (float) at.getMxx();
 112         final float mxy = (float) at.getMxy();
 113         final float myx = (float) at.getMyx();
 114         final float myy = (float) at.getMyy();
 115 
 116         if (mxy == 0.0f && myx == 0.0f) {
 117             if (mxx == 1.0f && myy == 1.0f) {
 118                 return out;
 119             } else {
 120                 // Scale only
 121                 if (rdrCtx.doClip) {
 122                     // adjust clip rectangle (ymin, ymax, xmin, xmax):
 123                     rdrCtx.clipInvScale = adjustClipScale(rdrCtx.clipRect,
 124                         mxx, myy);
 125                 }
 126                 return dt_DeltaScaleFilter.init(out, mxx, myy);
 127             }
 128         } else {
 129             if (rdrCtx.doClip) {
 130                 // adjust clip rectangle (ymin, ymax, xmin, xmax):
 131                 rdrCtx.clipInvScale = adjustClipInverseDelta(rdrCtx.clipRect,
 132                     mxx, mxy, myx, myy);
 133             }
 134             return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
 135         }
 136     }
 137 
 138     private static float adjustClipScale(final float[] clipRect,










 139                                          final float mxx, final float myy)
 140     {
 141         // Adjust the clipping rectangle (iv_DeltaScaleFilter):
 142         final float scaleY = 1.0f / myy;
 143         clipRect[0] *= scaleY;
 144         clipRect[1] *= scaleY;
 145 
 146         if (clipRect[1] < clipRect[0]) {
 147             float tmp = clipRect[0];
 148             clipRect[0] = clipRect[1];
 149             clipRect[1] = tmp;
 150         }
 151 
 152         final float scaleX = 1.0f / mxx;
 153         clipRect[2] *= scaleX;
 154         clipRect[3] *= scaleX;
 155 
 156         if (clipRect[3] < clipRect[2]) {
 157             float tmp = clipRect[2];
 158             clipRect[2] = clipRect[3];
 159             clipRect[3] = tmp;
 160         }
 161 
 162         if (MarlinConst.DO_LOG_CLIP) {
 163                 MarlinUtils.logInfo("clipRect (ClipScale): "
 164                                     + Arrays.toString(clipRect));
 165         }
 166         return 0.5f * (Math.abs(scaleX) + Math.abs(scaleY));
 167     }
 168 
 169     private static float adjustClipInverseDelta(final float[] clipRect,
 170                                                 final float mxx, final float mxy,
 171                                                 final float myx, final float myy)
 172     {
 173         // Adjust the clipping rectangle (iv_DeltaTransformFilter):
 174         final float det = mxx * myy - mxy * myx;
 175         final float imxx =  myy / det;
 176         final float imxy = -mxy / det;
 177         final float imyx = -myx / det;
 178         final float imyy =  mxx / det;
 179 
 180         float xmin, xmax, ymin, ymax;
 181         float x, y;
 182         // xmin, ymin:
 183         x = clipRect[2] * imxx + clipRect[0] * imxy;
 184         y = clipRect[2] * imyx + clipRect[0] * imyy;
 185 
 186         xmin = xmax = x;
 187         ymin = ymax = y;
 188 
 189         // xmax, ymin:


 194         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 195 
 196         // xmin, ymax:
 197         x = clipRect[2] * imxx + clipRect[1] * imxy;
 198         y = clipRect[2] * imyx + clipRect[1] * imyy;
 199 
 200         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 201         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 202 
 203         // xmax, ymax:
 204         x = clipRect[3] * imxx + clipRect[1] * imxy;
 205         y = clipRect[3] * imyx + clipRect[1] * imyy;
 206 
 207         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 208         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 209 
 210         clipRect[0] = ymin;
 211         clipRect[1] = ymax;
 212         clipRect[2] = xmin;
 213         clipRect[3] = xmax;
 214 
 215         if (MarlinConst.DO_LOG_CLIP) {
 216                 MarlinUtils.logInfo("clipRect (ClipInverseDelta): "
 217                                     + Arrays.toString(clipRect));
 218         }
 219 
 220         final float scaleX = (float) Math.sqrt(imxx * imxx + imxy * imxy);
 221         final float scaleY = (float) Math.sqrt(imyx * imyx + imyy * imyy);
 222 
 223         return 0.5f * (scaleX + scaleY);
 224     }
 225 
 226     public PathConsumer2D inverseDeltaTransformConsumer(PathConsumer2D out,
 227                                                         BaseTransform at)
 228     {
 229         if (at == null) {
 230             return out;
 231         }
 232         float mxx = (float) at.getMxx();
 233         float mxy = (float) at.getMxy();
 234         float myx = (float) at.getMyx();
 235         float myy = (float) at.getMyy();
 236 
 237         if (mxy == 0.0f && myx == 0.0f) {
 238             if (mxx == 1.0f && myy == 1.0f) {
 239                 return out;
 240             } else {
 241                 return iv_DeltaScaleFilter.init(out, 1.0f / mxx, 1.0f / myy);
 242             }
 243         } else {
 244             final float det = mxx * myy - mxy * myx;
 245             return iv_DeltaTransformFilter.init(out,
 246                                                 myy / det,
 247                                                -mxy / det,
 248                                                -myx / det,
 249                                                 mxx / det);
 250         }
 251     }
 252 
 253     static final class DeltaScaleFilter implements PathConsumer2D {
 254         private PathConsumer2D out;
 255         private float sx, sy;
 256 
 257         DeltaScaleFilter() {}
 258 
 259         DeltaScaleFilter init(PathConsumer2D out,
 260                               float mxx, float myy)
 261         {


 515         private float cx0, cy0;
 516 
 517         // The current point OUTSIDE
 518         private float cox0, coy0;
 519 
 520         private boolean subdivide = MarlinConst.DO_CLIP_SUBDIVIDER;
 521         private final CurveClipSplitter curveSplitter;
 522 
 523         PathClipFilter(final RendererContext rdrCtx) {
 524             this.clipRect = rdrCtx.clipRect;
 525             this.curveSplitter = rdrCtx.curveClipSplitter;
 526 
 527             this.stack = (rdrCtx.stats != null) ?
 528                 new IndexStack(rdrCtx,
 529                         rdrCtx.stats.stat_pcf_idxstack_indices,
 530                         rdrCtx.stats.hist_pcf_idxstack_indices,
 531                         rdrCtx.stats.stat_array_pcf_idxstack_indices)
 532                 : new IndexStack(rdrCtx);
 533         }
 534 
 535         PathClipFilter init(final PathConsumer2D out) {



 536             this.out = out;
 537 










 538             if (MarlinConst.DO_CLIP_SUBDIVIDER) {
 539                 // adjust padded clip rectangle:
 540                 curveSplitter.init();
 541             }
 542 
 543             this.init_corners = true;
 544             this.gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
 545 
 546             return this; // fluent API
 547         }
 548 
 549         /**
 550          * Disposes this instance:
 551          * clean up before reusing this instance
 552          */
 553         void dispose() {
 554             stack.dispose();
 555         }
 556 
 557         private void finishPath() {


 835 
 836             if (outside) {
 837                 finish();
 838             }
 839             // clipping disabled:
 840             out.quadTo(x1, y1, xe, ye);
 841             this.cx0 = xe;
 842             this.cy0 = ye;
 843         }
 844     }
 845 
 846     static final class CurveClipSplitter {
 847 
 848         static final float LEN_TH = MarlinProperties.getSubdividerMinLength();
 849         static final boolean DO_CHECK_LENGTH = (LEN_TH > 0.0f);
 850 
 851         private static final boolean TRACE = false;
 852 
 853         private static final int MAX_N_CURVES = 3 * 4;
 854 
 855         private final RendererContext rdrCtx;
 856 
 857         // scaled length threshold:
 858         private float minLength;
 859 
 860         // clip rectangle (ymin, ymax, xmin, xmax):
 861         final float[] clipRect;
 862 
 863         // clip rectangle (ymin, ymax, xmin, xmax) including padding:
 864         final float[] clipRectPad = new float[4];
 865         private boolean init_clipRectPad = false;
 866 
 867         // This is where the curve to be processed is put. We give it
 868         // enough room to store all curves.
 869         final float[] middle = new float[MAX_N_CURVES * 8 + 2];
 870         // t values at subdivision points
 871         private final float[] subdivTs = new float[MAX_N_CURVES];
 872 
 873         // dirty curve
 874         private final Curve curve;
 875 
 876         CurveClipSplitter(final RendererContext rdrCtx) {
 877             this.rdrCtx = rdrCtx;
 878             this.clipRect = rdrCtx.clipRect;
 879             this.curve = rdrCtx.curve;
 880         }
 881 
 882         void init() {
 883             this.init_clipRectPad = true;
 884 
 885             if (DO_CHECK_LENGTH) {
 886                 this.minLength = (this.rdrCtx.clipInvScale == 0.0f) ? LEN_TH
 887                                     : (LEN_TH * this.rdrCtx.clipInvScale);
 888 
 889                 if (MarlinConst.DO_LOG_CLIP) {
 890                     MarlinUtils.logInfo("CurveClipSplitter.minLength = "
 891                                             + minLength);
 892                 }
 893             }
 894         }
 895 
 896         private void initPaddedClip() {
 897             // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
 898             // adjust padded clip rectangle (ymin, ymax, xmin, xmax):
 899             // add a rounding error (curve subdivision ~ 0.1px):
 900             final float[] _clipRect = clipRect;
 901             final float[] _clipRectPad = clipRectPad;
 902 
 903             _clipRectPad[0] = _clipRect[0] - CLIP_RECT_PADDING;
 904             _clipRectPad[1] = _clipRect[1] + CLIP_RECT_PADDING;
 905             _clipRectPad[2] = _clipRect[2] - CLIP_RECT_PADDING;
 906             _clipRectPad[3] = _clipRect[3] + CLIP_RECT_PADDING;
 907 
 908             if (TRACE) {
 909                 MarlinUtils.logInfo("clip: X [" + _clipRectPad[2] + " .. " + _clipRectPad[3] +"] "
 910                                         + "Y [" + _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
 911             }
 912         }
 913 
 914         boolean splitLine(final float x0, final float y0,
 915                           final float x1, final float y1,
 916                           final int outCodeOR,
 917                           final PathConsumer2D out)
 918         {
 919             if (TRACE) {
 920                 MarlinUtils.logInfo("divLine P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ")");
 921             }
 922 
 923             if (DO_CHECK_LENGTH && Helpers.fastLineLen(x0, y0, x1, y1) <= minLength) {
 924                 return false;
 925             }
 926 
 927             final float[] mid = middle;
 928             mid[0] = x0;  mid[1] = y0;
 929             mid[2] = x1;  mid[3] = y1;
 930 
 931             return subdivideAtIntersections(4, outCodeOR, out);
 932         }
 933 
 934         boolean splitQuad(final float x0, final float y0,
 935                           final float x1, final float y1,
 936                           final float x2, final float y2,
 937                           final int outCodeOR,
 938                           final PathConsumer2D out)
 939         {
 940             if (TRACE) {
 941                 MarlinUtils.logInfo("divQuad P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ")");
 942             }
 943 
 944             if (DO_CHECK_LENGTH && Helpers.fastQuadLen(x0, y0, x1, y1, x2, y2) <= minLength) {
 945                 return false;
 946             }
 947 
 948             final float[] mid = middle;
 949             mid[0] = x0;  mid[1] = y0;
 950             mid[2] = x1;  mid[3] = y1;
 951             mid[4] = x2;  mid[5] = y2;
 952 
 953             return subdivideAtIntersections(6, outCodeOR, out);
 954         }
 955 
 956         boolean splitCurve(final float x0, final float y0,
 957                            final float x1, final float y1,
 958                            final float x2, final float y2,
 959                            final float x3, final float y3,
 960                            final int outCodeOR,
 961                            final PathConsumer2D out)
 962         {
 963             if (TRACE) {
 964                 MarlinUtils.logInfo("divCurve P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ")");
 965             }
 966 
 967             if (DO_CHECK_LENGTH && Helpers.fastCurvelen(x0, y0, x1, y1, x2, y2, x3, y3) <= minLength) {
 968                 return false;
 969             }
 970 
 971             final float[] mid = middle;
 972             mid[0] = x0;  mid[1] = y0;
 973             mid[2] = x1;  mid[3] = y1;
 974             mid[4] = x2;  mid[5] = y2;
 975             mid[6] = x3;  mid[7] = y3;
 976 
 977             return subdivideAtIntersections(8, outCodeOR, out);
 978         }
 979 
 980         private boolean subdivideAtIntersections(final int type, final int outCodeOR,
 981                                                  final PathConsumer2D out)
 982         {
 983             final float[] mid = middle;
 984             final float[] subTs = subdivTs;
 985 
 986             if (init_clipRectPad) {
 987                 init_clipRectPad = false;
 988                 initPaddedClip();
 989             }
 990 
 991             final int nSplits = Helpers.findClipPoints(curve, mid, subTs, type,
 992                                                         outCodeOR, clipRectPad);
 993 
 994             if (TRACE) {
 995                 MarlinUtils.logInfo("nSplits: " + nSplits);
 996                 MarlinUtils.logInfo("subTs: " + Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
 997             }
 998             if (nSplits == 0) {
 999                 // only curve support shortcut
1000                 return false;
1001             }
1002             float prevT = 0.0f;
1003 
1004             for (int i = 0, off = 0; i < nSplits; i++, off += type) {
1005                 final float t = subTs[i];
1006 
1007                 Helpers.subdivideAt((t - prevT) / (1.0f - prevT),
1008                                      mid, off, mid, off, type);
1009                 prevT = t;
1010             }
1011 
1012             for (int i = 0, off = 0; i <= nSplits; i++, off += type) {
1013                 if (TRACE) {
1014                     MarlinUtils.logInfo("Part Curve " + Arrays.toString(Arrays.copyOfRange(mid, off, off + type)));
1015                 }


< prev index next >