45 46 private static final double RDR_OFFSET_X = 0.5d / SUBPIXEL_SCALE_X; 47 private static final double RDR_OFFSET_Y = 0.5d / SUBPIXEL_SCALE_Y; 48 49 // common to all types of input path segments. 50 // OFFSET as bytes 51 // only integer values: 52 public static final long OFF_CURX_OR = 0; 53 public static final long OFF_ERROR = OFF_CURX_OR + SIZE_INT; 54 public static final long OFF_BUMP_X = OFF_ERROR + SIZE_INT; 55 public static final long OFF_BUMP_ERR = OFF_BUMP_X + SIZE_INT; 56 public static final long OFF_NEXT = OFF_BUMP_ERR + SIZE_INT; 57 public static final long OFF_YMAX = OFF_NEXT + SIZE_INT; 58 59 // size of one edge in bytes 60 public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT); 61 62 // curve break into lines 63 // cubic error in subpixels to decrement step 64 private static final double CUB_DEC_ERR_SUBPIX 65 = MarlinProperties.getCubicDecD2() * (NORM_SUBPIXELS / 8.0d); // 1 pixel 66 // cubic error in subpixels to increment step 67 private static final double CUB_INC_ERR_SUBPIX 68 = MarlinProperties.getCubicIncD1() * (NORM_SUBPIXELS / 8.0d); // 0.4 pixel 69 70 // TestNonAARasterization (JDK-8170879): cubics 71 // bad paths (59294/100000 == 59,29%, 94335 bad pixels (avg = 1,59), 3966 warnings (avg = 0,07) 72 73 // cubic bind length to decrement step 74 public static final double CUB_DEC_BND 75 = 8.0d * CUB_DEC_ERR_SUBPIX; 76 // cubic bind length to increment step 77 public static final double CUB_INC_BND 78 = 8.0d * CUB_INC_ERR_SUBPIX; 79 80 // cubic countlg 81 public static final int CUB_COUNT_LG = 2; 82 // cubic count = 2^countlg 83 private static final int CUB_COUNT = 1 << CUB_COUNT_LG; 84 // cubic count^2 = 4^countlg 85 private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG); 86 // cubic count^3 = 8^countlg 87 private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG); 88 // cubic dt = 1 / count 89 private static final double CUB_INV_COUNT = 1.0d / CUB_COUNT; 90 // cubic dt^2 = 1 / count^2 = 1 / 4^countlg 91 private static final double CUB_INV_COUNT_2 = 1.0d / CUB_COUNT_2; 92 // cubic dt^3 = 1 / count^3 = 1 / 8^countlg 93 private static final double CUB_INV_COUNT_3 = 1.0d / CUB_COUNT_3; 94 95 // quad break into lines 96 // quadratic error in subpixels 97 private static final double QUAD_DEC_ERR_SUBPIX 98 = MarlinProperties.getQuadDecD2() * (NORM_SUBPIXELS / 8.0d); // 0.5 pixel 99 100 // TestNonAARasterization (JDK-8170879): quads 101 // bad paths (62916/100000 == 62,92%, 103818 bad pixels (avg = 1,65), 6514 warnings (avg = 0,10) 102 103 // quadratic bind length to decrement step 104 public static final double QUAD_DEC_BND 105 = 8.0d * QUAD_DEC_ERR_SUBPIX; 106 107 ////////////////////////////////////////////////////////////////////////////// 108 // SCAN LINE 109 ////////////////////////////////////////////////////////////////////////////// 110 // crossings ie subpixel edge x coordinates 111 private int[] crossings; 112 // auxiliary storage for crossings (merge sort) 113 private int[] aux_crossings; 114 115 // indices into the segment pointer lists. They indicate the "active" 116 // sublist in the segment lists (the portion of the list that contains 117 // all the segments that cross the next scan line). 118 private int edgeCount; 119 private int[] edgePtrs; 120 // auxiliary storage for edge pointers (merge sort) 121 private int[] aux_edgePtrs; 150 private int buckets_minY; 151 private int buckets_maxY; 152 153 // edgeBuckets ref (clean) 154 private final IntArrayCache.Reference edgeBuckets_ref; 155 // edgeBucketCounts ref (clean) 156 private final IntArrayCache.Reference edgeBucketCounts_ref; 157 158 boolean useRLE = false; 159 160 // Flattens using adaptive forward differencing. This only carries out 161 // one iteration of the AFD loop. All it does is update AFD variables (i.e. 162 // X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings). 163 private void quadBreakIntoLinesAndAdd(double x0, double y0, 164 final DCurve c, 165 final double x2, final double y2) 166 { 167 int count = 1; // dt = 1 / count 168 169 // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1) 170 double maxDD = Math.abs(c.dbx) + Math.abs(c.dby); 171 172 final double _DEC_BND = QUAD_DEC_BND; 173 174 while (maxDD >= _DEC_BND) { 175 // divide step by half: 176 maxDD /= 4.0d; // error divided by 2^2 = 4 177 178 count <<= 1; 179 if (DO_STATS) { 180 rdrCtx.stats.stat_rdr_quadBreak_dec.add(count); 181 } 182 } 183 184 int nL = 0; // line count 185 if (count > 1) { 186 final double icount = 1.0d / count; // dt 187 final double icount2 = icount * icount; // dt^2 188 189 final double ddx = c.dbx * icount2; 190 final double ddy = c.dby * icount2; 191 double dx = c.bx * icount2 + c.cx * icount; 192 double dy = c.by * icount2 + c.cy * icount; 193 194 double x1, y1; 195 196 while (--count > 0) { 197 x1 = x0 + dx; 198 dx += ddx; 199 y1 = y0 + dy; 200 dy += ddy; 201 202 addLine(x0, y0, x1, y1); 203 204 if (DO_STATS) { nL++; } 205 x0 = x1; 206 y0 = y1; 207 } 208 } 209 addLine(x0, y0, x2, y2); 210 211 if (DO_STATS) { 212 rdrCtx.stats.stat_rdr_quadBreak.add(nL + 1); 213 } 214 } 215 216 // x0, y0 and x3,y3 are the endpoints of the curve. We could compute these 217 // using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce 218 // numerical errors, and our callers already have the exact values. 219 // Another alternative would be to pass all the control points, and call 220 // c.set here, but then too many numbers are passed around. 221 private void curveBreakIntoLinesAndAdd(double x0, double y0, 222 final DCurve c, 223 final double x3, final double y3) 224 { 225 int count = CUB_COUNT; 226 final double icount = CUB_INV_COUNT; // dt 227 final double icount2 = CUB_INV_COUNT_2; // dt^2 228 final double icount3 = CUB_INV_COUNT_3; // dt^3 229 230 // the dx and dy refer to forward differencing variables, not the last 231 // coefficients of the "points" polynomial 232 double dddx, dddy, ddx, ddy, dx, dy; 233 dddx = 2.0d * c.dax * icount3; 234 dddy = 2.0d * c.day * icount3; 235 ddx = dddx + c.dbx * icount2; 236 ddy = dddy + c.dby * icount2; 237 dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount; 238 dy = c.ay * icount3 + c.by * icount2 + c.cy * icount; 239 240 // we use x0, y0 to walk the line 241 double x1 = x0, y1 = y0; 242 int nL = 0; // line count 243 244 final double _DEC_BND = CUB_DEC_BND; 245 final double _INC_BND = CUB_INC_BND; 246 247 while (count > 0) { 248 // divide step by half: 249 while (Math.abs(ddx) + Math.abs(ddy) >= _DEC_BND) { 250 dddx /= 8.0d; 251 dddy /= 8.0d; 252 ddx = ddx / 4.0d - dddx; 253 ddy = ddy / 4.0d - dddy; 254 dx = (dx - ddx) / 2.0d; 255 dy = (dy - ddy) / 2.0d; 256 257 count <<= 1; 258 if (DO_STATS) { 259 rdrCtx.stats.stat_rdr_curveBreak_dec.add(count); 260 } 261 } 262 263 // double step: 264 // can only do this on even "count" values, because we must divide count by 2 265 while (count % 2 == 0 266 && Math.abs(dx) + Math.abs(dy) <= _INC_BND) 267 { 268 dx = 2.0d * dx + ddx; 269 dy = 2.0d * dy + ddy; 270 ddx = 4.0d * (ddx + dddx); 271 ddy = 4.0d * (ddy + dddy); 272 dddx *= 8.0d; 273 dddy *= 8.0d; 274 275 count >>= 1; 276 if (DO_STATS) { 277 rdrCtx.stats.stat_rdr_curveBreak_inc.add(count); 278 } 279 } 280 if (--count > 0) { 281 x1 += dx; 282 dx += ddx; 283 ddx += dddx; 284 y1 += dy; 285 dy += ddy; 286 ddy += dddy; 287 } else { 288 x1 = x3; 289 y1 = y3; 290 } 291 292 addLine(x0, y0, x1, y1); 293 294 if (DO_STATS) { nL++; } 295 x0 = x1; 296 y0 = y1; 297 } 298 if (DO_STATS) { 299 rdrCtx.stats.stat_rdr_curveBreak.add(nL); 300 } 301 } 302 303 private void addLine(double x1, double y1, double x2, double y2) { 304 if (DO_MONITORS) { 305 rdrCtx.stats.mon_rdr_addLine.start(); 306 } 307 if (DO_STATS) { 308 rdrCtx.stats.stat_rdr_addLine.add(1); 309 } 310 int or = 1; // orientation of the line. 1 if y increases, 0 otherwise. 311 if (y2 < y1) { 312 or = 0; 313 double tmp = y2; 314 y2 = y1; 315 y1 = tmp; 316 tmp = x2; 317 x2 = x1; 318 x1 = tmp; 319 } 660 this.x0 = sx; 661 this.y0 = sy; 662 } 663 664 @Override 665 public void lineTo(final double pix_x1, final double pix_y1) { 666 final double x1 = tosubpixx(pix_x1); 667 final double y1 = tosubpixy(pix_y1); 668 addLine(x0, y0, x1, y1); 669 x0 = x1; 670 y0 = y1; 671 } 672 673 @Override 674 public void curveTo(final double pix_x1, final double pix_y1, 675 final double pix_x2, final double pix_y2, 676 final double pix_x3, final double pix_y3) 677 { 678 final double xe = tosubpixx(pix_x3); 679 final double ye = tosubpixy(pix_y3); 680 curve.set(x0, y0, tosubpixx(pix_x1), tosubpixy(pix_y1), 681 tosubpixx(pix_x2), tosubpixy(pix_y2), xe, ye); 682 curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye); 683 x0 = xe; 684 y0 = ye; 685 } 686 687 @Override 688 public void quadTo(final double pix_x1, final double pix_y1, 689 final double pix_x2, final double pix_y2) 690 { 691 final double xe = tosubpixx(pix_x2); 692 final double ye = tosubpixy(pix_y2); 693 curve.set(x0, y0, tosubpixx(pix_x1), tosubpixy(pix_y1), xe, ye); 694 quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye); 695 x0 = xe; 696 y0 = ye; 697 } 698 699 @Override 700 public void closePath() { 701 if (x0 != sx0 || y0 != sy0) { 702 addLine(x0, y0, sx0, sy0); 703 x0 = sx0; 704 y0 = sy0; 705 } 706 } 707 708 @Override 709 public void pathDone() { 710 closePath(); 711 712 // call endRendering() to determine the boundaries: 713 endRendering(); | 45 46 private static final double RDR_OFFSET_X = 0.5d / SUBPIXEL_SCALE_X; 47 private static final double RDR_OFFSET_Y = 0.5d / SUBPIXEL_SCALE_Y; 48 49 // common to all types of input path segments. 50 // OFFSET as bytes 51 // only integer values: 52 public static final long OFF_CURX_OR = 0; 53 public static final long OFF_ERROR = OFF_CURX_OR + SIZE_INT; 54 public static final long OFF_BUMP_X = OFF_ERROR + SIZE_INT; 55 public static final long OFF_BUMP_ERR = OFF_BUMP_X + SIZE_INT; 56 public static final long OFF_NEXT = OFF_BUMP_ERR + SIZE_INT; 57 public static final long OFF_YMAX = OFF_NEXT + SIZE_INT; 58 59 // size of one edge in bytes 60 public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT); 61 62 // curve break into lines 63 // cubic error in subpixels to decrement step 64 private static final double CUB_DEC_ERR_SUBPIX 65 = MarlinProperties.getCubicDecD2() * (SUBPIXEL_POSITIONS_X / 8.0d); // 1.0 / 8th pixel 66 // cubic error in subpixels to increment step 67 private static final double CUB_INC_ERR_SUBPIX 68 = MarlinProperties.getCubicIncD1() * (SUBPIXEL_POSITIONS_X / 8.0d); // 0.4 / 8th pixel 69 // scale factor for Y-axis contribution to quad / cubic errors: 70 public static final double SCALE_DY = ((double) SUBPIXEL_POSITIONS_X) / SUBPIXEL_POSITIONS_Y; 71 72 // TestNonAARasterization (JDK-8170879): cubics 73 // bad paths (59294/100000 == 59,29%, 94335 bad pixels (avg = 1,59), 3966 warnings (avg = 0,07) 74 // 2018 75 // 1.0 / 0.2: bad paths (67194/100000 == 67,19%, 117394 bad pixels (avg = 1,75 - max = 9), 4042 warnings (avg = 0,06) 76 77 // cubic bind length to decrement step 78 public static final double CUB_DEC_BND 79 = 8.0d * CUB_DEC_ERR_SUBPIX; 80 // cubic bind length to increment step 81 public static final double CUB_INC_BND 82 = 8.0d * CUB_INC_ERR_SUBPIX; 83 84 // cubic countlg 85 public static final int CUB_COUNT_LG = 2; 86 // cubic count = 2^countlg 87 private static final int CUB_COUNT = 1 << CUB_COUNT_LG; 88 // cubic count^2 = 4^countlg 89 private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG); 90 // cubic count^3 = 8^countlg 91 private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG); 92 // cubic dt = 1 / count 93 private static final double CUB_INV_COUNT = 1.0d / CUB_COUNT; 94 // cubic dt^2 = 1 / count^2 = 1 / 4^countlg 95 private static final double CUB_INV_COUNT_2 = 1.0d / CUB_COUNT_2; 96 // cubic dt^3 = 1 / count^3 = 1 / 8^countlg 97 private static final double CUB_INV_COUNT_3 = 1.0d / CUB_COUNT_3; 98 99 // quad break into lines 100 // quadratic error in subpixels 101 private static final double QUAD_DEC_ERR_SUBPIX 102 = MarlinProperties.getQuadDecD2() * (SUBPIXEL_POSITIONS_X / 8.0d); // 0.5 / 8th pixel 103 104 // TestNonAARasterization (JDK-8170879): quads 105 // bad paths (62916/100000 == 62,92%, 103818 bad pixels (avg = 1,65), 6514 warnings (avg = 0,10) 106 // 2018 107 // 0.50px = bad paths (62915/100000 == 62,92%, 103810 bad pixels (avg = 1,65), 6512 warnings (avg = 0,10) 108 109 // quadratic bind length to decrement step 110 public static final double QUAD_DEC_BND 111 = 8.0d * QUAD_DEC_ERR_SUBPIX; 112 113 ////////////////////////////////////////////////////////////////////////////// 114 // SCAN LINE 115 ////////////////////////////////////////////////////////////////////////////// 116 // crossings ie subpixel edge x coordinates 117 private int[] crossings; 118 // auxiliary storage for crossings (merge sort) 119 private int[] aux_crossings; 120 121 // indices into the segment pointer lists. They indicate the "active" 122 // sublist in the segment lists (the portion of the list that contains 123 // all the segments that cross the next scan line). 124 private int edgeCount; 125 private int[] edgePtrs; 126 // auxiliary storage for edge pointers (merge sort) 127 private int[] aux_edgePtrs; 156 private int buckets_minY; 157 private int buckets_maxY; 158 159 // edgeBuckets ref (clean) 160 private final IntArrayCache.Reference edgeBuckets_ref; 161 // edgeBucketCounts ref (clean) 162 private final IntArrayCache.Reference edgeBucketCounts_ref; 163 164 boolean useRLE = false; 165 166 // Flattens using adaptive forward differencing. This only carries out 167 // one iteration of the AFD loop. All it does is update AFD variables (i.e. 168 // X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings). 169 private void quadBreakIntoLinesAndAdd(double x0, double y0, 170 final DCurve c, 171 final double x2, final double y2) 172 { 173 int count = 1; // dt = 1 / count 174 175 // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1) 176 double maxDD = Math.abs(c.dbx) + Math.abs(c.dby) * SCALE_DY; 177 178 final double _DEC_BND = QUAD_DEC_BND; 179 180 while (maxDD >= _DEC_BND) { 181 // divide step by half: 182 maxDD /= 4.0d; // error divided by 2^2 = 4 183 184 count <<= 1; 185 if (DO_STATS) { 186 rdrCtx.stats.stat_rdr_quadBreak_dec.add(count); 187 } 188 } 189 190 final int nL = count; // line count 191 192 if (count > 1) { 193 final double icount = 1.0d / count; // dt 194 final double icount2 = icount * icount; // dt^2 195 196 final double ddx = c.dbx * icount2; 197 final double ddy = c.dby * icount2; 198 double dx = c.bx * icount2 + c.cx * icount; 199 double dy = c.by * icount2 + c.cy * icount; 200 201 // we use x0, y0 to walk the line 202 for (double x1 = x0, y1 = y0; --count > 0; dx += ddx, dy += ddy) { 203 x1 += dx; 204 y1 += dy; 205 206 addLine(x0, y0, x1, y1); 207 x0 = x1; 208 y0 = y1; 209 } 210 } 211 addLine(x0, y0, x2, y2); 212 213 if (DO_STATS) { 214 rdrCtx.stats.stat_rdr_quadBreak.add(nL); 215 } 216 } 217 218 // x0, y0 and x3,y3 are the endpoints of the curve. We could compute these 219 // using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce 220 // numerical errors, and our callers already have the exact values. 221 // Another alternative would be to pass all the control points, and call 222 // c.set here, but then too many numbers are passed around. 223 private void curveBreakIntoLinesAndAdd(double x0, double y0, 224 final DCurve c, 225 final double x3, final double y3) 226 { 227 int count = CUB_COUNT; 228 final double icount = CUB_INV_COUNT; // dt 229 final double icount2 = CUB_INV_COUNT_2; // dt^2 230 final double icount3 = CUB_INV_COUNT_3; // dt^3 231 232 // the dx and dy refer to forward differencing variables, not the last 233 // coefficients of the "points" polynomial 234 double dddx, dddy, ddx, ddy, dx, dy; 235 dddx = 2.0d * c.dax * icount3; 236 dddy = 2.0d * c.day * icount3; 237 ddx = dddx + c.dbx * icount2; 238 ddy = dddy + c.dby * icount2; 239 dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount; 240 dy = c.ay * icount3 + c.by * icount2 + c.cy * icount; 241 242 int nL = 0; // line count 243 244 final double _DEC_BND = CUB_DEC_BND; 245 final double _INC_BND = CUB_INC_BND; 246 final double _SCALE_DY = SCALE_DY; 247 248 // we use x0, y0 to walk the line 249 for (double x1 = x0, y1 = y0; count > 0; ) { 250 // inc / dec => ratio ~ 5 to minimize upscale / downscale but minimize edges 251 252 // double step: 253 // can only do this on even "count" values, because we must divide count by 2 254 while ((count % 2 == 0) 255 && ((Math.abs(ddx) + Math.abs(ddy) * _SCALE_DY) <= _INC_BND)) { 256 dx = 2.0d * dx + ddx; 257 dy = 2.0d * dy + ddy; 258 ddx = 4.0d * (ddx + dddx); 259 ddy = 4.0d * (ddy + dddy); 260 dddx *= 8.0d; 261 dddy *= 8.0d; 262 263 count >>= 1; 264 if (DO_STATS) { 265 rdrCtx.stats.stat_rdr_curveBreak_inc.add(count); 266 } 267 } 268 269 // divide step by half: 270 while ((Math.abs(ddx) + Math.abs(ddy) * _SCALE_DY) >= _DEC_BND) { 271 dddx /= 8.0d; 272 dddy /= 8.0d; 273 ddx = ddx / 4.0d - dddx; 274 ddy = ddy / 4.0d - dddy; 275 dx = (dx - ddx) / 2.0d; 276 dy = (dy - ddy) / 2.0d; 277 278 count <<= 1; 279 if (DO_STATS) { 280 rdrCtx.stats.stat_rdr_curveBreak_dec.add(count); 281 } 282 } 283 if (--count == 0) { 284 break; 285 } 286 287 x1 += dx; 288 y1 += dy; 289 dx += ddx; 290 dy += ddy; 291 ddx += dddx; 292 ddy += dddy; 293 294 addLine(x0, y0, x1, y1); 295 x0 = x1; 296 y0 = y1; 297 } 298 addLine(x0, y0, x3, y3); 299 300 if (DO_STATS) { 301 rdrCtx.stats.stat_rdr_curveBreak.add(nL + 1); 302 } 303 } 304 305 private void addLine(double x1, double y1, double x2, double y2) { 306 if (DO_MONITORS) { 307 rdrCtx.stats.mon_rdr_addLine.start(); 308 } 309 if (DO_STATS) { 310 rdrCtx.stats.stat_rdr_addLine.add(1); 311 } 312 int or = 1; // orientation of the line. 1 if y increases, 0 otherwise. 313 if (y2 < y1) { 314 or = 0; 315 double tmp = y2; 316 y2 = y1; 317 y1 = tmp; 318 tmp = x2; 319 x2 = x1; 320 x1 = tmp; 321 } 662 this.x0 = sx; 663 this.y0 = sy; 664 } 665 666 @Override 667 public void lineTo(final double pix_x1, final double pix_y1) { 668 final double x1 = tosubpixx(pix_x1); 669 final double y1 = tosubpixy(pix_y1); 670 addLine(x0, y0, x1, y1); 671 x0 = x1; 672 y0 = y1; 673 } 674 675 @Override 676 public void curveTo(final double pix_x1, final double pix_y1, 677 final double pix_x2, final double pix_y2, 678 final double pix_x3, final double pix_y3) 679 { 680 final double xe = tosubpixx(pix_x3); 681 final double ye = tosubpixy(pix_y3); 682 curve.set(x0, y0, 683 tosubpixx(pix_x1), tosubpixy(pix_y1), 684 tosubpixx(pix_x2), tosubpixy(pix_y2), 685 xe, ye); 686 curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye); 687 x0 = xe; 688 y0 = ye; 689 } 690 691 @Override 692 public void quadTo(final double pix_x1, final double pix_y1, 693 final double pix_x2, final double pix_y2) 694 { 695 final double xe = tosubpixx(pix_x2); 696 final double ye = tosubpixy(pix_y2); 697 curve.set(x0, y0, 698 tosubpixx(pix_x1), tosubpixy(pix_y1), 699 xe, ye); 700 quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye); 701 x0 = xe; 702 y0 = ye; 703 } 704 705 @Override 706 public void closePath() { 707 if (x0 != sx0 || y0 != sy0) { 708 addLine(x0, y0, sx0, sy0); 709 x0 = sx0; 710 y0 = sy0; 711 } 712 } 713 714 @Override 715 public void pathDone() { 716 closePath(); 717 718 // call endRendering() to determine the boundaries: 719 endRendering(); |