jdk/test/java/awt/image/MultiResolutionImageTest.java
changeset 23256 d71287a532f8
child 31448 1066345d2a8a
equal deleted inserted replaced
23255:ebd69e3d93c5 23256:d71287a532f8
       
     1 /*
       
     2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 import java.awt.Color;
       
    25 import java.awt.Graphics;
       
    26 import java.awt.Graphics2D;
       
    27 import java.awt.Image;
       
    28 import java.awt.Toolkit;
       
    29 import java.awt.image.BufferedImage;
       
    30 import java.io.File;
       
    31 import java.lang.reflect.Method;
       
    32 import java.net.URL;
       
    33 import javax.imageio.ImageIO;
       
    34 import sun.awt.OSInfo;
       
    35 import sun.awt.SunHints;
       
    36 import java.awt.MediaTracker;
       
    37 import java.awt.geom.AffineTransform;
       
    38 import java.awt.image.ImageObserver;
       
    39 import java.util.Arrays;
       
    40 import java.util.List;
       
    41 import javax.swing.JPanel;
       
    42 import sun.awt.SunToolkit;
       
    43 import sun.awt.image.MultiResolutionImage;
       
    44 
       
    45 /**
       
    46  * @test
       
    47  * @bug 8011059
       
    48  * @author Alexander Scherbatiy
       
    49  * @summary [macosx] Make JDK demos look perfect on retina displays
       
    50  * @run main MultiResolutionImageTest CUSTOM
       
    51  * @run main MultiResolutionImageTest TOOLKIT_PREPARE
       
    52  * @run main MultiResolutionImageTest TOOLKIT_LOAD
       
    53  * @run main MultiResolutionImageTest TOOLKIT
       
    54  */
       
    55 public class MultiResolutionImageTest {
       
    56 
       
    57     private static final int IMAGE_WIDTH = 300;
       
    58     private static final int IMAGE_HEIGHT = 200;
       
    59     private static final Color COLOR_1X = Color.GREEN;
       
    60     private static final Color COLOR_2X = Color.BLUE;
       
    61     private static final String IMAGE_NAME_1X = "image.png";
       
    62     private static final String IMAGE_NAME_2X = "image@2x.png";
       
    63 
       
    64     public static void main(String[] args) throws Exception {
       
    65 
       
    66         System.out.println("args: " + args.length);
       
    67 
       
    68         if (args.length == 0) {
       
    69             throw new RuntimeException("Not found a test");
       
    70         }
       
    71 
       
    72         String test = args[0];
       
    73 
       
    74         System.out.println("TEST: " + test);
       
    75         System.out.println("CHECK OS: " + checkOS());
       
    76 
       
    77         if ("CUSTOM".equals(test)) {
       
    78             testCustomMultiResolutionImage();
       
    79         } else if (checkOS()) {
       
    80             switch (test) {
       
    81                 case "CUSTOM":
       
    82                     break;
       
    83                 case "TOOLKIT_PREPARE":
       
    84                     testToolkitMultiResolutionImagePrepare();
       
    85                     break;
       
    86                 case "TOOLKIT_LOAD":
       
    87                     testToolkitMultiResolutionImageLoad();
       
    88                     break;
       
    89                 case "TOOLKIT":
       
    90                     testToolkitMultiResolutionImage();
       
    91                     testImageNameTo2xParsing();
       
    92                     break;
       
    93                 default:
       
    94                     throw new RuntimeException("Unknown test: " + test);
       
    95             }
       
    96         }
       
    97     }
       
    98 
       
    99     static boolean checkOS() {
       
   100         return OSInfo.getOSType() == OSInfo.OSType.MACOSX;
       
   101     }
       
   102 
       
   103     public static void testCustomMultiResolutionImage() {
       
   104         testCustomMultiResolutionImage(false);
       
   105         testCustomMultiResolutionImage(true);
       
   106     }
       
   107 
       
   108     public static void testCustomMultiResolutionImage(boolean enableImageScaling) {
       
   109 
       
   110         Image image = new MultiResolutionBufferedImage();
       
   111 
       
   112         // Same image size
       
   113         BufferedImage bufferedImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT,
       
   114                 BufferedImage.TYPE_INT_RGB);
       
   115         Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
       
   116         setImageScalingHint(g2d, enableImageScaling);
       
   117         g2d.drawImage(image, 0, 0, null);
       
   118         checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
       
   119 
       
   120         // Twice image size
       
   121         bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT,
       
   122                 BufferedImage.TYPE_INT_RGB);
       
   123         g2d = (Graphics2D) bufferedImage.getGraphics();
       
   124         setImageScalingHint(g2d, enableImageScaling);
       
   125         g2d.drawImage(image, 0, 0, 2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
       
   126         checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
       
   127 
       
   128         // Scale 2x
       
   129         bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
       
   130         g2d = (Graphics2D) bufferedImage.getGraphics();
       
   131         setImageScalingHint(g2d, enableImageScaling);
       
   132         g2d.scale(2, 2);
       
   133         g2d.drawImage(image, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
       
   134         checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
       
   135 
       
   136         // Rotate
       
   137         bufferedImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT,
       
   138                 BufferedImage.TYPE_INT_RGB);
       
   139         g2d = (Graphics2D) bufferedImage.getGraphics();
       
   140         setImageScalingHint(g2d, enableImageScaling);
       
   141         g2d.drawImage(image, 0, 0, null);
       
   142         g2d.rotate(Math.PI / 4);
       
   143         checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
       
   144 
       
   145         // Scale 2x and Rotate
       
   146         bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
       
   147         g2d = (Graphics2D) bufferedImage.getGraphics();
       
   148         setImageScalingHint(g2d, enableImageScaling);
       
   149         g2d.scale(-2, 2);
       
   150         g2d.rotate(-Math.PI / 10);
       
   151         g2d.drawImage(image, -IMAGE_WIDTH, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
       
   152         checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
       
   153 
       
   154         // General Transform
       
   155         bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
       
   156         g2d = (Graphics2D) bufferedImage.getGraphics();
       
   157         setImageScalingHint(g2d, enableImageScaling);
       
   158         float delta = 0.05f;
       
   159         float cos = 1 - delta * delta / 2;
       
   160         float sin = 1 + delta;
       
   161         AffineTransform transform = new AffineTransform(2 * cos, 0.1, 0.3, -2 * sin, 10, -5);
       
   162         g2d.setTransform(transform);
       
   163         g2d.drawImage(image, 0, -IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT, null);
       
   164         checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
       
   165 
       
   166         int D = 10;
       
   167         // From Source to small Destination region
       
   168         bufferedImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
       
   169         g2d = (Graphics2D) bufferedImage.getGraphics();
       
   170         setImageScalingHint(g2d, enableImageScaling);
       
   171         g2d.drawImage(image, IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2, IMAGE_WIDTH - D, IMAGE_HEIGHT - D,
       
   172                 D, D, IMAGE_WIDTH - D, IMAGE_HEIGHT - D, null);
       
   173         checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
       
   174 
       
   175         // From Source to large Destination region
       
   176         bufferedImage = new BufferedImage(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
       
   177         g2d = (Graphics2D) bufferedImage.getGraphics();
       
   178         setImageScalingHint(g2d, enableImageScaling);
       
   179         g2d.drawImage(image, D, D, 2 * IMAGE_WIDTH - D, 2 * IMAGE_HEIGHT - D,
       
   180                 IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2, IMAGE_WIDTH - D, IMAGE_HEIGHT - D, null);
       
   181         checkColor(bufferedImage.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
       
   182     }
       
   183 
       
   184     static class MultiResolutionBufferedImage extends BufferedImage
       
   185             implements MultiResolutionImage {
       
   186 
       
   187         Image highResolutionImage;
       
   188 
       
   189         public MultiResolutionBufferedImage() {
       
   190             super(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
       
   191             highResolutionImage = new BufferedImage(
       
   192                     2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
       
   193             draw(getGraphics(), 1);
       
   194             draw(highResolutionImage.getGraphics(), 2);
       
   195         }
       
   196 
       
   197         void draw(Graphics graphics, float resolution) {
       
   198             Graphics2D g2 = (Graphics2D) graphics;
       
   199             g2.scale(resolution, resolution);
       
   200             g2.setColor((resolution == 1) ? COLOR_1X : COLOR_2X);
       
   201             g2.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
       
   202         }
       
   203 
       
   204         @Override
       
   205         public Image getResolutionVariant(int width, int height) {
       
   206             return ((width <= getWidth() && height <= getHeight()))
       
   207                     ? this : highResolutionImage;
       
   208         }
       
   209 
       
   210         @Override
       
   211         public List<Image> getResolutionVariants() {
       
   212             return Arrays.asList(this, highResolutionImage);
       
   213         }
       
   214     }
       
   215 
       
   216     static void testToolkitMultiResolutionImagePrepare() throws Exception {
       
   217 
       
   218         generateImages();
       
   219 
       
   220         File imageFile = new File(IMAGE_NAME_1X);
       
   221         String fileName = imageFile.getAbsolutePath();
       
   222 
       
   223         Image image = Toolkit.getDefaultToolkit().getImage(fileName);
       
   224 
       
   225         SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
       
   226         toolkit.prepareImage(image, IMAGE_WIDTH, IMAGE_HEIGHT, new LoadImageObserver(image));
       
   227 
       
   228         testToolkitMultiResolutionImageLoad(image);
       
   229     }
       
   230 
       
   231     static void testToolkitMultiResolutionImageLoad() throws Exception {
       
   232 
       
   233         generateImages();
       
   234 
       
   235         File imageFile = new File(IMAGE_NAME_1X);
       
   236         String fileName = imageFile.getAbsolutePath();
       
   237         Image image = Toolkit.getDefaultToolkit().getImage(fileName);
       
   238         testToolkitMultiResolutionImageLoad(image);
       
   239     }
       
   240 
       
   241     static void testToolkitMultiResolutionImageLoad(Image image) throws Exception {
       
   242 
       
   243         MediaTracker tracker = new MediaTracker(new JPanel());
       
   244         tracker.addImage(image, 0);
       
   245         tracker.waitForID(0);
       
   246         if (tracker.isErrorAny()) {
       
   247             throw new RuntimeException("Error during image loading");
       
   248         }
       
   249         tracker.removeImage(image, 0);
       
   250 
       
   251         testImageLoaded(image);
       
   252 
       
   253         int w = image.getWidth(null);
       
   254         int h = image.getHeight(null);
       
   255 
       
   256         Image resolutionVariant = ((MultiResolutionImage) image)
       
   257                 .getResolutionVariant(2 * w, 2 * h);
       
   258 
       
   259         if (image == resolutionVariant) {
       
   260             throw new RuntimeException("Resolution variant is not loaded");
       
   261         }
       
   262 
       
   263         testImageLoaded(resolutionVariant);
       
   264     }
       
   265 
       
   266     static void testImageLoaded(Image image) {
       
   267 
       
   268         SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
       
   269 
       
   270         int flags = toolkit.checkImage(image, IMAGE_WIDTH, IMAGE_WIDTH, new SilentImageObserver());
       
   271         if ((flags & (ImageObserver.FRAMEBITS | ImageObserver.ALLBITS)) == 0) {
       
   272             throw new RuntimeException("Image is not loaded!");
       
   273         }
       
   274     }
       
   275 
       
   276     static class SilentImageObserver implements ImageObserver {
       
   277 
       
   278         @Override
       
   279         public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
       
   280             throw new RuntimeException("Observer should not be called!");
       
   281         }
       
   282     }
       
   283 
       
   284     static class LoadImageObserver implements ImageObserver {
       
   285 
       
   286         Image image;
       
   287 
       
   288         public LoadImageObserver(Image image) {
       
   289             this.image = image;
       
   290         }
       
   291 
       
   292         @Override
       
   293         public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
       
   294 
       
   295             if (image != img) {
       
   296                 throw new RuntimeException("Original image is not passed to the observer");
       
   297             }
       
   298 
       
   299             if ((infoflags & ImageObserver.WIDTH) != 0) {
       
   300                 if (width != IMAGE_WIDTH) {
       
   301                     throw new RuntimeException("Original width is not passed to the observer");
       
   302                 }
       
   303             }
       
   304 
       
   305             if ((infoflags & ImageObserver.HEIGHT) != 0) {
       
   306                 if (height != IMAGE_HEIGHT) {
       
   307                     throw new RuntimeException("Original height is not passed to the observer");
       
   308                 }
       
   309             }
       
   310 
       
   311             return (infoflags & ALLBITS) == 0;
       
   312         }
       
   313 
       
   314     }
       
   315 
       
   316     static void testToolkitMultiResolutionImage() throws Exception {
       
   317 
       
   318         generateImages();
       
   319 
       
   320         File imageFile = new File(IMAGE_NAME_1X);
       
   321         String fileName = imageFile.getAbsolutePath();
       
   322         URL url = imageFile.toURI().toURL();
       
   323         testToolkitMultiResolutionImageChache(fileName, url);
       
   324 
       
   325         Image image = Toolkit.getDefaultToolkit().getImage(fileName);
       
   326         testToolkitImageObserver(image);
       
   327         testToolkitMultiResolutionImage(image, false);
       
   328         testToolkitMultiResolutionImage(image, true);
       
   329 
       
   330         image = Toolkit.getDefaultToolkit().getImage(url);
       
   331         testToolkitImageObserver(image);
       
   332         testToolkitMultiResolutionImage(image, false);
       
   333         testToolkitMultiResolutionImage(image, true);
       
   334     }
       
   335 
       
   336     static void testToolkitMultiResolutionImageChache(String fileName, URL url) {
       
   337 
       
   338         Image img1 = Toolkit.getDefaultToolkit().getImage(fileName);
       
   339         if (!(img1 instanceof MultiResolutionImage)) {
       
   340             throw new RuntimeException("Not a MultiResolutionImage");
       
   341         }
       
   342 
       
   343         Image img2 = Toolkit.getDefaultToolkit().getImage(fileName);
       
   344         if (img1 != img2) {
       
   345             throw new RuntimeException("Image is not cached");
       
   346         }
       
   347 
       
   348         img1 = Toolkit.getDefaultToolkit().getImage(url);
       
   349         if (!(img1 instanceof MultiResolutionImage)) {
       
   350             throw new RuntimeException("Not a MultiResolutionImage");
       
   351         }
       
   352 
       
   353         img2 = Toolkit.getDefaultToolkit().getImage(url);
       
   354         if (img1 != img2) {
       
   355             throw new RuntimeException("Image is not cached");
       
   356         }
       
   357     }
       
   358 
       
   359     static void testToolkitMultiResolutionImage(Image image, boolean enableImageScaling)
       
   360             throws Exception {
       
   361 
       
   362         MediaTracker tracker = new MediaTracker(new JPanel());
       
   363         tracker.addImage(image, 0);
       
   364         tracker.waitForID(0);
       
   365         if (tracker.isErrorAny()) {
       
   366             throw new RuntimeException("Error during image loading");
       
   367         }
       
   368 
       
   369         final BufferedImage bufferedImage1x = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT,
       
   370                 BufferedImage.TYPE_INT_RGB);
       
   371         Graphics2D g1x = (Graphics2D) bufferedImage1x.getGraphics();
       
   372         setImageScalingHint(g1x, false);
       
   373         g1x.drawImage(image, 0, 0, null);
       
   374         checkColor(bufferedImage1x.getRGB(3 * IMAGE_WIDTH / 4, 3 * IMAGE_HEIGHT / 4), false);
       
   375 
       
   376         Image resolutionVariant = ((MultiResolutionImage) image).
       
   377                 getResolutionVariant(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT);
       
   378 
       
   379         if (resolutionVariant == null) {
       
   380             throw new RuntimeException("Resolution variant is null");
       
   381         }
       
   382 
       
   383         MediaTracker tracker2x = new MediaTracker(new JPanel());
       
   384         tracker2x.addImage(resolutionVariant, 0);
       
   385         tracker2x.waitForID(0);
       
   386         if (tracker2x.isErrorAny()) {
       
   387             throw new RuntimeException("Error during scalable image loading");
       
   388         }
       
   389 
       
   390         final BufferedImage bufferedImage2x = new BufferedImage(2 * IMAGE_WIDTH,
       
   391                 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
       
   392         Graphics2D g2x = (Graphics2D) bufferedImage2x.getGraphics();
       
   393         setImageScalingHint(g2x, enableImageScaling);
       
   394         g2x.drawImage(image, 0, 0, 2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
       
   395         checkColor(bufferedImage2x.getRGB(3 * IMAGE_WIDTH / 2, 3 * IMAGE_HEIGHT / 2), enableImageScaling);
       
   396 
       
   397         if (!(image instanceof MultiResolutionImage)) {
       
   398             throw new RuntimeException("Not a MultiResolutionImage");
       
   399         }
       
   400 
       
   401         MultiResolutionImage multiResolutionImage = (MultiResolutionImage) image;
       
   402 
       
   403         Image image1x = multiResolutionImage.getResolutionVariant(IMAGE_WIDTH, IMAGE_HEIGHT);
       
   404         Image image2x = multiResolutionImage.getResolutionVariant(2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT);
       
   405 
       
   406         if (image1x.getWidth(null) * 2 != image2x.getWidth(null)
       
   407                 || image1x.getHeight(null) * 2 != image2x.getHeight(null)) {
       
   408             throw new RuntimeException("Wrong resolution variant size");
       
   409         }
       
   410     }
       
   411 
       
   412     static void testToolkitImageObserver(final Image image) {
       
   413 
       
   414         ImageObserver observer = new ImageObserver() {
       
   415 
       
   416             @Override
       
   417             public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
       
   418 
       
   419                 if (img != image) {
       
   420                     throw new RuntimeException("Wrong image in observer");
       
   421                 }
       
   422 
       
   423                 if ((infoflags & (ImageObserver.ERROR | ImageObserver.ABORT)) != 0) {
       
   424                     throw new RuntimeException("Error during image loading");
       
   425                 }
       
   426 
       
   427                 return (infoflags & ImageObserver.ALLBITS) == 0;
       
   428 
       
   429             }
       
   430         };
       
   431 
       
   432         final BufferedImage bufferedImage2x = new BufferedImage(2 * IMAGE_WIDTH,
       
   433                 2 * IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
       
   434         Graphics2D g2x = (Graphics2D) bufferedImage2x.getGraphics();
       
   435         setImageScalingHint(g2x, true);
       
   436 
       
   437         g2x.drawImage(image, 0, 0, 2 * IMAGE_WIDTH, 2 * IMAGE_HEIGHT, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, observer);
       
   438 
       
   439     }
       
   440 
       
   441     static void setImageScalingHint(Graphics2D g2d, boolean enableImageScaling) {
       
   442         g2d.setRenderingHint(SunHints.KEY_RESOLUTION_VARIANT, enableImageScaling
       
   443                 ? SunHints.VALUE_RESOLUTION_VARIANT_ON
       
   444                 : SunHints.VALUE_RESOLUTION_VARIANT_OFF);
       
   445     }
       
   446 
       
   447     static void checkColor(int rgb, boolean isImageScaled) {
       
   448 
       
   449         if (!isImageScaled && COLOR_1X.getRGB() != rgb) {
       
   450             throw new RuntimeException("Wrong 1x color: " + new Color(rgb));
       
   451         }
       
   452 
       
   453         if (isImageScaled && COLOR_2X.getRGB() != rgb) {
       
   454             throw new RuntimeException("Wrong 2x color" + new Color(rgb));
       
   455         }
       
   456     }
       
   457 
       
   458     static void generateImages() throws Exception {
       
   459         if (!new File(IMAGE_NAME_1X).exists()) {
       
   460             generateImage(1);
       
   461         }
       
   462 
       
   463         if (!new File(IMAGE_NAME_2X).exists()) {
       
   464             generateImage(2);
       
   465         }
       
   466     }
       
   467 
       
   468     static void generateImage(int scale) throws Exception {
       
   469         BufferedImage image = new BufferedImage(scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT,
       
   470                 BufferedImage.TYPE_INT_RGB);
       
   471         Graphics g = image.getGraphics();
       
   472         g.setColor(scale == 1 ? COLOR_1X : COLOR_2X);
       
   473         g.fillRect(0, 0, scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT);
       
   474         File file = new File(scale == 1 ? IMAGE_NAME_1X : IMAGE_NAME_2X);
       
   475         ImageIO.write(image, "png", file);
       
   476     }
       
   477 
       
   478     static void testImageNameTo2xParsing() throws Exception {
       
   479 
       
   480         for (String[] testNames : TEST_FILE_NAMES) {
       
   481             String testName = testNames[0];
       
   482             String goldenName = testNames[1];
       
   483             String resultName = getTestScaledImageName(testName);
       
   484 
       
   485             if (!isValidPath(testName) && resultName == null) {
       
   486                 continue;
       
   487             }
       
   488 
       
   489             if (goldenName.equals(resultName)) {
       
   490                 continue;
       
   491             }
       
   492 
       
   493             throw new RuntimeException("Test name " + testName
       
   494                     + ", result name: " + resultName);
       
   495         }
       
   496 
       
   497         for (URL[] testURLs : TEST_URLS) {
       
   498             URL testURL = testURLs[0];
       
   499             URL goldenURL = testURLs[1];
       
   500             URL resultURL = getTestScaledImageURL(testURL);
       
   501 
       
   502             if (!isValidPath(testURL.getPath()) && resultURL == null) {
       
   503                 continue;
       
   504             }
       
   505 
       
   506             if (goldenURL.equals(resultURL)) {
       
   507                 continue;
       
   508             }
       
   509 
       
   510             throw new RuntimeException("Test url: " + testURL
       
   511                     + ", result url: " + resultURL);
       
   512         }
       
   513 
       
   514     }
       
   515 
       
   516     static URL getTestScaledImageURL(URL url) throws Exception {
       
   517         Method method = getScalableImageMethod("getScaledImageURL", URL.class);
       
   518         return (URL) method.invoke(null, url);
       
   519     }
       
   520 
       
   521     static String getTestScaledImageName(String name) throws Exception {
       
   522         Method method = getScalableImageMethod("getScaledImageName", String.class);
       
   523         return (String) method.invoke(null, name);
       
   524     }
       
   525 
       
   526     private static boolean isValidPath(String path) {
       
   527         return !path.isEmpty() && !path.endsWith("/") && !path.endsWith(".")
       
   528                 && !path.contains("@2x");
       
   529     }
       
   530 
       
   531     private static Method getScalableImageMethod(String name,
       
   532             Class... parameterTypes) throws Exception {
       
   533         Toolkit toolkit = Toolkit.getDefaultToolkit();
       
   534         Method method = toolkit.getClass().getDeclaredMethod(name, parameterTypes);
       
   535         method.setAccessible(true);
       
   536         return method;
       
   537     }
       
   538     private static final String[][] TEST_FILE_NAMES;
       
   539     private static final URL[][] TEST_URLS;
       
   540 
       
   541     static {
       
   542         TEST_FILE_NAMES = new String[][]{
       
   543             {"", null},
       
   544             {".", null},
       
   545             {"..", null},
       
   546             {"/", null},
       
   547             {"/.", null},
       
   548             {"dir/", null},
       
   549             {"dir/.", null},
       
   550             {"aaa@2x.png", null},
       
   551             {"/dir/aaa@2x.png", null},
       
   552             {"image", "image@2x"},
       
   553             {"image.ext", "image@2x.ext"},
       
   554             {"image.aaa.ext", "image.aaa@2x.ext"},
       
   555             {"dir/image", "dir/image@2x"},
       
   556             {"dir/image.ext", "dir/image@2x.ext"},
       
   557             {"dir/image.aaa.ext", "dir/image.aaa@2x.ext"},
       
   558             {"dir/aaa.bbb/image", "dir/aaa.bbb/image@2x"},
       
   559             {"dir/aaa.bbb/image.ext", "dir/aaa.bbb/image@2x.ext"},
       
   560             {"dir/aaa.bbb/image.ccc.ext", "dir/aaa.bbb/image.ccc@2x.ext"},
       
   561             {"/dir/image", "/dir/image@2x"},
       
   562             {"/dir/image.ext", "/dir/image@2x.ext"},
       
   563             {"/dir/image.aaa.ext", "/dir/image.aaa@2x.ext"},
       
   564             {"/dir/aaa.bbb/image", "/dir/aaa.bbb/image@2x"},
       
   565             {"/dir/aaa.bbb/image.ext", "/dir/aaa.bbb/image@2x.ext"},
       
   566             {"/dir/aaa.bbb/image.ccc.ext", "/dir/aaa.bbb/image.ccc@2x.ext"}
       
   567         };
       
   568         try {
       
   569             TEST_URLS = new URL[][]{
       
   570                 // file
       
   571                 {new URL("file:/aaa"), new URL("file:/aaa@2x")},
       
   572                 {new URL("file:/aaa.ext"), new URL("file:/aaa@2x.ext")},
       
   573                 {new URL("file:/aaa.bbb.ext"), new URL("file:/aaa.bbb@2x.ext")},
       
   574                 {new URL("file:/ccc/aaa.bbb.ext"),
       
   575                     new URL("file:/ccc/aaa.bbb@2x.ext")},
       
   576                 {new URL("file:/ccc.ddd/aaa.bbb.ext"),
       
   577                     new URL("file:/ccc.ddd/aaa.bbb@2x.ext")},
       
   578                 {new URL("file:///~/image"), new URL("file:///~/image@2x")},
       
   579                 {new URL("file:///~/image.ext"),
       
   580                     new URL("file:///~/image@2x.ext")},
       
   581                 // http
       
   582                 {new URL("http://www.test.com"), null},
       
   583                 {new URL("http://www.test.com/"), null},
       
   584                 {new URL("http://www.test.com///"), null},
       
   585                 {new URL("http://www.test.com/image"),
       
   586                     new URL("http://www.test.com/image@2x")},
       
   587                 {new URL("http://www.test.com/image.ext"),
       
   588                     new URL("http://www.test.com/image@2x.ext")},
       
   589                 {new URL("http://www.test.com/dir/image"),
       
   590                     new URL("http://www.test.com/dir/image@2x")},
       
   591                 {new URL("http://www.test.com:80/dir/image.aaa.ext"),
       
   592                     new URL("http://www.test.com:80/dir/image.aaa@2x.ext")},
       
   593                 {new URL("http://www.test.com:8080/dir/image.aaa.ext"),
       
   594                     new URL("http://www.test.com:8080/dir/image.aaa@2x.ext")},
       
   595                 // jar
       
   596                 {new URL("jar:file:/dir/Java2D.jar!/image"),
       
   597                     new URL("jar:file:/dir/Java2D.jar!/image@2x")},
       
   598                 {new URL("jar:file:/dir/Java2D.jar!/image.aaa.ext"),
       
   599                     new URL("jar:file:/dir/Java2D.jar!/image.aaa@2x.ext")},
       
   600                 {new URL("jar:file:/dir/Java2D.jar!/images/image"),
       
   601                     new URL("jar:file:/dir/Java2D.jar!/images/image@2x")},
       
   602                 {new URL("jar:file:/dir/Java2D.jar!/images/image.ext"),
       
   603                     new URL("jar:file:/dir/Java2D.jar!/images/image@2x.ext")},
       
   604                 {new URL("jar:file:/aaa.bbb/Java2D.jar!/images/image.ext"),
       
   605                     new URL("jar:file:/aaa.bbb/Java2D.jar!/images/image@2x.ext")},
       
   606                 {new URL("jar:file:/dir/Java2D.jar!/aaa.bbb/image.ext"),
       
   607                     new URL("jar:file:/dir/Java2D.jar!/aaa.bbb/image@2x.ext")},};
       
   608         } catch (Exception e) {
       
   609             throw new RuntimeException(e);
       
   610         }
       
   611     }
       
   612 
       
   613     static class PreloadedImageObserver implements ImageObserver {
       
   614 
       
   615         @Override
       
   616         public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
       
   617             throw new RuntimeException("Image should be already preloaded");
       
   618         }
       
   619     }
       
   620 }