1 /* 2 * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 package sun.java2d.pisces; 27 28 public class Renderer extends LineSink { 29 public static final int WIND_EVEN_ODD = 0; 30 public static final int WIND_NON_ZERO = 1; 31 32 // Initial edge list size 33 // IMPL_NOTE - restore size after growth 34 public static final int INITIAL_EDGES = 1000; 35 36 // Recommended maximum scratchpad sizes. The arrays will grow 37 // larger if needed, but when finished() is called they will be released 38 // if they have grown larger than these sizes. 39 public static final int DEFAULT_INDICES_SIZE = 8192; 40 public static final int DEFAULT_CROSSINGS_SIZE = 32*1024; 41 42 // Antialiasing 43 private int SUBPIXEL_LG_POSITIONS_X; 44 private int SUBPIXEL_LG_POSITIONS_Y; 45 private int SUBPIXEL_MASK_X; 46 private int SUBPIXEL_MASK_Y; 47 private int SUBPIXEL_POSITIONS_X; 48 private int SUBPIXEL_POSITIONS_Y; 49 int MAX_AA_ALPHA; 50 private int MAX_AA_ALPHA_DENOM; 51 private int HALF_MAX_AA_ALPHA_DENOM; 52 private int XSHIFT; 53 private int YSHIFT; 54 private int YSTEP; 55 private int HYSTEP; 56 private int YMASK; 57 58 private static final int MIN_QUAD_OPT_WIDTH = 100 << 16; 59 60 // Cache to store RLE-encoded coverage mask of the current primitive 61 PiscesCache cache; 62 63 // Bounds of the drawing region, at S15.16 precsion 64 private int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY; 65 66 // Bounds of the current primitive, at subsample precision 67 private int rasterMinX, rasterMaxX, rasterMinY, rasterMaxY; 68 69 // Pixel bounding box for current primitive 70 private int bboxX0, bboxY0, bboxX1, bboxY1; 71 72 // Current winding rule 73 private int windingRule; 74 75 // Current drawing position, i.e., final point of last segment 76 private int x0, y0; 77 78 // Position of most recent 'moveTo' command 79 private int sx0, sy0; 80 81 // Buffer to be filled with one row's worth of alpha values 82 private byte[] rowAA; // needs to be short if 16x16 subsampling 83 84 // Track the number of vertical extrema of the incoming edge list 85 // in order to determine the maximum number of crossings of a 86 // scanline 87 private int firstOrientation; 88 private int lastOrientation; 89 private int flips; 90 91 // Parameters for emitRow 92 private int alphaWidth; 93 94 public Renderer() { 95 } 96 97 public void setAntialiasing(int subpixelLgPositionsX, 98 int subpixelLgPositionsY) { 99 this.SUBPIXEL_LG_POSITIONS_X = subpixelLgPositionsX; 100 this.SUBPIXEL_LG_POSITIONS_Y = subpixelLgPositionsY; 101 102 this.SUBPIXEL_MASK_X = 103 (1 << (SUBPIXEL_LG_POSITIONS_X)) - 1; 104 this.SUBPIXEL_MASK_Y = 105 (1 << (SUBPIXEL_LG_POSITIONS_Y)) - 1; 106 this.SUBPIXEL_POSITIONS_X = 107 1 << (SUBPIXEL_LG_POSITIONS_X); 108 this.SUBPIXEL_POSITIONS_Y = 109 1 << (SUBPIXEL_LG_POSITIONS_Y); 110 this.MAX_AA_ALPHA = 111 (SUBPIXEL_POSITIONS_X*SUBPIXEL_POSITIONS_Y); 112 this.MAX_AA_ALPHA_DENOM = 255*MAX_AA_ALPHA; 113 this.HALF_MAX_AA_ALPHA_DENOM = MAX_AA_ALPHA_DENOM/2; 114 this.XSHIFT = 16 - SUBPIXEL_LG_POSITIONS_X; 115 this.YSHIFT = 16 - SUBPIXEL_LG_POSITIONS_Y; 116 this.YSTEP = 1 << YSHIFT; 117 this.HYSTEP = 1 << (YSHIFT - 1); 118 this.YMASK = ~(YSTEP - 1); 119 } 120 121 public int getSubpixelLgPositionsX() { 122 return SUBPIXEL_LG_POSITIONS_X; 123 } 124 125 public int getSubpixelLgPositionsY() { 126 return SUBPIXEL_LG_POSITIONS_Y; 127 } 128 129 public void setWindingRule(int windingRule) { 130 this.windingRule = windingRule; 131 } 132 133 public int getWindingRule() { 134 return windingRule; 135 } 136 137 public void beginRendering(int boundsX, int boundsY, 138 int boundsWidth, int boundsHeight) { 139 lastOrientation = 0; 140 flips = 0; 141 142 resetEdges(); 143 144 this.boundsMinX = boundsX << 16; 145 this.boundsMinY = boundsY << 16; 146 this.boundsMaxX = (boundsX + boundsWidth) << 16; 147 this.boundsMaxY = (boundsY + boundsHeight) << 16; 148 149 this.bboxX0 = boundsX; 150 this.bboxY0 = boundsY; 151 this.bboxX1 = boundsX + boundsWidth; 152 this.bboxY1 = boundsY + boundsHeight; 153 } 154 155 public void moveTo(int x0, int y0) { 156 // System.out.println("Renderer: moveTo " + x0/65536.0 + " " + y0/65536.0); 157 close(); 158 this.sx0 = this.x0 = x0; 159 this.sy0 = this.y0 = y0; 160 this.lastOrientation = 0; 161 } 162 163 public void lineJoin() { 164 // System.out.println("Renderer: lineJoin"); 165 // do nothing 166 } 167 168 public void lineTo(int x1, int y1) { 169 // System.out.println("Renderer: lineTo " + x1/65536.0 + " " + y1/65536.0); 170 171 // Ignore horizontal lines 172 // Next line will count flip 173 if (y0 == y1) { 174 this.x0 = x1; 175 return; 176 } 177 178 int orientation = (y0 < y1) ? 1 : -1; 179 if (lastOrientation == 0) { 180 firstOrientation = orientation; 181 } else if (orientation != lastOrientation) { 182 ++flips; 183 } 184 lastOrientation = orientation; 185 186 // Bias Y by 1 ULP so endpoints never lie on a scanline 187 addEdge(x0, y0 | 0x1, x1, y1 | 0x1); 188 189 this.x0 = x1; 190 this.y0 = y1; 191 } 192 193 public void close() { 194 // System.out.println("Renderer: close"); 195 196 int orientation = lastOrientation; 197 if (y0 != sy0) { 198 orientation = (y0 < sy0) ? 1 : -1; 199 } 200 if (orientation != firstOrientation) { 201 ++flips; 202 } 203 lineTo(sx0, sy0); 204 } 205 206 public void end() { 207 close(); 208 // System.out.println("Renderer: end"); 209 // do nothing 210 } 211 212 // Scan convert a single edge 213 private void computeCrossingsForEdge(int index, 214 int boundsMinY, int boundsMaxY) { 215 int iy0 = edges[index + 1]; 216 int iy1 = edges[index + 3]; 217 218 // Clip to valid Y range 219 int clipy0 = (iy0 > boundsMinY) ? iy0 : boundsMinY; 220 int clipy1 = (iy1 < boundsMaxY) ? iy1 : boundsMaxY; 221 222 int minY = ((clipy0 + HYSTEP) & YMASK) + HYSTEP; 223 int maxY = ((clipy1 - HYSTEP) & YMASK) + HYSTEP; 224 225 // IMPL_NOTE - If line falls outside the valid X range, could 226 // draw a vertical line instead 227 228 // Exit if no scanlines are crossed 229 if (minY > maxY) { 230 return; 231 } 232 233 // Scan convert line using a DDA approach 234 235 int ix0 = edges[index]; 236 int ix1 = edges[index + 2]; 237 long dx = ((long) ix1) - ix0; 238 long dy = ((long) iy1) - iy0; 239 240 // Compute first crossing point at y = minY 241 int orientation = edges[index + 4]; 242 int y = minY; 243 long lx = (((long) y) - iy0)*dx/dy + ix0; 244 addCrossing(y >> YSHIFT, (int)(lx >> XSHIFT), orientation); 245 246 // Advance y to next scanline, exit if past endpoint 247 y += YSTEP; 248 if (y > maxY) { 249 return; 250 } 251 252 // Compute xstep only if additional scanlines are crossed 253 // For each scanline, add xstep to lx and YSTEP to y and 254 // emit the new crossing 255 long xstep = ((long)YSTEP*dx)/dy; 256 for (; y <= maxY; y += YSTEP) { 257 lx += xstep; 258 addCrossing(y >> YSHIFT, (int)(lx >> XSHIFT), orientation); 259 } 260 } 261 262 private void computeBounds() { 263 rasterMinX = crossingMinX & ~SUBPIXEL_MASK_X; 264 rasterMaxX = crossingMaxX | SUBPIXEL_MASK_X; 265 rasterMinY = crossingMinY & ~SUBPIXEL_MASK_Y; 266 rasterMaxY = crossingMaxY | SUBPIXEL_MASK_Y; 267 268 // If nothing was drawn, we have: 269 // minX = Integer.MAX_VALUE and maxX = Integer.MIN_VALUE 270 // so nothing to render 271 if (rasterMinX > rasterMaxX || rasterMinY > rasterMaxY) { 272 rasterMinX = 0; 273 rasterMaxX = -1; 274 rasterMinY = 0; 275 rasterMaxY = -1; 276 return; 277 } 278 279 if (rasterMinX < boundsMinX >> XSHIFT) { 280 rasterMinX = boundsMinX >> XSHIFT; 281 } 282 if (rasterMinY < boundsMinY >> YSHIFT) { 283 rasterMinY = boundsMinY >> YSHIFT; 284 } 285 if (rasterMaxX > boundsMaxX >> XSHIFT) { 286 rasterMaxX = boundsMaxX >> XSHIFT; 287 } 288 if (rasterMaxY > boundsMaxY >> YSHIFT) { 289 rasterMaxY = boundsMaxY >> YSHIFT; 290 } 291 } 292 293 private int clamp(int x, int min, int max) { 294 if (x < min) { 295 return min; 296 } else if (x > max) { 297 return max; 298 } 299 return x; 300 } 301 302 private void _endRendering() { 303 if (flips == 0) { 304 bboxX0 = bboxY0 = 0; 305 bboxX1 = bboxY1 = -1; 306 return; 307 } 308 309 // Special case for filling a single rect with a flat, opaque color 310 // REMIND: This special case was not originally written to fill a 311 // cache object and called directly to a Blit - it needs some code 312 // to fill the cache instead to be useful for this usage... 313 if (false /* Does not work with cache (yet?) */ && 314 edgeIdx == 10 && 315 edges[0] == edges[2] && 316 edges[1] == edges[6] && 317 edges[3] == edges[8] && 318 edges[5] == edges[7] && 319 Math.abs(edges[0] - edges[5]) > MIN_QUAD_OPT_WIDTH) 320 { 321 322 int x0 = edges[0] >> XSHIFT; 323 int y0 = edges[1] >> YSHIFT; 324 int x1 = edges[5] >> XSHIFT; 325 int y1 = edges[3] >> YSHIFT; 326 327 if (x0 > x1) { 328 int tmp = x0; 329 x0 = x1; 330 x1 = tmp; 331 } 332 if (y0 > y1) { 333 int tmp = y0; 334 y0 = y1; 335 y1 = tmp; 336 } 337 338 int bMinX = this.boundsMinX >> XSHIFT; 339 int bMinY = this.boundsMinY >> YSHIFT; 340 int bMaxX = this.boundsMaxX >> XSHIFT; 341 int bMaxY = this.boundsMaxY >> YSHIFT; 342 343 // Clip to image bounds in supersampled coordinates 344 x0 = clamp(x0, bMinX, bMaxX); 345 x1 = clamp(x1, bMinX, bMaxX); 346 y0 = clamp(y0, bMinY, bMaxY); 347 y1 = clamp(y1, bMinY, bMaxY); 348 349 /* 350 * REMIND: Need to fill the cache here instead... 351 Blit.fillRectSrcOver(this, 352 imageData, imageType, 353 imageOffset, 354 imageScanlineStride, imagePixelStride, 355 width, height, 356 x0, y0, x1, y1, 357 cred, cgreen, cblue); 358 */ 359 360 bboxX0 = x0 >> SUBPIXEL_LG_POSITIONS_X; 361 bboxY0 = y0 >> SUBPIXEL_LG_POSITIONS_Y; 362 bboxX1 = (x1 + SUBPIXEL_POSITIONS_X - 1) 363 >> SUBPIXEL_LG_POSITIONS_X; 364 bboxY1 = (y1 + SUBPIXEL_POSITIONS_Y - 1) 365 >> SUBPIXEL_LG_POSITIONS_Y; 366 367 return; 368 } 369 370 int minY = (edgeMinY > boundsMinY) ? edgeMinY : boundsMinY; 371 int maxY = (edgeMaxY < boundsMaxY) ? edgeMaxY : boundsMaxY; 372 373 // Check for empty intersection of primitive with the drawing area 374 if (minY > maxY) { 375 bboxX0 = bboxY0 = 0; 376 bboxX1 = bboxY1 = -1; 377 return; 378 } 379 380 // Compute Y extent in subpixel coordinates 381 int iminY = (minY >> YSHIFT) & ~SUBPIXEL_MASK_Y; 382 int imaxY = (maxY >> YSHIFT) | SUBPIXEL_MASK_Y; 383 int yextent = (imaxY - iminY) + 1; 384 385 // Maximum number of crossings 386 int size = flips*yextent; 387 388 int bmax = (boundsMaxY >> YSHIFT) - 1; 389 if (imaxY > bmax) { 390 imaxY = bmax; 391 } 392 393 // Initialize X bounds, will be refined for each strip 394 bboxX0 = Integer.MAX_VALUE; 395 bboxX1 = Integer.MIN_VALUE; 396 397 // Set Y bounds 398 bboxY0 = iminY >> SUBPIXEL_LG_POSITIONS_Y; 399 bboxY1 = (imaxY + SUBPIXEL_POSITIONS_Y - 1) >> SUBPIXEL_LG_POSITIONS_Y; 400 401 // Compute number of rows that can be processing using 402 // a crossings table no larger than DEFAULT_CROSSINGS_SIZE. 403 // However, we must process at least one row, so we grow the table 404 // temporarily if needed. This would require an object with a 405 // huge number of flips. 406 int rows = DEFAULT_CROSSINGS_SIZE/(flips*SUBPIXEL_POSITIONS_Y); 407 rows = Math.min(rows, yextent); 408 rows = Math.max(rows, 1); 409 for (int i = iminY; i <= imaxY; i += rows*SUBPIXEL_POSITIONS_Y) { 410 // Compute index of last scanline to be processed in this pass 411 int last = Math.min(i + rows*SUBPIXEL_POSITIONS_Y - 1, imaxY); 412 setCrossingsExtents(i, last, flips); 413 414 int bminY = i << YSHIFT; 415 int bmaxY = (last << YSHIFT) | ~YMASK; 416 417 // Process edges from the edge list 418 int maxIdx = edgeIdx; 419 for (int index = 0; index < maxIdx; index += 5) { 420 // Test y1 < min: 421 // 422 // If edge lies entirely above current strip, 423 // discard it 424 if (edges[index + 3] < bminY) { 425 // Overwrite the edge with the last edge 426 edgeIdx -= 5; 427 int fidx = edgeIdx; 428 int tidx = index; 429 edges[tidx++] = edges[fidx++]; 430 edges[tidx++] = edges[fidx++]; 431 edges[tidx++] = edges[fidx++]; 432 edges[tidx++] = edges[fidx++]; 433 edges[tidx ] = edges[fidx ]; 434 435 maxIdx -= 5; 436 index -= 5; 437 continue; 438 } 439 440 // Test y0 > max: 441 // 442 // If edge lies entirely below current strip, 443 // skip it for now 444 if (edges[index + 1] > bmaxY) { 445 continue; 446 } 447 448 computeCrossingsForEdge(index, bminY, bmaxY); 449 } 450 451 computeBounds(); 452 if (rasterMaxX < rasterMinX) { 453 continue; 454 } 455 456 bboxX0 = Math.min(bboxX0, 457 rasterMinX >> SUBPIXEL_LG_POSITIONS_X); 458 bboxX1 = Math.max(bboxX1, 459 (rasterMaxX + SUBPIXEL_POSITIONS_X - 1) 460 >> SUBPIXEL_LG_POSITIONS_X); 461 renderStrip(); 462 } 463 464 // Free up any unusually large scratchpad memory used by the 465 // preceding primitive 466 crossingListFinished(); 467 } 468 469 public void endRendering() { 470 // Set up the cache to accumulate the bounding box 471 if (cache != null) { 472 cache.bboxX0 = Integer.MAX_VALUE; 473 cache.bboxY0 = Integer.MAX_VALUE; 474 cache.bboxX1 = Integer.MIN_VALUE; 475 cache.bboxY1 = Integer.MIN_VALUE; 476 } 477 478 _endRendering(); 479 } 480 481 public void getBoundingBox(int[] bbox) { 482 bbox[0] = bboxX0; 483 bbox[1] = bboxY0; 484 bbox[2] = bboxX1 - bboxX0; 485 bbox[3] = bboxY1 - bboxY0; 486 } 487 488 private void renderStrip() { 489 // Grow rowAA according to the raster width 490 int width = (rasterMaxX - rasterMinX + 1) >> SUBPIXEL_LG_POSITIONS_X; 491 alphaWidth = width; 492 493 // Allocate one extra entry in rowAA to avoid a conditional in 494 // the rendering loop 495 int bufLen = width + 1; 496 if (this.rowAA == null || this.rowAA.length < bufLen) { 497 this.rowAA = new byte[bufLen]; 498 } 499 500 // Mask to determine the relevant bit of the crossing sum 501 // 0x1 if EVEN_ODD, all bits if NON_ZERO 502 int mask = (windingRule == WIND_EVEN_ODD) ? 0x1 : ~0x0; 503 504 int y = 0; 505 int prevY = rasterMinY - 1; 506 507 int minX = Integer.MAX_VALUE; 508 int maxX = Integer.MIN_VALUE; 509 510 iterateCrossings(); 511 while (hasMoreCrossingRows()) { 512 y = crossingY; 513 514 // Emit any skipped rows 515 for (int j = prevY + 1; j < y; j++) { 516 if (((j & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) || 517 (j == rasterMaxY)) { 518 emitRow(j >> SUBPIXEL_LG_POSITIONS_Y, 0, -1); 519 } 520 } 521 prevY = y; 522 523 if (crossingRowIndex < crossingRowCount) { 524 int lx = crossings[crossingRowOffset + crossingRowIndex]; 525 lx >>= 1; 526 int hx = crossings[crossingRowOffset + crossingRowCount - 1]; 527 hx >>= 1; 528 int x0 = lx > rasterMinX ? lx : rasterMinX; 529 int x1 = hx < rasterMaxX ? hx : rasterMaxX; 530 x0 -= rasterMinX; 531 x1 -= rasterMinX; 532 533 minX = Math.min(minX, x0 >> SUBPIXEL_LG_POSITIONS_X); 534 maxX = Math.max(maxX, x1 >> SUBPIXEL_LG_POSITIONS_X); 535 } 536 537 int sum = 0; 538 int prev = rasterMinX; 539 while (crossingRowIndex < crossingRowCount) { 540 int crxo = crossings[crossingRowOffset + crossingRowIndex]; 541 crossingRowIndex++; 542 543 int crx = crxo >> 1; 544 int crorientation = ((crxo & 0x1) == 0x1) ? 1 : -1; 545 546 if ((sum & mask) != 0) { 547 // Clip to active X range, if x1 < x0 loop will 548 // have no effect 549 int x0 = prev > rasterMinX ? prev : rasterMinX; 550 int x1 = crx < rasterMaxX ? crx : rasterMaxX; 551 552 // Empty spans 553 if (x1 > x0) { 554 x0 -= rasterMinX; 555 x1 -= rasterMinX; 556 557 // Accumulate alpha, equivalent to: 558 // for (int x = x0; x < x1; x++) { 559 // ++rowAA[x >> SUBPIXEL_LG_POSITIONS_X]; 560 // } 561 // 562 // In the middle of the span, we can update a full 563 // pixel at a time (i.e., SUBPIXEL_POSITIONS_X 564 // subpixels) 565 566 int x = x0 >> SUBPIXEL_LG_POSITIONS_X; 567 int xmaxm1 = (x1 - 1) >> SUBPIXEL_LG_POSITIONS_X; 568 if (x == xmaxm1) { 569 // Start and end in same pixel 570 rowAA[x] += x1 - x0; 571 } else { 572 // Start and end in different pixels 573 rowAA[x++] += SUBPIXEL_POSITIONS_X - 574 (x0 & SUBPIXEL_MASK_X); 575 int xmax = x1 >> SUBPIXEL_LG_POSITIONS_X; 576 while (x < xmax) { 577 rowAA[x++] += SUBPIXEL_POSITIONS_X; 578 } 579 // Note - at this point it is possible that 580 // x == width, which implies that 581 // x1 & SUBPIXEL_MASK_X == 0. We allocate 582 // one extra entry in rowAA so this 583 // assignment will be harmless. The alternative 584 // is an extra conditional here, or some other 585 // scheme to deal with the last pixel better. 586 rowAA[x] += x1 & SUBPIXEL_MASK_X; 587 } 588 } 589 } 590 sum += crorientation; 591 prev = crx; 592 } 593 594 // Every SUBPIXEL_POSITIONS rows, output an antialiased row 595 if (((y & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) || 596 (y == rasterMaxY)) { 597 emitRow(y >> SUBPIXEL_LG_POSITIONS_Y, minX, maxX); 598 minX = Integer.MAX_VALUE; 599 maxX = Integer.MIN_VALUE; 600 } 601 } 602 603 // Emit final row 604 for (int j = prevY + 1; j <= rasterMaxY; j++) { 605 if (((j & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) || 606 (j == rasterMaxY)) { 607 emitRow(j >> SUBPIXEL_LG_POSITIONS_Y, minX, maxX); 608 minX = Integer.MAX_VALUE; 609 maxX = Integer.MIN_VALUE; 610 } 611 } 612 } 613 614 private void clearAlpha(byte[] alpha, 615 int width, 616 int minX, int maxX) { 617 if (maxX >= minX) { 618 int w = maxX - minX + 1; 619 if (w + minX > width) { 620 w = width - minX; 621 } 622 623 int aidx = minX; 624 for (int i = 0; i < w; i++, aidx++) { 625 alpha[aidx] = (byte)0; 626 } 627 } 628 } 629 630 private void emitRow(int y, int minX, int maxX) { 631 // Copy rowAA data into the cache if one is present 632 if (cache != null) { 633 if (maxX >= minX) { 634 int x0 = minX + (rasterMinX >> SUBPIXEL_LG_POSITIONS_X); 635 int x1 = maxX + (rasterMinX >> SUBPIXEL_LG_POSITIONS_X); 636 637 cache.startRow(y, x0, x1); 638 int srcIdx = minX; 639 640 // Perform run-length encoding 641 // and store results in the cache 642 byte startVal = rowAA[srcIdx++]; 643 int runLen = 1; 644 while (srcIdx <= maxX) { 645 byte nextVal = rowAA[srcIdx++]; 646 if (nextVal == startVal && runLen < 255) { 647 ++runLen; 648 } else { 649 cache.addRLERun(startVal, runLen); 650 651 runLen = 1; 652 startVal = nextVal; 653 } 654 } 655 cache.addRLERun(startVal, runLen); 656 cache.addRLERun((byte)0, 0); 657 } 658 } 659 660 clearAlpha(rowAA, 661 alphaWidth, 662 minX, maxX); 663 } 664 665 public void setCache(PiscesCache cache) { 666 this.cache = cache; 667 } 668 669 // Edge list data 670 671 private int[] edges = new int[5*INITIAL_EDGES]; 672 private int edgeIdx = 0; 673 private int edgeMinY = Integer.MAX_VALUE; 674 private int edgeMaxY = Integer.MIN_VALUE; 675 676 private void addEdge(int x0, int y0, int x1, int y1) { 677 int newLen = edgeIdx + 5; 678 if (edges.length < newLen) { 679 int[] tmp = new int[Math.max(11*edges.length/10, newLen)]; 680 System.arraycopy(edges, 0, tmp, 0, edgeIdx); 681 this.edges = tmp; 682 } 683 684 int orientation = 1; 685 if (y0 > y1) { 686 int tmp = y0; 687 y0 = y1; 688 y1 = tmp; 689 690 orientation = -1; 691 } 692 693 // Skip edges that don't cross a subsampled scanline 694 int eminY = ((y0 + HYSTEP) & YMASK); 695 int emaxY = ((y1 - HYSTEP) & YMASK); 696 if (eminY > emaxY) { 697 return; 698 } 699 700 if (orientation == -1) { 701 int tmp = x0; 702 x0 = x1; 703 x1 = tmp; 704 } 705 706 edges[edgeIdx++] = x0; 707 edges[edgeIdx++] = y0; 708 edges[edgeIdx++] = x1; 709 edges[edgeIdx++] = y1; 710 edges[edgeIdx++] = orientation; 711 712 // Update Y bounds of primitive 713 if (y0 < edgeMinY) { 714 edgeMinY = y0; 715 } 716 if (y1 > edgeMaxY) { 717 edgeMaxY = y1; 718 } 719 } 720 721 private void resetEdges() { 722 this.edgeIdx = 0; 723 this.edgeMinY = Integer.MAX_VALUE; 724 this.edgeMaxY = Integer.MIN_VALUE; 725 } 726 727 // Crossing list data 728 729 private int[] crossingIndices; 730 private int[] crossings; 731 private int crossingMinY; 732 private int crossingMaxY; 733 private int crossingMinX = Integer.MAX_VALUE; 734 private int crossingMaxX = Integer.MIN_VALUE; 735 private int crossingMaxXEntries; 736 private int numCrossings = 0; 737 private boolean crossingsSorted = false; 738 739 private int crossingY; 740 private int crossingRowCount; 741 private int crossingRowOffset; 742 private int crossingRowIndex; 743 744 private void setCrossingsExtents(int minY, int maxY, int maxXEntries) { 745 int yextent = maxY - minY + 1; 746 747 // Grow indices array as needed 748 if (crossingIndices == null || crossingIndices.length < yextent) { 749 this.crossingIndices = 750 new int[Math.max(yextent, DEFAULT_INDICES_SIZE)]; 751 } 752 // Grow crossings array as needed 753 if (crossings == null || crossings.length < yextent*maxXEntries) { 754 this.crossings = new int[Math.max(yextent*maxXEntries, 755 DEFAULT_CROSSINGS_SIZE)]; 756 } 757 this.crossingMinY = minY; 758 this.crossingMaxY = maxY; 759 this.crossingMaxXEntries = maxXEntries; 760 resetCrossings(); 761 } 762 763 private void resetCrossings() { 764 int yextent = crossingMaxY - crossingMinY + 1; 765 int start = 0; 766 for (int i = 0; i < yextent; i++) { 767 crossingIndices[i] = start; 768 start += crossingMaxXEntries; 769 } 770 crossingMinX = Integer.MAX_VALUE; 771 crossingMaxX = Integer.MIN_VALUE; 772 numCrossings = 0; 773 crossingsSorted = false; 774 } 775 776 // Free sorting arrays if larger than maximum size 777 private void crossingListFinished() { 778 if (crossings.length > DEFAULT_CROSSINGS_SIZE) { 779 crossings = new int[DEFAULT_CROSSINGS_SIZE]; 780 } 781 if (crossingIndices.length > DEFAULT_INDICES_SIZE) { 782 crossingIndices = new int[DEFAULT_INDICES_SIZE]; 783 } 784 } 785 786 private void sortCrossings(int[] x, int off, int len) { 787 for (int i = off + 1; i < off + len; i++) { 788 int j = i; 789 int xj = x[j]; 790 int xjm1; 791 792 while (j > off && (xjm1 = x[j - 1]) > xj) { 793 x[j] = xjm1; 794 x[j - 1] = xj; 795 j--; 796 } 797 } 798 } 799 800 private void sortCrossings() { 801 int start = 0; 802 for (int i = 0; i <= crossingMaxY - crossingMinY; i++) { 803 sortCrossings(crossings, start, crossingIndices[i] - start); 804 start += crossingMaxXEntries; 805 } 806 } 807 808 private void addCrossing(int y, int x, int orientation) { 809 if (x < crossingMinX) { 810 crossingMinX = x; 811 } 812 if (x > crossingMaxX) { 813 crossingMaxX = x; 814 } 815 816 int index = crossingIndices[y - crossingMinY]++; 817 x <<= 1; 818 crossings[index] = (orientation == 1) ? (x | 0x1) : x; 819 820 ++numCrossings; 821 } 822 823 private void iterateCrossings() { 824 if (!crossingsSorted) { 825 sortCrossings(); 826 crossingsSorted = true; 827 } 828 crossingY = crossingMinY - 1; 829 crossingRowOffset = -crossingMaxXEntries; 830 } 831 832 private boolean hasMoreCrossingRows() { 833 if (++crossingY <= crossingMaxY) { 834 crossingRowOffset += crossingMaxXEntries; 835 int y = crossingY - crossingMinY; 836 crossingRowCount = crossingIndices[y] - y*crossingMaxXEntries; 837 crossingRowIndex = 0; 838 return true; 839 } else { 840 return false; 841 } 842 } 843 }