/*
 * Class:     sun_java2d_loops_MaskBlit
 * Method:    MaskBlit
 * Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;Ljava/awt/Composite;IIIIII[BII)V
 */
JNIEXPORT void JNICALL
Java_sun_java2d_loops_MaskBlit_MaskBlit
    (JNIEnv *env, jobject self,
     jobject srcData, jobject dstData, jobject comp, jobject clip,
     jint srcx, jint srcy, jint dstx, jint dsty, jint width, jint height,
     jbyteArray maskArray, jint maskoff, jint maskscan)
{
    SurfaceDataOps *srcOps;
    SurfaceDataOps *dstOps;
    SurfaceDataRasInfo srcInfo;
    SurfaceDataRasInfo dstInfo;
    NativePrimitive *pPrim;
    CompositeInfo compInfo;
    RegionData clipInfo;

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

    srcOps = SurfaceData_GetOps(env, srcData);
    dstOps = SurfaceData_GetOps(env, dstData);
    if (srcOps == 0 || dstOps == 0) {
        return;
    }

    srcInfo.bounds.x1 = srcx;
    srcInfo.bounds.y1 = srcy;
    srcInfo.bounds.x2 = srcx + width;
    srcInfo.bounds.y2 = srcy + height;
    dstInfo.bounds.x1 = dstx;
    dstInfo.bounds.y1 = dsty;
    dstInfo.bounds.x2 = dstx + width;
    dstInfo.bounds.y2 = dsty + height;
    srcx -= dstx;
    srcy -= dsty;
    SurfaceData_IntersectBounds(&dstInfo.bounds, &clipInfo.bounds);
    if (srcOps->Lock(env, srcOps, &srcInfo, pPrim->srcflags) != SD_SUCCESS) {
        return;
    }
    if (dstOps->Lock(env, dstOps, &dstInfo, pPrim->dstflags) != SD_SUCCESS) {
        SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
        return;
    }
    SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
                                    srcx, srcy);
    Region_IntersectBounds(&clipInfo, &dstInfo.bounds);

    if (!Region_IsEmpty(&clipInfo)) {
        srcOps->GetRasInfo(env, srcOps, &srcInfo);
        dstOps->GetRasInfo(env, dstOps, &dstInfo);
        if (srcInfo.rasBase && dstInfo.rasBase) {
            SurfaceDataBounds span;
            unsigned char *pMask =
                (maskArray
                 ? (*env)->GetPrimitiveArrayCritical(env, maskArray, 0)
                 : 0);
            jint savesx = srcInfo.bounds.x1;
            jint savedx = dstInfo.bounds.x1;
            Region_StartIteration(env, &clipInfo);
            while (Region_NextIteration(&clipInfo, &span)) {
                void *pSrc = PtrCoord(srcInfo.rasBase,
                                      srcx + span.x1, srcInfo.pixelStride,
                                      srcy + span.y1, srcInfo.scanStride);
                void *pDst = PtrCoord(dstInfo.rasBase,
                                      span.x1, dstInfo.pixelStride,
                                      span.y1, dstInfo.scanStride);
                maskoff += ((span.y1 - dsty) * maskscan + (span.x1 - dstx));
                /*
                 * Fix for 4804375
                 * REMIND: There should probably be a better
                 * way to give the span coordinates to the
                 * inner loop.  This is only really needed
                 * for the 1, 2, and 4 bit loops.
                 */
                srcInfo.bounds.x1 = srcx + span.x1;
                dstInfo.bounds.x1 = span.x1;
                (*pPrim->funcs.maskblit)(pDst, pSrc,
                                         pMask, maskoff, maskscan,
                                         span.x2 - span.x1, span.y2 - span.y1,
                                         &dstInfo, &srcInfo,
                                         pPrim, &compInfo);
            }
            Region_EndIteration(env, &clipInfo);
            if (pMask) {
                (*env)->ReleasePrimitiveArrayCritical(env, maskArray,
                                                      pMask, JNI_ABORT);
            }
            srcInfo.bounds.x1 = savesx;
            dstInfo.bounds.x1 = savedx;
        }
        SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
        SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
    }
    SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
    SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
}
Beispiel #2
0
/*
 * Class:     sun_java2d_loops_Blit
 * Method:    Blit
 * Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;Ljava/awt/Composite;IIIIII)V
 */
