提交 96638d6f 编写于 作者: A alexsch

8043869: [macosx] java -splash does not honor @2x hi dpi notation for retina support

Reviewed-by: pchelko, anthony, ksrini
上级 edae96d6
...@@ -35,6 +35,7 @@ SUNWprivate_1.1 { ...@@ -35,6 +35,7 @@ SUNWprivate_1.1 {
Java_java_awt_SplashScreen__1getImageFileName; Java_java_awt_SplashScreen__1getImageFileName;
Java_java_awt_SplashScreen__1getImageJarName; Java_java_awt_SplashScreen__1getImageJarName;
Java_java_awt_SplashScreen__1setImageData; Java_java_awt_SplashScreen__1setImageData;
Java_java_awt_SplashScreen__1getScaleFactor;
SplashLoadMemory; SplashLoadMemory;
SplashLoadFile; SplashLoadFile;
......
...@@ -125,6 +125,39 @@ done: ...@@ -125,6 +125,39 @@ done:
return buf; 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 void
SplashInitPlatform(Splash * splash) { SplashInitPlatform(Splash * splash) {
...@@ -132,7 +165,7 @@ SplashInitPlatform(Splash * splash) { ...@@ -132,7 +165,7 @@ SplashInitPlatform(Splash * splash) {
splash->maskRequired = 0; splash->maskRequired = 0;
//TODO: the following is too much of a hack but should work in 90% cases. //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 // besides we don't use device-dependant drawing, so probably
// that's very fine indeed // that's very fine indeed
...@@ -218,7 +251,15 @@ SplashRedrawWindow(Splash * splash) { ...@@ -218,7 +251,15 @@ SplashRedrawWindow(Splash * splash) {
[image setBackgroundColor: [NSColor clearColor]]; [image setBackgroundColor: [NSColor clearColor]];
[image addRepresentation: rep]; [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]; NSImageView * view = [[NSImageView alloc] init];
[view setImage: image]; [view setImage: image];
......
...@@ -1874,20 +1874,48 @@ ShowSplashScreen() ...@@ -1874,20 +1874,48 @@ ShowSplashScreen()
const char *jar_name = getenv(SPLASH_JAR_ENV_ENTRY); const char *jar_name = getenv(SPLASH_JAR_ENV_ENTRY);
const char *file_name = getenv(SPLASH_FILE_ENV_ENTRY); const char *file_name = getenv(SPLASH_FILE_ENV_ENTRY);
int data_size; 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) { 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) { if (image_data) {
DoSplashInit(); DoSplashInit();
DoSplashSetScaleFactor(scale_factor);
DoSplashLoadMemory(image_data, data_size); DoSplashLoadMemory(image_data, data_size);
JLI_MemFree(image_data); JLI_MemFree(image_data);
} }
} else if (file_name) {
DoSplashInit();
DoSplashLoadFile(file_name);
} else { } 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); DoSplashSetFileJarName(file_name, jar_name);
/* /*
......
...@@ -29,3 +29,6 @@ int DoSplashLoadFile(const char* filename); ...@@ -29,3 +29,6 @@ int DoSplashLoadFile(const char* filename);
void DoSplashInit(void); void DoSplashInit(void);
void DoSplashClose(void); void DoSplashClose(void);
void DoSplashSetFileJarName(const char* fileName, const char* jarName); void DoSplashSetFileJarName(const char* fileName, const char* jarName);
void DoSplashSetScaleFactor(float scaleFactor);
char* DoSplashGetScaledImageName(const char* jarName, const char* fileName,
float* scaleFactor);
...@@ -37,6 +37,9 @@ typedef void (*SplashInit_t)(void); ...@@ -37,6 +37,9 @@ typedef void (*SplashInit_t)(void);
typedef void (*SplashClose_t)(void); typedef void (*SplashClose_t)(void);
typedef void (*SplashSetFileJarName_t)(const char* fileName, typedef void (*SplashSetFileJarName_t)(const char* fileName,
const char* jarName); 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. * This macro invokes a function from the shared lib.
...@@ -58,11 +61,11 @@ typedef void (*SplashSetFileJarName_t)(const char* fileName, ...@@ -58,11 +61,11 @@ typedef void (*SplashSetFileJarName_t)(const char* fileName,
#define INVOKEV(name) _INVOKE(name, ,;) #define INVOKEV(name) _INVOKE(name, ,;)
int DoSplashLoadMemory(void* pdata, int size) { int DoSplashLoadMemory(void* pdata, int size) {
INVOKE(SplashLoadMemory,0)(pdata, size); INVOKE(SplashLoadMemory, NULL)(pdata, size);
} }
int DoSplashLoadFile(const char* filename) { int DoSplashLoadFile(const char* filename) {
INVOKE(SplashLoadFile,0)(filename); INVOKE(SplashLoadFile, NULL)(filename);
} }
void DoSplashInit(void) { void DoSplashInit(void) {
...@@ -76,3 +79,12 @@ void DoSplashClose(void) { ...@@ -76,3 +79,12 @@ void DoSplashClose(void) {
void DoSplashSetFileJarName(const char* fileName, const char* jarName) { void DoSplashSetFileJarName(const char* fileName, const char* jarName) {
INVOKEV(SplashSetFileJarName)(fileName, 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
...@@ -245,7 +245,14 @@ public final class SplashScreen { ...@@ -245,7 +245,14 @@ public final class SplashScreen {
public Rectangle getBounds() throws IllegalStateException { public Rectangle getBounds() throws IllegalStateException {
synchronized (SplashScreen.class) { synchronized (SplashScreen.class) {
checkVisible(); 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 { ...@@ -287,10 +294,19 @@ public final class SplashScreen {
public Graphics2D createGraphics() throws IllegalStateException { public Graphics2D createGraphics() throws IllegalStateException {
synchronized (SplashScreen.class) { synchronized (SplashScreen.class) {
if (image==null) { if (image==null) {
Dimension dim = getSize(); // get unscaled splash image size
image = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB); 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 { ...@@ -401,5 +417,6 @@ public final class SplashScreen {
private native static String _getImageFileName(long splashPtr); private native static String _getImageFileName(long splashPtr);
private native static String _getImageJarName(long SplashPtr); private native static String _getImageJarName(long SplashPtr);
private native static boolean _setImageData(long SplashPtr, byte[] data); private native static boolean _setImageData(long SplashPtr, byte[] data);
private native static float _getScaleFactor(long SplashPtr);
}; };
...@@ -220,3 +220,18 @@ JNIEXPORT jboolean JNICALL Java_java_awt_SplashScreen__1setImageData ...@@ -220,3 +220,18 @@ JNIEXPORT jboolean JNICALL Java_java_awt_SplashScreen__1setImageData
(*env)->ReleaseByteArrayElements(env, data, pBytes, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, data, pBytes, JNI_ABORT);
return rc ? JNI_TRUE : JNI_FALSE; 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
...@@ -59,6 +59,7 @@ SplashInit() ...@@ -59,6 +59,7 @@ SplashInit()
memset(splash, 0, sizeof(Splash)); memset(splash, 0, sizeof(Splash));
splash->currentFrame = -1; splash->currentFrame = -1;
splash->scaleFactor = 1;
initFormat(&splash->imageFormat, QUAD_RED_MASK, QUAD_GREEN_MASK, initFormat(&splash->imageFormat, QUAD_RED_MASK, QUAD_GREEN_MASK,
QUAD_BLUE_MASK, QUAD_ALPHA_MASK); QUAD_BLUE_MASK, QUAD_ALPHA_MASK);
SplashInitPlatform(splash); SplashInitPlatform(splash);
...@@ -101,6 +102,13 @@ SplashCleanup(Splash * splash) ...@@ -101,6 +102,13 @@ SplashCleanup(Splash * splash)
SplashSetFileJarName(NULL, NULL); SplashSetFileJarName(NULL, NULL);
} }
SPLASHEXPORT void
SplashSetScaleFactor(float scaleFactor)
{
Splash *splash = SplashGetInstance();
splash->scaleFactor = scaleFactor;
}
void void
SplashDone(Splash * splash) SplashDone(Splash * splash)
{ {
......
...@@ -35,6 +35,9 @@ SPLASHEXPORT int SplashLoadFile(const char *filename); // FIXME: range checking ...@@ -35,6 +35,9 @@ SPLASHEXPORT int SplashLoadFile(const char *filename); // FIXME: range checking
SPLASHEXPORT void SplashInit(void); SPLASHEXPORT void SplashInit(void);
SPLASHEXPORT void SplashClose(void); SPLASHEXPORT void SplashClose(void);
SPLASHEXPORT void SplashSetScaleFactor(float);
SPLASHEXPORT char* SplashGetScaledImageName(const char*, const char*, float*);
SPLASHEXPORT void SPLASHEXPORT void
SplashSetFileJarName(const char* fileName, const char* jarName); SplashSetFileJarName(const char* fileName, const char* jarName);
...@@ -79,6 +82,7 @@ typedef struct Splash ...@@ -79,6 +82,7 @@ typedef struct Splash
int fileNameLen; int fileNameLen;
char* jarName; /* stored in 16-bit unicode (jchars) */ char* jarName; /* stored in 16-bit unicode (jchars) */
int jarNameLen; int jarNameLen;
float scaleFactor;
#if defined(WITH_WIN32) #if defined(WITH_WIN32)
BOOL isLayered; BOOL isLayered;
HWND hWnd; HWND hWnd;
...@@ -115,6 +119,8 @@ void SplashDonePlatform(Splash * splash); ...@@ -115,6 +119,8 @@ void SplashDonePlatform(Splash * splash);
unsigned SplashTime(); unsigned SplashTime();
char* SplashConvertStringAlloc(const char* in, int *size); char* SplashConvertStringAlloc(const char* in, int *size);
char* SplashGetScaledImageName(const char* jarName,
const char* fileName, float *scaleFactor);
void SplashLock(Splash * splash); void SplashLock(Splash * splash);
void SplashUnlock(Splash * splash); void SplashUnlock(Splash * splash);
...@@ -138,6 +144,7 @@ void SplashDone(Splash * splash); ...@@ -138,6 +144,7 @@ void SplashDone(Splash * splash);
void SplashUpdateScreenData(Splash * splash); void SplashUpdateScreenData(Splash * splash);
void SplashCleanup(Splash * splash); void SplashCleanup(Splash * splash);
void SplashSetScaleFactor(float scaleFactor);
typedef struct SplashStream { typedef struct SplashStream {
......
...@@ -794,3 +794,11 @@ void ...@@ -794,3 +794,11 @@ void
SplashReconfigure(Splash * splash) { SplashReconfigure(Splash * splash) {
sendctl(splash, SPLASHCTL_RECONFIGURE); sendctl(splash, SPLASHCTL_RECONFIGURE);
} }
SPLASHEXPORT char*
SplashGetScaledImageName(const char* jarName, const char* fileName,
float *scaleFactor)
{
*scaleFactor = 1;
return NULL;
}
...@@ -568,3 +568,11 @@ SplashReconfigure(Splash * splash) ...@@ -568,3 +568,11 @@ SplashReconfigure(Splash * splash)
{ {
PostMessage(splash->hWnd, WM_SPLASHRECONFIGURE, 0, 0); PostMessage(splash->hWnd, WM_SPLASHRECONFIGURE, 0, 0);
} }
SPLASHEXPORT char*
SplashGetScaledImageName(const char* jarName, const char* fileName,
float *scaleFactor)
{
*scaleFactor = 1;
return NULL;
}
/*
* 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;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册