--- a/src/java.desktop/share/classes/sun/java2d/pisces/Renderer.java Fri Nov 24 17:19:47 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,571 +0,0 @@
-/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.java2d.pisces;
-
-import sun.awt.geom.PathConsumer2D;
-
-final class Renderer implements PathConsumer2D {
-
- private class ScanlineIterator {
-
- private int[] crossings;
-
- // crossing bounds. The bounds are not necessarily tight (the scan line
- // at minY, for example, might have no crossings). The x bounds will
- // be accumulated as crossings are computed.
- private final int maxY;
- private int nextY;
-
- // indices into the segment pointer lists. They indicate the "active"
- // sublist in the segment lists (the portion of the list that contains
- // all the segments that cross the next scan line).
- private int edgeCount;
- private int[] edgePtrs;
-
- private static final int INIT_CROSSINGS_SIZE = 10;
-
- // Preconditions: Only subpixel scanlines in the range
- // (start <= subpixel_y <= end) will be evaluated. No
- // edge may have a valid (i.e. inside the supplied clip)
- // crossing that would be generated outside that range.
- private ScanlineIterator(int start, int end) {
- crossings = new int[INIT_CROSSINGS_SIZE];
- edgePtrs = new int[INIT_CROSSINGS_SIZE];
-
- nextY = start;
- maxY = end;
- edgeCount = 0;
- }
-
- private int next() {
- int cury = nextY++;
- int bucket = cury - boundsMinY;
- int count = this.edgeCount;
- int ptrs[] = this.edgePtrs;
- int bucketcount = edgeBucketCounts[bucket];
- if ((bucketcount & 0x1) != 0) {
- int newCount = 0;
- for (int i = 0; i < count; i++) {
- int ecur = ptrs[i];
- if (edges[ecur+YMAX] > cury) {
- ptrs[newCount++] = ecur;
- }
- }
- count = newCount;
- }
- ptrs = Helpers.widenArray(ptrs, count, bucketcount >> 1);
- for (int ecur = edgeBuckets[bucket]; ecur != NULL; ecur = (int)edges[ecur+NEXT]) {
- ptrs[count++] = ecur;
- // REMIND: Adjust start Y if necessary
- }
- this.edgePtrs = ptrs;
- this.edgeCount = count;
-// if ((count & 0x1) != 0) {
-// System.out.println("ODD NUMBER OF EDGES!!!!");
-// }
- int xings[] = this.crossings;
- if (xings.length < count) {
- this.crossings = xings = new int[ptrs.length];
- }
- for (int i = 0; i < count; i++) {
- int ecur = ptrs[i];
- float curx = edges[ecur+CURX];
- int cross = ((int) curx) << 1;
- edges[ecur+CURX] = curx + edges[ecur+SLOPE];
- if (edges[ecur+OR] > 0) {
- cross |= 1;
- }
- int j = i;
- while (--j >= 0) {
- int jcross = xings[j];
- if (jcross <= cross) {
- break;
- }
- xings[j+1] = jcross;
- ptrs[j+1] = ptrs[j];
- }
- xings[j+1] = cross;
- ptrs[j+1] = ecur;
- }
- return count;
- }
-
- private boolean hasNext() {
- return nextY < maxY;
- }
-
- private int curY() {
- return nextY - 1;
- }
- }
-
-
-//////////////////////////////////////////////////////////////////////////////
-// EDGE LIST
-//////////////////////////////////////////////////////////////////////////////
-// TODO(maybe): very tempting to use fixed point here. A lot of opportunities
-// for shifts and just removing certain operations altogether.
-
- // common to all types of input path segments.
- private static final int YMAX = 0;
- private static final int CURX = 1;
- // NEXT and OR are meant to be indices into "int" fields, but arrays must
- // be homogenous, so every field is a float. However floats can represent
- // exactly up to 26 bit ints, so we're ok.
- private static final int OR = 2;
- private static final int SLOPE = 3;
- private static final int NEXT = 4;
-
- private float edgeMinY = Float.POSITIVE_INFINITY;
- private float edgeMaxY = Float.NEGATIVE_INFINITY;
- private float edgeMinX = Float.POSITIVE_INFINITY;
- private float edgeMaxX = Float.NEGATIVE_INFINITY;
-
- private static final int SIZEOF_EDGE = 5;
- // don't just set NULL to -1, because we want NULL+NEXT to be negative.
- private static final int NULL = -SIZEOF_EDGE;
- private float[] edges = null;
- private static final int INIT_NUM_EDGES = 8;
- private int[] edgeBuckets = null;
- private int[] edgeBucketCounts = null; // 2*newedges + (1 if pruning needed)
- private int numEdges;
-
- private static final float DEC_BND = 20f;
- private static final float INC_BND = 8f;
-
- // each bucket is a linked list. this method adds eptr to the
- // start of the "bucket"th linked list.
- private void addEdgeToBucket(final int eptr, final int bucket) {
- edges[eptr+NEXT] = edgeBuckets[bucket];
- edgeBuckets[bucket] = eptr;
- edgeBucketCounts[bucket] += 2;
- }
-
- // Flattens using adaptive forward differencing. This only carries out
- // one iteration of the AFD loop. All it does is update AFD variables (i.e.
- // X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
- private void quadBreakIntoLinesAndAdd(float x0, float y0,
- final Curve c,
- final float x2, final float y2)
- {
- final float QUAD_DEC_BND = 32;
- final int countlg = 4;
- int count = 1 << countlg;
- int countsq = count * count;
- float maxDD = Math.max(c.dbx / countsq, c.dby / countsq);
- while (maxDD > QUAD_DEC_BND) {
- maxDD /= 4;
- count <<= 1;
- }
-
- countsq = count * count;
- final float ddx = c.dbx / countsq;
- final float ddy = c.dby / countsq;
- float dx = c.bx / countsq + c.cx / count;
- float dy = c.by / countsq + c.cy / count;
-
- while (count-- > 1) {
- float x1 = x0 + dx;
- dx += ddx;
- float y1 = y0 + dy;
- dy += ddy;
- addLine(x0, y0, x1, y1);
- x0 = x1;
- y0 = y1;
- }
- addLine(x0, y0, x2, y2);
- }
-
- // x0, y0 and x3,y3 are the endpoints of the curve. We could compute these
- // using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce
- // numerical errors, and our callers already have the exact values.
- // Another alternative would be to pass all the control points, and call c.set
- // here, but then too many numbers are passed around.
- private void curveBreakIntoLinesAndAdd(float x0, float y0,
- final Curve c,
- final float x3, final float y3)
- {
- final int countlg = 3;
- int count = 1 << countlg;
-
- // the dx and dy refer to forward differencing variables, not the last
- // coefficients of the "points" polynomial
- float dddx, dddy, ddx, ddy, dx, dy;
- dddx = 2f * c.dax / (1 << (3 * countlg));
- dddy = 2f * c.day / (1 << (3 * countlg));
-
- ddx = dddx + c.dbx / (1 << (2 * countlg));
- ddy = dddy + c.dby / (1 << (2 * countlg));
- dx = c.ax / (1 << (3 * countlg)) + c.bx / (1 << (2 * countlg)) + c.cx / (1 << countlg);
- dy = c.ay / (1 << (3 * countlg)) + c.by / (1 << (2 * countlg)) + c.cy / (1 << countlg);
-
- // we use x0, y0 to walk the line
- float x1 = x0, y1 = y0;
- while (count > 0) {
- while (Math.abs(ddx) > DEC_BND || Math.abs(ddy) > DEC_BND) {
- dddx /= 8;
- dddy /= 8;
- ddx = ddx/4 - dddx;
- ddy = ddy/4 - dddy;
- dx = (dx - ddx) / 2;
- dy = (dy - ddy) / 2;
- count <<= 1;
- }
- // can only do this on even "count" values, because we must divide count by 2
- while (count % 2 == 0 && Math.abs(dx) <= INC_BND && Math.abs(dy) <= INC_BND) {
- dx = 2 * dx + ddx;
- dy = 2 * dy + ddy;
- ddx = 4 * (ddx + dddx);
- ddy = 4 * (ddy + dddy);
- dddx = 8 * dddx;
- dddy = 8 * dddy;
- count >>= 1;
- }
- count--;
- if (count > 0) {
- x1 += dx;
- dx += ddx;
- ddx += dddx;
- y1 += dy;
- dy += ddy;
- ddy += dddy;
- } else {
- x1 = x3;
- y1 = y3;
- }
- addLine(x0, y0, x1, y1);
- x0 = x1;
- y0 = y1;
- }
- }
-
- private void addLine(float x1, float y1, float x2, float y2) {
- float or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
- if (y2 < y1) {
- or = y2; // no need to declare a temp variable. We have or.
- y2 = y1;
- y1 = or;
- or = x2;
- x2 = x1;
- x1 = or;
- or = 0;
- }
- final int firstCrossing = Math.max((int)Math.ceil(y1), boundsMinY);
- final int lastCrossing = Math.min((int)Math.ceil(y2), boundsMaxY);
- if (firstCrossing >= lastCrossing) {
- return;
- }
- if (y1 < edgeMinY) { edgeMinY = y1; }
- if (y2 > edgeMaxY) { edgeMaxY = y2; }
-
- final float slope = (x2 - x1) / (y2 - y1);
-
- if (slope > 0) { // <==> x1 < x2
- if (x1 < edgeMinX) { edgeMinX = x1; }
- if (x2 > edgeMaxX) { edgeMaxX = x2; }
- } else {
- if (x2 < edgeMinX) { edgeMinX = x2; }
- if (x1 > edgeMaxX) { edgeMaxX = x1; }
- }
-
- final int ptr = numEdges * SIZEOF_EDGE;
- edges = Helpers.widenArray(edges, ptr, SIZEOF_EDGE);
- numEdges++;
- edges[ptr+OR] = or;
- edges[ptr+CURX] = x1 + (firstCrossing - y1) * slope;
- edges[ptr+SLOPE] = slope;
- edges[ptr+YMAX] = lastCrossing;
- final int bucketIdx = firstCrossing - boundsMinY;
- addEdgeToBucket(ptr, bucketIdx);
- edgeBucketCounts[lastCrossing - boundsMinY] |= 1;
- }
-
-// END EDGE LIST
-//////////////////////////////////////////////////////////////////////////////
-
-
- public static final int WIND_EVEN_ODD = 0;
- public static final int WIND_NON_ZERO = 1;
-
- // Antialiasing
- private final int SUBPIXEL_LG_POSITIONS_X;
- private final int SUBPIXEL_LG_POSITIONS_Y;
- private final int SUBPIXEL_POSITIONS_X;
- private final int SUBPIXEL_POSITIONS_Y;
- private final int SUBPIXEL_MASK_X;
- private final int SUBPIXEL_MASK_Y;
- final int MAX_AA_ALPHA;
-
- // Cache to store RLE-encoded coverage mask of the current primitive
- PiscesCache cache;
-
- // Bounds of the drawing region, at subpixel precision.
- private final int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
-
- // Current winding rule
- private final int windingRule;
-
- // Current drawing position, i.e., final point of last segment
- private float x0, y0;
-
- // Position of most recent 'moveTo' command
- private float pix_sx0, pix_sy0;
-
- public Renderer(int subpixelLgPositionsX, int subpixelLgPositionsY,
- int pix_boundsX, int pix_boundsY,
- int pix_boundsWidth, int pix_boundsHeight,
- int windingRule)
- {
- this.SUBPIXEL_LG_POSITIONS_X = subpixelLgPositionsX;
- this.SUBPIXEL_LG_POSITIONS_Y = subpixelLgPositionsY;
- this.SUBPIXEL_MASK_X = (1 << (SUBPIXEL_LG_POSITIONS_X)) - 1;
- this.SUBPIXEL_MASK_Y = (1 << (SUBPIXEL_LG_POSITIONS_Y)) - 1;
- this.SUBPIXEL_POSITIONS_X = 1 << (SUBPIXEL_LG_POSITIONS_X);
- this.SUBPIXEL_POSITIONS_Y = 1 << (SUBPIXEL_LG_POSITIONS_Y);
- this.MAX_AA_ALPHA = (SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_Y);
-
- this.windingRule = windingRule;
-
- this.boundsMinX = pix_boundsX * SUBPIXEL_POSITIONS_X;
- this.boundsMinY = pix_boundsY * SUBPIXEL_POSITIONS_Y;
- this.boundsMaxX = (pix_boundsX + pix_boundsWidth) * SUBPIXEL_POSITIONS_X;
- this.boundsMaxY = (pix_boundsY + pix_boundsHeight) * SUBPIXEL_POSITIONS_Y;
-
- edges = new float[INIT_NUM_EDGES * SIZEOF_EDGE];
- numEdges = 0;
- edgeBuckets = new int[boundsMaxY - boundsMinY];
- java.util.Arrays.fill(edgeBuckets, NULL);
- edgeBucketCounts = new int[edgeBuckets.length + 1];
- }
-
- private float tosubpixx(float pix_x) {
- return pix_x * SUBPIXEL_POSITIONS_X;
- }
- private float tosubpixy(float pix_y) {
- return pix_y * SUBPIXEL_POSITIONS_Y;
- }
-
- public void moveTo(float pix_x0, float pix_y0) {
- closePath();
- this.pix_sx0 = pix_x0;
- this.pix_sy0 = pix_y0;
- this.y0 = tosubpixy(pix_y0);
- this.x0 = tosubpixx(pix_x0);
- }
-
- public void lineTo(float pix_x1, float pix_y1) {
- float x1 = tosubpixx(pix_x1);
- float y1 = tosubpixy(pix_y1);
- addLine(x0, y0, x1, y1);
- x0 = x1;
- y0 = y1;
- }
-
- private Curve c = new Curve();
- @Override public void curveTo(float x1, float y1,
- float x2, float y2,
- float x3, float y3)
- {
- final float xe = tosubpixx(x3);
- final float ye = tosubpixy(y3);
- c.set(x0, y0, tosubpixx(x1), tosubpixy(y1), tosubpixx(x2), tosubpixy(y2), xe, ye);
- curveBreakIntoLinesAndAdd(x0, y0, c, xe, ye);
- x0 = xe;
- y0 = ye;
- }
-
- @Override public void quadTo(float x1, float y1, float x2, float y2) {
- final float xe = tosubpixx(x2);
- final float ye = tosubpixy(y2);
- c.set(x0, y0, tosubpixx(x1), tosubpixy(y1), xe, ye);
- quadBreakIntoLinesAndAdd(x0, y0, c, xe, ye);
- x0 = xe;
- y0 = ye;
- }
-
- public void closePath() {
- // lineTo expects its input in pixel coordinates.
- lineTo(pix_sx0, pix_sy0);
- }
-
- public void pathDone() {
- closePath();
- }
-
-
- @Override
- public long getNativeConsumer() {
- throw new InternalError("Renderer does not use a native consumer.");
- }
-
- private void _endRendering(final int pix_bboxx0, final int pix_bboxx1,
- int ymin, int ymax)
- {
- // Mask to determine the relevant bit of the crossing sum
- // 0x1 if EVEN_ODD, all bits if NON_ZERO
- int mask = (windingRule == WIND_EVEN_ODD) ? 0x1 : ~0x0;
-
- // add 2 to better deal with the last pixel in a pixel row.
- int width = pix_bboxx1 - pix_bboxx0;
- int[] alpha = new int[width+2];
-
- int bboxx0 = pix_bboxx0 << SUBPIXEL_LG_POSITIONS_X;
- int bboxx1 = pix_bboxx1 << SUBPIXEL_LG_POSITIONS_X;
-
- // Now we iterate through the scanlines. We must tell emitRow the coord
- // of the first non-transparent pixel, so we must keep accumulators for
- // the first and last pixels of the section of the current pixel row
- // that we will emit.
- // We also need to accumulate pix_bbox*, but the iterator does it
- // for us. We will just get the values from it once this loop is done
- int pix_maxX = Integer.MIN_VALUE;
- int pix_minX = Integer.MAX_VALUE;
-
- int y = boundsMinY; // needs to be declared here so we emit the last row properly.
- ScanlineIterator it = this.new ScanlineIterator(ymin, ymax);
- for ( ; it.hasNext(); ) {
- int numCrossings = it.next();
- int[] crossings = it.crossings;
- y = it.curY();
-
- if (numCrossings > 0) {
- int lowx = crossings[0] >> 1;
- int highx = crossings[numCrossings - 1] >> 1;
- int x0 = Math.max(lowx, bboxx0);
- int x1 = Math.min(highx, bboxx1);
-
- pix_minX = Math.min(pix_minX, x0 >> SUBPIXEL_LG_POSITIONS_X);
- pix_maxX = Math.max(pix_maxX, x1 >> SUBPIXEL_LG_POSITIONS_X);
- }
-
- int sum = 0;
- int prev = bboxx0;
- for (int i = 0; i < numCrossings; i++) {
- int curxo = crossings[i];
- int curx = curxo >> 1;
- // to turn {0, 1} into {-1, 1}, multiply by 2 and subtract 1.
- int crorientation = ((curxo & 0x1) << 1) - 1;
- if ((sum & mask) != 0) {
- int x0 = Math.max(prev, bboxx0);
- int x1 = Math.min(curx, bboxx1);
- if (x0 < x1) {
- x0 -= bboxx0; // turn x0, x1 from coords to indeces
- x1 -= bboxx0; // in the alpha array.
-
- int pix_x = x0 >> SUBPIXEL_LG_POSITIONS_X;
- int pix_xmaxm1 = (x1 - 1) >> SUBPIXEL_LG_POSITIONS_X;
-
- if (pix_x == pix_xmaxm1) {
- // Start and end in same pixel
- alpha[pix_x] += (x1 - x0);
- alpha[pix_x+1] -= (x1 - x0);
- } else {
- int pix_xmax = x1 >> SUBPIXEL_LG_POSITIONS_X;
- alpha[pix_x] += SUBPIXEL_POSITIONS_X - (x0 & SUBPIXEL_MASK_X);
- alpha[pix_x+1] += (x0 & SUBPIXEL_MASK_X);
- alpha[pix_xmax] -= SUBPIXEL_POSITIONS_X - (x1 & SUBPIXEL_MASK_X);
- alpha[pix_xmax+1] -= (x1 & SUBPIXEL_MASK_X);
- }
- }
- }
- sum += crorientation;
- prev = curx;
- }
-
- // even if this last row had no crossings, alpha will be zeroed
- // from the last emitRow call. But this doesn't matter because
- // maxX < minX, so no row will be emitted to the cache.
- if ((y & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) {
- emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX);
- pix_minX = Integer.MAX_VALUE;
- pix_maxX = Integer.MIN_VALUE;
- }
- }
-
- // Emit final row
- if (pix_maxX >= pix_minX) {
- emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX);
- }
- }
-
- public void endRendering() {
- int spminX = Math.max((int)Math.ceil(edgeMinX), boundsMinX);
- int spmaxX = Math.min((int)Math.ceil(edgeMaxX), boundsMaxX);
- int spminY = Math.max((int)Math.ceil(edgeMinY), boundsMinY);
- int spmaxY = Math.min((int)Math.ceil(edgeMaxY), boundsMaxY);
-
- int pminX = spminX >> SUBPIXEL_LG_POSITIONS_X;
- int pmaxX = (spmaxX + SUBPIXEL_MASK_X) >> SUBPIXEL_LG_POSITIONS_X;
- int pminY = spminY >> SUBPIXEL_LG_POSITIONS_Y;
- int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y;
-
- if (pminX > pmaxX || pminY > pmaxY) {
- this.cache = new PiscesCache(boundsMinX >> SUBPIXEL_LG_POSITIONS_X,
- boundsMinY >> SUBPIXEL_LG_POSITIONS_Y,
- boundsMaxX >> SUBPIXEL_LG_POSITIONS_X,
- boundsMaxY >> SUBPIXEL_LG_POSITIONS_Y);
- return;
- }
-
- this.cache = new PiscesCache(pminX, pminY, pmaxX, pmaxY);
- _endRendering(pminX, pmaxX, spminY, spmaxY);
- }
-
- public PiscesCache getCache() {
- if (cache == null) {
- throw new InternalError("cache not yet initialized");
- }
- return cache;
- }
-
- private void emitRow(int[] alphaRow, int pix_y, int pix_from, int pix_to) {
- // Copy rowAA data into the cache if one is present
- if (cache != null) {
- if (pix_to >= pix_from) {
- cache.startRow(pix_y, pix_from);
-
- // Perform run-length encoding and store results in the cache
- int from = pix_from - cache.bboxX0;
- int to = pix_to - cache.bboxX0;
-
- int runLen = 1;
- int startVal = alphaRow[from];
- for (int i = from + 1; i <= to; i++) {
- int nextVal = startVal + alphaRow[i];
- if (nextVal == startVal) {
- runLen++;
- } else {
- cache.addRLERun(startVal, runLen);
- runLen = 1;
- startVal = nextVal;
- }
- }
- cache.addRLERun(startVal, runLen);
- }
- }
- java.util.Arrays.fill(alphaRow, 0);
- }
-}