JNIEXPORT void JNICALL
Java_sun_java2d_loops_Blit_Blit
    (JNIEnv *env, jobject self,
     jobject srcData, jobject dstData, jobject comp, jobject clip,
     jint srcx, jint srcy, jint dstx, jint dsty, jint width, jint height)
{
    SurfaceDataOps *srcOps;
    SurfaceDataOps *dstOps;
    SurfaceDataRasInfo srcInfo;
    SurfaceDataRasInfo dstInfo;
    NativePrimitive *pPrim;
    CompositeInfo compInfo;
    RegionData clipInfo;
    jint dstFlags;

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

    srcOps = SurfaceData_GetOps(env, srcData);
    dstOps = SurfaceData_GetOps(env, dstData);
    if (srcOps == 0 || dstOps == 0) {
	return;
    }

    srcInfo.bounds.x1 = srcx;
    srcInfo.bounds.y1 = srcy;
    srcInfo.bounds.x2 = srcx + width;
    srcInfo.bounds.y2 = srcy + height;
    dstInfo.bounds.x1 = dstx;
    dstInfo.bounds.y1 = dsty;
    dstInfo.bounds.x2 = dstx + width;
    dstInfo.bounds.y2 = dsty + height;
    srcx -= dstx;
    srcy -= dsty;
    SurfaceData_IntersectBounds(&dstInfo.bounds, &clipInfo.bounds);
    if (srcOps->Lock(env, srcOps, &srcInfo, pPrim->srcflags) != SD_SUCCESS) {
	return;
    }

    dstFlags = pPrim->dstflags;
    if (!Region_IsRectangular(&clipInfo)) {
	dstFlags |= SD_LOCK_PARTIAL_WRITE;
    }
    if (dstOps->Lock(env, dstOps, &dstInfo, dstFlags) != SD_SUCCESS) {
	SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
	return;
    }
    SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
				    srcx, srcy);
    Region_IntersectBounds(&clipInfo, &dstInfo.bounds);

    if (!Region_IsEmpty(&clipInfo)) {
	srcOps->GetRasInfo(env, srcOps, &srcInfo);
	dstOps->GetRasInfo(env, dstOps, &dstInfo);
	if (srcInfo.rasBase && dstInfo.rasBase) {
	    SurfaceDataBounds span;
	    jint savesx = srcInfo.bounds.x1;
	    jint savedx = dstInfo.bounds.x1;
	    Region_StartIteration(env, &clipInfo);
	    while (Region_NextIteration(&clipInfo, &span)) {
		void *pSrc = PtrCoord(srcInfo.rasBase,
				      srcx + span.x1, srcInfo.pixelStride,
				      srcy + span.y1, srcInfo.scanStride);
		void *pDst = PtrCoord(dstInfo.rasBase,
				      span.x1, dstInfo.pixelStride,
				      span.y1, dstInfo.scanStride);
		/*
		 * Fix for 4804375
		 * REMIND: There should probably be a better
		 * way to give the span coordinates to the
		 * inner loop.  This is only really needed
		 * for the 1, 2, and 4 bit loops.
		 */
		srcInfo.bounds.x1 = srcx + span.x1;
		dstInfo.bounds.x1 = span.x1;
		(*pPrim->funcs.blit)(pSrc, pDst,
				     span.x2 - span.x1, span.y2 - span.y1,
				     &srcInfo, &dstInfo, pPrim, &compInfo);
	    }
	    Region_EndIteration(env, &clipInfo);
	    srcInfo.bounds.x1 = savesx;
	    dstInfo.bounds.x1 = savedx;
	}
	SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
	SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
    }
    SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
    SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
}
Beispiel #3
0
JNIEXPORT void JNICALL
Java_sun_awt_X11PMBlitLoops_Blit
    (JNIEnv *env, jobject joSelf,
     jobject srcData, jobject dstData,
     jobject composite, jobject clip,
     jint srcx, jint srcy,
     jint dstx, jint dsty,
     jint width, jint height)
{
#ifndef HEADLESS
    X11SDOps *srcXsdo, *dstXsdo;
    SurfaceDataBounds span;
    RegionData clipInfo;
    GC xgc;

    if (width <= 0 || height <= 0) {
	return;
    }

    srcXsdo = X11SurfaceData_GetOps(env, srcData);
    if (srcXsdo == NULL) {
	return;
    }
    dstXsdo = X11SurfaceData_GetOps(env, dstData);
    if (dstXsdo == NULL) {
	return;
    }
    if (Region_GetInfo(env, clip, &clipInfo)) {
	return;
    }

    xgc = dstXsdo->GetGC(env, dstXsdo, NULL, NULL, dstXsdo->lastpixel);
    if (xgc == NULL) {
	return;
    }

#ifdef MITSHM
    if (srcXsdo->isPixmap) {
	X11SD_UnPuntPixmap(srcXsdo);
    }
#endif /* MITSHM */

    if (srcXsdo->bitmask != 0) {
	XSetClipOrigin(awt_display, xgc, dstx - srcx, dsty - srcy);
	XSetClipMask(awt_display, xgc, srcXsdo->bitmask);
    }
    span.x1 = dstx;
    span.y1 = dsty;
    span.x2 = dstx + width;
    span.y2 = dsty + height;
    Region_IntersectBounds(&clipInfo, &span);
    if (!Region_IsEmpty(&clipInfo)) {
	Region_StartIteration(env, &clipInfo);
	srcx -= dstx;
	srcy -= dsty;
	while (Region_NextIteration(&clipInfo, &span)) {
	    XCopyArea(awt_display, srcXsdo->drawable, dstXsdo->drawable, xgc,
		      srcx + span.x1, srcy + span.y1,
		      span.x2 - span.x1, span.y2 - span.y1,
		      span.x1, span.y1);
	}
	Region_EndIteration(env, &clipInfo);
    }

    if (srcXsdo->bitmask != 0) {
	XSetClipMask(awt_display, xgc, None);
    }

#ifdef MITSHM
    if (srcXsdo->shmPMData.usingShmPixmap) { 
	srcXsdo->shmPMData.xRequestSent = JNI_TRUE;
    }
#endif /* MITSHM */
    dstXsdo->ReleaseGC(env, dstXsdo, xgc);
#endif /* !HEADLESS */
}
Beispiel #4
0
static void
Transform_SafeHelper(JNIEnv *env,
                     SurfaceDataOps *srcOps,
                     SurfaceDataOps *dstOps,
                     SurfaceDataRasInfo *pSrcInfo,
                     SurfaceDataRasInfo *pDstInfo,
                     NativePrimitive *pMaskBlitPrim,
                     CompositeInfo *pCompInfo,
                     TransformHelperFunc *pHelperFunc,
                     TransformInterpFunc *pInterpFunc,
                     RegionData *pClipInfo, TransformInfo *pItxInfo,
                     jint *pData, jint *pEdges,
                     jint dxoff, jint dyoff, jint sw, jint sh)
{
    SurfaceDataBounds span;
    jint dx1, dx2;
    jint dy1, dy2;
    jint i, iy;

    dy1 = pDstInfo->bounds.y1;
    dy2 = pDstInfo->bounds.y2;
    dx1 = pDstInfo->bounds.x1;
    dx2 = pDstInfo->bounds.x2;
    pEdges[0] = dy1;
    pEdges[1] = dy2;
    for (iy = dy1; iy < dy2; iy++) {
        jint i = (iy - dy1) * 2;
        /* row spans are set to max,min until we find a pixel in range below */
        pEdges[i + 2] = dx2;
        pEdges[i + 3] = dx1;
    }

    Region_StartIteration(env, pClipInfo);
    while (Region_NextIteration(pClipInfo, &span)) {
        dy1 = span.y1;
        dy2 = span.y2;
        while (dy1 < dy2) {
            dx1 = span.x1;
            dx2 = span.x2;
            i = (dy1 - pDstInfo->bounds.y1) * 2;
            while (dx1 < dx2) {
                jdouble x, y;
                jlong xlong, ylong;

                x = dxoff + dx1 + 0.5;
                y = dyoff + dy1 + 0.5;
                Transform_transform(pItxInfo, &x, &y);
                xlong = DblToLong(x);
                ylong = DblToLong(y);

                /* Process only pixels with centers in bounds
                 * Test double values to avoid overflow in conversion
                 * to long values and then also test the long values
                 * in case they rounded up and out of bounds during
                 * the conversion.
                 */
                if (x >= 0 && y >= 0 && x < sw && y < sh &&
                    WholeOfLong(xlong) < sw &&
                    WholeOfLong(ylong) < sh)
                {
                    void *pDst;

                    if (pEdges[i + 2] > dx1) {
                        pEdges[i + 2] = dx1;
                    }
                    if (pEdges[i + 3] <= dx1) {
                        pEdges[i + 3] = dx1 + 1;
                    }

                    /* Get IntArgbPre pixel data from source */
                    (*pHelperFunc)(pSrcInfo,
                                   pData, 1,
                                   xlong, 0,
                                   ylong, 0);

                    /* Interpolate result pixels if needed */
                    if (pInterpFunc) {
                        (*pInterpFunc)(pData, 1,
                                       FractOfLong(xlong-LongOneHalf), 0,
                                       FractOfLong(ylong-LongOneHalf), 0);
                    }

                    /* Store/Composite interpolated pixels into dest */
                    pDst = PtrCoord(pDstInfo->rasBase,
                                    dx1, pDstInfo->pixelStride,
                                    dy1, pDstInfo->scanStride);
                    (*pMaskBlitPrim->funcs.maskblit)(pDst, pData,
                                                     0, 0, 0,
                                                     1, 1,
                                                     pDstInfo, pSrcInfo,
                                                     pMaskBlitPrim,
                                                     pCompInfo);
                }

                /* Increment to next input pixel */
                dx1++;
            }

            /* Increment to next scanline */
            dy1++;
        }
    }
    Region_EndIteration(env, pClipInfo);
}
Beispiel #5
0
/*
 * Class:     sun_java2d_loops_TransformHelper
 * Method:    Transform
 * Signature: (Lsun/java2d/loops/MaskBlit;Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;Ljava/awt/Composite;Lsun/java2d/pipe/Region;Ljava/awt/geom/AffineTransform;IIIIIIIII[I)V
 */
