1 /* 2 * Copyright (c) 2005, 2006, 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 <math.h> 27 #include <assert.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 #include "j2d_md.h" 32 #include "java_awt_geom_PathIterator.h" 33 34 #include "ProcessPath.h" 35 36 /* 37 * This framework performs filling and drawing of paths with sub-pixel 38 * precision. Also, it performs clipping by the specified view area. 39 * 40 * Drawing of the shapes is performed not pixel by pixel but segment by segment 41 * except several pixels near endpoints of the drawn line. This approach saves 42 * lot's of cpu cycles especially in case of large primitives (like ovals with 43 * sizes more than 50) and helps in achieving appropriate visual quality. Also, 44 * such method of drawing is useful for the accelerated pipelines where 45 * overhead of the per-pixel drawing could eliminate all benefits of the 46 * hardware acceleration. 47 * 48 * Filling of the path was taken from 49 * 50 * [Graphics Gems, edited by Andrew S Glassner. Academic Press 1990, 51 * ISBN 0-12-286165-5 (Concave polygon scan conversion), 87-91] 52 * 53 * and modified to work with sub-pixel precision and non-continuous paths. 54 * It's also speeded up by using hash table by rows of the filled objects. 55 * 56 * Here is high level scheme showing the rendering process: 57 * 58 * doDrawPath doFillPath 59 * \ / 60 * ProcessPath 61 * | 62 * CheckPathSegment 63 * | 64 * --------+------ 65 * | | 66 * | | 67 * | | 68 * _->ProcessCurve | 69 * / / | | 70 * \___/ | | 71 * | | 72 * DrawCurve ProcessLine 73 * \ / 74 * \ / 75 * \ / 76 * \ / 77 * ------+------ 78 * (filling) / \ (drawing) 79 * / \ 80 * Clipping and Clipping 81 * clamping \ 82 * | \ 83 * StoreFixedLine ProcessFixedLine 84 * | / \ 85 * | / \ 86 * FillPolygon PROCESS_LINE PROCESS_POINT 87 * 88 * 89 * 90 * CheckPathSegment - rough checking and skipping path's segments in case of 91 * invalid or huge coordinates of the control points to 92 * avoid calculation problems with NaNs and values close 93 * to the FLT_MAX 94 * 95 * ProcessCurve - (ProcessQuad, ProcessCubic) Splitting the curve into 96 * monotonic parts having appropriate size (calculated as 97 * boundary box of the control points) 98 * 99 * DrawMonotonicCurve - (DrawMonotonicQuad, DrawMonotonicCubic) flattening 100 * monotonic curve using adaptive forward differencing 101 * 102 * StoreFixedLine - storing segment from the flattened path to the 103 * FillData structure. Performing clipping and clamping if 104 * necessary. 105 * 106 * PROCESS_LINE, PROCESS_POINT - Helpers for calling appropriate primitive from 107 * DrawHandler structure 108 * 109 * ProcessFixedLine - Drawing line segment with subpixel precision. 110 * 111 */ 112 113 #define PROCESS_LINE(hnd, fX0, fY0, fX1, fY1, checkBounds, pixelInfo) \ 114 do { \ 115 jint X0 = (fX0) >> MDP_PREC; \ 116 jint Y0 = (fY0) >> MDP_PREC; \ 117 jint X1 = (fX1) >> MDP_PREC; \ 118 jint Y1 = (fY1) >> MDP_PREC; \ 119 jint res; \ 120 \ 121 /* Checking bounds and clipping if necessary */ \ 122 if (checkBounds) { \ 123 TESTANDCLIP(hnd->dhnd->yMin, hnd->dhnd->yMax, Y0, X0, Y1, X1, \ 124 jint, res); \ 125 if (res == CRES_INVISIBLE) break; \ 126 TESTANDCLIP(hnd->dhnd->yMin, hnd->dhnd->yMax, Y1, X1, Y0, X0, \ 127 jint, res); \ 128 if (res == CRES_INVISIBLE) break; \ 129 TESTANDCLIP(hnd->dhnd->xMin, hnd->dhnd->xMax, X0, Y0, X1, Y1, \ 130 jint, res); \ 131 if (res == CRES_INVISIBLE) break; \ 132 TESTANDCLIP(hnd->dhnd->xMin, hnd->dhnd->xMax, X1, Y1, X0, Y0, \ 133 jint, res); \ 134 if (res == CRES_INVISIBLE) break; \ 135 } \ 136 \ 137 /* Handling lines having just one pixel */ \ 138 if (((X0^X1) | (Y0^Y1)) == 0) { \ 139 if (pixelInfo[0] == 0) { \ 140 pixelInfo[0] = 1; \ 141 pixelInfo[1] = X0; \ 142 pixelInfo[2] = Y0; \ 143 pixelInfo[3] = X0; \ 144 pixelInfo[4] = Y0; \ 145 hnd->dhnd->pDrawPixel(hnd->dhnd, X0, Y0); \ 146 } else if ((X0 != pixelInfo[3] || Y0 != pixelInfo[4]) && \ 147 (X0 != pixelInfo[1] || Y0 != pixelInfo[2])) { \ 148 hnd->dhnd->pDrawPixel(hnd->dhnd, X0, Y0); \ 149 pixelInfo[3] = X0; \ 150 pixelInfo[4] = Y0; \ 151 } \ 152 break; \ 153 } \ 154 \ 155 if (pixelInfo[0] && \ 156 ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) || \ 157 (pixelInfo[3] == X0 && pixelInfo[4] == Y0))) \ 158 { \ 159 hnd->dhnd->pDrawPixel(hnd->dhnd, X0, Y0); \ 160 } \ 161 \ 162 hnd->dhnd->pDrawLine(hnd->dhnd, X0, Y0, X1, Y1); \ 163 \ 164 if (pixelInfo[0] == 0) { \ 165 pixelInfo[0] = 1; \ 166 pixelInfo[1] = X0; \ 167 pixelInfo[2] = Y0; \ 168 pixelInfo[3] = X0; \ 169 pixelInfo[4] = Y0; \ 170 } \ 171 \ 172 /* Switch on last pixel of the line if it was already \ 173 * drawn during rendering of the previous segments \ 174 */ \ 175 if ((pixelInfo[1] == X1 && pixelInfo[2] == Y1) || \ 176 (pixelInfo[3] == X1 && pixelInfo[4] == Y1)) \ 177 { \ 178 hnd->dhnd->pDrawPixel(hnd->dhnd, X1, Y1); \ 179 } \ 180 pixelInfo[3] = X1; \ 181 pixelInfo[4] = Y1; \ 182 } while(0) 183 184 #define PROCESS_POINT(hnd, fX, fY, checkBounds, pixelInfo) \ 185 do { \ 186 jint _X = (fX)>> MDP_PREC; \ 187 jint _Y = (fY)>> MDP_PREC; \ 188 if (checkBounds && \ 189 (hnd->dhnd->yMin > _Y || \ 190 hnd->dhnd->yMax <= _Y || \ 191 hnd->dhnd->xMin > _X || \ 192 hnd->dhnd->xMax <= _X)) break; \ 193 /* \ 194 * (_X,_Y) should be inside boundaries \ 195 * \ 196 * assert(hnd->dhnd->yMin <= _Y && \ 197 * hnd->dhnd->yMax > _Y && \ 198 * hnd->dhnd->xMin <= _X && \ 199 * hnd->dhnd->xMax > _X); \ 200 * \ 201 */ \ 202 if (pixelInfo[0] == 0) { \ 203 pixelInfo[0] = 1; \ 204 pixelInfo[1] = _X; \ 205 pixelInfo[2] = _Y; \ 206 pixelInfo[3] = _X; \ 207 pixelInfo[4] = _Y; \ 208 hnd->dhnd->pDrawPixel(hnd->dhnd, _X, _Y); \ 209 } else if ((_X != pixelInfo[3] || _Y != pixelInfo[4]) && \ 210 (_X != pixelInfo[1] || _Y != pixelInfo[2])) { \ 211 hnd->dhnd->pDrawPixel(hnd->dhnd, _X, _Y); \ 212 pixelInfo[3] = _X; \ 213 pixelInfo[4] = _Y; \ 214 } \ 215 } while(0) 216 217 218 /* 219 * Constants for the forward differencing 220 * of the cubic and quad curves 221 */ 222 223 /* Maximum size of the cubic curve (calculated as the size of the bounding box 224 * of the control points) which could be rendered without splitting 225 */ 226 #define MAX_CUB_SIZE 256 227 228 /* Maximum size of the quad curve (calculated as the size of the bounding box 229 * of the control points) which could be rendered without splitting 230 */ 231 #define MAX_QUAD_SIZE 1024 232 233 /* Default power of 2 steps used in the forward differencing. Here DF prefix 234 * stands for DeFault. Constants below are used as initial values for the 235 * adaptive forward differencing algorithm. 236 */ 237 #define DF_CUB_STEPS 3 238 #define DF_QUAD_STEPS 2 239 240 /* Shift of the current point of the curve for preparing to the midpoint 241 * rounding 242 */ 243 #define DF_CUB_SHIFT (FWD_PREC + DF_CUB_STEPS*3 - MDP_PREC) 244 #define DF_QUAD_SHIFT (FWD_PREC + DF_QUAD_STEPS*2 - MDP_PREC) 245 246 /* Default amount of steps of the forward differencing */ 247 #define DF_CUB_COUNT (1<<DF_CUB_STEPS) 248 #define DF_QUAD_COUNT (1<<DF_QUAD_STEPS) 249 250 /* Default boundary constants used to check the necessity of the restepping */ 251 #define DF_CUB_DEC_BND (1<<(DF_CUB_STEPS*3 + FWD_PREC + 2)) 252 #define DF_CUB_INC_BND (1<<(DF_CUB_STEPS*3 + FWD_PREC - 1)) 253 #define DF_QUAD_DEC_BND (1<<(DF_QUAD_STEPS*2 + FWD_PREC + 2)) 254 255 /* Multiplyers for the coefficients of the polynomial form of the cubic and 256 * quad curves representation 257 */ 258 #define CUB_A_SHIFT FWD_PREC 259 #define CUB_B_SHIFT (DF_CUB_STEPS + FWD_PREC + 1) 260 #define CUB_C_SHIFT (DF_CUB_STEPS*2 + FWD_PREC) 261 262 #define CUB_A_MDP_MULT (1<<CUB_A_SHIFT) 263 #define CUB_B_MDP_MULT (1<<CUB_B_SHIFT) 264 #define CUB_C_MDP_MULT (1<<CUB_C_SHIFT) 265 266 #define QUAD_A_SHIFT FWD_PREC 267 #define QUAD_B_SHIFT (DF_QUAD_STEPS + FWD_PREC) 268 269 #define QUAD_A_MDP_MULT (1<<QUAD_A_SHIFT) 270 #define QUAD_B_MDP_MULT (1<<QUAD_B_SHIFT) 271 272 #define CALC_MAX(MAX, X) ((MAX)=((X)>(MAX))?(X):(MAX)) 273 #define CALC_MIN(MIN, X) ((MIN)=((X)<(MIN))?(X):(MIN)) 274 #define MAX(MAX, X) (((X)>(MAX))?(X):(MAX)) 275 #define MIN(MIN, X) (((X)<(MIN))?(X):(MIN)) 276 #define ABS32(X) (((X)^((X)>>31))-((X)>>31)) 277 #define SIGN32(X) ((X) >> 31) | ((juint)(-(X)) >> 31) 278 279 /* Boundaries used for clipping large path segments (those are inside 280 * [UPPER/LOWER]_BND boundaries) 281 */ 282 #define UPPER_OUT_BND (1 << (30 - MDP_PREC)) 283 #define LOWER_OUT_BND (-UPPER_OUT_BND) 284 285 #define ADJUST(X, LBND, UBND) \ 286 do { \ 287 if ((X) < (LBND)) { \ 288 (X) = (LBND); \ 289 } else if ((X) > UBND) { \ 290 (X) = (UBND); \ 291 } \ 292 } while(0) 293 294 /* Following constants are used for providing open boundaries of the intervals 295 */ 296 #define EPSFX 1 297 #define EPSF (((jfloat)EPSFX)/MDP_MULT) 298 299 /* Calculation boundary. It is used for switching to the more slow but allowing 300 * larger input values method of calculation of the initial values of the scan 301 * converted line segments inside the FillPolygon. 302 */ 303 #define CALC_BND (1 << (30 - MDP_PREC)) 304 305 /* Clipping macros for drawing and filling algorithms */ 306 307 #define CLIP(a1, b1, a2, b2, t) \ 308 (b1 + ((jdouble)(t - a1)*(b2 - b1)) / (a2 - a1)) 309 310 enum { 311 CRES_MIN_CLIPPED, 312 CRES_MAX_CLIPPED, 313 CRES_NOT_CLIPPED, 314 CRES_INVISIBLE 315 }; 316 317 #define IS_CLIPPED(res) (res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED) 318 319 #define TESTANDCLIP(LINE_MIN, LINE_MAX, a1, b1, a2, b2, TYPE, res) \ 320 do { \ 321 jdouble t; \ 322 res = CRES_NOT_CLIPPED; \ 323 if (a1 < (LINE_MIN) || a1 > (LINE_MAX)) { \ 324 if (a1 < (LINE_MIN)) { \ 325 if (a2 < (LINE_MIN)) { \ 326 res = CRES_INVISIBLE; \ 327 break; \ 328 }; \ 329 res = CRES_MIN_CLIPPED; \ 330 t = (LINE_MIN); \ 331 } else { \ 332 if (a2 > (LINE_MAX)) { \ 333 res = CRES_INVISIBLE; \ 334 break; \ 335 }; \ 336 res = CRES_MAX_CLIPPED; \ 337 t = (LINE_MAX); \ 338 } \ 339 b1 = (TYPE)CLIP(a1, b1, a2, b2, t); \ 340 a1 = (TYPE)t; \ 341 } \ 342 } while (0) 343 344 /* Following macro is used for clipping and clumping filled shapes. 345 * An example of this process is shown on the picture below: 346 * ----+ ----+ 347 * |/ | |/ | 348 * + | + | 349 * /| | I | 350 * / | | I | 351 * | | | ===> I | 352 * \ | | I | 353 * \| | I | 354 * + | + | 355 * |\ | |\ | 356 * | ----+ | ----+ 357 * boundary boundary 358 * 359 * We can only perform clipping in case of right side of the output area 360 * because all segments passed out the right boundary don't influence on the 361 * result of scan conversion algorithm (it correctly handles half open 362 * contours). 363 * 364 */ 365 #define CLIPCLAMP(LINE_MIN, LINE_MAX, a1, b1, a2, b2, a3, b3, TYPE, res) \ 366 do { \ 367 a3 = a1; \ 368 b3 = b1; \ 369 TESTANDCLIP(LINE_MIN, LINE_MAX, a1, b1, a2, b2, TYPE, res); \ 370 if (res == CRES_MIN_CLIPPED) { \ 371 a3 = a1; \ 372 } else if (res == CRES_MAX_CLIPPED) { \ 373 a3 = a1; \ 374 res = CRES_MAX_CLIPPED; \ 375 } else if (res == CRES_INVISIBLE) { \ 376 if (a1 > LINE_MAX) { \ 377 res = CRES_INVISIBLE; \ 378 } else { \ 379 a1 = (TYPE)LINE_MIN; \ 380 a2 = (TYPE)LINE_MIN; \ 381 res = CRES_NOT_CLIPPED; \ 382 } \ 383 } \ 384 } while (0) 385 386 /* Following macro is used for solving quadratic equations: 387 * A*t^2 + B*t + C = 0 388 * in (0,1) range. That means we put to the RES the only roots which 389 * belongs to the (0,1) range. Note: 0 and 1 are not included. 390 * See solveQuadratic method in 391 * src/share/classes/java/awt/geom/QuadCurve2D.java 392 * for more info about calculations 393 */ 394 #define SOLVEQUADINRANGE(A,B,C,RES,RCNT) \ 395 do { \ 396 double param; \ 397 if ((A) != 0) { \ 398 /* Calculating roots of the following equation \ 399 * A*t^2 + B*t + C = 0 \ 400 */ \ 401 double d = (B)*(B) - 4*(A)*(C); \ 402 double q; \ 403 if (d < 0) { \ 404 break; \ 405 } \ 406 d = sqrt(d); \ 407 /* For accuracy, calculate one root using: \ 408 * (-B +/- d) / 2*A \ 409 * and the other using: \ 410 * 2*C / (-B +/- d) \ 411 * Choose the sign of the +/- so that B+D gets larger \ 412 * in magnitude \ 413 */ \ 414 if ((B) < 0) { \ 415 d = -d; \ 416 } \ 417 q = ((B) + d) / -2.0; \ 418 param = q/(A); \ 419 if (param < 1.0 && param > 0.0) { \ 420 (RES)[(RCNT)++] = param; \ 421 } \ 422 if (d == 0 || q == 0) { \ 423 break; \ 424 } \ 425 param = (C)/q; \ 426 if (param < 1.0 && param > 0.0) { \ 427 (RES)[(RCNT)++] = param; \ 428 } \ 429 } else { \ 430 /* Calculating root of the following equation \ 431 * B*t + C = 0 \ 432 */ \ 433 if ((B) == 0) { \ 434 break; \ 435 } \ 436 param = -(C)/(B); \ 437 if (param < 1.0 && param > 0.0) { \ 438 (RES)[(RCNT)++] = param; \ 439 } \ 440 } \ 441 } while(0) 442 443 /* Drawing line with subpixel endpoints 444 * 445 * (x1, y1), (x2, y2) - fixed point coordinates of the endpoints 446 * with MDP_PREC bits for the fractional part 447 * 448 * pixelInfo - structure which keeps drawing info for avoiding 449 * multiple drawing at the same position on the 450 * screen (required for the XOR mode of drawing) 451 * 452 * pixelInfo[0] - state of the drawing 453 * 0 - no pixel drawn between 454 * moveTo/close of the path 455 * 1 - there are drawn pixels 456 * 457 * pixelInfo[1,2] - first pixel of the path 458 * between moveTo/close of the 459 * path 460 * 461 * pixelInfo[3,4] - last drawn pixel between 462 * moveTo/close of the path 463 * 464 * checkBounds - flag showing necessity of checking the clip 465 * 466 */ 467 void ProcessFixedLine(ProcessHandler* hnd,jint x1,jint y1,jint x2,jint y2, 468 jint* pixelInfo,jboolean checkBounds, 469 jboolean endSubPath) 470 { 471 /* Checking if line is inside a (X,Y),(X+MDP_MULT,Y+MDP_MULT) box */ 472 jint c = ((x1 ^ x2) | (y1 ^ y2)); 473 jint rx1, ry1, rx2, ry2; 474 if ((c & MDP_W_MASK) == 0) { 475 /* Checking for the segments with integer coordinates having 476 * the same start and end points 477 */ 478 if (c == 0) { 479 PROCESS_POINT(hnd, x1 + MDP_HALF_MULT, y1 + MDP_HALF_MULT, 480 checkBounds, pixelInfo); 481 } 482 return; 483 } 484 485 if (x1 == x2 || y1 == y2) { 486 rx1 = x1 + MDP_HALF_MULT; 487 rx2 = x2 + MDP_HALF_MULT; 488 ry1 = y1 + MDP_HALF_MULT; 489 ry2 = y2 + MDP_HALF_MULT; 490 } else { 491 /* Neither dx nor dy can be zero because of the check above */ 492 jint dx = x2 - x1; 493 jint dy = y2 - y1; 494 495 /* Floor of x1, y1, x2, y2 */ 496 jint fx1 = x1 & MDP_W_MASK; 497 jint fy1 = y1 & MDP_W_MASK; 498 jint fx2 = x2 & MDP_W_MASK; 499 jint fy2 = y2 & MDP_W_MASK; 500 501 /* Processing first endpoint */ 502 if (fx1 == x1 || fy1 == y1) { 503 /* Adding MDP_HALF_MULT to the [xy]1 if f[xy]1 == [xy]1 will not 504 * affect the result 505 */ 506 rx1 = x1 + MDP_HALF_MULT; 507 ry1 = y1 + MDP_HALF_MULT; 508 } else { 509 /* Boundary at the direction from (x1,y1) to (x2,y2) */ 510 jint bx1 = (x1 < x2) ? fx1 + MDP_MULT : fx1; 511 jint by1 = (y1 < y2) ? fy1 + MDP_MULT : fy1; 512 513 /* intersection with column bx1 */ 514 jint cross = y1 + ((bx1 - x1)*dy)/dx; 515 if (cross >= fy1 && cross <= fy1 + MDP_MULT) { 516 rx1 = bx1; 517 ry1 = cross + MDP_HALF_MULT; 518 } else { 519 /* intersection with row by1 */ 520 cross = x1 + ((by1 - y1)*dx)/dy; 521 rx1 = cross + MDP_HALF_MULT; 522 ry1 = by1; 523 } 524 } 525 526 /* Processing second endpoint */ 527 if (fx2 == x2 || fy2 == y2) { 528 /* Adding MDP_HALF_MULT to the [xy]2 if f[xy]2 == [xy]2 will not 529 * affect the result 530 */ 531 rx2 = x2 + MDP_HALF_MULT; 532 ry2 = y2 + MDP_HALF_MULT; 533 } else { 534 /* Boundary at the direction from (x2,y2) to (x1,y1) */ 535 jint bx2 = (x1 > x2) ? fx2 + MDP_MULT : fx2; 536 jint by2 = (y1 > y2) ? fy2 + MDP_MULT : fy2; 537 538 /* intersection with column bx2 */ 539 jint cross = y2 + ((bx2 - x2)*dy)/dx; 540 if (cross >= fy2 && cross <= fy2 + MDP_MULT) { 541 rx2 = bx2; 542 ry2 = cross + MDP_HALF_MULT; 543 } else { 544 /* intersection with row by2 */ 545 cross = x2 + ((by2 - y2)*dx)/dy; 546 rx2 = cross + MDP_HALF_MULT; 547 ry2 = by2; 548 } 549 } 550 } 551 552 PROCESS_LINE(hnd, rx1, ry1, rx2, ry2, checkBounds, pixelInfo); 553 } 554 555 /* Performing drawing of the monotonic in X and Y quadratic curves with sizes 556 * less than MAX_QUAD_SIZE by using forward differencing method of calculation. 557 * See comments to the DrawMonotonicCubic. 558 */ 559 static void DrawMonotonicQuad(ProcessHandler* hnd, 560 jfloat *coords, 561 jboolean checkBounds, 562 jint* pixelInfo) 563 { 564 jint x0 = (jint)(coords[0]*MDP_MULT); 565 jint y0 = (jint)(coords[1]*MDP_MULT); 566 567 jint xe = (jint)(coords[4]*MDP_MULT); 568 jint ye = (jint)(coords[5]*MDP_MULT); 569 570 /* Extracting fractional part of coordinates of first control point */ 571 jint px = (x0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT; 572 jint py = (y0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT; 573 574 /* Setting default amount of steps */ 575 jint count = DF_QUAD_COUNT; 576 577 /* Setting default shift for preparing to the midpoint rounding */ 578 jint shift = DF_QUAD_SHIFT; 579 580 jint ax = (jint)((coords[0] - 2*coords[2] + 581 coords[4])*QUAD_A_MDP_MULT); 582 jint ay = (jint)((coords[1] - 2*coords[3] + 583 coords[5])*QUAD_A_MDP_MULT); 584 585 jint bx = (jint)((-2*coords[0] + 2*coords[2])*QUAD_B_MDP_MULT); 586 jint by = (jint)((-2*coords[1] + 2*coords[3])*QUAD_B_MDP_MULT); 587 588 jint ddpx = 2*ax; 589 jint ddpy = 2*ay; 590 591 jint dpx = ax + bx; 592 jint dpy = ay + by; 593 594 jint x1, y1; 595 596 jint x2 = x0; 597 jint y2 = y0; 598 599 jint maxDD = MAX(ABS32(ddpx),ABS32(ddpy)); 600 jint x0w = x0 & MDP_W_MASK; 601 jint y0w = y0 & MDP_W_MASK; 602 603 jint dx = xe - x0; 604 jint dy = ye - y0; 605 606 /* Perform decreasing step in 2 times if slope of the second forward 607 * difference changes too quickly (more than a pixel per step in X or Y 608 * direction). We can perform adjusting of the step size before the 609 * rendering loop because the curvature of the quad curve remains the same 610 * along all the curve 611 */ 612 while (maxDD > DF_QUAD_DEC_BND) { 613 dpx = (dpx<<1) - ax; 614 dpy = (dpy<<1) - ay; 615 count <<= 1; 616 maxDD >>= 2; 617 px <<=2; 618 py <<=2; 619 shift += 2; 620 } 621 622 while(count-- > 1) { 623 624 px += dpx; 625 py += dpy; 626 627 dpx += ddpx; 628 dpy += ddpy; 629 630 x1 = x2; 631 y1 = y2; 632 633 x2 = x0w + (px >> shift); 634 y2 = y0w + (py >> shift); 635 636 /* Checking that we are not running out of the endpoint and bounding 637 * violating coordinate. The check is pretty simple because the curve 638 * passed to the DrawMonotonicQuad already splitted into the monotonic 639 * in X and Y pieces 640 */ 641 642 /* Bounding x2 by xe */ 643 if (((xe-x2)^dx) < 0) { 644 x2 = xe; 645 } 646 647 /* Bounding y2 by ye */ 648 if (((ye-y2)^dy) < 0) { 649 y2 = ye; 650 } 651 652 hnd->pProcessFixedLine(hnd, x1, y1, x2, y2, pixelInfo, checkBounds, 653 JNI_FALSE); 654 } 655 656 /* We are performing one step less than necessary and use actual (xe,ye) 657 * curve's endpoint instead of calculated. This prevent us from accumulated 658 * errors at the last point. 659 */ 660 661 hnd->pProcessFixedLine(hnd, x2, y2, xe, ye, pixelInfo, checkBounds, 662 JNI_FALSE); 663 } 664 665 /* 666 * Checking size of the quad curves and split them if necessary. 667 * Calling DrawMonotonicQuad for the curves of the appropriate size. 668 * Note: coords array could be changed 669 */ 670 static void ProcessMonotonicQuad(ProcessHandler* hnd, 671 jfloat *coords, 672 jint* pixelInfo) { 673 674 jfloat coords1[6]; 675 jfloat xMin, xMax; 676 jfloat yMin, yMax; 677 678 xMin = xMax = coords[0]; 679 yMin = yMax = coords[1]; 680 681 CALC_MIN(xMin, coords[2]); 682 CALC_MAX(xMax, coords[2]); 683 CALC_MIN(yMin, coords[3]); 684 CALC_MAX(yMax, coords[3]); 685 CALC_MIN(xMin, coords[4]); 686 CALC_MAX(xMax, coords[4]); 687 CALC_MIN(yMin, coords[5]); 688 CALC_MAX(yMax, coords[5]); 689 690 691 if (hnd->clipMode == PH_MODE_DRAW_CLIP) { 692 693 /* In case of drawing we could just skip curves which are completely 694 * out of bounds 695 */ 696 if (hnd->dhnd->xMaxf < xMin || hnd->dhnd->xMinf > xMax || 697 hnd->dhnd->yMaxf < yMin || hnd->dhnd->yMinf > yMax) { 698 return; 699 } 700 } else { 701 702 /* In case of filling we could skip curves which are above, 703 * below and behind the right boundary of the visible area 704 */ 705 706 if (hnd->dhnd->yMaxf < yMin || hnd->dhnd->yMinf > yMax || 707 hnd->dhnd->xMaxf < xMin) 708 { 709 return; 710 } 711 712 /* We could clamp x coordinates to the corresponding boundary 713 * if the curve is completely behind the left one 714 */ 715 716 if (hnd->dhnd->xMinf > xMax) { 717 coords[0] = coords[2] = coords[4] = hnd->dhnd->xMinf; 718 } 719 } 720 721 if (xMax - xMin > MAX_QUAD_SIZE || yMax - yMin > MAX_QUAD_SIZE) { 722 coords1[4] = coords[4]; 723 coords1[5] = coords[5]; 724 coords1[2] = (coords[2] + coords[4])/2.0f; 725 coords1[3] = (coords[3] + coords[5])/2.0f; 726 coords[2] = (coords[0] + coords[2])/2.0f; 727 coords[3] = (coords[1] + coords[3])/2.0f; 728 coords[4] = coords1[0] = (coords[2] + coords1[2])/2.0f; 729 coords[5] = coords1[1] = (coords[3] + coords1[3])/2.0f; 730 731 ProcessMonotonicQuad(hnd, coords, pixelInfo); 732 733 ProcessMonotonicQuad(hnd, coords1, pixelInfo); 734 } else { 735 DrawMonotonicQuad(hnd, coords, 736 /* Set checkBounds parameter if curve intersects 737 * boundary of the visible area. We know that the 738 * curve is visible, so the check is pretty simple 739 */ 740 hnd->dhnd->xMinf >= xMin || hnd->dhnd->xMaxf <= xMax || 741 hnd->dhnd->yMinf >= yMin || hnd->dhnd->yMaxf <= yMax, 742 pixelInfo); 743 } 744 } 745 746 /* 747 * Bite the piece of the quadratic curve from start point till the point 748 * corresponding to the specified parameter then call ProcessQuad for the 749 * bitten part. 750 * Note: coords array will be changed 751 */ 752 static void ProcessFirstMonotonicPartOfQuad(ProcessHandler* hnd, jfloat* coords, 753 jint* pixelInfo, jfloat t) 754 { 755 jfloat coords1[6]; 756 757 coords1[0] = coords[0]; 758 coords1[1] = coords[1]; 759 coords1[2] = coords[0] + t*(coords[2] - coords[0]); 760 coords1[3] = coords[1] + t*(coords[3] - coords[1]); 761 coords[2] = coords[2] + t*(coords[4] - coords[2]); 762 coords[3] = coords[3] + t*(coords[5] - coords[3]); 763 coords[0] = coords1[4] = coords1[2] + t*(coords[2] - coords1[2]); 764 coords[1] = coords1[5] = coords1[3] + t*(coords[3] - coords1[3]); 765 766 ProcessMonotonicQuad(hnd, coords1, pixelInfo); 767 } 768 769 /* 770 * Split quadratic curve into monotonic in X and Y parts. Calling 771 * ProcessMonotonicQuad for each monotonic piece of the curve. 772 * Note: coords array could be changed 773 */ 774 static void ProcessQuad(ProcessHandler* hnd, jfloat* coords, jint* pixelInfo) { 775 776 /* Temporary array for holding parameters corresponding to the extreme in X 777 * and Y points. The values are inside the (0,1) range (0 and 1 excluded) 778 * and in ascending order. 779 */ 780 double params[2]; 781 782 jint cnt = 0; 783 double param; 784 785 /* Simple check for monotonicity in X before searching for the extreme 786 * points of the X(t) function. We first check if the curve is monotonic 787 * in X by seeing if all of the X coordinates are strongly ordered. 788 */ 789 if ((coords[0] > coords[2] || coords[2] > coords[4]) && 790 (coords[0] < coords[2] || coords[2] < coords[4])) 791 { 792 /* Searching for extreme points of the X(t) function by solving 793 * dX(t) 794 * ---- = 0 equation 795 * dt 796 */ 797 double ax = coords[0] - 2*coords[2] + coords[4]; 798 if (ax != 0) { 799 /* Calculating root of the following equation 800 * ax*t + bx = 0 801 */ 802 double bx = coords[0] - coords[2]; 803 804 param = bx/ax; 805 if (param < 1.0 && param > 0.0) { 806 params[cnt++] = param; 807 } 808 } 809 } 810 811 /* Simple check for monotonicity in Y before searching for the extreme 812 * points of the Y(t) function. We first check if the curve is monotonic 813 * in Y by seeing if all of the Y coordinates are strongly ordered. 814 */ 815 if ((coords[1] > coords[3] || coords[3] > coords[5]) && 816 (coords[1] < coords[3] || coords[3] < coords[5])) 817 { 818 /* Searching for extreme points of the Y(t) function by solving 819 * dY(t) 820 * ----- = 0 equation 821 * dt 822 */ 823 double ay = coords[1] - 2*coords[3] + coords[5]; 824 825 if (ay != 0) { 826 /* Calculating root of the following equation 827 * ay*t + by = 0 828 */ 829 double by = coords[1] - coords[3]; 830 831 param = by/ay; 832 if (param < 1.0 && param > 0.0) { 833 if (cnt > 0) { 834 /* Inserting parameter only if it differs from 835 * already stored 836 */ 837 if (params[0] > param) { 838 params[cnt++] = params[0]; 839 params[0] = param; 840 } else if (params[0] < param) { 841 params[cnt++] = param; 842 } 843 } else { 844 params[cnt++] = param; 845 } 846 } 847 } 848 } 849 850 /* Processing obtained monotonic parts */ 851 switch(cnt) { 852 case 0: 853 break; 854 case 1: 855 ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, 856 (jfloat)params[0]); 857 break; 858 case 2: 859 ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, 860 (jfloat)params[0]); 861 param = params[1] - params[0]; 862 if (param > 0) { 863 ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, 864 /* Scale parameter to match with rest of the curve */ 865 (jfloat)(param/(1.0 - params[0]))); 866 } 867 break; 868 } 869 870 ProcessMonotonicQuad(hnd,coords,pixelInfo); 871 } 872 873 /* 874 * Performing drawing of the monotonic in X and Y cubic curves with sizes less 875 * than MAX_CUB_SIZE by using forward differencing method of calculation. 876 * 877 * Here is some math used in the code below. 878 * 879 * If we express the parametric equation for the coordinates as 880 * simple polynomial: 881 * 882 * V(t) = a * t^3 + b * t^2 + c * t + d 883 * 884 * The equations for how we derive these polynomial coefficients 885 * from the Bezier control points can be found in the method comments 886 * for the CubicCurve.fillEqn Java method. 887 * 888 * From this polynomial, we can derive the forward differences to 889 * allow us to calculate V(t+K) from V(t) as follows: 890 * 891 * 1) V1(0) 892 * = V(K)-V(0) 893 * = aK^3 + bK^2 + cK + d - d 894 * = aK^3 + bK^2 + cK 895 * 896 * 2) V1(K) 897 * = V(2K)-V(K) 898 * = 8aK^3 + 4bK^2 + 2cK + d - aK^3 - bK^2 - cK - d 899 * = 7aK^3 + 3bK^2 + cK 900 * 901 * 3) V1(2K) 902 * = V(3K)-V(2K) 903 * = 27aK^3 + 9bK^2 + 3cK + d - 8aK^3 - 4bK^2 - 2cK - d 904 * = 19aK^3 + 5bK^2 + cK 905 * 906 * 4) V2(0) 907 * = V1(K) - V1(0) 908 * = 7aK^3 + 3bK^2 + cK - aK^3 - bK^2 - cK 909 * = 6aK^3 + 2bK^2 910 * 911 * 5) V2(K) 912 * = V1(2K) - V1(K) 913 * = 19aK^3 + 5bK^2 + cK - 7aK^3 - 3bK^2 - cK 914 * = 12aK^3 + 2bK^2 915 * 916 * 6) V3(0) 917 * = V2(K) - V2(0) 918 * = 12aK^3 + 2bK^2 - 6aK^3 - 2bK^2 919 * = 6aK^3 920 * 921 * Note that if we continue on to calculate V1(3K), V2(2K) and 922 * V3(K) we will see that V3(K) == V3(0) so we need at most 923 * 3 cascading forward differences to step through the cubic 924 * curve. 925 * 926 * Note, b coefficient calculating in the DrawCubic is actually twice the b 927 * coefficient seen above. It's been done for the better accuracy. 928 * 929 * In our case, initialy K is chosen as 1/(2^DF_CUB_STEPS) this value is taken 930 * with FWD_PREC bits precision. This means that we should do 2^DF_CUB_STEPS 931 * steps to pass through all the curve. 932 * 933 * On each step we examine how far we are stepping by examining our first(V1) 934 * and second (V2) order derivatives and verifying that they are met following 935 * conditions: 936 * 937 * abs(V2) <= DF_CUB_DEC_BND 938 * abs(V1) > DF_CUB_INC_BND 939 * 940 * So, ensures that we step through the curve more slowly when its curvature is 941 * high and faster when its curvature is lower. If the step size needs 942 * adjustment we adjust it so that we step either twice as fast, or twice as 943 * slow until our step size is within range. This modifies our stepping 944 * variables as follows: 945 * 946 * Decreasing step size 947 * (See Graphics Gems/by A.Glassner,(Tutorial on forward differencing),601-602) 948 * 949 * V3 = oV3/8 950 * V2 = oV2/4 - V3 951 * V1 = (oV1 - V2)/2 952 * 953 * Here V1-V3 stands for new values of the forward differencies and oV1 - oV3 954 * for the old ones 955 * 956 * Using the equations above it's easy to calculating stepping variables for 957 * the increasing step size: 958 * 959 * V1 = 2*oV1 + oV2 960 * V2 = 4*oV2 + 4*oV3 961 * V3 = 8*oV3 962 * 963 * And then for not to running out of 32 bit precision we are performing 3 bit 964 * shift of the forward differencing precision (keeping in shift variable) in 965 * left or right direction depending on what is happening (decreasing or 966 * increasing). So, all oV1 - oV3 variables should be thought as appropriately 967 * shifted in regard to the V1 - V3. 968 * 969 * Taking all of the above into account we will have following: 970 * 971 * Decreasing step size: 972 * 973 * shift = shift + 3 974 * V3 keeps the same 975 * V2 = 2*oV2 - V3 976 * V1 = 4*oV1 - V2/2 977 * 978 * Increasing step size: 979 * 980 * shift = shift - 3 981 * V1 = oV1/4 + oV2/8 982 * V2 = oV2/2 + oV3/2 983 * V3 keeps the same 984 * 985 */ 986 987 static void DrawMonotonicCubic(ProcessHandler* hnd, 988 jfloat *coords, 989 jboolean checkBounds, 990 jint* pixelInfo) 991 { 992 jint x0 = (jint)(coords[0]*MDP_MULT); 993 jint y0 = (jint)(coords[1]*MDP_MULT); 994 995 jint xe = (jint)(coords[6]*MDP_MULT); 996 jint ye = (jint)(coords[7]*MDP_MULT); 997 998 /* Extracting fractional part of coordinates of first control point */ 999 jint px = (x0 & (~MDP_W_MASK)) << DF_CUB_SHIFT; 1000 jint py = (y0 & (~MDP_W_MASK)) << DF_CUB_SHIFT; 1001 1002 /* Setting default boundary values for checking first and second forward 1003 * difference for the necessity of the restepping. See comments to the 1004 * boundary values in ProcessQuad for more info. 1005 */ 1006 jint incStepBnd1 = DF_CUB_INC_BND; 1007 jint incStepBnd2 = DF_CUB_INC_BND << 1; 1008 jint decStepBnd1 = DF_CUB_DEC_BND; 1009 jint decStepBnd2 = DF_CUB_DEC_BND << 1; 1010 1011 /* Setting default amount of steps */ 1012 jint count = DF_CUB_COUNT; 1013 1014 /* Setting default shift for preparing to the midpoint rounding */ 1015 jint shift = DF_CUB_SHIFT; 1016 1017 jint ax = (jint)((-coords[0] + 3*coords[2] - 3*coords[4] + 1018 coords[6])*CUB_A_MDP_MULT); 1019 jint ay = (jint)((-coords[1] + 3*coords[3] - 3*coords[5] + 1020 coords[7])*CUB_A_MDP_MULT); 1021 1022 jint bx = (jint)((3*coords[0] - 6*coords[2] + 1023 3*coords[4])*CUB_B_MDP_MULT); 1024 jint by = (jint)((3*coords[1] - 6*coords[3] + 1025 3*coords[5])*CUB_B_MDP_MULT); 1026 1027 jint cx = (jint)((-3*coords[0] + 3*coords[2])*(CUB_C_MDP_MULT)); 1028 jint cy = (jint)((-3*coords[1] + 3*coords[3])*(CUB_C_MDP_MULT)); 1029 1030 jint dddpx = 6*ax; 1031 jint dddpy = 6*ay; 1032 1033 jint ddpx = dddpx + bx; 1034 jint ddpy = dddpy + by; 1035 1036 jint dpx = ax + (bx>>1) + cx; 1037 jint dpy = ay + (by>>1) + cy; 1038 1039 jint x1, y1; 1040 1041 jint x2 = x0; 1042 jint y2 = y0; 1043 1044 /* Calculating whole part of the first point of the curve */ 1045 jint x0w = x0 & MDP_W_MASK; 1046 jint y0w = y0 & MDP_W_MASK; 1047 1048 jint dx = xe - x0; 1049 jint dy = ye - y0; 1050 1051 while (count > 0) { 1052 /* Perform decreasing step in 2 times if necessary */ 1053 while ( 1054 /* The code below is an optimized version of the checks: 1055 * abs(ddpx) > decStepBnd1 || 1056 * abs(ddpy) > decStepBnd1 1057 */ 1058 (juint)(ddpx + decStepBnd1) > (juint)decStepBnd2 || 1059 (juint)(ddpy + decStepBnd1) > (juint)decStepBnd2) 1060 { 1061 ddpx = (ddpx<<1) - dddpx; 1062 ddpy = (ddpy<<1) - dddpy; 1063 dpx = (dpx<<2) - (ddpx>>1); 1064 dpy = (dpy<<2) - (ddpy>>1); 1065 count <<=1; 1066 decStepBnd1 <<=3; 1067 decStepBnd2 <<=3; 1068 incStepBnd1 <<=3; 1069 incStepBnd2 <<=3; 1070 px <<=3; 1071 py <<=3; 1072 shift += 3; 1073 } 1074 1075 /* Perform increasing step in 2 times if necessary. 1076 * Note: we could do it only in even steps 1077 */ 1078 1079 while (((count & 1) ^ 1) && shift > DF_CUB_SHIFT && 1080 /* The code below is an optimized version of the check: 1081 * abs(dpx) <= incStepBnd1 && 1082 * abs(dpy) <= incStepBnd1 1083 */ 1084 (juint)(dpx + incStepBnd1) <= (juint)incStepBnd2 && 1085 (juint)(dpy + incStepBnd1) <= (juint)incStepBnd2) 1086 { 1087 dpx = (dpx>>2) + (ddpx>>3); 1088 dpy = (dpy>>2) + (ddpy>>3); 1089 ddpx = (ddpx + dddpx)>>1; 1090 ddpy = (ddpy + dddpy)>>1; 1091 count >>=1; 1092 decStepBnd1 >>=3; 1093 decStepBnd2 >>=3; 1094 incStepBnd1 >>=3; 1095 incStepBnd2 >>=3; 1096 px >>=3; 1097 py >>=3; 1098 shift -= 3; 1099 } 1100 1101 count--; 1102 1103 /* We are performing one step less than necessary and use actual 1104 * (xe,ye) endpoint of the curve instead of calculated. This prevent 1105 * us from accumulated errors at the last point. 1106 */ 1107 if (count) { 1108 1109 px += dpx; 1110 py += dpy; 1111 1112 dpx += ddpx; 1113 dpy += ddpy; 1114 ddpx += dddpx; 1115 ddpy += dddpy; 1116 1117 x1 = x2; 1118 y1 = y2; 1119 1120 x2 = x0w + (px >> shift); 1121 y2 = y0w + (py >> shift); 1122 1123 /* Checking that we are not running out of the endpoint and 1124 * bounding violating coordinate. The check is pretty simple 1125 * because the curve passed to the DrawMonotonicCubic already 1126 * splitted into the monotonic in X and Y pieces 1127 */ 1128 1129 /* Bounding x2 by xe */ 1130 if (((xe-x2)^dx) < 0) { 1131 x2 = xe; 1132 } 1133 1134 /* Bounding y2 by ye */ 1135 if (((ye-y2)^dy) < 0) { 1136 y2 = ye; 1137 } 1138 1139 hnd->pProcessFixedLine(hnd, x1, y1, x2, y2, pixelInfo, checkBounds, 1140 JNI_FALSE); 1141 } else { 1142 hnd->pProcessFixedLine(hnd, x2, y2, xe, ye, pixelInfo, checkBounds, 1143 JNI_FALSE); 1144 } 1145 } 1146 } 1147 1148 /* 1149 * Checking size of the cubic curves and split them if necessary. 1150 * Calling DrawMonotonicCubic for the curves of the appropriate size. 1151 * Note: coords array could be changed 1152 */ 1153 static void ProcessMonotonicCubic(ProcessHandler* hnd, 1154 jfloat *coords, 1155 jint* pixelInfo) { 1156 1157 jfloat coords1[8]; 1158 jfloat tx, ty; 1159 jfloat xMin, xMax; 1160 jfloat yMin, yMax; 1161 1162 xMin = xMax = coords[0]; 1163 yMin = yMax = coords[1]; 1164 1165 CALC_MIN(xMin, coords[2]); 1166 CALC_MAX(xMax, coords[2]); 1167 CALC_MIN(yMin, coords[3]); 1168 CALC_MAX(yMax, coords[3]); 1169 CALC_MIN(xMin, coords[4]); 1170 CALC_MAX(xMax, coords[4]); 1171 CALC_MIN(yMin, coords[5]); 1172 CALC_MAX(yMax, coords[5]); 1173 CALC_MIN(xMin, coords[6]); 1174 CALC_MAX(xMax, coords[6]); 1175 CALC_MIN(yMin, coords[7]); 1176 CALC_MAX(yMax, coords[7]); 1177 1178 if (hnd->clipMode == PH_MODE_DRAW_CLIP) { 1179 1180 /* In case of drawing we could just skip curves which are completely 1181 * out of bounds 1182 */ 1183 if (hnd->dhnd->xMaxf < xMin || hnd->dhnd->xMinf > xMax || 1184 hnd->dhnd->yMaxf < yMin || hnd->dhnd->yMinf > yMax) { 1185 return; 1186 } 1187 } else { 1188 1189 /* In case of filling we could skip curves which are above, 1190 * below and behind the right boundary of the visible area 1191 */ 1192 1193 if (hnd->dhnd->yMaxf < yMin || hnd->dhnd->yMinf > yMax || 1194 hnd->dhnd->xMaxf < xMin) 1195 { 1196 return; 1197 } 1198 1199 /* We could clamp x coordinates to the corresponding boundary 1200 * if the curve is completely behind the left one 1201 */ 1202 1203 if (hnd->dhnd->xMinf > xMax) { 1204 coords[0] = coords[2] = coords[4] = coords[6] = 1205 hnd->dhnd->xMinf; 1206 } 1207 } 1208 1209 if (xMax - xMin > MAX_CUB_SIZE || yMax - yMin > MAX_CUB_SIZE) { 1210 coords1[6] = coords[6]; 1211 coords1[7] = coords[7]; 1212 coords1[4] = (coords[4] + coords[6])/2.0f; 1213 coords1[5] = (coords[5] + coords[7])/2.0f; 1214 tx = (coords[2] + coords[4])/2.0f; 1215 ty = (coords[3] + coords[5])/2.0f; 1216 coords1[2] = (tx + coords1[4])/2.0f; 1217 coords1[3] = (ty + coords1[5])/2.0f; 1218 coords[2] = (coords[0] + coords[2])/2.0f; 1219 coords[3] = (coords[1] + coords[3])/2.0f; 1220 coords[4] = (coords[2] + tx)/2.0f; 1221 coords[5] = (coords[3] + ty)/2.0f; 1222 coords[6]=coords1[0]=(coords[4] + coords1[2])/2.0f; 1223 coords[7]=coords1[1]=(coords[5] + coords1[3])/2.0f; 1224 1225 ProcessMonotonicCubic(hnd, coords, pixelInfo); 1226 1227 ProcessMonotonicCubic(hnd, coords1, pixelInfo); 1228 1229 } else { 1230 DrawMonotonicCubic(hnd, coords, 1231 /* Set checkBounds parameter if curve intersects 1232 * boundary of the visible area. We know that the 1233 * curve is visible, so the check is pretty simple 1234 */ 1235 hnd->dhnd->xMinf > xMin || hnd->dhnd->xMaxf < xMax || 1236 hnd->dhnd->yMinf > yMin || hnd->dhnd->yMaxf < yMax, 1237 pixelInfo); 1238 } 1239 } 1240 1241 /* 1242 * Bite the piece of the cubic curve from start point till the point 1243 * corresponding to the specified parameter then call ProcessMonotonicCubic for 1244 * the bitten part. 1245 * Note: coords array will be changed 1246 */ 1247 static void ProcessFirstMonotonicPartOfCubic(ProcessHandler* hnd, 1248 jfloat* coords, jint* pixelInfo, 1249 jfloat t) 1250 { 1251 jfloat coords1[8]; 1252 jfloat tx, ty; 1253 1254 coords1[0] = coords[0]; 1255 coords1[1] = coords[1]; 1256 tx = coords[2] + t*(coords[4] - coords[2]); 1257 ty = coords[3] + t*(coords[5] - coords[3]); 1258 coords1[2] = coords[0] + t*(coords[2] - coords[0]); 1259 coords1[3] = coords[1] + t*(coords[3] - coords[1]); 1260 coords1[4] = coords1[2] + t*(tx - coords1[2]); 1261 coords1[5] = coords1[3] + t*(ty - coords1[3]); 1262 coords[4] = coords[4] + t*(coords[6] - coords[4]); 1263 coords[5] = coords[5] + t*(coords[7] - coords[5]); 1264 coords[2] = tx + t*(coords[4] - tx); 1265 coords[3] = ty + t*(coords[5] - ty); 1266 coords[0]=coords1[6]=coords1[4] + t*(coords[2] - coords1[4]); 1267 coords[1]=coords1[7]=coords1[5] + t*(coords[3] - coords1[5]); 1268 1269 ProcessMonotonicCubic(hnd, coords1, pixelInfo); 1270 } 1271 1272 /* 1273 * Split cubic curve into monotonic in X and Y parts. Calling ProcessCubic for 1274 * each monotonic piece of the curve. 1275 * 1276 * Note: coords array could be changed 1277 */ 1278 static void ProcessCubic(ProcessHandler* hnd, jfloat* coords, jint* pixelInfo) 1279 { 1280 /* Temporary array for holding parameters corresponding to the extreme in X 1281 * and Y points. The values are inside the (0,1) range (0 and 1 excluded) 1282 * and in ascending order. 1283 */ 1284 double params[4]; 1285 jint cnt = 0, i; 1286 1287 /* Simple check for monotonicity in X before searching for the extreme 1288 * points of the X(t) function. We first check if the curve is monotonic in 1289 * X by seeing if all of the X coordinates are strongly ordered. 1290 */ 1291 if ((coords[0] > coords[2] || coords[2] > coords[4] || 1292 coords[4] > coords[6]) && 1293 (coords[0] < coords[2] || coords[2] < coords[4] || 1294 coords[4] < coords[6])) 1295 { 1296 /* Searching for extreme points of the X(t) function by solving 1297 * dX(t) 1298 * ---- = 0 equation 1299 * dt 1300 */ 1301 double ax = -coords[0] + 3*coords[2] - 3*coords[4] + coords[6]; 1302 double bx = 2*(coords[0] - 2*coords[2] + coords[4]); 1303 double cx = -coords[0] + coords[2]; 1304 1305 SOLVEQUADINRANGE(ax,bx,cx,params,cnt); 1306 } 1307 1308 /* Simple check for monotonicity in Y before searching for the extreme 1309 * points of the Y(t) function. We first check if the curve is monotonic in 1310 * Y by seeing if all of the Y coordinates are strongly ordered. 1311 */ 1312 if ((coords[1] > coords[3] || coords[3] > coords[5] || 1313 coords[5] > coords[7]) && 1314 (coords[1] < coords[3] || coords[3] < coords[5] || 1315 coords[5] < coords[7])) 1316 { 1317 /* Searching for extreme points of the Y(t) function by solving 1318 * dY(t) 1319 * ----- = 0 equation 1320 * dt 1321 */ 1322 double ay = -coords[1] + 3*coords[3] - 3*coords[5] + coords[7]; 1323 double by = 2*(coords[1] - 2*coords[3] + coords[5]); 1324 double cy = -coords[1] + coords[3]; 1325 1326 SOLVEQUADINRANGE(ay,by,cy,params,cnt); 1327 } 1328 1329 if (cnt > 0) { 1330 /* Sorting parameter values corresponding to the extremum points of 1331 * the curve. We are using insertion sort because of tiny size of the 1332 * array. 1333 */ 1334 jint j; 1335 1336 for(i = 1; i < cnt; i++) { 1337 double value = params[i]; 1338 for (j = i - 1; j >= 0 && params[j] > value; j--) { 1339 params[j + 1] = params[j]; 1340 } 1341 params[j + 1] = value; 1342 } 1343 1344 /* Processing obtained monotonic parts */ 1345 ProcessFirstMonotonicPartOfCubic(hnd, coords, pixelInfo, 1346 (jfloat)params[0]); 1347 for (i = 1; i < cnt; i++) { 1348 double param = params[i] - params[i-1]; 1349 if (param > 0) { 1350 ProcessFirstMonotonicPartOfCubic(hnd, coords, pixelInfo, 1351 /* Scale parameter to match with rest of the curve */ 1352 (float)(param/(1.0 - params[i - 1]))); 1353 } 1354 } 1355 } 1356 1357 ProcessMonotonicCubic(hnd,coords,pixelInfo); 1358 } 1359 1360 static void ProcessLine(ProcessHandler* hnd, 1361 jfloat *coord1, jfloat *coord2, jint* pixelInfo) { 1362 1363 jfloat xMin, yMin, xMax, yMax; 1364 jint X1, Y1, X2, Y2, X3, Y3, res; 1365 jboolean clipped = JNI_FALSE; 1366 jfloat x1 = coord1[0]; 1367 jfloat y1 = coord1[1]; 1368 jfloat x2 = coord2[0]; 1369 jfloat y2 = coord2[1]; 1370 jfloat x3,y3; 1371 1372 jboolean lastClipped; 1373 1374 xMin = hnd->dhnd->xMinf; 1375 yMin = hnd->dhnd->yMinf; 1376 xMax = hnd->dhnd->xMaxf; 1377 yMax = hnd->dhnd->yMaxf; 1378 1379 TESTANDCLIP(yMin, yMax, y1, x1, y2, x2, jfloat, res); 1380 if (res == CRES_INVISIBLE) return; 1381 clipped = IS_CLIPPED(res); 1382 TESTANDCLIP(yMin, yMax, y2, x2, y1, x1, jfloat, res); 1383 if (res == CRES_INVISIBLE) return; 1384 lastClipped = IS_CLIPPED(res); 1385 clipped = clipped || lastClipped; 1386 1387 if (hnd->clipMode == PH_MODE_DRAW_CLIP) { 1388 TESTANDCLIP(xMin, xMax, 1389 x1, y1, x2, y2, jfloat, res); 1390 if (res == CRES_INVISIBLE) return; 1391 clipped = clipped || IS_CLIPPED(res); 1392 TESTANDCLIP(xMin, xMax, 1393 x2, y2, x1, y1, jfloat, res); 1394 if (res == CRES_INVISIBLE) return; 1395 lastClipped = lastClipped || IS_CLIPPED(res); 1396 clipped = clipped || lastClipped; 1397 X1 = (jint)(x1*MDP_MULT); 1398 Y1 = (jint)(y1*MDP_MULT); 1399 X2 = (jint)(x2*MDP_MULT); 1400 Y2 = (jint)(y2*MDP_MULT); 1401 1402 hnd->pProcessFixedLine(hnd, X1, Y1, X2, Y2, pixelInfo, 1403 clipped, /* enable boundary checking in case 1404 of clipping to avoid entering 1405 out of bounds which could 1406 happens during rounding 1407 */ 1408 lastClipped /* Notify pProcessFixedLine that 1409 this is the end of the 1410 subpath (because of exiting 1411 out of boundaries) 1412 */ 1413 ); 1414 } else { 1415 /* Clamping starting from first vertex of the the processed segment 1416 */ 1417 CLIPCLAMP(xMin, xMax, x1, y1, x2, y2, x3, y3, jfloat, res); 1418 X1 = (jint)(x1*MDP_MULT); 1419 Y1 = (jint)(y1*MDP_MULT); 1420 1421 /* Clamping only by left boundary */ 1422 if (res == CRES_MIN_CLIPPED) { 1423 X3 = (jint)(x3*MDP_MULT); 1424 Y3 = (jint)(y3*MDP_MULT); 1425 hnd->pProcessFixedLine(hnd, X3, Y3, X1, Y1, pixelInfo, 1426 JNI_FALSE, lastClipped); 1427 1428 } else if (res == CRES_INVISIBLE) { 1429 return; 1430 } 1431 1432 /* Clamping starting from last vertex of the the processed segment 1433 */ 1434 CLIPCLAMP(xMin, xMax, x2, y2, x1, y1, x3, y3, jfloat, res); 1435 1436 /* Checking if there was a clip by right boundary */ 1437 lastClipped = lastClipped || (res == CRES_MAX_CLIPPED); 1438 1439 X2 = (jint)(x2*MDP_MULT); 1440 Y2 = (jint)(y2*MDP_MULT); 1441 hnd->pProcessFixedLine(hnd, X1, Y1, X2, Y2, pixelInfo, 1442 JNI_FALSE, lastClipped); 1443 1444 /* Clamping only by left boundary */ 1445 if (res == CRES_MIN_CLIPPED) { 1446 X3 = (jint)(x3*MDP_MULT); 1447 Y3 = (jint)(y3*MDP_MULT); 1448 hnd->pProcessFixedLine(hnd, X2, Y2, X3, Y3, pixelInfo, 1449 JNI_FALSE, lastClipped); 1450 } 1451 } 1452 } 1453 1454 jboolean ProcessPath(ProcessHandler* hnd, 1455 jfloat transXf, jfloat transYf, 1456 jfloat* coords, jint maxCoords, 1457 jbyte* types, jint numTypes) 1458 { 1459 jfloat tCoords[8]; 1460 jfloat closeCoord[2]; 1461 jint pixelInfo[5]; 1462 jboolean skip = JNI_FALSE; 1463 jboolean subpathStarted = JNI_FALSE; 1464 jfloat lastX, lastY; 1465 int i, index = 0; 1466 1467 pixelInfo[0] = 0; 1468 1469 /* Adding support of the KEY_STROKE_CONTROL rendering hint. 1470 * Now we are supporting two modes: "pixels at centers" and 1471 * "pixels at corners". 1472 * First one is disabled by default but could be enabled by setting 1473 * VALUE_STROKE_PURE to the rendering hint. It means that pixel at the 1474 * screen (x,y) has (x + 0.5, y + 0.5) float coordinates. 1475 * 1476 * Second one is enabled by default and means straightforward mapping 1477 * (x,y) --> (x,y) 1478 * 1479 */ 1480 if (hnd->stroke == PH_STROKE_PURE) { 1481 closeCoord[0] = -0.5f; 1482 closeCoord[1] = -0.5f; 1483 transXf -= 0.5; 1484 transYf -= 0.5; 1485 } else { 1486 closeCoord[0] = 0.0f; 1487 closeCoord[1] = 0.0f; 1488 } 1489 1490 /* Adjusting boundaries to the capabilities of the ProcessPath code */ 1491 ADJUST(hnd->dhnd->xMin, LOWER_OUT_BND, UPPER_OUT_BND); 1492 ADJUST(hnd->dhnd->yMin, LOWER_OUT_BND, UPPER_OUT_BND); 1493 ADJUST(hnd->dhnd->xMax, LOWER_OUT_BND, UPPER_OUT_BND); 1494 ADJUST(hnd->dhnd->yMax, LOWER_OUT_BND, UPPER_OUT_BND); 1495 1496 1497 /* Setting up fractional clipping box 1498 * 1499 * We are using following float -> int mapping: 1500 * 1501 * xi = floor(xf + 0.5) 1502 * 1503 * So, fractional values that hit the [xmin, xmax) integer interval will be 1504 * situated inside the [xmin-0.5, xmax - 0.5) fractional interval. We are 1505 * using EPSF constant to provide that upper boundary is not included. 1506 */ 1507 hnd->dhnd->xMinf = hnd->dhnd->xMin - 0.5f; 1508 hnd->dhnd->yMinf = hnd->dhnd->yMin - 0.5f; 1509 hnd->dhnd->xMaxf = hnd->dhnd->xMax - 0.5f - EPSF; 1510 hnd->dhnd->yMaxf = hnd->dhnd->yMax - 0.5f - EPSF; 1511 1512 1513 for (i = 0; i < numTypes; i++) { 1514 switch (types[i]) { 1515 case java_awt_geom_PathIterator_SEG_MOVETO: 1516 if (index + 2 <= maxCoords) { 1517 /* Performing closing of the unclosed segments */ 1518 if (subpathStarted & !skip) { 1519 if (hnd->clipMode == PH_MODE_FILL_CLIP) { 1520 if (tCoords[0] != closeCoord[0] || 1521 tCoords[1] != closeCoord[1]) 1522 { 1523 ProcessLine(hnd, tCoords, closeCoord, 1524 pixelInfo); 1525 } 1526 } 1527 hnd->pProcessEndSubPath(hnd); 1528 } 1529 1530 tCoords[0] = coords[index++] + transXf; 1531 tCoords[1] = coords[index++] + transYf; 1532 1533 /* Checking SEG_MOVETO coordinates if they are out of the 1534 * [LOWER_BND, UPPER_BND] range. This check also handles 1535 * NaN and Infinity values. Skipping next path segment in 1536 * case of invalid data. 1537 */ 1538 1539 if (tCoords[0] < UPPER_BND && 1540 tCoords[0] > LOWER_BND && 1541 tCoords[1] < UPPER_BND && 1542 tCoords[1] > LOWER_BND) 1543 { 1544 subpathStarted = JNI_TRUE; 1545 skip = JNI_FALSE; 1546 closeCoord[0] = tCoords[0]; 1547 closeCoord[1] = tCoords[1]; 1548 } else { 1549 skip = JNI_TRUE; 1550 } 1551 } else { 1552 return JNI_FALSE; 1553 } 1554 break; 1555 case java_awt_geom_PathIterator_SEG_LINETO: 1556 if (index + 2 <= maxCoords) { 1557 lastX = tCoords[2] = coords[index++] + transXf; 1558 lastY = tCoords[3] = coords[index++] + transYf; 1559 1560 /* Checking SEG_LINETO coordinates if they are out of the 1561 * [LOWER_BND, UPPER_BND] range. This check also handles 1562 * NaN and Infinity values. Ignoring current path segment 1563 * in case of invalid data. If segment is skipped its 1564 * endpoint (if valid) is used to begin new subpath. 1565 */ 1566 1567 if (lastX < UPPER_BND && 1568 lastX > LOWER_BND && 1569 lastY < UPPER_BND && 1570 lastY > LOWER_BND) 1571 { 1572 if (skip) { 1573 tCoords[0] = closeCoord[0] = lastX; 1574 tCoords[1] = closeCoord[1] = lastY; 1575 subpathStarted = JNI_TRUE; 1576 skip = JNI_FALSE; 1577 } else { 1578 ProcessLine(hnd, tCoords, tCoords + 2, 1579 pixelInfo); 1580 tCoords[0] = lastX; 1581 tCoords[1] = lastY; 1582 } 1583 } 1584 } else { 1585 return JNI_FALSE; 1586 } 1587 break; 1588 case java_awt_geom_PathIterator_SEG_QUADTO: 1589 if (index + 4 <= maxCoords) { 1590 tCoords[2] = coords[index++] + transXf; 1591 tCoords[3] = coords[index++] + transYf; 1592 lastX = tCoords[4] = coords[index++] + transXf; 1593 lastY = tCoords[5] = coords[index++] + transYf; 1594 1595 /* Checking SEG_QUADTO coordinates if they are out of the 1596 * [LOWER_BND, UPPER_BND] range. This check also handles 1597 * NaN and Infinity values. Ignoring current path segment 1598 * in case of invalid endpoints's data. Equivalent to 1599 * the SEG_LINETO if endpoint coordinates are valid but 1600 * there are invalid data among other coordinates 1601 */ 1602 1603 if (lastX < UPPER_BND && 1604 lastX > LOWER_BND && 1605 lastY < UPPER_BND && 1606 lastY > LOWER_BND) 1607 { 1608 if (skip) { 1609 tCoords[0] = closeCoord[0] = lastX; 1610 tCoords[1] = closeCoord[1] = lastY; 1611 subpathStarted = JNI_TRUE; 1612 skip = JNI_FALSE; 1613 } else { 1614 if (tCoords[2] < UPPER_BND && 1615 tCoords[2] > LOWER_BND && 1616 tCoords[3] < UPPER_BND && 1617 tCoords[3] > LOWER_BND) 1618 { 1619 ProcessQuad(hnd, tCoords, pixelInfo); 1620 } else { 1621 ProcessLine(hnd, tCoords, 1622 tCoords + 4, pixelInfo); 1623 } 1624 tCoords[0] = lastX; 1625 tCoords[1] = lastY; 1626 } 1627 } 1628 } else { 1629 return JNI_FALSE; 1630 } 1631 break; 1632 case java_awt_geom_PathIterator_SEG_CUBICTO: 1633 if (index + 6 <= maxCoords) { 1634 tCoords[2] = coords[index++] + transXf; 1635 tCoords[3] = coords[index++] + transYf; 1636 tCoords[4] = coords[index++] + transXf; 1637 tCoords[5] = coords[index++] + transYf; 1638 lastX = tCoords[6] = coords[index++] + transXf; 1639 lastY = tCoords[7] = coords[index++] + transYf; 1640 1641 /* Checking SEG_CUBICTO coordinates if they are out of the 1642 * [LOWER_BND, UPPER_BND] range. This check also handles 1643 * NaN and Infinity values. Ignoring current path segment 1644 * in case of invalid endpoints's data. Equivalent to 1645 * the SEG_LINETO if endpoint coordinates are valid but 1646 * there are invalid data among other coordinates 1647 */ 1648 1649 if (lastX < UPPER_BND && 1650 lastX > LOWER_BND && 1651 lastY < UPPER_BND && 1652 lastY > LOWER_BND) 1653 { 1654 if (skip) { 1655 tCoords[0] = closeCoord[0] = tCoords[6]; 1656 tCoords[1] = closeCoord[1] = tCoords[7]; 1657 subpathStarted = JNI_TRUE; 1658 skip = JNI_FALSE; 1659 } else { 1660 if (tCoords[2] < UPPER_BND && 1661 tCoords[2] > LOWER_BND && 1662 tCoords[3] < UPPER_BND && 1663 tCoords[3] > LOWER_BND && 1664 tCoords[4] < UPPER_BND && 1665 tCoords[4] > LOWER_BND && 1666 tCoords[5] < UPPER_BND && 1667 tCoords[5] > LOWER_BND) 1668 { 1669 ProcessCubic(hnd, tCoords, pixelInfo); 1670 } else { 1671 ProcessLine(hnd, tCoords, tCoords + 6, 1672 pixelInfo); 1673 } 1674 tCoords[0] = lastX; 1675 tCoords[1] = lastY; 1676 } 1677 } 1678 } else { 1679 return JNI_FALSE; 1680 } 1681 break; 1682 case java_awt_geom_PathIterator_SEG_CLOSE: 1683 if (subpathStarted && !skip) { 1684 skip = JNI_FALSE; 1685 if (tCoords[0] != closeCoord[0] || 1686 tCoords[1] != closeCoord[1]) 1687 { 1688 ProcessLine(hnd, tCoords, closeCoord, pixelInfo); 1689 /* Storing last path's point for using in 1690 * following segments without initial moveTo 1691 */ 1692 tCoords[0] = closeCoord[0]; 1693 tCoords[1] = closeCoord[1]; 1694 } 1695 1696 hnd->pProcessEndSubPath(hnd); 1697 } 1698 1699 break; 1700 } 1701 } 1702 1703 /* Performing closing of the unclosed segments */ 1704 if (subpathStarted & !skip) { 1705 if (hnd->clipMode == PH_MODE_FILL_CLIP) { 1706 if (tCoords[0] != closeCoord[0] || 1707 tCoords[1] != closeCoord[1]) 1708 { 1709 ProcessLine(hnd, tCoords, closeCoord, 1710 pixelInfo); 1711 } 1712 } 1713 hnd->pProcessEndSubPath(hnd); 1714 } 1715 1716 return JNI_TRUE; 1717 } 1718 1719 /* TODO Add checking of the result of the malloc/realloc functions to handle 1720 * out of memory error and don't leak earlier allocated data 1721 */ 1722 1723 1724 #define ALLOC(ptr, type, n) \ 1725 ptr = (type *)malloc((n)*sizeof(type)) 1726 #define REALLOC(ptr, type, n) \ 1727 ptr = (type *)realloc(ptr, (n)*sizeof(type)) 1728 1729 1730 struct _Edge; 1731 1732 typedef struct _Point { 1733 jint x; 1734 jint y; 1735 jboolean lastPoint; 1736 struct _Point* prev; 1737 struct _Point* next; 1738 struct _Point* nextByY; 1739 jboolean endSL; 1740 struct _Edge* edge; 1741 } Point; 1742 1743 1744 typedef struct _Edge { 1745 jint x; 1746 jint dx; 1747 Point* p; 1748 jint dir; 1749 struct _Edge* prev; 1750 struct _Edge* next; 1751 } Edge; 1752 1753 /* Size of the default buffer in the FillData structure. This buffer is 1754 * replaced with heap allocated in case of large paths. 1755 */ 1756 #define DF_MAX_POINT 256 1757 1758 /* Following structure accumulates points of the non-continuous flattened 1759 * path during iteration through the origin path's segments . The end 1760 * of the each subpath is marked as lastPoint flag set at the last point 1761 */ 1762 1763 typedef struct { 1764 Point *plgPnts; 1765 Point dfPlgPnts[DF_MAX_POINT]; 1766 jint plgSize; 1767 jint plgMax; 1768 jint plgYMin; 1769 jint plgYMax; 1770 } FillData; 1771 1772 #define FD_INIT(PTR) \ 1773 do { \ 1774 (PTR)->plgPnts = (PTR)->dfPlgPnts; \ 1775 (PTR)->plgSize = 0; \ 1776 (PTR)->plgMax = DF_MAX_POINT; \ 1777 } while(0) 1778 1779 #define FD_ADD_POINT(PTR, X, Y, LASTPT) \ 1780 do { \ 1781 Point* _pnts = (PTR)->plgPnts; \ 1782 jint _size = (PTR)->plgSize; \ 1783 if (_size >= (PTR)->plgMax) { \ 1784 jint newMax = (PTR)->plgMax*2; \ 1785 if ((PTR)->plgPnts == (PTR)->dfPlgPnts) { \ 1786 (PTR)->plgPnts = (Point*)malloc(newMax*sizeof(Point)); \ 1787 memcpy((PTR)->plgPnts, _pnts, _size*sizeof(Point)); \ 1788 } else { \ 1789 (PTR)->plgPnts = (Point*)realloc( \ 1790 _pnts, newMax*sizeof(Point)); \ 1791 } \ 1792 _pnts = (PTR)->plgPnts; \ 1793 (PTR)->plgMax = newMax; \ 1794 } \ 1795 _pnts += _size; \ 1796 _pnts->x = X; \ 1797 _pnts->y = Y; \ 1798 _pnts->lastPoint = LASTPT; \ 1799 if (_size) { \ 1800 if ((PTR)->plgYMin > Y) (PTR)->plgYMin = Y; \ 1801 if ((PTR)->plgYMax < Y) (PTR)->plgYMax = Y; \ 1802 } else { \ 1803 (PTR)->plgYMin = Y; \ 1804 (PTR)->plgYMax = Y; \ 1805 } \ 1806 (PTR)->plgSize = _size + 1; \ 1807 } while(0) 1808 1809 1810 #define FD_FREE_POINTS(PTR) \ 1811 do { \ 1812 if ((PTR)->plgPnts != (PTR)->dfPlgPnts) { \ 1813 free((PTR)->plgPnts); \ 1814 } \ 1815 } while(0) 1816 1817 #define FD_IS_EMPTY(PTR) (!((PTR)->plgSize)) 1818 1819 #define FD_IS_ENDED(PTR) ((PTR)->plgPnts[(PTR)->plgSize - 1].lastPoint) 1820 1821 #define FD_SET_ENDED(PTR) \ 1822 do { \ 1823 (PTR)->plgPnts[(PTR)->plgSize - 1].lastPoint = JNI_TRUE; \ 1824 } while(0) 1825 1826 #define PFD(HND) ((FillData*)(HND)->pData) 1827 1828 /* Bubble sorting in the ascending order of the linked list. This 1829 * implementation stops processing the list if there were no changes during the 1830 * previous pass. 1831 * 1832 * LIST - ptr to the ptr to the first element of the list 1833 * ETYPE - type of the element in the list 1834 * NEXT - accessor to the next field in the list element 1835 * GET_LKEY - accessor to the key of the list element 1836 */ 1837 #define LBUBBLE_SORT(LIST, ETYPE, NEXT, GET_LKEY) \ 1838 do { \ 1839 ETYPE *p, *q, *r, *s = NULL, *temp ; \ 1840 jint wasSwap = 1; \ 1841 /* r precedes p and s points to the node up to which comparisons \ 1842 * are to be made */ \ 1843 while ( s != NEXT(*LIST) && wasSwap) { \ 1844 r = p = *LIST; \ 1845 q = NEXT(p); \ 1846 wasSwap = 0; \ 1847 while ( p != s ) { \ 1848 if (GET_LKEY(p) >= GET_LKEY(q)) { \ 1849 wasSwap = 1; \ 1850 if ( p == *LIST ) { \ 1851 temp = NEXT(q); \ 1852 NEXT(q) = p ; \ 1853 NEXT(p) = temp ; \ 1854 *LIST = q ; \ 1855 r = q ; \ 1856 } else { \ 1857 temp = NEXT(q); \ 1858 NEXT(q) = p ; \ 1859 NEXT(p) = temp ; \ 1860 NEXT(r) = q ; \ 1861 r = q ; \ 1862 } \ 1863 } else { \ 1864 r = p ; \ 1865 p = NEXT(p); \ 1866 } \ 1867 q = NEXT(p); \ 1868 if ( q == s ) s = p ; \ 1869 } \ 1870 } \ 1871 } while(0); 1872 1873 /* Accessors for the Edge structure to work with LBUBBLE_SORT */ 1874 #define GET_ACTIVE_KEY(a) (a->x) 1875 #define GET_ACTIVE_NEXT(a) ((a)->next) 1876 1877 /* TODO: Implement stack/heap allocation technique for active edges 1878 */ 1879 #define DELETE_ACTIVE(head,pnt) \ 1880 do { \ 1881 Edge *prevp = pnt->prev; \ 1882 Edge *nextp = pnt->next; \ 1883 if (prevp) { \ 1884 prevp->next = nextp; \ 1885 } else { \ 1886 head = nextp; \ 1887 } \ 1888 if (nextp) { \ 1889 nextp->prev = prevp; \ 1890 } \ 1891 } while(0); 1892 1893 #define INSERT_ACTIVE(head,pnt,cy) \ 1894 do { \ 1895 Point *np = pnt->next; \ 1896 Edge *ne = active + nact; \ 1897 if (pnt->y == np->y) { \ 1898 /* Skipping horizontal segments */ \ 1899 break; \ 1900 } else { \ 1901 jint dX = np->x - pnt->x; \ 1902 jint dY = np->y - pnt->y; \ 1903 jint dy; \ 1904 if (pnt->y < np->y) { \ 1905 ne->dir = -1; \ 1906 ne->p = pnt; \ 1907 ne->x = pnt->x; \ 1908 dy = cy - pnt->y; \ 1909 } else { /* pnt->y > np->y */ \ 1910 ne->dir = 1; \ 1911 ne->p = np; \ 1912 ne->x = np->x; \ 1913 dy = cy - np->y; \ 1914 } \ 1915 \ 1916 /* We need to worry only about dX because dY is in */\ 1917 /* denominator and abs(dy) < MDP_MULT (cy is a first */\ 1918 /* scanline of the scan converted segment and we subtract */\ 1919 /* y coordinate of the nearest segment's end from it to */\ 1920 /* obtain dy) */\ 1921 if (ABS32(dX) > CALC_BND) { \ 1922 ne->dx = (jint)((((jdouble)dX)*MDP_MULT)/dY); \ 1923 ne->x += (jint)((((jdouble)dX)*dy)/dY); \ 1924 } else { \ 1925 ne->dx = ((dX)<<MDP_PREC)/dY; \ 1926 ne->x += (dX*dy)/dY; \ 1927 } \ 1928 } \ 1929 ne->next = head; \ 1930 ne->prev = NULL; \ 1931 if (head) { \ 1932 head->prev = ne; \ 1933 } \ 1934 head = active + nact; \ 1935 pnt->edge = head; \ 1936 nact++; \ 1937 } while(0); 1938 1939 void FillPolygon(ProcessHandler* hnd, 1940 jint fillRule) { 1941 jint k, y, xl, xr; 1942 jint drawing; 1943 Edge* activeList, *active; 1944 Edge* curEdge, *prevEdge; 1945 jint nact; 1946 jint n; 1947 Point* pt, *curpt, *ept; 1948 Point** yHash; 1949 Point** curHash; 1950 jint rightBnd = hnd->dhnd->xMax - 1; 1951 FillData* pfd = (FillData*)(hnd->pData); 1952 jint yMin = pfd->plgYMin; 1953 jint yMax = pfd->plgYMax; 1954 jint hashSize = ((yMax - yMin)>>MDP_PREC) + 4; 1955 1956 /* Because of support of the KEY_STROKE_CONTROL hint we are performing 1957 * shift of the coordinates at the higher level 1958 */ 1959 jint hashOffset = ((yMin - 1) & MDP_W_MASK); 1960 1961 // TODO creating lists using fake first element to avoid special casing of 1962 // the first element in the list (which otherwise should be performed in each 1963 // list operation) 1964 1965 /* Winding counter */ 1966 jint counter; 1967 1968 /* Calculating mask to be applied to the winding counter */ 1969 jint counterMask = 1970 (fillRule == java_awt_geom_PathIterator_WIND_NON_ZERO)? -1:1; 1971 pt = pfd->plgPnts; 1972 n = pfd->plgSize; 1973 1974 if (n <=1) return; 1975 1976 ALLOC(yHash, Point*, hashSize); 1977 for (k = 0; k < hashSize; k++) { 1978 yHash[k] = NULL; 1979 } 1980 1981 ALLOC(active, Edge, n); 1982 1983 /* Creating double linked list (prev, next links) describing path order and 1984 * hash table with points which fall between scanlines. nextByY link is 1985 * used for the points which are between same scanlines. Scanlines are 1986 * passed through the centers of the pixels. 1987 */ 1988 curpt = pt; 1989 curpt->prev = NULL; 1990 ept = pt + n - 1; 1991 for (curpt = pt; curpt != ept; curpt++) { 1992 Point* nextpt = curpt + 1; 1993 curHash = yHash + ((curpt->y - hashOffset - 1) >> MDP_PREC); 1994 curpt->nextByY = *curHash; 1995 *curHash = curpt; 1996 curpt->next = nextpt; 1997 nextpt->prev = curpt; 1998 curpt->edge = NULL; 1999 } 2000 2001 curHash = yHash + ((ept->y - hashOffset - 1) >> MDP_PREC); 2002 ept->nextByY = *curHash; 2003 *curHash = ept; 2004 ept->next = NULL; 2005 ept->edge = NULL; 2006 nact = 0; 2007 2008 activeList = NULL; 2009 for (y=hashOffset + MDP_MULT,k = 0; 2010 y<=yMax && k < hashSize; y += MDP_MULT, k++) 2011 { 2012 for(pt = yHash[k];pt; pt=pt->nextByY) { 2013 /* pt->y should be inside hashed interval 2014 * assert(y-MDP_MULT <= pt->y && pt->y < y); 2015 */ 2016 if (pt->prev && !pt->prev->lastPoint) { 2017 if (pt->prev->edge && pt->prev->y <= y) { 2018 DELETE_ACTIVE(activeList, pt->prev->edge); 2019 pt->prev->edge = NULL; 2020 } else if (pt->prev->y > y) { 2021 INSERT_ACTIVE(activeList, pt->prev, y); 2022 } 2023 } 2024 2025 if (!pt->lastPoint && pt->next) { 2026 if (pt->edge && pt->next->y <= y) { 2027 DELETE_ACTIVE(activeList, pt->edge); 2028 pt->edge = NULL; 2029 } else if (pt->next->y > y) { 2030 INSERT_ACTIVE(activeList, pt, y); 2031 } 2032 } 2033 } 2034 2035 if (!activeList) continue; 2036 2037 /* We could not use O(N) Radix sort here because in most cases list of 2038 * edges almost sorted. So, bubble sort (O(N^2))is working much 2039 * better. Note, in case of array of edges Shell sort is more 2040 * efficient. 2041 */ 2042 LBUBBLE_SORT((&activeList), Edge, GET_ACTIVE_NEXT, GET_ACTIVE_KEY); 2043 2044 /* Correction of the back links in the double linked edge list */ 2045 curEdge=activeList; 2046 prevEdge = NULL; 2047 while (curEdge) { 2048 curEdge->prev = prevEdge; 2049 prevEdge = curEdge; 2050 curEdge = curEdge->next; 2051 } 2052 2053 xl = xr = hnd->dhnd->xMin; 2054 curEdge = activeList; 2055 counter = 0; 2056 drawing = 0; 2057 for(;curEdge; curEdge = curEdge->next) { 2058 counter += curEdge->dir; 2059 if ((counter & counterMask) && !drawing) { 2060 xl = (curEdge->x + MDP_MULT - 1)>>MDP_PREC; 2061 drawing = 1; 2062 } 2063 2064 if (!(counter & counterMask) && drawing) { 2065 xr = (curEdge->x - 1)>>MDP_PREC; 2066 if (xl <= xr) { 2067 hnd->dhnd->pDrawScanline(hnd->dhnd, xl, xr, y >> MDP_PREC); 2068 } 2069 drawing = 0; 2070 } 2071 2072 curEdge->x += curEdge->dx; 2073 } 2074 2075 /* Performing drawing till the right boundary (for correct rendering 2076 * shapes clipped at the right side) 2077 */ 2078 if (drawing && xl <= rightBnd) { 2079 hnd->dhnd->pDrawScanline(hnd->dhnd, xl, rightBnd, y >> MDP_PREC); 2080 } 2081 } 2082 free(active); 2083 free(yHash); 2084 } 2085 2086 2087 2088 void StoreFixedLine(ProcessHandler* hnd,jint x1,jint y1,jint x2,jint y2, 2089 jint* pixelInfo,jboolean checkBounds, 2090 jboolean endSubPath) { 2091 FillData* pfd; 2092 jint outXMin, outXMax, outYMin, outYMax; 2093 jint x3, y3, res; 2094 2095 /* There is no need to round line coordinates to the forward differencing 2096 * precision anymore. Such a rounding was used for preventing the curve go 2097 * out the endpoint (this sometimes does not help). The problem was fixed 2098 * in the forward differencing loops. 2099 */ 2100 2101 if (checkBounds) { 2102 jboolean lastClipped = JNI_FALSE; 2103 2104 /* This function is used only for filling shapes, so there is no 2105 * check for the type of clipping 2106 */ 2107 outXMin = (jint)(hnd->dhnd->xMinf * MDP_MULT); 2108 outXMax = (jint)(hnd->dhnd->xMaxf * MDP_MULT); 2109 outYMin = (jint)(hnd->dhnd->yMinf * MDP_MULT); 2110 outYMax = (jint)(hnd->dhnd->yMaxf * MDP_MULT); 2111 2112 TESTANDCLIP(outYMin, outYMax, y1, x1, y2, x2, jint, res); 2113 if (res == CRES_INVISIBLE) return; 2114 TESTANDCLIP(outYMin, outYMax, y2, x2, y1, x1, jint, res); 2115 if (res == CRES_INVISIBLE) return; 2116 lastClipped = IS_CLIPPED(res); 2117 2118 /* Clamping starting from first vertex of the the processed segment */ 2119 CLIPCLAMP(outXMin, outXMax, x1, y1, x2, y2, x3, y3, jint, res); 2120 2121 /* Clamping only by left boundary */ 2122 if (res == CRES_MIN_CLIPPED) { 2123 StoreFixedLine(hnd, x3, y3, x1, y1, pixelInfo, 2124 JNI_FALSE, lastClipped); 2125 2126 } else if (res == CRES_INVISIBLE) { 2127 return; 2128 } 2129 2130 /* Clamping starting from last vertex of the the processed segment */ 2131 CLIPCLAMP(outXMin, outXMax, x2, y2, x1, y1, x3, y3, jint, res); 2132 2133 /* Checking if there was a clip by right boundary */ 2134 lastClipped = lastClipped || (res == CRES_MAX_CLIPPED); 2135 2136 StoreFixedLine(hnd, x1, y1, x2, y2, pixelInfo, 2137 JNI_FALSE, lastClipped); 2138 2139 /* Clamping only by left boundary */ 2140 if (res == CRES_MIN_CLIPPED) { 2141 StoreFixedLine(hnd, x2, y2, x3, y3, pixelInfo, 2142 JNI_FALSE, lastClipped); 2143 } 2144 2145 return; 2146 } 2147 pfd = (FillData*)(hnd->pData); 2148 2149 /* Adding first point of the line only in case of empty or just finished 2150 * path 2151 */ 2152 if (FD_IS_EMPTY(pfd) || FD_IS_ENDED(pfd)) { 2153 FD_ADD_POINT(pfd, x1, y1, JNI_FALSE); 2154 } 2155 2156 FD_ADD_POINT(pfd, x2, y2, JNI_FALSE); 2157 2158 if (endSubPath) { 2159 FD_SET_ENDED(pfd); 2160 } 2161 } 2162 2163 2164 static void endSubPath(ProcessHandler* hnd) { 2165 FillData* pfd = (FillData*)(hnd->pData); 2166 if (!FD_IS_EMPTY(pfd)) { 2167 FD_SET_ENDED(pfd); 2168 } 2169 } 2170 2171 static void stubEndSubPath(ProcessHandler* hnd) { 2172 } 2173 2174 jboolean doFillPath(DrawHandler* dhnd, 2175 jint transX, jint transY, 2176 jfloat* coords, jint maxCoords, 2177 jbyte* types, jint numTypes, 2178 PHStroke stroke, jint fillRule) 2179 { 2180 jint res; 2181 2182 FillData fillData; 2183 2184 ProcessHandler hnd = 2185 { 2186 &StoreFixedLine, 2187 &endSubPath, 2188 NULL, 2189 PH_STROKE_DEFAULT, 2190 PH_MODE_FILL_CLIP, 2191 NULL 2192 }; 2193 2194 /* Initialization of the following fields in the declaration of the hnd 2195 * above causes warnings on sun studio compiler with -xc99=%none option 2196 * applied (this option means compliance with C90 standard instead of C99) 2197 */ 2198 hnd.dhnd = dhnd; 2199 hnd.pData = &fillData; 2200 hnd.stroke = stroke; 2201 2202 FD_INIT(&fillData); 2203 res = ProcessPath(&hnd, (jfloat)transX, (jfloat)transY, 2204 coords, maxCoords, types, numTypes); 2205 if (!res) { 2206 FD_FREE_POINTS(&fillData); 2207 return JNI_FALSE; 2208 } 2209 FillPolygon(&hnd, fillRule); 2210 FD_FREE_POINTS(&fillData); 2211 return JNI_TRUE; 2212 } 2213 2214 jboolean doDrawPath(DrawHandler* dhnd, 2215 void (*pProcessEndSubPath)(ProcessHandler*), 2216 jint transX, jint transY, 2217 jfloat* coords, jint maxCoords, 2218 jbyte* types, jint numTypes, PHStroke stroke) 2219 { 2220 ProcessHandler hnd = 2221 { 2222 &ProcessFixedLine, 2223 NULL, 2224 NULL, 2225 PH_STROKE_DEFAULT, 2226 PH_MODE_DRAW_CLIP, 2227 NULL 2228 }; 2229 2230 /* Initialization of the following fields in the declaration of the hnd 2231 * above causes warnings on sun studio compiler with -xc99=%none option 2232 * applied (this option means compliance with C90 standard instead of C99) 2233 */ 2234 hnd.dhnd = dhnd; 2235 hnd.stroke = stroke; 2236 2237 hnd.pProcessEndSubPath = (pProcessEndSubPath == NULL)? 2238 stubEndSubPath : pProcessEndSubPath; 2239 return ProcessPath(&hnd, (jfloat)transX, (jfloat)transY, coords, maxCoords, 2240 types, numTypes); 2241 }