alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (MaskFill.c)

This example Java source code file (MaskFill.c) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

accum_edge, compositeinfo, cx1, cx2, dbltomask, imax, imin, jni_true, mask_buf_len, min_delta, null, ptrcoord, surfacedata_invokeunlock, surfacedatarasinfo

The MaskFill.c Java example source code

/*
 * Copyright (c) 2000, 2013, 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.
 */

#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
 */
JNIEXPORT void JNICALL
Java_sun_java2d_loops_MaskFill_MaskFill
    (JNIEnv *env, jobject self,
     jobject sg2d, jobject sData, jobject comp,
     jint x, jint y, jint w, jint h,
     jbyteArray maskArray, jint maskoff, jint maskscan)
{
    SurfaceDataOps *sdOps;
    SurfaceDataRasInfo rasInfo;
    NativePrimitive *pPrim;
    CompositeInfo compInfo;

    pPrim = GetNativePrim(env, self);
    if (pPrim == NULL) {
        return;
    }
    if (pPrim->pCompType->getCompInfo != NULL) {
        (*pPrim->pCompType->getCompInfo)(env, &compInfo, comp);
    }

    sdOps = SurfaceData_GetOps(env, sData);
    if (sdOps == 0) {
        return;
    }

    rasInfo.bounds.x1 = x;
    rasInfo.bounds.y1 = y;
    rasInfo.bounds.x2 = x + w;
    rasInfo.bounds.y2 = y + h;
    if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {
        return;
    }

    if (rasInfo.bounds.x2 > rasInfo.bounds.x1 &&
        rasInfo.bounds.y2 > rasInfo.bounds.y1)
    {
        jint color = GrPrim_Sg2dGetEaRGB(env, sg2d);
        sdOps->GetRasInfo(env, sdOps, &rasInfo);
        if (rasInfo.rasBase) {
            jint width = rasInfo.bounds.x2 - rasInfo.bounds.x1;
            jint height = rasInfo.bounds.y2 - rasInfo.bounds.y1;
            void *pDst = PtrCoord(rasInfo.rasBase,
                                  rasInfo.bounds.x1, rasInfo.pixelStride,
                                  rasInfo.bounds.y1, rasInfo.scanStride);
            unsigned char *pMask =
                (maskArray
                 ? (*env)->GetPrimitiveArrayCritical(env, maskArray, 0)
                 : 0);
            if (maskArray != NULL && pMask == NULL) {
                SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
                SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
                return;
            }
            maskoff += ((rasInfo.bounds.y1 - y) * maskscan +
                        (rasInfo.bounds.x1 - x));
            (*pPrim->funcs.maskfill)(pDst,
                                     pMask, maskoff, maskscan,
                                     width, height,
                                     color, &rasInfo,
                                     pPrim, &compInfo);
            if (pMask) {
                (*env)->ReleasePrimitiveArrayCritical(env, maskArray,
                                                      pMask, JNI_ABORT);
            }
        }
        SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
   }
   SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
}

#define MASK_BUF_LEN 1024

#define DblToMask(v) ((unsigned char) ((v)*255.9999))