JNIEXPORT void JNICALL
Java_sun_java2d_loops_TransformHelper_Transform
    (JNIEnv *env, jobject self,
     jobject maskblit,
     jobject srcData, jobject dstData,
     jobject comp, jobject clip,
     jobject itxform, jint txtype,
     jint sx1, jint sy1, jint sx2, jint sy2,
     jint dx1, jint dy1, jint dx2, jint dy2,
     jintArray edgeArray, jint dxoff, jint dyoff)
{
    SurfaceDataOps *srcOps;
    SurfaceDataOps *dstOps;
    SurfaceDataRasInfo srcInfo;
    SurfaceDataRasInfo dstInfo;
    NativePrimitive *pHelperPrim;
    NativePrimitive *pMaskBlitPrim;
    CompositeInfo compInfo;
    RegionData clipInfo;
    TransformInfo itxInfo;
    jint maxlinepix;
    TransformHelperFunc *pHelperFunc;
    TransformInterpFunc *pInterpFunc;
    jdouble xorig, yorig;
    jlong numedges;
    jint *pEdges;
    jint edgebuf[2 + MAXEDGES * 2];
    union {
        jlong align;
        jint data[LINE_SIZE];
    } rgb;

#ifdef MAKE_STUBS
    static int th_initialized;

    /* For debugging only - used to swap in alternate funcs for perf testing */
    if (!th_initialized) {
        if (getenv("TXSTUB") != 0) {
            pBilinearFunc = BilinearInterpStub;
            pBicubicFunc = BicubicInterpStub;
        } else if (getenv("TXNOVIS") != 0) {
            pBilinearFunc = BilinearInterp;
            pBicubicFunc = BicubicInterp;
        }
        th_initialized = 1;
    }
#endif /* MAKE_STUBS */

    pHelperPrim = GetNativePrim(env, self);
    if (pHelperPrim == NULL) {
        /* Should never happen... */
        return;
    }
    pMaskBlitPrim = GetNativePrim(env, maskblit);
    if (pMaskBlitPrim == NULL) {
        /* Exception was thrown by GetNativePrim */
        return;
    }
    if (pMaskBlitPrim->pCompType->getCompInfo != NULL) {
        (*pMaskBlitPrim->pCompType->getCompInfo)(env, &compInfo, comp);
    }
    if (Region_GetInfo(env, clip, &clipInfo)) {
        return;
    }

    srcOps = SurfaceData_GetOps(env, srcData);
    dstOps = SurfaceData_GetOps(env, dstData);
    if (srcOps == 0 || dstOps == 0) {
        return;
    }

    /*
     * Grab the appropriate pointer to the helper and interpolation
     * routines and calculate the maximum number of destination pixels
     * that can be processed in one intermediate buffer based on the
     * size of the buffer and the number of samples needed per pixel.
     */
    switch (txtype) {
    case java_awt_image_AffineTransformOp_TYPE_NEAREST_NEIGHBOR:
        pHelperFunc = pHelperPrim->funcs.transformhelpers->nnHelper;
        pInterpFunc = NULL;
        maxlinepix = LINE_SIZE;
        break;
    case java_awt_image_AffineTransformOp_TYPE_BILINEAR:
        pHelperFunc = pHelperPrim->funcs.transformhelpers->blHelper;
        pInterpFunc = pBilinearFunc;
        maxlinepix = LINE_SIZE / 4;
        break;
    case java_awt_image_AffineTransformOp_TYPE_BICUBIC:
        pHelperFunc = pHelperPrim->funcs.transformhelpers->bcHelper;
        pInterpFunc = pBicubicFunc;
        maxlinepix = LINE_SIZE / 16;
        break;
    }

    srcInfo.bounds.x1 = sx1;
    srcInfo.bounds.y1 = sy1;
    srcInfo.bounds.x2 = sx2;
    srcInfo.bounds.y2 = sy2;
    dstInfo.bounds.x1 = dx1;
    dstInfo.bounds.y1 = dy1;
    dstInfo.bounds.x2 = dx2;
    dstInfo.bounds.y2 = dy2;
    SurfaceData_IntersectBounds(&dstInfo.bounds, &clipInfo.bounds);
    if (srcOps->Lock(env, srcOps, &srcInfo, pHelperPrim->srcflags)
        != SD_SUCCESS)
    {
        /* edgeArray should already contain zeros for min/maxy */
        return;
    }
    if (dstOps->Lock(env, dstOps, &dstInfo, pMaskBlitPrim->dstflags)
        != SD_SUCCESS)
    {
        SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
        /* edgeArray should already contain zeros for min/maxy */
        return;
    }
    Region_IntersectBounds(&clipInfo, &dstInfo.bounds);

    numedges = (((jlong) dstInfo.bounds.y2) - ((jlong) dstInfo.bounds.y1));
    if (numedges <= 0) {
        pEdges = NULL;
    } else if (!JNU_IsNull(env, edgeArray)) {
        /*
         * Ideally Java should allocate an array large enough, but if
         * we ever have a miscommunication about the number of edge
         * lines, or if the Java array calculation should overflow to
         * a positive number and succeed in allocating an array that
         * is too small, we need to verify that it can still hold the
         * number of integers that we plan to store to be safe.
         */
        jsize edgesize = (*env)->GetArrayLength(env, edgeArray);
        /* (edgesize/2 - 1) should avoid any overflow or underflow. */
        pEdges = (((edgesize / 2) - 1) >= numedges)
            ? (*env)->GetPrimitiveArrayCritical(env, edgeArray, NULL)
            : NULL;
    } else if (numedges > MAXEDGES) {
        /* numedges variable (jlong) can be at most ((1<<32)-1) */
        /* memsize can overflow a jint, but not a jlong */
        jlong memsize = ((numedges * 2) + 2) * sizeof(*pEdges);
        pEdges = (memsize == ((size_t) memsize))
            ? malloc((size_t) memsize)
            : NULL;
    } else {
        pEdges = edgebuf;
    }

    if (pEdges == NULL) {
        if (numedges > 0) {
            JNU_ThrowInternalError(env, "Unable to allocate edge list");
        }
        SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
        SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
        /* edgeArray should already contain zeros for min/maxy */
        return;
    }

    Transform_GetInfo(env, itxform, &itxInfo);

    if (!Region_IsEmpty(&clipInfo)) {
        srcOps->GetRasInfo(env, srcOps, &srcInfo);
        dstOps->GetRasInfo(env, dstOps, &dstInfo);
        if (srcInfo.rasBase == NULL || dstInfo.rasBase == NULL) {
            pEdges[0] = pEdges[1] = 0;
        } else if (checkOverflow(dxoff, dyoff, &dstInfo.bounds,
                                 &itxInfo, &xorig, &yorig))
        {
            Transform_SafeHelper(env, srcOps, dstOps,
                                 &srcInfo, &dstInfo,
                                 pMaskBlitPrim, &compInfo,
                                 pHelperFunc, pInterpFunc,
                                 &clipInfo, &itxInfo, rgb.data, pEdges,
                                 dxoff, dyoff, sx2-sx1, sy2-sy1);
        } else {
            SurfaceDataBounds span;
            jlong dxdxlong, dydxlong;
            jlong dxdylong, dydylong;
            jlong xbase, ybase;

            dxdxlong = DblToLong(itxInfo.dxdx);
            dydxlong = DblToLong(itxInfo.dydx);
            dxdylong = DblToLong(itxInfo.dxdy);
            dydylong = DblToLong(itxInfo.dydy);
            xbase = DblToLong(xorig);
            ybase = DblToLong(yorig);

            calculateEdges(pEdges, &dstInfo.bounds, &itxInfo,
                           xbase, ybase, sx2-sx1, sy2-sy1);

            Region_StartIteration(env, &clipInfo);
            while (Region_NextIteration(&clipInfo, &span)) {
                jlong rowxlong, rowylong;
                void *pDst;

                dy1 = span.y1;
                dy2 = span.y2;
                rowxlong = xbase + (dy1 - dstInfo.bounds.y1) * dxdylong;
                rowylong = ybase + (dy1 - dstInfo.bounds.y1) * dydylong;

                while (dy1 < dy2) {
                    jlong xlong, ylong;

                    /* Note - process at most one scanline at a time. */

                    dx1 = pEdges[(dy1 - dstInfo.bounds.y1) * 2 + 2];
                    dx2 = pEdges[(dy1 - dstInfo.bounds.y1) * 2 + 3];
                    if (dx1 < span.x1) dx1 = span.x1;
                    if (dx2 > span.x2) dx2 = span.x2;

                    /* All pixels from dx1 to dx2 have centers in bounds */
                    while (dx1 < dx2) {
                        /* Can process at most one buffer full at a time */
                        jint numpix = dx2 - dx1;
                        if (numpix > maxlinepix) {
                            numpix = maxlinepix;
                        }

                        xlong =
                            rowxlong + ((dx1 - dstInfo.bounds.x1) * dxdxlong);
                        ylong =
                            rowylong + ((dx1 - dstInfo.bounds.x1) * dydxlong);

                        /* Get IntArgbPre pixel data from source */
                        (*pHelperFunc)(&srcInfo,
                                       rgb.data, numpix,
                                       xlong, dxdxlong,
                                       ylong, dydxlong);

                        /* Interpolate result pixels if needed */
                        if (pInterpFunc) {
                            (*pInterpFunc)(rgb.data, numpix,
                                           FractOfLong(xlong-LongOneHalf),
                                           FractOfLong(dxdxlong),
                                           FractOfLong(ylong-LongOneHalf),
                                           FractOfLong(dydxlong));
                        }

                        /* Store/Composite interpolated pixels into dest */
                        pDst = PtrCoord(dstInfo.rasBase,
                                        dx1, dstInfo.pixelStride,
                                        dy1, dstInfo.scanStride);
                        (*pMaskBlitPrim->funcs.maskblit)(pDst, rgb.data,
                                                         0, 0, 0,
                                                         numpix, 1,
                                                         &dstInfo, &srcInfo,
                                                         pMaskBlitPrim,
                                                         &compInfo);

                        /* Increment to next buffer worth of input pixels */
                        dx1 += maxlinepix;
                    }

                    /* Increment to next scanline */
                    rowxlong += dxdylong;
                    rowylong += dydylong;
                    dy1++;
                }
            }
            Region_EndIteration(env, &clipInfo);
        }
        SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
        SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
    } else {
        pEdges[0] = pEdges[1] = 0;
    }

    if (!JNU_IsNull(env, edgeArray)) {
        (*env)->ReleasePrimitiveArrayCritical(env, edgeArray, pEdges, 0);
    } else if (pEdges != edgebuf) {
        free(pEdges);
    }
    SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
    SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
}
Beispiel #6
0
/*
 * Class:     sun_java2d_loops_TransformHelper
 * Method:    Transform
 * Signature: (Lsun/java2d/loops/MaskBlit;Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;Ljava/awt/Composite;Lsun/java2d/pipe/Region;Ljava/awt/geom/AffineTransform;IIIIIIIII[I)V
 */
