1 /* 2 * Copyright (c) 2007, 2018, 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 package sun.java2d.marlin; 27 28 import java.util.Arrays; 29 import sun.java2d.marlin.stats.Histogram; 30 import sun.java2d.marlin.stats.StatLong; 31 32 final class DHelpers implements MarlinConst { 33 34 private DHelpers() { 35 throw new Error("This is a non instantiable class"); 36 } 37 38 static boolean within(final double x, final double y, final double err) { 39 final double d = y - x; 40 return (d <= err && d >= -err); 41 } 42 43 static double evalCubic(final double a, final double b, 44 final double c, final double d, 45 final double t) 46 { 47 return t * (t * (t * a + b) + c) + d; 48 } 49 50 static double evalQuad(final double a, final double b, 51 final double c, final double t) 52 { 53 return t * (t * a + b) + c; 54 } 55 56 static int quadraticRoots(final double a, final double b, final double c, 57 final double[] zeroes, final int off) 58 { 59 int ret = off; 60 if (a != 0.0d) { 61 final double dis = b*b - 4.0d * a * c; 62 if (dis > 0.0d) { 63 final double sqrtDis = Math.sqrt(dis); 64 // depending on the sign of b we use a slightly different 65 // algorithm than the traditional one to find one of the roots 66 // so we can avoid adding numbers of different signs (which 67 // might result in loss of precision). 68 if (b >= 0.0d) { 69 zeroes[ret++] = (2.0d * c) / (-b - sqrtDis); 70 zeroes[ret++] = (-b - sqrtDis) / (2.0d * a); 71 } else { 72 zeroes[ret++] = (-b + sqrtDis) / (2.0d * a); 73 zeroes[ret++] = (2.0d * c) / (-b + sqrtDis); 74 } 75 } else if (dis == 0.0d) { 76 zeroes[ret++] = -b / (2.0d * a); 77 } 78 } else if (b != 0.0d) { 79 zeroes[ret++] = -c / b; 80 } 81 return ret - off; 82 } 83 84 // find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B) 85 static int cubicRootsInAB(final double d, double a, double b, double c, 86 final double[] pts, final int off, 87 final double A, final double B) 88 { 89 if (d == 0.0d) { 90 final int num = quadraticRoots(a, b, c, pts, off); 91 return filterOutNotInAB(pts, off, num, A, B) - off; 92 } 93 // From Graphics Gems: 94 // https://github.com/erich666/GraphicsGems/blob/master/gems/Roots3And4.c 95 // (also from awt.geom.CubicCurve2D. But here we don't need as 96 // much accuracy and we don't want to create arrays so we use 97 // our own customized version). 98 99 // normal form: x^3 + ax^2 + bx + c = 0 100 101 /* 102 * TODO: cleanup all that code after reading Roots3And4.c 103 */ 104 a /= d; 105 b /= d; 106 c /= d; 107 108 // substitute x = y - A/3 to eliminate quadratic term: 109 // x^3 +Px + Q = 0 110 // 111 // Since we actually need P/3 and Q/2 for all of the 112 // calculations that follow, we will calculate 113 // p = P/3 114 // q = Q/2 115 // instead and use those values for simplicity of the code. 116 final double sub = (1.0d / 3.0d) * a; 117 final double sq_A = a * a; 118 final double p = (1.0d / 3.0d) * ((-1.0d / 3.0d) * sq_A + b); 119 final double q = (1.0d / 2.0d) * ((2.0d / 27.0d) * a * sq_A - sub * b + c); 120 121 // use Cardano's formula 122 123 final double cb_p = p * p * p; 124 final double D = q * q + cb_p; 125 126 int num; 127 if (D < 0.0d) { 128 // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method 129 final double phi = (1.0d / 3.0d) * Math.acos(-q / Math.sqrt(-cb_p)); 130 final double t = 2.0d * Math.sqrt(-p); 131 132 pts[off ] = ( t * Math.cos(phi) - sub); 133 pts[off + 1] = (-t * Math.cos(phi + (Math.PI / 3.0d)) - sub); 134 pts[off + 2] = (-t * Math.cos(phi - (Math.PI / 3.0d)) - sub); 135 num = 3; 136 } else { 137 final double sqrt_D = Math.sqrt(D); 138 final double u = Math.cbrt(sqrt_D - q); 139 final double v = - Math.cbrt(sqrt_D + q); 140 141 pts[off ] = (u + v - sub); 142 num = 1; 143 144 if (within(D, 0.0d, 1e-8d)) { 145 pts[off + 1] = ((-1.0d / 2.0d) * (u + v) - sub); 146 num = 2; 147 } 148 } 149 150 return filterOutNotInAB(pts, off, num, A, B) - off; 151 } 152 153 // returns the index 1 past the last valid element remaining after filtering 154 static int filterOutNotInAB(final double[] nums, final int off, final int len, 155 final double a, final double b) 156 { 157 int ret = off; 158 for (int i = off, end = off + len; i < end; i++) { 159 if (nums[i] >= a && nums[i] < b) { 160 nums[ret++] = nums[i]; 161 } 162 } 163 return ret; 164 } 165 166 static double fastLineLen(final double x0, final double y0, 167 final double x1, final double y1) 168 { 169 final double dx = x1 - x0; 170 final double dy = y1 - y0; 171 172 // use manhattan norm: 173 return Math.abs(dx) + Math.abs(dy); 174 } 175 176 static double linelen(final double x0, final double y0, 177 final double x1, final double y1) 178 { 179 final double dx = x1 - x0; 180 final double dy = y1 - y0; 181 return Math.sqrt(dx * dx + dy * dy); 182 } 183 184 static double fastQuadLen(final double x0, final double y0, 185 final double x1, final double y1, 186 final double x2, final double y2) 187 { 188 final double dx1 = x1 - x0; 189 final double dx2 = x2 - x1; 190 final double dy1 = y1 - y0; 191 final double dy2 = y2 - y1; 192 193 // use manhattan norm: 194 return Math.abs(dx1) + Math.abs(dx2) 195 + Math.abs(dy1) + Math.abs(dy2); 196 } 197 198 static double quadlen(final double x0, final double y0, 199 final double x1, final double y1, 200 final double x2, final double y2) 201 { 202 return (linelen(x0, y0, x1, y1) 203 + linelen(x1, y1, x2, y2) 204 + linelen(x0, y0, x2, y2)) / 2.0d; 205 } 206 207 static double fastCurvelen(final double x0, final double y0, 208 final double x1, final double y1, 209 final double x2, final double y2, 210 final double x3, final double y3) 211 { 212 final double dx1 = x1 - x0; 213 final double dx2 = x2 - x1; 214 final double dx3 = x3 - x2; 215 final double dy1 = y1 - y0; 216 final double dy2 = y2 - y1; 217 final double dy3 = y3 - y2; 218 219 // use manhattan norm: 220 return Math.abs(dx1) + Math.abs(dx2) + Math.abs(dx3) 221 + Math.abs(dy1) + Math.abs(dy2) + Math.abs(dy3); 222 } 223 224 static double curvelen(final double x0, final double y0, 225 final double x1, final double y1, 226 final double x2, final double y2, 227 final double x3, final double y3) 228 { 229 return (linelen(x0, y0, x1, y1) 230 + linelen(x1, y1, x2, y2) 231 + linelen(x2, y2, x3, y3) 232 + linelen(x0, y0, x3, y3)) / 2.0d; 233 } 234 235 // finds values of t where the curve in pts should be subdivided in order 236 // to get good offset curves a distance of w away from the middle curve. 237 // Stores the points in ts, and returns how many of them there were. 238 static int findSubdivPoints(final DCurve c, final double[] pts, 239 final double[] ts, final int type, 240 final double w2) 241 { 242 final double x12 = pts[2] - pts[0]; 243 final double y12 = pts[3] - pts[1]; 244 // if the curve is already parallel to either axis we gain nothing 245 // from rotating it. 246 if ((y12 != 0.0d && x12 != 0.0d)) { 247 // we rotate it so that the first vector in the control polygon is 248 // parallel to the x-axis. This will ensure that rotated quarter 249 // circles won't be subdivided. 250 final double hypot = Math.sqrt(x12 * x12 + y12 * y12); 251 final double cos = x12 / hypot; 252 final double sin = y12 / hypot; 253 final double x1 = cos * pts[0] + sin * pts[1]; 254 final double y1 = cos * pts[1] - sin * pts[0]; 255 final double x2 = cos * pts[2] + sin * pts[3]; 256 final double y2 = cos * pts[3] - sin * pts[2]; 257 final double x3 = cos * pts[4] + sin * pts[5]; 258 final double y3 = cos * pts[5] - sin * pts[4]; 259 260 switch(type) { 261 case 8: 262 final double x4 = cos * pts[6] + sin * pts[7]; 263 final double y4 = cos * pts[7] - sin * pts[6]; 264 c.set(x1, y1, x2, y2, x3, y3, x4, y4); 265 break; 266 case 6: 267 c.set(x1, y1, x2, y2, x3, y3); 268 break; 269 default: 270 } 271 } else { 272 c.set(pts, type); 273 } 274 275 int ret = 0; 276 // we subdivide at values of t such that the remaining rotated 277 // curves are monotonic in x and y. 278 ret += c.dxRoots(ts, ret); 279 ret += c.dyRoots(ts, ret); 280 281 // subdivide at inflection points. 282 if (type == 8) { 283 // quadratic curves can't have inflection points 284 ret += c.infPoints(ts, ret); 285 } 286 287 // now we must subdivide at points where one of the offset curves will have 288 // a cusp. This happens at ts where the radius of curvature is equal to w. 289 ret += c.rootsOfROCMinusW(ts, ret, w2, 0.0001d); 290 291 ret = filterOutNotInAB(ts, 0, ret, 0.0001d, 0.9999d); 292 isort(ts, ret); 293 return ret; 294 } 295 296 // finds values of t where the curve in pts should be subdivided in order 297 // to get intersections with the given clip rectangle. 298 // Stores the points in ts, and returns how many of them there were. 299 static int findClipPoints(final DCurve curve, final double[] pts, 300 final double[] ts, final int type, 301 final int outCodeOR, 302 final double[] clipRect) 303 { 304 curve.set(pts, type); 305 306 // clip rectangle (ymin, ymax, xmin, xmax) 307 int ret = 0; 308 309 if ((outCodeOR & OUTCODE_LEFT) != 0) { 310 ret += curve.xPoints(ts, ret, clipRect[2]); 311 } 312 if ((outCodeOR & OUTCODE_RIGHT) != 0) { 313 ret += curve.xPoints(ts, ret, clipRect[3]); 314 } 315 if ((outCodeOR & OUTCODE_TOP) != 0) { 316 ret += curve.yPoints(ts, ret, clipRect[0]); 317 } 318 if ((outCodeOR & OUTCODE_BOTTOM) != 0) { 319 ret += curve.yPoints(ts, ret, clipRect[1]); 320 } 321 isort(ts, ret); 322 return ret; 323 } 324 325 static void subdivide(final double[] src, 326 final double[] left, final double[] right, 327 final int type) 328 { 329 switch(type) { 330 case 8: 331 subdivideCubic(src, left, right); 332 return; 333 case 6: 334 subdivideQuad(src, left, right); 335 return; 336 default: 337 throw new InternalError("Unsupported curve type"); 338 } 339 } 340 341 static void isort(final double[] a, final int len) { 342 for (int i = 1, j; i < len; i++) { 343 final double ai = a[i]; 344 j = i - 1; 345 for (; j >= 0 && a[j] > ai; j--) { 346 a[j + 1] = a[j]; 347 } 348 a[j + 1] = ai; 349 } 350 } 351 352 // Most of these are copied from classes in java.awt.geom because we need 353 // both single and double precision variants of these functions, and Line2D, 354 // CubicCurve2D, QuadCurve2D don't provide them. 355 /** 356 * Subdivides the cubic curve specified by the coordinates 357 * stored in the <code>src</code> array at indices <code>srcoff</code> 358 * through (<code>srcoff</code> + 7) and stores the 359 * resulting two subdivided curves into the two result arrays at the 360 * corresponding indices. 361 * Either or both of the <code>left</code> and <code>right</code> 362 * arrays may be <code>null</code> or a reference to the same array 363 * as the <code>src</code> array. 364 * Note that the last point in the first subdivided curve is the 365 * same as the first point in the second subdivided curve. Thus, 366 * it is possible to pass the same array for <code>left</code> 367 * and <code>right</code> and to use offsets, such as <code>rightoff</code> 368 * equals (<code>leftoff</code> + 6), in order 369 * to avoid allocating extra storage for this common point. 370 * @param src the array holding the coordinates for the source curve 371 * @param left the array for storing the coordinates for the first 372 * half of the subdivided curve 373 * @param right the array for storing the coordinates for the second 374 * half of the subdivided curve 375 * @since 1.7 376 */ 377 static void subdivideCubic(final double[] src, 378 final double[] left, 379 final double[] right) 380 { 381 double x1 = src[0]; 382 double y1 = src[1]; 383 double cx1 = src[2]; 384 double cy1 = src[3]; 385 double cx2 = src[4]; 386 double cy2 = src[5]; 387 double x2 = src[6]; 388 double y2 = src[7]; 389 390 left[0] = x1; 391 left[1] = y1; 392 393 right[6] = x2; 394 right[7] = y2; 395 396 x1 = (x1 + cx1) / 2.0d; 397 y1 = (y1 + cy1) / 2.0d; 398 x2 = (x2 + cx2) / 2.0d; 399 y2 = (y2 + cy2) / 2.0d; 400 401 double cx = (cx1 + cx2) / 2.0d; 402 double cy = (cy1 + cy2) / 2.0d; 403 404 cx1 = (x1 + cx) / 2.0d; 405 cy1 = (y1 + cy) / 2.0d; 406 cx2 = (x2 + cx) / 2.0d; 407 cy2 = (y2 + cy) / 2.0d; 408 cx = (cx1 + cx2) / 2.0d; 409 cy = (cy1 + cy2) / 2.0d; 410 411 left[2] = x1; 412 left[3] = y1; 413 left[4] = cx1; 414 left[5] = cy1; 415 left[6] = cx; 416 left[7] = cy; 417 418 right[0] = cx; 419 right[1] = cy; 420 right[2] = cx2; 421 right[3] = cy2; 422 right[4] = x2; 423 right[5] = y2; 424 } 425 426 static void subdivideCubicAt(final double t, 427 final double[] src, final int offS, 428 final double[] pts, final int offL, final int offR) 429 { 430 double x1 = src[offS ]; 431 double y1 = src[offS + 1]; 432 double cx1 = src[offS + 2]; 433 double cy1 = src[offS + 3]; 434 double cx2 = src[offS + 4]; 435 double cy2 = src[offS + 5]; 436 double x2 = src[offS + 6]; 437 double y2 = src[offS + 7]; 438 439 pts[offL ] = x1; 440 pts[offL + 1] = y1; 441 442 pts[offR + 6] = x2; 443 pts[offR + 7] = y2; 444 445 x1 = x1 + t * (cx1 - x1); 446 y1 = y1 + t * (cy1 - y1); 447 x2 = cx2 + t * (x2 - cx2); 448 y2 = cy2 + t * (y2 - cy2); 449 450 double cx = cx1 + t * (cx2 - cx1); 451 double cy = cy1 + t * (cy2 - cy1); 452 453 cx1 = x1 + t * (cx - x1); 454 cy1 = y1 + t * (cy - y1); 455 cx2 = cx + t * (x2 - cx); 456 cy2 = cy + t * (y2 - cy); 457 cx = cx1 + t * (cx2 - cx1); 458 cy = cy1 + t * (cy2 - cy1); 459 460 pts[offL + 2] = x1; 461 pts[offL + 3] = y1; 462 pts[offL + 4] = cx1; 463 pts[offL + 5] = cy1; 464 pts[offL + 6] = cx; 465 pts[offL + 7] = cy; 466 467 pts[offR ] = cx; 468 pts[offR + 1] = cy; 469 pts[offR + 2] = cx2; 470 pts[offR + 3] = cy2; 471 pts[offR + 4] = x2; 472 pts[offR + 5] = y2; 473 } 474 475 static void subdivideQuad(final double[] src, 476 final double[] left, 477 final double[] right) 478 { 479 double x1 = src[0]; 480 double y1 = src[1]; 481 double cx = src[2]; 482 double cy = src[3]; 483 double x2 = src[4]; 484 double y2 = src[5]; 485 486 left[0] = x1; 487 left[1] = y1; 488 489 right[4] = x2; 490 right[5] = y2; 491 492 x1 = (x1 + cx) / 2.0d; 493 y1 = (y1 + cy) / 2.0d; 494 x2 = (x2 + cx) / 2.0d; 495 y2 = (y2 + cy) / 2.0d; 496 cx = (x1 + x2) / 2.0d; 497 cy = (y1 + y2) / 2.0d; 498 499 left[2] = x1; 500 left[3] = y1; 501 left[4] = cx; 502 left[5] = cy; 503 504 right[0] = cx; 505 right[1] = cy; 506 right[2] = x2; 507 right[3] = y2; 508 } 509 510 static void subdivideQuadAt(final double t, 511 final double[] src, final int offS, 512 final double[] pts, final int offL, final int offR) 513 { 514 double x1 = src[offS ]; 515 double y1 = src[offS + 1]; 516 double cx = src[offS + 2]; 517 double cy = src[offS + 3]; 518 double x2 = src[offS + 4]; 519 double y2 = src[offS + 5]; 520 521 pts[offL ] = x1; 522 pts[offL + 1] = y1; 523 524 pts[offR + 4] = x2; 525 pts[offR + 5] = y2; 526 527 x1 = x1 + t * (cx - x1); 528 y1 = y1 + t * (cy - y1); 529 x2 = cx + t * (x2 - cx); 530 y2 = cy + t * (y2 - cy); 531 cx = x1 + t * (x2 - x1); 532 cy = y1 + t * (y2 - y1); 533 534 pts[offL + 2] = x1; 535 pts[offL + 3] = y1; 536 pts[offL + 4] = cx; 537 pts[offL + 5] = cy; 538 539 pts[offR ] = cx; 540 pts[offR + 1] = cy; 541 pts[offR + 2] = x2; 542 pts[offR + 3] = y2; 543 } 544 545 static void subdivideLineAt(final double t, 546 final double[] src, final int offS, 547 final double[] pts, final int offL, final int offR) 548 { 549 double x1 = src[offS ]; 550 double y1 = src[offS + 1]; 551 double x2 = src[offS + 2]; 552 double y2 = src[offS + 3]; 553 554 pts[offL ] = x1; 555 pts[offL + 1] = y1; 556 557 pts[offR + 2] = x2; 558 pts[offR + 3] = y2; 559 560 x1 = x1 + t * (x2 - x1); 561 y1 = y1 + t * (y2 - y1); 562 563 pts[offL + 2] = x1; 564 pts[offL + 3] = y1; 565 566 pts[offR ] = x1; 567 pts[offR + 1] = y1; 568 } 569 570 static void subdivideAt(final double t, 571 final double[] src, final int offS, 572 final double[] pts, final int offL, final int type) 573 { 574 // if instead of switch (perf + most probable cases first) 575 if (type == 8) { 576 subdivideCubicAt(t, src, offS, pts, offL, offL + type); 577 } else if (type == 4) { 578 subdivideLineAt(t, src, offS, pts, offL, offL + type); 579 } else { 580 subdivideQuadAt(t, src, offS, pts, offL, offL + type); 581 } 582 } 583 584 // From sun.java2d.loops.GeneralRenderer: 585 586 static int outcode(final double x, final double y, 587 final double[] clipRect) 588 { 589 int code; 590 if (y < clipRect[0]) { 591 code = OUTCODE_TOP; 592 } else if (y >= clipRect[1]) { 593 code = OUTCODE_BOTTOM; 594 } else { 595 code = 0; 596 } 597 if (x < clipRect[2]) { 598 code |= OUTCODE_LEFT; 599 } else if (x >= clipRect[3]) { 600 code |= OUTCODE_RIGHT; 601 } 602 return code; 603 } 604 605 // a stack of polynomial curves where each curve shares endpoints with 606 // adjacent ones. 607 static final class PolyStack { 608 private static final byte TYPE_LINETO = (byte) 0; 609 private static final byte TYPE_QUADTO = (byte) 1; 610 private static final byte TYPE_CUBICTO = (byte) 2; 611 612 // curves capacity = edges count (8192) = edges x 2 (coords) 613 private static final int INITIAL_CURVES_COUNT = INITIAL_EDGES_COUNT << 1; 614 615 // types capacity = edges count (4096) 616 private static final int INITIAL_TYPES_COUNT = INITIAL_EDGES_COUNT; 617 618 double[] curves; 619 int end; 620 byte[] curveTypes; 621 int numCurves; 622 623 // curves ref (dirty) 624 final DoubleArrayCache.Reference curves_ref; 625 // curveTypes ref (dirty) 626 final ByteArrayCache.Reference curveTypes_ref; 627 628 // used marks (stats only) 629 int curveTypesUseMark; 630 int curvesUseMark; 631 632 private final StatLong stat_polystack_types; 633 private final StatLong stat_polystack_curves; 634 private final Histogram hist_polystack_curves; 635 private final StatLong stat_array_polystack_curves; 636 private final StatLong stat_array_polystack_curveTypes; 637 638 PolyStack(final DRendererContext rdrCtx) { 639 this(rdrCtx, null, null, null, null, null); 640 } 641 642 PolyStack(final DRendererContext rdrCtx, 643 final StatLong stat_polystack_types, 644 final StatLong stat_polystack_curves, 645 final Histogram hist_polystack_curves, 646 final StatLong stat_array_polystack_curves, 647 final StatLong stat_array_polystack_curveTypes) 648 { 649 curves_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_CURVES_COUNT); // 32K 650 curves = curves_ref.initial; 651 652 curveTypes_ref = rdrCtx.newDirtyByteArrayRef(INITIAL_TYPES_COUNT); // 4K 653 curveTypes = curveTypes_ref.initial; 654 numCurves = 0; 655 end = 0; 656 657 if (DO_STATS) { 658 curveTypesUseMark = 0; 659 curvesUseMark = 0; 660 } 661 this.stat_polystack_types = stat_polystack_types; 662 this.stat_polystack_curves = stat_polystack_curves; 663 this.hist_polystack_curves = hist_polystack_curves; 664 this.stat_array_polystack_curves = stat_array_polystack_curves; 665 this.stat_array_polystack_curveTypes = stat_array_polystack_curveTypes; 666 } 667 668 /** 669 * Disposes this PolyStack: 670 * clean up before reusing this instance 671 */ 672 void dispose() { 673 end = 0; 674 numCurves = 0; 675 676 if (DO_STATS) { 677 stat_polystack_types.add(curveTypesUseMark); 678 stat_polystack_curves.add(curvesUseMark); 679 hist_polystack_curves.add(curvesUseMark); 680 681 // reset marks 682 curveTypesUseMark = 0; 683 curvesUseMark = 0; 684 } 685 686 // Return arrays: 687 // curves and curveTypes are kept dirty 688 curves = curves_ref.putArray(curves); 689 curveTypes = curveTypes_ref.putArray(curveTypes); 690 } 691 692 private void ensureSpace(final int n) { 693 // use substraction to avoid integer overflow: 694 if (curves.length - end < n) { 695 if (DO_STATS) { 696 stat_array_polystack_curves.add(end + n); 697 } 698 curves = curves_ref.widenArray(curves, end, end + n); 699 } 700 if (curveTypes.length <= numCurves) { 701 if (DO_STATS) { 702 stat_array_polystack_curveTypes.add(numCurves + 1); 703 } 704 curveTypes = curveTypes_ref.widenArray(curveTypes, 705 numCurves, 706 numCurves + 1); 707 } 708 } 709 710 void pushCubic(double x0, double y0, 711 double x1, double y1, 712 double x2, double y2) 713 { 714 ensureSpace(6); 715 curveTypes[numCurves++] = TYPE_CUBICTO; 716 // we reverse the coordinate order to make popping easier 717 final double[] _curves = curves; 718 int e = end; 719 _curves[e++] = x2; _curves[e++] = y2; 720 _curves[e++] = x1; _curves[e++] = y1; 721 _curves[e++] = x0; _curves[e++] = y0; 722 end = e; 723 } 724 725 void pushQuad(double x0, double y0, 726 double x1, double y1) 727 { 728 ensureSpace(4); 729 curveTypes[numCurves++] = TYPE_QUADTO; 730 final double[] _curves = curves; 731 int e = end; 732 _curves[e++] = x1; _curves[e++] = y1; 733 _curves[e++] = x0; _curves[e++] = y0; 734 end = e; 735 } 736 737 void pushLine(double x, double y) { 738 ensureSpace(2); 739 curveTypes[numCurves++] = TYPE_LINETO; 740 curves[end++] = x; curves[end++] = y; 741 } 742 743 void pullAll(final DPathConsumer2D io) { 744 final int nc = numCurves; 745 if (nc == 0) { 746 return; 747 } 748 if (DO_STATS) { 749 // update used marks: 750 if (numCurves > curveTypesUseMark) { 751 curveTypesUseMark = numCurves; 752 } 753 if (end > curvesUseMark) { 754 curvesUseMark = end; 755 } 756 } 757 final byte[] _curveTypes = curveTypes; 758 final double[] _curves = curves; 759 int e = 0; 760 761 for (int i = 0; i < nc; i++) { 762 switch(_curveTypes[i]) { 763 case TYPE_LINETO: 764 io.lineTo(_curves[e], _curves[e+1]); 765 e += 2; 766 continue; 767 case TYPE_QUADTO: 768 io.quadTo(_curves[e], _curves[e+1], 769 _curves[e+2], _curves[e+3]); 770 e += 4; 771 continue; 772 case TYPE_CUBICTO: 773 io.curveTo(_curves[e], _curves[e+1], 774 _curves[e+2], _curves[e+3], 775 _curves[e+4], _curves[e+5]); 776 e += 6; 777 continue; 778 default: 779 } 780 } 781 numCurves = 0; 782 end = 0; 783 } 784 785 void popAll(final DPathConsumer2D io) { 786 int nc = numCurves; 787 if (nc == 0) { 788 return; 789 } 790 if (DO_STATS) { 791 // update used marks: 792 if (numCurves > curveTypesUseMark) { 793 curveTypesUseMark = numCurves; 794 } 795 if (end > curvesUseMark) { 796 curvesUseMark = end; 797 } 798 } 799 final byte[] _curveTypes = curveTypes; 800 final double[] _curves = curves; 801 int e = end; 802 803 while (nc != 0) { 804 switch(_curveTypes[--nc]) { 805 case TYPE_LINETO: 806 e -= 2; 807 io.lineTo(_curves[e], _curves[e+1]); 808 continue; 809 case TYPE_QUADTO: 810 e -= 4; 811 io.quadTo(_curves[e], _curves[e+1], 812 _curves[e+2], _curves[e+3]); 813 continue; 814 case TYPE_CUBICTO: 815 e -= 6; 816 io.curveTo(_curves[e], _curves[e+1], 817 _curves[e+2], _curves[e+3], 818 _curves[e+4], _curves[e+5]); 819 continue; 820 default: 821 } 822 } 823 numCurves = 0; 824 end = 0; 825 } 826 827 @Override 828 public String toString() { 829 String ret = ""; 830 int nc = numCurves; 831 int last = end; 832 int len; 833 while (nc != 0) { 834 switch(curveTypes[--nc]) { 835 case TYPE_LINETO: 836 len = 2; 837 ret += "line: "; 838 break; 839 case TYPE_QUADTO: 840 len = 4; 841 ret += "quad: "; 842 break; 843 case TYPE_CUBICTO: 844 len = 6; 845 ret += "cubic: "; 846 break; 847 default: 848 len = 0; 849 } 850 last -= len; 851 ret += Arrays.toString(Arrays.copyOfRange(curves, last, last+len)) 852 + "\n"; 853 } 854 return ret; 855 } 856 } 857 858 // a stack of integer indices 859 static final class IndexStack { 860 861 // integer capacity = edges count / 4 ~ 1024 862 private static final int INITIAL_COUNT = INITIAL_EDGES_COUNT >> 2; 863 864 private int end; 865 private int[] indices; 866 867 // indices ref (dirty) 868 private final IntArrayCache.Reference indices_ref; 869 870 // used marks (stats only) 871 private int indicesUseMark; 872 873 private final StatLong stat_idxstack_indices; 874 private final Histogram hist_idxstack_indices; 875 private final StatLong stat_array_idxstack_indices; 876 877 IndexStack(final DRendererContext rdrCtx) { 878 this(rdrCtx, null, null, null); 879 } 880 881 IndexStack(final DRendererContext rdrCtx, 882 final StatLong stat_idxstack_indices, 883 final Histogram hist_idxstack_indices, 884 final StatLong stat_array_idxstack_indices) 885 { 886 indices_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_COUNT); // 4K 887 indices = indices_ref.initial; 888 end = 0; 889 890 if (DO_STATS) { 891 indicesUseMark = 0; 892 } 893 this.stat_idxstack_indices = stat_idxstack_indices; 894 this.hist_idxstack_indices = hist_idxstack_indices; 895 this.stat_array_idxstack_indices = stat_array_idxstack_indices; 896 } 897 898 /** 899 * Disposes this PolyStack: 900 * clean up before reusing this instance 901 */ 902 void dispose() { 903 end = 0; 904 905 if (DO_STATS) { 906 stat_idxstack_indices.add(indicesUseMark); 907 hist_idxstack_indices.add(indicesUseMark); 908 909 // reset marks 910 indicesUseMark = 0; 911 } 912 913 // Return arrays: 914 // values is kept dirty 915 indices = indices_ref.putArray(indices); 916 } 917 918 boolean isEmpty() { 919 return (end == 0); 920 } 921 922 void reset() { 923 end = 0; 924 } 925 926 void push(final int v) { 927 // remove redundant values (reverse order): 928 int[] _values = indices; 929 final int nc = end; 930 if (nc != 0) { 931 if (_values[nc - 1] == v) { 932 // remove both duplicated values: 933 end--; 934 return; 935 } 936 } 937 if (_values.length <= nc) { 938 if (DO_STATS) { 939 stat_array_idxstack_indices.add(nc + 1); 940 } 941 indices = _values = indices_ref.widenArray(_values, nc, nc + 1); 942 } 943 _values[end++] = v; 944 945 if (DO_STATS) { 946 // update used marks: 947 if (end > indicesUseMark) { 948 indicesUseMark = end; 949 } 950 } 951 } 952 953 void pullAll(final double[] points, final DPathConsumer2D io) { 954 final int nc = end; 955 if (nc == 0) { 956 return; 957 } 958 final int[] _values = indices; 959 960 for (int i = 0, j; i < nc; i++) { 961 j = _values[i] << 1; 962 io.lineTo(points[j], points[j + 1]); 963 } 964 end = 0; 965 } 966 } 967 }