Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/java2d/pisces/Renderer.java
38918 views
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
26
package sun.java2d.pisces;
27
28
import sun.awt.geom.PathConsumer2D;
29
30
final 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
}
572
573