JNIEXPORT void JNICALL
Java_sun_java2d_loops_TransformHelper_Transform
    (JNIEnv *env, jobject self,
     jobject maskblit,
     jobject srcData, jobject dstData,
     jobject comp, jobject clip,
     jobject itxform, jint txtype,
     jint sx1, jint sy1, jint sx2, jint sy2,
     jint dx1, jint dy1, jint dx2, jint dy2,
     jintArray edgeArray, jint dxoff, jint dyoff)
{
    SurfaceDataOps *srcOps;
    SurfaceDataOps *dstOps;
    SurfaceDataRasInfo srcInfo;
    SurfaceDataRasInfo dstInfo;
    NativePrimitive *pHelperPrim;
    NativePrimitive *pMaskBlitPrim;
    CompositeInfo compInfo;
    RegionData clipInfo;
    TransformInfo itxInfo;
    jint maxlinepix;
    TransformHelperFunc *pHelperFunc;
    TransformInterpFunc *pInterpFunc;
    jint edgebuf[MAXEDGES * 2];
    jint *pEdges;
    jdouble x, y;
    jlong xbase, ybase;
    jlong dxdxlong, dydxlong;
    jlong dxdylong, dydylong;

#ifdef MAKE_STUBS
    static int th_initialized;

    /* For debugging only - used to swap in alternate funcs for perf testing */
    if (!th_initialized) {
        if (getenv("TXSTUB") != 0) {
            pBilinearFunc = BilinearInterpStub;
            pBicubicFunc = BicubicInterpStub;
        } else if (getenv("TXNOVIS") != 0) {
            pBilinearFunc = BilinearInterp;
            pBicubicFunc = BicubicInterp;
        }
        th_initialized = 1;
    }
#endif /* MAKE_STUBS */

    pHelperPrim = GetNativePrim(env, self);
    if (pHelperPrim == NULL) {
        /* Should never happen... */
        return;
    }
    pMaskBlitPrim = GetNativePrim(env, maskblit);
    if (pMaskBlitPrim == NULL) {
        /* Exception was thrown by GetNativePrim */
        return;
    }
    if (pMaskBlitPrim->pCompType->getCompInfo != NULL) {
        (*pMaskBlitPrim->pCompType->getCompInfo)(env, &compInfo, comp);
    }
    if (Region_GetInfo(env, clip, &clipInfo)) {
        return;
    }

    srcOps = SurfaceData_GetOps(env, srcData);
    dstOps = SurfaceData_GetOps(env, dstData);
    if (srcOps == 0 || dstOps == 0) {
        return;
    }

    /*
     * Grab the appropriate pointer to the helper and interpolation
     * routines and calculate the maximum number of destination pixels
     * that can be processed in one intermediate buffer based on the
     * size of the buffer and the number of samples needed per pixel.
     */
    switch (txtype) {
    case java_awt_image_AffineTransformOp_TYPE_NEAREST_NEIGHBOR:
        pHelperFunc = pHelperPrim->funcs.transformhelpers->nnHelper;
        pInterpFunc = NULL;
        maxlinepix = LINE_SIZE;
        break;
    case java_awt_image_AffineTransformOp_TYPE_BILINEAR:
        pHelperFunc = pHelperPrim->funcs.transformhelpers->blHelper;
        pInterpFunc = pBilinearFunc;
        maxlinepix = LINE_SIZE / 4;
        break;
    case java_awt_image_AffineTransformOp_TYPE_BICUBIC:
        pHelperFunc = pHelperPrim->funcs.transformhelpers->bcHelper;
        pInterpFunc = pBicubicFunc;
        maxlinepix = LINE_SIZE / 16;
        break;
    }

    srcInfo.bounds.x1 = sx1;
    srcInfo.bounds.y1 = sy1;
    srcInfo.bounds.x2 = sx2;
    srcInfo.bounds.y2 = sy2;
    dstInfo.bounds.x1 = dx1;
    dstInfo.bounds.y1 = dy1;
    dstInfo.bounds.x2 = dx2;
    dstInfo.bounds.y2 = dy2;
    SurfaceData_IntersectBounds(&dstInfo.bounds, &clipInfo.bounds);
    if (srcOps->Lock(env, srcOps, &srcInfo, pHelperPrim->srcflags)
        != SD_SUCCESS)
    {
        return;
    }
    if (dstOps->Lock(env, dstOps, &dstInfo, pMaskBlitPrim->dstflags)
        != SD_SUCCESS)
    {
        SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
        return;
    }
    Region_IntersectBounds(&clipInfo, &dstInfo.bounds);

    Transform_GetInfo(env, itxform, &itxInfo);
    dxdxlong = DblToLong(itxInfo.dxdx);
    dydxlong = DblToLong(itxInfo.dydx);
    dxdylong = DblToLong(itxInfo.dxdy);
    dydylong = DblToLong(itxInfo.dydy);
    x = dxoff+dstInfo.bounds.x1+0.5; /* Center of pixel x1 */
    y = dyoff+dstInfo.bounds.y1+0.5; /* Center of pixel y1 */
    Transform_transform(&itxInfo, &x, &y);
    xbase = DblToLong(x);
    ybase = DblToLong(y);

    pEdges = calculateEdges(edgebuf, &dstInfo.bounds, &itxInfo,
                            xbase, ybase, sx2-sx1, sy2-sy1);

    if (!Region_IsEmpty(&clipInfo)) {
        srcOps->GetRasInfo(env, srcOps, &srcInfo);
        dstOps->GetRasInfo(env, dstOps, &dstInfo);
        if (srcInfo.rasBase && dstInfo.rasBase) {
            union {
                jlong align;
                jint data[LINE_SIZE];
            } rgb;
            SurfaceDataBounds span;

            Region_StartIteration(env, &clipInfo);
            while (Region_NextIteration(&clipInfo, &span)) {
                jlong rowxlong, rowylong;
                void *pDst;

                dy1 = span.y1;
                dy2 = span.y2;
                rowxlong = xbase + (dy1 - dstInfo.bounds.y1) * dxdylong;
                rowylong = ybase + (dy1 - dstInfo.bounds.y1) * dydylong;

                while (dy1 < dy2) {
                    jlong xlong, ylong;

                    /* Note - process at most one scanline at a time. */

                    dx1 = pEdges[(dy1 - dstInfo.bounds.y1) * 2];
                    dx2 = pEdges[(dy1 - dstInfo.bounds.y1) * 2 + 1];
                    if (dx1 < span.x1) dx1 = span.x1;
                    if (dx2 > span.x2) dx2 = span.x2;

                    /* All pixels from dx1 to dx2 have centers in bounds */
                    while (dx1 < dx2) {
                        /* Can process at most one buffer full at a time */
                        jint numpix = dx2 - dx1;
                        if (numpix > maxlinepix) {
                            numpix = maxlinepix;
                        }

                        xlong =
                            rowxlong + ((dx1 - dstInfo.bounds.x1) * dxdxlong);
                        ylong =
                            rowylong + ((dx1 - dstInfo.bounds.x1) * dydxlong);

                        /* Get IntArgbPre pixel data from source */
                        (*pHelperFunc)(&srcInfo,
                                       rgb.data, numpix,
                                       xlong, dxdxlong,
                                       ylong, dydxlong);

                        /* Interpolate result pixels if needed */
                        if (pInterpFunc) {
                            (*pInterpFunc)(rgb.data, numpix,
                                           FractOfLong(xlong-LongOneHalf),
                                           FractOfLong(dxdxlong),
                                           FractOfLong(ylong-LongOneHalf),
                                           FractOfLong(dydxlong));
                        }

                        /* Store/Composite interpolated pixels into dest */
                        pDst = PtrCoord(dstInfo.rasBase,
                                        dx1, dstInfo.pixelStride,
                                        dy1, dstInfo.scanStride);
                        (*pMaskBlitPrim->funcs.maskblit)(pDst, rgb.data,
                                                         0, 0, 0,
                                                         numpix, 1,
                                                         &dstInfo, &srcInfo,
                                                         pMaskBlitPrim,
                                                         &compInfo);

                        /* Increment to next buffer worth of input pixels */
                        dx1 += maxlinepix;
                    }

                    /* Increment to next scanline */
                    rowxlong += dxdylong;
                    rowylong += dydylong;
                    dy1++;
                }
            }
            Region_EndIteration(env, &clipInfo);
        }
        SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
        SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
    }
    SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
    SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
    if (!JNU_IsNull(env, edgeArray)) {
        (*env)->SetIntArrayRegion(env, edgeArray, 0, 1, &dstInfo.bounds.y1);
        (*env)->SetIntArrayRegion(env, edgeArray, 1, 1, &dstInfo.bounds.y2);
        (*env)->SetIntArrayRegion(env, edgeArray,
                                  2, (dstInfo.bounds.y2 - dstInfo.bounds.y1)*2,
                                  pEdges);
    }
    if (pEdges != edgebuf) {
        free(pEdges);
    }
}
Beispiel #7
0
/*
 * Class:     sun_java2d_loops_ScaledBlit
 * Method:    Scale
 * Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;Ljava/awt/Composite;Lsun/java2d/pipe/Region;IIIIDDDD)V
 */
