History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/java2d/pisces/Renderer.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/java2d/pisces/Renderer.java+571−0
@@ -0,0 +1,571 @@
1/*
2 * Copyright (c) 2007, 2011, 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
23 * questions.
24 */
25
26package sun.java2d.pisces;
27
28import sun.awt.geom.PathConsumer2D;
29
30final class Renderer implements PathConsumer2D {
31
32 private class ScanlineIterator {
33
34 private int[] crossings;
35
36 // crossing bounds. The bounds are not necessarily tight (the scan line
37 // at minY, for example, might have no crossings). The x bounds will
38 // be accumulated as crossings are computed.
39 private final int maxY;
40 private int nextY;
41
42 // indices into the segment pointer lists. They indicate the "active"
43 // sublist in the segment lists (the portion of the list that contains
44 // all the segments that cross the next scan line).
45 private int edgeCount;
46 private int[] edgePtrs;
47
48 private static final int INIT_CROSSINGS_SIZE = 10;
49
50 // Preconditions: Only subpixel scanlines in the range
51 // (start <= subpixel_y <= end) will be evaluated. No
52 // edge may have a valid (i.e. inside the supplied clip)
53 // crossing that would be generated outside that range.
54 private ScanlineIterator(int start, int end) {
55 crossings = new int[INIT_CROSSINGS_SIZE];
56 edgePtrs = new int[INIT_CROSSINGS_SIZE];
57
58 nextY = start;
59 maxY = end;
60 edgeCount = 0;
61 }
62
63 private int next() {
64 int cury = nextY++;
65 int bucket = cury - boundsMinY;
66 int count = this.edgeCount;
67 int ptrs[] = this.edgePtrs;
68 int bucketcount = edgeBucketCounts[bucket];
69 if ((bucketcount & 0x1) != 0) {
70 int newCount = 0;
71 for (int i = 0; i < count; i++) {
72 int ecur = ptrs[i];
73 if (edges[ecur+YMAX] > cury) {
74 ptrs[newCount++] = ecur;
75 }
76 }
77 count = newCount;
78 }
79 ptrs = Helpers.widenArray(ptrs, count, bucketcount >> 1);
80 for (int ecur = edgeBuckets[bucket]; ecur != NULL; ecur = (int)edges[ecur+NEXT]) {
81 ptrs[count++] = ecur;
82 // REMIND: Adjust start Y if necessary
83 }
84 this.edgePtrs = ptrs;
85 this.edgeCount = count;
86// if ((count & 0x1) != 0) {
87// System.out.println("ODD NUMBER OF EDGES!!!!");
88// }
89 int xings[] = this.crossings;
90 if (xings.length < count) {
91 this.crossings = xings = new int[ptrs.length];
92 }
93 for (int i = 0; i < count; i++) {
94 int ecur = ptrs[i];
95 float curx = edges[ecur+CURX];
96 int cross = ((int) curx) << 1;
97 edges[ecur+CURX] = curx + edges[ecur+SLOPE];
98 if (edges[ecur+OR] > 0) {
99 cross |= 1;
100 }
101 int j = i;
102 while (--j >= 0) {
103 int jcross = xings[j];
104 if (jcross <= cross) {
105 break;
106 }
107 xings[j+1] = jcross;
108 ptrs[j+1] = ptrs[j];
109 }
110 xings[j+1] = cross;
111 ptrs[j+1] = ecur;
112 }
113 return count;
114 }
115
116 private boolean hasNext() {
117 return nextY < maxY;
118 }
119
120 private int curY() {
121 return nextY - 1;
122 }
123 }
124
125
126//////////////////////////////////////////////////////////////////////////////
127// EDGE LIST
128//////////////////////////////////////////////////////////////////////////////
129// TODO(maybe): very tempting to use fixed point here. A lot of opportunities
130// for shifts and just removing certain operations altogether.
131
132 // common to all types of input path segments.
133 private static final int YMAX = 0;
134 private static final int CURX = 1;
135 // NEXT and OR are meant to be indices into "int" fields, but arrays must
136 // be homogenous, so every field is a float. However floats can represent
137 // exactly up to 26 bit ints, so we're ok.
138 private static final int OR = 2;
139 private static final int SLOPE = 3;
140 private static final int NEXT = 4;
141
142 private float edgeMinY = Float.POSITIVE_INFINITY;
143 private float edgeMaxY = Float.NEGATIVE_INFINITY;
144 private float edgeMinX = Float.POSITIVE_INFINITY;
145 private float edgeMaxX = Float.NEGATIVE_INFINITY;
146
147 private static final int SIZEOF_EDGE = 5;
148 // don't just set NULL to -1, because we want NULL+NEXT to be negative.
149 private static final int NULL = -SIZEOF_EDGE;
150 private float[] edges = null;
151 private static final int INIT_NUM_EDGES = 8;
152 private int[] edgeBuckets = null;
153 private int[] edgeBucketCounts = null; // 2*newedges + (1 if pruning needed)
154 private int numEdges;
155
156 private static final float DEC_BND = 20f;
157 private static final float INC_BND = 8f;
158
159 // each bucket is a linked list. this method adds eptr to the
160 // start of the "bucket"th linked list.
161 private void addEdgeToBucket(final int eptr, final int bucket) {
162 edges[eptr+NEXT] = edgeBuckets[bucket];
163 edgeBuckets[bucket] = eptr;
164 edgeBucketCounts[bucket] += 2;
165 }
166
167 // Flattens using adaptive forward differencing. This only carries out
168 // one iteration of the AFD loop. All it does is update AFD variables (i.e.
169 // X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
170 private void quadBreakIntoLinesAndAdd(float x0, float y0,
171 final Curve c,
172 final float x2, final float y2)
173 {
174 final float QUAD_DEC_BND = 32;
175 final int countlg = 4;
176 int count = 1 << countlg;
177 int countsq = count * count;
178 float maxDD = Math.max(c.dbx / countsq, c.dby / countsq);
179 while (maxDD > QUAD_DEC_BND) {
180 maxDD /= 4;
181 count <<= 1;
182 }
183
184 countsq = count * count;
185 final float ddx = c.dbx / countsq;
186 final float ddy = c.dby / countsq;
187 float dx = c.bx / countsq + c.cx / count;
188 float dy = c.by / countsq + c.cy / count;
189
190 while (count-- > 1) {
191 float x1 = x0 + dx;
192 dx += ddx;
193 float y1 = y0 + dy;
194 dy += ddy;
195 addLine(x0, y0, x1, y1);
196 x0 = x1;
197 y0 = y1;
198 }
199 addLine(x0, y0, x2, y2);
200 }
201
202 // x0, y0 and x3,y3 are the endpoints of the curve. We could compute these
203 // using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce
204 // numerical errors, and our callers already have the exact values.
205 // Another alternative would be to pass all the control points, and call c.set
206 // here, but then too many numbers are passed around.
207 private void curveBreakIntoLinesAndAdd(float x0, float y0,
208 final Curve c,
209 final float x3, final float y3)
210 {
211 final int countlg = 3;
212 int count = 1 << countlg;
213
214 // the dx and dy refer to forward differencing variables, not the last
215 // coefficients of the "points" polynomial
216 float dddx, dddy, ddx, ddy, dx, dy;
217 dddx = 2f * c.dax / (1 << (3 * countlg));
218 dddy = 2f * c.day / (1 << (3 * countlg));
219
220 ddx = dddx + c.dbx / (1 << (2 * countlg));
221 ddy = dddy + c.dby / (1 << (2 * countlg));
222 dx = c.ax / (1 << (3 * countlg)) + c.bx / (1 << (2 * countlg)) + c.cx / (1 << countlg);
223 dy = c.ay / (1 << (3 * countlg)) + c.by / (1 << (2 * countlg)) + c.cy / (1 << countlg);
224
225 // we use x0, y0 to walk the line
226 float x1 = x0, y1 = y0;
227 while (count > 0) {
228 while (Math.abs(ddx) > DEC_BND || Math.abs(ddy) > DEC_BND) {
229 dddx /= 8;
230 dddy /= 8;
231 ddx = ddx/4 - dddx;
232 ddy = ddy/4 - dddy;
233 dx = (dx - ddx) / 2;
234 dy = (dy - ddy) / 2;
235 count <<= 1;
236 }
237 // can only do this on even "count" values, because we must divide count by 2
238 while (count % 2 == 0 && Math.abs(dx) <= INC_BND && Math.abs(dy) <= INC_BND) {
239 dx = 2 * dx + ddx;
240 dy = 2 * dy + ddy;
241 ddx = 4 * (ddx + dddx);
242 ddy = 4 * (ddy + dddy);
243 dddx = 8 * dddx;
244 dddy = 8 * dddy;
245 count >>= 1;
246 }
247 count--;
248 if (count > 0) {
249 x1 += dx;
250 dx += ddx;
251 ddx += dddx;
252 y1 += dy;
253 dy += ddy;
254 ddy += dddy;
255 } else {
256 x1 = x3;
257 y1 = y3;
258 }
259 addLine(x0, y0, x1, y1);
260 x0 = x1;
261 y0 = y1;
262 }
263 }
264
265 private void addLine(float x1, float y1, float x2, float y2) {
266 float or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
267 if (y2 < y1) {
268 or = y2; // no need to declare a temp variable. We have or.
269 y2 = y1;
270 y1 = or;
271 or = x2;
272 x2 = x1;
273 x1 = or;
274 or = 0;
275 }
276 final int firstCrossing = Math.max((int)Math.ceil(y1), boundsMinY);
277 final int lastCrossing = Math.min((int)Math.ceil(y2), boundsMaxY);
278 if (firstCrossing >= lastCrossing) {
279 return;
280 }
281 if (y1 < edgeMinY) { edgeMinY = y1; }
282 if (y2 > edgeMaxY) { edgeMaxY = y2; }
283
284 final float slope = (x2 - x1) / (y2 - y1);
285
286 if (slope > 0) { // <==> x1 < x2
287 if (x1 < edgeMinX) { edgeMinX = x1; }
288 if (x2 > edgeMaxX) { edgeMaxX = x2; }
289 } else {
290 if (x2 < edgeMinX) { edgeMinX = x2; }
291 if (x1 > edgeMaxX) { edgeMaxX = x1; }
292 }
293
294 final int ptr = numEdges * SIZEOF_EDGE;
295 edges = Helpers.widenArray(edges, ptr, SIZEOF_EDGE);
296 numEdges++;
297 edges[ptr+OR] = or;
298 edges[ptr+CURX] = x1 + (firstCrossing - y1) * slope;
299 edges[ptr+SLOPE] = slope;
300 edges[ptr+YMAX] = lastCrossing;
301 final int bucketIdx = firstCrossing - boundsMinY;
302 addEdgeToBucket(ptr, bucketIdx);
303 edgeBucketCounts[lastCrossing - boundsMinY] |= 1;
304 }
305
306// END EDGE LIST
307//////////////////////////////////////////////////////////////////////////////
308
309
310 public static final int WIND_EVEN_ODD = 0;
311 public static final int WIND_NON_ZERO = 1;
312
313 // Antialiasing
314 final private int SUBPIXEL_LG_POSITIONS_X;
315 final private int SUBPIXEL_LG_POSITIONS_Y;
316 final private int SUBPIXEL_POSITIONS_X;
317 final private int SUBPIXEL_POSITIONS_Y;
318 final private int SUBPIXEL_MASK_X;
319 final private int SUBPIXEL_MASK_Y;
320 final int MAX_AA_ALPHA;
321
322 // Cache to store RLE-encoded coverage mask of the current primitive
323 PiscesCache cache;
324
325 // Bounds of the drawing region, at subpixel precision.
326 private final int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
327
328 // Current winding rule
329 private final int windingRule;
330
331 // Current drawing position, i.e., final point of last segment
332 private float x0, y0;
333
334 // Position of most recent 'moveTo' command
335 private float pix_sx0, pix_sy0;
336
337 public Renderer(int subpixelLgPositionsX, int subpixelLgPositionsY,
338 int pix_boundsX, int pix_boundsY,
339 int pix_boundsWidth, int pix_boundsHeight,
340 int windingRule)
341 {
342 this.SUBPIXEL_LG_POSITIONS_X = subpixelLgPositionsX;
343 this.SUBPIXEL_LG_POSITIONS_Y = subpixelLgPositionsY;
344 this.SUBPIXEL_MASK_X = (1 << (SUBPIXEL_LG_POSITIONS_X)) - 1;
345 this.SUBPIXEL_MASK_Y = (1 << (SUBPIXEL_LG_POSITIONS_Y)) - 1;
346 this.SUBPIXEL_POSITIONS_X = 1 << (SUBPIXEL_LG_POSITIONS_X);
347 this.SUBPIXEL_POSITIONS_Y = 1 << (SUBPIXEL_LG_POSITIONS_Y);
348 this.MAX_AA_ALPHA = (SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_Y);
349
350 this.windingRule = windingRule;
351
352 this.boundsMinX = pix_boundsX * SUBPIXEL_POSITIONS_X;
353 this.boundsMinY = pix_boundsY * SUBPIXEL_POSITIONS_Y;
354 this.boundsMaxX = (pix_boundsX + pix_boundsWidth) * SUBPIXEL_POSITIONS_X;
355 this.boundsMaxY = (pix_boundsY + pix_boundsHeight) * SUBPIXEL_POSITIONS_Y;
356
357 edges = new float[INIT_NUM_EDGES * SIZEOF_EDGE];
358 numEdges = 0;
359 edgeBuckets = new int[boundsMaxY - boundsMinY];
360 java.util.Arrays.fill(edgeBuckets, NULL);
361 edgeBucketCounts = new int[edgeBuckets.length + 1];
362 }
363
364 private float tosubpixx(float pix_x) {
365 return pix_x * SUBPIXEL_POSITIONS_X;
366 }
367 private float tosubpixy(float pix_y) {
368 return pix_y * SUBPIXEL_POSITIONS_Y;
369 }
370
371 public void moveTo(float pix_x0, float pix_y0) {
372 closePath();
373 this.pix_sx0 = pix_x0;
374 this.pix_sy0 = pix_y0;
375 this.y0 = tosubpixy(pix_y0);
376 this.x0 = tosubpixx(pix_x0);
377 }
378
379 public void lineTo(float pix_x1, float pix_y1) {
380 float x1 = tosubpixx(pix_x1);
381 float y1 = tosubpixy(pix_y1);
382 addLine(x0, y0, x1, y1);
383 x0 = x1;
384 y0 = y1;
385 }
386
387 private Curve c = new Curve();
388 @Override public void curveTo(float x1, float y1,
389 float x2, float y2,
390 float x3, float y3)
391 {
392 final float xe = tosubpixx(x3);
393 final float ye = tosubpixy(y3);
394 c.set(x0, y0, tosubpixx(x1), tosubpixy(y1), tosubpixx(x2), tosubpixy(y2), xe, ye);
395 curveBreakIntoLinesAndAdd(x0, y0, c, xe, ye);
396 x0 = xe;
397 y0 = ye;
398 }
399
400 @Override public void quadTo(float x1, float y1, float x2, float y2) {
401 final float xe = tosubpixx(x2);
402 final float ye = tosubpixy(y2);
403 c.set(x0, y0, tosubpixx(x1), tosubpixy(y1), xe, ye);
404 quadBreakIntoLinesAndAdd(x0, y0, c, xe, ye);
405 x0 = xe;
406 y0 = ye;
407 }
408
409 public void closePath() {
410 // lineTo expects its input in pixel coordinates.
411 lineTo(pix_sx0, pix_sy0);
412 }
413
414 public void pathDone() {
415 closePath();
416 }
417
418
419 @Override
420 public long getNativeConsumer() {
421 throw new InternalError("Renderer does not use a native consumer.");
422 }
423
424 private void _endRendering(final int pix_bboxx0, final int pix_bboxx1,
425 int ymin, int ymax)
426 {
427 // Mask to determine the relevant bit of the crossing sum
428 // 0x1 if EVEN_ODD, all bits if NON_ZERO
429 int mask = (windingRule == WIND_EVEN_ODD) ? 0x1 : ~0x0;
430
431 // add 2 to better deal with the last pixel in a pixel row.
432 int width = pix_bboxx1 - pix_bboxx0;
433 int[] alpha = new int[width+2];
434
435 int bboxx0 = pix_bboxx0 << SUBPIXEL_LG_POSITIONS_X;
436 int bboxx1 = pix_bboxx1 << SUBPIXEL_LG_POSITIONS_X;
437
438 // Now we iterate through the scanlines. We must tell emitRow the coord
439 // of the first non-transparent pixel, so we must keep accumulators for
440 // the first and last pixels of the section of the current pixel row
441 // that we will emit.
442 // We also need to accumulate pix_bbox*, but the iterator does it
443 // for us. We will just get the values from it once this loop is done
444 int pix_maxX = Integer.MIN_VALUE;
445 int pix_minX = Integer.MAX_VALUE;
446
447 int y = boundsMinY; // needs to be declared here so we emit the last row properly.
448 ScanlineIterator it = this.new ScanlineIterator(ymin, ymax);
449 for ( ; it.hasNext(); ) {
450 int numCrossings = it.next();
451 int[] crossings = it.crossings;
452 y = it.curY();
453
454 if (numCrossings > 0) {
455 int lowx = crossings[0] >> 1;
456 int highx = crossings[numCrossings - 1] >> 1;
457 int x0 = Math.max(lowx, bboxx0);
458 int x1 = Math.min(highx, bboxx1);
459
460 pix_minX = Math.min(pix_minX, x0 >> SUBPIXEL_LG_POSITIONS_X);
461 pix_maxX = Math.max(pix_maxX, x1 >> SUBPIXEL_LG_POSITIONS_X);
462 }
463
464 int sum = 0;
465 int prev = bboxx0;
466 for (int i = 0; i < numCrossings; i++) {
467 int curxo = crossings[i];
468 int curx = curxo >> 1;
469 // to turn {0, 1} into {-1, 1}, multiply by 2 and subtract 1.
470 int crorientation = ((curxo & 0x1) << 1) - 1;
471 if ((sum & mask) != 0) {
472 int x0 = Math.max(prev, bboxx0);
473 int x1 = Math.min(curx, bboxx1);
474 if (x0 < x1) {
475 x0 -= bboxx0; // turn x0, x1 from coords to indeces
476 x1 -= bboxx0; // in the alpha array.
477
478 int pix_x = x0 >> SUBPIXEL_LG_POSITIONS_X;
479 int pix_xmaxm1 = (x1 - 1) >> SUBPIXEL_LG_POSITIONS_X;
480
481 if (pix_x == pix_xmaxm1) {
482 // Start and end in same pixel
483 alpha[pix_x] += (x1 - x0);
484 alpha[pix_x+1] -= (x1 - x0);
485 } else {
486 int pix_xmax = x1 >> SUBPIXEL_LG_POSITIONS_X;
487 alpha[pix_x] += SUBPIXEL_POSITIONS_X - (x0 & SUBPIXEL_MASK_X);
488 alpha[pix_x+1] += (x0 & SUBPIXEL_MASK_X);
489 alpha[pix_xmax] -= SUBPIXEL_POSITIONS_X - (x1 & SUBPIXEL_MASK_X);
490 alpha[pix_xmax+1] -= (x1 & SUBPIXEL_MASK_X);
491 }
492 }
493 }
494 sum += crorientation;
495 prev = curx;
496 }
497
498 // even if this last row had no crossings, alpha will be zeroed
499 // from the last emitRow call. But this doesn't matter because
500 // maxX < minX, so no row will be emitted to the cache.
501 if ((y & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) {
502 emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX);
503 pix_minX = Integer.MAX_VALUE;
504 pix_maxX = Integer.MIN_VALUE;
505 }
506 }
507
508 // Emit final row
509 if (pix_maxX >= pix_minX) {
510 emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX);
511 }
512 }
513
514 public void endRendering() {
515 int spminX = Math.max((int)Math.ceil(edgeMinX), boundsMinX);
516 int spmaxX = Math.min((int)Math.ceil(edgeMaxX), boundsMaxX);
517 int spminY = Math.max((int)Math.ceil(edgeMinY), boundsMinY);
518 int spmaxY = Math.min((int)Math.ceil(edgeMaxY), boundsMaxY);
519
520 int pminX = spminX >> SUBPIXEL_LG_POSITIONS_X;
521 int pmaxX = (spmaxX + SUBPIXEL_MASK_X) >> SUBPIXEL_LG_POSITIONS_X;
522 int pminY = spminY >> SUBPIXEL_LG_POSITIONS_Y;
523 int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y;
524
525 if (pminX > pmaxX || pminY > pmaxY) {
526 this.cache = new PiscesCache(boundsMinX >> SUBPIXEL_LG_POSITIONS_X,
527 boundsMinY >> SUBPIXEL_LG_POSITIONS_Y,
528 boundsMaxX >> SUBPIXEL_LG_POSITIONS_X,
529 boundsMaxY >> SUBPIXEL_LG_POSITIONS_Y);
530 return;
531 }
532
533 this.cache = new PiscesCache(pminX, pminY, pmaxX, pmaxY);
534 _endRendering(pminX, pmaxX, spminY, spmaxY);
535 }
536
537 public PiscesCache getCache() {
538 if (cache == null) {
539 throw new InternalError("cache not yet initialized");
540 }
541 return cache;
542 }
543
544 private void emitRow(int[] alphaRow, int pix_y, int pix_from, int pix_to) {
545 // Copy rowAA data into the cache if one is present
546 if (cache != null) {
547 if (pix_to >= pix_from) {
548 cache.startRow(pix_y, pix_from);
549
550 // Perform run-length encoding and store results in the cache
551 int from = pix_from - cache.bboxX0;
552 int to = pix_to - cache.bboxX0;
553
554 int runLen = 1;
555 int startVal = alphaRow[from];
556 for (int i = from + 1; i <= to; i++) {
557 int nextVal = startVal + alphaRow[i];
558 if (nextVal == startVal) {
559 runLen++;
560 } else {
561 cache.addRLERun(startVal, runLen);
562 runLen = 1;
563 startVal = nextVal;
564 }
565 }
566 cache.addRLERun(startVal, runLen);
567 }
568 }
569 java.util.Arrays.fill(alphaRow, 0);
570 }
571}