1 /*
   2  * Copyright (c) 2010, 2015, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene.image;
  27 
  28 import com.sun.javafx.pgstub.*;
  29 import com.sun.javafx.test.PropertyInvalidationCounter;
  30 import com.sun.javafx.tk.Toolkit;
  31 import javafx.beans.InvalidationListener;
  32 import javafx.beans.Observable;
  33 import org.junit.Before;
  34 import org.junit.Test;
  35 
  36 import java.io.ByteArrayInputStream;
  37 import java.io.InputStream;
  38 import java.util.LinkedList;
  39 import java.util.Queue;
  40 
  41 import static org.junit.Assert.*;
  42 
  43 public final class ImageTest {
  44     private final StubToolkit toolkit;
  45     private final StubImageLoaderFactory imageLoaderFactory;
  46 
  47     public ImageTest() {
  48         toolkit = (StubToolkit) Toolkit.getToolkit();
  49         imageLoaderFactory = toolkit.getImageLoaderFactory();
  50     }
  51 
  52     @Before
  53     public void setUp() {
  54         imageLoaderFactory.reset();
  55     }
  56 
  57     @Test
  58     public void loadImageFromUrlBasicTest() {
  59         final String url = "file:test.png";
  60         registerImage(url, 100, 200);
  61         
  62         final Image image = new Image(url);
  63 
  64         assertEquals(url, image.impl_getUrl());
  65         verifyLoadedImage(image, 0, 0, false, false, 100, 200);
  66     }
  67 
  68     @Test
  69     public void loadImageFromUrlScaledTest() {
  70         final String url = "file:test.png";
  71         registerImage(url, 300, 100);
  72 
  73         final Image image = new Image(url, 200, 400, true, true);
  74 
  75         assertEquals(url, image.impl_getUrl());
  76         verifyLoadedImage(image, 200, 400, true, true, 300, 100);
  77     }
  78 
  79     @Test
  80     public void loadImageFromMissingUrlTest() {
  81         final Image image = new Image("file:missing.png");
  82 
  83         assertTrue(image.isError());
  84     }
  85 
  86     @Test
  87     public void loadImageFromStreamBasicTest() {
  88         final InputStream is = new ByteArrayInputStream(new byte[0]);
  89         registerImage(is, 100, 200);
  90 
  91         final Image image = new Image(is);
  92 
  93         assertEquals(is, image.getImpl_source());
  94         verifyLoadedImage(image, 0, 0, false, false, 100, 200);
  95     }
  96 
  97     @Test
  98     public void loadImageFromStreamScaledTest() {
  99         final InputStream is = new ByteArrayInputStream(new byte[0]);
 100         registerImage(is, 300, 100);
 101 
 102         final Image image = new Image(is, 200, 400, true, true);
 103 
 104         assertEquals(is, image.getImpl_source());
 105         verifyLoadedImage(image, 200, 400, true, true, 300, 100);
 106     }
 107 
 108     @Test
 109     public void fromPlatformImageTest() {
 110         final Object fakePlatformImage = new Object();
 111         registerImage(fakePlatformImage, 200, 500);
 112 
 113         final Image image = Image.impl_fromPlatformImage(fakePlatformImage);
 114         verifyLoadedImage(image, 0, 0, false, false, 200, 500);
 115     }
 116 
 117     @Test
 118     public void loadImageAsyncProgressTest() {
 119         final String url = "file:test.png";
 120         registerImage(url, 200, 100);
 121 
 122         final Image image = new Image(url, true);
 123 
 124         final StubAsyncImageLoader lastAsyncImageLoader =
 125                 getLastAsyncImageLoader();
 126 
 127         lastAsyncImageLoader.setProgress(0, 100);
 128         final float p1 = (float) image.getProgress();
 129 
 130         lastAsyncImageLoader.setProgress(33, 100);
 131         final float p2 = (float) image.getProgress();
 132 
 133         lastAsyncImageLoader.setProgress(66, 100);
 134         final float p3 = (float) image.getProgress();
 135 
 136         lastAsyncImageLoader.setProgress(200, 100);
 137         final float p4 = (float) image.getProgress();
 138 
 139         assertTrue(p1 < p2);
 140         assertTrue(p2 < p3);
 141         assertTrue(p3 == p4);
 142     }
 143 
 144     /*
 145     @Test
 146     public void loadImageAsyncPlaceholderTest() {
 147         final Object fakePlatformImage1 = new Object();
 148         registerImage(fakePlatformImage1, 200, 500);
 149         final Object fakePlatformImage2 = new Object();
 150         registerImage(fakePlatformImage2, 200, 500);
 151         
 152         final String url = "file:test.png";
 153         registerImage(url, 200, 100);
 154 
 155         final Image placeholderImage1 =
 156                 Image.impl_fromPlatformImage(fakePlatformImage1);
 157         final Image placeholderImage2 =
 158                 Image.impl_fromPlatformImage(fakePlatformImage2);
 159         final Image image = new Image(url, 500, 200, true, false, 
 160                                       true);
 161 
 162         final StubAsyncImageLoader lastAsyncImageLoader =
 163                 getLastAsyncImageLoader();
 164 
 165         final Object platformImage1 = getPlatformImage(image);
 166         final Object platformImage2 = getPlatformImage(image);
 167         lastAsyncImageLoader.finish();
 168         final Object platformImage3 = getPlatformImage(image);
 169         final Object platformImage4 = getPlatformImage(image);
 170 
 171         assertNotSame(platformImage1, platformImage2);
 172         assertNotSame(platformImage2, platformImage3);
 173         assertNotSame(platformImage1, platformImage3);
 174         assertSame(platformImage3, platformImage4);
 175 
 176         verifyLoadedImage(image, 500, 200, true, false, 200, 100);
 177     }
 178 
 179     @Test
 180     public void loadImageAsyncWithAsyncPlaceholderTest() {
 181         final String placeholderUrl = "file:placeholder.png";
 182         registerImage(placeholderUrl, 200, 100);
 183         final String finalUrl = "file:final.png";
 184         registerImage(finalUrl, 100, 200);
 185 
 186         final Image placeholderImage =
 187                 new Image(placeholderUrl, true);
 188         final StubAsyncImageLoader placeholderLoader =
 189                 getLastAsyncImageLoader();
 190 
 191         final Image finalImage =
 192                 new Image(finalUrl, true);
 193         final StubAsyncImageLoader finalLoader =
 194                 getLastAsyncImageLoader();
 195 
 196         assertNull(finalImage.impl_getPlatformImage());
 197         assertEquals(0, finalImage.getWidth(), 0);
 198         assertEquals(0, finalImage.getHeight(), 0);
 199 
 200         placeholderLoader.finish();
 201         assertEquals(placeholderUrl, getPlatformImage(finalImage).getSource());
 202         assertEquals(200, finalImage.getWidth(), 0);
 203         assertEquals(100, finalImage.getHeight(), 0);
 204 
 205         finalLoader.finish();
 206         assertEquals(finalUrl, getPlatformImage(finalImage).getSource());
 207         assertEquals(100, finalImage.getWidth(), 0);
 208         assertEquals(200, finalImage.getHeight(), 0);
 209     }
 210     */
 211 
 212     @Test
 213     public void loadImageAsyncCancelTest() {
 214         final String url = "file:test.png";
 215         registerImage(url, 200, 100);
 216 
 217         final Image image1 = new Image(url, true);
 218         final StubAsyncImageLoader lastAsyncImageLoader =
 219                 getLastAsyncImageLoader();
 220 
 221         image1.cancel();
 222         assertTrue(lastAsyncImageLoader.isCancelled());
 223         assertTrue(image1.isError());
 224 
 225         final Image image2 = new Image(url);
 226         image2.cancel();
 227         verifyLoadedImage(image2, 0, 0, false, false, 200, 100);
 228     }
 229 
 230     @Test
 231     public void loadImageAsyncErrorTest() {
 232         final String url = "file:test.png";
 233         registerImage(url, 200, 100);
 234 
 235         final Image image = new Image(url, true);
 236 
 237         final StubAsyncImageLoader lastAsyncImageLoader =
 238                 getLastAsyncImageLoader();
 239 
 240         final Exception testException = new Exception("Test exception");
 241 
 242         lastAsyncImageLoader.finish(testException);
 243         assertTrue(image.isError());
 244         assertEquals(testException, image.getException());
 245     }
 246 
 247     @Test
 248     public void loadMultipleImagesAsyncTest() {
 249         final int multiImageCount = 100;
 250         final Queue<StubAsyncImageLoader> asyncLoaders =
 251                 new LinkedList<StubAsyncImageLoader>();
 252         final Image[] images = new Image[multiImageCount];
 253 
 254         StubAsyncImageLoader lastAsyncLoader = null;
 255         for (int i = 0; i < multiImageCount; ++i) {
 256             final String url = "file:multi" + i + ".png";
 257             registerImage(url, 100, 100);
 258 
 259             images[i] = new Image(url, true);
 260 
 261             StubAsyncImageLoader asyncLoader =
 262                     imageLoaderFactory.getLastAsyncImageLoader();
 263             assertNotNull(asyncLoader);
 264             if (lastAsyncLoader == asyncLoader) {
 265                 asyncLoaders.poll().finish();
 266                 asyncLoader = imageLoaderFactory.getLastAsyncImageLoader();
 267                 assertNotSame(lastAsyncLoader, asyncLoader);
 268             }
 269 
 270             asyncLoaders.add(asyncLoader);
 271             lastAsyncLoader = asyncLoader;
 272         }
 273 
 274         for (final StubAsyncImageLoader asyncLoader: asyncLoaders) {
 275             asyncLoader.finish();
 276         }
 277 
 278         for (final Image image: images) {
 279             verifyLoadedImage(image, 0, 0, false, false, 100, 100);
 280         }
 281     }
 282 
 283     @Test
 284     public void loadMultipleImagesAsyncCancelTest() {
 285         final int multiImageCount = 100;
 286         final Image[] images = new Image[multiImageCount];
 287 
 288         for (int i = 0; i < multiImageCount; ++i) {
 289             final String url = "file:multi_cancel_" + i + ".png";
 290             registerImage(url, 100, 100);
 291 
 292             images[i] = new Image(url, true);
 293         }
 294 
 295         // traverse backwards to first cancel images which were queued because
 296         // of the thread limit
 297         for (int i = images.length - 1; i >= 0; --i) {
 298             final Image image = images[i];
 299             image.cancel();
 300             assertTrue(image.isError());
 301         }
 302     }
 303 
 304     @Test
 305     public void animatedImageTest() {
 306         // reset time
 307         toolkit.setAnimationTime(0);
 308         final Image animatedImage = 
 309                 TestImages.createAnimatedTestImage(
 310                         300, 400,        // width, height
 311                         0,               // loop count
 312                         2000, 1000, 3000 // frame delays
 313                 );
 314 
 315         verifyLoadedImage(animatedImage, 0, 0, false, false, 300, 400);
 316 
 317         toolkit.setAnimationTime(1000);
 318         assertEquals(0, getPlatformImage(animatedImage).getFrame());
 319 
 320         toolkit.setAnimationTime(2500);
 321         assertEquals(1, getPlatformImage(animatedImage).getFrame());
 322         
 323         toolkit.setAnimationTime(4500);
 324         assertEquals(2, getPlatformImage(animatedImage).getFrame());
 325         
 326         toolkit.setAnimationTime(7000);
 327         assertEquals(0, getPlatformImage(animatedImage).getFrame());
 328 
 329         TestImages.disposeAnimatedImage(animatedImage);
 330     }
 331 
 332     @Test
 333     public void animatedImageTestLoopOnce() {
 334         // reset time
 335         toolkit.setAnimationTime(0);
 336         final Image animatedImage = 
 337                 TestImages.createAnimatedTestImage(
 338                         300, 400,        // width, height
 339                         1,               // loop count
 340                         2000, 1000, 3000 // frame delays
 341                 );
 342 
 343         verifyLoadedImage(animatedImage, 0, 0, false, false, 300, 400);
 344 
 345         toolkit.setAnimationTime(1000);
 346         assertEquals(0, getPlatformImage(animatedImage).getFrame());
 347 
 348         toolkit.setAnimationTime(2500);
 349         assertEquals(1, getPlatformImage(animatedImage).getFrame());
 350         
 351         toolkit.setAnimationTime(4500);
 352         assertEquals(2, getPlatformImage(animatedImage).getFrame());
 353         
 354         toolkit.setAnimationTime(7000);
 355         assertEquals(2, getPlatformImage(animatedImage).getFrame());
 356 
 357         TestImages.disposeAnimatedImage(animatedImage);
 358     }
 359 
 360     @Test
 361     public void imagePropertyListenersCalledOnceTest() {
 362         final String url = "file:test.png";
 363         registerImage(url, 200, 100);
 364 
 365         final Image image = new Image(url, true);
 366 
 367         final StubAsyncImageLoader lastAsyncImageLoader =
 368                 getLastAsyncImageLoader();
 369 
 370         final PropertyInvalidationCounter<Number> widthInvalidationCounter =
 371                 new PropertyInvalidationCounter<Number>();
 372         final PropertyInvalidationCounter<Number> heightInvalidationCounter =
 373                 new PropertyInvalidationCounter<Number>();
 374         final PropertyInvalidationCounter<Object> plImageInvalidationCounter =
 375                 new PropertyInvalidationCounter<Object>();
 376 
 377         image.widthProperty().addListener(widthInvalidationCounter);
 378         image.heightProperty().addListener(heightInvalidationCounter);
 379         Toolkit.getImageAccessor().getImageProperty(image).addListener(plImageInvalidationCounter);
 380 
 381         assertEquals(0, image.getWidth(), 0);
 382         assertEquals(0, image.getHeight(), 0);
 383         assertEquals(null, image.impl_getPlatformImage());
 384 
 385         lastAsyncImageLoader.finish();
 386 
 387         assertEquals(1, widthInvalidationCounter.getCounter());
 388         assertEquals(1, heightInvalidationCounter.getCounter());
 389         assertEquals(1, plImageInvalidationCounter.getCounter());
 390     }
 391 
 392     @Test
 393     public void imagePropertiesChangedAtomicallyTest() {
 394         final String url = "file:test.png";
 395         registerImage(url, 200, 100);
 396 
 397         final Image image = new Image(url, true);
 398         final StubAsyncImageLoader lastAsyncImageLoader =
 399                 getLastAsyncImageLoader();
 400 
 401         final InvalidationListener imageChecker =
 402                 observable -> {
 403                     assertEquals(200, image.getWidth(), 0);
 404                     assertEquals(100, image.getHeight(), 0);
 405                     assertNotNull(image.impl_getPlatformImage());
 406                 };
 407 
 408         image.widthProperty().addListener(imageChecker);
 409         image.heightProperty().addListener(imageChecker);
 410         Toolkit.getImageAccessor().getImageProperty(image).addListener(imageChecker);
 411 
 412         assertEquals(0, image.getWidth(), 0);
 413         assertEquals(0, image.getHeight(), 0);
 414         assertEquals(null, image.impl_getPlatformImage());
 415 
 416         lastAsyncImageLoader.finish();
 417     }
 418 
 419     private static void verifyLoadedImage(final Image image,
 420                                           final int loadWidth,
 421                                           final int loadHeight,
 422                                           final boolean preserveRatio,
 423                                           final boolean smooth,
 424                                           final int imageWidth,
 425                                           final int imageHeight) {
 426         assertFalse(image.isError());
 427         assertEquals(1, (int) image.getProgress());
 428 
 429         final StubPlatformImage platformImage =
 430                 getPlatformImage(image);
 431         assertEquals(0, platformImage.getFrame());
 432 
 433         final StubImageLoader imageLoader =
 434                 platformImage.getImageLoader();
 435         assertEquals(loadWidth, imageLoader.getLoadWidth());
 436         assertEquals(loadHeight, imageLoader.getLoadHeight());
 437         assertEquals(preserveRatio, imageLoader.getPreserveRatio());
 438         assertEquals(smooth, imageLoader.getSmooth());
 439 
 440         assertEquals(imageWidth, (int) image.getWidth());
 441         assertEquals(imageHeight, (int) image.getHeight());
 442     }
 443 
 444     private static StubPlatformImage getPlatformImage(final Image srcImage) {
 445         final Object unknownPlatformImage = srcImage.impl_getPlatformImage();
 446         assertTrue(unknownPlatformImage instanceof StubPlatformImage);
 447         return (StubPlatformImage) unknownPlatformImage;
 448     }
 449 
 450     private void registerImage(final Object source,
 451                                final int width,
 452                                final int height) {
 453         imageLoaderFactory.registerImage(
 454                 source, new StubPlatformImageInfo(width, height));
 455     }
 456 
 457     private StubAsyncImageLoader getLastAsyncImageLoader() {
 458         final StubAsyncImageLoader lastAsyncImageLoader =
 459                 imageLoaderFactory.getLastAsyncImageLoader();
 460         assertNotNull(lastAsyncImageLoader);
 461         assertTrue(lastAsyncImageLoader.isStarted());
 462 
 463         return lastAsyncImageLoader;
 464     }
 465 
 466     @Test
 467     public void createImageFromClasspathTest() {
 468         final String url = "javafx/scene/image/test.png";
 469         final String resolvedUrl = Thread.currentThread().getContextClassLoader().getResource(url).toString();
 470         registerImage(resolvedUrl, 100, 200);
 471         
 472         final Image image = new Image(url);
 473 
 474         assertEquals(resolvedUrl, image.impl_getUrl());
 475         verifyLoadedImage(image, 0, 0, false, false, 100, 200);
 476     }
 477     
 478     @Test
 479     public void createImageFromClasspathTest_withLeadingSlash() {
 480         final String url = "/javafx/scene/image/test.png";
 481         final String resolvedUrl = Thread.currentThread().getContextClassLoader().getResource(url.substring(1)).toString();
 482         registerImage(resolvedUrl, 100, 200);
 483         
 484         final Image image = new Image(url);
 485 
 486         assertEquals(resolvedUrl, image.impl_getUrl());
 487         verifyLoadedImage(image, 0, 0, false, false, 100, 200);
 488     }
 489 
 490     @Test(expected=NullPointerException.class)
 491     public void createImageFromNullUrlTest() {
 492         new Image((String) null);
 493     }
 494 
 495     @Test(expected=NullPointerException.class)
 496     public void createImageAsyncFromNullUrlTest() {
 497         new Image(null, true);
 498     }
 499 
 500     @Test(expected=NullPointerException.class)
 501     public void createImageFromNullInputStreamTest() {
 502         new Image((InputStream) null);
 503     }
 504 
 505     @Test(expected=IllegalArgumentException.class)
 506     public void createImageFromEmptyUrlTest() {
 507         new Image("");
 508     }
 509 
 510     @Test(expected=IllegalArgumentException.class)
 511     public void createImageAsyncFromEmptyUrlTest() {
 512         new Image("", true);
 513     }
 514 
 515     @Test(expected=IllegalArgumentException.class)
 516     public void createImageFromInvalidUrlTest() {
 517         new Image(":");
 518     }
 519 
 520     @Test(expected=IllegalArgumentException.class)
 521     public void createImageAsyncFromInvalidUrlTest() {
 522         new Image(":", true);
 523     }
 524 
 525     @Test(expected=IllegalArgumentException.class)
 526     public void createImageFromUnsupportedUrlTest() {
 527         new Image("unsupported:image.png");
 528     }
 529 
 530     @Test(expected=IllegalArgumentException.class)
 531     public void createImageAsyncFromUnsupportedUrlTest() {
 532         new Image("unsupported:image.png", true);
 533     }
 534 }