1 /*
2 * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
36 static final boolean ENABLE_BLOCK_FLAGS_HEURISTICS = MarlinProperties.isUseTileFlagsWithHeuristics();
37
38 private static final int ALL_BUT_LSB = 0xFFFFFFFE;
39 private static final int ERR_STEP_MAX = 0x7FFFFFFF; // = 2^31 - 1
40
41 private static final double POWER_2_TO_32 = 0x1.0p32d;
42
43 // use double to make tosubpix methods faster (no int to double conversion)
44 static final double SUBPIXEL_SCALE_X = SUBPIXEL_POSITIONS_X;
45 static final double SUBPIXEL_SCALE_Y = SUBPIXEL_POSITIONS_Y;
46 static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1;
47 static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1;
48
49 static final double RDR_OFFSET_X = 0.5d / SUBPIXEL_SCALE_X;
50 static final double RDR_OFFSET_Y = 0.5d / SUBPIXEL_SCALE_Y;
51
52 // number of subpixels corresponding to a tile line
53 private static final int SUBPIXEL_TILE
54 = TILE_H << SUBPIXEL_LG_POSITIONS_Y;
55
56 // 2048 (pixelSize) pixels (height) x 8 subpixels = 64K
57 static final int INITIAL_BUCKET_ARRAY
58 = INITIAL_PIXEL_DIM * SUBPIXEL_POSITIONS_Y;
59
60 // crossing capacity = edges count / 4 ~ 1024
61 static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 2;
62
63 // common to all types of input path segments.
64 // OFFSET as bytes
65 // only integer values:
66 public static final long OFF_CURX_OR = 0;
67 public static final long OFF_ERROR = OFF_CURX_OR + SIZE_INT;
68 public static final long OFF_BUMP_X = OFF_ERROR + SIZE_INT;
69 public static final long OFF_BUMP_ERR = OFF_BUMP_X + SIZE_INT;
70 public static final long OFF_NEXT = OFF_BUMP_ERR + SIZE_INT;
71 public static final long OFF_YMAX = OFF_NEXT + SIZE_INT;
72
73 // size of one edge in bytes
74 public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT);
75
76 // curve break into lines
77 // cubic error in subpixels to decrement step
78 private static final double CUB_DEC_ERR_SUBPIX
79 = MarlinProperties.getCubicDecD2() * (NORM_SUBPIXELS / 8.0d); // 1 pixel
80 // cubic error in subpixels to increment step
81 private static final double CUB_INC_ERR_SUBPIX
82 = MarlinProperties.getCubicIncD1() * (NORM_SUBPIXELS / 8.0d); // 0.4 pixel
83
84 // TestNonAARasterization (JDK-8170879): cubics
85 // bad paths (59294/100000 == 59,29%, 94335 bad pixels (avg = 1,59), 3966 warnings (avg = 0,07)
86
87 // cubic bind length to decrement step
88 public static final double CUB_DEC_BND
89 = 8.0d * CUB_DEC_ERR_SUBPIX;
90 // cubic bind length to increment step
91 public static final double CUB_INC_BND
92 = 8.0d * CUB_INC_ERR_SUBPIX;
93
94 // cubic countlg
95 public static final int CUB_COUNT_LG = 2;
96 // cubic count = 2^countlg
97 private static final int CUB_COUNT = 1 << CUB_COUNT_LG;
98 // cubic count^2 = 4^countlg
99 private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG);
100 // cubic count^3 = 8^countlg
101 private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
102 // cubic dt = 1 / count
103 private static final double CUB_INV_COUNT = 1.0d / CUB_COUNT;
104 // cubic dt^2 = 1 / count^2 = 1 / 4^countlg
105 private static final double CUB_INV_COUNT_2 = 1.0d / CUB_COUNT_2;
106 // cubic dt^3 = 1 / count^3 = 1 / 8^countlg
107 private static final double CUB_INV_COUNT_3 = 1.0d / CUB_COUNT_3;
108
109 // quad break into lines
110 // quadratic error in subpixels
111 private static final double QUAD_DEC_ERR_SUBPIX
112 = MarlinProperties.getQuadDecD2() * (NORM_SUBPIXELS / 8.0d); // 0.5 pixel
113
114 // TestNonAARasterization (JDK-8170879): quads
115 // bad paths (62916/100000 == 62,92%, 103818 bad pixels (avg = 1,65), 6514 warnings (avg = 0,10)
116
117 // quadratic bind length to decrement step
118 public static final double QUAD_DEC_BND
119 = 8.0d * QUAD_DEC_ERR_SUBPIX;
120
121 //////////////////////////////////////////////////////////////////////////////
122 // SCAN LINE
123 //////////////////////////////////////////////////////////////////////////////
124 // crossings ie subpixel edge x coordinates
125 private int[] crossings;
126 // auxiliary storage for crossings (merge sort)
127 private int[] aux_crossings;
128
129 // indices into the segment pointer lists. They indicate the "active"
130 // sublist in the segment lists (the portion of the list that contains
131 // all the segments that cross the next scan line).
132 private int edgeCount;
133 private int[] edgePtrs;
134 // auxiliary storage for edge pointers (merge sort)
135 private int[] aux_edgePtrs;
162 private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed)
163 // used range for edgeBuckets / edgeBucketCounts
164 private int buckets_minY;
165 private int buckets_maxY;
166
167 // edgeBuckets ref (clean)
168 private final IntArrayCache.Reference edgeBuckets_ref;
169 // edgeBucketCounts ref (clean)
170 private final IntArrayCache.Reference edgeBucketCounts_ref;
171
172 // Flattens using adaptive forward differencing. This only carries out
173 // one iteration of the AFD loop. All it does is update AFD variables (i.e.
174 // X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
175 private void quadBreakIntoLinesAndAdd(double x0, double y0,
176 final DCurve c,
177 final double x2, final double y2)
178 {
179 int count = 1; // dt = 1 / count
180
181 // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
182 double maxDD = Math.abs(c.dbx) + Math.abs(c.dby);
183
184 final double _DEC_BND = QUAD_DEC_BND;
185
186 while (maxDD >= _DEC_BND) {
187 // divide step by half:
188 maxDD /= 4.0d; // error divided by 2^2 = 4
189
190 count <<= 1;
191 if (DO_STATS) {
192 rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
193 }
194 }
195
196 int nL = 0; // line count
197 if (count > 1) {
198 final double icount = 1.0d / count; // dt
199 final double icount2 = icount * icount; // dt^2
200
201 final double ddx = c.dbx * icount2;
202 final double ddy = c.dby * icount2;
203 double dx = c.bx * icount2 + c.cx * icount;
204 double dy = c.by * icount2 + c.cy * icount;
205
206 double x1, y1;
207
208 while (--count > 0) {
209 x1 = x0 + dx;
210 dx += ddx;
211 y1 = y0 + dy;
212 dy += ddy;
213
214 addLine(x0, y0, x1, y1);
215
216 if (DO_STATS) { nL++; }
217 x0 = x1;
218 y0 = y1;
219 }
220 }
221 addLine(x0, y0, x2, y2);
222
223 if (DO_STATS) {
224 rdrCtx.stats.stat_rdr_quadBreak.add(nL + 1);
225 }
226 }
227
228 // x0, y0 and x3,y3 are the endpoints of the curve. We could compute these
229 // using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce
230 // numerical errors, and our callers already have the exact values.
231 // Another alternative would be to pass all the control points, and call
232 // c.set here, but then too many numbers are passed around.
233 private void curveBreakIntoLinesAndAdd(double x0, double y0,
234 final DCurve c,
235 final double x3, final double y3)
236 {
237 int count = CUB_COUNT;
238 final double icount = CUB_INV_COUNT; // dt
239 final double icount2 = CUB_INV_COUNT_2; // dt^2
240 final double icount3 = CUB_INV_COUNT_3; // dt^3
241
242 // the dx and dy refer to forward differencing variables, not the last
243 // coefficients of the "points" polynomial
244 double dddx, dddy, ddx, ddy, dx, dy;
245 dddx = 2.0d * c.dax * icount3;
246 dddy = 2.0d * c.day * icount3;
247 ddx = dddx + c.dbx * icount2;
248 ddy = dddy + c.dby * icount2;
249 dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
250 dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
251
252 // we use x0, y0 to walk the line
253 double x1 = x0, y1 = y0;
254 int nL = 0; // line count
255
256 final double _DEC_BND = CUB_DEC_BND;
257 final double _INC_BND = CUB_INC_BND;
258
259 while (count > 0) {
260 // divide step by half:
261 while (Math.abs(ddx) + Math.abs(ddy) >= _DEC_BND) {
262 dddx /= 8.0d;
263 dddy /= 8.0d;
264 ddx = ddx / 4.0d - dddx;
265 ddy = ddy / 4.0d - dddy;
266 dx = (dx - ddx) / 2.0d;
267 dy = (dy - ddy) / 2.0d;
268
269 count <<= 1;
270 if (DO_STATS) {
271 rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
272 }
273 }
274
275 // double step:
276 // can only do this on even "count" values, because we must divide count by 2
277 while (count % 2 == 0
278 && Math.abs(dx) + Math.abs(dy) <= _INC_BND)
279 {
280 dx = 2.0d * dx + ddx;
281 dy = 2.0d * dy + ddy;
282 ddx = 4.0d * (ddx + dddx);
283 ddy = 4.0d * (ddy + dddy);
284 dddx *= 8.0d;
285 dddy *= 8.0d;
286
287 count >>= 1;
288 if (DO_STATS) {
289 rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
290 }
291 }
292 if (--count > 0) {
293 x1 += dx;
294 dx += ddx;
295 ddx += dddx;
296 y1 += dy;
297 dy += ddy;
298 ddy += dddy;
299 } else {
300 x1 = x3;
301 y1 = y3;
302 }
303
304 addLine(x0, y0, x1, y1);
305
306 if (DO_STATS) { nL++; }
307 x0 = x1;
308 y0 = y1;
309 }
310 if (DO_STATS) {
311 rdrCtx.stats.stat_rdr_curveBreak.add(nL);
312 }
313 }
314
315 private void addLine(double x1, double y1, double x2, double y2) {
316 if (DO_MONITORS) {
317 rdrCtx.stats.mon_rdr_addLine.start();
318 }
319 if (DO_STATS) {
320 rdrCtx.stats.stat_rdr_addLine.add(1);
321 }
322 int or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
323 if (y2 < y1) {
324 or = 0;
325 double tmp = y2;
326 y2 = y1;
327 y1 = tmp;
328 tmp = x2;
329 x2 = x1;
330 x1 = tmp;
331 }
516
517 /* block flags (0|1) */
518 private int[] blkFlags;
519
520 // blkFlags ref (clean)
521 private final IntArrayCache.Reference blkFlags_ref;
522
523 DRenderer(final DRendererContext rdrCtx) {
524 this.rdrCtx = rdrCtx;
525 this.curve = rdrCtx.curve;
526 this.cache = rdrCtx.cache;
527
528 this.edges = rdrCtx.newOffHeapArray(INITIAL_EDGES_CAPACITY); // 96K
529
530 edgeBuckets_ref = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K
531 edgeBucketCounts_ref = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K
532
533 edgeBuckets = edgeBuckets_ref.initial;
534 edgeBucketCounts = edgeBucketCounts_ref.initial;
535
536 // 2048 (pixelsize) pixel large
537 alphaLine_ref = rdrCtx.newCleanIntArrayRef(INITIAL_AA_ARRAY); // 8K
538 alphaLine = alphaLine_ref.initial;
539
540 crossings_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
541 aux_crossings_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
542 edgePtrs_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
543 aux_edgePtrs_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
544
545 crossings = crossings_ref.initial;
546 aux_crossings = aux_crossings_ref.initial;
547 edgePtrs = edgePtrs_ref.initial;
548 aux_edgePtrs = aux_edgePtrs_ref.initial;
549
550 blkFlags_ref = rdrCtx.newCleanIntArrayRef(INITIAL_ARRAY); // 1K = 1 tile line
551 blkFlags = blkFlags_ref.initial;
552 }
553
554 DRenderer init(final int pix_boundsX, final int pix_boundsY,
555 final int pix_boundsWidth, final int pix_boundsHeight,
556 final int windingRule)
557 {
675 this.x0 = sx;
676 this.y0 = sy;
677 }
678
679 @Override
680 public void lineTo(final double pix_x1, final double pix_y1) {
681 final double x1 = tosubpixx(pix_x1);
682 final double y1 = tosubpixy(pix_y1);
683 addLine(x0, y0, x1, y1);
684 x0 = x1;
685 y0 = y1;
686 }
687
688 @Override
689 public void curveTo(final double pix_x1, final double pix_y1,
690 final double pix_x2, final double pix_y2,
691 final double pix_x3, final double pix_y3)
692 {
693 final double xe = tosubpixx(pix_x3);
694 final double ye = tosubpixy(pix_y3);
695 curve.set(x0, y0, tosubpixx(pix_x1), tosubpixy(pix_y1),
696 tosubpixx(pix_x2), tosubpixy(pix_y2), xe, ye);
697 curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
698 x0 = xe;
699 y0 = ye;
700 }
701
702 @Override
703 public void quadTo(final double pix_x1, final double pix_y1,
704 final double pix_x2, final double pix_y2)
705 {
706 final double xe = tosubpixx(pix_x2);
707 final double ye = tosubpixy(pix_y2);
708 curve.set(x0, y0, tosubpixx(pix_x1), tosubpixy(pix_y1), xe, ye);
709 quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
710 x0 = xe;
711 y0 = ye;
712 }
713
714 @Override
715 public void closePath() {
716 if (x0 != sx0 || y0 != sy0) {
717 addLine(x0, y0, sx0, sy0);
718 x0 = sx0;
719 y0 = sy0;
720 }
721 }
722
723 @Override
724 public void pathDone() {
725 closePath();
726 }
727
728 @Override
|
1 /*
2 * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
36 static final boolean ENABLE_BLOCK_FLAGS_HEURISTICS = MarlinProperties.isUseTileFlagsWithHeuristics();
37
38 private static final int ALL_BUT_LSB = 0xFFFFFFFE;
39 private static final int ERR_STEP_MAX = 0x7FFFFFFF; // = 2^31 - 1
40
41 private static final double POWER_2_TO_32 = 0x1.0p32d;
42
43 // use double to make tosubpix methods faster (no int to double conversion)
44 static final double SUBPIXEL_SCALE_X = SUBPIXEL_POSITIONS_X;
45 static final double SUBPIXEL_SCALE_Y = SUBPIXEL_POSITIONS_Y;
46 static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1;
47 static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1;
48
49 static final double RDR_OFFSET_X = 0.5d / SUBPIXEL_SCALE_X;
50 static final double RDR_OFFSET_Y = 0.5d / SUBPIXEL_SCALE_Y;
51
52 // number of subpixels corresponding to a tile line
53 private static final int SUBPIXEL_TILE
54 = TILE_H << SUBPIXEL_LG_POSITIONS_Y;
55
56 // 2176 pixels (height) x 8 subpixels = 68K
57 static final int INITIAL_BUCKET_ARRAY
58 = INITIAL_PIXEL_HEIGHT * SUBPIXEL_POSITIONS_Y;
59
60 // crossing capacity = edges count / 4 ~ 1024
61 static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 2;
62
63 // common to all types of input path segments.
64 // OFFSET as bytes
65 // only integer values:
66 public static final long OFF_CURX_OR = 0;
67 public static final long OFF_ERROR = OFF_CURX_OR + SIZE_INT;
68 public static final long OFF_BUMP_X = OFF_ERROR + SIZE_INT;
69 public static final long OFF_BUMP_ERR = OFF_BUMP_X + SIZE_INT;
70 public static final long OFF_NEXT = OFF_BUMP_ERR + SIZE_INT;
71 public static final long OFF_YMAX = OFF_NEXT + SIZE_INT;
72
73 // size of one edge in bytes
74 public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT);
75
76 // curve break into lines
77 // cubic error in subpixels to decrement step
78 private static final double CUB_DEC_ERR_SUBPIX
79 = MarlinProperties.getCubicDecD2() * (SUBPIXEL_POSITIONS_X / 8.0d); // 1.0 / 8th pixel
80 // cubic error in subpixels to increment step
81 private static final double CUB_INC_ERR_SUBPIX
82 = MarlinProperties.getCubicIncD1() * (SUBPIXEL_POSITIONS_X / 8.0d); // 0.4 / 8th pixel
83 // scale factor for Y-axis contribution to quad / cubic errors:
84 public static final double SCALE_DY = ((double) SUBPIXEL_POSITIONS_X) / SUBPIXEL_POSITIONS_Y;
85
86 // TestNonAARasterization (JDK-8170879): cubics
87 // bad paths (59294/100000 == 59,29%, 94335 bad pixels (avg = 1,59), 3966 warnings (avg = 0,07)
88 // 2018
89 // 1.0 / 0.2: bad paths (67194/100000 == 67,19%, 117394 bad pixels (avg = 1,75 - max = 9), 4042 warnings (avg = 0,06)
90
91 // cubic bind length to decrement step
92 public static final double CUB_DEC_BND
93 = 8.0d * CUB_DEC_ERR_SUBPIX;
94 // cubic bind length to increment step
95 public static final double CUB_INC_BND
96 = 8.0d * CUB_INC_ERR_SUBPIX;
97
98 // cubic countlg
99 public static final int CUB_COUNT_LG = 2;
100 // cubic count = 2^countlg
101 private static final int CUB_COUNT = 1 << CUB_COUNT_LG;
102 // cubic count^2 = 4^countlg
103 private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG);
104 // cubic count^3 = 8^countlg
105 private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
106 // cubic dt = 1 / count
107 private static final double CUB_INV_COUNT = 1.0d / CUB_COUNT;
108 // cubic dt^2 = 1 / count^2 = 1 / 4^countlg
109 private static final double CUB_INV_COUNT_2 = 1.0d / CUB_COUNT_2;
110 // cubic dt^3 = 1 / count^3 = 1 / 8^countlg
111 private static final double CUB_INV_COUNT_3 = 1.0d / CUB_COUNT_3;
112
113 // quad break into lines
114 // quadratic error in subpixels
115 private static final double QUAD_DEC_ERR_SUBPIX
116 = MarlinProperties.getQuadDecD2() * (SUBPIXEL_POSITIONS_X / 8.0d); // 0.5 / 8th pixel
117
118 // TestNonAARasterization (JDK-8170879): quads
119 // bad paths (62916/100000 == 62,92%, 103818 bad pixels (avg = 1,65), 6514 warnings (avg = 0,10)
120 // 2018
121 // 0.50px = bad paths (62915/100000 == 62,92%, 103810 bad pixels (avg = 1,65), 6512 warnings (avg = 0,10)
122
123 // quadratic bind length to decrement step
124 public static final double QUAD_DEC_BND
125 = 8.0d * QUAD_DEC_ERR_SUBPIX;
126
127 //////////////////////////////////////////////////////////////////////////////
128 // SCAN LINE
129 //////////////////////////////////////////////////////////////////////////////
130 // crossings ie subpixel edge x coordinates
131 private int[] crossings;
132 // auxiliary storage for crossings (merge sort)
133 private int[] aux_crossings;
134
135 // indices into the segment pointer lists. They indicate the "active"
136 // sublist in the segment lists (the portion of the list that contains
137 // all the segments that cross the next scan line).
138 private int edgeCount;
139 private int[] edgePtrs;
140 // auxiliary storage for edge pointers (merge sort)
141 private int[] aux_edgePtrs;
168 private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed)
169 // used range for edgeBuckets / edgeBucketCounts
170 private int buckets_minY;
171 private int buckets_maxY;
172
173 // edgeBuckets ref (clean)
174 private final IntArrayCache.Reference edgeBuckets_ref;
175 // edgeBucketCounts ref (clean)
176 private final IntArrayCache.Reference edgeBucketCounts_ref;
177
178 // Flattens using adaptive forward differencing. This only carries out
179 // one iteration of the AFD loop. All it does is update AFD variables (i.e.
180 // X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
181 private void quadBreakIntoLinesAndAdd(double x0, double y0,
182 final DCurve c,
183 final double x2, final double y2)
184 {
185 int count = 1; // dt = 1 / count
186
187 // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
188 double maxDD = Math.abs(c.dbx) + Math.abs(c.dby) * SCALE_DY;
189
190 final double _DEC_BND = QUAD_DEC_BND;
191
192 while (maxDD >= _DEC_BND) {
193 // divide step by half:
194 maxDD /= 4.0d; // error divided by 2^2 = 4
195
196 count <<= 1;
197 if (DO_STATS) {
198 rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
199 }
200 }
201
202 final int nL = count; // line count
203
204 if (count > 1) {
205 final double icount = 1.0d / count; // dt
206 final double icount2 = icount * icount; // dt^2
207
208 final double ddx = c.dbx * icount2;
209 final double ddy = c.dby * icount2;
210 double dx = c.bx * icount2 + c.cx * icount;
211 double dy = c.by * icount2 + c.cy * icount;
212
213 // we use x0, y0 to walk the line
214 for (double x1 = x0, y1 = y0; --count > 0; dx += ddx, dy += ddy) {
215 x1 += dx;
216 y1 += dy;
217
218 addLine(x0, y0, x1, y1);
219 x0 = x1;
220 y0 = y1;
221 }
222 }
223 addLine(x0, y0, x2, y2);
224
225 if (DO_STATS) {
226 rdrCtx.stats.stat_rdr_quadBreak.add(nL);
227 }
228 }
229
230 // x0, y0 and x3,y3 are the endpoints of the curve. We could compute these
231 // using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce
232 // numerical errors, and our callers already have the exact values.
233 // Another alternative would be to pass all the control points, and call
234 // c.set here, but then too many numbers are passed around.
235 private void curveBreakIntoLinesAndAdd(double x0, double y0,
236 final DCurve c,
237 final double x3, final double y3)
238 {
239 int count = CUB_COUNT;
240 final double icount = CUB_INV_COUNT; // dt
241 final double icount2 = CUB_INV_COUNT_2; // dt^2
242 final double icount3 = CUB_INV_COUNT_3; // dt^3
243
244 // the dx and dy refer to forward differencing variables, not the last
245 // coefficients of the "points" polynomial
246 double dddx, dddy, ddx, ddy, dx, dy;
247 dddx = 2.0d * c.dax * icount3;
248 dddy = 2.0d * c.day * icount3;
249 ddx = dddx + c.dbx * icount2;
250 ddy = dddy + c.dby * icount2;
251 dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
252 dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
253
254 int nL = 0; // line count
255
256 final double _DEC_BND = CUB_DEC_BND;
257 final double _INC_BND = CUB_INC_BND;
258 final double _SCALE_DY = SCALE_DY;
259
260 // we use x0, y0 to walk the line
261 for (double x1 = x0, y1 = y0; count > 0; ) {
262 // inc / dec => ratio ~ 5 to minimize upscale / downscale but minimize edges
263
264 // double step:
265 // can only do this on even "count" values, because we must divide count by 2
266 while ((count % 2 == 0)
267 && ((Math.abs(ddx) + Math.abs(ddy) * _SCALE_DY) <= _INC_BND
268 // && (Math.abs(ddx + dddx) + Math.abs(ddy + dddy) * _SCALE_DY) <= _INC_BND
269 )) {
270 dx = 2.0d * dx + ddx;
271 dy = 2.0d * dy + ddy;
272 ddx = 4.0d * (ddx + dddx);
273 ddy = 4.0d * (ddy + dddy);
274 dddx *= 8.0d;
275 dddy *= 8.0d;
276
277 count >>= 1;
278 if (DO_STATS) {
279 rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
280 }
281 }
282
283 // divide step by half:
284 while ((Math.abs(ddx) + Math.abs(ddy) * _SCALE_DY) >= _DEC_BND
285 // || (Math.abs(ddx + dddx) + Math.abs(ddy + dddy) * _SCALE_DY) >= _DEC_BND
286 ) {
287 dddx /= 8.0d;
288 dddy /= 8.0d;
289 ddx = ddx / 4.0d - dddx;
290 ddy = ddy / 4.0d - dddy;
291 dx = (dx - ddx) / 2.0d;
292 dy = (dy - ddy) / 2.0d;
293
294 count <<= 1;
295 if (DO_STATS) {
296 rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
297 }
298 }
299 if (--count == 0) {
300 break;
301 }
302
303 x1 += dx;
304 y1 += dy;
305 dx += ddx;
306 dy += ddy;
307 ddx += dddx;
308 ddy += dddy;
309
310 addLine(x0, y0, x1, y1);
311 x0 = x1;
312 y0 = y1;
313 }
314 addLine(x0, y0, x3, y3);
315
316 if (DO_STATS) {
317 rdrCtx.stats.stat_rdr_curveBreak.add(nL + 1);
318 }
319 }
320
321 private void addLine(double x1, double y1, double x2, double y2) {
322 if (DO_MONITORS) {
323 rdrCtx.stats.mon_rdr_addLine.start();
324 }
325 if (DO_STATS) {
326 rdrCtx.stats.stat_rdr_addLine.add(1);
327 }
328 int or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
329 if (y2 < y1) {
330 or = 0;
331 double tmp = y2;
332 y2 = y1;
333 y1 = tmp;
334 tmp = x2;
335 x2 = x1;
336 x1 = tmp;
337 }
522
523 /* block flags (0|1) */
524 private int[] blkFlags;
525
526 // blkFlags ref (clean)
527 private final IntArrayCache.Reference blkFlags_ref;
528
529 DRenderer(final DRendererContext rdrCtx) {
530 this.rdrCtx = rdrCtx;
531 this.curve = rdrCtx.curve;
532 this.cache = rdrCtx.cache;
533
534 this.edges = rdrCtx.newOffHeapArray(INITIAL_EDGES_CAPACITY); // 96K
535
536 edgeBuckets_ref = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K
537 edgeBucketCounts_ref = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K
538
539 edgeBuckets = edgeBuckets_ref.initial;
540 edgeBucketCounts = edgeBucketCounts_ref.initial;
541
542 // 4096 pixels large
543 alphaLine_ref = rdrCtx.newCleanIntArrayRef(INITIAL_AA_ARRAY); // 16K
544 alphaLine = alphaLine_ref.initial;
545
546 crossings_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
547 aux_crossings_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
548 edgePtrs_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
549 aux_edgePtrs_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
550
551 crossings = crossings_ref.initial;
552 aux_crossings = aux_crossings_ref.initial;
553 edgePtrs = edgePtrs_ref.initial;
554 aux_edgePtrs = aux_edgePtrs_ref.initial;
555
556 blkFlags_ref = rdrCtx.newCleanIntArrayRef(INITIAL_ARRAY); // 1K = 1 tile line
557 blkFlags = blkFlags_ref.initial;
558 }
559
560 DRenderer init(final int pix_boundsX, final int pix_boundsY,
561 final int pix_boundsWidth, final int pix_boundsHeight,
562 final int windingRule)
563 {
681 this.x0 = sx;
682 this.y0 = sy;
683 }
684
685 @Override
686 public void lineTo(final double pix_x1, final double pix_y1) {
687 final double x1 = tosubpixx(pix_x1);
688 final double y1 = tosubpixy(pix_y1);
689 addLine(x0, y0, x1, y1);
690 x0 = x1;
691 y0 = y1;
692 }
693
694 @Override
695 public void curveTo(final double pix_x1, final double pix_y1,
696 final double pix_x2, final double pix_y2,
697 final double pix_x3, final double pix_y3)
698 {
699 final double xe = tosubpixx(pix_x3);
700 final double ye = tosubpixy(pix_y3);
701 curve.set(x0, y0,
702 tosubpixx(pix_x1), tosubpixy(pix_y1),
703 tosubpixx(pix_x2), tosubpixy(pix_y2),
704 xe, ye);
705 curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
706 x0 = xe;
707 y0 = ye;
708 }
709
710 @Override
711 public void quadTo(final double pix_x1, final double pix_y1,
712 final double pix_x2, final double pix_y2)
713 {
714 final double xe = tosubpixx(pix_x2);
715 final double ye = tosubpixy(pix_y2);
716 curve.set(x0, y0,
717 tosubpixx(pix_x1), tosubpixy(pix_y1),
718 xe, ye);
719 quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
720 x0 = xe;
721 y0 = ye;
722 }
723
724 @Override
725 public void closePath() {
726 if (x0 != sx0 || y0 != sy0) {
727 addLine(x0, y0, sx0, sy0);
728 x0 = sx0;
729 y0 = sy0;
730 }
731 }
732
733 @Override
734 public void pathDone() {
735 closePath();
736 }
737
738 @Override
|