8000629: [macosx] Blurry rendering with Java 7 on Retina display
Reviewed-by: anthony, prr, flar
--- a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java Fri Apr 12 15:28:49 2013 +0400
@@ -219,6 +219,12 @@
return nativeGetDisplayModes(displayID);
}
+ public int getScaleFactor() {
+ return (int) nativeGetScaleFactor(displayID);
+ }
+
+ private static native double nativeGetScaleFactor(int displayID);
+
private static native void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate);
private static native DisplayMode nativeGetDisplayMode(int displayID);
--- a/jdk/src/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java Fri Apr 12 15:28:49 2013 +0400
@@ -441,29 +441,37 @@
@Override
public int getMaxTextureWidth() {
- int width;
+ //Temporary disable this logic and use some magic constrain.
+ /*
+ int width;
- synchronized (totalDisplayBounds) {
- if (totalDisplayBounds.width == 0) {
- updateTotalDisplayBounds();
- }
- width = totalDisplayBounds.width;
- }
+ synchronized (totalDisplayBounds) {
+ if (totalDisplayBounds.width == 0) {
+ updateTotalDisplayBounds();
+ }
+ width = totalDisplayBounds.width;
+ }
- return Math.min(width, getMaxTextureSize());
+ return Math.min(width, getMaxTextureSize());
+ */
+ return getMaxTextureSize() / (getDevice().getScaleFactor() * 2);
}
@Override
public int getMaxTextureHeight() {
- int height;
+ //Temporary disable this logic and use some magic constrain.
+ /*
+ int height;
- synchronized (totalDisplayBounds) {
- if (totalDisplayBounds.height == 0) {
- updateTotalDisplayBounds();
- }
- height = totalDisplayBounds.height;
- }
+ synchronized (totalDisplayBounds) {
+ if (totalDisplayBounds.height == 0) {
+ updateTotalDisplayBounds();
+ }
+ height = totalDisplayBounds.height;
+ }
- return Math.min(height, getMaxTextureSize());
+ return Math.min(height, getMaxTextureSize());
+ */
+ return getMaxTextureSize() / (getDevice().getScaleFactor() * 2);
}
}
--- a/jdk/src/macosx/classes/sun/java2d/opengl/CGLLayer.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/macosx/classes/sun/java2d/opengl/CGLLayer.java Fri Apr 12 15:28:49 2013 +0400
@@ -40,11 +40,12 @@
public class CGLLayer extends CFRetainedResource {
private native long nativeCreateLayer();
-
+ private static native void nativeSetScale(long layerPtr, double scale);
private static native void validate(long layerPtr, CGLSurfaceData cglsd);
private static native void blitTexture(long layerPtr);
private LWWindowPeer peer;
+ private int scale = 1;
private SurfaceData surfaceData; // represents intermediate buffer (texture)
@@ -90,7 +91,7 @@
// and blits the buffer to the layer surface (in drawInCGLContext callback)
CGraphicsConfig gc = (CGraphicsConfig)peer.getGraphicsConfiguration();
surfaceData = gc.createSurfaceData(this);
-
+ setScale(gc.getDevice().getScaleFactor());
// the layer holds a reference to the buffer, which in
// turn has a reference back to this layer
if (surfaceData instanceof CGLSurfaceData) {
@@ -121,6 +122,13 @@
super.dispose();
}
+ private void setScale(final int _scale) {
+ if (scale != _scale) {
+ scale = _scale;
+ nativeSetScale(getPointer(), scale);
+ }
+ }
+
// ----------------------------------------------------------------------
// NATIVE CALLBACKS
// ----------------------------------------------------------------------
--- a/jdk/src/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java Fri Apr 12 15:28:49 2013 +0400
@@ -30,7 +30,6 @@
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
-import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
@@ -41,6 +40,9 @@
public abstract class CGLSurfaceData extends OGLSurfaceData {
+ protected final int scale;
+ protected final int width;
+ protected final int height;
protected CPlatformView pView;
private CGLGraphicsConfig graphicsConfig;
@@ -52,10 +54,19 @@
protected native boolean initPbuffer(long pData, long pConfigInfo,
boolean isOpaque, int width, int height);
+ protected CGLSurfaceData(CGLGraphicsConfig gc, ColorModel cm, int type,
+ int width, int height) {
+ super(gc, cm, type);
+ // TEXTURE shouldn't be scaled, it is used for managed BufferedImages.
+ scale = type == TEXTURE ? 1 : gc.getDevice().getScaleFactor();
+ this.width = width * scale;
+ this.height = height * scale;
+ }
+
protected CGLSurfaceData(CPlatformView pView, CGLGraphicsConfig gc,
- ColorModel cm, int type)
+ ColorModel cm, int type,int width, int height)
{
- super(gc, cm, type);
+ this(gc, cm, type, width, height);
this.pView = pView;
this.graphicsConfig = gc;
@@ -70,9 +81,9 @@
}
protected CGLSurfaceData(CGLLayer layer, CGLGraphicsConfig gc,
- ColorModel cm, int type)
+ ColorModel cm, int type,int width, int height)
{
- super(gc, cm, type);
+ this(gc, cm, type, width, height);
this.graphicsConfig = gc;
long pConfigInfo = gc.getNativeConfigInfo();
@@ -157,13 +168,43 @@
// Overridden in CGLWindowSurfaceData below
}
+ @Override
+ public int getDefaultScale() {
+ return scale;
+ }
+
+ @Override
+ public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h,
+ int dx, int dy) {
+ final int state = sg2d.transformState;
+ if (state > SunGraphics2D.TRANSFORM_TRANSLATESCALE
+ || sg2d.compositeState >= SunGraphics2D.COMP_XOR) {
+ return false;
+ }
+ if (state <= SunGraphics2D.TRANSFORM_ANY_TRANSLATE) {
+ x += sg2d.transX;
+ y += sg2d.transY;
+ } else if (state == SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
+ final double[] coords = {x, y, x + w, y + h, x + dx, y + dy};
+ sg2d.transform.transform(coords, 0, coords, 0, 3);
+ x = (int) Math.ceil(coords[0] - 0.5);
+ y = (int) Math.ceil(coords[1] - 0.5);
+ w = ((int) Math.ceil(coords[2] - 0.5)) - x;
+ h = ((int) Math.ceil(coords[3] - 0.5)) - y;
+ dx = ((int) Math.ceil(coords[4] - 0.5)) - x;
+ dy = ((int) Math.ceil(coords[5] - 0.5)) - y;
+ }
+ oglRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy);
+ return true;
+ }
+
protected native void clearWindow();
public static class CGLWindowSurfaceData extends CGLSurfaceData {
public CGLWindowSurfaceData(CPlatformView pView,
CGLGraphicsConfig gc) {
- super(pView, gc, gc.getColorModel(), WINDOW);
+ super(pView, gc, gc.getColorModel(), WINDOW, 0, 0);
}
@Override
@@ -217,17 +258,12 @@
public static class CGLLayerSurfaceData extends CGLSurfaceData {
private CGLLayer layer;
- private int width, height;
public CGLLayerSurfaceData(CGLLayer layer, CGLGraphicsConfig gc,
int width, int height) {
- super(layer, gc, gc.getColorModel(), FBOBJECT);
-
- this.width = width;
- this.height = height;
+ super(layer, gc, gc.getColorModel(), FBOBJECT, width, height);
this.layer = layer;
-
- initSurface(width, height);
+ initSurface(this.width, this.height);
}
@Override
@@ -296,18 +332,13 @@
public static class CGLOffScreenSurfaceData extends CGLSurfaceData {
private Image offscreenImage;
- private int width, height;
public CGLOffScreenSurfaceData(CPlatformView pView,
CGLGraphicsConfig gc, int width, int height, Image image,
ColorModel cm, int type) {
- super(pView, gc, cm, type);
-
- this.width = width;
- this.height = height;
+ super(pView, gc, cm, type, width, height);
offscreenImage = image;
-
- initSurface(width, height);
+ initSurface(this.width, this.height);
}
@Override
--- a/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java Fri Apr 12 15:28:49 2013 +0400
@@ -463,35 +463,8 @@
private void applyConstrain(final Graphics g) {
final SunGraphics2D sg2d = (SunGraphics2D) g;
- final Rectangle constr = localToWindow(getSize());
- // translate and set rectangle constrain.
- sg2d.constrain(constr.x, constr.y, constr.width, constr.height);
- // set region constrain.
- //sg2d.constrain(getVisibleRegion());
- SG2DConstraint(sg2d, getVisibleRegion());
- }
-
- //TODO Move this method to SG2D?
- void SG2DConstraint(final SunGraphics2D sg2d, Region r) {
- sg2d.constrainX = sg2d.transX;
- sg2d.constrainY = sg2d.transY;
-
- Region c = sg2d.constrainClip;
- if ((sg2d.constrainX | sg2d.constrainY) != 0) {
- r = r.getTranslatedRegion(sg2d.constrainX, sg2d.constrainY);
- }
- if (c == null) {
- c = r;
- } else {
- c = c.getIntersection(r);
- if (c == sg2d.constrainClip) {
- // Common case to ignore
- return;
- }
- }
- sg2d.constrainClip = c;
- //validateCompClip() forced call.
- sg2d.setDevClip(r.getLoX(), r.getLoY(), r.getWidth(), r.getHeight());
+ final Rectangle size = localToWindow(getSize());
+ sg2d.constrain(size.x, size.y, size.width, size.height, getVisibleRegion());
}
public Region getVisibleRegion() {
--- a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java Fri Apr 12 15:28:49 2013 +0400
@@ -580,17 +580,16 @@
setBounds(x, y, w, h, SET_BOUNDS, false, false);
// Second, update the graphics config and surface data
- checkIfOnNewScreen();
- if (resized) {
+ final boolean isNewDevice = updateGraphicsDevice();
+ if (resized || isNewDevice) {
replaceSurfaceData();
- flushOnscreenGraphics();
}
// Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events
if (moved || invalid) {
handleMove(x, y, true);
}
- if (resized || invalid) {
+ if (resized || invalid || isNewDevice) {
handleResize(w, h, true);
repaintPeer();
}
@@ -610,7 +609,7 @@
}
if (!isTextured()) {
if (g instanceof SunGraphics2D) {
- SG2DConstraint((SunGraphics2D) g, getRegion());
+ ((SunGraphics2D) g).constrain(0, 0, w, h, getRegion());
}
g.setColor(getBackground());
g.fillRect(0, 0, w, h);
@@ -922,7 +921,7 @@
}
// If window's graphics config is changed from the app code, the
// config correspond to the same device as before; when the window
- // is moved by user, graphicsDevice is updated in checkIfOnNewScreen().
+ // is moved by user, graphicsDevice is updated in notifyReshape().
// In either case, there's nothing to do with screenOn here
graphicsConfig = gc;
}
@@ -930,11 +929,14 @@
return true;
}
- private void checkIfOnNewScreen() {
+ /**
+ * Returns true if the GraphicsDevice has been changed, false otherwise.
+ */
+ public boolean updateGraphicsDevice() {
GraphicsDevice newGraphicsDevice = platformWindow.getGraphicsDevice();
synchronized (getStateLock()) {
if (graphicsDevice == newGraphicsDevice) {
- return;
+ return false;
}
graphicsDevice = newGraphicsDevice;
}
@@ -942,13 +944,14 @@
// TODO: DisplayChangedListener stuff
final GraphicsConfiguration newGC = newGraphicsDevice.getDefaultConfiguration();
- if (!setGraphicsConfig(newGC)) return;
+ if (!setGraphicsConfig(newGC)) return false;
SunToolkit.executeOnEventHandlerThread(getTarget(), new Runnable() {
public void run() {
AWTAccessor.getComponentAccessor().setGraphicsConfiguration(getTarget(), newGC);
}
});
+ return true;
}
/*
@@ -983,6 +986,7 @@
oldData.flush();
}
}
+ flushOnscreenGraphics();
}
private void blitSurfaceData(final SurfaceData src, final SurfaceData dst) {
@@ -990,14 +994,15 @@
if (src != dst && src != null && dst != null
&& !(dst instanceof NullSurfaceData)
&& !(src instanceof NullSurfaceData)
- && src.getSurfaceType().equals(dst.getSurfaceType())) {
- final Rectangle size = getSize();
+ && src.getSurfaceType().equals(dst.getSurfaceType())
+ && src.getDefaultScale() == dst.getDefaultScale()) {
+ final Rectangle size = src.getBounds();
final Blit blit = Blit.locate(src.getSurfaceType(),
CompositeType.Src,
dst.getSurfaceType());
if (blit != null) {
- blit.Blit(src, dst, AlphaComposite.Src,
- getRegion(), 0, 0, 0, 0, size.width, size.height);
+ blit.Blit(src, dst, AlphaComposite.Src, null, 0, 0, 0, 0,
+ size.width, size.height);
}
}
}
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Fri Apr 12 15:28:49 2013 +0400
@@ -860,8 +860,8 @@
}
}
- private void flushBuffers() {
- if (isVisible() && !nativeBounds.isEmpty()) {
+ void flushBuffers() {
+ if (isVisible() && !nativeBounds.isEmpty() && !isFullScreenMode) {
try {
LWCToolkit.invokeAndWait(new Runnable() {
@Override
--- a/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m Fri Apr 12 15:28:49 2013 +0400
@@ -315,3 +315,34 @@
return jreturnArray;
}
+
+/*
+ * Class: sun_awt_CGraphicsDevice
+ * Method: nativeGetScaleFactor
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_sun_awt_CGraphicsDevice_nativeGetScaleFactor
+(JNIEnv *env, jclass class, jint displayID)
+{
+ __block jdouble ret = 1.0f;
+
+JNF_COCOA_ENTER(env);
+
+ [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
+ NSArray *screens = [NSScreen screens];
+ for (NSScreen *screen in screens) {
+ NSDictionary *screenInfo = [screen deviceDescription];
+ NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
+ if ([screenID pointerValue] == displayID){
+ if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
+ ret = [screen backingScaleFactor];
+ }
+ break;
+ }
+ }
+ }];
+
+JNF_COCOA_EXIT(env);
+ return ret;
+}
--- a/jdk/src/macosx/native/sun/java2d/opengl/CGLLayer.m Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/macosx/native/sun/java2d/opengl/CGLLayer.m Fri Apr 12 15:28:49 2013 +0400
@@ -61,6 +61,19 @@
//Layer backed view
//self.needsDisplayOnBoundsChange = YES;
//self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
+
+ //Disable CALayer's default animation
+ NSMutableDictionary * actions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
+ [NSNull null], @"bounds",
+ [NSNull null], @"contents",
+ [NSNull null], @"contentsScale",
+ [NSNull null], @"onOrderIn",
+ [NSNull null], @"onOrderOut",
+ [NSNull null], @"sublayers",
+ nil];
+ self.actions = actions;
+ [actions release];
+
textureID = 0; // texture will be created by rendering pipe
target = 0;
@@ -121,8 +134,12 @@
// Set the current context to the one given to us.
CGLSetCurrentContext(glContext);
+ // Should clear the whole CALayer, because it can be larger than our texture.
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
glViewport(0, 0, textureWidth, textureHeight);
-
+
JNIEnv *env = [ThreadUtilities getJNIEnv];
static JNF_CLASS_CACHE(jc_JavaLayer, "sun/java2d/opengl/CGLLayer");
static JNF_MEMBER_CACHE(jm_drawInCGLContext, jc_JavaLayer, "drawInCGLContext", "()V");
@@ -168,7 +185,7 @@
// Must be called under the RQ lock.
JNIEXPORT void JNICALL
Java_sun_java2d_opengl_CGLLayer_validate
-(JNIEnv *env, jobject obj, jlong layerPtr, jobject surfaceData)
+(JNIEnv *env, jclass cls, jlong layerPtr, jobject surfaceData)
{
CGLLayer *layer = OBJC(layerPtr);
@@ -186,9 +203,21 @@
// Must be called on the AppKit thread and under the RQ lock.
JNIEXPORT void JNICALL
Java_sun_java2d_opengl_CGLLayer_blitTexture
-(JNIEnv *env, jobject obj, jlong layerPtr)
+(JNIEnv *env, jclass cls, jlong layerPtr)
{
CGLLayer *layer = jlong_to_ptr(layerPtr);
[layer blitTexture];
}
+
+JNIEXPORT void JNICALL
+Java_sun_java2d_opengl_CGLLayer_nativeSetScale
+(JNIEnv *env, jclass cls, jlong layerPtr, jdouble scale)
+{
+ JNF_COCOA_ENTER(env);
+ CGLLayer *layer = jlong_to_ptr(layerPtr);
+ [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
+ layer.contentsScale = scale;
+ }];
+ JNF_COCOA_EXIT(env);
+}
--- a/jdk/src/share/classes/sun/awt/image/SurfaceManager.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/share/classes/sun/awt/image/SurfaceManager.java Fri Apr 12 15:28:49 2013 +0400
@@ -31,6 +31,7 @@
import java.awt.Image;
import java.awt.ImageCapabilities;
import java.awt.image.BufferedImage;
+import java.awt.image.VolatileImage;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Iterator;
import sun.java2d.SurfaceData;
@@ -287,4 +288,18 @@
flush(true);
}
}
+
+ /**
+ * Returns a scale factor of the image. This is utility method, which
+ * fetches information from the SurfaceData of the image.
+ *
+ * @see SurfaceData#getDefaultScale
+ */
+ public static int getImageScale(final Image img) {
+ if (!(img instanceof VolatileImage)) {
+ return 1;
+ }
+ final SurfaceManager sm = getManager(img);
+ return sm.getPrimarySurfaceData().getDefaultScale();
+ }
}
--- a/jdk/src/share/classes/sun/java2d/SunGraphics2D.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/share/classes/sun/java2d/SunGraphics2D.java Fri Apr 12 15:28:49 2013 +0400
@@ -65,6 +65,8 @@
import java.awt.Transparency;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
+
+import sun.awt.image.SurfaceManager;
import sun.font.FontDesignMetrics;
import sun.font.FontUtilities;
import sun.java2d.pipe.PixelDrawPipe;
@@ -82,14 +84,12 @@
import sun.java2d.loops.SurfaceType;
import sun.java2d.loops.Blit;
import sun.java2d.loops.MaskFill;
-import sun.font.FontManager;
import java.awt.font.FontRenderContext;
import sun.java2d.loops.XORComposite;
import sun.awt.ConstrainableGraphics;
import sun.awt.SunHints;
import java.util.Map;
import java.util.Iterator;
-import sun.java2d.DestSurfaceProvider;
import sun.misc.PerformanceLogger;
import javax.tools.annotation.GenerateNativeHeader;
@@ -207,13 +207,15 @@
public RenderingHints hints;
- public Region constrainClip; // lightweight bounds
+ public Region constrainClip; // lightweight bounds in pixels
public int constrainX;
public int constrainY;
public Region clipRegion;
public Shape usrClip;
- protected Region devClip; // Actual physical drawable
+ protected Region devClip; // Actual physical drawable in pixels
+
+ private final int devScale; // Actual physical scale factor
// cached state for text rendering
private boolean validFontInfo;
@@ -256,6 +258,12 @@
validateColor();
+ devScale = sd.getDefaultScale();
+ if (devScale != 1) {
+ transform.setToScale(devScale, devScale);
+ invalidateTransform();
+ }
+
font = f;
if (font == null) {
font = defaultFont;
@@ -320,6 +328,49 @@
/**
* Constrain rendering for lightweight objects.
+ */
+ public void constrain(int x, int y, int w, int h, Region region) {
+ if ((x | y) != 0) {
+ translate(x, y);
+ }
+ if (transformState > TRANSFORM_TRANSLATESCALE) {
+ clipRect(0, 0, w, h);
+ return;
+ }
+ // changes parameters according to the current scale and translate.
+ final double scaleX = transform.getScaleX();
+ final double scaleY = transform.getScaleY();
+ x = constrainX = (int) transform.getTranslateX();
+ y = constrainY = (int) transform.getTranslateY();
+ w = Region.dimAdd(x, Region.clipScale(w, scaleX));
+ h = Region.dimAdd(y, Region.clipScale(h, scaleY));
+
+ Region c = constrainClip;
+ if (c == null) {
+ c = Region.getInstanceXYXY(x, y, w, h);
+ } else {
+ c = c.getIntersectionXYXY(x, y, w, h);
+ }
+ if (region != null) {
+ region = region.getScaledRegion(scaleX, scaleY);
+ region = region.getTranslatedRegion(x, y);
+ c = c.getIntersection(region);
+ }
+
+ if (c == constrainClip) {
+ // Common case to ignore
+ return;
+ }
+
+ constrainClip = c;
+ if (!devClip.isInsideQuickCheck(c)) {
+ devClip = devClip.getIntersection(c);
+ validateCompClip();
+ }
+ }
+
+ /**
+ * Constrain rendering for lightweight objects.
*
* REMIND: This method will back off to the "workaround"
* of using translate and clipRect if the Graphics
@@ -330,33 +381,9 @@
* @exception IllegalStateException If the Graphics
* to be constrained has a complex transform.
*/
+ @Override
public void constrain(int x, int y, int w, int h) {
- if ((x|y) != 0) {
- translate(x, y);
- }
- if (transformState >= TRANSFORM_TRANSLATESCALE) {
- clipRect(0, 0, w, h);
- return;
- }
- x = constrainX = transX;
- y = constrainY = transY;
- w = Region.dimAdd(x, w);
- h = Region.dimAdd(y, h);
- Region c = constrainClip;
- if (c == null) {
- c = Region.getInstanceXYXY(x, y, w, h);
- } else {
- c = c.getIntersectionXYXY(x, y, w, h);
- if (c == constrainClip) {
- // Common case to ignore
- return;
- }
- }
- constrainClip = c;
- if (!devClip.isInsideQuickCheck(c)) {
- devClip = devClip.getIntersection(c);
- validateCompClip();
- }
+ constrain(x, y, w, h, null);
}
protected static ValidatePipe invalidpipe = new ValidatePipe();
@@ -1540,11 +1567,13 @@
* @see TransformChain
* @see AffineTransform
*/
+ @Override
public void setTransform(AffineTransform Tx) {
- if ((constrainX|constrainY) == 0) {
+ if ((constrainX | constrainY) == 0 && devScale == 1) {
transform.setTransform(Tx);
} else {
- transform.setToTranslation(constrainX, constrainY);
+ transform.setTransform(devScale, 0, 0, devScale, constrainX,
+ constrainY);
transform.concatenate(Tx);
}
invalidateTransform();
@@ -1602,12 +1631,15 @@
* @see #transform
* @see #setTransform
*/
+ @Override
public AffineTransform getTransform() {
- if ((constrainX|constrainY) == 0) {
+ if ((constrainX | constrainY) == 0 && devScale == 1) {
return new AffineTransform(transform);
}
- AffineTransform tx =
- AffineTransform.getTranslateInstance(-constrainX, -constrainY);
+ final double invScale = 1.0 / devScale;
+ AffineTransform tx = new AffineTransform(invScale, 0, 0, invScale,
+ -constrainX * invScale,
+ -constrainY * invScale);
tx.concatenate(transform);
return tx;
}
@@ -2991,6 +3023,37 @@
}
// end of text rendering methods
+ private static boolean isHiDPIImage(final Image img) {
+ return SurfaceManager.getImageScale(img) != 1;
+ }
+
+ private boolean drawHiDPIImage(Image img, int dx1, int dy1, int dx2,
+ int dy2, int sx1, int sy1, int sx2, int sy2,
+ Color bgcolor, ImageObserver observer) {
+ final int scale = SurfaceManager.getImageScale(img);
+ sx1 = Region.clipScale(sx1, scale);
+ sx2 = Region.clipScale(sx2, scale);
+ sy1 = Region.clipScale(sy1, scale);
+ sy2 = Region.clipScale(sy2, scale);
+ try {
+ return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1, sy1,
+ sx2, sy2, bgcolor, observer);
+ } catch (InvalidPipeException e) {
+ try {
+ revalidateAll();
+ return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1,
+ sy1, sx2, sy2, bgcolor, observer);
+ } catch (InvalidPipeException e2) {
+ // Still catching the exception; we are not yet ready to
+ // validate the surfaceData correctly. Fail for now and
+ // try again next time around.
+ return false;
+ }
+ } finally {
+ surfaceData.markDirty();
+ }
+ }
+
/**
* Draws an image scaled to x,y,w,h in nonblocking mode with a
* callback object.
@@ -3004,8 +3067,9 @@
* Not part of the advertised API but a useful utility method
* to call internally. This is for the case where we are
* drawing to/from given coordinates using a given width/height,
- * but we guarantee that the weidth/height of the src and dest
- * areas are equal (no scale needed).
+ * but we guarantee that the surfaceData's width/height of the src and dest
+ * areas are equal (no scale needed). Note that this method intentionally
+ * ignore scale factor of the source image, and copy it as is.
*/
public boolean copyImage(Image img, int dx, int dy, int sx, int sy,
int width, int height, Color bgcolor,
@@ -3043,7 +3107,15 @@
if ((width == 0) || (height == 0)) {
return true;
}
- if (width == img.getWidth(null) && height == img.getHeight(null)) {
+
+ final int imgW = img.getWidth(null);
+ final int imgH = img.getHeight(null);
+ if (isHiDPIImage(img)) {
+ return drawHiDPIImage(img, x, y, x + width, y + height, 0, 0, imgW,
+ imgH, bg, observer);
+ }
+
+ if (width == imgW && height == imgH) {
return copyImage(img, x, y, 0, 0, width, height, bg, observer);
}
@@ -3084,6 +3156,13 @@
return true;
}
+ if (isHiDPIImage(img)) {
+ final int imgW = img.getWidth(null);
+ final int imgH = img.getHeight(null);
+ return drawHiDPIImage(img, x, y, x + imgW, y + imgH, 0, 0, imgW,
+ imgH, bg, observer);
+ }
+
try {
return imagepipe.copyImage(this, img, x, y, bg, observer);
} catch (InvalidPipeException e) {
@@ -3132,6 +3211,11 @@
return true;
}
+ if (isHiDPIImage(img)) {
+ return drawHiDPIImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
+ bgcolor, observer);
+ }
+
if (((sx2 - sx1) == (dx2 - dx1)) &&
((sy2 - sy1) == (dy2 - dy1)))
{
@@ -3210,6 +3294,18 @@
return drawImage(img, 0, 0, null, observer);
}
+ if (isHiDPIImage(img)) {
+ final int w = img.getWidth(null);
+ final int h = img.getHeight(null);
+ final AffineTransform tx = new AffineTransform(transform);
+ transform(xform);
+ boolean result = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h, null,
+ observer);
+ transform.setTransform(tx);
+ invalidateTransform();
+ return result;
+ }
+
try {
return imagepipe.transformImage(this, img, xform, observer);
} catch (InvalidPipeException e) {
--- a/jdk/src/share/classes/sun/java2d/SurfaceData.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/share/classes/sun/java2d/SurfaceData.java Fri Apr 12 15:28:49 2013 +0400
@@ -1057,4 +1057,14 @@
* responsible for returning the appropriate object.
*/
public abstract Object getDestination();
+
+ /**
+ * Returns default scale factor of the destination surface. Scale factor
+ * describes the mapping between virtual and physical coordinates of the
+ * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be
+ * doubled for physical pixels.
+ */
+ public int getDefaultScale() {
+ return 1;
+ }
}
--- a/jdk/src/share/classes/sun/java2d/pipe/BufferedContext.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/share/classes/sun/java2d/pipe/BufferedContext.java Fri Apr 12 15:28:49 2013 +0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -99,8 +99,7 @@
private int validatedRGB;
private int validatedFlags;
private boolean xformInUse;
- private int transX;
- private int transY;
+ private AffineTransform transform;
protected BufferedContext(RenderQueue rq) {
this.rq = rq;
@@ -277,14 +276,11 @@
resetTransform();
xformInUse = false;
txChanged = true;
- } else if (sg2d != null) {
- if (transX != sg2d.transX || transY != sg2d.transY) {
- txChanged = true;
- }
+ } else if (sg2d != null && !sg2d.transform.equals(transform)) {
+ txChanged = true;
}
- if (sg2d != null) {
- transX = sg2d.transX;
- transY = sg2d.transY;
+ if (sg2d != null && txChanged) {
+ transform = new AffineTransform(sg2d.transform);
}
} else {
setTransform(xform);
--- a/jdk/src/share/classes/sun/java2d/pipe/DrawImage.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/share/classes/sun/java2d/pipe/DrawImage.java Fri Apr 12 15:28:49 2013 +0400
@@ -27,9 +27,7 @@
import java.awt.AlphaComposite;
import java.awt.Color;
-import java.awt.Graphics2D;
import java.awt.Image;
-import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
@@ -38,15 +36,13 @@
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
-import java.awt.image.DirectColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.VolatileImage;
-import java.awt.image.WritableRaster;
-import java.awt.image.ImagingOpException;
import sun.awt.SunHints;
import sun.awt.image.ImageRepresentation;
+import sun.awt.image.SurfaceManager;
import sun.awt.image.ToolkitImage;
import sun.java2d.InvalidPipeException;
import sun.java2d.SunGraphics2D;
@@ -323,15 +319,17 @@
BufferedImage makeBufferedImage(Image img, Color bgColor, int type,
int sx1, int sy1, int sx2, int sy2)
{
- BufferedImage bimg = new BufferedImage(sx2-sx1, sy2-sy1, type);
- Graphics2D g2d = bimg.createGraphics();
+ final int width = sx2 - sx1;
+ final int height = sy2 - sy1;
+ final BufferedImage bimg = new BufferedImage(width, height, type);
+ final SunGraphics2D g2d = (SunGraphics2D) bimg.createGraphics();
g2d.setComposite(AlphaComposite.Src);
if (bgColor != null) {
g2d.setColor(bgColor);
- g2d.fillRect(0, 0, sx2-sx1, sy2-sy1);
+ g2d.fillRect(0, 0, width, height);
g2d.setComposite(AlphaComposite.SrcOver);
}
- g2d.drawImage(img, -sx1, -sy1, null);
+ g2d.copyImage(img, 0, 0, sx1, sy1, width, height, null, null);
g2d.dispose();
return bimg;
}
@@ -737,8 +735,9 @@
atfm.scale(m00, m11);
atfm.translate(srcX-sx1, srcY-sy1);
- int imgW = img.getWidth(null);
- int imgH = img.getHeight(null);
+ final int scale = SurfaceManager.getImageScale(img);
+ final int imgW = img.getWidth(null) * scale;
+ final int imgH = img.getHeight(null) * scale;
srcW += srcX;
srcH += srcY;
// Make sure we are not out of bounds
--- a/jdk/src/share/classes/sun/java2d/pipe/Region.java Fri Apr 12 14:33:38 2013 +0400
+++ b/jdk/src/share/classes/sun/java2d/pipe/Region.java Fri Apr 12 15:28:49 2013 +0400
@@ -131,6 +131,28 @@
return newv;
}
+ /**
+ * Multiply the scale factor {@code sv} and the value {@code v} with
+ * appropriate clipping to the bounds of Integer resolution. If the answer
+ * would be greater than {@code Integer.MAX_VALUE} then {@code
+ * Integer.MAX_VALUE} is returned. If the answer would be less than {@code
+ * Integer.MIN_VALUE} then {@code Integer.MIN_VALUE} is returned. Otherwise
+ * the multiplication is returned.
+ */
+ public static int clipScale(final int v, final double sv) {
+ if (sv == 1.0) {
+ return v;
+ }
+ final double newv = v * sv;
+ if (newv < Integer.MIN_VALUE) {
+ return Integer.MIN_VALUE;
+ }
+ if (newv > Integer.MAX_VALUE) {
+ return Integer.MAX_VALUE;
+ }
+ return (int) Math.round(newv);
+ }
+
protected Region(int lox, int loy, int hix, int hiy) {
this.lox = lox;
this.loy = loy;
@@ -349,6 +371,79 @@
}
/**
+ * Returns a Region object that represents the same list of rectangles as
+ * the current Region object, scaled by the specified sx, sy factors.
+ */
+ public Region getScaledRegion(final double sx, final double sy) {
+ if (sx == 0 || sy == 0 || this == EMPTY_REGION) {
+ return EMPTY_REGION;
+ }
+ if ((sx == 1.0 && sy == 1.0) || (this == WHOLE_REGION)) {
+ return this;
+ }
+
+ int tlox = clipScale(lox, sx);
+ int tloy = clipScale(loy, sy);
+ int thix = clipScale(hix, sx);
+ int thiy = clipScale(hiy, sy);
+ Region ret = new Region(tlox, tloy, thix, thiy);
+ int bands[] = this.bands;
+ if (bands != null) {
+ int end = endIndex;
+ int newbands[] = new int[end];
+ int i = 0; // index for source bands
+ int j = 0; // index for translated newbands
+ int ncol;
+ while (i < end) {
+ int y1, y2;
+ newbands[j++] = y1 = clipScale(bands[i++], sy);
+ newbands[j++] = y2 = clipScale(bands[i++], sy);
+ newbands[j++] = ncol = bands[i++];
+ int savej = j;
+ if (y1 < y2) {
+ while (--ncol >= 0) {
+ int x1 = clipScale(bands[i++], sx);
+ int x2 = clipScale(bands[i++], sx);
+ if (x1 < x2) {
+ newbands[j++] = x1;
+ newbands[j++] = x2;
+ }
+ }
+ } else {
+ i += ncol * 2;
+ }
+ // Did we get any non-empty bands in this row?
+ if (j > savej) {
+ newbands[savej-1] = (j - savej) / 2;
+ } else {
+ j = savej - 3;
+ }
+ }
+ if (j <= 5) {
+ if (j < 5) {
+ // No rows or bands were generated...
+ ret.lox = ret.loy = ret.hix = ret.hiy = 0;
+ } else {
+ // Only generated one single rect in the end...
+ ret.loy = newbands[0];
+ ret.hiy = newbands[1];
+ ret.lox = newbands[3];
+ ret.hix = newbands[4];
+ }
+ // ret.endIndex and ret.bands were never initialized...
+ // ret.endIndex = 0;
+ // ret.newbands = null;
+ } else {
+ // Generated multiple bands and/or multiple rows...
+ ret.endIndex = j;
+ ret.bands = newbands;
+ }
+ }
+ return ret;
+ }
+
+
+ /**
* Returns a Region object that represents the same list of
* rectangles as the current Region object, translated by
* the specified dx, dy translation factors.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Graphics2D/FillTexturePaint/FillTexturePaint.java Fri Apr 12 15:28:49 2013 +0400
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Rectangle;
+import java.awt.TexturePaint;
+import java.awt.image.BufferedImage;
+import java.awt.image.VolatileImage;
+
+/**
+ * @test
+ * @bug 8000629
+ * @summary TexturePaint areas shouldn't separates.
+ * @author Sergey Bylokhov
+ */
+public class FillTexturePaint {
+
+ private static TexturePaint shape;
+ private static final int size = 400;
+
+ static {
+ BufferedImage bi = new BufferedImage(50, 50,
+ BufferedImage.TYPE_INT_RGB);
+ Graphics2D gi = bi.createGraphics();
+ gi.setBackground(Color.GREEN);
+ gi.clearRect(0, 0, 50, 50);
+ shape = new TexturePaint(bi, new Rectangle(0, 0, 50, 50));
+ }
+
+ public static void main(final String[] args) {
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsConfiguration gc =
+ ge.getDefaultScreenDevice().getDefaultConfiguration();
+ VolatileImage vi = gc.createCompatibleVolatileImage(size, size);
+ while (true) {
+ vi.validate(gc);
+ Graphics2D g2d = vi.createGraphics();
+ g2d.setComposite(AlphaComposite.Src);
+ g2d.setPaint(shape);
+ g2d.fill(new Rectangle(0, 0, size, size));
+ g2d.dispose();
+
+ if (vi.validate(gc) != VolatileImage.IMAGE_OK) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ continue;
+ }
+
+ BufferedImage bi = vi.getSnapshot();
+
+ if (vi.contentsLost()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ continue;
+ }
+
+ for (int x = 0; x < size; ++x) {
+ for (int y = 0; y < size; ++y) {
+ if (bi.getRGB(x, y) != Color.GREEN.getRGB()) {
+ throw new RuntimeException("Test failed.");
+ }
+ }
+ }
+ break;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Graphics2D/FlipDrawImage/FlipDrawImage.java Fri Apr 12 15:28:49 2013 +0400
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.image.BufferedImage;
+import java.awt.image.VolatileImage;
+
+/**
+ * @test
+ * @bug 8000629
+ * @author Sergey Bylokhov
+ */
+public final class FlipDrawImage {
+
+ private static final int width = 400;
+ private static final int height = 400;
+
+ public static void main(final String[] args) {
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsConfiguration gc =
+ ge.getDefaultScreenDevice().getDefaultConfiguration();
+ VolatileImage vi = gc.createCompatibleVolatileImage(width, height);
+ final BufferedImage bi = new BufferedImage(width, height,
+ BufferedImage.TYPE_INT_ARGB);
+ while (true) {
+ vi.validate(gc);
+ Graphics2D g2d = vi.createGraphics();
+ g2d.setColor(Color.red);
+ g2d.fillRect(0, 0, width, height);
+ g2d.setColor(Color.green);
+ g2d.fillRect(0, 0, width / 2, height / 2);
+ g2d.dispose();
+
+ if (vi.validate(gc) != VolatileImage.IMAGE_OK) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ continue;
+ }
+
+ Graphics2D g = bi.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.setColor(Color.BLUE);
+ g.fillRect(0, 0, width, height);
+ // destination width and height are flipped and scale is used.
+ g.drawImage(vi, width / 2, height / 2, -width / 2, -height / 2,
+ null, null);
+ g.dispose();
+
+ if (vi.contentsLost()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ continue;
+ }
+
+ for (int x = 0; x < width; ++x) {
+ for (int y = 0; y < height; ++y) {
+ if (x < width / 2 && y < height / 2) {
+ if (x >= width / 4 && y >= height / 4) {
+ if (bi.getRGB(x, y) != Color.green.getRGB()) {
+ throw new RuntimeException("Test failed.");
+ }
+ } else if (bi.getRGB(x, y) != Color.red.getRGB()) {
+ throw new RuntimeException("Test failed.");
+ }
+ } else {
+ if (bi.getRGB(x, y) != Color.BLUE.getRGB()) {
+ throw new RuntimeException("Test failed.");
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Graphics2D/TransformSetGet/TransformSetGet.java Fri Apr 12 15:28:49 2013 +0400
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.geom.AffineTransform;
+import java.awt.image.VolatileImage;
+
+import sun.java2d.SunGraphics2D;
+
+/**
+ * @test
+ * @bug 8000629
+ * @summary Set/get transform should work on constrained graphics.
+ * @author Sergey Bylokhov
+ */
+public class TransformSetGet {
+
+ public static void main(final String[] args) {
+ final GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ final GraphicsConfiguration gc =
+ ge.getDefaultScreenDevice().getDefaultConfiguration();
+ final VolatileImage vi = gc.createCompatibleVolatileImage(200, 200);
+ final SunGraphics2D sg2d = (SunGraphics2D) vi.createGraphics();
+
+ sg2d.constrain(0, 61, 100, 100);
+ final AffineTransform expected = sg2d.cloneTransform();
+ sg2d.setTransform(sg2d.getTransform());
+ final AffineTransform actual = sg2d.cloneTransform();
+ sg2d.dispose();
+ vi.flush();
+ if (!expected.equals(actual)) {
+ System.out.println("Expected = " + expected);
+ System.out.println("Actual = " + actual);
+ throw new RuntimeException("Wrong transform");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/image/DrawImage/IncorrectBounds.java Fri Apr 12 15:28:49 2013 +0400
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.image.BufferedImage;
+import java.awt.image.VolatileImage;
+
+/**
+ * @test
+ * @bug 8000629
+ * @summary Temporary backbuffer in the DrawImage should not fill background
+ * outside of source image bounds.
+ * @author Sergey Bylokhov
+ */
+public final class IncorrectBounds {
+
+ private static final int width = 400;
+ private static final int height = 400;
+
+ public static void main(final String[] args) {
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsConfiguration gc =
+ ge.getDefaultScreenDevice().getDefaultConfiguration();
+ VolatileImage vi = gc.createCompatibleVolatileImage(width / 4,
+ height / 4);
+ final BufferedImage bi = new BufferedImage(width, height,
+ BufferedImage.TYPE_INT_ARGB);
+ while (true) {
+ vi.validate(gc);
+ Graphics2D g2d = vi.createGraphics();
+ g2d.setColor(Color.green);
+ g2d.fillRect(0, 0, width / 4, height / 4);
+ g2d.dispose();
+
+ if (vi.validate(gc) != VolatileImage.IMAGE_OK) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ continue;
+ }
+
+ Graphics2D g = bi.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.setColor(Color.red);
+ g.fillRect(0, 0, width, height);
+ // Use sx and sy outside of VI bounds.
+ g.drawImage(vi, 0, 0, width / 2, height / 2, 0, 0, width * 2,
+ height * 2, null);
+ g.dispose();
+
+ if (vi.contentsLost()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ continue;
+ }
+
+ for (int x = 0; x < width; ++x) {
+ for (int y = 0; y < height; ++y) {
+ if (x < width / 16 && y < height / 16) {
+ if (bi.getRGB(x, y) != Color.green.getRGB()) {
+ throw new RuntimeException("Test failed.");
+ }
+ } else {
+ if (bi.getRGB(x, y) != Color.red.getRGB()) {
+ throw new RuntimeException("Test failed.");
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/image/DrawImage/IncorrectOffset.java Fri Apr 12 15:28:49 2013 +0400
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.image.BufferedImage;
+import java.awt.image.VolatileImage;
+
+/**
+ * @test
+ * @bug 8000629
+ * @summary Temporary backbuffer in the DrawImage should have correct offset.
+ * @author Sergey Bylokhov
+ */
+public final class IncorrectOffset {
+
+ private static final int width = 400;
+ private static final int height = 400;
+
+ public static void main(final String[] args) {
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsConfiguration gc =
+ ge.getDefaultScreenDevice().getDefaultConfiguration();
+ VolatileImage vi = gc.createCompatibleVolatileImage(width, height);
+ BufferedImage bi = new BufferedImage(width / 4, height / 4,
+ BufferedImage.TYPE_INT_ARGB);
+ while (true) {
+ vi.validate(gc);
+ Graphics2D g2d = vi.createGraphics();
+ g2d.setColor(Color.black);
+ g2d.fillRect(0, 0, width, height);
+ g2d.setColor(Color.green);
+ g2d.fillRect(width / 4, height / 4, width / 2, height / 2);
+ g2d.dispose();
+
+ if (vi.validate(gc) != VolatileImage.IMAGE_OK) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ continue;
+ }
+
+ Graphics2D g = bi.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ // Scale part of VI to BI. Only green area should be copied.
+ g.drawImage(vi, 0, 0, width / 4, height / 4, width / 4, height / 4,
+ width / 4 + width / 2, height / 4 + height / 2, null);
+ g.dispose();
+
+ if (vi.contentsLost()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ continue;
+ }
+
+ for (int x = 0; x < width / 4; ++x) {
+ for (int y = 0; y < height / 4; ++y) {
+ if (bi.getRGB(x, y) != Color.green.getRGB()) {
+ throw new RuntimeException("Test failed.");
+ }
+ }
+ }
+ break;
+ }
+ }
+}