/* Fills an aligned rectangle with potentially translucent edges. */
static void
fillAARect(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo,
           CompositeInfo *pCompInfo, jint color, unsigned char *pMask,
           void *pDst,
           jdouble x1, jdouble y1, jdouble x2, jdouble y2)
{
    jint cx1 = pRasInfo->bounds.x1;
    jint cy1 = pRasInfo->bounds.y1;
    jint cx2 = pRasInfo->bounds.x2;
    jint cy2 = pRasInfo->bounds.y2;
    jint rx1 = (jint) ceil(x1);
    jint ry1 = (jint) ceil(y1);
    jint rx2 = (jint) floor(x2);
    jint ry2 = (jint) floor(y2);
    jint width = cx2 - cx1;
    jint scan = pRasInfo->scanStride;
    /* Convert xy12 into the edge coverage fractions for those edges. */
    x1 = rx1-x1;
    y1 = ry1-y1;
    x2 = x2-rx2;
    y2 = y2-ry2;
    if (ry2 < ry1) {
        /* Accumulate bottom coverage into top coverage. */
        y1 = y1 + y2 - 1.0;
        /* prevent processing of "bottom fractional row" */
        ry2 = cy2;
    }
    if (rx2 < rx1) {
        /* Accumulate right coverage into left coverage. */
        x1 = x1 + x2 - 1.0;
        /* prevent processing of "right fractional column" */
        rx2 = cx2;
    }
    /* Check for a visible "top fractional row" and process it */
    if (cy1 < ry1) {
        unsigned char midcov = DblToMask(y1);
        jint x;
        for (x = 0; x < width; x++) {
            pMask[x] = midcov;
        }
        if (cx1 < rx1) {
            pMask[0] = DblToMask(y1 * x1);
        }
        if (cx2 > rx2) {
            pMask[width-1] = DblToMask(y1 * x2);
        }
        (*pPrim->funcs.maskfill)(pDst,
                                 pMask, 0, 0,
                                 width, 1,
                                 color, pRasInfo,
                                 pPrim, pCompInfo);
        pDst = PtrAddBytes(pDst, scan);
        cy1++;
    }
    /* Check for a visible "left fract, solid middle, right fract" section. */
    if (cy1 < ry2 && cy1 < cy2) {
        jint midh = ((ry2 < cy2) ? ry2 : cy2) - cy1;
        jint midx = cx1;
        void *pMid = pDst;
        /* First process the left "fractional column" if it is visible. */
        if (midx < rx1) {
            pMask[0] = DblToMask(x1);
            /* Note: maskscan == 0 means we reuse this value for every row. */
            (*pPrim->funcs.maskfill)(pMid,
                                     pMask, 0, 0,
                                     1, midh,
                                     color, pRasInfo,
                                     pPrim, pCompInfo);
            pMid = PtrAddBytes(pMid, pRasInfo->pixelStride);
            midx++;
        }
        /* Process the central solid section if it is visible. */
        if (midx < rx2 && midx < cx2) {
            jint midw = ((rx2 < cx2) ? rx2 : cx2) - midx;
            /* A NULL mask buffer means "all coverages are 0xff" */
            (*pPrim->funcs.maskfill)(pMid,
                                     NULL, 0, 0,
                                     midw, midh,
                                     color, pRasInfo,
                                     pPrim, pCompInfo);
            pMid = PtrCoord(pMid, midw, pRasInfo->pixelStride, 0, 0);
            midx += midw;
        }
        /* Finally process the right "fractional column" if it is visible. */
        if (midx < cx2) {
            pMask[0] = DblToMask(x2);
            /* Note: maskscan == 0 means we reuse this value for every row. */
            (*pPrim->funcs.maskfill)(pMid,
                                     pMask, 0, 0,
                                     1, midh,
                                     color, pRasInfo,
                                     pPrim, pCompInfo);
        }
        cy1 += midh;
        pDst = PtrCoord(pDst, 0, 0, midh, scan);
    }
    /* Check for a visible "bottom fractional row" and process it */
    if (cy1 < cy2) {
        unsigned char midcov = DblToMask(y2);
        jint x;
        for (x = 0; x < width; x++) {
            pMask[x] = midcov;
        }
        if (cx1 < rx1) {
            pMask[0] = DblToMask(y2 * x1);
        }
        if (cx2 > rx2) {
            pMask[width-1] = DblToMask(y2 * x2);
        }
        (*pPrim->funcs.maskfill)(pDst,
                                 pMask, 0, 0,
                                 width, 1,
                                 color, pRasInfo,
                                 pPrim, pCompInfo);
    }
}

