--- old/src/java.desktop/share/classes/sun/java2d/pipe/DrawImage.java 2014-11-10 20:52:24.509255500 +0400 +++ new/src/java.desktop/share/classes/sun/java2d/pipe/DrawImage.java 2014-11-10 20:52:24.353255200 +0400 @@ -364,8 +364,53 @@ int sx1, int sy1, int sx2, int sy2, Color bgColor) { + final AffineTransform itx; + try { + itx = tx.createInverse(); + } catch (final NoninvertibleTransformException ignored) { + // 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. + */ + final 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; + } + Region clip = sg.getCompClip(); - SurfaceData dstData = sg.surfaceData; + final int dx1 = Math.max((int) Math.floor(ddx1), clip.lox); + final int dy1 = Math.max((int) Math.floor(ddy1), clip.loy); + final int dx2 = Math.min((int) Math.ceil(ddx2), clip.hix); + final int dy2 = Math.min((int) Math.ceil(ddy2), clip.hiy); + if (dx2 <= dx1 || dy2 <= dy1) { + // empty destination means no output + return; + } + + final SurfaceData dstData = sg.surfaceData; SurfaceData srcData = dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_GENERIC, sg.imageComp, @@ -429,56 +474,13 @@ // 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 <= SunGraphics2D.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); + MaskBlit 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 @@ -496,27 +498,19 @@ 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, + final int w = dx2 - dx1; + final int h = dy2 - dy1; + BufferedImage tmpimg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); SurfaceData tmpData = SurfaceData.getPrimarySurfaceData(tmpimg); SurfaceType tmpType = tmpData.getSurfaceType(); - MaskBlit tmpmaskblit = - MaskBlit.getFromCache(SurfaceType.IntArgbPre, - CompositeType.SrcNoEa, - tmpType); + 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 @@ -531,7 +525,7 @@ * * edges thus has to be h*2+2 in length */ - int edges[] = new int[(dy2-dy1)*2+2]; + final int[] edges = new int[h * 2 + 2]; // It is important that edges[0]=edges[1]=0 when we call // Transform in case it must return early and we would // not want to render anything on an error condition. @@ -539,35 +533,30 @@ AlphaComposite.Src, null, itx, interpType, sx1, sy1, sx2, sy2, - 0, 0, dx2-dx1, dy2-dy1, + 0, 0, w, h, edges, dx1, dy1); /* - * Now copy the results, scanline by scanline, into the dest. + * Now create clipped region, scanline by scanline. * The edges array helps us minimize the work. */ + Region region = Region.EMPTY_REGION; int index = 2; for (int y = edges[0]; y < edges[1]; y++) { int relx1 = edges[index++]; int relx2 = edges[index++]; - if (relx1 >= relx2) { - continue; - } - if (maskblit != null) { - maskblit.MaskBlit(tmpData, dstData, - sg.composite, clip, - relx1, y, - dx1+relx1, dy1+y, - relx2 - relx1, 1, - null, 0, 0); - } else { - blit.Blit(tmpData, dstData, - sg.composite, clip, - relx1, y, - dx1+relx1, dy1+y, - relx2 - relx1, 1); + if (relx1 < relx2) { + region = region.getUnionXYXY(relx1, y, relx2, y + 1); } } + region = region.getTranslatedRegion(dx1, dy1); + clip = clip.getIntersection(region); + + /* NOTE: We either have, or we can make, + * a Blit for any composite type, even Custom + */ + final Blit blit = Blit.getFromCache(tmpType, sg.imageComp, dstType); + blit.Blit(tmpData, dstData, sg.composite, clip, 0, 0, dx1, dy1, w, h); } // Render an image using only integer translation