提交 1cb74638 编写于 作者: S serb

8000629: [macosx] Blurry rendering with Java 7 on Retina display

Reviewed-by: anthony, prr, flar
上级 54541a1c
...@@ -219,6 +219,12 @@ public final class CGraphicsDevice extends GraphicsDevice { ...@@ -219,6 +219,12 @@ public final class CGraphicsDevice extends GraphicsDevice {
return nativeGetDisplayModes(displayID); 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 void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate);
private static native DisplayMode nativeGetDisplayMode(int displayID); private static native DisplayMode nativeGetDisplayMode(int displayID);
......
...@@ -441,6 +441,8 @@ public final class CGLGraphicsConfig extends CGraphicsConfig ...@@ -441,6 +441,8 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
@Override @Override
public int getMaxTextureWidth() { public int getMaxTextureWidth() {
//Temporary disable this logic and use some magic constrain.
/*
int width; int width;
synchronized (totalDisplayBounds) { synchronized (totalDisplayBounds) {
...@@ -451,10 +453,14 @@ public final class CGLGraphicsConfig extends CGraphicsConfig ...@@ -451,10 +453,14 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
} }
return Math.min(width, getMaxTextureSize()); return Math.min(width, getMaxTextureSize());
*/
return getMaxTextureSize() / (getDevice().getScaleFactor() * 2);
} }
@Override @Override
public int getMaxTextureHeight() { public int getMaxTextureHeight() {
//Temporary disable this logic and use some magic constrain.
/*
int height; int height;
synchronized (totalDisplayBounds) { synchronized (totalDisplayBounds) {
...@@ -465,5 +471,7 @@ public final class CGLGraphicsConfig extends CGraphicsConfig ...@@ -465,5 +471,7 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
} }
return Math.min(height, getMaxTextureSize()); return Math.min(height, getMaxTextureSize());
*/
return getMaxTextureSize() / (getDevice().getScaleFactor() * 2);
} }
} }
...@@ -40,11 +40,12 @@ import java.awt.Transparency; ...@@ -40,11 +40,12 @@ import java.awt.Transparency;
public class CGLLayer extends CFRetainedResource { public class CGLLayer extends CFRetainedResource {
private native long nativeCreateLayer(); 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 validate(long layerPtr, CGLSurfaceData cglsd);
private static native void blitTexture(long layerPtr); private static native void blitTexture(long layerPtr);
private LWWindowPeer peer; private LWWindowPeer peer;
private int scale = 1;
private SurfaceData surfaceData; // represents intermediate buffer (texture) private SurfaceData surfaceData; // represents intermediate buffer (texture)
...@@ -90,7 +91,7 @@ public class CGLLayer extends CFRetainedResource { ...@@ -90,7 +91,7 @@ public class CGLLayer extends CFRetainedResource {
// and blits the buffer to the layer surface (in drawInCGLContext callback) // and blits the buffer to the layer surface (in drawInCGLContext callback)
CGraphicsConfig gc = (CGraphicsConfig)peer.getGraphicsConfiguration(); CGraphicsConfig gc = (CGraphicsConfig)peer.getGraphicsConfiguration();
surfaceData = gc.createSurfaceData(this); surfaceData = gc.createSurfaceData(this);
setScale(gc.getDevice().getScaleFactor());
// the layer holds a reference to the buffer, which in // the layer holds a reference to the buffer, which in
// turn has a reference back to this layer // turn has a reference back to this layer
if (surfaceData instanceof CGLSurfaceData) { if (surfaceData instanceof CGLSurfaceData) {
...@@ -121,6 +122,13 @@ public class CGLLayer extends CFRetainedResource { ...@@ -121,6 +122,13 @@ public class CGLLayer extends CFRetainedResource {
super.dispose(); super.dispose();
} }
private void setScale(final int _scale) {
if (scale != _scale) {
scale = _scale;
nativeSetScale(getPointer(), scale);
}
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// NATIVE CALLBACKS // NATIVE CALLBACKS
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
......
...@@ -30,7 +30,6 @@ import java.awt.GraphicsConfiguration; ...@@ -30,7 +30,6 @@ import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice; import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment; import java.awt.GraphicsEnvironment;
import java.awt.Image; import java.awt.Image;
import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.image.ColorModel; import java.awt.image.ColorModel;
...@@ -41,6 +40,9 @@ import sun.lwawt.macosx.CPlatformView; ...@@ -41,6 +40,9 @@ import sun.lwawt.macosx.CPlatformView;
public abstract class CGLSurfaceData extends OGLSurfaceData { public abstract class CGLSurfaceData extends OGLSurfaceData {
protected final int scale;
protected final int width;
protected final int height;
protected CPlatformView pView; protected CPlatformView pView;
private CGLGraphicsConfig graphicsConfig; private CGLGraphicsConfig graphicsConfig;
...@@ -52,10 +54,19 @@ public abstract class CGLSurfaceData extends OGLSurfaceData { ...@@ -52,10 +54,19 @@ public abstract class CGLSurfaceData extends OGLSurfaceData {
protected native boolean initPbuffer(long pData, long pConfigInfo, protected native boolean initPbuffer(long pData, long pConfigInfo,
boolean isOpaque, int width, int height); 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, 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.pView = pView;
this.graphicsConfig = gc; this.graphicsConfig = gc;
...@@ -70,9 +81,9 @@ public abstract class CGLSurfaceData extends OGLSurfaceData { ...@@ -70,9 +81,9 @@ public abstract class CGLSurfaceData extends OGLSurfaceData {
} }
protected CGLSurfaceData(CGLLayer layer, CGLGraphicsConfig gc, 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; this.graphicsConfig = gc;
long pConfigInfo = gc.getNativeConfigInfo(); long pConfigInfo = gc.getNativeConfigInfo();
...@@ -157,13 +168,43 @@ public abstract class CGLSurfaceData extends OGLSurfaceData { ...@@ -157,13 +168,43 @@ public abstract class CGLSurfaceData extends OGLSurfaceData {
// Overridden in CGLWindowSurfaceData below // 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(); protected native void clearWindow();
public static class CGLWindowSurfaceData extends CGLSurfaceData { public static class CGLWindowSurfaceData extends CGLSurfaceData {
public CGLWindowSurfaceData(CPlatformView pView, public CGLWindowSurfaceData(CPlatformView pView,
CGLGraphicsConfig gc) { CGLGraphicsConfig gc) {
super(pView, gc, gc.getColorModel(), WINDOW); super(pView, gc, gc.getColorModel(), WINDOW, 0, 0);
} }
@Override @Override
...@@ -217,17 +258,12 @@ public abstract class CGLSurfaceData extends OGLSurfaceData { ...@@ -217,17 +258,12 @@ public abstract class CGLSurfaceData extends OGLSurfaceData {
public static class CGLLayerSurfaceData extends CGLSurfaceData { public static class CGLLayerSurfaceData extends CGLSurfaceData {
private CGLLayer layer; private CGLLayer layer;
private int width, height;
public CGLLayerSurfaceData(CGLLayer layer, CGLGraphicsConfig gc, public CGLLayerSurfaceData(CGLLayer layer, CGLGraphicsConfig gc,
int width, int height) { int width, int height) {
super(layer, gc, gc.getColorModel(), FBOBJECT); super(layer, gc, gc.getColorModel(), FBOBJECT, width, height);
this.width = width;
this.height = height;
this.layer = layer; this.layer = layer;
initSurface(this.width, this.height);
initSurface(width, height);
} }
@Override @Override
...@@ -296,18 +332,13 @@ public abstract class CGLSurfaceData extends OGLSurfaceData { ...@@ -296,18 +332,13 @@ public abstract class CGLSurfaceData extends OGLSurfaceData {
public static class CGLOffScreenSurfaceData extends CGLSurfaceData { public static class CGLOffScreenSurfaceData extends CGLSurfaceData {
private Image offscreenImage; private Image offscreenImage;
private int width, height;
public CGLOffScreenSurfaceData(CPlatformView pView, public CGLOffScreenSurfaceData(CPlatformView pView,
CGLGraphicsConfig gc, int width, int height, Image image, CGLGraphicsConfig gc, int width, int height, Image image,
ColorModel cm, int type) { ColorModel cm, int type) {
super(pView, gc, cm, type); super(pView, gc, cm, type, width, height);
this.width = width;
this.height = height;
offscreenImage = image; offscreenImage = image;
initSurface(this.width, this.height);
initSurface(width, height);
} }
@Override @Override
......
...@@ -463,35 +463,8 @@ public abstract class LWComponentPeer<T extends Component, D extends JComponent> ...@@ -463,35 +463,8 @@ public abstract class LWComponentPeer<T extends Component, D extends JComponent>
private void applyConstrain(final Graphics g) { private void applyConstrain(final Graphics g) {
final SunGraphics2D sg2d = (SunGraphics2D) g; final SunGraphics2D sg2d = (SunGraphics2D) g;
final Rectangle constr = localToWindow(getSize()); final Rectangle size = localToWindow(getSize());
// translate and set rectangle constrain. sg2d.constrain(size.x, size.y, size.width, size.height, getVisibleRegion());
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());
} }
public Region getVisibleRegion() { public Region getVisibleRegion() {
......
...@@ -580,17 +580,16 @@ public class LWWindowPeer ...@@ -580,17 +580,16 @@ public class LWWindowPeer
setBounds(x, y, w, h, SET_BOUNDS, false, false); setBounds(x, y, w, h, SET_BOUNDS, false, false);
// Second, update the graphics config and surface data // Second, update the graphics config and surface data
checkIfOnNewScreen(); final boolean isNewDevice = updateGraphicsDevice();
if (resized) { if (resized || isNewDevice) {
replaceSurfaceData(); replaceSurfaceData();
flushOnscreenGraphics();
} }
// Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events // Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events
if (moved || invalid) { if (moved || invalid) {
handleMove(x, y, true); handleMove(x, y, true);
} }
if (resized || invalid) { if (resized || invalid || isNewDevice) {
handleResize(w, h, true); handleResize(w, h, true);
repaintPeer(); repaintPeer();
} }
...@@ -610,7 +609,7 @@ public class LWWindowPeer ...@@ -610,7 +609,7 @@ public class LWWindowPeer
} }
if (!isTextured()) { if (!isTextured()) {
if (g instanceof SunGraphics2D) { if (g instanceof SunGraphics2D) {
SG2DConstraint((SunGraphics2D) g, getRegion()); ((SunGraphics2D) g).constrain(0, 0, w, h, getRegion());
} }
g.setColor(getBackground()); g.setColor(getBackground());
g.fillRect(0, 0, w, h); g.fillRect(0, 0, w, h);
...@@ -922,7 +921,7 @@ public class LWWindowPeer ...@@ -922,7 +921,7 @@ public class LWWindowPeer
} }
// If window's graphics config is changed from the app code, the // If window's graphics config is changed from the app code, the
// config correspond to the same device as before; when the window // 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 // In either case, there's nothing to do with screenOn here
graphicsConfig = gc; graphicsConfig = gc;
} }
...@@ -930,11 +929,14 @@ public class LWWindowPeer ...@@ -930,11 +929,14 @@ public class LWWindowPeer
return true; return true;
} }
private void checkIfOnNewScreen() { /**
* Returns true if the GraphicsDevice has been changed, false otherwise.
*/
public boolean updateGraphicsDevice() {
GraphicsDevice newGraphicsDevice = platformWindow.getGraphicsDevice(); GraphicsDevice newGraphicsDevice = platformWindow.getGraphicsDevice();
synchronized (getStateLock()) { synchronized (getStateLock()) {
if (graphicsDevice == newGraphicsDevice) { if (graphicsDevice == newGraphicsDevice) {
return; return false;
} }
graphicsDevice = newGraphicsDevice; graphicsDevice = newGraphicsDevice;
} }
...@@ -942,13 +944,14 @@ public class LWWindowPeer ...@@ -942,13 +944,14 @@ public class LWWindowPeer
// TODO: DisplayChangedListener stuff // TODO: DisplayChangedListener stuff
final GraphicsConfiguration newGC = newGraphicsDevice.getDefaultConfiguration(); final GraphicsConfiguration newGC = newGraphicsDevice.getDefaultConfiguration();
if (!setGraphicsConfig(newGC)) return; if (!setGraphicsConfig(newGC)) return false;
SunToolkit.executeOnEventHandlerThread(getTarget(), new Runnable() { SunToolkit.executeOnEventHandlerThread(getTarget(), new Runnable() {
public void run() { public void run() {
AWTAccessor.getComponentAccessor().setGraphicsConfiguration(getTarget(), newGC); AWTAccessor.getComponentAccessor().setGraphicsConfiguration(getTarget(), newGC);
} }
}); });
return true;
} }
/* /*
...@@ -983,6 +986,7 @@ public class LWWindowPeer ...@@ -983,6 +986,7 @@ public class LWWindowPeer
oldData.flush(); oldData.flush();
} }
} }
flushOnscreenGraphics();
} }
private void blitSurfaceData(final SurfaceData src, final SurfaceData dst) { private void blitSurfaceData(final SurfaceData src, final SurfaceData dst) {
...@@ -990,14 +994,15 @@ public class LWWindowPeer ...@@ -990,14 +994,15 @@ public class LWWindowPeer
if (src != dst && src != null && dst != null if (src != dst && src != null && dst != null
&& !(dst instanceof NullSurfaceData) && !(dst instanceof NullSurfaceData)
&& !(src instanceof NullSurfaceData) && !(src instanceof NullSurfaceData)
&& src.getSurfaceType().equals(dst.getSurfaceType())) { && src.getSurfaceType().equals(dst.getSurfaceType())
final Rectangle size = getSize(); && src.getDefaultScale() == dst.getDefaultScale()) {
final Rectangle size = src.getBounds();
final Blit blit = Blit.locate(src.getSurfaceType(), final Blit blit = Blit.locate(src.getSurfaceType(),
CompositeType.Src, CompositeType.Src,
dst.getSurfaceType()); dst.getSurfaceType());
if (blit != null) { if (blit != null) {
blit.Blit(src, dst, AlphaComposite.Src, blit.Blit(src, dst, AlphaComposite.Src, null, 0, 0, 0, 0,
getRegion(), 0, 0, 0, 0, size.width, size.height); size.width, size.height);
} }
} }
} }
......
...@@ -860,8 +860,8 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo ...@@ -860,8 +860,8 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
} }
} }
private void flushBuffers() { void flushBuffers() {
if (isVisible() && !nativeBounds.isEmpty()) { if (isVisible() && !nativeBounds.isEmpty() && !isFullScreenMode) {
try { try {
LWCToolkit.invokeAndWait(new Runnable() { LWCToolkit.invokeAndWait(new Runnable() {
@Override @Override
......
...@@ -315,3 +315,34 @@ Java_sun_awt_CGraphicsDevice_nativeGetDisplayModes ...@@ -315,3 +315,34 @@ Java_sun_awt_CGraphicsDevice_nativeGetDisplayModes
return jreturnArray; 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;
}
...@@ -61,6 +61,19 @@ AWT_ASSERT_APPKIT_THREAD; ...@@ -61,6 +61,19 @@ AWT_ASSERT_APPKIT_THREAD;
//Layer backed view //Layer backed view
//self.needsDisplayOnBoundsChange = YES; //self.needsDisplayOnBoundsChange = YES;
//self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; //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 textureID = 0; // texture will be created by rendering pipe
target = 0; target = 0;
...@@ -121,6 +134,10 @@ AWT_ASSERT_APPKIT_THREAD; ...@@ -121,6 +134,10 @@ AWT_ASSERT_APPKIT_THREAD;
// Set the current context to the one given to us. // Set the current context to the one given to us.
CGLSetCurrentContext(glContext); 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); glViewport(0, 0, textureWidth, textureHeight);
JNIEnv *env = [ThreadUtilities getJNIEnv]; JNIEnv *env = [ThreadUtilities getJNIEnv];
...@@ -168,7 +185,7 @@ JNF_COCOA_EXIT(env); ...@@ -168,7 +185,7 @@ JNF_COCOA_EXIT(env);
// Must be called under the RQ lock. // Must be called under the RQ lock.
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_java2d_opengl_CGLLayer_validate 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); CGLLayer *layer = OBJC(layerPtr);
...@@ -186,9 +203,21 @@ Java_sun_java2d_opengl_CGLLayer_validate ...@@ -186,9 +203,21 @@ Java_sun_java2d_opengl_CGLLayer_validate
// Must be called on the AppKit thread and under the RQ lock. // Must be called on the AppKit thread and under the RQ lock.
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_java2d_opengl_CGLLayer_blitTexture Java_sun_java2d_opengl_CGLLayer_blitTexture
(JNIEnv *env, jobject obj, jlong layerPtr) (JNIEnv *env, jclass cls, jlong layerPtr)
{ {
CGLLayer *layer = jlong_to_ptr(layerPtr); CGLLayer *layer = jlong_to_ptr(layerPtr);
[layer blitTexture]; [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);
}
...@@ -31,6 +31,7 @@ import java.awt.GraphicsConfiguration; ...@@ -31,6 +31,7 @@ import java.awt.GraphicsConfiguration;
import java.awt.Image; import java.awt.Image;
import java.awt.ImageCapabilities; import java.awt.ImageCapabilities;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.VolatileImage;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.Iterator; import java.util.Iterator;
import sun.java2d.SurfaceData; import sun.java2d.SurfaceData;
...@@ -287,4 +288,18 @@ public abstract class SurfaceManager { ...@@ -287,4 +288,18 @@ public abstract class SurfaceManager {
flush(true); 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();
}
} }
...@@ -65,6 +65,8 @@ import java.awt.image.ImageObserver; ...@@ -65,6 +65,8 @@ import java.awt.image.ImageObserver;
import java.awt.Transparency; import java.awt.Transparency;
import java.awt.font.GlyphVector; import java.awt.font.GlyphVector;
import java.awt.font.TextLayout; import java.awt.font.TextLayout;
import sun.awt.image.SurfaceManager;
import sun.font.FontDesignMetrics; import sun.font.FontDesignMetrics;
import sun.font.FontUtilities; import sun.font.FontUtilities;
import sun.java2d.pipe.PixelDrawPipe; import sun.java2d.pipe.PixelDrawPipe;
...@@ -82,14 +84,12 @@ import sun.java2d.loops.CompositeType; ...@@ -82,14 +84,12 @@ import sun.java2d.loops.CompositeType;
import sun.java2d.loops.SurfaceType; import sun.java2d.loops.SurfaceType;
import sun.java2d.loops.Blit; import sun.java2d.loops.Blit;
import sun.java2d.loops.MaskFill; import sun.java2d.loops.MaskFill;
import sun.font.FontManager;
import java.awt.font.FontRenderContext; import java.awt.font.FontRenderContext;
import sun.java2d.loops.XORComposite; import sun.java2d.loops.XORComposite;
import sun.awt.ConstrainableGraphics; import sun.awt.ConstrainableGraphics;
import sun.awt.SunHints; import sun.awt.SunHints;
import java.util.Map; import java.util.Map;
import java.util.Iterator; import java.util.Iterator;
import sun.java2d.DestSurfaceProvider;
import sun.misc.PerformanceLogger; import sun.misc.PerformanceLogger;
import javax.tools.annotation.GenerateNativeHeader; import javax.tools.annotation.GenerateNativeHeader;
...@@ -207,13 +207,15 @@ public final class SunGraphics2D ...@@ -207,13 +207,15 @@ public final class SunGraphics2D
public RenderingHints hints; public RenderingHints hints;
public Region constrainClip; // lightweight bounds public Region constrainClip; // lightweight bounds in pixels
public int constrainX; public int constrainX;
public int constrainY; public int constrainY;
public Region clipRegion; public Region clipRegion;
public Shape usrClip; 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 // cached state for text rendering
private boolean validFontInfo; private boolean validFontInfo;
...@@ -256,6 +258,12 @@ public final class SunGraphics2D ...@@ -256,6 +258,12 @@ public final class SunGraphics2D
validateColor(); validateColor();
devScale = sd.getDefaultScale();
if (devScale != 1) {
transform.setToScale(devScale, devScale);
invalidateTransform();
}
font = f; font = f;
if (font == null) { if (font == null) {
font = defaultFont; font = defaultFont;
...@@ -320,38 +328,40 @@ public final class SunGraphics2D ...@@ -320,38 +328,40 @@ public final class SunGraphics2D
/** /**
* Constrain rendering for lightweight objects. * Constrain rendering for lightweight objects.
*
* REMIND: This method will back off to the "workaround"
* of using translate and clipRect if the Graphics
* to be constrained has a complex transform. The
* drawback of the workaround is that the resulting
* clip and device origin cannot be "enforced".
*
* @exception IllegalStateException If the Graphics
* to be constrained has a complex transform.
*/ */
public void constrain(int x, int y, int w, int h) { public void constrain(int x, int y, int w, int h, Region region) {
if ((x|y) != 0) { if ((x | y) != 0) {
translate(x, y); translate(x, y);
} }
if (transformState >= TRANSFORM_TRANSLATESCALE) { if (transformState > TRANSFORM_TRANSLATESCALE) {
clipRect(0, 0, w, h); clipRect(0, 0, w, h);
return; return;
} }
x = constrainX = transX; // changes parameters according to the current scale and translate.
y = constrainY = transY; final double scaleX = transform.getScaleX();
w = Region.dimAdd(x, w); final double scaleY = transform.getScaleY();
h = Region.dimAdd(y, h); 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; Region c = constrainClip;
if (c == null) { if (c == null) {
c = Region.getInstanceXYXY(x, y, w, h); c = Region.getInstanceXYXY(x, y, w, h);
} else { } else {
c = c.getIntersectionXYXY(x, y, w, h); 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) { if (c == constrainClip) {
// Common case to ignore // Common case to ignore
return; return;
} }
}
constrainClip = c; constrainClip = c;
if (!devClip.isInsideQuickCheck(c)) { if (!devClip.isInsideQuickCheck(c)) {
devClip = devClip.getIntersection(c); devClip = devClip.getIntersection(c);
...@@ -359,6 +369,23 @@ public final class SunGraphics2D ...@@ -359,6 +369,23 @@ public final class SunGraphics2D
} }
} }
/**
* Constrain rendering for lightweight objects.
*
* REMIND: This method will back off to the "workaround"
* of using translate and clipRect if the Graphics
* to be constrained has a complex transform. The
* drawback of the workaround is that the resulting
* clip and device origin cannot be "enforced".
*
* @exception IllegalStateException If the Graphics
* to be constrained has a complex transform.
*/
@Override
public void constrain(int x, int y, int w, int h) {
constrain(x, y, w, h, null);
}
protected static ValidatePipe invalidpipe = new ValidatePipe(); protected static ValidatePipe invalidpipe = new ValidatePipe();
/* /*
...@@ -1540,11 +1567,13 @@ public final class SunGraphics2D ...@@ -1540,11 +1567,13 @@ public final class SunGraphics2D
* @see TransformChain * @see TransformChain
* @see AffineTransform * @see AffineTransform
*/ */
@Override
public void setTransform(AffineTransform Tx) { public void setTransform(AffineTransform Tx) {
if ((constrainX|constrainY) == 0) { if ((constrainX | constrainY) == 0 && devScale == 1) {
transform.setTransform(Tx); transform.setTransform(Tx);
} else { } else {
transform.setToTranslation(constrainX, constrainY); transform.setTransform(devScale, 0, 0, devScale, constrainX,
constrainY);
transform.concatenate(Tx); transform.concatenate(Tx);
} }
invalidateTransform(); invalidateTransform();
...@@ -1602,12 +1631,15 @@ public final class SunGraphics2D ...@@ -1602,12 +1631,15 @@ public final class SunGraphics2D
* @see #transform * @see #transform
* @see #setTransform * @see #setTransform
*/ */
@Override
public AffineTransform getTransform() { public AffineTransform getTransform() {
if ((constrainX|constrainY) == 0) { if ((constrainX | constrainY) == 0 && devScale == 1) {
return new AffineTransform(transform); return new AffineTransform(transform);
} }
AffineTransform tx = final double invScale = 1.0 / devScale;
AffineTransform.getTranslateInstance(-constrainX, -constrainY); AffineTransform tx = new AffineTransform(invScale, 0, 0, invScale,
-constrainX * invScale,
-constrainY * invScale);
tx.concatenate(transform); tx.concatenate(transform);
return tx; return tx;
} }
...@@ -2991,6 +3023,37 @@ public final class SunGraphics2D ...@@ -2991,6 +3023,37 @@ public final class SunGraphics2D
} }
// end of text rendering methods // 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 * Draws an image scaled to x,y,w,h in nonblocking mode with a
* callback object. * callback object.
...@@ -3004,8 +3067,9 @@ public final class SunGraphics2D ...@@ -3004,8 +3067,9 @@ public final class SunGraphics2D
* Not part of the advertised API but a useful utility method * Not part of the advertised API but a useful utility method
* to call internally. This is for the case where we are * to call internally. This is for the case where we are
* drawing to/from given coordinates using a given width/height, * drawing to/from given coordinates using a given width/height,
* but we guarantee that the weidth/height of the src and dest * but we guarantee that the surfaceData's width/height of the src and dest
* areas are equal (no scale needed). * 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, public boolean copyImage(Image img, int dx, int dy, int sx, int sy,
int width, int height, Color bgcolor, int width, int height, Color bgcolor,
...@@ -3043,7 +3107,15 @@ public final class SunGraphics2D ...@@ -3043,7 +3107,15 @@ public final class SunGraphics2D
if ((width == 0) || (height == 0)) { if ((width == 0) || (height == 0)) {
return true; 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); return copyImage(img, x, y, 0, 0, width, height, bg, observer);
} }
...@@ -3084,6 +3156,13 @@ public final class SunGraphics2D ...@@ -3084,6 +3156,13 @@ public final class SunGraphics2D
return true; 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 { try {
return imagepipe.copyImage(this, img, x, y, bg, observer); return imagepipe.copyImage(this, img, x, y, bg, observer);
} catch (InvalidPipeException e) { } catch (InvalidPipeException e) {
...@@ -3132,6 +3211,11 @@ public final class SunGraphics2D ...@@ -3132,6 +3211,11 @@ public final class SunGraphics2D
return true; return true;
} }
if (isHiDPIImage(img)) {
return drawHiDPIImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
bgcolor, observer);
}
if (((sx2 - sx1) == (dx2 - dx1)) && if (((sx2 - sx1) == (dx2 - dx1)) &&
((sy2 - sy1) == (dy2 - dy1))) ((sy2 - sy1) == (dy2 - dy1)))
{ {
...@@ -3210,6 +3294,18 @@ public final class SunGraphics2D ...@@ -3210,6 +3294,18 @@ public final class SunGraphics2D
return drawImage(img, 0, 0, null, observer); 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 { try {
return imagepipe.transformImage(this, img, xform, observer); return imagepipe.transformImage(this, img, xform, observer);
} catch (InvalidPipeException e) { } catch (InvalidPipeException e) {
......
...@@ -1057,4 +1057,14 @@ public abstract class SurfaceData ...@@ -1057,4 +1057,14 @@ public abstract class SurfaceData
* responsible for returning the appropriate object. * responsible for returning the appropriate object.
*/ */
public abstract Object getDestination(); 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;
}
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -99,8 +99,7 @@ public abstract class BufferedContext { ...@@ -99,8 +99,7 @@ public abstract class BufferedContext {
private int validatedRGB; private int validatedRGB;
private int validatedFlags; private int validatedFlags;
private boolean xformInUse; private boolean xformInUse;
private int transX; private AffineTransform transform;
private int transY;
protected BufferedContext(RenderQueue rq) { protected BufferedContext(RenderQueue rq) {
this.rq = rq; this.rq = rq;
...@@ -277,14 +276,11 @@ public abstract class BufferedContext { ...@@ -277,14 +276,11 @@ public abstract class BufferedContext {
resetTransform(); resetTransform();
xformInUse = false; xformInUse = false;
txChanged = true; txChanged = true;
} else if (sg2d != null) { } else if (sg2d != null && !sg2d.transform.equals(transform)) {
if (transX != sg2d.transX || transY != sg2d.transY) {
txChanged = true; txChanged = true;
} }
} if (sg2d != null && txChanged) {
if (sg2d != null) { transform = new AffineTransform(sg2d.transform);
transX = sg2d.transX;
transY = sg2d.transY;
} }
} else { } else {
setTransform(xform); setTransform(xform);
......
...@@ -27,9 +27,7 @@ package sun.java2d.pipe; ...@@ -27,9 +27,7 @@ package sun.java2d.pipe;
import java.awt.AlphaComposite; import java.awt.AlphaComposite;
import java.awt.Color; import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image; import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Transparency; import java.awt.Transparency;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.NoninvertibleTransformException;
...@@ -38,15 +36,13 @@ import java.awt.image.BufferedImage; ...@@ -38,15 +36,13 @@ import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp; import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel; import java.awt.image.ColorModel;
import java.awt.image.DataBuffer; import java.awt.image.DataBuffer;
import java.awt.image.DirectColorModel;
import java.awt.image.ImageObserver; import java.awt.image.ImageObserver;
import java.awt.image.IndexColorModel; import java.awt.image.IndexColorModel;
import java.awt.image.Raster; import java.awt.image.Raster;
import java.awt.image.VolatileImage; import java.awt.image.VolatileImage;
import java.awt.image.WritableRaster;
import java.awt.image.ImagingOpException;
import sun.awt.SunHints; import sun.awt.SunHints;
import sun.awt.image.ImageRepresentation; import sun.awt.image.ImageRepresentation;
import sun.awt.image.SurfaceManager;
import sun.awt.image.ToolkitImage; import sun.awt.image.ToolkitImage;
import sun.java2d.InvalidPipeException; import sun.java2d.InvalidPipeException;
import sun.java2d.SunGraphics2D; import sun.java2d.SunGraphics2D;
...@@ -323,15 +319,17 @@ public class DrawImage implements DrawImagePipe ...@@ -323,15 +319,17 @@ public class DrawImage implements DrawImagePipe
BufferedImage makeBufferedImage(Image img, Color bgColor, int type, BufferedImage makeBufferedImage(Image img, Color bgColor, int type,
int sx1, int sy1, int sx2, int sy2) int sx1, int sy1, int sx2, int sy2)
{ {
BufferedImage bimg = new BufferedImage(sx2-sx1, sy2-sy1, type); final int width = sx2 - sx1;
Graphics2D g2d = bimg.createGraphics(); final int height = sy2 - sy1;
final BufferedImage bimg = new BufferedImage(width, height, type);
final SunGraphics2D g2d = (SunGraphics2D) bimg.createGraphics();
g2d.setComposite(AlphaComposite.Src); g2d.setComposite(AlphaComposite.Src);
if (bgColor != null) { if (bgColor != null) {
g2d.setColor(bgColor); g2d.setColor(bgColor);
g2d.fillRect(0, 0, sx2-sx1, sy2-sy1); g2d.fillRect(0, 0, width, height);
g2d.setComposite(AlphaComposite.SrcOver); g2d.setComposite(AlphaComposite.SrcOver);
} }
g2d.drawImage(img, -sx1, -sy1, null); g2d.copyImage(img, 0, 0, sx1, sy1, width, height, null, null);
g2d.dispose(); g2d.dispose();
return bimg; return bimg;
} }
...@@ -737,8 +735,9 @@ public class DrawImage implements DrawImagePipe ...@@ -737,8 +735,9 @@ public class DrawImage implements DrawImagePipe
atfm.scale(m00, m11); atfm.scale(m00, m11);
atfm.translate(srcX-sx1, srcY-sy1); atfm.translate(srcX-sx1, srcY-sy1);
int imgW = img.getWidth(null); final int scale = SurfaceManager.getImageScale(img);
int imgH = img.getHeight(null); final int imgW = img.getWidth(null) * scale;
final int imgH = img.getHeight(null) * scale;
srcW += srcX; srcW += srcX;
srcH += srcY; srcH += srcY;
// Make sure we are not out of bounds // Make sure we are not out of bounds
......
...@@ -131,6 +131,28 @@ public class Region { ...@@ -131,6 +131,28 @@ public class Region {
return newv; 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) { protected Region(int lox, int loy, int hix, int hiy) {
this.lox = lox; this.lox = lox;
this.loy = loy; this.loy = loy;
...@@ -348,6 +370,79 @@ public class Region { ...@@ -348,6 +370,79 @@ public class Region {
calcBBox(); calcBBox();
} }
/**
* 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 * Returns a Region object that represents the same list of
* rectangles as the current Region object, translated by * rectangles as the current Region object, translated by
......
/*
* 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;
}
}
}
/*
* 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;
}
}
}
/*
* 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");
}
}
}
/*
* 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;
}
}
}
/*
* 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;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册