/*
 * 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;
    jdouble xbot;
    jdouble ybot;
    jdouble xnexty;
    jdouble ynextx;
    jdouble xnextx;
    jdouble linedx;
    jdouble celldx;
    jdouble celldy;
    jboolean isTrailing;
} EdgeInfo;

#define MIN_DELTA  (1.0/256.0)

/*
 * 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
storeEdge(EdgeInfo *pEdge,
          jdouble x, jdouble y, jdouble dx, jdouble dy,
          jint cx1, jint cy1, jint cx2, jint cy2,
          jboolean isTrailing)
{
    jdouble xbot = x + dx;
    jdouble ybot = y + dy;
    jboolean ret;

    pEdge->x = x;
    pEdge->y = y;
    pEdge->xbot = xbot;
    pEdge->ybot = ybot;

    /* Note that parallelograms are sorted so dy is always non-negative */
    if (dy > MIN_DELTA &&        /* NaN and horizontal protection */
        ybot > cy1 &&            /* NaN and "OUT_ABOVE" protection */
        y < cy2 &&               /* NaN and "OUT_BELOW" protection */
        xbot == xbot &&          /* NaN protection */
        (x < cx2 || xbot < cx2)) /* "OUT_RIGHT" protection */
        /* Note: "OUT_LEFT" segments may still contribute coverage... */
    {
        /* no NaNs, dy is not horizontal, and segment contributes to clip */
        if (dx < -MIN_DELTA || dx > MIN_DELTA) {
            /* dx is not vertical */
            jdouble linedx;
            jdouble celldy;
            jdouble nextx;

            linedx = dx / dy;
            celldy = dy / dx;
            if (y < cy1) {
                pEdge->x = x = x + (cy1 - y) * linedx;
                pEdge->y = y = cy1;
            }
            pEdge->linedx = linedx;
            if (dx < 0) {
                pEdge->celldx = -1.0;
                pEdge->celldy = -celldy;
                pEdge->xnextx = nextx = ceil(x) - 1.0;
            } else {
                pEdge->celldx = +1.0;
                pEdge->celldy = celldy;
                pEdge->xnextx = nextx = floor(x) + 1.0;
            }
            pEdge->ynextx = y + (nextx - x) * celldy;
            pEdge->xnexty = x + ((floor(y) + 1) - y) * linedx;
        } else {
            /* dx is essentially vertical */
            if (y < cy1) {
                pEdge->y = y = cy1;
            }
            pEdge->xbot = x;
            pEdge->linedx = 0.0;
            pEdge->celldx = 0.0;
            pEdge->celldy = 1.0;
            pEdge->xnextx = x;
            pEdge->xnexty = x;
            pEdge->ynextx = ybot;
        }
        ret = JNI_TRUE;
    } else {
        /* There is some reason to ignore this segment, "celldy=0" omits it */
        pEdge->ybot = y;
        pEdge->linedx = dx;
        pEdge->celldx = dx;
        pEdge->celldy = 0.0;
        pEdge->xnextx = xbot;
        pEdge->xnexty = xbot;
        pEdge->ynextx = y;
        ret = JNI_FALSE;
    }
    pEdge->isTrailing = isTrailing;
    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
