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