JNIEXPORT void JNICALL
Java_sun_java2d_loops_ScaledBlit_Scale
    (JNIEnv *env, jobject self,
     jobject srcData, jobject dstData,
     jobject comp, jobject clip,
     jint sx1, jint sy1, jint sx2, jint sy2,
     jdouble ddx1, jdouble ddy1, jdouble ddx2, jdouble ddy2)
{
    SurfaceDataOps *srcOps;
    SurfaceDataOps *dstOps;
    SurfaceDataRasInfo srcInfo;
    SurfaceDataRasInfo dstInfo;
    NativePrimitive *pPrim;
    CompositeInfo compInfo;
    jint sxinc, syinc, shift;
    jint tilesize;
    jint idx1, idy1;
    jdouble scalex, scaley;
    RegionData clipInfo;
    jint dstFlags;
    jboolean xunderflow, yunderflow;

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

    srcOps = SurfaceData_GetOps(env, srcData);
    dstOps = SurfaceData_GetOps(env, dstData);
    if (srcOps == 0 || dstOps == 0) {
	return;
    }

    /*
     * Determine the precision to use for the fixed point math
     * for the coordinate scaling.
     * - OR together srcw and srch to get the MSB between the two
     * - Next shift it up until it goes negative
     * - Count the shifts and that will be the most accurate
     *   precision available for the fixed point math
     * - a source coordinate of 1.0 will be (1 << shift)
     * - srcw & srch will be (srcw << shift) and (srch << shift)
     *   and will not overflow
     * Note that if srcw or srch are so large that they are
     * negative numbers before shifting, then:
     * - shift will be 0
     * - tilesize will end up being 1x1 tiles
     * - we will brute force calculate the source location
     *   of every destination pixel using the TILESTART and
     *   SRCLOC macros in this function and then call the
     *   scale helper function to copy one pixel at a time.
     * - TILESTART involves mostly jdouble calculations so
     *   it should not have integer overflow problems.
     */
    sxinc = (sx2 - sx1) | (sy2 - sy1);
    shift = 0;
    if (sxinc > 0) {
        while ((sxinc <<= 1) > 0) {
            shift++;
        }
    }
    /*
     * Now determine the scaled integer increments used to traverse
     * the source image for each destination pixel.  Our shift value
     * has been calculated above so that any location within the
     * destination image can be represented as a scaled integer
     * without incurring integer overflow.
     *
     * But we also need to worry about overflow of the sxinc and syinc
     * parameters.  We already know that "srcw<<shift" and "srch<<shift"
     * cannot overflow a jint, and the only time that sxinc and syinc
     * can be larger than those two values is if ddy2-ddy1 or ddx2-ddx1
     * are smaller than 1.  Since this situation implies that the
     * output area is no more than one pixel wide or tall, then we are
     * stepping by distances that are at least the size of the image
     * and only one destination pixel will ever be rendered - thus the
     * amount by which we step is largely irrelevant since after
     * drawing the first "in bounds" pixel, we will step completely
     * out of the source image and render nothing more.  As a result,
     * we assign the appropriate "size of image" stepping parameter
     * for any scale to smaller than one device pixel.
     */
    yunderflow = (ddy2 - ddy1) < 1.0;
    scaley = (((jdouble) (sy2 - sy1)) / (ddy2 - ddy1)) * (1 << shift);
    syinc = (yunderflow ? ((sy2 - sy1) << shift) : (jint) scaley);
    xunderflow = (ddx2 - ddx1) < 1.0;
    scalex = (((jdouble) (sx2 - sx1)) / (ddx2 - ddx1)) * (1 << shift);
    sxinc = (xunderflow ? ((sx2 - sx1) << shift) : (jint) scalex);
    tilesize = findpow2tilesize(shift, sxinc, syinc);


    srcInfo.bounds.x1 = sx1;
    srcInfo.bounds.y1 = sy1;
    srcInfo.bounds.x2 = sx2;
    srcInfo.bounds.y2 = sy2;
    if (srcOps->Lock(env, srcOps, &srcInfo, pPrim->srcflags) != SD_SUCCESS) {
	return;
    }
    if (srcInfo.bounds.x2 <= srcInfo.bounds.x1 ||
	srcInfo.bounds.y2 <= srcInfo.bounds.y1)
    {
	SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
	return;
    }

    /*
     * Only refine lower bounds if lower source coordinate was clipped
     * because the math will work out to be exactly idx1, idy1 if not.
     * Always refine upper bounds since we want to make sure not to
     * overstep the source bounds based on the tiled iteration math.
     *
     * For underflow cases, simply check if the SRCLOC for the single
     * destination pixel maps inside the source bounds.  If it does,
     * we render that pixel row or column (and only that pixel row
     * or column).  If it does not, we render nothing.
     */
    idx1 = (jint) ceil(ddx1 - 0.5);
    idy1 = (jint) ceil(ddy1 - 0.5);
    if (xunderflow) {
        jdouble x = sx1 + (SRCLOC(idx1, ddx1, scalex) / (1 << shift));
        dstInfo.bounds.x1 = dstInfo.bounds.x2 = idx1;
        if (x >= srcInfo.bounds.x1 && x < srcInfo.bounds.x2) {
            dstInfo.bounds.x2++;
        }
    } else {
        dstInfo.bounds.x1 = ((srcInfo.bounds.x1 <= sx1)
                             ? idx1
                             : refine(idx1, ddx1, tilesize, scalex,
                                      (srcInfo.bounds.x1-sx1) << shift, sxinc));
        dstInfo.bounds.x2 = refine(idx1, ddx1, tilesize, scalex,
                                   (srcInfo.bounds.x2-sx1) << shift, sxinc);
    }
    if (yunderflow) {
        jdouble y = sy1 + (SRCLOC(idy1, ddy1, scaley) / (1 << shift));
        dstInfo.bounds.y1 = dstInfo.bounds.y2 = idy1;
        if (y >= srcInfo.bounds.y1 && y < srcInfo.bounds.y2) {
            dstInfo.bounds.y2++;
        }
    } else {
        dstInfo.bounds.y1 = ((srcInfo.bounds.y1 <= sy1)
                             ? idy1
                             : refine(idy1, ddy1, tilesize, scaley,
                                      (srcInfo.bounds.y1-sy1) << shift, syinc));
        dstInfo.bounds.y2 = refine(idy1, ddy1, tilesize, scaley,
                                   (srcInfo.bounds.y2-sy1) << shift, syinc);
    }

    SurfaceData_IntersectBounds(&dstInfo.bounds, &clipInfo.bounds);
    dstFlags = pPrim->dstflags;
    if (!Region_IsRectangular(&clipInfo)) {
	dstFlags |= SD_LOCK_PARTIAL_WRITE;
    }
    if (dstOps->Lock(env, dstOps, &dstInfo, dstFlags) != SD_SUCCESS) {
	SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
	return;
    }

    if (dstInfo.bounds.x2 > dstInfo.bounds.x1 &&
	dstInfo.bounds.y2 > dstInfo.bounds.y1)
    {
	srcOps->GetRasInfo(env, srcOps, &srcInfo);
	dstOps->GetRasInfo(env, dstOps, &dstInfo);
	if (srcInfo.rasBase && dstInfo.rasBase) {
	    SurfaceDataBounds span;
	    void *pSrc = PtrCoord(srcInfo.rasBase,
				  sx1, srcInfo.pixelStride,
				  sy1, srcInfo.scanStride);

	    Region_IntersectBounds(&clipInfo, &dstInfo.bounds);
	    Region_StartIteration(env, &clipInfo);
	    if (tilesize >= (ddx2 - ddx1) &&
		tilesize >= (ddy2 - ddy1))
	    {
		/* Do everything in one tile */
		jint sxloc = (jint) SRCLOC(idx1, ddx1, scalex);
		jint syloc = (jint) SRCLOC(idy1, ddy1, scaley);
		while (Region_NextIteration(&clipInfo, &span)) {
		    jint tsxloc = sxloc;
		    jint tsyloc = syloc;
		    void *pDst;

		    if (span.y1 > idy1) {
			tsyloc += syinc * (span.y1 - idy1);
		    }
		    if (span.x1 > idx1) {
			tsxloc += sxinc * (span.x1 - idx1);
		    }

		    pDst = PtrCoord(dstInfo.rasBase,
				    span.x1, dstInfo.pixelStride,
				    span.y1, dstInfo.scanStride);
		    (*pPrim->funcs.scaledblit)(pSrc, pDst,
					       span.x2-span.x1, span.y2-span.y1,
					       tsxloc, tsyloc,
					       sxinc, syinc, shift,
					       &srcInfo, &dstInfo,
					       pPrim, &compInfo);
		}
	    } else {
		/* Break each clip span into tiles for better accuracy. */
		while (Region_NextIteration(&clipInfo, &span)) {
		    jint tilex, tiley;
		    jint sxloc, syloc;
		    jint x1, y1, x2, y2;
		    void *pDst;

		    for (tiley = TILESTART(span.y1, idy1, tilesize);
			 tiley < span.y2;
			 tiley += tilesize)
		    {
			/* Clip span to Y range of current tile */
			y1 = tiley;
			y2 = tiley + tilesize;
			if (y1 < span.y1) y1 = span.y1;
			if (y2 > span.y2) y2 = span.y2;

			/* Find scaled source coordinate of first pixel */
			syloc = (jint) SRCLOC(tiley, ddy1, scaley);
			if (y1 > tiley) {
			    syloc += syinc * (y1 - tiley);
			}

			for (tilex = TILESTART(span.x1, idx1, tilesize);
			     tilex < span.x2;
			     tilex += tilesize)
			{
			    /* Clip span to X range of current tile */
			    x1 = tilex;
			    x2 = tilex + tilesize;
			    if (x1 < span.x1) x1 = span.x1;
			    if (x2 > span.x2) x2 = span.x2;

			    /* Find scaled source coordinate of first pixel */
			    sxloc = (jint) SRCLOC(tilex, ddx1, scalex);
			    if (x1 > tilex) {
				sxloc += sxinc * (x1 - tilex);
			    }

			    pDst = PtrCoord(dstInfo.rasBase,
					    x1, dstInfo.pixelStride,
					    y1, dstInfo.scanStride);
			    (*pPrim->funcs.scaledblit)(pSrc, pDst, x2-x1, y2-y1,
						       sxloc, syloc,
						       sxinc, syinc, shift,
						       &srcInfo, &dstInfo,
						       pPrim, &compInfo);
			}
		    }
		}
	    }
	    Region_EndIteration(env, &clipInfo);
	}
	SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
	SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
    }
    SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
    SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
}
Beispiel #8
0
/*
 * Class:     sun_java2d_loops_ScaledBlit
 * Method:    Scale
 * Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;Ljava/awt/Composite;IIIIIIII)V
 */