storePgram(EdgeInfo *pLeftEdge, EdgeInfo *pRightEdge,
           jdouble x, jdouble y,
           jdouble dx1, jdouble dy1,
           jdouble dx2, jdouble dy2,
           jint cx1, jint cy1, jint cx2, jint cy2,
           jboolean inverted)
{
    jboolean ret = JNI_FALSE;
    ret = (storeEdge(pLeftEdge  + 0,
                     x    , y    , dx1, dy1,
                     cx1, cy1, cx2, cy2, inverted) || ret);
    ret = (storeEdge(pLeftEdge  + 1,
                     x+dx1, y+dy1, dx2, dy2,
                     cx1, cy1, cx2, cy2, inverted) || ret);
    ret = (storeEdge(pRightEdge + 0,
                     x    , y    , dx2, dy2,
                     cx1, cy1, cx2, cy2, !inverted) || ret);
    ret = (storeEdge(pRightEdge + 1,
                     x+dx2, y+dy2, dx1, dy1,
                     cx1, cy1, cx2, cy2, !inverted) || ret);
    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.
 */
#define INSERT_ACCUM(pACCUM, IMIN, IMAX, X0, Y0, X1, Y1, CX1, CX2, MULT) \
    do { \
        jdouble xmid = ((X0) + (X1)) * 0.5; \
        if (xmid <= (CX2)) { \
            jdouble sliceh = ((Y1) - (Y0)); \
            jdouble slicearea; \
            jint i; \
            if (xmid < (CX1)) { \
                /* Accumulate the entire slice height into accum[0]. */ \
                i = 0; \
                slicearea = sliceh; \
            } else { \
                jdouble xpos = floor(xmid); \
                i = ((jint) xpos) - (CX1); \
                slicearea = (xpos+1-xmid) * sliceh; \
            } \
            if (IMIN > i) { \
                IMIN = i; \
            } \
            (pACCUM)[i++] += (jfloat) ((MULT) * slicearea); \
            (pACCUM)[i++] += (jfloat) ((MULT) * (sliceh - slicearea)); \
            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.
 */
#define ACCUM_EDGE(pEDGE, pACCUM, IMIN, IMAX, CX1, CY1, CX2, CY2) \
    do { \
        jdouble x, y, xnext, ynext, xlast, ylast, dx, dy, mult; \
        y = (pEDGE)->y; \
        dy = (pEDGE)->celldy; \
        ylast = (pEDGE)->ybot; \
        if (ylast <= (CY1) || y >= (CY2) || dy == 0.0) { \
            break; \
        } \
        x = (pEDGE)->x; \
        dx = (pEDGE)->celldx; \
        if (ylast > (CY2)) { \
            ylast = (CY2); \
            xlast = (pEDGE)->xnexty; \
        } else { \
            xlast = (pEDGE)->xbot; \
        } \
        xnext = (pEDGE)->xnextx; \
        ynext = (pEDGE)->ynextx; \
        mult = ((pEDGE)->isTrailing) ? -1.0 : 1.0; \
        while (ynext <= ylast) { \
            INSERT_ACCUM(pACCUM, IMIN, IMAX, \
                         x, y, xnext, ynext, \
                         CX1, CX2, mult); \
            x = xnext; \
            y = ynext; \
            xnext += dx; \
            ynext += dy; \
        } \
        (pEDGE)->ynextx = ynext; \
        (pEDGE)->xnextx = xnext; \
        INSERT_ACCUM(pACCUM, IMIN, IMAX, \
                     x, y, xlast, ylast, \
                     CX1, CX2, mult); \
        (pEDGE)->x = xlast; \
        (pEDGE)->y = ylast; \
        (pEDGE)->xnexty = xlast + (pEDGE)->linedx; \
    } while(0)

/* Main function to fill a single Parallelogram */
static void
fillAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo,
            CompositeInfo *pCompInfo, jint color, unsigned char *pMask,
            void *pDst,
            jdouble x1, jdouble y1,
            jdouble dx1, jdouble dy1,
            jdouble dx2, jdouble dy2)
{
    jint cx1 = pRasInfo->bounds.x1;
    jint cy1 = pRasInfo->bounds.y1;
    jint cx2 = pRasInfo->bounds.x2;
    jint cy2 = pRasInfo->bounds.y2;
    jint width = cx2 - cx1;
    EdgeInfo edges[4];
    jfloat localaccum[MASK_BUF_LEN + 1];
    jfloat *pAccum;

    if (!storePgram(edges + 0, edges + 2,
                    x1, y1, dx1, dy1, dx2, dy2,
                    cx1, cy1, cx2, cy2,
                    JNI_FALSE))
    {
        return;
    }

    pAccum = ((width > MASK_BUF_LEN)
              ? malloc((width + 1) * sizeof(jfloat))
              : localaccum);
    if (pAccum == NULL) {
        return;
    }
    memset(pAccum, 0, (width+1) * sizeof(jfloat));

    while (cy1 < cy2) {
        jint lmin, lmax, rmin, rmax;
        jint moff, x;
        jdouble accum;
        unsigned char lastcov;

        lmin = rmin = width + 2;
        lmax = rmax = 0;
        ACCUM_EDGE(&edges[0], pAccum, lmin, lmax,
                   cx1, cy1, cx2, cy1+1);
        ACCUM_EDGE(&edges[1], pAccum, lmin, lmax,
                   cx1, cy1, cx2, cy1+1);
        ACCUM_EDGE(&edges[2], pAccum, rmin, rmax,
                   cx1, cy1, cx2, cy1+1);
        ACCUM_EDGE(&edges[3], pAccum, rmin, rmax,
                   cx1, cy1, cx2, cy1+1);
        if (lmax > width) {
            lmax = width; /* Extra col has data we do not need. */
        }
        if (rmax > width) {
            rmax = width; /* Extra col has data we do not need. */
        }
        /* If ranges overlap, handle both in the first pass. */
        if (rmin <= lmax) {
            lmax = rmax;
        }

        x = lmin;
        accum = 0.0;
        moff = 0;
        lastcov = 0;
        while (x < lmax) {
            accum += pAccum[x];
            pAccum[x] = 0.0f;
            pMask[moff++] = lastcov = DblToMask(accum);
            x++;
        }
        /* Check for a solid center section. */
        if (lastcov == 0xFF) {
            jint endx;
            void *pRow;

            /* First process the existing partial coverage data. */
            if (moff > 0) {
                pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0);
                (*pPrim->funcs.maskfill)(pRow,
                                         pMask, 0, 0,
                                         moff, 1,
                                         color, pRasInfo,
                                         pPrim, pCompInfo);
                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 */
            endx = (rmin < rmax) ? rmin : width;
            if (x < endx) {
                pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0);
                (*pPrim->funcs.maskfill)(pRow,
                                         NULL, 0, 0,
                                         endx - x, 1,
                                         color, pRasInfo,
                                         pPrim, pCompInfo);
                x = endx;
            }
        } else if (lastcov > 0 && rmin >= rmax) {
            /* We are not at 0 coverage, but there is no right edge, */
            /* force a right edge so we process pixels out to width. */
            rmax = width;
        }
        /* The following loop will process the right AA edge and/or any */
        /* partial coverage center section not processed above. */
        while (x < rmax) {
            accum += pAccum[x];
            pAccum[x] = 0.0f;
            pMask[moff++] = DblToMask(accum);
            x++;
        }
        if (moff > 0) {
            void *pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0);
            (*pPrim->funcs.maskfill)(pRow,
                                     pMask, 0, 0,
                                     moff, 1,
                                     color, pRasInfo,
                                     pPrim, pCompInfo);
        }
        pDst = PtrAddBytes(pDst, pRasInfo->scanStride);
        cy1++;
    }
    if (pAccum != localaccum) {
        free(pAccum);
    }
}

