package com.sun.javafx.tk.quantum;
import java.io.IOException;
import java.io.InputStream;
import com.sun.javafx.iio.ImageFrame;
import com.sun.javafx.iio.ImageLoadListener;
import com.sun.javafx.iio.ImageLoader;
import com.sun.javafx.iio.ImageMetadata;
import com.sun.javafx.iio.ImageStorage;
import com.sun.javafx.iio.ImageStorageException;
import com.sun.javafx.runtime.async.AbstractRemoteResource;
import com.sun.javafx.runtime.async.AsyncOperationListener;
import com.sun.javafx.tk.PlatformImage;
import com.sun.prism.Image;
import com.sun.prism.impl.PrismSettings;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.sun.javafx.logging.PlatformLogger;
class PrismImageLoader2 implements com.sun.javafx.tk.ImageLoader {
private static PlatformLogger imageioLogger = null;
private Image[] images;
private int[] delayTimes;
private int loopCount;
private double width;
private double height;
private float pixelScale;
private Exception exception;
public PrismImageLoader2(String url, double width, double height,
boolean preserveRatio, float pixelScale,
boolean smooth)
{
loadAll(url, width, height, preserveRatio, pixelScale, smooth);
}
public PrismImageLoader2(InputStream stream, double width, double height,
boolean preserveRatio, boolean smooth)
{
loadAll(stream, width, height, preserveRatio, smooth);
}
public double getWidth() {
return width;
}
public double getHeight() {
return height;
}
public int getFrameCount() {
if (images == null) {
return 0;
}
return images.length;
}
public PlatformImage getFrame(int index) {
if (images == null) {
return null;
}
return images[index];
}
public int getFrameDelay(int index) {
if (images == null) {
return 0;
}
return delayTimes[index];
}
public int getLoopCount() {
if (images == null) {
return 0;
}
return loopCount;
}
public Exception getException() {
return exception;
}
private void loadAll(String url, double w, double h,
boolean preserveRatio, float pixelScale,
boolean smooth)
{
ImageLoadListener listener = new PrismLoadListener();
try {
ImageFrame[] imgFrames =
ImageStorage.loadAll(url, listener, w, h, preserveRatio, pixelScale, smooth);
convertAll(imgFrames);
} catch (ImageStorageException e) {
handleException(e);
} catch (Exception e) {
handleException(e);
}
}
private void loadAll(InputStream stream, double w, double h,
boolean preserveRatio, boolean smooth)
{
ImageLoadListener listener = new PrismLoadListener();
try {
ImageFrame[] imgFrames =
ImageStorage.loadAll(stream, listener, w, h, preserveRatio, 1.0f, smooth);
convertAll(imgFrames);
} catch (ImageStorageException e) {
handleException(e);
} catch (Exception e) {
handleException(e);
}
}
private void handleException(final ImageStorageException isException) {
final Throwable exceptionCause = isException.getCause();
if (exceptionCause instanceof Exception) {
handleException((Exception) exceptionCause);
} else {
handleException((Exception) isException);
}
}
private void handleException(final Exception exception) {
if (PrismSettings.verbose) {
exception.printStackTrace(System.err);
}
this.exception = exception;
}
private void convertAll(ImageFrame[] imgFrames) {
int numFrames = imgFrames.length;
images = new Image[numFrames];
delayTimes = new int[numFrames];
for (int i = 0; i < numFrames; i++) {
ImageFrame frame = imgFrames[i];
images[i] = com.sun.prism.Image.convertImageFrame(frame);
ImageMetadata metadata = frame.getMetadata();
if (metadata != null) {
Integer delay = metadata.delayTime;
if (delay != null) {
delayTimes[i] = delay.intValue();
}
Integer loopCount = metadata.loopCount;
if (loopCount != null) {
this.loopCount = loopCount;
}
}
if (i == 0) {
width = frame.getWidth();
height = frame.getHeight();
}
}
}
private static synchronized PlatformLogger getImageioLogger() {
if (imageioLogger == null) {
imageioLogger = PlatformLogger.getLogger("javafx.scene.image");
}
return imageioLogger;
}
private class PrismLoadListener implements ImageLoadListener {
public void imageLoadWarning(ImageLoader loader, String message) {
getImageioLogger().warning(message);
}
public void imageLoadProgress(ImageLoader loader,
float percentageComplete)
{
}
public void imageLoadMetaData(ImageLoader loader, ImageMetadata metadata) {
}
}
static final class AsyncImageLoader
extends AbstractRemoteResource<PrismImageLoader2>
{
private static final ExecutorService BG_LOADING_EXECUTOR =
createExecutor();
private final AccessControlContext acc;
double width, height;
boolean preserveRatio;
boolean smooth;
public AsyncImageLoader(
AsyncOperationListener<PrismImageLoader2> listener,
String url,
double width, double height, boolean preserveRatio, boolean smooth)
{
super(url, listener);
this.width = width;
this.height = height;
this.preserveRatio = preserveRatio;
this.smooth = smooth;
this.acc = AccessController.getContext();
}
@Override
protected PrismImageLoader2 processStream(InputStream stream) throws IOException {
return new PrismImageLoader2(stream, width, height, preserveRatio, smooth);
}
@Override
public PrismImageLoader2 call() throws IOException {
try {
return AccessController.doPrivileged(
(PrivilegedExceptionAction<PrismImageLoader2>) () -> AsyncImageLoader.super.call(), acc);
} catch (final PrivilegedActionException e) {
final Throwable cause = e.getCause();
if (cause instanceof IOException) {
throw (IOException) cause;
}
throw new UndeclaredThrowableException(cause);
}
}
@Override
public void start() {
BG_LOADING_EXECUTOR.execute(future);
}
private static ExecutorService createExecutor() {
final ThreadGroup bgLoadingThreadGroup =
AccessController.doPrivileged(
(PrivilegedAction<ThreadGroup>) () -> new ThreadGroup(
QuantumToolkit.getFxUserThread()
.getThreadGroup(),
"Background image loading thread pool")
);
final ThreadFactory bgLoadingThreadFactory =
runnable -> AccessController.doPrivileged(
(PrivilegedAction<Thread>) () -> {
final Thread newThread =
new Thread(bgLoadingThreadGroup,
runnable);
newThread.setPriority(
Thread.MIN_PRIORITY);
return newThread;
}
);
final ExecutorService bgLoadingExecutor =
Executors.newCachedThreadPool(bgLoadingThreadFactory);
((ThreadPoolExecutor) bgLoadingExecutor).setKeepAliveTime(
1, TimeUnit.SECONDS);
return bgLoadingExecutor;
}
}
}