/* * Class: sun_awt_image_DataBufferNative * Method: getElem * Signature: */ JNIEXPORT jint JNICALL Java_sun_awt_image_DataBufferNative_getElem(JNIEnv *env, jobject dbn, jint x, jint y, jobject sd) { jint returnVal = -1; unsigned char *pixelPtr; SurfaceDataRasInfo lockInfo; SurfaceDataOps *ops; ops = SurfaceData_GetOps(env, sd); if (!(pixelPtr = DBN_GetPixelPointer(env, x, y, &lockInfo, ops, SD_LOCK_READ))) { return returnVal; } switch (lockInfo.pixelStride) { case 4: returnVal = *(int *)pixelPtr; break; /* REMIND: do we need a 3-byte case (for 24-bit) here? */ case 2: returnVal = *(unsigned short *)pixelPtr; break; case 1: returnVal = *pixelPtr; break; default: break; } SurfaceData_InvokeRelease(env, ops, &lockInfo); SurfaceData_InvokeUnlock(env, ops, &lockInfo); return returnVal; }
unsigned char *DBN_GetPixelPointer(JNIEnv *env, jint x, int y, SurfaceDataRasInfo *lockInfo, SurfaceDataOps *ops, int lockFlag) { if (ops == NULL) { return NULL; } lockInfo->bounds.x1 = x; lockInfo->bounds.y1 = y; lockInfo->bounds.x2 = x + 1; lockInfo->bounds.y2 = y + 1; if (ops->Lock(env, ops, lockInfo, lockFlag) != SD_SUCCESS) { return NULL; } ops->GetRasInfo(env, ops, lockInfo); if (lockInfo->rasBase) { unsigned char *pixelPtr = ( (unsigned char*)lockInfo->rasBase + (x * lockInfo->pixelStride + y * lockInfo->scanStride)); return pixelPtr; } SurfaceData_InvokeRelease(env, ops, lockInfo); SurfaceData_InvokeUnlock(env, ops, lockInfo); return NULL; }
/* * Class: sun_java2d_loops_FillRect * Method: FillRect * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;IIII)V */ JNIEXPORT void JNICALL Java_sun_java2d_loops_FillRect_FillRect (JNIEnv *env, jobject self, jobject sg2d, jobject sData, jint x, jint y, jint w, jint h) { SurfaceDataOps *sdOps; SurfaceDataRasInfo rasInfo; NativePrimitive *pPrim; CompositeInfo compInfo; jint pixel = GrPrim_Sg2dGetPixel(env, sg2d); if (w <= 0 || h <= 0) { return; } pPrim = GetNativePrim(env, self); if (pPrim == NULL) { return; } if (pPrim->pCompType->getCompInfo != NULL) { GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo); } sdOps = SurfaceData_GetOps(env, sData); if (sdOps == 0) { return; } GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); SurfaceData_IntersectBoundsXYWH(&rasInfo.bounds, x, y, w, h); 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; } if (rasInfo.bounds.x2 > rasInfo.bounds.x1 && rasInfo.bounds.y2 > rasInfo.bounds.y1) { sdOps->GetRasInfo(env, sdOps, &rasInfo); if (rasInfo.rasBase) { (*pPrim->funcs.fillrect)(&rasInfo, rasInfo.bounds.x1, rasInfo.bounds.y1, rasInfo.bounds.x2, rasInfo.bounds.y2, pixel, pPrim, &compInfo); } SurfaceData_InvokeRelease(env, sdOps, &rasInfo); } SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); }
/* * 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); }
/* * 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_Sg2dGetRGB(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); 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); }
/* * Class: sun_java2d_loops_FillPath * Method: FillPath * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;IILjava/awt/geom/Path2D.Float;)V */ JNIEXPORT void JNICALL Java_sun_java2d_loops_FillPath_FillPath (JNIEnv *env, jobject self, jobject sg2d, jobject sData, jint transX, jint transY, jobject p2df) { jarray typesArray; jarray coordsArray; jint numTypes; jint fillRule; jboolean ok = JNI_TRUE; jint pixel = GrPrim_Sg2dGetPixel(env, sg2d); jint maxCoords; jfloat *coords; SurfaceDataOps *sdOps; SurfaceDataRasInfo rasInfo; CompositeInfo compInfo; jint ret; NativePrimitive *pPrim = GetNativePrim(env, self); jint stroke = (*env)->GetIntField(env, sg2d, sg2dStrokeHintID); if (pPrim == NULL) { return; } if (pPrim->pCompType->getCompInfo != NULL) { GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo); } sdOps = SurfaceData_GetOps(env, sData); if (sdOps == 0) { return; } typesArray = (jarray)(*env)->GetObjectField(env, p2df, path2DTypesID); coordsArray = (jarray)(*env)->GetObjectField(env, p2df, path2DFloatCoordsID); if (coordsArray == NULL) { JNU_ThrowNullPointerException(env, "coordinates array"); return; } numTypes = (*env)->GetIntField(env, p2df, path2DNumTypesID); fillRule = (*env)->GetIntField(env, p2df, path2DWindingRuleID); if ((*env)->GetArrayLength(env, typesArray) < numTypes) { JNU_ThrowArrayIndexOutOfBoundsException(env, "types array"); return; } GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); ret = sdOps->Lock(env, sdOps, &rasInfo, SD_LOCK_FASTEST | pPrim->dstflags); if (ret == SD_FAILURE) { return; } maxCoords = (*env)->GetArrayLength(env, coordsArray); coords = (jfloat*)(*env)->GetPrimitiveArrayCritical( env, coordsArray, NULL); if (ret == SD_SLOWLOCK) { GrPrim_RefineBounds(&rasInfo.bounds, transX, transY, coords, maxCoords); ok = (rasInfo.bounds.x2 > rasInfo.bounds.x1 && rasInfo.bounds.y2 > rasInfo.bounds.y1); } if (ok) { sdOps->GetRasInfo(env, sdOps, &rasInfo); if (rasInfo.rasBase) { if (rasInfo.bounds.x2 > rasInfo.bounds.x1 && rasInfo.bounds.y2 > rasInfo.bounds.y1) { DrawHandlerData dHData; DrawHandler drawHandler = { NULL, NULL, &drawScanline, 0, 0, 0, 0, 0, 0, 0, 0, NULL }; jbyte *types = (jbyte*)(*env)->GetPrimitiveArrayCritical( env, typesArray, NULL); /* Initialization of the following fields in the declaration of * the dHData and drawHandler above causes warnings on sun * studio compiler with * -xc99=%none option applied (this option means compliance * with C90 standard instead of C99) */ dHData.pRasInfo = &rasInfo; dHData.pixel = pixel; dHData.pPrim = pPrim; dHData.pCompInfo = &compInfo; drawHandler.xMin = rasInfo.bounds.x1; drawHandler.yMin = rasInfo.bounds.y1; drawHandler.xMax = rasInfo.bounds.x2; drawHandler.yMax = rasInfo.bounds.y2; drawHandler.pData = &dHData; if (!doFillPath(&drawHandler, transX, transY, coords, maxCoords, types, numTypes, (stroke == sunHints_INTVAL_STROKE_PURE)? PH_STROKE_PURE : PH_STROKE_DEFAULT, fillRule)) { JNU_ThrowArrayIndexOutOfBoundsException(env, "coords array"); } (*env)->ReleasePrimitiveArrayCritical(env, typesArray, types, JNI_ABORT); } } SurfaceData_InvokeRelease(env, sdOps, &rasInfo); } (*env)->ReleasePrimitiveArrayCritical(env, coordsArray, coords, JNI_ABORT); SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); }
/* * Class: sun_java2d_loops_DrawPolygons * Method: DrawPolygons * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;[I[I[IIIIZ)V */ JNIEXPORT void JNICALL Java_sun_java2d_loops_DrawPolygons_DrawPolygons (JNIEnv *env, jobject self, jobject sg2d, jobject sData, jintArray xPointsArray, jintArray yPointsArray, jintArray nPointsArray, jint numPolys, jint transX, jint transY, jboolean close) { SurfaceDataOps *sdOps; SurfaceDataRasInfo rasInfo; NativePrimitive *pPrim; CompositeInfo compInfo; jsize nPointsLen, xPointsLen, yPointsLen; jint *nPointsPtr = NULL; jint *xPointsPtr = NULL; jint *yPointsPtr = NULL; jint pointsNeeded; jint i, ret; jboolean ok = JNI_TRUE; jint pixel = GrPrim_Sg2dGetPixel(env, sg2d); if (JNU_IsNull(env, xPointsArray) || JNU_IsNull(env, yPointsArray)) { JNU_ThrowNullPointerException(env, "coordinate array"); return; } if (JNU_IsNull(env, nPointsArray)) { JNU_ThrowNullPointerException(env, "polygon length array"); return; } nPointsLen = (*env)->GetArrayLength(env, nPointsArray); xPointsLen = (*env)->GetArrayLength(env, xPointsArray); yPointsLen = (*env)->GetArrayLength(env, yPointsArray); if (nPointsLen < numPolys) { JNU_ThrowArrayIndexOutOfBoundsException(env, "polygon length array size"); return; } pPrim = GetNativePrim(env, self); if (pPrim == NULL) { return; } if (pPrim->pCompType->getCompInfo != NULL) { GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo); } sdOps = SurfaceData_GetOps(env, sData); if (sdOps == 0) { return; } GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); ret = sdOps->Lock(env, sdOps, &rasInfo, SD_LOCK_FASTEST | pPrim->dstflags); if (ret == SD_FAILURE) { return; } nPointsPtr = (*env)->GetPrimitiveArrayCritical(env, nPointsArray, NULL); if (!nPointsPtr) { ok = JNI_FALSE; } if (ok) { pointsNeeded = 0; for (i = 0; i < numPolys; i++) { if (nPointsPtr[i] > 0) { pointsNeeded += nPointsPtr[i]; } } if (yPointsLen < pointsNeeded || xPointsLen < pointsNeeded) { (*env)->ReleasePrimitiveArrayCritical(env, nPointsArray, nPointsPtr, JNI_ABORT); SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); JNU_ThrowArrayIndexOutOfBoundsException(env, "coordinate array length"); return; } xPointsPtr = (*env)->GetPrimitiveArrayCritical(env, xPointsArray, NULL); yPointsPtr = (*env)->GetPrimitiveArrayCritical(env, yPointsArray, NULL); if (!xPointsPtr || !yPointsPtr) { ok = JNI_FALSE; } } if (ok) { if (ret == SD_SLOWLOCK) { RefineBounds(&rasInfo.bounds, transX, transY, xPointsPtr, yPointsPtr, pointsNeeded); ok = (rasInfo.bounds.x2 > rasInfo.bounds.x1 && rasInfo.bounds.y2 > rasInfo.bounds.y1); } } if (ok) { sdOps->GetRasInfo(env, sdOps, &rasInfo); if (rasInfo.rasBase && rasInfo.bounds.x2 > rasInfo.bounds.x1 && rasInfo.bounds.y2 > rasInfo.bounds.y1) { ProcessPoly(&rasInfo, pPrim->funcs.drawline, pPrim, &compInfo, pixel, transX, transY, xPointsPtr, yPointsPtr, nPointsPtr, numPolys, close); } SurfaceData_InvokeRelease(env, sdOps, &rasInfo); } if (nPointsPtr) { (*env)->ReleasePrimitiveArrayCritical(env, nPointsArray, nPointsPtr, JNI_ABORT); } if (xPointsPtr) { (*env)->ReleasePrimitiveArrayCritical(env, xPointsArray, xPointsPtr, JNI_ABORT); } if (yPointsPtr) { (*env)->ReleasePrimitiveArrayCritical(env, yPointsArray, yPointsPtr, JNI_ABORT); } SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); }
/* * 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); }
/* * 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); }
/* * Class: sun_java2d_loops_DrawRect * Method: DrawRect * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;IIII)V */ JNIEXPORT void JNICALL Java_sun_java2d_loops_DrawRect_DrawRect (JNIEnv *env, jobject self, jobject sg2d, jobject sData, jint x, jint y, jint w, jint h) { SurfaceDataOps *sdOps; SurfaceDataRasInfo rasInfo; NativePrimitive *pPrim; CompositeInfo compInfo; jint lox, loy, hix, hiy; jint pixel = GrPrim_Sg2dGetPixel(env, sg2d); if (w < 0 || h < 0) { return; } pPrim = GetNativePrim(env, self); if (pPrim == NULL) { return; } if (pPrim->pCompType->getCompInfo != NULL) { GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo); } sdOps = SurfaceData_GetOps(env, sData); if (sdOps == 0) { return; } lox = x; loy = y; hix = x + w + 1; hiy = y + h + 1; if (hix < lox) { hix = 0x7fffffff; } if (hiy < loy) { hiy = 0x7fffffff; } GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); if (rasInfo.bounds.x1 < lox) rasInfo.bounds.x1 = lox; if (rasInfo.bounds.y1 < loy) rasInfo.bounds.y1 = loy; if (rasInfo.bounds.x2 > hix) rasInfo.bounds.x2 = hix; if (rasInfo.bounds.y2 > hiy) rasInfo.bounds.y2 = hiy; if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) { return; } if (rasInfo.bounds.x2 > rasInfo.bounds.x1 && rasInfo.bounds.y2 > rasInfo.bounds.y1) { sdOps->GetRasInfo(env, sdOps, &rasInfo); if (rasInfo.rasBase) { DrawLineFunc *pLine = pPrim->funcs.drawline; int loyin = (loy == rasInfo.bounds.y1); int hiyin = (hiy == rasInfo.bounds.y2); int xsize = (rasInfo.bounds.x2 - rasInfo.bounds.x1); int ysize = (rasInfo.bounds.y2 - rasInfo.bounds.y1 - loyin - hiyin); /* * To avoid drawing the corners twice (both for performance * and because XOR erases them otherwise) and to maximize the * number of pixels we draw in the horizontal portions * which are more cache-friendly, we include the corner * pixels only in the top and bottom segments. * We also protect against degenerate rectangles where we * would draw the same line for top & bottom or left & right. */ if (loyin) { /* Line across the top */ (*pLine)(&rasInfo, rasInfo.bounds.x1, rasInfo.bounds.y1, pixel, xsize, 0, BUMP_POS_PIXEL, 0, BUMP_NOOP, 0, pPrim, &compInfo); } if (lox == rasInfo.bounds.x1 && ysize > 0) { /* Line down the left side */ (*pLine)(&rasInfo, rasInfo.bounds.x1, rasInfo.bounds.y1 + loyin, pixel, ysize, 0, BUMP_POS_SCAN, 0, BUMP_NOOP, 0, pPrim, &compInfo); } if (hix == rasInfo.bounds.x2 && ysize > 0 && lox != hix - 1) { /* Line down the right side */ (*pLine)(&rasInfo, rasInfo.bounds.x2 - 1, rasInfo.bounds.y1 + loyin, pixel, ysize, 0, BUMP_POS_SCAN, 0, BUMP_NOOP, 0, pPrim, &compInfo); } if (hiyin && loy != hiy - 1) { /* Line across the bottom */ (*pLine)(&rasInfo, rasInfo.bounds.x1, rasInfo.bounds.y2 - 1, pixel, xsize, 0, BUMP_POS_PIXEL, 0, BUMP_NOOP, 0, pPrim, &compInfo); } } SurfaceData_InvokeRelease(env, sdOps, &rasInfo); } SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); }
static void drawGlyphListLCD(JNIEnv *env, jobject self, jobject sg2d, jobject sData, GlyphBlitVector *gbv, jint pixel, jint color, jboolean rgbOrder, int contrast, NativePrimitive *pPrim, DrawGlyphListLCDFunc *func) { SurfaceDataOps *sdOps; SurfaceDataRasInfo rasInfo; CompositeInfo compInfo; int clipLeft, clipRight, clipTop, clipBottom; int ret; sdOps = SurfaceData_GetOps(env, sData); if (sdOps == 0) { return; } if (pPrim->pCompType->getCompInfo != NULL) { GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo); } GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 || rasInfo.bounds.x2 <= rasInfo.bounds.x1) { return; } ret = sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags); if (ret != SD_SUCCESS) { if (ret == SD_SLOWLOCK) { if (!RefineBounds(gbv, &rasInfo.bounds)) { SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); return; } } else { return; } } sdOps->GetRasInfo(env, sdOps, &rasInfo); if (!rasInfo.rasBase) { SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); return; } clipLeft = rasInfo.bounds.x1; clipRight = rasInfo.bounds.x2; clipTop = rasInfo.bounds.y1; clipBottom = rasInfo.bounds.y2; if (clipRight > clipLeft && clipBottom > clipTop) { (*func)(&rasInfo, gbv->glyphs, gbv->numGlyphs, pixel, color, clipLeft, clipTop, clipRight, clipBottom, (jint)rgbOrder, getLCDGammaLUT(contrast), getInvLCDGammaLUT(contrast), pPrim, &compInfo); SurfaceData_InvokeRelease(env, sdOps, &rasInfo); } SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); }
/* * 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); } }
/* * 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); }
/* * Class: sun_java2d_windows_GDIBlitLoops * Method: nativeBlit * Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;IIIIIIZ)V */ JNIEXPORT void JNICALL Java_sun_java2d_windows_GDIBlitLoops_nativeBlit (JNIEnv *env, jobject joSelf, jobject srcData, jobject dstData, jobject clip, jint srcx, jint srcy, jint dstx, jint dsty, jint width, jint height, jint rmask, jint gmask, jint bmask, jboolean needLut) { J2dTraceLn(J2D_TRACE_INFO, "GDIBlitLoops_nativeBlit"); SurfaceDataRasInfo srcInfo; SurfaceDataOps *srcOps = SurfaceData_GetOps(env, srcData); GDIWinSDOps *dstOps = GDIWindowSurfaceData_GetOps(env, dstData); jint lockFlags; HDC hDC = dstOps->GetDC(env, dstOps, 0, NULL, clip, NULL, 0); if (hDC == NULL) { return; } srcInfo.bounds.x1 = srcx; srcInfo.bounds.y1 = srcy; srcInfo.bounds.x2 = srcx + width; srcInfo.bounds.y2 = srcy + height; if (needLut) { lockFlags = (SD_LOCK_READ | SD_LOCK_LUT); } else { lockFlags = SD_LOCK_READ; } if (srcOps->Lock(env, srcOps, &srcInfo, lockFlags) != SD_SUCCESS) { dstOps->ReleaseDC(env, dstOps, hDC); return; } SurfaceDataBounds dstBounds = {dstx, dsty, dstx + width, dsty + height}; // Intersect the source and dest rects. Note that the source blit bounds // will be adjusted to the surfaces's bounds if needed. SurfaceData_IntersectBlitBounds(&(srcInfo.bounds), &dstBounds, dstx - srcx, dsty - srcy); srcx = srcInfo.bounds.x1; srcy = srcInfo.bounds.y1; dstx = dstBounds.x1; dsty = dstBounds.y1; width = srcInfo.bounds.x2 - srcInfo.bounds.x1; height = srcInfo.bounds.y2 - srcInfo.bounds.y1; if (width > 0 && height > 0) { BmiType bmi; // REMIND: A performance tweak here would be to make some of this // data static. For example, we could have one structure that is // always used for ByteGray copies and we only change dynamic data // in the structure with every new copy. Also, we could store // structures with Ops or with the Java objects so that surfaces // could retain their own DIB info and we would not need to // recreate it every time. srcOps->GetRasInfo(env, srcOps, &srcInfo); void *rasBase = ((char *)srcInfo.rasBase) + srcInfo.scanStride * srcy + srcInfo.pixelStride * srcx; // If scanlines are DWORD-aligned (scanStride is a multiple of 4), // then we can do the work much faster. This is due to a constraint // in the way DIBs are structured and parsed by GDI jboolean fastBlt = ((srcInfo.scanStride & 0x03) == 0); bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = srcInfo.scanStride/srcInfo.pixelStride; // fastBlt copies whole image in one call; else copy line-by-line bmi.bmiHeader.biHeight = (fastBlt) ? -(srcInfo.bounds.y2 - srcInfo.bounds.y1) : -1; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = srcInfo.pixelStride * 8; // 1,3,4 byte use BI_RGB, 2 byte use BI_BITFIELD... // 4 byte _can_ use BI_BITFIELD, but this seems to cause a performance // penalty. Since we only ever have one format (xrgb) for 32-bit // images that enter this function, just use BI_RGB. // Could do BI_RGB for 2-byte 555 format, but no perceived // performance benefit. bmi.bmiHeader.biCompression = (srcInfo.pixelStride != 2) ? BI_RGB : BI_BITFIELDS; bmi.bmiHeader.biSizeImage = (bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight * srcInfo.pixelStride); bmi.bmiHeader.biXPelsPerMeter = 0; bmi.bmiHeader.biYPelsPerMeter = 0; bmi.bmiHeader.biClrUsed = 0; bmi.bmiHeader.biClrImportant = 0; if (srcInfo.pixelStride == 1) { // Copy palette info into bitmap for 8-bit image if (needLut) { memcpy(bmi.colors.palette, srcInfo.lutBase, srcInfo.lutSize * sizeof(RGBQUAD)); if (srcInfo.lutSize != 256) { bmi.bmiHeader.biClrUsed = srcInfo.lutSize; } } else { // If no LUT needed, must be ByteGray src. If we have not // yet created the byteGrayPalette, create it now and copy // it into our temporary bmi structure. // REMIND: byteGrayPalette is a leak since we do not have // a mechansim to free it up. This should be fine, since it // is only 256 bytes for any process and only gets malloc'd // when using ByteGray surfaces. Eventually, we should use // the new Disposer mechanism to delete this native memory. if (byteGrayPalette == NULL) { byteGrayPalette = (RGBQUAD *)safe_Malloc(256 * sizeof(RGBQUAD)); for (int i = 0; i < 256; ++i) { byteGrayPalette[i].rgbRed = i; byteGrayPalette[i].rgbGreen = i; byteGrayPalette[i].rgbBlue = i; } } memcpy(bmi.colors.palette, byteGrayPalette, 256 * sizeof(RGBQUAD)); } } else if (srcInfo.pixelStride == 2) { // For 16-bit case, init the masks for the pixel depth bmi.colors.dwMasks[0] = rmask; bmi.colors.dwMasks[1] = gmask; bmi.colors.dwMasks[2] = bmask; } if (fastBlt) { // Window could go away at any time, leaving bits on the screen // from this GDI call, so make sure window still exists if (::IsWindowVisible(dstOps->window)) { // Could also call StretchDIBits. Testing showed slight // performance advantage of SetDIBits instead, so since we // have no need of scaling, might as well use SetDIBits. SetDIBitsToDevice(hDC, dstx, dsty, width, height, 0, 0, 0, height, rasBase, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); } } else { // Source scanlines not DWORD-aligned - copy each scanline individually for (int i = 0; i < height; i += 1) { if (::IsWindowVisible(dstOps->window)) { SetDIBitsToDevice(hDC, dstx, dsty+i, width, 1, 0, 0, 0, 1, rasBase, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); rasBase = (void*)((char*)rasBase + srcInfo.scanStride); } else { break; } } } SurfaceData_InvokeRelease(env, srcOps, &srcInfo); } SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); dstOps->ReleaseDC(env, dstOps, hDC); return; }
/* * 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); }