summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEthan Vrhel <ethanvrhel@gmail.com>2020-08-10 14:08:42 -0700
committerRobin Watts <Robin.Watts@artifex.com>2020-09-24 13:10:48 +0100
commitb4f6bc2c5c8bcc7011760a8ab147db711122aec5 (patch)
tree2b003d793a616ef3ad9b7b4d6a7e4ff0465b6eeb
parent531331d831bf697315efed64a193f3a674a12c34 (diff)
downloadghostpdl-b4f6bc2c5c8bcc7011760a8ab147db711122aec5.tar.gz
Fixed some errors related to loading pages too fast
An error would occasionally be thrown in the SmartLoader having to do with the Document being modified while in the SmartLoader, causing an error. Reconfigured how the SmartLoader handles documents and is started and stopped.
-rw-r--r--demos/java/gsjava/src/com/artifex/gsjava/GSInstance.java38
-rw-r--r--demos/java/gsviewer/src/com/artifex/gsviewer/Document.java108
-rw-r--r--demos/java/gsviewer/src/com/artifex/gsviewer/ViewerController.java56
3 files changed, 156 insertions, 46 deletions
diff --git a/demos/java/gsjava/src/com/artifex/gsjava/GSInstance.java b/demos/java/gsjava/src/com/artifex/gsjava/GSInstance.java
index 9d6a349e1..5bb19037d 100644
--- a/demos/java/gsjava/src/com/artifex/gsjava/GSInstance.java
+++ b/demos/java/gsjava/src/com/artifex/gsjava/GSInstance.java
@@ -15,7 +15,7 @@ import com.artifex.gsjava.util.IntReference;
import com.artifex.gsjava.util.LongReference;
/**
- * Utility class to make Ghostscript calls easier by automatically storing a
+ * Utility class to make Ghostscript calls easier by storing a
* Ghostscript instance and, optionally, a caller handle.
*
* @author Ethan Vrhel
@@ -40,8 +40,10 @@ public class GSInstance {
}
public void deleteInstance() {
- gsapi_delete_instance(instance);
- instance = GS_NULL;
+ if (instance != GS_NULL) {
+ gsapi_delete_instance(instance);
+ instance = GS_NULL;
+ }
}
public int setStdio(IStdInFunction stdin, IStdOutFunction stdout, IStdErrFunction stderr) {
@@ -92,8 +94,38 @@ public class GSInstance {
return gsapi_run_string_begin(instance, userErrors, pExitCode);
}
+ public int runStringContinue(byte[] str, int length, int userErrors, IntReference pExitCode) {
+ return gsapi_run_string_continue(instance, str, length, userErrors, pExitCode);
+ }
+
+ public int runStringContinue(String str, int length, int userErrors, IntReference pExitCode) {
+ return gsapi_run_string_continue(instance, str, length, userErrors, pExitCode);
+ }
+
+ public int runString(byte[] str, int userErrors, IntReference pExitCode) {
+ return gsapi_run_string(instance, str, userErrors, pExitCode);
+ }
+
+ public int runString(String str, int userErrors, IntReference pExitCode) {
+ return gsapi_run_string(instance, str, userErrors, pExitCode);
+ }
+
+ public int runFile(byte[] fileName, int userErrors, IntReference pExitCode) {
+ return gsapi_run_file(instance, fileName, userErrors, pExitCode);
+ }
+
+ public int runFile(String filename, int userErrors, IntReference pExitCode) {
+ return gsapi_run_file(instance, filename, userErrors, pExitCode);
+ }
+
+ public int exit() {
+ return gsapi_exit(instance);
+ }
+
@Override
public void finalize() {
+ if (instance != GS_NULL)
+ exit();
deleteInstance();
}
diff --git a/demos/java/gsviewer/src/com/artifex/gsviewer/Document.java b/demos/java/gsviewer/src/com/artifex/gsviewer/Document.java
index c32b49514..fd3d20b57 100644
--- a/demos/java/gsviewer/src/com/artifex/gsviewer/Document.java
+++ b/demos/java/gsviewer/src/com/artifex/gsviewer/Document.java
@@ -15,6 +15,7 @@ import java.util.Objects;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
+import com.artifex.gsjava.GSInstance;
import com.artifex.gsjava.callbacks.DisplayCallback;
import com.artifex.gsjava.util.BytePointer;
import com.artifex.gsjava.util.LongReference;
@@ -303,24 +304,43 @@ public class Document implements List<Page> {
* @param instanceRef A reference to the instance of Ghostscript.
* @throws IllegalStateException When any Ghostscript operation fails to execute.
*/
- private static void initDocInstance(LongReference instanceRef) throws IllegalStateException {
- int code = gsapi_new_instance(instanceRef, GS_NULL);
+// private static void initDocInstance(LongReference instanceRef) throws IllegalStateException {
+// int code = gsapi_new_instance(instanceRef, GS_NULL);
+// if (code != GS_ERROR_OK) {
+// gsapi_delete_instance(instanceRef.value);
+// throw new IllegalStateException("Failed to set stdio with handle (code = " + code + ")");
+// }
+//
+// code = gsapi_set_arg_encoding(instanceRef.value, 1);
+// if (code != GS_ERROR_OK) {
+// gsapi_delete_instance(instanceRef.value);
+// throw new IllegalArgumentException("Failed to set arg encoding (code = " + code + ")");
+// }
+//
+// code = gsapi_set_display_callback(instanceRef.value, documentLoader.reset());
+// if (code != GS_ERROR_OK) {
+// gsapi_delete_instance(instanceRef.value);
+// throw new IllegalStateException("Failed to set display callback code=" + code);
+// }
+// }
+
+ private static GSInstance initDocInstance() throws IllegalStateException {
+ GSInstance instance = new GSInstance();
+
+ int code;
+ code = instance.setArgEncoding(1);
if (code != GS_ERROR_OK) {
- gsapi_delete_instance(instanceRef.value);
- throw new IllegalStateException("Failed to set stdio with handle (code = " + code + ")");
+ instance.deleteInstance();
+ throw new IllegalStateException("Failed to set arg encoding (code = " + code + ")");
}
- code = gsapi_set_arg_encoding(instanceRef.value, 1);
+ code = instance.setDisplayCallback(documentLoader.reset());
if (code != GS_ERROR_OK) {
- gsapi_delete_instance(instanceRef.value);
- throw new IllegalArgumentException("Failed to set arg encoding (code = " + code + ")");
+ instance.deleteInstance();
+ throw new IllegalStateException("Failed to set display callback (code = " + code + ")");
}
- code = gsapi_set_display_callback(instanceRef.value, documentLoader.reset());
- if (code != GS_ERROR_OK) {
- gsapi_delete_instance(instanceRef.value);
- throw new IllegalStateException("Failed to set display callback code=" + code);
- }
+ return instance;
}
/**
@@ -411,18 +431,21 @@ public class Document implements List<Page> {
startOperation();
- LongReference instanceRef = new LongReference();
+ GSInstance instance = null;
try {
- initDocInstance(instanceRef);
+ instance = initDocInstance();
} catch (IllegalStateException e) {
operationDone();
}
+ if (instance == null)
+ throw new IllegalStateException("Failed to initialize Ghostscript");
+
documentLoader.callback = loadCallback;
- int code = gsapi_init_with_args(instanceRef.value, gargs);
- gsapi_exit(instanceRef.value);
- gsapi_delete_instance(instanceRef.value);
+ int code = instance.initWithArgs(gargs);
+ instance.exit();
+ instance.deleteInstance();
if (code != GS_ERROR_OK) {
operationDone();
throw new IllegalStateException("Failed to gsapi_init_with_args code=" + code);
@@ -543,12 +566,19 @@ public class Document implements List<Page> {
"-dTextAlphaBits=4", "-dGraphicsAlphaBits=4",
"-f", file.getAbsolutePath() };
- LongReference instanceRef = new LongReference();
- initDocInstance(instanceRef);
+ GSInstance instance = null;
+ try {
+ instance = initDocInstance();
+ } catch (IllegalStateException e) {
+ operationDone();
+ }
+
+ if (instance == null)
+ throw new IllegalStateException("Failed to initialize Ghoscript");
- int code = gsapi_init_with_args(instanceRef.value, gargs);
- gsapi_exit(instanceRef.value);
- gsapi_delete_instance(instanceRef.value);
+ int code = instance.initWithArgs(gargs);
+ instance.exit();
+ instance.deleteInstance();
if (code != GS_ERROR_OK) {
operationDone();
throw new IllegalStateException("Failed to gsapi_init_with_args code=" + code);
@@ -627,12 +657,19 @@ public class Document implements List<Page> {
"-dTextAlphaBits=4", "-dGraphicsAlphaBits=4",
"-f", file.getAbsolutePath() };
- LongReference instanceRef = new LongReference();
- initDocInstance(instanceRef);
+ GSInstance instance = null;
+ try {
+ instance = initDocInstance();
+ } catch (IllegalStateException e) {
+ operationDone();
+ }
+
+ if (instance == null)
+ throw new IllegalStateException("Failed to initialize Ghoscript");
- int code = gsapi_init_with_args(instanceRef.value, gargs);
- gsapi_exit(instanceRef.value);
- gsapi_delete_instance(instanceRef.value);
+ int code = instance.initWithArgs(gargs);
+ instance.exit();
+ instance.deleteInstance();
if (code != GS_ERROR_OK) {
throw new IllegalStateException("Failed to gsapi_init_with_args code=" + code);
}
@@ -765,12 +802,19 @@ public class Document implements List<Page> {
"-dTextAlphaBits=4", "-dGraphicsAlphaBits=4",
"-f", file.getAbsolutePath() };
- LongReference instanceRef = new LongReference();
- initDocInstance(instanceRef);
+ GSInstance instance = null;
+ try {
+ instance = initDocInstance();
+ } catch (IllegalStateException e) {
+ operationDone();
+ }
+
+ if (instance == null)
+ throw new IllegalStateException("Failed to initialize Ghoscript");
- int code = gsapi_init_with_args(instanceRef.value, gargs);
- gsapi_exit(instanceRef.value);
- gsapi_delete_instance(instanceRef.value);
+ int code = instance.initWithArgs(gargs);
+ instance.exit();
+ instance.deleteInstance();
if (code != GS_ERROR_OK) {
operationDone();
throw new IllegalStateException("Failed to gsapi_init_with_args code=" + code);
diff --git a/demos/java/gsviewer/src/com/artifex/gsviewer/ViewerController.java b/demos/java/gsviewer/src/com/artifex/gsviewer/ViewerController.java
index c0b6b464c..aa60d9b92 100644
--- a/demos/java/gsviewer/src/com/artifex/gsviewer/ViewerController.java
+++ b/demos/java/gsviewer/src/com/artifex/gsviewer/ViewerController.java
@@ -27,6 +27,7 @@ public class ViewerController implements ViewerGUIListener {
private ViewerWindow source;
private Document currentDocument;
+ private SmartLoader smartLoader;
public void open(final File file) {
if (currentDocument != null)
@@ -121,6 +122,8 @@ public class ViewerController implements ViewerGUIListener {
@Override
public void onCloseFile() {
+ smartLoader.stop();
+ smartLoader = null;
close();
}
@@ -134,10 +137,10 @@ public class ViewerController implements ViewerGUIListener {
public void onSettingsOpen() { }
private void dispatchSmartLoader() {
- Thread t = new Thread(new SmartLoader());
- t.setDaemon(true);
- t.setName("Document-Smart-Loader-Thread");
- t.start();
+ if (smartLoader != null)
+ smartLoader.stop();
+ smartLoader = new SmartLoader(currentDocument);
+ smartLoader.start();
}
private class UnhandledExceptionHandler implements Thread.UncaughtExceptionHandler {
@@ -158,22 +161,55 @@ public class ViewerController implements ViewerGUIListener {
private class SmartLoader implements Runnable {
+ private volatile boolean[] loaded;
+ private volatile boolean shouldRun;
+ private Thread thread;
+
+ private SmartLoader(Document doc) {
+ loaded = new boolean[doc.size()];
+ shouldRun = true;
+ }
+
+ private void start() {
+ if (thread != null)
+ stop();
+ shouldRun = true;
+ thread = new Thread(this);
+ thread.setDaemon(true);
+ thread.setName("Document-Smart-Loader-Thread");
+ thread.start();
+ }
+
+ private void stop() {
+ shouldRun = false;
+ lock.lock();
+ cv.signalAll();
+ lock.unlock();
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Thread join interrupted", e);
+ }
+ thread = null;
+ }
+
@Override
public void run() {
System.out.println("Smart loader dispatched.");
- boolean[] loaded = new boolean[currentDocument.size()];
- Document doc;
- while ((doc = source.getLoadedDocument()) != null) {
+ while (shouldRun) {
int currentPage = source.getCurrentPage();
int[] toLoad = new int[] {
currentPage, currentPage - 1, currentPage + 1,
currentPage - 2, currentPage + 2 };
+ if (loaded.length != currentDocument.size())
+ throw new IllegalStateException("Array is size " + loaded.length + " while doc size is " + currentDocument.size());
+
int ind = 0;
for (int page : toLoad) {
- if (page >= 1 && page <= doc.size()) {
+ if (page >= 1 && page <= currentDocument.size()) {
if (!loaded[page - 1]) {
- doc.loadHighRes(Document.OPERATION_WAIT, page);
+ currentDocument.loadHighRes(Document.OPERATION_WAIT, page);
loaded[page - 1] = true;
}
}
@@ -187,8 +223,6 @@ public class ViewerController implements ViewerGUIListener {
cv.await();
} catch (InterruptedException e) {
System.err.println("Interrupted in smart loader: " + e);
- } catch (IllegalMonitorStateException e) {
- System.err.println("Exception in smart loader await: " + e);
} finally {
lock.unlock();
}