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