Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/libawt/java2d/pipe/ShapeSpanIterator.c
41159 views
1
/*
2
* Copyright (c) 1998, 2013, 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
#include <stdlib.h>
27
#include <string.h>
28
#include <math.h>
29
30
#include "jni.h"
31
#include "jni_util.h"
32
#include <jlong.h>
33
34
#include "j2d_md.h"
35
36
#include "PathConsumer2D.h"
37
#include "SpanIterator.h"
38
39
#include "sun_java2d_pipe_ShapeSpanIterator.h"
40
#include "java_awt_geom_PathIterator.h"
41
42
/*
43
* This structure holds all of the information needed to trace and
44
* manage a single line segment of the shape's outline.
45
*/
46
typedef struct {
47
jint curx;
48
jint cury;
49
jint lasty;
50
jint error;
51
jint bumpx;
52
jint bumperr;
53
jbyte windDir;
54
jbyte pad0;
55
jbyte pad1;
56
jbyte pad2;
57
} segmentData;
58
59
/*
60
* This structure holds all of the information needed to trace out
61
* the entire span list of a single Shape object.
62
*/
63
typedef struct {
64
PathConsumerVec funcs; /* Native PathConsumer function vector */
65
66
char state; /* Path delivery sequence state */
67
char evenodd; /* non-zero if path has EvenOdd winding rule */
68
char first; /* non-zero if first path segment */
69
char adjust; /* normalize to nearest (0.25, 0.25) */
70
71
jint lox; /* clip bbox low X */
72
jint loy; /* clip bbox low Y */
73
jint hix; /* clip bbox high X */
74
jint hiy; /* clip bbox high Y */
75
76
jfloat curx; /* current path point X coordinate */
77
jfloat cury; /* current path point Y coordinate */
78
jfloat movx; /* last moveto X coordinate */
79
jfloat movy; /* last moveto Y coordinate */
80
81
jfloat adjx; /* last X coordinate adjustment */
82
jfloat adjy; /* last Y coordinate adjustment */
83
84
jfloat pathlox; /* lowest X coordinate in path */
85
jfloat pathloy; /* lowest Y coordinate in path */
86
jfloat pathhix; /* highest X coordinate in path */
87
jfloat pathhiy; /* highest Y coordinate in path */
88
89
segmentData *segments; /* pointer to array of path segments */
90
int numSegments; /* number of segments entries in array */
91
int segmentsSize; /* size of array of path segments */
92
93
int lowSegment; /* lower limit of segments in active range */
94
int curSegment; /* index of next active segment to return */
95
int hiSegment; /* upper limit of segments in active range */
96
97
segmentData **segmentTable; /* pointers to segments being stepped */
98
} pathData;
99
100
#define STATE_INIT 0
101
#define STATE_HAVE_CLIP 1
102
#define STATE_HAVE_RULE 2
103
#define STATE_PATH_DONE 3
104
#define STATE_SPAN_STARTED 4
105
106
static jboolean subdivideLine(pathData *pd, int level,
107
jfloat x0, jfloat y0,
108
jfloat x1, jfloat y1);
109
static jboolean subdivideQuad(pathData *pd, int level,
110
jfloat x0, jfloat y0,
111
jfloat x1, jfloat y1,
112
jfloat x2, jfloat y2);
113
static jboolean subdivideCubic(pathData *pd, int level,
114
jfloat x0, jfloat y0,
115
jfloat x1, jfloat y1,
116
jfloat x2, jfloat y2,
117
jfloat x3, jfloat y3);
118
static jboolean appendSegment(pathData *pd,
119
jfloat x0, jfloat y0,
120
jfloat x1, jfloat y1);
121
static jboolean initSegmentTable(pathData *pd);
122
123
static void *ShapeSIOpen(JNIEnv *env, jobject iterator);
124
static void ShapeSIClose(JNIEnv *env, void *private);
125
static void ShapeSIGetPathBox(JNIEnv *env, void *private, jint pathbox[]);
126
static void ShapeSIIntersectClipBox(JNIEnv *env, void *private,
127
jint lox, jint loy, jint hix, jint hiy);
128
static jboolean ShapeSINextSpan(void *state, jint spanbox[]);
129
static void ShapeSISkipDownTo(void *private, jint y);
130
131
static jfieldID pSpanDataID;
132
133
static SpanIteratorFuncs ShapeSIFuncs = {
134
ShapeSIOpen,
135
ShapeSIClose,
136
ShapeSIGetPathBox,
137
ShapeSIIntersectClipBox,
138
ShapeSINextSpan,
139
ShapeSISkipDownTo
140
};
141
142
static LineToFunc PCLineTo;
143
static MoveToFunc PCMoveTo;
144
static QuadToFunc PCQuadTo;
145
static CubicToFunc PCCubicTo;
146
static ClosePathFunc PCClosePath;
147
static PathDoneFunc PCPathDone;
148
149
#define PDBOXPOINT(pd, x, y) \
150
do { \
151
if (pd->first) { \
152
pd->pathlox = pd->pathhix = x; \
153
pd->pathloy = pd->pathhiy = y; \
154
pd->first = 0; \
155
} else { \
156
if (pd->pathlox > x) pd->pathlox = x; \
157
if (pd->pathloy > y) pd->pathloy = y; \
158
if (pd->pathhix < x) pd->pathhix = x; \
159
if (pd->pathhiy < y) pd->pathhiy = y; \
160
} \
161
} while (0)
162
163
/*
164
* _ADJUST is the internal macro used to adjust a new endpoint
165
* and then invoke the "additional" code from the callers below
166
* which will adjust the control points as needed to match.
167
*
168
* When the "additional" code is executed, newadj[xy] will
169
* contain the adjustment applied to the new endpoint and
170
* pd->adj[xy] will still contain the previous adjustment
171
* that was applied to the old endpoint.
172
*/
173
#define _ADJUST(pd, x, y, additional) \
174
do { \
175
if (pd->adjust) { \
176
jfloat newx = (jfloat) floor(x + 0.25f) + 0.25f; \
177
jfloat newy = (jfloat) floor(y + 0.25f) + 0.25f; \
178
jfloat newadjx = newx - x; \
179
jfloat newadjy = newy - y; \
180
x = newx; \
181
y = newy; \
182
additional; \
183
pd->adjx = newadjx; \
184
pd->adjy = newadjy; \
185
} \
186
} while (0)
187
188
/*
189
* Adjust a single endpoint with no control points.
190
* "additional" code is a null statement.
191
*/
192
#define ADJUST1(pd, x1, y1) \
193
_ADJUST(pd, x1, y1, \
194
do { \
195
} while (0))
196
197
/*
198
* Adjust a quadratic curve. The _ADJUST macro takes care
199
* of the new endpoint and the "additional" code adjusts
200
* the single quadratic control point by the averge of
201
* the prior and the new adjustment amounts.
202
*/
203
#define ADJUST2(pd, x1, y1, x2, y2) \
204
_ADJUST(pd, x2, y2, \
205
do { \
206
x1 += (pd->adjx + newadjy) / 2; \
207
y1 += (pd->adjy + newadjy) / 2; \
208
} while (0))
209
210
/*
211
* Adjust a cubic curve. The _ADJUST macro takes care
212
* of the new endpoint and the "additional" code adjusts
213
* the first of the two cubic control points by the same
214
* amount that the prior endpoint was adjusted and then
215
* adjusts the second of the two control points by the
216
* same amount as the new endpoint was adjusted. This
217
* keeps the tangent lines from xy0 to xy1 and xy3 to xy2
218
* parallel before and after the adjustment.
219
*/
220
#define ADJUST3(pd, x1, y1, x2, y2, x3, y3) \
221
_ADJUST(pd, x3, y3, \
222
do { \
223
x1 += pd->adjx; \
224
y1 += pd->adjy; \
225
x2 += newadjx; \
226
y2 += newadjy; \
227
} while (0))
228
229
#define HANDLEMOVETO(pd, x0, y0, OOMERR) \
230
do { \
231
HANDLECLOSE(pd, OOMERR); \
232
ADJUST1(pd, x0, y0); \
233
pd->movx = x0; \
234
pd->movy = y0; \
235
PDBOXPOINT(pd, x0, y0); \
236
pd->curx = x0; \
237
pd->cury = y0; \
238
} while (0)
239
240
#define HANDLELINETO(pd, x1, y1, OOMERR) \
241
do { \
242
ADJUST1(pd, x1, y1); \
243
if (!subdivideLine(pd, 0, \
244
pd->curx, pd->cury, \
245
x1, y1)) { \
246
OOMERR; \
247
break; \
248
} \
249
PDBOXPOINT(pd, x1, y1); \
250
pd->curx = x1; \
251
pd->cury = y1; \
252
} while (0)
253
254
#define HANDLEQUADTO(pd, x1, y1, x2, y2, OOMERR) \
255
do { \
256
ADJUST2(pd, x1, y1, x2, y2); \
257
if (!subdivideQuad(pd, 0, \
258
pd->curx, pd->cury, \
259
x1, y1, x2, y2)) { \
260
OOMERR; \
261
break; \
262
} \
263
PDBOXPOINT(pd, x1, y1); \
264
PDBOXPOINT(pd, x2, y2); \
265
pd->curx = x2; \
266
pd->cury = y2; \
267
} while (0)
268
269
#define HANDLECUBICTO(pd, x1, y1, x2, y2, x3, y3, OOMERR) \
270
do { \
271
ADJUST3(pd, x1, y1, x2, y2, x3, y3); \
272
if (!subdivideCubic(pd, 0, \
273
pd->curx, pd->cury, \
274
x1, y1, x2, y2, x3, y3)) { \
275
OOMERR; \
276
break; \
277
} \
278
PDBOXPOINT(pd, x1, y1); \
279
PDBOXPOINT(pd, x2, y2); \
280
PDBOXPOINT(pd, x3, y3); \
281
pd->curx = x3; \
282
pd->cury = y3; \
283
} while (0)
284
285
#define HANDLECLOSE(pd, OOMERR) \
286
do { \
287
if (pd->curx != pd->movx || pd->cury != pd->movy) { \
288
if (!subdivideLine(pd, 0, \
289
pd->curx, pd->cury, \
290
pd->movx, pd->movy)) { \
291
OOMERR; \
292
break; \
293
} \
294
pd->curx = pd->movx; \
295
pd->cury = pd->movy; \
296
} \
297
} while (0)
298
299
#define HANDLEENDPATH(pd, OOMERR) \
300
do { \
301
HANDLECLOSE(pd, OOMERR); \
302
pd->state = STATE_PATH_DONE; \
303
} while (0)
304
305
static pathData *
306
GetSpanData(JNIEnv *env, jobject sr, int minState, int maxState)
307
{
308
pathData *pd = (pathData *) JNU_GetLongFieldAsPtr(env, sr, pSpanDataID);
309
310
if (pd == NULL) {
311
JNU_ThrowNullPointerException(env, "private data");
312
} else if (pd->state < minState || pd->state > maxState) {
313
JNU_ThrowInternalError(env, "bad path delivery sequence");
314
pd = NULL;
315
}
316
317
return pd;
318
}
319
320
static pathData *
321
MakeSpanData(JNIEnv *env, jobject sr)
322
{
323
pathData *pd = (pathData *) JNU_GetLongFieldAsPtr(env, sr, pSpanDataID);
324
325
if (pd != NULL) {
326
JNU_ThrowInternalError(env, "private data already initialized");
327
return NULL;
328
}
329
330
pd = calloc(1, sizeof(pathData));
331
332
if (pd == NULL) {
333
JNU_ThrowOutOfMemoryError(env, "private data");
334
} else {
335
/* Initialize PathConsumer2D struct header */
336
pd->funcs.moveTo = PCMoveTo;
337
pd->funcs.lineTo = PCLineTo;
338
pd->funcs.quadTo = PCQuadTo;
339
pd->funcs.cubicTo = PCCubicTo;
340
pd->funcs.closePath = PCClosePath;
341
pd->funcs.pathDone = PCPathDone;
342
343
/* Initialize ShapeSpanIterator fields */
344
pd->first = 1;
345
346
(*env)->SetLongField(env, sr, pSpanDataID, ptr_to_jlong(pd));
347
}
348
349
return pd;
350
}
351
352
JNIEXPORT void JNICALL
353
Java_sun_java2d_pipe_ShapeSpanIterator_initIDs
354
(JNIEnv *env, jclass src)
355
{
356
pSpanDataID = (*env)->GetFieldID(env, src, "pData", "J");
357
}
358
359
/*
360
* Class: sun_java2d_pipe_ShapeSpanIterator
361
* Method: setNormalize
362
* Signature: (Z)V
363
*/
364
JNIEXPORT void JNICALL
365
Java_sun_java2d_pipe_ShapeSpanIterator_setNormalize
366
(JNIEnv *env, jobject sr, jboolean adjust)
367
{
368
pathData *pd;
369
370
pd = MakeSpanData(env, sr);
371
if (pd == NULL) {
372
return;
373
}
374
375
pd->adjust = adjust;
376
}
377
378
JNIEXPORT void JNICALL
379
Java_sun_java2d_pipe_ShapeSpanIterator_setOutputAreaXYXY
380
(JNIEnv *env, jobject sr, jint lox, jint loy, jint hix, jint hiy)
381
{
382
pathData *pd;
383
384
pd = GetSpanData(env, sr, STATE_INIT, STATE_INIT);
385
if (pd == NULL) {
386
return;
387
}
388
389
pd->lox = lox;
390
pd->loy = loy;
391
pd->hix = hix;
392
pd->hiy = hiy;
393
pd->state = STATE_HAVE_CLIP;
394
}
395
396
JNIEXPORT void JNICALL
397
Java_sun_java2d_pipe_ShapeSpanIterator_setRule
398
(JNIEnv *env, jobject sr, jint rule)
399
{
400
pathData *pd;
401
402
pd = GetSpanData(env, sr, STATE_HAVE_CLIP, STATE_HAVE_CLIP);
403
if (pd == NULL) {
404
return;
405
}
406
407
pd->evenodd = (rule == java_awt_geom_PathIterator_WIND_EVEN_ODD);
408
pd->state = STATE_HAVE_RULE;
409
}
410
411
JNIEXPORT void JNICALL
412
Java_sun_java2d_pipe_ShapeSpanIterator_addSegment
413
(JNIEnv *env, jobject sr, jint type, jfloatArray coordObj)
414
{
415
jfloat coords[6];
416
jfloat x1, y1, x2, y2, x3, y3;
417
jboolean oom = JNI_FALSE;
418
pathData *pd;
419
int numpts = 0;
420
421
pd = GetSpanData(env, sr, STATE_HAVE_RULE, STATE_HAVE_RULE);
422
if (pd == NULL) {
423
return;
424
}
425
426
(*env)->GetFloatArrayRegion(env, coordObj, 0, 6, coords);
427
if ((*env)->ExceptionCheck(env)) {
428
return;
429
}
430
431
switch (type) {
432
case java_awt_geom_PathIterator_SEG_MOVETO:
433
x1 = coords[0]; y1 = coords[1];
434
HANDLEMOVETO(pd, x1, y1, {oom = JNI_TRUE;});
435
break;
436
case java_awt_geom_PathIterator_SEG_LINETO:
437
x1 = coords[0]; y1 = coords[1];
438
HANDLELINETO(pd, x1, y1, {oom = JNI_TRUE;});
439
break;
440
case java_awt_geom_PathIterator_SEG_QUADTO:
441
x1 = coords[0]; y1 = coords[1];
442
x2 = coords[2]; y2 = coords[3];
443
HANDLEQUADTO(pd, x1, y1, x2, y2, {oom = JNI_TRUE;});
444
break;
445
case java_awt_geom_PathIterator_SEG_CUBICTO:
446
x1 = coords[0]; y1 = coords[1];
447
x2 = coords[2]; y2 = coords[3];
448
x3 = coords[4]; y3 = coords[5];
449
HANDLECUBICTO(pd, x1, y1, x2, y2, x3, y3, {oom = JNI_TRUE;});
450
break;
451
case java_awt_geom_PathIterator_SEG_CLOSE:
452
HANDLECLOSE(pd, {oom = JNI_TRUE;});
453
break;
454
default:
455
JNU_ThrowInternalError(env, "bad path segment type");
456
return;
457
}
458
459
if (oom) {
460
JNU_ThrowOutOfMemoryError(env, "path segment data");
461
return;
462
}
463
}
464
465
JNIEXPORT void JNICALL
466
Java_sun_java2d_pipe_ShapeSpanIterator_getPathBox
467
(JNIEnv *env, jobject sr, jintArray spanbox)
468
{
469
pathData *pd;
470
jint coords[4];
471
472
pd = GetSpanData(env, sr, STATE_PATH_DONE, STATE_PATH_DONE);
473
if (pd == NULL) {
474
return;
475
}
476
477
ShapeSIGetPathBox(env, pd, coords);
478
479
(*env)->SetIntArrayRegion(env, spanbox, 0, 4, coords);
480
}
481
482
JNIEXPORT void JNICALL
483
Java_sun_java2d_pipe_ShapeSpanIterator_intersectClipBox
484
(JNIEnv *env, jobject ri, jint clox, jint cloy, jint chix, jint chiy)
485
{
486
pathData *pd;
487
488
pd = GetSpanData(env, ri, STATE_PATH_DONE, STATE_PATH_DONE);
489
if (pd == NULL) {
490
return;
491
}
492
493
ShapeSIIntersectClipBox(env, pd, clox, cloy, chix, chiy);
494
}
495
496
JNIEXPORT jboolean JNICALL
497
Java_sun_java2d_pipe_ShapeSpanIterator_nextSpan
498
(JNIEnv *env, jobject sr, jintArray spanbox)
499
{
500
pathData *pd;
501
jboolean ret;
502
jint coords[4];
503
504
pd = GetSpanData(env, sr, STATE_PATH_DONE, STATE_SPAN_STARTED);
505
if (pd == NULL) {
506
return JNI_FALSE;
507
}
508
509
ret = ShapeSINextSpan(pd, coords);
510
if (ret) {
511
(*env)->SetIntArrayRegion(env, spanbox, 0, 4, coords);
512
}
513
514
return ret;
515
}
516
517
JNIEXPORT void JNICALL
518
Java_sun_java2d_pipe_ShapeSpanIterator_skipDownTo
519
(JNIEnv *env, jobject sr, jint y)
520
{
521
pathData *pd;
522
523
pd = GetSpanData(env, sr, STATE_PATH_DONE, STATE_SPAN_STARTED);
524
if (pd == NULL) {
525
return;
526
}
527
528
ShapeSISkipDownTo(pd, y);
529
}
530
531
JNIEXPORT jlong JNICALL
532
Java_sun_java2d_pipe_ShapeSpanIterator_getNativeIterator
533
(JNIEnv *env, jobject sr)
534
{
535
return ptr_to_jlong(&ShapeSIFuncs);
536
}
537
538
JNIEXPORT void JNICALL
539
Java_sun_java2d_pipe_ShapeSpanIterator_dispose
540
(JNIEnv *env, jobject sr)
541
{
542
pathData *pd = (pathData *) JNU_GetLongFieldAsPtr(env, sr, pSpanDataID);
543
544
if (pd == NULL) {
545
return;
546
}
547
548
if (pd->segments != NULL) {
549
free(pd->segments);
550
}
551
if (pd->segmentTable != NULL) {
552
free(pd->segmentTable);
553
}
554
free(pd);
555
556
(*env)->SetLongField(env, sr, pSpanDataID, jlong_zero);
557
}
558
559
#define OUT_XLO 1
560
#define OUT_XHI 2
561
#define OUT_YLO 4
562
#define OUT_YHI 8
563
564
#define CALCULATE_OUTCODES(pd, outc, x, y) \
565
do { \
566
if (y <= pd->loy) outc = OUT_YLO; \
567
else if (y >= pd->hiy) outc = OUT_YHI; \
568
else outc = 0; \
569
if (x <= pd->lox) outc |= OUT_XLO; \
570
else if (x >= pd->hix) outc |= OUT_XHI; \
571
} while (0)
572
573
JNIEXPORT void JNICALL
574
Java_sun_java2d_pipe_ShapeSpanIterator_appendPoly
575
(JNIEnv *env, jobject sr,
576
jintArray xArray, jintArray yArray, jint nPoints,
577
jint ixoff, jint iyoff)
578
{
579
pathData *pd;
580
int i;
581
jint *xPoints, *yPoints;
582
jboolean oom = JNI_FALSE;
583
jfloat xoff = (jfloat) ixoff, yoff = (jfloat) iyoff;
584
585
pd = GetSpanData(env, sr, STATE_HAVE_CLIP, STATE_HAVE_CLIP);
586
if (pd == NULL) {
587
return;
588
}
589
590
pd->evenodd = JNI_TRUE;
591
pd->state = STATE_HAVE_RULE;
592
if (pd->adjust) {
593
xoff += 0.25f;
594
yoff += 0.25f;
595
}
596
597
if (xArray == NULL || yArray == NULL) {
598
JNU_ThrowNullPointerException(env, "polygon data arrays");
599
return;
600
}
601
if ((*env)->GetArrayLength(env, xArray) < nPoints ||
602
(*env)->GetArrayLength(env, yArray) < nPoints)
603
{
604
JNU_ThrowArrayIndexOutOfBoundsException(env, "polygon data arrays");
605
return;
606
}
607
608
if (nPoints > 0) {
609
xPoints = (*env)->GetPrimitiveArrayCritical(env, xArray, NULL);
610
if (xPoints != NULL) {
611
yPoints = (*env)->GetPrimitiveArrayCritical(env, yArray, NULL);
612
if (yPoints != NULL) {
613
jint outc0;
614
jfloat x, y;
615
616
x = xPoints[0] + xoff;
617
y = yPoints[0] + yoff;
618
CALCULATE_OUTCODES(pd, outc0, x, y);
619
pd->movx = pd->curx = x;
620
pd->movy = pd->cury = y;
621
pd->pathlox = pd->pathhix = x;
622
pd->pathloy = pd->pathhiy = y;
623
pd->first = 0;
624
for (i = 1; !oom && i < nPoints; i++) {
625
jint outc1;
626
627
x = xPoints[i] + xoff;
628
y = yPoints[i] + yoff;
629
if (y == pd->cury) {
630
/* Horizontal segment - do not append */
631
if (x != pd->curx) {
632
/* Not empty segment - track change in X */
633
CALCULATE_OUTCODES(pd, outc0, x, y);
634
pd->curx = x;
635
if (pd->pathlox > x) pd->pathlox = x;
636
if (pd->pathhix < x) pd->pathhix = x;
637
}
638
continue;
639
}
640
CALCULATE_OUTCODES(pd, outc1, x, y);
641
outc0 &= outc1;
642
if (outc0 == 0) {
643
oom = !appendSegment(pd, pd->curx, pd->cury, x, y);
644
} else if (outc0 == OUT_XLO) {
645
oom = !appendSegment(pd, (jfloat) pd->lox, pd->cury,
646
(jfloat) pd->lox, y);
647
}
648
if (pd->pathlox > x) pd->pathlox = x;
649
if (pd->pathloy > y) pd->pathloy = y;
650
if (pd->pathhix < x) pd->pathhix = x;
651
if (pd->pathhiy < y) pd->pathhiy = y;
652
outc0 = outc1;
653
pd->curx = x;
654
pd->cury = y;
655
}
656
(*env)->ReleasePrimitiveArrayCritical(env, yArray,
657
yPoints, JNI_ABORT);
658
}
659
(*env)->ReleasePrimitiveArrayCritical(env, xArray,
660
xPoints, JNI_ABORT);
661
}
662
if (xPoints == NULL || yPoints == NULL) {
663
return;
664
}
665
}
666
if (!oom) {
667
HANDLEENDPATH(pd, {oom = JNI_TRUE;});
668
}
669
if (oom) {
670
JNU_ThrowOutOfMemoryError(env, "path segment data");
671
}
672
}
673
674
JNIEXPORT void JNICALL
675
Java_sun_java2d_pipe_ShapeSpanIterator_moveTo
676
(JNIEnv *env, jobject sr, jfloat x0, jfloat y0)
677
{
678
pathData *pd;
679
680
pd = GetSpanData(env, sr, STATE_HAVE_RULE, STATE_HAVE_RULE);
681
if (pd == NULL) {
682
return;
683
}
684
685
HANDLEMOVETO(pd, x0, y0,
686
{JNU_ThrowOutOfMemoryError(env, "path segment data");});
687
}
688
689
JNIEXPORT void JNICALL
690
Java_sun_java2d_pipe_ShapeSpanIterator_lineTo
691
(JNIEnv *env, jobject sr, jfloat x1, jfloat y1)
692
{
693
pathData *pd;
694
695
pd = GetSpanData(env, sr, STATE_HAVE_RULE, STATE_HAVE_RULE);
696
if (pd == NULL) {
697
return;
698
}
699
700
HANDLELINETO(pd, x1, y1,
701
{JNU_ThrowOutOfMemoryError(env, "path segment data");});
702
}
703
704
JNIEXPORT void JNICALL
705
Java_sun_java2d_pipe_ShapeSpanIterator_quadTo
706
(JNIEnv *env, jobject sr,
707
jfloat xm, jfloat ym, jfloat x1, jfloat y1)
708
{
709
pathData *pd;
710
711
pd = GetSpanData(env, sr, STATE_HAVE_RULE, STATE_HAVE_RULE);
712
if (pd == NULL) {
713
return;
714
}
715
716
HANDLEQUADTO(pd, xm, ym, x1, y1,
717
{JNU_ThrowOutOfMemoryError(env, "path segment data");});
718
}
719
720
JNIEXPORT void JNICALL
721
Java_sun_java2d_pipe_ShapeSpanIterator_curveTo
722
(JNIEnv *env, jobject sr,
723
jfloat xm, jfloat ym,
724
jfloat xn, jfloat yn,
725
jfloat x1, jfloat y1)
726
{
727
pathData *pd;
728
729
pd = GetSpanData(env, sr, STATE_HAVE_RULE, STATE_HAVE_RULE);
730
if (pd == NULL) {
731
return;
732
}
733
734
HANDLECUBICTO(pd, xm, ym, xn, yn, x1, y1,
735
{JNU_ThrowOutOfMemoryError(env, "path segment data");});
736
}
737
738
JNIEXPORT void JNICALL
739
Java_sun_java2d_pipe_ShapeSpanIterator_closePath
740
(JNIEnv *env, jobject sr)
741
{
742
pathData *pd;
743
744
pd = GetSpanData(env, sr, STATE_HAVE_RULE, STATE_HAVE_RULE);
745
if (pd == NULL) {
746
return;
747
}
748
749
HANDLECLOSE(pd, {JNU_ThrowOutOfMemoryError(env, "path segment data");});
750
}
751
752
JNIEXPORT void JNICALL
753
Java_sun_java2d_pipe_ShapeSpanIterator_pathDone
754
(JNIEnv *env, jobject sr)
755
{
756
pathData *pd;
757
758
pd = GetSpanData(env, sr, STATE_HAVE_RULE, STATE_HAVE_RULE);
759
if (pd == NULL) {
760
return;
761
}
762
763
HANDLEENDPATH(pd, {JNU_ThrowOutOfMemoryError(env, "path segment data");});
764
}
765
766
JNIEXPORT jlong JNICALL
767
Java_sun_java2d_pipe_ShapeSpanIterator_getNativeConsumer
768
(JNIEnv *env, jobject sr)
769
{
770
pathData *pd = GetSpanData(env, sr, STATE_HAVE_RULE, STATE_HAVE_RULE);
771
772
if (pd == NULL) {
773
return jlong_zero;
774
}
775
776
return ptr_to_jlong(&(pd->funcs));
777
}
778
779
static jboolean
780
PCMoveTo(PathConsumerVec *consumer,
781
jfloat x0, jfloat y0)
782
{
783
pathData *pd = (pathData *) consumer;
784
jboolean oom = JNI_FALSE;
785
786
HANDLEMOVETO(pd, x0, y0, {oom = JNI_TRUE;});
787
788
return oom;
789
}
790
791
static jboolean
792
PCLineTo(PathConsumerVec *consumer,
793
jfloat x1, jfloat y1)
794
{
795
pathData *pd = (pathData *) consumer;
796
jboolean oom = JNI_FALSE;
797
798
HANDLELINETO(pd, x1, y1, {oom = JNI_TRUE;});
799
800
return oom;
801
}
802
803
static jboolean
804
PCQuadTo(PathConsumerVec *consumer,
805
jfloat x1, jfloat y1,
806
jfloat x2, jfloat y2)
807
{
808
pathData *pd = (pathData *) consumer;
809
jboolean oom = JNI_FALSE;
810
811
HANDLEQUADTO(pd, x1, y1, x2, y2, {oom = JNI_TRUE;});
812
813
return oom;
814
}
815
816
static jboolean
817
PCCubicTo(PathConsumerVec *consumer,
818
jfloat x1, jfloat y1,
819
jfloat x2, jfloat y2,
820
jfloat x3, jfloat y3)
821
{
822
pathData *pd = (pathData *) consumer;
823
jboolean oom = JNI_FALSE;
824
825
HANDLECUBICTO(pd, x1, y1, x2, y2, x3, y3, {oom = JNI_TRUE;});
826
827
return oom;
828
}
829
830
static jboolean
831
PCClosePath(PathConsumerVec *consumer)
832
{
833
pathData *pd = (pathData *) consumer;
834
jboolean oom = JNI_FALSE;
835
836
HANDLECLOSE(pd, {oom = JNI_TRUE;});
837
838
return oom;
839
}
840
841
static jboolean
842
PCPathDone(PathConsumerVec *consumer)
843
{
844
pathData *pd = (pathData *) consumer;
845
jboolean oom = JNI_FALSE;
846
847
HANDLEENDPATH(pd, {oom = JNI_TRUE;});
848
849
return oom;
850
}
851
852
/*
853
* REMIND: CDECL needed for WIN32 "qsort"
854
*/
855
856
#ifdef _WIN32
857
#define CDECL __cdecl
858
#else
859
#define CDECL
860
#endif
861
862
#define SUBDIVIDE_MAX 10
863
#define MAX_FLAT_SQ (1.0 * 1.0)
864
#define GROW_SIZE 20
865
#define ERRSTEP_MAX (0x7fffffff)
866
#define FRACTTOJINT(f) ((jint) ((f) * (double) ERRSTEP_MAX))
867
868
#define minmax2(v1, v2, min, max) \
869
do { \
870
if (v1 < v2) { \
871
min = v1; \
872
max = v2; \
873
} else { \
874
min = v2; \
875
max = v1; \
876
} \
877
} while(0)
878
879
#define minmax3(v1, v2, v3, min, max) \
880
do { \
881
if (v1 < v2) { \
882
if (v1 < v3) { \
883
min = v1; \
884
max = (v2 < v3) ? v3 : v2; \
885
} else { \
886
max = v2; \
887
min = v3; \
888
} \
889
} else { \
890
if (v1 < v3) { \
891
max = v3; \
892
min = v2; \
893
} else { \
894
max = v1; \
895
min = (v2 < v3) ? v2 : v3; \
896
} \
897
} \
898
} while (0)
899
900
#define minmax4(v1, v2, v3, v4, min, max) \
901
do { \
902
if (v1 < v2) { \
903
if (v3 < v4) { \
904
max = (v2 < v4) ? v4 : v2; \
905
min = (v1 < v3) ? v1 : v3; \
906
} else { \
907
max = (v2 < v3) ? v3 : v2; \
908
min = (v1 < v4) ? v1 : v4; \
909
} \
910
} else { \
911
if (v3 < v4) { \
912
max = (v1 < v4) ? v4 : v1; \
913
min = (v2 < v3) ? v2 : v3; \
914
} else { \
915
max = (v1 < v3) ? v3 : v1; \
916
min = (v2 < v4) ? v2 : v4; \
917
} \
918
} \
919
} while(0)
920
921
static jfloat
922
ptSegDistSq(jfloat x0, jfloat y0,
923
jfloat x1, jfloat y1,
924
jfloat px, jfloat py)
925
{
926
jfloat dotprod, projlenSq;
927
928
/* Adjust vectors relative to x0,y0 */
929
/* x1,y1 becomes relative vector from x0,y0 to end of segment */
930
x1 -= x0;
931
y1 -= y0;
932
/* px,py becomes relative vector from x0,y0 to test point */
933
px -= x0;
934
py -= y0;
935
dotprod = px * x1 + py * y1;
936
if (dotprod <= 0.0) {
937
/* px,py is on the side of x0,y0 away from x1,y1 */
938
/* distance to segment is length of px,py vector */
939
/* "length of its (clipped) projection" is now 0.0 */
940
projlenSq = 0.0;
941
} else {
942
/* switch to backwards vectors relative to x1,y1 */
943
/* x1,y1 are already the negative of x0,y0=>x1,y1 */
944
/* to get px,py to be the negative of px,py=>x1,y1 */
945
/* the dot product of two negated vectors is the same */
946
/* as the dot product of the two normal vectors */
947
px = x1 - px;
948
py = y1 - py;
949
dotprod = px * x1 + py * y1;
950
if (dotprod <= 0.0) {
951
/* px,py is on the side of x1,y1 away from x0,y0 */
952
/* distance to segment is length of (backwards) px,py vector */
953
/* "length of its (clipped) projection" is now 0.0 */
954
projlenSq = 0.0;
955
} else {
956
/* px,py is between x0,y0 and x1,y1 */
957
/* dotprod is the length of the px,py vector */
958
/* projected on the x1,y1=>x0,y0 vector times the */
959
/* length of the x1,y1=>x0,y0 vector */
960
projlenSq = dotprod * dotprod / (x1 * x1 + y1 * y1);
961
}
962
}
963
/* Distance to line is now the length of the relative point */
964
/* vector minus the length of its projection onto the line */
965
/* (which is zero if the projection falls outside the range */
966
/* of the line segment). */
967
return px * px + py * py - projlenSq;
968
}
969
970
static jboolean
971
appendSegment(pathData *pd,
972
jfloat x0, jfloat y0,
973
jfloat x1, jfloat y1)
974
{
975
jbyte windDir;
976
jint istartx, istarty, ilasty;
977
jfloat dx, dy, slope;
978
jfloat ystartbump;
979
jint bumpx, bumperr, error;
980
segmentData *seg;
981
982
if (y0 > y1) {
983
jfloat t;
984
t = x0; x0 = x1; x1 = t;
985
t = y0; y0 = y1; y1 = t;
986
windDir = -1;
987
} else {
988
windDir = 1;
989
}
990
/* We want to iterate at every horizontal pixel center (HPC) crossing. */
991
/* First calculate next highest HPC we will cross at the start. */
992
istarty = (jint) ceil(y0 - 0.5f);
993
/* Then calculate next highest HPC we would cross at the end. */
994
ilasty = (jint) ceil(y1 - 0.5f);
995
/* Ignore if we start and end outside clip, or on the same scanline. */
996
if (istarty >= ilasty || istarty >= pd->hiy || ilasty <= pd->loy) {
997
return JNI_TRUE;
998
}
999
1000
/* We will need to insert this segment, check for room. */
1001
if (pd->numSegments >= pd->segmentsSize) {
1002
segmentData *newSegs;
1003
int newSize = pd->segmentsSize + GROW_SIZE;
1004
newSegs = (segmentData *) calloc(newSize, sizeof(segmentData));
1005
if (newSegs == NULL) {
1006
return JNI_FALSE;
1007
}
1008
if (pd->segments != NULL) {
1009
memcpy(newSegs, pd->segments,
1010
sizeof(segmentData) * pd->segmentsSize);
1011
free(pd->segments);
1012
}
1013
pd->segments = newSegs;
1014
pd->segmentsSize = newSize;
1015
}
1016
1017
dx = x1 - x0;
1018
dy = y1 - y0;
1019
slope = dx / dy;
1020
1021
/*
1022
* The Y coordinate of the first HPC was calculated as istarty. We
1023
* now need to calculate the corresponding X coordinate (both integer
1024
* version for span start coordinate and float version for sub-pixel
1025
* error calculation).
1026
*/
1027
/* First, how far does y bump to get to next HPC? */
1028
ystartbump = istarty + 0.5f - y0;
1029
/* Now, bump the float x coordinate to get X sample at that HPC. */
1030
x0 += ystartbump * dx / dy;
1031
/* Now calculate the integer coordinate that such a span starts at. */
1032
/* NOTE: Span inclusion is based on vertical pixel centers (VPC). */
1033
istartx = (jint) ceil(x0 - 0.5f);
1034
/* What is the lower bound of the per-scanline change in the X coord? */
1035
bumpx = (jint) floor(slope);
1036
/* What is the subpixel amount by which the bumpx is off? */
1037
bumperr = FRACTTOJINT(slope - floor(slope));
1038
/* Finally, find out how far the x coordinate can go before next VPC. */
1039
error = FRACTTOJINT(x0 - (istartx - 0.5f));
1040
1041
seg = &pd->segments[pd->numSegments++];
1042
seg->curx = istartx;
1043
seg->cury = istarty;
1044
seg->lasty = ilasty;
1045
seg->error = error;
1046
seg->bumpx = bumpx;
1047
seg->bumperr = bumperr;
1048
seg->windDir = windDir;
1049
return JNI_TRUE;
1050
}
1051
1052
/*
1053
* Lines don't really need to be subdivided, but this function performs
1054
* the same trivial rejections and reductions that the curve subdivision
1055
* functions perform before it hands the coordinates off to the appendSegment
1056
* function.
1057
*/
1058
static jboolean
1059
subdivideLine(pathData *pd, int level,
1060
jfloat x0, jfloat y0,
1061
jfloat x1, jfloat y1)
1062
{
1063
jfloat miny, maxy;
1064
jfloat minx, maxx;
1065
1066
minmax2(x0, x1, minx, maxx);
1067
minmax2(y0, y1, miny, maxy);
1068
1069
if (maxy <= pd->loy || miny >= pd->hiy || minx >= pd->hix) {
1070
return JNI_TRUE;
1071
}
1072
if (maxx <= pd->lox) {
1073
return appendSegment(pd, maxx, y0, maxx, y1);
1074
}
1075
1076
return appendSegment(pd, x0, y0, x1, y1);
1077
}
1078
1079
static jboolean
1080
subdivideQuad(pathData *pd, int level,
1081
jfloat x0, jfloat y0,
1082
jfloat x1, jfloat y1,
1083
jfloat x2, jfloat y2)
1084
{
1085
jfloat miny, maxy;
1086
jfloat minx, maxx;
1087
1088
minmax3(x0, x1, x2, minx, maxx);
1089
minmax3(y0, y1, y2, miny, maxy);
1090
1091
if (maxy <= pd->loy || miny >= pd->hiy || minx >= pd->hix) {
1092
return JNI_TRUE;
1093
}
1094
if (maxx <= pd->lox) {
1095
return appendSegment(pd, maxx, y0, maxx, y2);
1096
}
1097
1098
if (level < SUBDIVIDE_MAX) {
1099
/* Test if the curve is flat enough for insertion. */
1100
if (ptSegDistSq(x0, y0, x2, y2, x1, y1) > MAX_FLAT_SQ) {
1101
jfloat cx1, cx2;
1102
jfloat cy1, cy2;
1103
1104
cx1 = (x0 + x1) / 2.0f;
1105
cx2 = (x1 + x2) / 2.0f;
1106
x1 = (cx1 + cx2) / 2.0f;
1107
1108
cy1 = (y0 + y1) / 2.0f;
1109
cy2 = (y1 + y2) / 2.0f;
1110
y1 = (cy1 + cy2) / 2.0f;
1111
1112
level++;
1113
return (subdivideQuad(pd, level, x0, y0, cx1, cy1, x1, y1) &&
1114
subdivideQuad(pd, level, x1, y1, cx2, cy2, x2, y2));
1115
}
1116
}
1117
1118
return appendSegment(pd, x0, y0, x2, y2);
1119
}
1120
1121
static jboolean
1122
subdivideCubic(pathData *pd, int level,
1123
jfloat x0, jfloat y0,
1124
jfloat x1, jfloat y1,
1125
jfloat x2, jfloat y2,
1126
jfloat x3, jfloat y3)
1127
{
1128
jfloat miny, maxy;
1129
jfloat minx, maxx;
1130
1131
minmax4(x0, x1, x2, x3, minx, maxx);
1132
minmax4(y0, y1, y2, y3, miny, maxy);
1133
1134
if (maxy <= pd->loy || miny >= pd->hiy || minx >= pd->hix) {
1135
return JNI_TRUE;
1136
}
1137
if (maxx <= pd->lox) {
1138
return appendSegment(pd, maxx, y0, maxx, y3);
1139
}
1140
1141
if (level < SUBDIVIDE_MAX) {
1142
/* Test if the curve is flat enough for insertion. */
1143
if (ptSegDistSq(x0, y0, x3, y3, x1, y1) > MAX_FLAT_SQ ||
1144
ptSegDistSq(x0, y0, x3, y3, x2, y2) > MAX_FLAT_SQ)
1145
{
1146
jfloat ctrx, cx12, cx21;
1147
jfloat ctry, cy12, cy21;
1148
1149
ctrx = (x1 + x2) / 2.0f;
1150
x1 = (x0 + x1) / 2.0f;
1151
x2 = (x2 + x3) / 2.0f;
1152
cx12 = (x1 + ctrx) / 2.0f;
1153
cx21 = (ctrx + x2) / 2.0f;
1154
ctrx = (cx12 + cx21) / 2.0f;
1155
1156
ctry = (y1 + y2) / 2.0f;
1157
y1 = (y0 + y1) / 2.0f;
1158
y2 = (y2 + y3) / 2.0f;
1159
cy12 = (y1 + ctry) / 2.0f;
1160
cy21 = (ctry + y2) / 2.0f;
1161
ctry = (cy12 + cy21) / 2.0f;
1162
1163
level++;
1164
return (subdivideCubic(pd, level, x0, y0, x1, y1,
1165
cx12, cy12, ctrx, ctry) &&
1166
subdivideCubic(pd, level, ctrx, ctry, cx21, cy21,
1167
x2, y2, x3, y3));
1168
}
1169
}
1170
1171
return appendSegment(pd, x0, y0, x3, y3);
1172
}
1173
1174
static int CDECL
1175
sortSegmentsByLeadingY(const void *elem1, const void *elem2)
1176
{
1177
segmentData *seg1 = *(segmentData **)elem1;
1178
segmentData *seg2 = *(segmentData **)elem2;
1179
1180
if (seg1->cury < seg2->cury) {
1181
return -1;
1182
}
1183
if (seg1->cury > seg2->cury) {
1184
return 1;
1185
}
1186
if (seg1->curx < seg2->curx) {
1187
return -1;
1188
}
1189
if (seg1->curx > seg2->curx) {
1190
return 1;
1191
}
1192
if (seg1->lasty < seg2->lasty) {
1193
return -1;
1194
}
1195
if (seg1->lasty > seg2->lasty) {
1196
return 1;
1197
}
1198
return 0;
1199
}
1200
1201
static void *
1202
ShapeSIOpen(JNIEnv *env, jobject iterator)
1203
{
1204
return GetSpanData(env, iterator, STATE_PATH_DONE, STATE_PATH_DONE);
1205
}
1206
1207
static void
1208
ShapeSIClose(JNIEnv *env, void *private)
1209
{
1210
}
1211
1212
static void
1213
ShapeSIGetPathBox(JNIEnv *env, void *private, jint pathbox[])
1214
{
1215
pathData *pd = (pathData *)private;
1216
1217
pathbox[0] = (jint) floor(pd->pathlox);
1218
pathbox[1] = (jint) floor(pd->pathloy);
1219
pathbox[2] = (jint) ceil(pd->pathhix);
1220
pathbox[3] = (jint) ceil(pd->pathhiy);
1221
}
1222
1223
/* Adjust the clip box from the given bounds. Used to constrain
1224
the output to a device clip
1225
*/
1226
static void
1227
ShapeSIIntersectClipBox(JNIEnv *env, void *private,
1228
jint clox, jint cloy, jint chix, jint chiy)
1229
{
1230
pathData *pd = (pathData *)private;
1231
1232
if (clox > pd->lox) {
1233
pd->lox = clox;
1234
}
1235
if (cloy > pd->loy) {
1236
pd->loy = cloy;
1237
}
1238
if (chix < pd->hix) {
1239
pd->hix = chix;
1240
}
1241
if (chiy < pd->hiy) {
1242
pd->hiy = chiy;
1243
}
1244
}
1245
1246
static jboolean
1247
ShapeSINextSpan(void *state, jint spanbox[])
1248
{
1249
pathData *pd = (pathData *)state;
1250
int lo, cur, new, hi;
1251
int num = pd->numSegments;
1252
jint x0, x1, y0, err;
1253
jint loy;
1254
int ret = JNI_FALSE;
1255
segmentData **segmentTable;
1256
segmentData *seg;
1257
1258
if (pd->state != STATE_SPAN_STARTED) {
1259
if (!initSegmentTable(pd)) {
1260
/* REMIND: - throw exception? */
1261
pd->lowSegment = num;
1262
return JNI_FALSE;
1263
}
1264
}
1265
1266
lo = pd->lowSegment;
1267
cur = pd->curSegment;
1268
hi = pd->hiSegment;
1269
num = pd->numSegments;
1270
loy = pd->loy;
1271
segmentTable = pd->segmentTable;
1272
1273
while (lo < num) {
1274
if (cur < hi) {
1275
seg = segmentTable[cur];
1276
x0 = seg->curx;
1277
if (x0 >= pd->hix) {
1278
cur = hi;
1279
continue;
1280
}
1281
if (x0 < pd->lox) {
1282
x0 = pd->lox;
1283
}
1284
1285
if (pd->evenodd) {
1286
cur += 2;
1287
if (cur <= hi) {
1288
x1 = segmentTable[cur - 1]->curx;
1289
} else {
1290
x1 = pd->hix;
1291
}
1292
} else {
1293
int wind = seg->windDir;
1294
cur++;
1295
1296
while (JNI_TRUE) {
1297
if (cur >= hi) {
1298
x1 = pd->hix;
1299
break;
1300
}
1301
seg = segmentTable[cur++];
1302
wind += seg->windDir;
1303
if (wind == 0) {
1304
x1 = seg->curx;
1305
break;
1306
}
1307
}
1308
}
1309
1310
if (x1 > pd->hix) {
1311
x1 = pd->hix;
1312
}
1313
if (x1 <= x0) {
1314
continue;
1315
}
1316
spanbox[0] = x0;
1317
spanbox[1] = loy;
1318
spanbox[2] = x1;
1319
spanbox[3] = loy + 1;
1320
ret = JNI_TRUE;
1321
break;
1322
}
1323
1324
if (++loy >= pd->hiy) {
1325
lo = cur = hi = num;
1326
break;
1327
}
1328
1329
/* Go through active segments and toss which end "above" loy */
1330
cur = new = hi;
1331
while (--cur >= lo) {
1332
seg = segmentTable[cur];
1333
if (seg->lasty > loy) {
1334
segmentTable[--new] = seg;
1335
}
1336
}
1337
1338
lo = new;
1339
if (lo == hi && lo < num) {
1340
/* The current list of segments is empty so we need to
1341
* jump to the beginning of the next set of segments.
1342
* Since the segments are not clipped to the output
1343
* area we need to make sure we don't jump "backwards"
1344
*/
1345
seg = segmentTable[lo];
1346
if (loy < seg->cury) {
1347
loy = seg->cury;
1348
}
1349
}
1350
1351
/* Go through new segments and accept any which start "above" loy */
1352
while (hi < num && segmentTable[hi]->cury <= loy) {
1353
hi++;
1354
}
1355
1356
/* Update and sort the active segments by x0 */
1357
for (cur = lo; cur < hi; cur++) {
1358
seg = segmentTable[cur];
1359
1360
/* First update the x0, y0 of the segment */
1361
x0 = seg->curx;
1362
y0 = seg->cury;
1363
err = seg->error;
1364
if (++y0 == loy) {
1365
x0 += seg->bumpx;
1366
err += seg->bumperr;
1367
x0 -= (err >> 31);
1368
err &= ERRSTEP_MAX;
1369
} else {
1370
jlong steps = loy;
1371
steps -= y0 - 1;
1372
y0 = loy;
1373
x0 += (jint) (steps * seg->bumpx);
1374
steps = err + (steps * seg->bumperr);
1375
x0 += (jint) (steps >> 31);
1376
err = ((jint) steps) & ERRSTEP_MAX;
1377
}
1378
seg->curx = x0;
1379
seg->cury = y0;
1380
seg->error = err;
1381
1382
/* Then make sure the segment is sorted by x0 */
1383
for (new = cur; new > lo; new--) {
1384
segmentData *seg2 = segmentTable[new - 1];
1385
if (seg2->curx <= x0) {
1386
break;
1387
}
1388
segmentTable[new] = seg2;
1389
}
1390
segmentTable[new] = seg;
1391
}
1392
cur = lo;
1393
}
1394
1395
pd->lowSegment = lo;
1396
pd->hiSegment = hi;
1397
pd->curSegment = cur;
1398
pd->loy = loy;
1399
return ret;
1400
}
1401
1402
static void
1403
ShapeSISkipDownTo(void *private, jint y)
1404
{
1405
pathData *pd = (pathData *)private;
1406
1407
if (pd->state != STATE_SPAN_STARTED) {
1408
if (!initSegmentTable(pd)) {
1409
/* REMIND: - throw exception? */
1410
pd->lowSegment = pd->numSegments;
1411
return;
1412
}
1413
}
1414
1415
/* Make sure we are jumping forward */
1416
if (pd->loy < y) {
1417
/* Pretend like we just finished with the span line y-1... */
1418
pd->loy = y - 1;
1419
pd->curSegment = pd->hiSegment; /* no more segments on that line */
1420
}
1421
}
1422
1423
static jboolean
1424
initSegmentTable(pathData *pd)
1425
{
1426
int i, cur, num, loy;
1427
segmentData **segmentTable;
1428
segmentTable = malloc(pd->numSegments * sizeof(segmentData *));
1429
if (segmentTable == NULL) {
1430
return JNI_FALSE;
1431
}
1432
pd->state = STATE_SPAN_STARTED;
1433
for (i = 0; i < pd->numSegments; i++) {
1434
segmentTable[i] = &pd->segments[i];
1435
}
1436
qsort(segmentTable, pd->numSegments, sizeof(segmentData *),
1437
sortSegmentsByLeadingY);
1438
1439
pd->segmentTable = segmentTable;
1440
1441
/* Skip to the first segment that ends below the top clip edge */
1442
cur = 0;
1443
num = pd->numSegments;
1444
loy = pd->loy;
1445
while (cur < num && segmentTable[cur]->lasty <= loy) {
1446
cur++;
1447
}
1448
pd->lowSegment = pd->curSegment = pd->hiSegment = cur;
1449
1450
/* Prepare for next action to increment loy and prepare new segments */
1451
pd->loy--;
1452
1453
return JNI_TRUE;
1454
}
1455
1456