sg.imageComp,
bgColor);
}
SurfaceType srcType = srcData.getSurfaceType();
TransformHelper helper = TransformHelper.getFromCache(srcType);
if (helper == null) {
/* We have no helper for this source image type.
* But we know that we do have helpers for both RGB and ARGB,
* so convert to one of those types depending on transparency.
* ARGB_PRE might be a better choice if the source image has
* alpha, but it may cause some recursion here since we only
* tend to have converters that convert to ARGB.
*/
int type = ((srcData.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB
: BufferedImage.TYPE_INT_ARGB);
img = makeBufferedImage(img, null, type, sx1, sy1, sx2, sy2);
// Temp image has appropriate subimage at 0,0 now.
sx2 -= sx1;
sy2 -= sy1;
sx1 = sy1 = 0;
srcData = dstData.getSourceSurfaceData(img,
sg.TRANSFORM_GENERIC,
sg.imageComp,
null);
srcType = srcData.getSurfaceType();
helper = TransformHelper.getFromCache(srcType);
// assert(helper != null);
}
AffineTransform itx;
try {
itx = tx.createInverse();
} catch (NoninvertibleTransformException e) {
// Non-invertible transform means no output
return;
}
/*
* Find the maximum bounds on the destination that will be
* affected by the transformed source. First, transform all
* four corners of the source and then min and max the resulting
* destination coordinates of the transformed corners.
* Note that tx already has the offset to sx1,sy1 accounted
* for so we use the box (0, 0, sx2-sx1, sy2-sy1) as the
* source coordinates.
*/
double coords[] = new double[8];
/* corner: UL UR LL LR */
/* index: 0 1 2 3 4 5 6 7 */
/* coord: (0, 0), (w, 0), (0, h), (w, h) */
coords[2] = coords[6] = sx2 - sx1;
coords[5] = coords[7] = sy2 - sy1;
tx.transform(coords, 0, coords, 0, 4);
double ddx1, ddy1, ddx2, ddy2;
ddx1 = ddx2 = coords[0];
ddy1 = ddy2 = coords[1];
for (int i = 2; i < coords.length; i += 2) {
double d = coords[i];
if (ddx1 > d) ddx1 = d;
else if (ddx2 < d) ddx2 = d;
d = coords[i+1];
if (ddy1 > d) ddy1 = d;
else if (ddy2 < d) ddy2 = d;
}
int dx1 = (int) Math.floor(ddx1);
int dy1 = (int) Math.floor(ddy1);
int dx2 = (int) Math.ceil(ddx2);
int dy2 = (int) Math.ceil(ddy2);
SurfaceType dstType = dstData.getSurfaceType();
MaskBlit maskblit;
Blit blit;
if (sg.compositeState <= sg.COMP_ALPHA) {
/* NOTE: We either have, or we can make,
* a MaskBlit for any alpha composite type
*/
maskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre,
sg.imageComp,
dstType);
/* NOTE: We can only use the native TransformHelper
* func to go directly to the dest if both the helper
* and the MaskBlit are native.
* All helpers are native at this point, but some MaskBlit
* objects are implemented in Java, so we need to check.
*/
if (maskblit.getNativePrim() != 0) {
// We can render directly.
helper.Transform(maskblit, srcData, dstData,
sg.composite, clip,
itx, interpType,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2,
null, 0, 0);
return;
}
blit = null;
} else {
/* NOTE: We either have, or we can make,
* a Blit for any composite type, even Custom
*/
maskblit = null;
blit = Blit.getFromCache(SurfaceType.IntArgbPre,
sg.imageComp,
dstType);
}
// We need to transform to a temp image and then copy
// just the pieces that are valid data to the dest.
BufferedImage tmpimg = new BufferedImage(dx2-dx1, dy2-dy1,
BufferedImage.TYPE_INT_ARGB);
SurfaceData tmpData = SurfaceData.getPrimarySurfaceData(tmpimg);
SurfaceType tmpType = tmpData.getSurfaceType();
MaskBlit tmpmaskblit =
MaskBlit.getFromCache(SurfaceType.IntArgbPre,
CompositeType.SrcNoEa,
tmpType);
/*
* The helper function fills a temporary edges buffer
* for us with the bounding coordinates of each scanline
* in the following format:
*
* edges[0, 1] = [top y, bottom y)
* edges[2, 3] = [left x, right x) of top row
* ...
* edges[h*2, h*2+1] = [left x, right x) of bottom row
*
* all coordinates in the edges array will be relative to dx1, dy1
*
* edges thus has to be h*2+2 in length
*/
int edges[] = new int[(dy2-dy1)*2+2];
helper.Transform(tmpmaskblit, srcData, tmpData,
AlphaComposite.Src, null,
itx, interpType,
sx1, sy1, sx2, sy2,
0, 0, dx2-dx1, dy2-dy1,
edges, dx1, dy1);