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 */
46typedef 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 */
63typedef 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
106static jboolean subdivideLine(pathData *pd, int level,
107                              jfloat x0, jfloat y0,
108                              jfloat x1, jfloat y1);
109static jboolean subdivideQuad(pathData *pd, int level,
110                              jfloat x0, jfloat y0,
111                              jfloat x1, jfloat y1,
112                              jfloat x2, jfloat y2);
113static 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);
118static jboolean appendSegment(pathData *pd,
119                              jfloat x0, jfloat y0,
120                              jfloat x1, jfloat y1);
121static jboolean initSegmentTable(pathData *pd);
122
123static void *ShapeSIOpen(JNIEnv *env, jobject iterator);
124static void ShapeSIClose(JNIEnv *env, void *private);
125static void ShapeSIGetPathBox(JNIEnv *env, void *private, jint pathbox[]);
126static void ShapeSIIntersectClipBox(JNIEnv *env, void *private,
127                                        jint lox, jint loy, jint hix, jint hiy);
128static jboolean ShapeSINextSpan(void *state, jint spanbox[]);
129static void ShapeSISkipDownTo(void *private, jint y);
130
131static jfieldID pSpanDataID;
132
133static SpanIteratorFuncs ShapeSIFuncs = {
134    ShapeSIOpen,
135    ShapeSIClose,
136    ShapeSIGetPathBox,
137    ShapeSIIntersectClipBox,
138    ShapeSINextSpan,
139    ShapeSISkipDownTo
140};
141
142static LineToFunc PCLineTo;
143static MoveToFunc PCMoveTo;
144static QuadToFunc PCQuadTo;
145static CubicToFunc PCCubicTo;
146static ClosePathFunc PCClosePath;
147static 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
305static pathData *
306GetSpanData(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
320static pathData *
321MakeSpanData(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
352JNIEXPORT void JNICALL
353Java_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 */
364JNIEXPORT void JNICALL
365Java_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
378JNIEXPORT void JNICALL
379Java_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
396JNIEXPORT void JNICALL
397Java_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
411JNIEXPORT void JNICALL
412Java_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
465JNIEXPORT void JNICALL
466Java_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
482JNIEXPORT void JNICALL
483Java_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
496JNIEXPORT jboolean JNICALL
497Java_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
517JNIEXPORT void JNICALL
518Java_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
531JNIEXPORT jlong JNICALL
532Java_sun_java2d_pipe_ShapeSpanIterator_getNativeIterator
533    (JNIEnv *env, jobject sr)
534{
535    return ptr_to_jlong(&ShapeSIFuncs);
536}
537
538JNIEXPORT void JNICALL
539Java_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
573JNIEXPORT void JNICALL
574Java_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
674JNIEXPORT void JNICALL
675Java_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
689JNIEXPORT void JNICALL
690Java_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
704JNIEXPORT void JNICALL
705Java_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
720JNIEXPORT void JNICALL
721Java_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
738JNIEXPORT void JNICALL
739Java_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
752JNIEXPORT void JNICALL
753Java_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
766JNIEXPORT jlong JNICALL
767Java_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
779static jboolean
780PCMoveTo(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
791static jboolean
792PCLineTo(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
803static jboolean
804PCQuadTo(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
816static jboolean
817PCCubicTo(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
830static jboolean
831PCClosePath(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
841static jboolean
842PCPathDone(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)       \
869do {                                    \
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)   \
880do {                                    \
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)       \
901do {                                            \
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
921static jfloat
922ptSegDistSq(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
970static jboolean
971appendSegment(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 */
1058static jboolean
1059subdivideLine(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
1079static jboolean
1080subdivideQuad(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
1121static jboolean
1122subdivideCubic(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
1174static int CDECL
1175sortSegmentsByLeadingY(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
1201static void *
1202ShapeSIOpen(JNIEnv *env, jobject iterator)
1203{
1204    return GetSpanData(env, iterator, STATE_PATH_DONE, STATE_PATH_DONE);
1205}
1206
1207static void
1208ShapeSIClose(JNIEnv *env, void *private)
1209{
1210}
1211
1212static void
1213ShapeSIGetPathBox(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*/
1226static void
1227ShapeSIIntersectClipBox(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
1246static jboolean
1247ShapeSINextSpan(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
1402static void
1403ShapeSISkipDownTo(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
1423static jboolean
1424initSegmentTable(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