--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CCustomCursor.java Thu Jan 09 18:04:31 2014 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CCustomCursor.java Thu Jan 09 18:41:00 2014 +0400
@@ -38,6 +38,8 @@
Image fImage;
Point fHotspot;
+ int fWidth;
+ int fHeight;
public CCustomCursor(final Image cursor, final Point hotSpot, final String name) throws IndexOutOfBoundsException, HeadlessException {
super(name);
@@ -50,6 +52,7 @@
// Make sure image is fully loaded.
final Component c = new Canvas(); // for its imageUpdate method
final MediaTracker tracker = new MediaTracker(c);
+ // MediaTracker loads resolution variants from MultiResolution Toolkit image
tracker.addImage(fImage, 0);
try {
tracker.waitForAll();
@@ -67,15 +70,15 @@
width = height = 1;
fImage = createTransparentImage(width, height);
} else {
- // Scale image to nearest supported size
+ // Get the nearest supported cursor size
final Dimension nativeSize = toolkit.getBestCursorSize(width, height);
- if (nativeSize.width != width || nativeSize.height != height) {
- fImage = fImage.getScaledInstance(nativeSize.width, nativeSize.height, Image.SCALE_DEFAULT);
- width = nativeSize.width;
- height = nativeSize.height;
- }
+ width = nativeSize.width;
+ height = nativeSize.height;
}
+ fWidth = width;
+ fHeight = height;
+
// NOTE: this was removed for 3169146, but in 1.5 the JCK tests for an exception and fails if one isn't thrown.
// See what JBuilder does.
// Verify that the hotspot is within cursor bounds.
@@ -138,6 +141,7 @@
// failed to do its job. Return null to keep the cursor unchanged.
return 0L;
} else {
+ fCImage.resizeRepresentations(fWidth, fHeight);
return fCImage.ptr;
}
} catch (IllegalArgumentException iae) {
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CImage.java Thu Jan 09 18:04:31 2014 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CImage.java Thu Jan 09 18:41:00 2014 +0400
@@ -31,6 +31,7 @@
import java.util.Arrays;
import java.util.List;
+import sun.awt.image.MultiResolutionImage;
import sun.awt.image.SunWritableRaster;
@@ -44,6 +45,7 @@
private static native void nativeCopyNSImageIntoArray(long image, int[] buffer, int w, int h);
private static native Dimension2D nativeGetNSImageSize(long image);
private static native void nativeSetNSImageSize(long image, double w, double h);
+ private static native void nativeResizeNSImageRepresentations(long image, double w, double h);
static Creator creator = new Creator();
static Creator getCreator() {
@@ -145,6 +147,12 @@
// This is used to create a CImage from a Image
public CImage createFromImage(final Image image) {
+ if (image instanceof MultiResolutionImage) {
+ List<Image> resolutionVariants
+ = ((MultiResolutionImage) image).getResolutionVariants();
+ return createFromImages(resolutionVariants);
+ }
+
int[] buffer = imageToArray(image, true);
if (buffer == null) {
return null;
@@ -223,4 +231,8 @@
if (ptr != 0) nativeSetNSImageSize(ptr, w, h);
return this;
}
+
+ void resizeRepresentations(double w, double h) {
+ if (ptr != 0) nativeResizeNSImageRepresentations(ptr, w, h);
+ }
}
--- a/jdk/src/macosx/native/sun/awt/CImage.m Thu Jan 09 18:04:31 2014 +0400
+++ b/jdk/src/macosx/native/sun/awt/CImage.m Thu Jan 09 18:41:00 2014 +0400
@@ -320,3 +320,26 @@
JNF_COCOA_EXIT(env);
}
+
+/*
+ * Class: sun_lwawt_macosx_CImage
+ * Method: nativeResizeNSImageRepresentations
+ * Signature: (JDD)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeResizeNSImageRepresentations
+(JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h)
+{
+ if (!image) return;
+ NSImage *i = (NSImage *)jlong_to_ptr(image);
+
+JNF_COCOA_ENTER(env);
+
+ NSImageRep *imageRep = nil;
+ NSArray *imageRepresentations = [i representations];
+ NSEnumerator *imageEnumerator = [imageRepresentations objectEnumerator];
+ while ((imageRep = [imageEnumerator nextObject]) != nil) {
+ [imageRep setSize:NSMakeSize(w, h)];
+ }
+
+JNF_COCOA_EXIT(env);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Cursor/MultiResolutionCursorTest/MultiResolutionCursorTest.html Thu Jan 09 18:41:00 2014 +0400
@@ -0,0 +1,32 @@
+<!--
+ 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.
+-->
+
+<html>
+ <head>
+ <title>High resolution custom cursor test, bug ID 8028212</title>
+ </head>
+ <body>
+ <applet CODE="MultiResolutionCursorTest.class" WIDTH=300 HEIGHT=100></applet>
+ <p> See the dialog box (usually in upper left corner) for instructions</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Cursor/MultiResolutionCursorTest/MultiResolutionCursorTest.java Thu Jan 09 18:41:00 2014 +0400
@@ -0,0 +1,266 @@
+/*
+ * 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.BorderLayout;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Label;
+import java.awt.Point;
+import java.awt.TextArea;
+import java.awt.Toolkit;
+import java.awt.image.BufferedImage;
+import java.util.LinkedList;
+import java.util.List;
+import javax.swing.JApplet;
+import sun.awt.OSInfo;
+import sun.awt.image.MultiResolutionImage;
+
+/**
+ * @test
+ * @bug 8028212
+ * @summary [macosx] Custom Cursor HiDPI support
+ * @author Alexander Scherbatiy
+ * @run applet/manual=yesno MultiResolutionCursorTest.html
+ */
+public class MultiResolutionCursorTest extends JApplet {
+ //Declare things used in the test, like buttons and labels here
+
+ static final int sizes[] = {16, 32, 128};
+ static final Color colors[] = {Color.WHITE, Color.RED, Color.GREEN, Color.BLUE};
+
+ public void init() {
+ //Create instructions for the user here, as well as set up
+ // the environment -- set the layout manager, add buttons,
+ // etc.
+ this.setLayout(new BorderLayout());
+
+ if (OSInfo.getOSType().equals(OSInfo.OSType.MACOSX)) {
+ String[] instructions = {
+ "Verify that high resolution custom cursor is used"
+ + " on HiDPI displays.",
+ "1) Run the test on Retina display or enable the Quartz Debug"
+ + " and select the screen resolution with (HiDPI) label",
+ "2) Move the cursor to the Test Frame",
+ "3) Check that cursor has red, green or blue color",
+ "If so, press PASS, else press FAIL."
+ };
+ Sysout.createDialogWithInstructions(instructions);
+
+ } else {
+ String[] instructions = {
+ "This test is not applicable to the current platform. Press PASS."
+ };
+ Sysout.createDialogWithInstructions(instructions);
+ }
+ }//End init()
+
+ public void start() {
+ //Get things going. Request focus, set size, et cetera
+ setSize(200, 200);
+ setVisible(true);
+ validate();
+
+ final Image image = new MultiResolutionCursor();
+
+ int center = sizes[0] / 2;
+ Cursor cursor = Toolkit.getDefaultToolkit().createCustomCursor(
+ image, new Point(center, center), "multi-resolution cursor");
+
+ Frame frame = new Frame("Test Frame");
+ frame.setSize(300, 300);
+ frame.setLocation(300, 50);
+ frame.add(new Label("Move cursor here"));
+ frame.setCursor(cursor);
+ frame.setVisible(true);
+ }// start()
+
+
+ static class MultiResolutionCursor extends BufferedImage implements MultiResolutionImage {
+
+ List<Image> highResolutionImages;
+
+ public MultiResolutionCursor() {
+ super(sizes[0], sizes[0], BufferedImage.TYPE_INT_RGB);
+
+ draw(getGraphics(), 0);
+ highResolutionImages = new LinkedList<>();
+ highResolutionImages.add(this);
+
+ for (int i = 1; i < sizes.length; i++) {
+ BufferedImage highResolutionImage =
+ new BufferedImage(sizes[i], sizes[i], BufferedImage.TYPE_INT_RGB);
+ draw(highResolutionImage.getGraphics(), i);
+ highResolutionImages.add(highResolutionImage);
+ }
+ }
+
+ @Override
+ public Image getResolutionVariant(int width, int height) {
+
+ for (int i = 0; i < sizes.length; i++) {
+ Image image = highResolutionImages.get(i);
+ int w = image.getWidth(null);
+ int h = image.getHeight(null);
+
+ if (width <= w && height <= h) {
+ return image;
+ }
+ }
+
+ return highResolutionImages.get(highResolutionImages.size() - 1);
+ }
+
+ void draw(Graphics graphics, int index) {
+ Graphics2D g2 = (Graphics2D) graphics;
+ Color color = colors[index];
+ g2.setColor(color);
+ g2.fillRect(0, 0, sizes[index], sizes[index]);
+ }
+
+ @Override
+ public List<Image> getResolutionVariants() {
+ return highResolutionImages;
+ }
+ }
+}// class BlockedWindowTest
+
+/* Place other classes related to the test after this line */
+/**
+ * **************************************************
+ * Standard Test Machinery DO NOT modify anything below -- it's a standard chunk
+ * of code whose purpose is to make user interaction uniform, and thereby make
+ * it simpler to read and understand someone else's test.
+ * **************************************************
+ */
+/**
+ * This is part of the standard test machinery. It creates a dialog (with the
+ * instructions), and is the interface for sending text messages to the user. To
+ * print the instructions, send an array of strings to Sysout.createDialog
+ * WithInstructions method. Put one line of instructions per array entry. To
+ * display a message for the tester to see, simply call Sysout.println with the
+ * string to be displayed. This mimics System.out.println but works within the
+ * test harness as well as standalone.
+ */
+class Sysout {
+
+ private static TestDialog dialog;
+
+ public static void createDialogWithInstructions(String[] instructions) {
+ dialog = new TestDialog(new Frame(), "Instructions");
+ dialog.printInstructions(instructions);
+ dialog.setVisible(true);
+ println("Any messages for the tester will display here.");
+ }
+
+ public static void createDialog() {
+ dialog = new TestDialog(new Frame(), "Instructions");
+ String[] defInstr = {"Instructions will appear here. ", ""};
+ dialog.printInstructions(defInstr);
+ dialog.setVisible(true);
+ println("Any messages for the tester will display here.");
+ }
+
+ public static void printInstructions(String[] instructions) {
+ dialog.printInstructions(instructions);
+ }
+
+ public static void println(String messageIn) {
+ dialog.displayMessage(messageIn);
+ }
+}// Sysout class
+
+/**
+ * This is part of the standard test machinery. It provides a place for the test
+ * instructions to be displayed, and a place for interactive messages to the
+ * user to be displayed. To have the test instructions displayed, see Sysout. To
+ * have a message to the user be displayed, see Sysout. Do not call anything in
+ * this dialog directly.
+ */
+class TestDialog extends Dialog {
+
+ TextArea instructionsText;
+ TextArea messageText;
+ int maxStringLength = 80;
+
+ //DO NOT call this directly, go through Sysout
+ public TestDialog(Frame frame, String name) {
+ super(frame, name);
+ int scrollBoth = TextArea.SCROLLBARS_BOTH;
+ instructionsText = new TextArea("", 15, maxStringLength, scrollBoth);
+ add("North", instructionsText);
+
+ messageText = new TextArea("", 5, maxStringLength, scrollBoth);
+ add("Center", messageText);
+
+ pack();
+
+ setVisible(true);
+ }// TestDialog()
+
+ //DO NOT call this directly, go through Sysout
+ public void printInstructions(String[] instructions) {
+ //Clear out any current instructions
+ instructionsText.setText("");
+
+ //Go down array of instruction strings
+
+ String printStr, remainingStr;
+ for (int i = 0; i < instructions.length; i++) {
+ //chop up each into pieces maxSringLength long
+ remainingStr = instructions[ i];
+ while (remainingStr.length() > 0) {
+ //if longer than max then chop off first max chars to print
+ if (remainingStr.length() >= maxStringLength) {
+ //Try to chop on a word boundary
+ int posOfSpace = remainingStr.lastIndexOf(' ', maxStringLength - 1);
+
+ if (posOfSpace <= 0) {
+ posOfSpace = maxStringLength - 1;
+ }
+
+ printStr = remainingStr.substring(0, posOfSpace + 1);
+ remainingStr = remainingStr.substring(posOfSpace + 1);
+ } //else just print
+ else {
+ printStr = remainingStr;
+ remainingStr = "";
+ }
+
+ instructionsText.append(printStr + "\n");
+
+ }// while
+
+ }// for
+
+ }//printInstructions()
+
+ //DO NOT call this directly, go through Sysout
+ public void displayMessage(String messageIn) {
+ messageText.append(messageIn + "\n");
+ System.out.println(messageIn);
+ }
+}// Te
\ No newline at end of file