Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/sun/java2d/marlin/Helpers.java
41159 views
1
/*
2
* Copyright (c) 2007, 2021, 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.marlin;
27
28
import java.util.Arrays;
29
import sun.java2d.marlin.stats.Histogram;
30
import sun.java2d.marlin.stats.StatLong;
31
32
final class Helpers implements MarlinConst {
33
34
private Helpers() {
35
throw new Error("This is a non instantiable class");
36
}
37
38
static boolean within(final double x, final double y, final double err) {
39
final double d = y - x;
40
return (d <= err && d >= -err);
41
}
42
43
static double evalCubic(final double a, final double b,
44
final double c, final double d,
45
final double t)
46
{
47
return t * (t * (t * a + b) + c) + d;
48
}
49
50
static double evalQuad(final double a, final double b,
51
final double c, final double t)
52
{
53
return t * (t * a + b) + c;
54
}
55
56
static int quadraticRoots(final double a, final double b, final double c,
57
final double[] zeroes, final int off)
58
{
59
int ret = off;
60
if (a != 0.0d) {
61
final double dis = b*b - 4.0d * a * c;
62
if (dis > 0.0d) {
63
final double sqrtDis = Math.sqrt(dis);
64
// depending on the sign of b we use a slightly different
65
// algorithm than the traditional one to find one of the roots
66
// so we can avoid adding numbers of different signs (which
67
// might result in loss of precision).
68
if (b >= 0.0d) {
69
zeroes[ret++] = (2.0d * c) / (-b - sqrtDis);
70
zeroes[ret++] = (-b - sqrtDis) / (2.0d * a);
71
} else {
72
zeroes[ret++] = (-b + sqrtDis) / (2.0d * a);
73
zeroes[ret++] = (2.0d * c) / (-b + sqrtDis);
74
}
75
} else if (dis == 0.0d) {
76
zeroes[ret++] = -b / (2.0d * a);
77
}
78
} else if (b != 0.0d) {
79
zeroes[ret++] = -c / b;
80
}
81
return ret - off;
82
}
83
84
// find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B)
85
static int cubicRootsInAB(final double d, double a, double b, double c,
86
final double[] pts, final int off,
87
final double A, final double B)
88
{
89
if (d == 0.0d) {
90
final int num = quadraticRoots(a, b, c, pts, off);
91
return filterOutNotInAB(pts, off, num, A, B) - off;
92
}
93
// From Graphics Gems:
94
// https://github.com/erich666/GraphicsGems/blob/master/gems/Roots3And4.c
95
// (also from awt.geom.CubicCurve2D. But here we don't need as
96
// much accuracy and we don't want to create arrays so we use
97
// our own customized version).
98
99
// normal form: x^3 + ax^2 + bx + c = 0
100
101
/*
102
* TODO: cleanup all that code after reading Roots3And4.c
103
*/
104
a /= d;
105
b /= d;
106
c /= d;
107
108
// substitute x = y - A/3 to eliminate quadratic term:
109
// x^3 +Px + Q = 0
110
//
111
// Since we actually need P/3 and Q/2 for all of the
112
// calculations that follow, we will calculate
113
// p = P/3
114
// q = Q/2
115
// instead and use those values for simplicity of the code.
116
final double sub = (1.0d / 3.0d) * a;
117
final double sq_A = a * a;
118
final double p = (1.0d / 3.0d) * ((-1.0d / 3.0d) * sq_A + b);
119
final double q = (1.0d / 2.0d) * ((2.0d / 27.0d) * a * sq_A - sub * b + c);
120
121
// use Cardano's formula
122
123
final double cb_p = p * p * p;
124
final double D = q * q + cb_p;
125
126
int num;
127
if (D < 0.0d) {
128
// see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
129
final double phi = (1.0d / 3.0d) * Math.acos(-q / Math.sqrt(-cb_p));
130
final double t = 2.0d * Math.sqrt(-p);
131
132
pts[off ] = ( t * Math.cos(phi) - sub);
133
pts[off + 1] = (-t * Math.cos(phi + (Math.PI / 3.0d)) - sub);
134
pts[off + 2] = (-t * Math.cos(phi - (Math.PI / 3.0d)) - sub);
135
num = 3;
136
} else {
137
final double sqrt_D = Math.sqrt(D);
138
final double u = Math.cbrt(sqrt_D - q);
139
final double v = - Math.cbrt(sqrt_D + q);
140
141
pts[off ] = (u + v - sub);
142
num = 1;
143
144
if (within(D, 0.0d, 1e-8d)) {
145
pts[off + 1] = ((-1.0d / 2.0d) * (u + v) - sub);
146
num = 2;
147
}
148
}
149
150
return filterOutNotInAB(pts, off, num, A, B) - off;
151
}
152
153
// returns the index 1 past the last valid element remaining after filtering
154
static int filterOutNotInAB(final double[] nums, final int off, final int len,
155
final double a, final double b)
156
{
157
int ret = off;
158
for (int i = off, end = off + len; i < end; i++) {
159
if (nums[i] >= a && nums[i] < b) {
160
nums[ret++] = nums[i];
161
}
162
}
163
return ret;
164
}
165
166
static double fastLineLen(final double x0, final double y0,
167
final double x1, final double y1)
168
{
169
final double dx = x1 - x0;
170
final double dy = y1 - y0;
171
172
// use manhattan norm:
173
return Math.abs(dx) + Math.abs(dy);
174
}
175
176
static double linelen(final double x0, final double y0,
177
final double x1, final double y1)
178
{
179
final double dx = x1 - x0;
180
final double dy = y1 - y0;
181
return Math.sqrt(dx * dx + dy * dy);
182
}
183
184
static double fastQuadLen(final double x0, final double y0,
185
final double x1, final double y1,
186
final double x2, final double y2)
187
{
188
final double dx1 = x1 - x0;
189
final double dx2 = x2 - x1;
190
final double dy1 = y1 - y0;
191
final double dy2 = y2 - y1;
192
193
// use manhattan norm:
194
return Math.abs(dx1) + Math.abs(dx2)
195
+ Math.abs(dy1) + Math.abs(dy2);
196
}
197
198
static double quadlen(final double x0, final double y0,
199
final double x1, final double y1,
200
final double x2, final double y2)
201
{
202
return (linelen(x0, y0, x1, y1)
203
+ linelen(x1, y1, x2, y2)
204
+ linelen(x0, y0, x2, y2)) / 2.0d;
205
}
206
207
static double fastCurvelen(final double x0, final double y0,
208
final double x1, final double y1,
209
final double x2, final double y2,
210
final double x3, final double y3)
211
{
212
final double dx1 = x1 - x0;
213
final double dx2 = x2 - x1;
214
final double dx3 = x3 - x2;
215
final double dy1 = y1 - y0;
216
final double dy2 = y2 - y1;
217
final double dy3 = y3 - y2;
218
219
// use manhattan norm:
220
return Math.abs(dx1) + Math.abs(dx2) + Math.abs(dx3)
221
+ Math.abs(dy1) + Math.abs(dy2) + Math.abs(dy3);
222
}
223
224
static double curvelen(final double x0, final double y0,
225
final double x1, final double y1,
226
final double x2, final double y2,
227
final double x3, final double y3)
228
{
229
return (linelen(x0, y0, x1, y1)
230
+ linelen(x1, y1, x2, y2)
231
+ linelen(x2, y2, x3, y3)
232
+ linelen(x0, y0, x3, y3)) / 2.0d;
233
}
234
235
// finds values of t where the curve in pts should be subdivided in order
236
// to get good offset curves a distance of w away from the middle curve.
237
// Stores the points in ts, and returns how many of them there were.
238
static int findSubdivPoints(final Curve c, final double[] pts,
239
final double[] ts, final int type,
240
final double w2)
241
{
242
final double x12 = pts[2] - pts[0];
243
final double y12 = pts[3] - pts[1];
244
// if the curve is already parallel to either axis we gain nothing
245
// from rotating it.
246
if ((y12 != 0.0d) && (x12 != 0.0d)) {
247
// we rotate it so that the first vector in the control polygon is
248
// parallel to the x-axis. This will ensure that rotated quarter
249
// circles won't be subdivided.
250
final double hypot = Math.sqrt(x12 * x12 + y12 * y12);
251
final double cos = x12 / hypot;
252
final double sin = y12 / hypot;
253
final double x1 = cos * pts[0] + sin * pts[1];
254
final double y1 = cos * pts[1] - sin * pts[0];
255
final double x2 = cos * pts[2] + sin * pts[3];
256
final double y2 = cos * pts[3] - sin * pts[2];
257
final double x3 = cos * pts[4] + sin * pts[5];
258
final double y3 = cos * pts[5] - sin * pts[4];
259
260
switch(type) {
261
case 8:
262
final double x4 = cos * pts[6] + sin * pts[7];
263
final double y4 = cos * pts[7] - sin * pts[6];
264
c.set(x1, y1, x2, y2, x3, y3, x4, y4);
265
break;
266
case 6:
267
c.set(x1, y1, x2, y2, x3, y3);
268
break;
269
default:
270
}
271
} else {
272
c.set(pts, type);
273
}
274
275
int ret = 0;
276
// we subdivide at values of t such that the remaining rotated
277
// curves are monotonic in x and y.
278
ret += c.dxRoots(ts, ret);
279
ret += c.dyRoots(ts, ret);
280
281
// subdivide at inflection points.
282
if (type == 8) {
283
// quadratic curves can't have inflection points
284
ret += c.infPoints(ts, ret);
285
}
286
287
// now we must subdivide at points where one of the offset curves will have
288
// a cusp. This happens at ts where the radius of curvature is equal to w.
289
ret += c.rootsOfROCMinusW(ts, ret, w2, 0.0001d);
290
291
ret = filterOutNotInAB(ts, 0, ret, 0.0001d, 0.9999d);
292
isort(ts, ret);
293
return ret;
294
}
295
296
// finds values of t where the curve in pts should be subdivided in order
297
// to get intersections with the given clip rectangle.
298
// Stores the points in ts, and returns how many of them there were.
299
static int findClipPoints(final Curve curve, final double[] pts,
300
final double[] ts, final int type,
301
final int outCodeOR,
302
final double[] clipRect)
303
{
304
curve.set(pts, type);
305
306
// clip rectangle (ymin, ymax, xmin, xmax)
307
int ret = 0;
308
309
if ((outCodeOR & OUTCODE_LEFT) != 0) {
310
ret += curve.xPoints(ts, ret, clipRect[2]);
311
}
312
if ((outCodeOR & OUTCODE_RIGHT) != 0) {
313
ret += curve.xPoints(ts, ret, clipRect[3]);
314
}
315
if ((outCodeOR & OUTCODE_TOP) != 0) {
316
ret += curve.yPoints(ts, ret, clipRect[0]);
317
}
318
if ((outCodeOR & OUTCODE_BOTTOM) != 0) {
319
ret += curve.yPoints(ts, ret, clipRect[1]);
320
}
321
isort(ts, ret);
322
return ret;
323
}
324
325
static void subdivide(final double[] src,
326
final double[] left, final double[] right,
327
final int type)
328
{
329
switch(type) {
330
case 8:
331
subdivideCubic(src, left, right);
332
return;
333
case 6:
334
subdivideQuad(src, left, right);
335
return;
336
default:
337
throw new InternalError("Unsupported curve type");
338
}
339
}
340
341
static void isort(final double[] a, final int len) {
342
for (int i = 1, j; i < len; i++) {
343
final double ai = a[i];
344
j = i - 1;
345
for (; j >= 0 && a[j] > ai; j--) {
346
a[j + 1] = a[j];
347
}
348
a[j + 1] = ai;
349
}
350
}
351
352
// Most of these are copied from classes in java.awt.geom because we need
353
// both single and double precision variants of these functions, and Line2D,
354
// CubicCurve2D, QuadCurve2D don't provide them.
355
/**
356
* Subdivides the cubic curve specified by the coordinates
357
* stored in the <code>src</code> array at indices <code>srcoff</code>
358
* through (<code>srcoff</code>&nbsp;+&nbsp;7) and stores the
359
* resulting two subdivided curves into the two result arrays at the
360
* corresponding indices.
361
* Either or both of the <code>left</code> and <code>right</code>
362
* arrays may be <code>null</code> or a reference to the same array
363
* as the <code>src</code> array.
364
* Note that the last point in the first subdivided curve is the
365
* same as the first point in the second subdivided curve. Thus,
366
* it is possible to pass the same array for <code>left</code>
367
* and <code>right</code> and to use offsets, such as <code>rightoff</code>
368
* equals (<code>leftoff</code> + 6), in order
369
* to avoid allocating extra storage for this common point.
370
* @param src the array holding the coordinates for the source curve
371
* @param left the array for storing the coordinates for the first
372
* half of the subdivided curve
373
* @param right the array for storing the coordinates for the second
374
* half of the subdivided curve
375
* @since 1.7
376
*/
377
static void subdivideCubic(final double[] src,
378
final double[] left,
379
final double[] right)
380
{
381
double x1 = src[0];
382
double y1 = src[1];
383
double cx1 = src[2];
384
double cy1 = src[3];
385
double cx2 = src[4];
386
double cy2 = src[5];
387
double x2 = src[6];
388
double y2 = src[7];
389
390
left[0] = x1;
391
left[1] = y1;
392
393
right[6] = x2;
394
right[7] = y2;
395
396
x1 = (x1 + cx1) / 2.0d;
397
y1 = (y1 + cy1) / 2.0d;
398
x2 = (x2 + cx2) / 2.0d;
399
y2 = (y2 + cy2) / 2.0d;
400
401
double cx = (cx1 + cx2) / 2.0d;
402
double cy = (cy1 + cy2) / 2.0d;
403
404
cx1 = (x1 + cx) / 2.0d;
405
cy1 = (y1 + cy) / 2.0d;
406
cx2 = (x2 + cx) / 2.0d;
407
cy2 = (y2 + cy) / 2.0d;
408
cx = (cx1 + cx2) / 2.0d;
409
cy = (cy1 + cy2) / 2.0d;
410
411
left[2] = x1;
412
left[3] = y1;
413
left[4] = cx1;
414
left[5] = cy1;
415
left[6] = cx;
416
left[7] = cy;
417
418
right[0] = cx;
419
right[1] = cy;
420
right[2] = cx2;
421
right[3] = cy2;
422
right[4] = x2;
423
right[5] = y2;
424
}
425
426
static void subdivideCubicAt(final double t,
427
final double[] src, final int offS,
428
final double[] pts, final int offL, final int offR)
429
{
430
double x1 = src[offS ];
431
double y1 = src[offS + 1];
432
double cx1 = src[offS + 2];
433
double cy1 = src[offS + 3];
434
double cx2 = src[offS + 4];
435
double cy2 = src[offS + 5];
436
double x2 = src[offS + 6];
437
double y2 = src[offS + 7];
438
439
pts[offL ] = x1;
440
pts[offL + 1] = y1;
441
442
pts[offR + 6] = x2;
443
pts[offR + 7] = y2;
444
445
x1 = x1 + t * (cx1 - x1);
446
y1 = y1 + t * (cy1 - y1);
447
x2 = cx2 + t * (x2 - cx2);
448
y2 = cy2 + t * (y2 - cy2);
449
450
double cx = cx1 + t * (cx2 - cx1);
451
double cy = cy1 + t * (cy2 - cy1);
452
453
cx1 = x1 + t * (cx - x1);
454
cy1 = y1 + t * (cy - y1);
455
cx2 = cx + t * (x2 - cx);
456
cy2 = cy + t * (y2 - cy);
457
cx = cx1 + t * (cx2 - cx1);
458
cy = cy1 + t * (cy2 - cy1);
459
460
pts[offL + 2] = x1;
461
pts[offL + 3] = y1;
462
pts[offL + 4] = cx1;
463
pts[offL + 5] = cy1;
464
pts[offL + 6] = cx;
465
pts[offL + 7] = cy;
466
467
pts[offR ] = cx;
468
pts[offR + 1] = cy;
469
pts[offR + 2] = cx2;
470
pts[offR + 3] = cy2;
471
pts[offR + 4] = x2;
472
pts[offR + 5] = y2;
473
}
474
475
static void subdivideQuad(final double[] src,
476
final double[] left,
477
final double[] right)
478
{
479
double x1 = src[0];
480
double y1 = src[1];
481
double cx = src[2];
482
double cy = src[3];
483
double x2 = src[4];
484
double y2 = src[5];
485
486
left[0] = x1;
487
left[1] = y1;
488
489
right[4] = x2;
490
right[5] = y2;
491
492
x1 = (x1 + cx) / 2.0d;
493
y1 = (y1 + cy) / 2.0d;
494
x2 = (x2 + cx) / 2.0d;
495
y2 = (y2 + cy) / 2.0d;
496
cx = (x1 + x2) / 2.0d;
497
cy = (y1 + y2) / 2.0d;
498
499
left[2] = x1;
500
left[3] = y1;
501
left[4] = cx;
502
left[5] = cy;
503
504
right[0] = cx;
505
right[1] = cy;
506
right[2] = x2;
507
right[3] = y2;
508
}
509
510
static void subdivideQuadAt(final double t,
511
final double[] src, final int offS,
512
final double[] pts, final int offL, final int offR)
513
{
514
double x1 = src[offS ];
515
double y1 = src[offS + 1];
516
double cx = src[offS + 2];
517
double cy = src[offS + 3];
518
double x2 = src[offS + 4];
519
double y2 = src[offS + 5];
520
521
pts[offL ] = x1;
522
pts[offL + 1] = y1;
523
524
pts[offR + 4] = x2;
525
pts[offR + 5] = y2;
526
527
x1 = x1 + t * (cx - x1);
528
y1 = y1 + t * (cy - y1);
529
x2 = cx + t * (x2 - cx);
530
y2 = cy + t * (y2 - cy);
531
cx = x1 + t * (x2 - x1);
532
cy = y1 + t * (y2 - y1);
533
534
pts[offL + 2] = x1;
535
pts[offL + 3] = y1;
536
pts[offL + 4] = cx;
537
pts[offL + 5] = cy;
538
539
pts[offR ] = cx;
540
pts[offR + 1] = cy;
541
pts[offR + 2] = x2;
542
pts[offR + 3] = y2;
543
}
544
545
static void subdivideLineAt(final double t,
546
final double[] src, final int offS,
547
final double[] pts, final int offL, final int offR)
548
{
549
double x1 = src[offS ];
550
double y1 = src[offS + 1];
551
double x2 = src[offS + 2];
552
double y2 = src[offS + 3];
553
554
pts[offL ] = x1;
555
pts[offL + 1] = y1;
556
557
pts[offR + 2] = x2;
558
pts[offR + 3] = y2;
559
560
x1 = x1 + t * (x2 - x1);
561
y1 = y1 + t * (y2 - y1);
562
563
pts[offL + 2] = x1;
564
pts[offL + 3] = y1;
565
566
pts[offR ] = x1;
567
pts[offR + 1] = y1;
568
}
569
570
static void subdivideAt(final double t,
571
final double[] src, final int offS,
572
final double[] pts, final int offL, final int type)
573
{
574
// if instead of switch (perf + most probable cases first)
575
if (type == 8) {
576
subdivideCubicAt(t, src, offS, pts, offL, offL + type);
577
} else if (type == 4) {
578
subdivideLineAt(t, src, offS, pts, offL, offL + type);
579
} else {
580
subdivideQuadAt(t, src, offS, pts, offL, offL + type);
581
}
582
}
583
584
// From sun.java2d.loops.GeneralRenderer:
585
586
static int outcode(final double x, final double y,
587
final double[] clipRect)
588
{
589
int code;
590
if (y < clipRect[0]) {
591
code = OUTCODE_TOP;
592
} else if (y >= clipRect[1]) {
593
code = OUTCODE_BOTTOM;
594
} else {
595
code = 0;
596
}
597
if (x < clipRect[2]) {
598
code |= OUTCODE_LEFT;
599
} else if (x >= clipRect[3]) {
600
code |= OUTCODE_RIGHT;
601
}
602
return code;
603
}
604
605
// a stack of polynomial curves where each curve shares endpoints with
606
// adjacent ones.
607
static final class PolyStack {
608
private static final byte TYPE_LINETO = (byte) 0;
609
private static final byte TYPE_QUADTO = (byte) 1;
610
private static final byte TYPE_CUBICTO = (byte) 2;
611
612
// curves capacity = edges count (8192) = edges x 2 (coords)
613
private static final int INITIAL_CURVES_COUNT = INITIAL_EDGES_COUNT << 1;
614
615
// types capacity = edges count (4096)
616
private static final int INITIAL_TYPES_COUNT = INITIAL_EDGES_COUNT;
617
618
double[] curves;
619
int end;
620
byte[] curveTypes;
621
int numCurves;
622
623
// curves ref (dirty)
624
final DoubleArrayCache.Reference curves_ref;
625
// curveTypes ref (dirty)
626
final ByteArrayCache.Reference curveTypes_ref;
627
628
// used marks (stats only)
629
int curveTypesUseMark;
630
int curvesUseMark;
631
632
private final StatLong stat_polystack_types;
633
private final StatLong stat_polystack_curves;
634
private final Histogram hist_polystack_curves;
635
private final StatLong stat_array_polystack_curves;
636
private final StatLong stat_array_polystack_curveTypes;
637
638
PolyStack(final RendererContext rdrCtx) {
639
this(rdrCtx, null, null, null, null, null);
640
}
641
642
PolyStack(final RendererContext rdrCtx,
643
final StatLong stat_polystack_types,
644
final StatLong stat_polystack_curves,
645
final Histogram hist_polystack_curves,
646
final StatLong stat_array_polystack_curves,
647
final StatLong stat_array_polystack_curveTypes)
648
{
649
curves_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_CURVES_COUNT); // 32K
650
curves = curves_ref.initial;
651
652
curveTypes_ref = rdrCtx.newDirtyByteArrayRef(INITIAL_TYPES_COUNT); // 4K
653
curveTypes = curveTypes_ref.initial;
654
numCurves = 0;
655
end = 0;
656
657
if (DO_STATS) {
658
curveTypesUseMark = 0;
659
curvesUseMark = 0;
660
}
661
this.stat_polystack_types = stat_polystack_types;
662
this.stat_polystack_curves = stat_polystack_curves;
663
this.hist_polystack_curves = hist_polystack_curves;
664
this.stat_array_polystack_curves = stat_array_polystack_curves;
665
this.stat_array_polystack_curveTypes = stat_array_polystack_curveTypes;
666
}
667
668
/**
669
* Disposes this PolyStack:
670
* clean up before reusing this instance
671
*/
672
void dispose() {
673
end = 0;
674
numCurves = 0;
675
676
if (DO_STATS) {
677
stat_polystack_types.add(curveTypesUseMark);
678
stat_polystack_curves.add(curvesUseMark);
679
hist_polystack_curves.add(curvesUseMark);
680
681
// reset marks
682
curveTypesUseMark = 0;
683
curvesUseMark = 0;
684
}
685
686
// Return arrays:
687
// curves and curveTypes are kept dirty
688
curves = curves_ref.putArray(curves);
689
curveTypes = curveTypes_ref.putArray(curveTypes);
690
}
691
692
private void ensureSpace(final int n) {
693
// use substraction to avoid integer overflow:
694
if (curves.length - end < n) {
695
if (DO_STATS) {
696
stat_array_polystack_curves.add(end + n);
697
}
698
curves = curves_ref.widenArray(curves, end, end + n);
699
}
700
if (curveTypes.length <= numCurves) {
701
if (DO_STATS) {
702
stat_array_polystack_curveTypes.add(numCurves + 1);
703
}
704
curveTypes = curveTypes_ref.widenArray(curveTypes,
705
numCurves,
706
numCurves + 1);
707
}
708
}
709
710
void pushCubic(double x0, double y0,
711
double x1, double y1,
712
double x2, double y2)
713
{
714
ensureSpace(6);
715
curveTypes[numCurves++] = TYPE_CUBICTO;
716
// we reverse the coordinate order to make popping easier
717
final double[] _curves = curves;
718
int e = end;
719
_curves[e++] = x2; _curves[e++] = y2;
720
_curves[e++] = x1; _curves[e++] = y1;
721
_curves[e++] = x0; _curves[e++] = y0;
722
end = e;
723
}
724
725
void pushQuad(double x0, double y0,
726
double x1, double y1)
727
{
728
ensureSpace(4);
729
curveTypes[numCurves++] = TYPE_QUADTO;
730
final double[] _curves = curves;
731
int e = end;
732
_curves[e++] = x1; _curves[e++] = y1;
733
_curves[e++] = x0; _curves[e++] = y0;
734
end = e;
735
}
736
737
void pushLine(double x, double y) {
738
ensureSpace(2);
739
curveTypes[numCurves++] = TYPE_LINETO;
740
curves[end++] = x; curves[end++] = y;
741
}
742
743
void pullAll(final DPathConsumer2D io) {
744
final int nc = numCurves;
745
if (nc == 0) {
746
return;
747
}
748
if (DO_STATS) {
749
// update used marks:
750
if (numCurves > curveTypesUseMark) {
751
curveTypesUseMark = numCurves;
752
}
753
if (end > curvesUseMark) {
754
curvesUseMark = end;
755
}
756
}
757
final byte[] _curveTypes = curveTypes;
758
final double[] _curves = curves;
759
int e = 0;
760
761
for (int i = 0; i < nc; i++) {
762
switch(_curveTypes[i]) {
763
case TYPE_LINETO:
764
io.lineTo(_curves[e], _curves[e+1]);
765
e += 2;
766
continue;
767
case TYPE_CUBICTO:
768
io.curveTo(_curves[e], _curves[e+1],
769
_curves[e+2], _curves[e+3],
770
_curves[e+4], _curves[e+5]);
771
e += 6;
772
continue;
773
case TYPE_QUADTO:
774
io.quadTo(_curves[e], _curves[e+1],
775
_curves[e+2], _curves[e+3]);
776
e += 4;
777
continue;
778
default:
779
}
780
}
781
numCurves = 0;
782
end = 0;
783
}
784
785
void popAll(final DPathConsumer2D io) {
786
int nc = numCurves;
787
if (nc == 0) {
788
return;
789
}
790
if (DO_STATS) {
791
// update used marks:
792
if (numCurves > curveTypesUseMark) {
793
curveTypesUseMark = numCurves;
794
}
795
if (end > curvesUseMark) {
796
curvesUseMark = end;
797
}
798
}
799
final byte[] _curveTypes = curveTypes;
800
final double[] _curves = curves;
801
int e = end;
802
803
while (nc != 0) {
804
switch(_curveTypes[--nc]) {
805
case TYPE_LINETO:
806
e -= 2;
807
io.lineTo(_curves[e], _curves[e+1]);
808
continue;
809
case TYPE_CUBICTO:
810
e -= 6;
811
io.curveTo(_curves[e], _curves[e+1],
812
_curves[e+2], _curves[e+3],
813
_curves[e+4], _curves[e+5]);
814
continue;
815
case TYPE_QUADTO:
816
e -= 4;
817
io.quadTo(_curves[e], _curves[e+1],
818
_curves[e+2], _curves[e+3]);
819
continue;
820
default:
821
}
822
}
823
numCurves = 0;
824
end = 0;
825
}
826
827
@Override
828
public String toString() {
829
String ret = "";
830
int nc = numCurves;
831
int last = end;
832
int len;
833
while (nc != 0) {
834
switch(curveTypes[--nc]) {
835
case TYPE_LINETO:
836
len = 2;
837
ret += "line: ";
838
break;
839
case TYPE_QUADTO:
840
len = 4;
841
ret += "quad: ";
842
break;
843
case TYPE_CUBICTO:
844
len = 6;
845
ret += "cubic: ";
846
break;
847
default:
848
len = 0;
849
}
850
last -= len;
851
ret += Arrays.toString(Arrays.copyOfRange(curves, last, last+len))
852
+ "\n";
853
}
854
return ret;
855
}
856
}
857
858
// a stack of integer indices
859
static final class IndexStack {
860
861
// integer capacity = edges count / 4 ~ 1024
862
private static final int INITIAL_COUNT = INITIAL_EDGES_COUNT >> 2;
863
864
private int end;
865
private int[] indices;
866
867
// indices ref (dirty)
868
private final IntArrayCache.Reference indices_ref;
869
870
// used marks (stats only)
871
private int indicesUseMark;
872
873
private final StatLong stat_idxstack_indices;
874
private final Histogram hist_idxstack_indices;
875
private final StatLong stat_array_idxstack_indices;
876
877
IndexStack(final RendererContext rdrCtx) {
878
this(rdrCtx, null, null, null);
879
}
880
881
IndexStack(final RendererContext rdrCtx,
882
final StatLong stat_idxstack_indices,
883
final Histogram hist_idxstack_indices,
884
final StatLong stat_array_idxstack_indices)
885
{
886
indices_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_COUNT); // 4K
887
indices = indices_ref.initial;
888
end = 0;
889
890
if (DO_STATS) {
891
indicesUseMark = 0;
892
}
893
this.stat_idxstack_indices = stat_idxstack_indices;
894
this.hist_idxstack_indices = hist_idxstack_indices;
895
this.stat_array_idxstack_indices = stat_array_idxstack_indices;
896
}
897
898
/**
899
* Disposes this PolyStack:
900
* clean up before reusing this instance
901
*/
902
void dispose() {
903
end = 0;
904
905
if (DO_STATS) {
906
stat_idxstack_indices.add(indicesUseMark);
907
hist_idxstack_indices.add(indicesUseMark);
908
909
// reset marks
910
indicesUseMark = 0;
911
}
912
913
// Return arrays:
914
// values is kept dirty
915
indices = indices_ref.putArray(indices);
916
}
917
918
boolean isEmpty() {
919
return (end == 0);
920
}
921
922
void reset() {
923
end = 0;
924
}
925
926
void push(final int v) {
927
// remove redundant values (reverse order):
928
int[] _values = indices;
929
final int nc = end;
930
if (nc != 0) {
931
if (_values[nc - 1] == v) {
932
// remove both duplicated values:
933
end--;
934
return;
935
}
936
}
937
if (_values.length <= nc) {
938
if (DO_STATS) {
939
stat_array_idxstack_indices.add(nc + 1);
940
}
941
indices = _values = indices_ref.widenArray(_values, nc, nc + 1);
942
}
943
_values[end++] = v;
944
945
if (DO_STATS) {
946
// update used marks:
947
if (end > indicesUseMark) {
948
indicesUseMark = end;
949
}
950
}
951
}
952
953
void pullAll(final double[] points, final DPathConsumer2D io) {
954
final int nc = end;
955
if (nc == 0) {
956
return;
957
}
958
final int[] _values = indices;
959
960
for (int i = 0, j; i < nc; i++) {
961
j = _values[i] << 1;
962
io.lineTo(points[j], points[j + 1]);
963
}
964
end = 0;
965
}
966
}
967
}
968
969