/*
 * Class:     sun_java2d_loops_MaskFill
 * Method:    FillAAPgram
 * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;DDDDDD)V
 */
JNIEXPORT void JNICALL
Java_sun_java2d_loops_MaskFill_FillAAPgram
    (JNIEnv *env, jobject self,
     jobject sg2d, jobject sData, jobject comp,
     jdouble x0, jdouble y0,
     jdouble dx1, jdouble dy1,
     jdouble dx2, jdouble dy2)
{
    SurfaceDataOps *sdOps;
    SurfaceDataRasInfo rasInfo;
    NativePrimitive *pPrim;
    CompositeInfo compInfo;
    jint ix1, iy1, ix2, iy2;

    if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) {
        return;
    }

    /*
     * Sort parallelogram by y values, ensure that each delta vector
     * has a non-negative y delta.
     */
    SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, );

    PGRAM_MIN_MAX(ix1, ix2, x0, dx1, dx2, JNI_TRUE);
    iy1 = (jint) floor(y0);
    iy2 = (jint) ceil(y0 + dy1 + dy2);

    pPrim = GetNativePrim(env, self);
    if (pPrim == NULL) {
        return;
    }
    if (pPrim->pCompType->getCompInfo != NULL) {
        (*pPrim->pCompType->getCompInfo)(env, &compInfo, comp);
    }

    sdOps = SurfaceData_GetOps(env, sData);
    if (sdOps == 0) {
        return;
    }

    GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);
    SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2);
    if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 ||
        rasInfo.bounds.x2 <= rasInfo.bounds.x1)
    {
        return;
    }

    if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {
        return;
    }

    ix1 = rasInfo.bounds.x1;
    iy1 = rasInfo.bounds.y1;
    ix2 = rasInfo.bounds.x2;
    iy2 = rasInfo.bounds.y2;
    if (ix2 > ix1 && iy2 > iy1) {
        jint width = ix2 - ix1;
        jint color = GrPrim_Sg2dGetEaRGB(env, sg2d);
        unsigned char localmask[MASK_BUF_LEN];
        unsigned char *pMask = ((width > MASK_BUF_LEN)
                                ? malloc(width)
                                : localmask);

        sdOps->GetRasInfo(env, sdOps, &rasInfo);
        if (rasInfo.rasBase != NULL && pMask != NULL) {
            void *pDst = PtrCoord(rasInfo.rasBase,
                                  ix1, rasInfo.pixelStride,
                                  iy1, rasInfo.scanStride);
            if (dy1 == 0 && dx2 == 0) {
                if (dx1 < 0) {
                    // We sorted by Y above, but not by X
                    x0 += dx1;
                    dx1 = -dx1;
                }
                fillAARect(pPrim, &rasInfo, &compInfo,
                           color, pMask, pDst,
                           x0, y0, x0+dx1, y0+dy2);
            } else if (dx1 == 0 && dy2 == 0) {
                if (dx2 < 0) {
                    // We sorted by Y above, but not by X
                    x0 += dx2;
                    dx2 = -dx2;
                }
                fillAARect(pPrim, &rasInfo, &compInfo,
                           color, pMask, pDst,
                           x0, y0, x0+dx2, y0+dy1);
            } else {
                fillAAPgram(pPrim, &rasInfo, &compInfo,
                            color, pMask, pDst,
                            x0, y0, dx1, dy1, dx2, dy2);
            }
        }
        SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
        if (pMask != NULL && pMask != localmask) {
            free(pMask);
        }
    }
    SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
}

