/* * 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_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_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); }