diff --git a/make/mapfiles/libsplashscreen/mapfile-vers b/make/mapfiles/libsplashscreen/mapfile-vers index b9507326ca0824f4320aa1eac731b5ee42f261a9..2be756be1e5fecc678dd8a3924d6d810e77ca2ab 100644 --- a/make/mapfiles/libsplashscreen/mapfile-vers +++ b/make/mapfiles/libsplashscreen/mapfile-vers @@ -35,6 +35,7 @@ SUNWprivate_1.1 { Java_java_awt_SplashScreen__1getImageFileName; Java_java_awt_SplashScreen__1getImageJarName; Java_java_awt_SplashScreen__1setImageData; + Java_java_awt_SplashScreen__1getScaleFactor; SplashLoadMemory; SplashLoadFile; diff --git a/src/macosx/native/sun/awt/splashscreen/splashscreen_sys.m b/src/macosx/native/sun/awt/splashscreen/splashscreen_sys.m index 40f380bdeb15ce87704f89cad8ce2891a49c868e..bcb59a9ff3104ad97bf71241539949cbe9038f70 100644 --- a/src/macosx/native/sun/awt/splashscreen/splashscreen_sys.m +++ b/src/macosx/native/sun/awt/splashscreen/splashscreen_sys.m @@ -125,6 +125,39 @@ done: return buf; } +char* SplashGetScaledImageName(const char* jar, const char* file, + float *scaleFactor) { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + *scaleFactor = 1; + char* scaledFile = nil; + float screenScaleFactor = [SplashNSScreen() backingScaleFactor]; + + if (screenScaleFactor > 1) { + NSString *fileName = [NSString stringWithUTF8String: file]; + NSUInteger length = [fileName length]; + NSRange range = [fileName rangeOfString: @"." + options:NSBackwardsSearch]; + NSUInteger dotIndex = range.location; + NSString *fileName2x = nil; + + if (dotIndex == NSNotFound) { + fileName2x = [fileName stringByAppendingString: @"@2x"]; + } else { + fileName2x = [fileName substringToIndex: dotIndex]; + fileName2x = [fileName2x stringByAppendingString: @"@2x"]; + fileName2x = [fileName2x stringByAppendingString: + [fileName substringFromIndex: dotIndex]]; + } + + if ((fileName2x != nil) && (jar || [[NSFileManager defaultManager] + fileExistsAtPath: fileName2x])){ + *scaleFactor = 2; + scaledFile = strdup([fileName2x UTF8String]); + } + } + [pool drain]; + return scaledFile; +} void SplashInitPlatform(Splash * splash) { @@ -132,7 +165,7 @@ SplashInitPlatform(Splash * splash) { splash->maskRequired = 0; - + //TODO: the following is too much of a hack but should work in 90% cases. // besides we don't use device-dependant drawing, so probably // that's very fine indeed @@ -218,7 +251,15 @@ SplashRedrawWindow(Splash * splash) { [image setBackgroundColor: [NSColor clearColor]]; [image addRepresentation: rep]; - + float scaleFactor = splash->scaleFactor; + if (scaleFactor > 0 && scaleFactor != 1) { + [image setScalesWhenResized:YES]; + NSSize size = [image size]; + size.width /= scaleFactor; + size.height /= scaleFactor; + [image setSize: size]; + } + NSImageView * view = [[NSImageView alloc] init]; [view setImage: image]; diff --git a/src/share/bin/java.c b/src/share/bin/java.c index cc354ebaf40cdb6e935e649103fd252211250741..4b16e8b5c4d823cfe67272d6df63f96d54f9ab32 100644 --- a/src/share/bin/java.c +++ b/src/share/bin/java.c @@ -1874,20 +1874,48 @@ ShowSplashScreen() const char *jar_name = getenv(SPLASH_JAR_ENV_ENTRY); const char *file_name = getenv(SPLASH_FILE_ENV_ENTRY); int data_size; - void *image_data; + void *image_data = NULL; + float scale_factor = 1; + char *scaled_splash_name = NULL; + + if (file_name == NULL){ + return; + } + + scaled_splash_name = DoSplashGetScaledImageName( + jar_name, file_name, &scale_factor); if (jar_name) { - image_data = JLI_JarUnpackFile(jar_name, file_name, &data_size); + + if (scaled_splash_name) { + image_data = JLI_JarUnpackFile( + jar_name, scaled_splash_name, &data_size); + } + + if (!image_data) { + scale_factor = 1; + image_data = JLI_JarUnpackFile( + jar_name, file_name, &data_size); + } if (image_data) { DoSplashInit(); + DoSplashSetScaleFactor(scale_factor); DoSplashLoadMemory(image_data, data_size); JLI_MemFree(image_data); } - } else if (file_name) { - DoSplashInit(); - DoSplashLoadFile(file_name); } else { - return; + DoSplashInit(); + if (scaled_splash_name) { + DoSplashSetScaleFactor(scale_factor); + DoSplashLoadFile(scaled_splash_name); + } else { + DoSplashLoadFile(file_name); + } + } + + if (scaled_splash_name) { + JLI_MemFree(scaled_splash_name); } + DoSplashSetFileJarName(file_name, jar_name); /* diff --git a/src/share/bin/splashscreen.h b/src/share/bin/splashscreen.h index da64bf6518deb5e67ce1342c955dbbce8edfa15f..3afd68c71e2e9df8533ac2a01515d4953636658d 100644 --- a/src/share/bin/splashscreen.h +++ b/src/share/bin/splashscreen.h @@ -29,3 +29,6 @@ int DoSplashLoadFile(const char* filename); void DoSplashInit(void); void DoSplashClose(void); void DoSplashSetFileJarName(const char* fileName, const char* jarName); +void DoSplashSetScaleFactor(float scaleFactor); +char* DoSplashGetScaledImageName(const char* jarName, const char* fileName, + float* scaleFactor); diff --git a/src/share/bin/splashscreen_stubs.c b/src/share/bin/splashscreen_stubs.c index 1ceee65ef605809ac5f6948c145d9bc5e4bd7865..9c1f5148c456c6783efe1cc05d02a9a9483caa63 100644 --- a/src/share/bin/splashscreen_stubs.c +++ b/src/share/bin/splashscreen_stubs.c @@ -37,6 +37,9 @@ typedef void (*SplashInit_t)(void); typedef void (*SplashClose_t)(void); typedef void (*SplashSetFileJarName_t)(const char* fileName, const char* jarName); +typedef void (*SplashSetScaleFactor_t)(float scaleFactor); +typedef char* (*SplashGetScaledImageName_t)(const char* fileName, + const char* jarName, float* scaleFactor); /* * This macro invokes a function from the shared lib. @@ -58,11 +61,11 @@ typedef void (*SplashSetFileJarName_t)(const char* fileName, #define INVOKEV(name) _INVOKE(name, ,;) int DoSplashLoadMemory(void* pdata, int size) { - INVOKE(SplashLoadMemory,0)(pdata, size); + INVOKE(SplashLoadMemory, NULL)(pdata, size); } int DoSplashLoadFile(const char* filename) { - INVOKE(SplashLoadFile,0)(filename); + INVOKE(SplashLoadFile, NULL)(filename); } void DoSplashInit(void) { @@ -76,3 +79,12 @@ void DoSplashClose(void) { void DoSplashSetFileJarName(const char* fileName, const char* jarName) { INVOKEV(SplashSetFileJarName)(fileName, jarName); } + +void DoSplashSetScaleFactor(float scaleFactor) { + INVOKEV(SplashSetScaleFactor)(scaleFactor); +} + +char* DoSplashGetScaledImageName(const char* fileName, const char* jarName, + float* scaleFactor) { + INVOKE(SplashGetScaledImageName, NULL)(fileName, jarName, scaleFactor); +} \ No newline at end of file diff --git a/src/share/classes/java/awt/SplashScreen.java b/src/share/classes/java/awt/SplashScreen.java index a1d4b6f9ac020f0c766d95b94489b40c82ffd295..9ec56251a359001e115942305ccfacdfa5e650cf 100644 --- a/src/share/classes/java/awt/SplashScreen.java +++ b/src/share/classes/java/awt/SplashScreen.java @@ -245,7 +245,14 @@ public final class SplashScreen { public Rectangle getBounds() throws IllegalStateException { synchronized (SplashScreen.class) { checkVisible(); - return _getBounds(splashPtr); + float scale = _getScaleFactor(splashPtr); + Rectangle bounds = _getBounds(splashPtr); + assert scale > 0; + if (scale > 0 && scale != 1) { + bounds.setSize((int) (bounds.getWidth() / scale), + (int) (bounds.getWidth() / scale)); + } + return bounds; } } @@ -287,10 +294,19 @@ public final class SplashScreen { public Graphics2D createGraphics() throws IllegalStateException { synchronized (SplashScreen.class) { if (image==null) { - Dimension dim = getSize(); - image = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB); + // get unscaled splash image size + Dimension dim = _getBounds(splashPtr).getSize(); + image = new BufferedImage(dim.width, dim.height, + BufferedImage.TYPE_INT_ARGB); + } + float scale = _getScaleFactor(splashPtr); + Graphics2D g = image.createGraphics(); + assert (scale > 0); + if (scale <= 0) { + scale = 1; } - return image.createGraphics(); + g.scale(scale, scale); + return g; } } @@ -401,5 +417,6 @@ public final class SplashScreen { private native static String _getImageFileName(long splashPtr); private native static String _getImageJarName(long SplashPtr); private native static boolean _setImageData(long SplashPtr, byte[] data); + private native static float _getScaleFactor(long SplashPtr); }; diff --git a/src/share/native/sun/awt/splashscreen/java_awt_SplashScreen.c b/src/share/native/sun/awt/splashscreen/java_awt_SplashScreen.c index 86f6837a773c87dbbfde38ee454030e9510d5ebf..eb63c49d681529841873f224a9769bce9ff9d749 100644 --- a/src/share/native/sun/awt/splashscreen/java_awt_SplashScreen.c +++ b/src/share/native/sun/awt/splashscreen/java_awt_SplashScreen.c @@ -220,3 +220,18 @@ JNIEXPORT jboolean JNICALL Java_java_awt_SplashScreen__1setImageData (*env)->ReleaseByteArrayElements(env, data, pBytes, JNI_ABORT); return rc ? JNI_TRUE : JNI_FALSE; } + +/* + * Class: java_awt_SplashScreen + * Method: _getScaleFactor + * Signature: (J)F + */ +JNIEXPORT jfloat JNICALL Java_java_awt_SplashScreen__1getScaleFactor +(JNIEnv *env, jclass thisClass, jlong jsplash) +{ + Splash *splash = (Splash *) jlong_to_ptr(jsplash); + if (!splash) { + return 1; + } + return splash->scaleFactor; +} \ No newline at end of file diff --git a/src/share/native/sun/awt/splashscreen/splashscreen_impl.c b/src/share/native/sun/awt/splashscreen/splashscreen_impl.c index 021447e287f30e4f835a8bb71d2fe2e65ea7eff4..ad30a9a3f8bf70b6dce863eb6b9ee24b438ecf36 100644 --- a/src/share/native/sun/awt/splashscreen/splashscreen_impl.c +++ b/src/share/native/sun/awt/splashscreen/splashscreen_impl.c @@ -59,6 +59,7 @@ SplashInit() memset(splash, 0, sizeof(Splash)); splash->currentFrame = -1; + splash->scaleFactor = 1; initFormat(&splash->imageFormat, QUAD_RED_MASK, QUAD_GREEN_MASK, QUAD_BLUE_MASK, QUAD_ALPHA_MASK); SplashInitPlatform(splash); @@ -101,6 +102,13 @@ SplashCleanup(Splash * splash) SplashSetFileJarName(NULL, NULL); } +SPLASHEXPORT void +SplashSetScaleFactor(float scaleFactor) +{ + Splash *splash = SplashGetInstance(); + splash->scaleFactor = scaleFactor; +} + void SplashDone(Splash * splash) { diff --git a/src/share/native/sun/awt/splashscreen/splashscreen_impl.h b/src/share/native/sun/awt/splashscreen/splashscreen_impl.h index 21f09cee1983d33fa79af66e413fb1a7ffff51b9..d26a4cb6be7d0506edf53e8e50381ecaad810c59 100644 --- a/src/share/native/sun/awt/splashscreen/splashscreen_impl.h +++ b/src/share/native/sun/awt/splashscreen/splashscreen_impl.h @@ -35,6 +35,9 @@ SPLASHEXPORT int SplashLoadFile(const char *filename); // FIXME: range checking SPLASHEXPORT void SplashInit(void); SPLASHEXPORT void SplashClose(void); +SPLASHEXPORT void SplashSetScaleFactor(float); +SPLASHEXPORT char* SplashGetScaledImageName(const char*, const char*, float*); + SPLASHEXPORT void SplashSetFileJarName(const char* fileName, const char* jarName); @@ -79,6 +82,7 @@ typedef struct Splash int fileNameLen; char* jarName; /* stored in 16-bit unicode (jchars) */ int jarNameLen; + float scaleFactor; #if defined(WITH_WIN32) BOOL isLayered; HWND hWnd; @@ -115,6 +119,8 @@ void SplashDonePlatform(Splash * splash); unsigned SplashTime(); char* SplashConvertStringAlloc(const char* in, int *size); +char* SplashGetScaledImageName(const char* jarName, + const char* fileName, float *scaleFactor); void SplashLock(Splash * splash); void SplashUnlock(Splash * splash); @@ -138,6 +144,7 @@ void SplashDone(Splash * splash); void SplashUpdateScreenData(Splash * splash); void SplashCleanup(Splash * splash); +void SplashSetScaleFactor(float scaleFactor); typedef struct SplashStream { diff --git a/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c b/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c index 1122258120724ffb73b66957954fff11a7122b69..85a93042f1d86c56698bb5a7e5ca9c751dc46fc0 100644 --- a/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c +++ b/src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c @@ -794,3 +794,11 @@ void SplashReconfigure(Splash * splash) { sendctl(splash, SPLASHCTL_RECONFIGURE); } + +SPLASHEXPORT char* +SplashGetScaledImageName(const char* jarName, const char* fileName, + float *scaleFactor) +{ + *scaleFactor = 1; + return NULL; +} diff --git a/src/windows/native/sun/awt/splashscreen/splashscreen_sys.c b/src/windows/native/sun/awt/splashscreen/splashscreen_sys.c index 8e02c1869fa29fe1c7ad452963c8d85701eb6720..3c1fe7f509192c77f028cd92187e85003c197517 100644 --- a/src/windows/native/sun/awt/splashscreen/splashscreen_sys.c +++ b/src/windows/native/sun/awt/splashscreen/splashscreen_sys.c @@ -568,3 +568,11 @@ SplashReconfigure(Splash * splash) { PostMessage(splash->hWnd, WM_SPLASHRECONFIGURE, 0, 0); } + +SPLASHEXPORT char* +SplashGetScaledImageName(const char* jarName, const char* fileName, + float *scaleFactor) +{ + *scaleFactor = 1; + return NULL; +} diff --git a/test/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java b/test/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a13cd81520e0f500cd2a0294413da8c426e1e2bb --- /dev/null +++ b/test/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2014, 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.Color; +import java.awt.Dialog; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.SplashScreen; +import java.awt.Window; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; +import sun.java2d.SunGraphics2D; + +/** + * @test + * @bug 8043869 + * @author Alexander Scherbatiy + * @summary [macosx] java -splash does not honor 2x hi dpi notation for retina + * support + * @run main MultiResolutionSplashTest GENERATE_IMAGES + * @run main/othervm -splash:splash1.png MultiResolutionSplashTest TEST_SPLASH 0 + * @run main/othervm -splash:splash2 MultiResolutionSplashTest TEST_SPLASH 1 + * @run main/othervm -splash:splash3. MultiResolutionSplashTest TEST_SPLASH 2 + */ +public class MultiResolutionSplashTest { + + private static final int IMAGE_WIDTH = 300; + private static final int IMAGE_HEIGHT = 200; + + private static final ImageInfo[] tests = { + new ImageInfo("splash1.png", "splash1@2x.png", Color.BLUE, Color.GREEN), + new ImageInfo("splash2", "splash2@2x", Color.WHITE, Color.BLACK), + new ImageInfo("splash3.", "splash3@2x.", Color.YELLOW, Color.RED) + }; + + public static void main(String[] args) throws Exception { + + String test = args[0]; + + switch (test) { + case "GENERATE_IMAGES": + generateImages(); + break; + case "TEST_SPLASH": + int index = Integer.parseInt(args[1]); + testSplash(tests[index]); + break; + default: + throw new RuntimeException("Unknown test: " + test); + } + } + + static void testSplash(ImageInfo test) throws Exception { + SplashScreen splashScreen = SplashScreen.getSplashScreen(); + + if (splashScreen == null) { + throw new RuntimeException("Splash screen is not shown!"); + } + + Graphics2D g = splashScreen.createGraphics(); + Rectangle splashBounds = splashScreen.getBounds(); + int screenX = (int) splashBounds.getCenterX(); + int screenY = (int) splashBounds.getCenterY(); + + Robot robot = new Robot(); + Color splashScreenColor = robot.getPixelColor(screenX, screenY); + + float scaleFactor = getScaleFactor(); + Color testColor = (1 < scaleFactor) ? test.color2x : test.color1x; + + if (!testColor.equals(splashScreenColor)) { + throw new RuntimeException( + "Image with wrong resolution is used for splash screen!"); + } + } + + static float getScaleFactor() { + + final Dialog dialog = new Dialog((Window) null); + dialog.setSize(100, 100); + dialog.setModal(true); + final float[] scaleFactors = new float[1]; + Panel panel = new Panel() { + + @Override + public void paint(Graphics g) { + float scaleFactor = 1; + if (g instanceof SunGraphics2D) { + scaleFactor = ((SunGraphics2D) g).surfaceData.getDefaultScale(); + } + scaleFactors[0] = scaleFactor; + dialog.setVisible(false); + } + }; + + dialog.add(panel); + dialog.setVisible(true); + dialog.dispose(); + + return scaleFactors[0]; + } + + static void generateImages() throws Exception { + for (ImageInfo test : tests) { + generateImage(test.name1x, test.color1x, 1); + generateImage(test.name2x, test.color2x, 2); + } + } + + static void generateImage(String name, Color color, int scale) throws Exception { + File file = new File(name); + if (file.exists()) { + return; + } + BufferedImage image = new BufferedImage(scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.getGraphics(); + g.setColor(color); + g.fillRect(0, 0, scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT); + ImageIO.write(image, "png", file); + } + + static class ImageInfo { + + final String name1x; + final String name2x; + final Color color1x; + final Color color2x; + + public ImageInfo(String name1x, String name2x, Color color1x, Color color2x) { + this.name1x = name1x; + this.name2x = name2x; + this.color1x = color1x; + this.color2x = color2x; + } + } +}