JNIEXPORT void JNICALL
Java_sun_java2d_loops_ScaledBlit_Scale
    (JNIEnv *env, jobject self,
     jobject srcData, jobject dstData,
     jobject comp, jobject clip,
     jint srcx, jint srcy, jint dstx, jint dsty,
     jint srcw, jint srch, jint dstw, jint dsth)
{
    SurfaceDataOps *srcOps;
    SurfaceDataOps *dstOps;
    SurfaceDataRasInfo srcInfo;
    SurfaceDataRasInfo dstInfo;
    NativePrimitive *pPrim;
    CompositeInfo compInfo;
    jint sxloc, syloc, sxinc, syinc, shift;
    double scale;
    RegionData clipInfo;
    jint dstFlags;

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

    srcOps = SurfaceData_GetOps(env, srcData);
    dstOps = SurfaceData_GetOps(env, dstData);
    if (srcOps == 0 || dstOps == 0) {
	return;
    }

    /*
     * Determine the precision to use for the fixed point math
     * for the coordinate scaling.
     * - OR together srcw and srch to get the MSB between the two
     * - Next shift it up until it goes negative
     * - Count the shifts and that will be the most accurate
     *   precision available for the fixed point math
     * - 1.0 will be (1 << shift)
     * - srcw & srch will be (srcw << shift) and (srch << shift)
     *   and will not overflow
     */
    sxloc = srcw | srch;
    shift = 0;
    while ((sxloc <<= 1) > 0) {
	shift++;
    }
    sxloc = (1 << shift);
    scale = ((double) (srch)) / ((double) (dsth));
    syinc = (int) (scale * sxloc);
    scale = ((double) (srcw)) / ((double) (dstw));
    sxinc = (int) (scale * sxloc);

    /*
     * Round by setting the initial sxyloc to half a destination
     * pixel which equals half of the x/y increments.
     */
    sxloc = sxinc / 2;
    syloc = syinc / 2;

    srcw += srcx;
    srch += srcy;
    srcInfo.bounds.x1 = srcx;
    srcInfo.bounds.y1 = srcy;
    srcInfo.bounds.x2 = srcw;
    srcInfo.bounds.y2 = srch;
    if (srcOps->Lock(env, srcOps, &srcInfo, pPrim->srcflags) != SD_SUCCESS) {
	return;
    }
    if (srcInfo.bounds.x2 <= srcInfo.bounds.x1 ||
	srcInfo.bounds.y2 <= srcInfo.bounds.y1)
    {
	SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
	return;
    }
    dstw += dstx;
    dsth += dsty;
    Scale_adjustUp(srcx, srcInfo.bounds.x1,
		   &sxloc, sxinc, shift,
		   &dstx);
    Scale_adjustUp(srcy, srcInfo.bounds.y1,
		   &syloc, syinc, shift,
		   &dsty);
    Scale_adjustDn(srcw, srcInfo.bounds.x1, srcInfo.bounds.x2,
		   sxloc, sxinc, shift,
		   dstx, &dstw);
    Scale_adjustDn(srch, srcInfo.bounds.y1, srcInfo.bounds.y2,
		   syloc, syinc, shift,
		   dsty, &dsth);

    dstInfo.bounds.x1 = dstx;
    dstInfo.bounds.y1 = dsty;
    dstInfo.bounds.x2 = dstw;
    dstInfo.bounds.y2 = dsth;
    SurfaceData_IntersectBounds(&dstInfo.bounds, &clipInfo.bounds);
    dstFlags = pPrim->dstflags;
    if (!Region_IsRectangular(&clipInfo)) {
	dstFlags |= SD_LOCK_PARTIAL_WRITE;
    }
    if (dstOps->Lock(env, dstOps, &dstInfo, dstFlags) != SD_SUCCESS) {
	SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
	return;
    }

    if (dstInfo.bounds.x2 > dstInfo.bounds.x1 &&
	dstInfo.bounds.y2 > dstInfo.bounds.y1)
    {
	srcOps->GetRasInfo(env, srcOps, &srcInfo);
	dstOps->GetRasInfo(env, dstOps, &dstInfo);
	if (srcInfo.rasBase && dstInfo.rasBase) {
	    SurfaceDataBounds span;
	    void *pSrc = PtrCoord(srcInfo.rasBase,
				  srcInfo.bounds.x1, srcInfo.pixelStride,
				  srcInfo.bounds.y1, srcInfo.scanStride);
	    Region_IntersectBounds(&clipInfo, &dstInfo.bounds);
	    Region_StartIteration(env, &clipInfo);
	    while (Region_NextIteration(&clipInfo, &span)) {
		jint width = span.x2 - span.x1;
		jint height = span.y2 - span.y1;
		jint tsxloc = sxloc;
		jint tsyloc = syloc;
		void *pDst = PtrCoord(dstInfo.rasBase,
				      span.x1, dstInfo.pixelStride,
				      span.y1, dstInfo.scanStride);
		if (span.y1 > dsty) {
		    tsyloc += syinc * (span.y1 - dsty);
		}
		if (span.x1 > dstx) {
		    tsxloc += sxinc * (span.x1 - dstx);
		}
		(*pPrim->funcs.scaledblit)(pSrc, pDst, width, height,
					   tsxloc, tsyloc, sxinc, syinc, shift,
					   &srcInfo, &dstInfo,
					   pPrim, &compInfo);
	    }
	    Region_EndIteration(env, &clipInfo);
	}
	SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
	SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
    }
    SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
    SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
}