/* Main function to fill a double pair of (inner and outer) parallelograms */
static void
drawAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo,
            CompositeInfo *pCompInfo, jint color, unsigned char *pMask,
            void *pDst,
            jdouble ox0, jdouble oy0,
            jdouble dx1, jdouble dy1,
            jdouble dx2, jdouble dy2,
            jdouble ldx1, jdouble ldy1,
            jdouble ldx2, jdouble ldy2)
{
    jint cx1 = pRasInfo->bounds.x1;
    jint cy1 = pRasInfo->bounds.y1;
    jint cx2 = pRasInfo->bounds.x2;
    jint cy2 = pRasInfo->bounds.y2;
    jint width = cx2 - cx1;
    EdgeInfo edges[8];
    jfloat localaccum[MASK_BUF_LEN + 1];
    jfloat *pAccum;

    if (!storePgram(edges + 0, edges + 6,
                    ox0, oy0,
                    dx1 + ldx1, dy1 + ldy1,
                    dx2 + ldx2, dy2 + ldy2,
                    cx1, cy1, cx2, cy2,
                    JNI_FALSE))
    {
        /* If outer pgram does not contribute, then inner cannot either. */
        return;
    }
    storePgram(edges + 2, edges + 4,
               ox0 + ldx1 + ldx2, oy0 + ldy1 + ldy2,
               dx1 - ldx1, dy1 - ldy1,
               dx2 - ldx2, dy2 - ldy2,
               cx1, cy1, cx2, cy2,
               JNI_TRUE);

    pAccum = ((width > MASK_BUF_LEN)
              ? malloc((width + 1) * sizeof(jfloat))
              : localaccum);
    if (pAccum == NULL) {
        return;
    }
    memset(pAccum, 0, (width+1) * sizeof(jfloat));

    while (cy1 < cy2) {
        jint lmin, lmax, rmin, rmax;
        jint moff, x;
        jdouble accum;
        unsigned char lastcov;

        lmin = rmin = width + 2;
        lmax = rmax = 0;
        ACCUM_EDGE(&edges[0], pAccum, lmin, lmax,
                   cx1, cy1, cx2, cy1+1);
        ACCUM_EDGE(&edges[1], pAccum, lmin, lmax,
                   cx1, cy1, cx2, cy1+1);
        ACCUM_EDGE(&edges[2], pAccum, lmin, lmax,
                   cx1, cy1, cx2, cy1+1);
        ACCUM_EDGE(&edges[3], pAccum, lmin, lmax,
                   cx1, cy1, cx2, cy1+1);
        ACCUM_EDGE(&edges[4], pAccum, rmin, rmax,
                   cx1, cy1, cx2, cy1+1);
        ACCUM_EDGE(&edges[5], pAccum, rmin, rmax,
                   cx1, cy1, cx2, cy1+1);
        ACCUM_EDGE(&edges[6], pAccum, rmin, rmax,
                   cx1, cy1, cx2, cy1+1);
        ACCUM_EDGE(&edges[7], pAccum, rmin, rmax,
                   cx1, cy1, cx2, cy1+1);
        if (lmax > width) {
            lmax = width; /* Extra col has data we do not need. */
        }
        if (rmax > width) {
            rmax = width; /* Extra col has data we do not need. */
        }
        /* If ranges overlap, handle both in the first pass. */
        if (rmin <= lmax) {
            lmax = rmax;
        }

        x = lmin;
        accum = 0.0;
        moff = 0;
        lastcov = 0;
        while (x < lmax) {
            accum += pAccum[x];
            pAccum[x] = 0.0f;
            pMask[moff++] = lastcov = DblToMask(accum);
            x++;
        }
        /* Check for an empty or solidcenter section. */
        if (lastcov == 0 || lastcov == 0xFF) {
            jint endx;
            void *pRow;

            /* First process the existing partial coverage data. */
            if (moff > 0) {
                pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0);
                (*pPrim->funcs.maskfill)(pRow,
                                         pMask, 0, 0,
                                         moff, 1,
                                         color, pRasInfo,
                                         pPrim, pCompInfo);
                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 */
            endx = (rmin < rmax) ? rmin : width;
            if (x < endx) {
                if (lastcov == 0xFF) {
                    pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0);
                    (*pPrim->funcs.maskfill)(pRow,
                                             NULL, 0, 0,
                                             endx - x, 1,
                                             color, pRasInfo,
                                             pPrim, pCompInfo);
                }
                x = endx;
            }
        } else if (rmin >= rmax) {
            /* We are not at 0 coverage, but there is no right edge, */
            /* force a right edge so we process pixels out to width. */
            rmax = width;
        }
        /* The following loop will process the right AA edge and/or any */
        /* partial coverage center section not processed above. */
        while (x < rmax) {
            accum += pAccum[x];
            pAccum[x] = 0.0f;
            pMask[moff++] = lastcov = DblToMask(accum);
            x++;
        }
        if (moff > 0) {
            void *pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0);
            (*pPrim->funcs.maskfill)(pRow,
                                     pMask, 0, 0,
                                     moff, 1,
                                     color, pRasInfo,
                                     pPrim, pCompInfo);
        }
        if (lastcov == 0xFF && x < width) {
            void *pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0);
            (*pPrim->funcs.maskfill)(pRow,
                                     NULL, 0, 0,
                                     width - x, 1,
                                     color, pRasInfo,
                                     pPrim, pCompInfo);
        }
        pDst = PtrAddBytes(pDst, pRasInfo->scanStride);
        cy1++;
    }
    if (pAccum != localaccum) {
        free(pAccum);
    }
}

