45 46 private static final float RDR_OFFSET_X = 0.5f / SUBPIXEL_SCALE_X; 47 private static final float RDR_OFFSET_Y = 0.5f / 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 float CUB_DEC_ERR_SUBPIX 65 = MarlinProperties.getCubicDecD2() * (NORM_SUBPIXELS / 8.0f); // 1 pixel 66 // cubic error in subpixels to increment step 67 private static final float CUB_INC_ERR_SUBPIX 68 = MarlinProperties.getCubicIncD1() * (NORM_SUBPIXELS / 8.0f); // 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 float CUB_DEC_BND 75 = 8.0f * CUB_DEC_ERR_SUBPIX; 76 // cubic bind length to increment step 77 public static final float CUB_INC_BND 78 = 8.0f * 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 float CUB_INV_COUNT = 1.0f / CUB_COUNT; 90 // cubic dt^2 = 1 / count^2 = 1 / 4^countlg 91 private static final float CUB_INV_COUNT_2 = 1.0f / CUB_COUNT_2; 92 // cubic dt^3 = 1 / count^3 = 1 / 8^countlg 93 private static final float CUB_INV_COUNT_3 = 1.0f / CUB_COUNT_3; 94 95 // quad break into lines 96 // quadratic error in subpixels 97 private static final float QUAD_DEC_ERR_SUBPIX 98 = MarlinProperties.getQuadDecD2() * (NORM_SUBPIXELS / 8.0f); // 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 float QUAD_DEC_BND 105 = 8.0f * 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(float x0, float y0, 164 final Curve c, 165 final float x2, final float y2) 166 { 167 int count = 1; // dt = 1 / count 168 169 // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1) 170 float maxDD = Math.abs(c.dbx) + Math.abs(c.dby); 171 172 final float _DEC_BND = QUAD_DEC_BND; 173 174 while (maxDD >= _DEC_BND) { 175 // divide step by half: 176 maxDD /= 4.0f; // 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 float icount = 1.0f / count; // dt 187 final float icount2 = icount * icount; // dt^2 188 189 final float ddx = c.dbx * icount2; 190 final float ddy = c.dby * icount2; 191 float dx = c.bx * icount2 + c.cx * icount; 192 float dy = c.by * icount2 + c.cy * icount; 193 194 float 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(float x0, float y0, 222 final Curve c, 223 final float x3, final float y3) 224 { 225 int count = CUB_COUNT; 226 final float icount = CUB_INV_COUNT; // dt 227 final float icount2 = CUB_INV_COUNT_2; // dt^2 228 final float 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 float dddx, dddy, ddx, ddy, dx, dy; 233 dddx = 2.0f * c.dax * icount3; 234 dddy = 2.0f * 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 float x1 = x0, y1 = y0; 242 int nL = 0; // line count 243 244 final float _DEC_BND = CUB_DEC_BND; 245 final float _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.0f; 251 dddy /= 8.0f; 252 ddx = ddx / 4.0f - dddx; 253 ddy = ddy / 4.0f - dddy; 254 dx = (dx - ddx) / 2.0f; 255 dy = (dy - ddy) / 2.0f; 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.0f * dx + ddx; 269 dy = 2.0f * dy + ddy; 270 ddx = 4.0f * (ddx + dddx); 271 ddy = 4.0f * (ddy + dddy); 272 dddx *= 8.0f; 273 dddy *= 8.0f; 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(float x1, float y1, float x2, float 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 float tmp = y2; 314 y2 = y1; 315 y1 = tmp; 316 tmp = x2; 317 x2 = x1; 318 x1 = tmp; 319 } 663 this.x0 = sx; 664 this.y0 = sy; 665 } 666 667 @Override 668 public void lineTo(final float pix_x1, final float pix_y1) { 669 final float x1 = tosubpixx(pix_x1); 670 final float y1 = tosubpixy(pix_y1); 671 addLine(x0, y0, x1, y1); 672 x0 = x1; 673 y0 = y1; 674 } 675 676 @Override 677 public void curveTo(final float pix_x1, final float pix_y1, 678 final float pix_x2, final float pix_y2, 679 final float pix_x3, final float pix_y3) 680 { 681 final float xe = tosubpixx(pix_x3); 682 final float ye = tosubpixy(pix_y3); 683 curve.set(x0, y0, tosubpixx(pix_x1), tosubpixy(pix_y1), 684 tosubpixx(pix_x2), tosubpixy(pix_y2), xe, ye); 685 curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye); 686 x0 = xe; 687 y0 = ye; 688 } 689 690 @Override 691 public void quadTo(final float pix_x1, final float pix_y1, 692 final float pix_x2, final float pix_y2) 693 { 694 final float xe = tosubpixx(pix_x2); 695 final float ye = tosubpixy(pix_y2); 696 curve.set(x0, y0, tosubpixx(pix_x1), tosubpixy(pix_y1), xe, ye); 697 quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye); 698 x0 = xe; 699 y0 = ye; 700 } 701 702 @Override 703 public void closePath() { 704 if (x0 != sx0 || y0 != sy0) { 705 addLine(x0, y0, sx0, sy0); 706 x0 = sx0; 707 y0 = sy0; 708 } 709 } 710 711 @Override 712 public void pathDone() { 713 closePath(); 714 715 // call endRendering() to determine the boundaries: 716 endRendering(); | 45 46 private static final float RDR_OFFSET_X = 0.5f / SUBPIXEL_SCALE_X; 47 private static final float RDR_OFFSET_Y = 0.5f / 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 float CUB_DEC_ERR_SUBPIX 65 = MarlinProperties.getCubicDecD2() * (SUBPIXEL_POSITIONS_X / 8.0f); // 1.0 / 8th pixel 66 // cubic error in subpixels to increment step 67 private static final float CUB_INC_ERR_SUBPIX 68 = MarlinProperties.getCubicIncD1() * (SUBPIXEL_POSITIONS_X / 8.0f); // 0.4 / 8th pixel 69 // scale factor for Y-axis contribution to quad / cubic errors: 70 public static final float SCALE_DY = ((float) 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 float CUB_DEC_BND 79 = 8.0f * CUB_DEC_ERR_SUBPIX; 80 // cubic bind length to increment step 81 public static final float CUB_INC_BND 82 = 8.0f * 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 float CUB_INV_COUNT = 1.0f / CUB_COUNT; 94 // cubic dt^2 = 1 / count^2 = 1 / 4^countlg 95 private static final float CUB_INV_COUNT_2 = 1.0f / CUB_COUNT_2; 96 // cubic dt^3 = 1 / count^3 = 1 / 8^countlg 97 private static final float CUB_INV_COUNT_3 = 1.0f / CUB_COUNT_3; 98 99 // quad break into lines 100 // quadratic error in subpixels 101 private static final float QUAD_DEC_ERR_SUBPIX 102 = MarlinProperties.getQuadDecD2() * (SUBPIXEL_POSITIONS_X / 8.0f); // 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 float QUAD_DEC_BND 111 = 8.0f * 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(float x0, float y0, 170 final Curve c, 171 final float x2, final float y2) 172 { 173 int count = 1; // dt = 1 / count 174 175 // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1) 176 float maxDD = Math.abs(c.dbx) + Math.abs(c.dby) * SCALE_DY; 177 178 final float _DEC_BND = QUAD_DEC_BND; 179 180 while (maxDD >= _DEC_BND) { 181 // divide step by half: 182 maxDD /= 4.0f; // 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 float icount = 1.0f / count; // dt 194 final float icount2 = icount * icount; // dt^2 195 196 final float ddx = c.dbx * icount2; 197 final float ddy = c.dby * icount2; 198 float dx = c.bx * icount2 + c.cx * icount; 199 float dy = c.by * icount2 + c.cy * icount; 200 201 // we use x0, y0 to walk the line 202 for (float 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(float x0, float y0, 224 final Curve c, 225 final float x3, final float y3) 226 { 227 int count = CUB_COUNT; 228 final float icount = CUB_INV_COUNT; // dt 229 final float icount2 = CUB_INV_COUNT_2; // dt^2 230 final float 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 float dddx, dddy, ddx, ddy, dx, dy; 235 dddx = 2.0f * c.dax * icount3; 236 dddy = 2.0f * 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 float _DEC_BND = CUB_DEC_BND; 245 final float _INC_BND = CUB_INC_BND; 246 final float _SCALE_DY = SCALE_DY; 247 248 // we use x0, y0 to walk the line 249 for (float x1 = x0, y1 = y0; count > 0; ) { 250 // inc / dec => ratio ~ 5 to minimize upscale / downscale but minimize edges 251 252 // float 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.0f * dx + ddx; 257 dy = 2.0f * dy + ddy; 258 ddx = 4.0f * (ddx + dddx); 259 ddy = 4.0f * (ddy + dddy); 260 dddx *= 8.0f; 261 dddy *= 8.0f; 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.0f; 272 dddy /= 8.0f; 273 ddx = ddx / 4.0f - dddx; 274 ddy = ddy / 4.0f - dddy; 275 dx = (dx - ddx) / 2.0f; 276 dy = (dy - ddy) / 2.0f; 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(float x1, float y1, float x2, float 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 float tmp = y2; 316 y2 = y1; 317 y1 = tmp; 318 tmp = x2; 319 x2 = x1; 320 x1 = tmp; 321 } 665 this.x0 = sx; 666 this.y0 = sy; 667 } 668 669 @Override 670 public void lineTo(final float pix_x1, final float pix_y1) { 671 final float x1 = tosubpixx(pix_x1); 672 final float y1 = tosubpixy(pix_y1); 673 addLine(x0, y0, x1, y1); 674 x0 = x1; 675 y0 = y1; 676 } 677 678 @Override 679 public void curveTo(final float pix_x1, final float pix_y1, 680 final float pix_x2, final float pix_y2, 681 final float pix_x3, final float pix_y3) 682 { 683 final float xe = tosubpixx(pix_x3); 684 final float ye = tosubpixy(pix_y3); 685 curve.set(x0, y0, 686 tosubpixx(pix_x1), tosubpixy(pix_y1), 687 tosubpixx(pix_x2), tosubpixy(pix_y2), 688 xe, ye); 689 curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye); 690 x0 = xe; 691 y0 = ye; 692 } 693 694 @Override 695 public void quadTo(final float pix_x1, final float pix_y1, 696 final float pix_x2, final float pix_y2) 697 { 698 final float xe = tosubpixx(pix_x2); 699 final float ye = tosubpixy(pix_y2); 700 curve.set(x0, y0, 701 tosubpixx(pix_x1), tosubpixy(pix_y1), 702 xe, ye); 703 quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye); 704 x0 = xe; 705 y0 = ye; 706 } 707 708 @Override 709 public void closePath() { 710 if (x0 != sx0 || y0 != sy0) { 711 addLine(x0, y0, sx0, sy0); 712 x0 = sx0; 713 y0 = sy0; 714 } 715 } 716 717 @Override 718 public void pathDone() { 719 closePath(); 720 721 // call endRendering() to determine the boundaries: 722 endRendering(); |