diff options
author | Sven Gothel <[email protected]> | 2014-06-08 08:11:57 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-06-08 08:11:57 +0200 |
commit | 2571ed0b5ef14155d204540d38b564a7d4cd47b6 (patch) | |
tree | 8aaf1171af1b95f1cb1ebe706771a4aff3752c2f /src/nativewindow | |
parent | ff7bf3122fd2007bbe70cfadca9f0f978ee96456 (diff) |
Bug 741 HiDPI: Add ScalableSurface interface to get/set pixelScale w/ full OSX impl.
Add ScalableSurface interface
- To set pixelScale before and after realization
- To get pixelScale
- Implemented on:
- NEWT Window
- Generic impl. in WindowImpl
- OSX WindowDriver impl.
- Also propagetes pixelScale to parent JAWTWindow if offscreen (NewtCanvasAWT)
- AWT WindowDriver impl.
- JAWTWindow / OSXCalayer
- AWT GLCanvas
- AWT GLJPanel
- NEWTCanvasAWT:
- Propagates NEWT Window's pixelScale to underlying JAWTWindow
- WrappedSurface for pixelScale propagation
using offscreen drawables, i.e. GLJPanel
- Generic helper in SurfaceScaleUtils (nativewindow package)
- Fully implemented on OSX
- Capable to switch pixelScale before realization,
i.e. native-creation, as well as on-the-fly.
- Impl. uses int[2] for pixelScale to support
non-uniform scale.
Test cases:
- com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT
- com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT
- com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelAWT
- com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT
- Press 'x' to toggle HiDPI
- Commandline '-pixelScale <value>'
- Added basic auto unit test (setting pre-realization)
Diffstat (limited to 'src/nativewindow')
7 files changed, 452 insertions, 51 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java index 690d77901..efe9409ac 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java @@ -61,6 +61,7 @@ import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.OffscreenLayerOption; import javax.media.nativewindow.OffscreenLayerSurface; +import javax.media.nativewindow.ScalableSurface; import javax.media.nativewindow.SurfaceUpdatedListener; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; @@ -70,13 +71,14 @@ import javax.media.nativewindow.util.PointImmutable; import javax.media.nativewindow.util.Rectangle; import javax.media.nativewindow.util.RectangleImmutable; +import jogamp.nativewindow.SurfaceScaleUtils; import jogamp.nativewindow.SurfaceUpdatedHelper; import jogamp.nativewindow.awt.AWTMisc; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWT_Rectangle; -public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, OffscreenLayerOption { +public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, OffscreenLayerOption, ScalableSurface { protected static final boolean DEBUG = JAWTUtil.DEBUG; // user properties @@ -98,7 +100,10 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, protected Rectangle bounds; protected Insets insets; private volatile long offscreenSurfaceLayer; - private volatile int pixelScale; + + private volatile int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + protected final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; + private long drawable_old; /** @@ -122,7 +127,6 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, invalidate(); this.isApplet = false; this.offscreenSurfaceLayer = 0; - this.pixelScale = 1; } private static String id(Object obj) { return ( null!=obj ? toHexString(obj.hashCode()) : "nil" ); } private String jawtStr() { return "JAWTWindow["+id(JAWTWindow.this)+"]"; } @@ -260,22 +264,37 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, drawable_old = 0; bounds = new Rectangle(); insets = new Insets(); - pixelScale = 1; + hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; + hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; } protected abstract void invalidateNative(); /** + * {@inheritDoc} + * <p> + * Per default impl. only works for not yet {@link #isRealized() realized} instances, + * current exception OSX. + * </p> + */ + @Override + public void setSurfaceScale(final int[] pixelScale) { + SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG ? getClass().getSimpleName() : null); + } + + @Override + public final int[] getSurfaceScale(final int[] result) { + // 0 != drawable -> locked at least once ! + System.arraycopy(0 != drawable ? hasPixelScale : reqPixelScale, 0, result, 0, 2); + return result; + } + + /** * Updates bounds and pixelScale + * @return true if bounds or pixelScale has changed, otherwise false */ protected final boolean updateLockedData(JAWT_Rectangle jawtBounds) { final Rectangle jb = new Rectangle(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight()); - final int newPixelScale; - { - final int s = JAWTUtil.getPixelScale(config.getAWTGraphicsConfiguration()); - newPixelScale = 0 < s ? s : 1; - } final boolean changedBounds = !bounds.equals(jb); - final boolean changedPixelScale = newPixelScale != pixelScale; if( changedBounds ) { if( DEBUG ) { @@ -288,20 +307,31 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom); } } - if( changedPixelScale ) { - if( DEBUG ) { - System.err.println("JAWTWindow.updatePixelScale: "+pixelScale+" -> "+newPixelScale); - } - pixelScale = newPixelScale; + + return updatePixelScale() || changedBounds; + } + + /** + * Update pixelScale + * @return true if pixelScale has changed, otherwise false + */ + protected final boolean updatePixelScale() { + final int[] pixelScaleInt; + { + final int ps = JAWTUtil.getPixelScale(config.getAWTGraphicsConfiguration()); + pixelScaleInt = new int[] { ps, ps }; } - return changedBounds || changedPixelScale; + return SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, pixelScaleInt, DEBUG ? getClass().getSimpleName() : null); } /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */ public final RectangleImmutable getBounds() { return bounds; } - /** @return the safe pixelScale value, i.e. never negative or zero. Updated with lock. */ - public final int getPixelScale() { return pixelScale; } + /** @return the safe pixelScale value for x-direction, i.e. never negative or zero. Updated with lock. */ + protected final int getPixelScaleX() { return hasPixelScale[0]; } + + /** @return the safe pixelScale value for y-direction, i.e. never negative or zero. Updated with lock. */ + protected final int getPixelScaleY() { return hasPixelScale[1]; } @Override public final InsetsImmutable getInsets() { return insets; } @@ -625,12 +655,26 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, @Override public final int getSurfaceWidth() { - return getWidth() * getPixelScale(); + return getWidth() * getPixelScaleX(); } @Override public final int getSurfaceHeight() { - return getHeight() * getPixelScale(); + return getHeight() * getPixelScaleY(); + } + + @Override + public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { + pixelUnitsAndResult[0] /= getPixelScaleX(); + pixelUnitsAndResult[1] /= getPixelScaleY(); + return pixelUnitsAndResult; + } + + @Override + public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { + windowUnitsAndResult[0] *= getPixelScaleX(); + windowUnitsAndResult[1] *= getPixelScaleY(); + return windowUnitsAndResult; } @Override @@ -651,22 +695,6 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } @Override - public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { - final int scale = getPixelScale(); - pixelUnitsAndResult[0] /= scale; - pixelUnitsAndResult[1] /= scale; - return pixelUnitsAndResult; - } - - @Override - public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { - final int scale = getPixelScale(); - windowUnitsAndResult[0] *= scale; - windowUnitsAndResult[1] *= scale; - return windowUnitsAndResult; - } - - @Override public void destroy() { surfaceLock.lock(); try { @@ -810,7 +838,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, append(", CA_LAYER: ").append(JAWTUtil.isJAWTUsingOffscreenLayer(jawt)). append(", isLayeredSurface ").append(isOffscreenLayerSurfaceEnabled()). append(", bounds ").append(bounds).append(", insets ").append(insets). - append(", pixelScale ").append(getPixelScale()); + append(", pixelScale ").append(getPixelScaleX()).append("x").append(getPixelScaleY()); } else { sb.append("JAWT n/a, bounds ").append(bounds).append(", insets ").append(insets); } @@ -830,7 +858,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, ", bounds "+bounds+", insets "+insets ); sb.append(", window ["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+ - "], pixels[x"+getPixelScale()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+ + "], pixels[s "+getPixelScaleX()+"x"+getPixelScaleY()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+ ", visible "+component.isVisible()); sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+ ",\n\tconfig "+config+ diff --git a/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java b/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java new file mode 100644 index 000000000..024f22bc9 --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java @@ -0,0 +1,80 @@ +/** + * Copyright 2014 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package javax.media.nativewindow; + +/** + * Adding mutable surface pixel scale property to implementing class, usually to a {@link NativeSurface} implementation, + * see {@link #setSurfaceScale(int[])}. + */ +public interface ScalableSurface { + /** Setting surface-pixel-scale of {@value}, results in same pixel- and window-units. */ + public static final int IDENTITY_PIXELSCALE = 1; + /** Setting surface-pixel-scale of {@value}, results in maximum platform dependent pixel-scale, i.e. pixel-units >> window-units where available. */ + public static final int AUTOMAX_PIXELSCALE = 0; + + /** + * Request a pixel scale in x- and y-direction for the associated {@link NativeSurface}. + * <p> + * Default pixel scale request for both directions is {@link #AUTOMAX_PIXELSCALE}. + * </p> + * <p> + * In case platform only supports uniform pixel scale, i.e. one scale for both directions, + * either {@link #AUTOMAX_PIXELSCALE} or the maximum requested pixel scale component is used. + * </p> + * <p> + * The <i>requested</i> pixel scale will be validated against platform limits before native scale-setup, + * i.e. clipped to {@link #IDENTITY_PIXELSCALE} if not supported or the platform maximum. + * </p> + * <p> + * The actual <i>realized</i> pixel scale values of the {@link NativeSurface} + * can be queried via {@link #getSurfaceScale(int[])} or + * computed via <code>surface.{@link NativeSurface#convertToPixelUnits(int[]) convertToPixelUnits}(new int[] { 1, 1 })</code> + * </p> + * + * @param pixelScale <i>requested</i> surface pixel scale int[2] values for x- and y-direction. + */ + public void setSurfaceScale(final int[] pixelScale); + + /** + * Returns the pixel scale of the associated {@link NativeSurface}. + * <p> + * In case the {@link NativeSurface} is not yet realized, method returns the + * requested pixel scale as validated via {@link #setSurfaceScale(int[])} + * if called earlier or the implementation default, usually {@link #AUTOMAX_PIXELSCALE}. + * </p> + * <p> + * In case the {@link NativeSurface} is already realized, method returns the + * actual used pixel scale. + * </p> + * @param result int[2] storage for the result + * @return the passed storage for chaining + */ + public int[] getSurfaceScale(final int[] result); +} + diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java new file mode 100644 index 000000000..22e67ecff --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java @@ -0,0 +1,175 @@ +/** + * Copyright 2014 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.nativewindow; + +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ScalableSurface; + +/** + * Basic {@link ScalableSurface} utility to validate and compute pixel-scale values. + */ +public class SurfaceScaleUtils { + + private static final int[] PlatformMaxPixelScale; + private static final boolean PlatformUniformPixelScale; + private static final boolean PlatformPixelScaleSupported; + + static { + if( NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(true) ) { + PlatformMaxPixelScale = new int[] { jogamp.nativewindow.macosx.OSXUtil.MAX_PIXELSCALE, jogamp.nativewindow.macosx.OSXUtil.MAX_PIXELSCALE }; + PlatformUniformPixelScale = true; + PlatformPixelScaleSupported = true; + } else { + PlatformMaxPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + PlatformUniformPixelScale = false; + PlatformPixelScaleSupported = false; + } + } + + /** + * Compute a new valid pixelScale to be used by {@link NativeSurface} implementations, + * based on the given request and surface's pixelScale + * + * @param result int[2] storage for result, maybe same as <code>prePixelScale</code> for in-place + * @param prePixelScale previous pixelScale + * @param reqPixelScale requested pixelScale, validated via {@link #validateReqPixelScale(int[], int, String)}. + * @param surfPixelScaleRaw raw surface pixelScale + * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix + * @return true if pixelScale has changed, otherwise false + */ + public static boolean computePixelScale(int[] result, final int[] prePixelScale, final int[] reqPixelScale, final int[] surfPixelScaleRaw, final String DEBUG_PREFIX) { + final int surfPixelScaleSafeX = 0 < surfPixelScaleRaw[0] ? surfPixelScaleRaw[0] : ScalableSurface.IDENTITY_PIXELSCALE; + final int surfPixelScaleSafeY = 0 < surfPixelScaleRaw[1] ? surfPixelScaleRaw[1] : ScalableSurface.IDENTITY_PIXELSCALE; + final boolean useHiDPI = ScalableSurface.IDENTITY_PIXELSCALE != reqPixelScale[0] || ScalableSurface.IDENTITY_PIXELSCALE != reqPixelScale[1]; + final int prePixelScaleX = prePixelScale[0]; + final int prePixelScaleY = prePixelScale[1]; + + if( useHiDPI ) { + result[0] = surfPixelScaleSafeX; + result[1] = surfPixelScaleSafeY; + } else { + result[0] = ScalableSurface.IDENTITY_PIXELSCALE; + result[1] = ScalableSurface.IDENTITY_PIXELSCALE; + } + + if( result[0] != prePixelScaleX || result[1] != prePixelScaleY ) { + if( null != DEBUG_PREFIX ) { + System.err.println(DEBUG_PREFIX+".computePixelScale: useHiDPI "+useHiDPI+", ["+prePixelScaleX+"x"+prePixelScaleY+" (pre), "+ + reqPixelScale[0]+"x"+reqPixelScale[1]+" (req)] -> "+ + surfPixelScaleRaw[0]+"x"+surfPixelScaleRaw[1]+" (raw) -> "+ + surfPixelScaleSafeX+"x"+surfPixelScaleSafeY+" (safe) -> "+ + result[0]+"x"+result[1]+" (use)"); + } + return true; + } else { + return false; + } + } + + /** + * Validate the given requested pixelScale value pair, i.e. clip it to the + * limits of {@link ScalableSurface#AUTOMAX_PIXELSCALE} and {@link #getPlatformMaxPixelScale(int[])} + * <p> + * To be used by {@link ScalableSurface#setSurfaceScale(int[])} implementations. + * </p> + * + * @param result int[2] storage for result + * @param reqPixelScale requested pixelScale + * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix + */ + public static void validateReqPixelScale(final int[] result, final int[] reqPixelScale, final String DEBUG_PREFIX) { + final int minPS = Math.min(reqPixelScale[0], reqPixelScale[1]); + if( ScalableSurface.AUTOMAX_PIXELSCALE >= minPS ) { + result[0] = ScalableSurface.AUTOMAX_PIXELSCALE; + result[1] = ScalableSurface.AUTOMAX_PIXELSCALE; + } else if( PlatformUniformPixelScale ) { + final int maxPS = Math.max(reqPixelScale[0], reqPixelScale[1]); + if( maxPS >= PlatformMaxPixelScale[0] ) { + result[0] = PlatformMaxPixelScale[0]; + result[1] = PlatformMaxPixelScale[1]; + } else { + result[0] = maxPS; + result[1] = maxPS; + } + } else { + if( reqPixelScale[0] >= PlatformMaxPixelScale[0] ) { + result[0] = PlatformMaxPixelScale[0]; + } else { + result[0] = reqPixelScale[0]; + } + if( reqPixelScale[1] >= PlatformMaxPixelScale[1] ) { + result[1] = PlatformMaxPixelScale[1]; + } else { + result[1] = reqPixelScale[1]; + } + } + if( null != DEBUG_PREFIX ) { + System.err.println(DEBUG_PREFIX+".validateReqPixelScale: ["+reqPixelScale[0]+"x"+reqPixelScale[1]+" (req), "+ + PlatformMaxPixelScale[0]+"x"+PlatformMaxPixelScale[1]+" (max)] -> "+ + result[0]+"x"+result[1]+" (valid)"); + } + } + + /** + * Replaces {@link ScalableSurface#AUTOMAX_PIXELSCALE} with {@link #getPlatformMaxPixelScale(int[])}, + * for each component. + * + * @param pixelScale int[2] value array to be tested and replaced + */ + public static void replaceAutoMaxWithPlatformMax(final int[] pixelScale) { + if( ScalableSurface.AUTOMAX_PIXELSCALE == pixelScale[0] ) { + pixelScale[0] = PlatformMaxPixelScale[0]; + } + if( ScalableSurface.AUTOMAX_PIXELSCALE == pixelScale[1] ) { + pixelScale[1] = PlatformMaxPixelScale[1]; + } + } + + /** + * Returns the maximum platform pixelScale + */ + public static int[] getPlatformMaxPixelScale(final int[] result) { + System.arraycopy(PlatformMaxPixelScale, 0, result, 0, 2); + return result; + } + + /** + * Returns true if platform pixelScale is uniform, i.e. same scale factor for x- and y-direction, otherwise false. + */ + public static boolean isPlatformPixelScaleUniform() { + return PlatformUniformPixelScale; + } + + /** + * Returns whether the platform supports pixelScale + */ + public static boolean isPlatformPixelScaleSupported() { + return PlatformPixelScaleSupported; + } + +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java index 902223c80..1a8772988 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java @@ -31,6 +31,7 @@ package jogamp.nativewindow; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.ScalableSurface; import javax.media.nativewindow.UpstreamSurfaceHook; import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; @@ -40,8 +41,9 @@ import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; * * @see ProxySurface */ -public class WrappedSurface extends ProxySurfaceImpl { - protected long surfaceHandle; +public class WrappedSurface extends ProxySurfaceImpl implements ScalableSurface { + private final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + private long surfaceHandle; /** * Utilizes a {@link UpstreamSurfaceHook.MutableSize} to hold the size information, @@ -76,6 +78,8 @@ public class WrappedSurface extends ProxySurfaceImpl { @Override protected void invalidateImpl() { surfaceHandle = 0; + hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; + hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; } @Override @@ -97,14 +101,61 @@ public class WrappedSurface extends ProxySurfaceImpl { protected final void unlockSurfaceImpl() { } + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(int[]) given pixelScale} directly. + * </p> + */ @Override public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { - return pixelUnitsAndResult; // FIXME HiDPI: use 'pixelScale' + pixelUnitsAndResult[0] /= hasPixelScale[0]; + pixelUnitsAndResult[1] /= hasPixelScale[1]; + return pixelUnitsAndResult; } + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(int[]) given pixelScale} directly. + * </p> + */ @Override public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { - return windowUnitsAndResult; // FIXME HiDPI: use 'pixelScale' + windowUnitsAndResult[0] *= hasPixelScale[0]; + windowUnitsAndResult[1] *= hasPixelScale[1]; + return windowUnitsAndResult; + } + + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation is to simply pass the given pixelScale + * from the caller <i>down</i> to this instance without validation to be applied in the {@link #convertToPixelUnits(int[]) conversion} {@link #convertToWindowUnits(int[]) methods} <b>only</b>.<br/> + * This allows the caller to pass down knowledge about window- and pixel-unit conversion and utilize mentioned conversion methods. + * </p> + * <p> + * The given pixelScale will not impact the actual {@link #getSurfaceWidth()} and {@link #getSurfaceHeight()}, + * which is determinated by this instances {@link #getUpstreamSurface() upstream surface}. + * </p> + * <p> + * Implementation uses the default pixelScale {@link ScalableSurface#IDENTITY_PIXELSCALE} + * and resets to default values on {@link #invalidateImpl()}, i.e. {@link #destroyNotify()}. + * </p> + * <p> + * Implementation returns the given pixelScale array. + * </p> + */ + @Override + public final void setSurfaceScale(final int[] pixelScale) { + hasPixelScale[0] = pixelScale[0]; + hasPixelScale[1] = pixelScale[1]; + } + + @Override + public final int[] getSurfaceScale(final int[] result) { + System.arraycopy(hasPixelScale, 0, result, 0, 2); + return result; } }
\ No newline at end of file diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index 3b91fc8ab..3d88049b2 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -114,6 +114,27 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { } @Override + public void setSurfaceScale(final int[] pixelScale) { + super.setSurfaceScale(pixelScale); + if( 0 != drawable ) { // locked at least once ! + final int hadPixelScaleX = getPixelScaleX(); + updatePixelScale(); + + if( hadPixelScaleX != getPixelScaleX() && 0 != getAttachedSurfaceLayer() ) { + OSXUtil.RunOnMainThread(false, new Runnable() { + @Override + public void run() { + final long osl = getAttachedSurfaceLayer(); + if( 0 != osl ) { + OSXUtil.SetCALayerPixelScale(rootSurfaceLayer, osl, getPixelScaleX()); + } + } + }); + } + } + } + + @Override protected void attachSurfaceLayerImpl(final long layerHandle) { OSXUtil.RunOnMainThread(false, new Runnable() { @Override @@ -143,7 +164,8 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { } else if( DEBUG ) { System.err.println("JAWTWindow.attachSurfaceLayerImpl: "+toHexString(layerHandle) + ", [ins "+outterInsets+"], p0 "+p0+" -> "+p1+", bounds "+bounds); } - OSXUtil.AddCASublayer(rootSurfaceLayer, layerHandle, p1.getX(), p1.getY(), getWidth(), getHeight(), getPixelScale(), JAWTUtil.getOSXCALayerQuirks()); + // HiDPI: uniform pixel scale + OSXUtil.AddCASublayer(rootSurfaceLayer, layerHandle, p1.getX(), p1.getY(), getWidth(), getHeight(), getPixelScaleX(), JAWTUtil.getOSXCALayerQuirks()); } } ); } @@ -309,7 +331,7 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { public void run() { String errMsg = null; if(0 == rootSurfaceLayer && 0 != jawtSurfaceLayersHandle) { - rootSurfaceLayer = OSXUtil.CreateCALayer(bounds.getWidth(), bounds.getHeight(), getPixelScale()); + rootSurfaceLayer = OSXUtil.CreateCALayer(bounds.getWidth(), bounds.getHeight(), getPixelScaleX()); // HiDPI: uniform pixel scale if(0 == rootSurfaceLayer) { errMsg = "Could not create root CALayer"; } else { diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index 12e574ced..a91698f62 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -44,6 +44,9 @@ public class OSXUtil implements ToolkitProperties { private static boolean isInit = false; private static final boolean DEBUG = Debug.debug("OSXUtil"); + /** FIXME HiDPI: OSX unique and maximum value {@value} */ + public static final int MAX_PIXELSCALE = 2; + /** * Called by {@link NativeWindowFactory#initSingleton()} * @see ToolkitProperties @@ -201,6 +204,20 @@ public class OSXUtil implements ToolkitProperties { } /** + * Set root and sub CALayer pixelScale / contentScale for HiDPI + * + * @param rootCALayer the root surface layer, maybe null. + * @param subCALayer the client surface layer, maybe null. + * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale + */ + public static void SetCALayerPixelScale(final long rootCALayer, final long subCALayer, final float contentsScale) { + if( 0==rootCALayer && 0==subCALayer ) { + return; + } + SetCALayerPixelScale0(rootCALayer, subCALayer, contentsScale); + } + + /** * Detach a sub CALayer from the root CALayer. */ public static void RemoveCASublayer(final long rootCALayer, final long subCALayer) { @@ -364,6 +381,7 @@ public class OSXUtil implements ToolkitProperties { private static native long CreateCALayer0(int width, int height, float contentsScale); private static native void AddCASublayer0(long rootCALayer, long subCALayer, int x, int y, int width, int height, float contentsScale, int caLayerQuirks); private static native void FixCALayerLayout0(long rootCALayer, long subCALayer, boolean visible, int x, int y, int width, int height, int caLayerQuirks); + private static native void SetCALayerPixelScale0(long rootCALayer, long subCALayer, float contentsScale); private static native void RemoveCASublayer0(long rootCALayer, long subCALayer); private static native void DestroyCALayer0(long caLayer); private static native void RunOnMainThread0(Runnable runnable); diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index 62d3d67bb..fa3bf026a 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -639,13 +639,11 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 if(0 == width) { width = 32; } if(0 == height) { height = 32; } - if( 1.0 != contentsScale ) { NS_DURING - // Available >= 10.7 - [layer setContentsScale: (CGFloat)contentsScale]; + // Available >= 10.7 + [layer setContentsScale: (CGFloat)contentsScale]; NS_HANDLER NS_ENDHANDLER - } // initial dummy size ! CGRect lFrame = [layer frame]; @@ -692,12 +690,10 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 caLayerQuirks, rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount], lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (float)contentsScale); - if( 1.0 != contentsScale ) { NS_DURING - [subLayer setContentsScale: (CGFloat)contentsScale]; + [subLayer setContentsScale: (CGFloat)contentsScale]; NS_HANDLER NS_ENDHANDLER - } [subLayer setFrame:lRectRoot]; [rootLayer addSublayer:subLayer]; @@ -753,6 +749,37 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_FixCALayerLayout0 /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: SetCALayerPixelScale0 + * Signature: (JJF)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_SetCALayerPixelScale0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jfloat contentsScale) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); + if( NULL == rootLayer ) { + NativewindowCommon_throwNewRuntimeException(env, "Argument \"rootLayer\" is null"); + } + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + +NS_DURING + [rootLayer setContentsScale: (CGFloat)contentsScale]; + if( NULL != subLayer ) { + [subLayer setContentsScale: (CGFloat)contentsScale]; + } +NS_HANDLER +NS_ENDHANDLER + + [CATransaction commit]; + + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: RemoveCASublayer0 * Signature: (JJ)V */ |