/*
 * Class:     sun_java2d_loops_MaskFill
 * Method:    DrawAAPgram
 * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;DDDDDDDD)V
 */
JNIEXPORT void JNICALL
Java_sun_java2d_loops_MaskFill_DrawAAPgram
    (JNIEnv *env, jobject self,
     jobject sg2d, jobject sData, jobject comp,
     jdouble x0, jdouble y0,
     jdouble dx1, jdouble dy1,
     jdouble dx2, jdouble dy2,
     jdouble lw1, jdouble lw2)
{
    SurfaceDataOps *sdOps;
    SurfaceDataRasInfo rasInfo;
    NativePrimitive *pPrim;
    CompositeInfo compInfo;
    jint ix1, iy1, ix2, iy2;
    jdouble ldx1, ldy1, ldx2, ldy2;
    jdouble ox0, oy0;

    if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) {
        return;
    }

    /*
     * Sort parallelogram by y values, ensure that each delta vector
     * has a non-negative y delta.
     */
    SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2,
               v = lw1; lw1 = lw2; lw2 = v;);

    // dx,dy for line width in the "1" and "2" directions.
    ldx1 = dx1 * lw1;
    ldy1 = dy1 * lw1;
    ldx2 = dx2 * lw2;
    ldy2 = dy2 * lw2;

    // calculate origin of the outer parallelogram
    ox0 = x0 - (ldx1 + ldx2) / 2.0;
    oy0 = y0 - (ldy1 + ldy2) / 2.0;

    if (lw1 >= 1.0 || lw2 >= 1.0) {
        /* 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).
         */
        Java_sun_java2d_loops_MaskFill_FillAAPgram(env, self,
                                                   sg2d, sData, comp,
                                                   ox0, oy0,
                                                   dx1 + ldx1, dy1 + ldy1,
                                                   dx2 + ldx2, dy2 + ldy2);
        return;
    }

    PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2, JNI_TRUE);
    iy1 = (jint) floor(oy0);
    iy2 = (jint) ceil(oy0 + dy1 + ldy1 + dy2 + ldy2);

    pPrim = GetNativePrim(env, self);
    if (pPrim == NULL) {
        return;
    }
    if (pPrim->pCompType->getCompInfo != NULL) {
        (*pPrim->pCompType->getCompInfo)(env, &compInfo, comp);
    }

    sdOps = SurfaceData_GetOps(env, sData);
    if (sdOps == 0) {
        return;
    }

    GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);
    SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2);
    if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 ||
        rasInfo.bounds.x2 <= rasInfo.bounds.x1)
    {
        return;
    }

    if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {
        return;
    }

    ix1 = rasInfo.bounds.x1;
    iy1 = rasInfo.bounds.y1;
    ix2 = rasInfo.bounds.x2;
    iy2 = rasInfo.bounds.y2;
    if (ix2 > ix1 && iy2 > iy1) {
        jint width = ix2 - ix1;
        jint color = GrPrim_Sg2dGetEaRGB(env, sg2d);
        unsigned char localmask[MASK_BUF_LEN];
        unsigned char *pMask = ((width > MASK_BUF_LEN)
                                ? malloc(width)
                                : localmask);

        sdOps->GetRasInfo(env, sdOps, &rasInfo);
        if (rasInfo.rasBase != NULL && pMask != NULL) {
            void *pDst = PtrCoord(rasInfo.rasBase,
                                  ix1, rasInfo.pixelStride,
                                  iy1, rasInfo.scanStride);
            /*
             * 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 {
             */
            drawAAPgram(pPrim, &rasInfo, &compInfo,
                        color, pMask, pDst,
                        ox0, oy0,
                        dx1, dy1, dx2, dy2,
                        ldx1, ldy1, ldx2, ldy2);
            /*
             * }
             */
        }
        SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
        if (pMask != NULL && pMask != localmask) {
            free(pMask);
        }
    }
    SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
}

Other Java examples (source code examples)

Here is a short list of links related to this Java MaskFill.c source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.