/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "GraphicsPrimitiveMgr.h"
#include "ParallelogramUtils.h"
#include "sun_java2d_loops_MaskFill.h"
/*
* Class: sun_java2d_loops_MaskFill
* Method: MaskFill
* Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;IIII[BII)V
*/
{
return;
}
}
if (sdOps == 0) {
return;
}
return;
}
{
unsigned char *pMask =
: 0);
if (pMask) {
}
}
}
}
/* Fills an aligned rectangle with potentially translucent edges. */
static void
void *pDst,
{
/* Convert xy12 into the edge coverage fractions for those edges. */
/* Accumulate bottom coverage into top coverage. */
/* prevent processing of "bottom fractional row" */
}
/* Accumulate right coverage into left coverage. */
/* prevent processing of "right fractional column" */
}
/* Check for a visible "top fractional row" and process it */
jint x;
for (x = 0; x < width; x++) {
}
}
}
pMask, 0, 0,
width, 1,
cy1++;
}
/* Check for a visible "left fract, solid middle, right fract" section. */
/* First process the left "fractional column" if it is visible. */
/* Note: maskscan == 0 means we reuse this value for every row. */
pMask, 0, 0,
1, midh,
midx++;
}
/* Process the central solid section if it is visible. */
/* A NULL mask buffer means "all coverages are 0xff" */
NULL, 0, 0,
}
/* Finally process the right "fractional column" if it is visible. */
/* Note: maskscan == 0 means we reuse this value for every row. */
pMask, 0, 0,
1, midh,
}
}
/* Check for a visible "bottom fractional row" and process it */
jint x;
for (x = 0; x < width; x++) {
}
}
}
pMask, 0, 0,
width, 1,
}
}
/*
* Support code for arbitrary tracing and MaskFill filling of
* non-rectilinear (diagonal) parallelograms.
*
* This code is based upon the following model of AA coverage.
*
* Each edge of a parallelogram (for fillPgram) or a double
* parallelogram (inner and outer parallelograms for drawPgram)
* can be rasterized independently because the geometry is well
* defined in such a way that none of the sides will ever cross
* each other and they have a fixed ordering that is fairly
* well predetermined.
*
* So, for each edge we will look at the diagonal line that
* the edge makes as it passes through a row of pixels. Some
* such diagonal lines may pass entirely through the row of
* pixels in a single pixel column. Some may cut across the
* row and pass through several pixel columns before they pass
* on to the next row.
*
* As the edge passes through the row of pixels it will affect
* the coverage of the pixels it passes through as well as all
* of the pixels to the right of the edge. The coverage will
* either be increased (by a left edge of a parallelogram) or
* decreased (by a right edge) for all pixels to the right, until
* another edge passing the opposite direction is encountered.
*
* The coverage added or subtracted by an edge as it crosses a
* given pixel is calculated using a trapezoid formula in the
* following manner:
*
* /
* +-----+---/-+-----+
* | | / | |
* | | / | |
* +-----+/----+-----+
* /
*
* The area to the right of that edge for the pixel where it
* crosses is given as:
*
* trapheight * (topedge + bottomedge)/2
*
* Another thing to note is that the above formula gives the
* contribution of that edge to the given pixel where it crossed,
* but in so crossing the pixel row, it also created 100% coverage
* for all of the pixels to the right.
*
* This example was simplified in that the edge depicted crossed
* the complete pixel row and it did so entirely within the bounds
* of a single pixel column. In practice, many edges may start or
* end in a given row and thus provide only partial row coverage
* (i.e. the total "trapheight" in the formula never reaches 1.0).
* And in other cases, edges may travel sideways through several
* pixel columns on a given pixel row from where they enter it to
* where the leave it (which also mans that the trapheight for a
* given pixel will be less than 1.0, but by the time the edge
* completes its journey through the pixel row the "coverage shadow"
* that it casts on all pixels to the right eventually reaches 100%).
*
* In order to simplify the calculations so that we don't have to
* keep propagating coverages we calculate for one edge "until we
* reach another edge" we will process one edge at a time and
* simply record in a buffer the amount that an edge added to
* or subtracted from the coverage for a given pixel and its
* following right-side neighbors. Thus, the true total coverage
* of a given pixel is only determined by summing the deltas for
* that pixel and all of the pixels to its left. Since we already
* have to scan the buffer to change floating point coverages into
* mask values for a MaskFill loop, it is simple enough to sum the
* values as we perform that scan from left to right.
*
* In the above example, note that 2 deltas need to be recorded even
* though the edge only intersected a single pixel. The delta recorded
* for the pixel where the edge crossed will be approximately 55%
* (guesstimating by examining the poor ascii art) which is fine for
* determining how to render that pixel, but the rest of the pixels
* to its right should have their coverage modified by a full 100%
* and the 55% delta value we recorded for the pixel that the edge
* crossed will not get them there. We adjust for this by adding
* the "remainder" of the coverage implied by the shadow to the
* pixel immediately to the right of where we record a trapezoidal
* contribution. In this case a delta of 45% will be recorded in
* the pixel immediately to the right to raise the total to 100%.
*
* As we sum these delta values as we process the line from left
* to right, these delta values will typically drive the sum from
* 0% up to 100% and back down to 0% over the course of a single
* pixel row. In the case of a drawn (double) parallelogram the
* sum will go to 100% and back to 0% twice on most scanlines.
*
* The fillAAPgram and drawAAPgram functions drive the main flow
* of the algorithm with help from the following structures,
* macros, and functions. It is probably best to start with
* those 2 functions to gain an understanding of the algorithm.
*/
typedef struct {
jdouble x;
jdouble y;
} EdgeInfo;
/*
* Calculates slopes and deltas for an edge and stores results in an EdgeInfo.
* Returns true if the edge was valid (i.e. not ignored for some reason).
*/
static jboolean
{
pEdge->x = x;
pEdge->y = y;
/* Note that parallelograms are sorted so dy is always non-negative */
y < cy2 && /* NaN and "OUT_BELOW" protection */
/* Note: "OUT_LEFT" segments may still contribute coverage... */
{
/* no NaNs, dy is not horizontal, and segment contributes to clip */
/* dx is not vertical */
if (y < cy1) {
}
if (dx < 0) {
} else {
}
} else {
/* dx is essentially vertical */
if (y < cy1) {
}
}
} else {
/* There is some reason to ignore this segment, "celldy=0" omits it */
}
return ret;
}
/*
* Calculates and stores slopes and deltas for all edges of a parallelogram.
* Returns true if at least 1 edge was valid (i.e. not ignored for some reason).
*
* The inverted flag is true for an outer parallelogram (left and right
* edges are leading and trailing) and false for an inner parallelogram
* (where the left edge is trailing and the right edge is leading).
*/
static jboolean
{
return ret;
}
/*
* The X0,Y0,X1,Y1 values represent a trapezoidal fragment whose
* coverage must be accounted for in the accum buffer.
*
* All four values are assumed to fall within (or on the edge of)
* a single pixel.
*
* The trapezoid area is accumulated into the proper element of
* the accum buffer and the remainder of the "slice height" is
* accumulated into the element to its right.
*/
do { \
jint i; \
/* Accumulate the entire slice height into accum[0]. */ \
i = 0; \
} else { \
} \
if (IMIN > i) { \
IMIN = i; \
} \
if (IMAX < i) { \
IMAX = i; \
} \
} \
} while (0)
/*
* Accumulate the contributions for a given edge crossing a given
* scan line into the corresponding entries of the accum buffer.
* CY1 is the Y coordinate of the top edge of the scanline and CY2
* is equal to (CY1 + 1) and is the Y coordinate of the bottom edge
* of the scanline. CX1 and CX2 are the left and right edges of the
* clip (or area of interest) being rendered.
*
* The edge is processed from the top edge to the bottom edge and
* a single pixel column at a time.
*/
do { \
y = (pEDGE)->y; \
break; \
} \
x = (pEDGE)->x; \
} else { \
} \
x = xnext; \
y = ynext; \
} \
} while(0)
/* Main function to fill a single Parallelogram */
static void
void *pDst,
{
{
return;
}
: localaccum);
return;
}
unsigned char lastcov;
}
}
/* If ranges overlap, handle both in the first pass. */
}
x = lmin;
accum = 0.0;
moff = 0;
lastcov = 0;
while (x < lmax) {
pAccum[x] = 0.0f;
x++;
}
/* Check for a solid center section. */
if (lastcov == 0xFF) {
void *pRow;
/* First process the existing partial coverage data. */
if (moff > 0) {
pMask, 0, 0,
moff, 1,
moff = 0;
}
/* Where does the center section end? */
/* If there is no right AA edge in the accum buffer, then */
/* the right edge was beyond the clip, so fill out to width */
if (x < endx) {
NULL, 0, 0,
endx - x, 1,
x = endx;
}
/* We are not at 0 coverage, but there is no right edge, */
/* force a right edge so we process pixels out to width. */
}
/* partial coverage center section not processed above. */
while (x < rmax) {
pAccum[x] = 0.0f;
x++;
}
if (moff > 0) {
pMask, 0, 0,
moff, 1,
}
cy1++;
}
if (pAccum != localaccum) {
}
}
/*
* Class: sun_java2d_loops_MaskFill
* Method: FillAAPgram
* Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;DDDDDD)V
*/
{
return;
}
/*
* Sort parallelogram by y values, ensure that each delta vector
* has a non-negative y delta.
*/
return;
}
}
if (sdOps == 0) {
return;
}
{
return;
}
return;
}
: localmask);
if (dx1 < 0) {
// We sorted by Y above, but not by X
}
if (dx2 < 0) {
// We sorted by Y above, but not by X
}
} else {
}
}
}
}
}
/* Main function to fill a double pair of (inner and outer) parallelograms */
static void
void *pDst,
{
{
/* If outer pgram does not contribute, then inner cannot either. */
return;
}
JNI_TRUE);
: localaccum);
return;
}
unsigned char lastcov;
}
}
/* If ranges overlap, handle both in the first pass. */
}
x = lmin;
accum = 0.0;
moff = 0;
lastcov = 0;
while (x < lmax) {
pAccum[x] = 0.0f;
x++;
}
/* Check for an empty or solidcenter section. */
void *pRow;
/* First process the existing partial coverage data. */
if (moff > 0) {
pMask, 0, 0,
moff, 1,
moff = 0;
}
/* Where does the center section end? */
/* If there is no right AA edge in the accum buffer, then */
/* the right edge was beyond the clip, so fill out to width */
if (x < endx) {
if (lastcov == 0xFF) {
NULL, 0, 0,
endx - x, 1,
}
x = endx;
}
/* We are not at 0 coverage, but there is no right edge, */
/* force a right edge so we process pixels out to width. */
}
/* partial coverage center section not processed above. */
while (x < rmax) {
pAccum[x] = 0.0f;
x++;
}
if (moff > 0) {
pMask, 0, 0,
moff, 1,
}
NULL, 0, 0,
width - x, 1,
}
cy1++;
}
if (pAccum != localaccum) {
}
}
/*
* Class: sun_java2d_loops_MaskFill
* Method: DrawAAPgram
* Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;DDDDDDDD)V
*/
{
return;
}
/*
* Sort parallelogram by y values, ensure that each delta vector
* has a non-negative y delta.
*/
// dx,dy for line width in the "1" and "2" directions.
// calculate origin of the outer parallelogram
/* Only need to fill an outer pgram if the interior no longer
* has a hole in it (i.e. if either of the line width ratios
* were greater than or equal to 1.0).
*/
return;
}
return;
}
}
if (sdOps == 0) {
return;
}
{
return;
}
return;
}
: localmask);
/*
* NOTE: aligned rects could probably be drawn
* even faster with a little work here.
* if (dy1 == 0 && dx2 == 0) {
* drawAARect(pPrim, &rasInfo, &compInfo,
* color, pMask, pDst,
* ox0, oy0, ox0+dx1+ldx1, oy0+dy2+ldy2, ldx1, ldy2);
* } else if (dx1 == 0 && dy2 == 0) {
* drawAARect(pPrim, &rasInfo, &compInfo,
* color, pMask, pDst,
* ox0, oy0, ox0+dx2+ldx2, oy0+dy1+ldy1, ldx2, ldy1);
* } else {
*/
/*
* }
*/
}
}
}
}