summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2015-12-09 17:57:20 +0000
committerTor Andersson <tor.andersson@artifex.com>2016-02-29 16:03:34 +0100
commita6e15a6c904f700543429d94c703a4d1911e1ac2 (patch)
treec071a9eafc5834a04aad312e961b6099d0919b77
parent7621953bf3f8534ce53ae5611f6cbd2ef4cc869a (diff)
downloadmupdf-a6e15a6c904f700543429d94c703a4d1911e1ac2.tar.xz
jni: First attempt at generic JNI bindings.
The purpose of JNI bindings is to allow MuPDF to be driven from Java. There are several possible use cases here. Firstly, and most simply a java application can ask the core of MuPDF to open a document and render it using the existing devices to produce output on a standard Java bitmap. Secondly, a java application might want to drive the device interface itself, making use of the standard MuPDF devices (such as using the rendering engine to render high quality graphics). Thirdly, a java application might want to implement its own device and then call MuPDF to run the document to that device (perhaps to do custom text or image extraction). The first of these cases requires a simple reflection of the main document and standard device classes in JNI. The second of these cases requires the actual device interface itself to be made available as a java interface, together with the ability to construct and manipulate data types like paths, text and fonts so the Java code can build the required objects to pass to implementers of the device interface. The final case requires a reflection layer whereby calls through the device interface in C can be turned into method calls to a Java interface. All of this is attempted in this commit. Some highlights: For each type in the C (such as fz_colorspace) we have a corresponding java class (such as ColorSpace). Where the 'fz_' types are reference counted (such as an fz_colorspace), the java objects (such as ColorSpace) simply take a reference to a pointer to the underlying fz type. Java accessor methods are then provided to manipulate these types. Where the 'fz_' types are not reference counted (such as an fz_rect), the data is actually contained within the Java object itself (such as Rect, RectI and Transform). We add a VS jni project. This doesn't do anything except make the files accessible for editing in the IDE. As much as possible, the Java layers do nothing (other than some programmer friendly type overloading), construction (unavoidable, as can't be done in JNI) and boiler-plate destruction. All the smartness is done in the C. Due to Java and C's differing approach to constness, we need to be careful that a java device does not destructively alter objects passed to it. For example, consider running a display list through a device implemented in java. If the java device were to change a Font object passed to it, this might affect other objects in the display list that shared the same underlying fz_font. Possibly we can achieve this by having an 'isConst' flag on java objects that are created from device calls and passed to the Java device (see the Text class, for an attempt at this currently). This could alternatively be achieved by cloning every such piece of data (see the path code for an example of this approach), but this is probably slow. Better to clone 'just in time' as the first write operation is done to the object.
-rw-r--r--platform/android/jni/Android.mk2
-rw-r--r--platform/android/jni/mupdf_native.c3473
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/AndroidDrawDevice.java19
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Annotation.java27
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/AwtDrawDevice.java12
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/CDevice.java49
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/ColorSpace.java34
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Context.java20
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Cookie.java30
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Device.java172
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/DisplayList.java32
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/DisplayListDevice.java14
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Document.java60
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Font.java22
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Image.java56
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Link.java27
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Matrix.java59
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Outline.java22
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Page.java37
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Path.java82
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/PathProcessor.java9
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Point.java29
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Rect.java79
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/RectI.java79
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Shade.java28
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/StrokeState.java64
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/Text.java46
-rw-r--r--platform/android/src/com/artifex/mupdf/fitz/TryLaterException.java9
-rw-r--r--platform/android/src/com/artifex/mupdfdemo/MuPDFCore.java2
-rw-r--r--platform/win32/jni.vcproj441
-rw-r--r--platform/win32/mupdf.sln17
31 files changed, 5051 insertions, 1 deletions
diff --git a/platform/android/jni/Android.mk b/platform/android/jni/Android.mk
index 55cf593d..5c0b2294 100644
--- a/platform/android/jni/Android.mk
+++ b/platform/android/jni/Android.mk
@@ -19,7 +19,7 @@ LOCAL_C_INCLUDES := \
$(MUPDF_ROOT)/source/pdf
LOCAL_CFLAGS :=
LOCAL_MODULE := mupdf
-LOCAL_SRC_FILES := mupdf.c
+LOCAL_SRC_FILES := mupdf.c mupdf_native.c
LOCAL_STATIC_LIBRARIES := mupdfcore mupdfthirdparty
ifdef NDK_PROFILER
LOCAL_CFLAGS += -pg -DNDK_PROFILER
diff --git a/platform/android/jni/mupdf_native.c b/platform/android/jni/mupdf_native.c
new file mode 100644
index 00000000..b6ac0966
--- /dev/null
+++ b/platform/android/jni/mupdf_native.c
@@ -0,0 +1,3473 @@
+#include <jni.h>
+#include <time.h>
+#include <pthread.h>
+#include <android/log.h>
+#include <android/bitmap.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef NDK_PROFILER
+#include "prof.h"
+#endif
+
+#include "mupdf/fitz.h"
+#include "mupdf/pdf.h"
+
+#define MY_JNI_VERSION JNI_VERSION_1_6
+
+#define JNI_FN(A) Java_com_artifex_mupdf_fitz_ ## A
+#define PACKAGENAME "com.artifex.mupdf.fitz"
+#define PACKAGEPATH "com/artifex/mupdf/fitz/"
+
+#define LOG_TAG "libmupdf"
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
+#define LOGT(...) __android_log_print(ANDROID_LOG_INFO,"alert",__VA_ARGS__)
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
+
+/* Set to 1 to enable debug log traces. */
+#define DEBUG 0
+
+/* All the cached classes/mids/fids we need */
+
+static jclass annot_class;
+static jfieldID annot_fid;
+static jmethodID annot_const_mid;
+static jclass cdevice_class;
+static jfieldID cdevice_nativeresource_fid;
+static jfieldID cdevice_nativeinfo_fid;
+static jclass colorspace_class;
+static jfieldID colorspace_fid;
+static jmethodID colorspace_const_mid;
+static jclass cookie_class;
+static jfieldID cookie_fid;
+static jclass device_class;
+static jfieldID device_fid;
+static jmethodID device_begin_page_mid;
+static jmethodID device_end_page_mid;
+static jmethodID device_fill_path_mid;
+static jmethodID device_stroke_path_mid;
+static jmethodID device_clip_path_mid;
+static jmethodID device_clip_stroke_path_mid;
+static jmethodID device_fill_text_mid;
+static jmethodID device_stroke_text_mid;
+static jmethodID device_clip_text_mid;
+static jmethodID device_clip_stroke_text_mid;
+static jmethodID device_ignore_text_mid;
+static jmethodID device_fill_shade_mid;
+static jmethodID device_fill_image_mid;
+static jmethodID device_fill_image_mask_mid;
+static jmethodID device_clip_image_mask_mid;
+static jmethodID device_pop_clip_mid;
+static jmethodID device_begin_mask_mid;
+static jmethodID device_end_mask_mid;
+static jmethodID device_begin_group_mid;
+static jmethodID device_end_group_mid;
+static jmethodID device_begin_tile_mid;
+static jmethodID device_end_tile_mid;
+static jclass displaylist_class;
+static jfieldID displaylist_fid;
+static jclass document_class;
+static jfieldID document_fid;
+static jclass exception_class;
+static jclass font_class;
+static jfieldID font_fid;
+//static jfieldID font_isconst_fid;
+static jclass image_class;
+static jfieldID image_fid;
+static jmethodID image_const_mid;
+static jclass link_class;
+static jfieldID link_fid;
+static jclass matrix_class;
+static jfieldID matrix_a_fid;
+static jfieldID matrix_b_fid;
+static jfieldID matrix_c_fid;
+static jfieldID matrix_d_fid;
+static jfieldID matrix_e_fid;
+static jfieldID matrix_f_fid;
+static jmethodID matrix_const_mid;
+static jclass outline_class;
+static jfieldID outline_fid;
+static jmethodID outline_const_mid;
+static jclass page_class;
+static jfieldID page_fid;
+static jmethodID page_const_mid;
+static jfieldID page_document_fid;
+static jfieldID page_annots_fid;
+static jclass path_class;
+static jfieldID path_fid;
+static jmethodID path_const_mid;
+static jclass pathproc_class;
+static jmethodID pathproc_moveto_mid;
+static jmethodID pathproc_lineto_mid;
+static jmethodID pathproc_curveto_mid;
+static jmethodID pathproc_close_mid;
+static jclass point_class;
+static jfieldID point_fid;
+static jmethodID point_const_mid;
+static jclass rect_class;
+static jfieldID rect_x0_fid;
+static jfieldID rect_x1_fid;
+static jfieldID rect_y0_fid;
+static jfieldID rect_y1_fid;
+static jmethodID rect_const_mid;
+static jclass shade_class;
+static jfieldID shade_fid;
+static jmethodID shade_const_mid;
+static jclass stroke_class;
+static jfieldID stroke_fid;
+static jmethodID stroke_const_mid;
+static jclass text_class;
+static jfieldID text_fid;
+static jmethodID text_const_mid;
+static jclass trylaterexception_class;
+
+static pthread_key_t context_key;
+static fz_context *base_context;
+
+static void
+throwOutOfMemoryError(JNIEnv *env, const char *info)
+{
+ jclass oomCls = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
+
+ if (oomCls == NULL)
+ return; /* Well, what hope have we got! */
+
+ (*env)->ExceptionClear(env);
+ (*env)->ThrowNew(env, oomCls, info);
+}
+
+static const char *last_class_obtained = NULL;
+
+static jclass
+get_class(int *failed, JNIEnv *env, const char *str)
+{
+ jclass local, global;
+
+ if (*failed)
+ return NULL;
+
+ last_class_obtained = str;
+ local = (*env)->FindClass(env, str);
+ if (local == NULL)
+ {
+ LOGI("Failed to find class %s", str);
+ *failed = 1;
+ return NULL;
+ }
+
+ global = (*env)->NewGlobalRef(env, local);
+ if (global == NULL)
+ {
+ LOGI("Failed to make global ref for %s", str);
+ *failed = 1;
+ return NULL;
+ }
+
+ (*env)->DeleteLocalRef(env, local);
+
+ return global;
+}
+
+static jfieldID
+get_field(int *failed, JNIEnv *env, jclass cla, const char *field, const char *sig)
+{
+ jfieldID fid;
+
+ if (*failed || cla == NULL)
+ return NULL;
+
+ fid = (*env)->GetFieldID(env, cla, field, sig);
+ if (fid == (jfieldID)0)
+ {
+ LOGI("Failed to get field for %s %s %s", last_class_obtained ? last_class_obtained : "<noclass>", field, sig);
+ *failed = 1;
+ }
+
+ return fid;
+}
+
+static jmethodID
+get_method(int *failed, JNIEnv *env, jclass cla, const char *method, const char *sig)
+{
+ jmethodID mid;
+
+ if (*failed || cla == NULL)
+ return NULL;
+
+ mid = (*env)->GetMethodID(env, cla, method, sig);
+ if (mid == (jmethodID)0)
+ {
+ LOGI("Failed to get method for %s %s %s", last_class_obtained ? last_class_obtained : "<noclass>", method, sig);
+ *failed = 1;
+ }
+
+ return mid;
+}
+
+static int find_fids(JNIEnv *env)
+{
+ int failed = 0;
+
+ annot_class = get_class(&failed, env, PACKAGEPATH"Annotation");
+ annot_fid = get_field(&failed, env, annot_class, "nativeAnnot", "J");
+ annot_const_mid = get_method(&failed, env, annot_class, "<init>", "(J)V");
+ cdevice_class = get_class(&failed, env, PACKAGEPATH"CDevice");
+ cdevice_nativeresource_fid = get_field(&failed, env, cdevice_class, "nativeResource", "Ljava.lang.Object;");
+ cdevice_nativeinfo_fid = get_field(&failed, env, cdevice_class, "nativeInfo", "J");
+ colorspace_class = get_class(&failed, env, PACKAGEPATH"ColorSpace");
+ colorspace_fid = get_field(&failed, env, colorspace_class, "nativeColorSpace", "J");
+ colorspace_const_mid = get_method(&failed, env, colorspace_class, "<init>", "(J)V");
+ cookie_class = get_class(&failed, env, PACKAGEPATH"Cookie");
+ cookie_fid = get_field(&failed, env, cookie_class, "nativeCookie", "J");
+ device_class = get_class(&failed, env, PACKAGEPATH"Device");
+ device_fid = get_field(&failed, env, device_class, "nativeDevice", "J");
+ device_begin_page_mid = get_method(&failed, env, device_class, "beginPage", "(L"PACKAGEPATH"Rect;L"PACKAGEPATH"Matrix;)V");
+ device_end_page_mid = get_method(&failed, env, device_class, "endPage", "()V");
+ device_fill_path_mid = get_method(&failed, env, device_class, "fillPath", "(L"PACKAGEPATH"Path;IL"PACKAGEPATH"Matrix;L"PACKAGEPATH"ColorSpace;[FF)V");
+ device_stroke_path_mid = get_method(&failed, env, device_class, "strokePath", "(JL"PACKAGEPATH"Path;L"PACKAGEPATH"StrokeState;L"PACKAGEPATH"Matrix;L"PACKAGEPATH"ColorSpace;[FF)V");
+ device_clip_path_mid = get_method(&failed, env, device_class, "clipPath", "(L"PACKAGEPATH"Path;L"PACKAGEPATH"Rect;IL"PACKAGEPATH"Matrix;)V");
+ device_clip_stroke_path_mid = get_method(&failed, env, device_class, "clipStrokePath", "(L"PACKAGEPATH"Path;L"PACKAGEPATH"Rect;L"PACKAGEPATH"StrokeState;L"PACKAGEPATH"Matrix;)V");
+ device_fill_text_mid = get_method(&failed, env, device_class, "fillText", "(L"PACKAGEPATH"Text;L"PACKAGEPATH"Matrix;L"PACKAGEPATH"ColorSpace;[FF)V");
+ device_stroke_text_mid = get_method(&failed, env, device_class, "strokeText", "(L"PACKAGEPATH"Text;L"PACKAGEPATH"StrokeState;L"PACKAGEPATH"Matrix;L"PACKAGEPATH"ColorSpace;[FF)V");
+ device_clip_text_mid = get_method(&failed, env, device_class, "clipText", "(L"PACKAGEPATH"Text;L"PACKAGEPATH"Matrix;)V");
+ device_clip_stroke_text_mid = get_method(&failed, env, device_class, "clipStrokeText", "(L"PACKAGEPATH"Text;L"PACKAGEPATH"StrokeState;L"PACKAGEPATH"Matrix;)V");
+ device_ignore_text_mid = get_method(&failed, env, device_class, "ignoreText", "(L"PACKAGEPATH"Text;L"PACKAGEPATH"Matrix;)V");
+ device_fill_shade_mid = get_method(&failed, env, device_class, "fillShade", "(L"PACKAGEPATH"Shade;L"PACKAGEPATH"Matrix;F)V");
+ device_fill_image_mid = get_method(&failed, env, device_class, "fillImage", "(L"PACKAGEPATH"Image;L"PACKAGEPATH"Matrix;F)V");
+ device_fill_image_mask_mid = get_method(&failed, env, device_class, "fillImageMask", "(L"PACKAGEPATH"Image;L"PACKAGEPATH"Matrix;L"PACKAGEPATH"ColorSpace;[FF)V");
+ device_clip_image_mask_mid = get_method(&failed, env, device_class, "clipImageMask", "(L"PACKAGEPATH"Image;L"PACKAGEPATH"Rect;L"PACKAGEPATH"Matrix;)V");
+ device_pop_clip_mid = get_method(&failed, env, device_class, "popClip", "()V");
+ device_begin_mask_mid = get_method(&failed, env, device_class, "beginMask", "(L"PACKAGEPATH"Rect;IL"PACKAGEPATH"ColorSpace;[F)V");
+ device_end_mask_mid = get_method(&failed, env, device_class, "endMask", "()V");
+ device_begin_group_mid = get_method(&failed, env, device_class, "beginGroup", "(L"PACKAGEPATH"Rect;IIIF)V");
+ device_end_group_mid = get_method(&failed, env, device_class, "endGroup", "()V");
+ device_begin_tile_mid = get_method(&failed, env, device_class, "beginTile", "(L"PACKAGEPATH"Rect;L"PACKAGEPATH"Rect;FFL"PACKAGEPATH"Matrix;I)I");
+ device_end_tile_mid = get_method(&failed, env, device_class, "endTile", "()V");
+ exception_class = get_class(&failed, env, "java/lang/Exception");
+ displaylist_class = get_class(&failed, env, PACKAGEPATH"DisplayList");
+ displaylist_fid = get_field(&failed, env, displaylist_class, "nativeDisplayList", "J");
+ document_class = get_class(&failed, env, PACKAGEPATH"Document");
+ document_fid = get_field(&failed, env, document_class, "nativeDocument", "J");
+ font_class = get_class(&failed, env, PACKAGEPATH"Font");
+ font_fid = get_field(&failed, env, font_class, "nativeFont", "J");
+ //font_isconst_fid = get_field(&failed, env, font_class, "isConst", "Z");
+ image_class = get_class(&failed, env, PACKAGEPATH"Image");
+ image_fid = get_field(&failed, env, image_class, "nativeImage", "J");
+ image_const_mid = get_method(&failed, env, image_class, "<init>", "(J)V");
+ link_class = get_class(&failed, env, PACKAGEPATH"Link");
+ link_fid = get_field(&failed, env, link_class, "nativeLink", "J");
+ matrix_class = get_class(&failed, env, PACKAGEPATH"Matrix");
+ matrix_a_fid = get_field(&failed, env, matrix_class, "a", "F");
+ matrix_b_fid = get_field(&failed, env, matrix_class, "b", "F");
+ matrix_c_fid = get_field(&failed, env, matrix_class, "c", "F");
+ matrix_d_fid = get_field(&failed, env, matrix_class, "d", "F");
+ matrix_e_fid = get_field(&failed, env, matrix_class, "e", "F");
+ matrix_f_fid = get_field(&failed, env, matrix_class, "f", "F");
+ matrix_const_mid = get_method(&failed, env, matrix_class, "<init>", "(FFFFFF)V");
+ outline_class = get_class(&failed, env, PACKAGEPATH"Outline");
+ outline_fid = get_field(&failed, env, outline_class, "nativeOutline", "J");
+ outline_const_mid = get_method(&failed, env, outline_class, "<init>", "(J)V");
+ page_class = get_class(&failed, env, PACKAGEPATH"Page");
+ page_fid = get_field(&failed, env, page_class, "nativePage", "J");
+ page_const_mid = get_method(&failed, env, page_class, "<init>", "(J)V");
+ page_annots_fid = get_field(&failed, env, page_class, "nativeAnnots", "[L"PACKAGEPATH"Annotation;");
+ path_class = get_class(&failed, env, PACKAGEPATH"Path");
+ path_fid = get_field(&failed, env, path_class, "nativePath", "J");
+ path_const_mid = get_method(&failed, env, path_class, "<init>", "(J)V");
+ point_class = get_class(&failed, env, PACKAGEPATH"Point");
+ point_const_mid = get_method(&failed, env, point_class, "<init>", "(FF)V");
+ pathproc_class = get_class(&failed, env, PACKAGEPATH"PathProcessor");
+ pathproc_moveto_mid = get_method(&failed, env, pathproc_class, "moveTo", "(FF)V");
+ pathproc_lineto_mid = get_method(&failed, env, pathproc_class, "lineTo", "(FF)V");
+ pathproc_curveto_mid = get_method(&failed, env, pathproc_class, "curveTo", "(FFFFFF)V");
+ pathproc_close_mid = get_method(&failed, env, pathproc_class, "close", "()V");
+ rect_class = get_class(&failed, env, PACKAGEPATH"Rect");
+ rect_x0_fid = get_field(&failed, env, rect_class, "x0", "F");
+ rect_x1_fid = get_field(&failed, env, rect_class, "x1", "F");
+ rect_y0_fid = get_field(&failed, env, rect_class, "y0", "F");
+ rect_y1_fid = get_field(&failed, env, rect_class, "y1", "F");
+ rect_const_mid = get_method(&failed, env, rect_class, "<init>", "(FFFF)V");
+ shade_class = get_class(&failed, env, PACKAGEPATH"Shade");
+ shade_fid = get_field(&failed, env, shade_class, "nativeShade", "J");
+ shade_const_mid = get_method(&failed, env, shade_class, "<init>", "(J)V");
+ stroke_class = get_class(&failed, env, PACKAGEPATH"StrokeState");
+ stroke_fid = get_field(&failed, env, stroke_class, "nativeStroke", "J");
+ stroke_const_mid = get_method(&failed, env, stroke_class, "<init>", "(J)V");
+ text_class = get_class(&failed, env, PACKAGEPATH"Text");
+ text_fid = get_field(&failed, env, text_class, "nativeText", "J");
+ text_const_mid = get_method(&failed, env, text_class, "<init>", "(J)V");
+ trylaterexception_class = get_class(&failed, env, PACKAGEPATH"TryLaterException");
+
+ return failed;
+}
+
+static void lose_fids(JNIEnv *env)
+{
+ (*env)->DeleteGlobalRef(env, annot_class);
+ (*env)->DeleteGlobalRef(env, cdevice_class);
+ (*env)->DeleteGlobalRef(env, colorspace_class);
+ (*env)->DeleteGlobalRef(env, cookie_class);
+ (*env)->DeleteGlobalRef(env, device_class);
+ (*env)->DeleteGlobalRef(env, displaylist_class);
+ (*env)->DeleteGlobalRef(env, document_class);
+ (*env)->DeleteGlobalRef(env, exception_class);
+ (*env)->DeleteGlobalRef(env, font_class);
+ (*env)->DeleteGlobalRef(env, image_class);
+ (*env)->DeleteGlobalRef(env, link_class);
+ (*env)->DeleteGlobalRef(env, matrix_class);
+ (*env)->DeleteGlobalRef(env, outline_class);
+ (*env)->DeleteGlobalRef(env, page_class);
+ (*env)->DeleteGlobalRef(env, path_class);
+ (*env)->DeleteGlobalRef(env, pathproc_class);
+ (*env)->DeleteGlobalRef(env, rect_class);
+ (*env)->DeleteGlobalRef(env, shade_class);
+ (*env)->DeleteGlobalRef(env, stroke_class);
+ (*env)->DeleteGlobalRef(env, text_class);
+ (*env)->DeleteGlobalRef(env, trylaterexception_class);
+}
+
+static pthread_mutex_t mutexes[FZ_LOCK_MAX];
+
+static void lock(void *user, int lock)
+{
+ (void)pthread_mutex_lock(&mutexes[lock]);
+}
+
+static void unlock(void *user, int lock)
+{
+ (void)pthread_mutex_unlock(&mutexes[lock]);
+}
+
+static const fz_locks_context locks =
+{
+ NULL, /* user */
+ lock,
+ unlock
+};
+
+static void fin_context(void *ctx)
+{
+ fz_drop_context((fz_context *)ctx);
+}
+
+static int fin_base_context(JNIEnv *env)
+{
+ int i;
+
+ for (i = 0; i < FZ_LOCK_MAX; i++)
+ (void)pthread_mutex_destroy(&mutexes[i]);
+
+ fz_drop_context(base_context);
+ base_context = NULL;
+}
+
+static int init_base_context(JNIEnv *env)
+{
+ int i;
+
+ for (i = 0; i < FZ_LOCK_MAX; i++)
+ (void)pthread_mutex_init(&mutexes[i], NULL);
+
+ base_context = fz_new_context(NULL, &locks, FZ_STORE_DEFAULT);
+ if (base_context == NULL)
+ return -1;
+
+ fz_register_document_handlers(base_context);
+
+ return 0;
+}
+
+static fz_context *get_context(JNIEnv *env)
+{
+ fz_context *ctx = (fz_context *)pthread_getspecific(context_key);
+
+ if (ctx != NULL)
+ return ctx;
+
+ ctx = fz_clone_context(base_context);
+ if (ctx == NULL)
+ {
+ throwOutOfMemoryError(env, "Failed to clone fz_context");
+ return NULL;
+ }
+ pthread_setspecific(context_key, ctx);
+ return ctx;
+}
+
+jint JNI_OnLoad(JavaVM *vm, void *reserved)
+{
+ JNIEnv *env;
+
+ if ((*vm)->GetEnv(vm, (void **)&env, MY_JNI_VERSION) != JNI_OK)
+ return -1;
+
+ /* Must init the context before find_finds, because the act of
+ * finding the fids can cause classes to load. This causes
+ * statics to be setup, which can in turn call JNI code, which
+ * requires the context. (For example see ColorSpace) */
+ if (init_base_context(env) < 0)
+ return -1;
+
+ if (find_fids(env) != 0)
+ {
+ fin_base_context(env);
+ return -1;
+ }
+
+ return MY_JNI_VERSION;
+}
+
+void JNI_OnUnload(JavaVM *vm, void *reserved)
+{
+ JNIEnv *env;
+
+ if ((*vm)->GetEnv(vm, (void **)&env, MY_JNI_VERSION) != JNI_OK)
+ return; /* If this fails, we're really in trouble! */
+
+ fz_drop_context(base_context);
+ base_context = NULL;
+ lose_fids(env);
+}
+
+// Do our best to avoid casting warnings.
+#define CAST(type, var) (type)pointer_cast(var)
+
+static inline void *pointer_cast(jlong l)
+{
+ return (void *)(intptr_t)l;
+}
+
+static inline jlong jlong_cast(const void *p)
+{
+ return (jlong)(intptr_t)p;
+}
+
+/* Conversion functions: C to Java */
+static inline jobject Annotation_from_fz_annot(fz_context *ctx, JNIEnv *env, fz_annot *annot)
+{
+ jobject jannot;
+
+ if (ctx == NULL)
+ return NULL;
+
+ (*env)->NewObject(env, annot_class, annot_const_mid, annot);
+ if (jannot == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Annotation creation failed");
+
+ return jannot;
+}
+
+static inline jobject ColorSpace_from_fz_colorspace(fz_context *ctx, JNIEnv *env, fz_colorspace *cs)
+{
+ jobject jobj;
+
+ if (ctx == NULL)
+ return NULL;
+
+ jobj = (*env)->NewObject(env, colorspace_class, colorspace_const_mid, jlong_cast(cs));
+ if (jobj == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of ColorSpace failed");
+
+ fz_keep_colorspace(ctx, cs);
+
+ return jobj;
+}
+
+static inline jobject Image_from_fz_image(fz_context *ctx, JNIEnv *env, fz_image *img)
+{
+ jobject jobj;
+
+ if (ctx == NULL)
+ return NULL;
+
+ jobj = (*env)->NewObject(env, image_class, image_const_mid, jlong_cast(img));
+ if (jobj == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of Image failed");
+
+ fz_keep_image(ctx, img);
+
+ return jobj;
+}
+
+static inline jobject Matrix_from_fz_matrix(fz_context *ctx, JNIEnv *env, const fz_matrix *mat)
+{
+ jobject jobj;
+
+ if (ctx == NULL)
+ return NULL;
+
+ jobj = (*env)->NewObject(env, matrix_class, matrix_const_mid, mat->a, mat->b, mat->c, mat->d, mat->e, mat->f);
+ if (jobj == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of Matrix failed");
+
+ return jobj;
+}
+
+static inline jobject Outline_from_fz_outline(fz_context *ctx, JNIEnv *env, fz_outline *outline)
+{
+ jobject joutline;
+
+ if (ctx == NULL)
+ return NULL;
+
+ joutline = (*env)->NewObject(env, outline_class, outline_const_mid, jlong_cast(outline));
+ if (joutline == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "getOutline failed (3)");
+
+ return joutline;
+}
+
+static inline jobject Page_from_fz_page(fz_context *ctx, JNIEnv *env, fz_page *page)
+{
+ jobject jobj;
+
+ if (ctx == NULL)
+ return NULL;
+
+ jobj = (*env)->NewObject(env, page_class, page_const_mid, jlong_cast(page));
+ if (jobj == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of Page failed");
+
+ return jobj;
+}
+
+static inline jobject Path_from_fz_path(fz_context *ctx, JNIEnv *env, fz_path *path)
+{
+ jobject jobj;
+ fz_path *new_path;
+
+ if (ctx == NULL)
+ return NULL;
+
+ new_path = fz_clone_path(ctx, path);
+
+ jobj = (*env)->NewObject(env, path_class, path_const_mid, jlong_cast(new_path));
+ if (jobj == NULL)
+ {
+ fz_drop_path(ctx, new_path);
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of Path failed");
+ }
+
+ return jobj;
+}
+
+static inline jobject Point_from_fz_point(fz_context *ctx, JNIEnv *env, fz_point point)
+{
+ jobject jpoint;
+
+ if (ctx == NULL)
+ return NULL;
+
+ jpoint = (*env)->NewObject(env, point_class, point_const_mid, point.x, point.y);
+ if (jpoint == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "currentPoint failed (3)");
+
+ return jpoint;
+}
+
+static inline jobject Rect_from_fz_rect(fz_context *ctx, JNIEnv *env, const fz_rect *rect)
+{
+ jobject jobj;
+
+ if (ctx == NULL)
+ return NULL;
+
+ jobj = (*env)->NewObject(env, rect_class, rect_const_mid, rect->x0, rect->y0, rect->x1, rect->y1);
+ if (jobj == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of Rect failed");
+
+ return jobj;
+}
+
+static inline jobject Shade_from_fz_shade(fz_context *ctx, JNIEnv *env, fz_shade *shade)
+{
+ jobject jobj;
+
+ if (ctx == NULL)
+ return NULL;
+
+ jobj = (*env)->NewObject(env, shade_class, shade_const_mid, jlong_cast(shade));
+ if (jobj == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of Shade failed");
+
+ fz_keep_shade(ctx, shade);
+
+ return jobj;
+}
+
+static inline jobject StrokeState_from_fz_stroke_state(fz_context *ctx, JNIEnv *env, fz_stroke_state *state)
+{
+ jobject jobj;
+
+ if (ctx == NULL)
+ return NULL;
+
+ jobj = (*env)->NewObject(env, stroke_class, stroke_const_mid, jlong_cast(state));
+ if (jobj == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of StrokeState failed");
+
+ fz_keep_stroke_state(ctx, state);
+
+ return jobj;
+}
+
+static inline jobject Text_from_fz_text(fz_context *ctx, JNIEnv *env, fz_text *text)
+{
+ jobject jobj;
+ fz_text *new_text;
+
+ if (ctx == NULL)
+ return NULL;
+
+ new_text = fz_clone_text(ctx, text);
+
+ jobj = (*env)->NewObject(env, text_class, text_const_mid, jlong_cast(new_text));
+ if (jobj == NULL)
+ {
+ fz_drop_text(ctx, new_text);
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of Text failed");
+ }
+
+ return jobj;
+}
+
+static inline jfloatArray jfloatArray_from_fz_color(fz_context *ctx, JNIEnv *env, float *color, int n)
+{
+ jfloatArray arr;
+
+ if (ctx == NULL)
+ return NULL;
+
+ arr = (*env)->NewFloatArray(env, n);
+ if (arr == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of floatArray failed");
+
+ (*env)->SetFloatArrayRegion(env, arr, 0, n, color);
+
+ return arr;
+}
+
+/* Devices can either be implemented in C, or in Java.
+ *
+ * We therefore have to think about 4 possible call combinations.
+ *
+ * 1) C -> C: The standard mupdf case. No special worries here.
+ * 2) C -> Java: This can only happen when we call run on a page/annotation/
+ * displaylist. We need to ensure that the java Device has an
+ * appropriate fz_java_device generated for it. The 'run' calls
+ * take care to lock/unlock for us.
+ * 3) Java -> C: The C device will have a java shim (a subclass of CDevice).
+ * All calls will go through the device methods in CDevice,
+ * which converts the java objects to C ones, and lock/unlock
+ * any underlying objects as required.
+ * 4) Java -> Java: No special worries.
+ */
+
+/* Our java device wrapping functions */
+
+typedef struct
+{
+ fz_device base;
+ JNIEnv *env;
+ jobject self;
+}
+fz_java_device;
+
+static void
+fz_java_device_begin_page(fz_context *ctx, fz_device *dev, const fz_rect *rect, const fz_matrix *ctm)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jrect = Rect_from_fz_rect(ctx, env, rect);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_begin_page_mid, jrect, jctm);
+}
+
+static void
+fz_java_device_end_page(fz_context *ctx, fz_device *dev)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+
+ (*env)->CallVoidMethod(env, jdev->self, device_end_page_mid);
+}
+
+static void
+fz_java_device_fill_path(fz_context *ctx, fz_device *dev, fz_path *path, int even_odd, const fz_matrix *ctm, fz_colorspace *cs, float *color, float alpha)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jpath = Path_from_fz_path(ctx, env, path);
+ jobject jcs = ColorSpace_from_fz_colorspace(ctx, env, cs);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+ jfloatArray jcolor = jfloatArray_from_fz_color(ctx, env, color, cs ? cs->n : FZ_MAX_COLORS);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_fill_path_mid, jpath, even_odd, jctm, jcs, jcolor, alpha);
+}
+
+static void
+fz_java_device_stroke_path(fz_context *ctx, fz_device *dev, fz_path *path, fz_stroke_state *state, const fz_matrix *ctm, fz_colorspace *cs, float *color, float alpha)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jpath = Path_from_fz_path(ctx, env, path);
+ jobject jstate = StrokeState_from_fz_stroke_state(ctx, env, state);
+ jobject jcs = ColorSpace_from_fz_colorspace(ctx, env, cs);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+ jfloatArray jcolor = jfloatArray_from_fz_color(ctx, env, color, cs ? cs->n : FZ_MAX_COLORS);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_stroke_path_mid, jpath, jstate, jctm, jcs, jcolor, alpha);
+}
+
+static void
+fz_java_device_clip_path(fz_context *ctx, fz_device *dev, fz_path *path, const fz_rect *rect, int even_odd, const fz_matrix *ctm)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jpath = Path_from_fz_path(ctx, env, path);
+ jobject jrect = Rect_from_fz_rect(ctx, env, rect);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_clip_path_mid, jpath, jrect, even_odd, jctm);
+}
+
+static void
+fz_java_device_clip_stroke_path(fz_context *ctx, fz_device *dev, fz_path *path, const fz_rect *rect, fz_stroke_state *state, const fz_matrix *ctm)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jpath = Path_from_fz_path(ctx, env, path);
+ jobject jrect = Rect_from_fz_rect(ctx, env, rect);
+ jobject jstate = StrokeState_from_fz_stroke_state(ctx, env, state);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_clip_stroke_path_mid, jpath, jrect, jstate, jctm);
+}
+
+static void
+fz_java_device_fill_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm, fz_colorspace *cs, float *color, float alpha)
+{
+ LOGI("fz_java_device_fill_text");
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jtext = Text_from_fz_text(ctx, env, text);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+ jobject jcs = ColorSpace_from_fz_colorspace(ctx, env, cs);
+ jfloatArray jcolor = jfloatArray_from_fz_color(ctx, env, color, cs ? cs->n : FZ_MAX_COLORS);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_fill_text_mid, jtext, jctm, jcs, jcolor, alpha);
+}
+
+static void
+fz_java_device_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stroke_state *state, const fz_matrix *ctm, fz_colorspace *cs, float *color, float alpha)
+{
+ LOGI("fz_java_device_stroke_text");
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jtext = Text_from_fz_text(ctx, env, text);
+ jobject jstate = StrokeState_from_fz_stroke_state(ctx, env, state);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+ jobject jcs = ColorSpace_from_fz_colorspace(ctx, env, cs);
+ jfloatArray jcolor = jfloatArray_from_fz_color(ctx, env, color, cs ? cs->n : FZ_MAX_COLORS);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_stroke_text_mid, jtext, jstate, jctm, jcs, jcolor, alpha);
+}
+
+static void
+fz_java_device_clip_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm)
+{
+ LOGI("fz_java_device_clip_text");
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jtext = Text_from_fz_text(ctx, env, text);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_clip_text_mid, jtext, jctm);
+}
+
+static void
+fz_java_device_clip_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stroke_state *state, const fz_matrix *ctm)
+{
+ LOGI("fz_java_device_clip_stroke_text");
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jtext = Text_from_fz_text(ctx, env, text);
+ jobject jstate = StrokeState_from_fz_stroke_state(ctx, env, state);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_clip_stroke_text_mid, jtext, jstate, jctm);
+}
+
+static void
+fz_java_device_ignore_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm)
+{
+ LOGI("fz_java_device_ignore_text");
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jtext = Text_from_fz_text(ctx, env, text);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_ignore_text_mid, jtext, jctm);
+}
+
+static void
+fz_java_device_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shd, const fz_matrix *ctm, float alpha)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jshd = Shade_from_fz_shade(ctx, env, shd);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_fill_shade_mid, jshd, jctm, alpha);
+}
+
+static void
+fz_java_device_fill_image(fz_context *ctx, fz_device *dev, fz_image *img, const fz_matrix *ctm, float alpha)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jimg = Image_from_fz_image(ctx, env, img);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_fill_image_mid, jimg, jctm, alpha);
+}
+
+static void
+fz_java_device_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *img, const fz_matrix *ctm, fz_colorspace *cs, float *color, float alpha)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jimg = Image_from_fz_image(ctx, env, img);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+ jobject jcs = ColorSpace_from_fz_colorspace(ctx, env, cs);
+ jfloatArray jcolor = jfloatArray_from_fz_color(ctx, env, color, cs ? cs->n : FZ_MAX_COLORS);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_fill_image_mask_mid, jimg, jctm, jcs, jcolor, alpha);
+}
+
+static void
+fz_java_device_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *img, const fz_rect *rect, const fz_matrix *ctm)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jimg = Image_from_fz_image(ctx, env, img);
+ jobject jrect = Rect_from_fz_rect(ctx, env, rect);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_clip_image_mask_mid, jimg, jrect, jctm);
+}
+
+static void
+fz_java_device_pop_clip(fz_context *ctx, fz_device *dev)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+
+ (*env)->CallVoidMethod(env, jdev->self, device_pop_clip_mid);
+}
+
+static void
+fz_java_device_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *rect, int luminosity, fz_colorspace *cs, float *bc)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jrect = Rect_from_fz_rect(ctx, env, rect);
+ jobject jcs = ColorSpace_from_fz_colorspace(ctx, env, cs);
+ jfloatArray jbc = jfloatArray_from_fz_color(ctx, env, bc, cs ? cs->n : FZ_MAX_COLORS);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_begin_mask_mid, jrect, luminosity, jcs, jbc);
+}
+
+static void
+fz_java_device_end_mask(fz_context *ctx, fz_device *dev)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+
+ (*env)->CallVoidMethod(env, jdev->self, device_end_mask_mid);
+}
+
+static void
+fz_java_device_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *rect, int isolated, int knockout, int blendmode, float alpha)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jrect = Rect_from_fz_rect(ctx, env, rect);
+
+ (*env)->CallVoidMethod(env, jdev->self, device_begin_group_mid, jrect, isolated, knockout, blendmode, alpha);
+}
+
+static void
+fz_java_device_end_group(fz_context *ctx, fz_device *dev)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+
+ (*env)->CallVoidMethod(env, jdev->self, device_end_group_mid);
+}
+
+static int
+fz_java_device_begin_tile(fz_context *ctx, fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+ jobject jarea = Rect_from_fz_rect(ctx, env, area);
+ jobject jview = Rect_from_fz_rect(ctx, env, view);
+ jobject jctm = Matrix_from_fz_matrix(ctx, env, ctm);
+ int res;
+
+ res = (*env)->CallIntMethod(env, jdev->self, device_begin_tile_mid, jarea, jview, xstep, ystep, jctm, id);
+
+ return res;
+}
+
+static void
+fz_java_device_end_tile(fz_context *ctx, fz_device *dev)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+ JNIEnv *env = jdev->env;
+
+ (*env)->CallVoidMethod(env, jdev->self, device_end_tile_mid);
+}
+
+static void
+fz_java_device_drop_imp(fz_context *ctx, fz_device *dev)
+{
+ fz_java_device *jdev = (fz_java_device *)dev;
+
+ /* Nothing to do, currently */
+ jdev = jdev;
+}
+
+static fz_device *fz_new_java_device(JNIEnv *env, jobject self, fz_context *ctx)
+{
+ fz_device *dev = NULL;
+ fz_java_device *jdev = NULL;
+
+ fz_var(dev);
+ fz_var(jdev);
+
+ fz_try(ctx)
+ {
+ jdev = fz_new_device(ctx, sizeof(fz_java_device));
+ dev = &jdev->base;
+ jdev->env = env;
+ jdev->self = self;
+ dev->drop_imp = fz_java_device_drop_imp;
+
+ dev->fill_path = fz_java_device_fill_path;
+ dev->stroke_path = fz_java_device_stroke_path;
+ dev->clip_path = fz_java_device_clip_path;
+ dev->clip_stroke_path = fz_java_device_clip_stroke_path;
+
+ dev->fill_text = fz_java_device_fill_text;
+ dev->stroke_text = fz_java_device_stroke_text;
+ dev->clip_text = fz_java_device_clip_text;
+ dev->clip_stroke_text = fz_java_device_clip_stroke_text;
+
+ dev->fill_shade = fz_java_device_fill_shade;
+ dev->fill_image = fz_java_device_fill_image;
+ dev->fill_image_mask = fz_java_device_fill_image_mask;
+ dev->clip_image_mask = fz_java_device_clip_image_mask;
+
+ dev->pop_clip = fz_java_device_pop_clip;
+
+ dev->begin_mask = fz_java_device_begin_mask;
+ dev->end_mask = fz_java_device_end_mask;
+ dev->begin_group = fz_java_device_begin_group;
+ dev->end_group = fz_java_device_end_group;
+
+ dev->begin_tile = fz_java_device_begin_tile;
+ dev->end_tile = fz_java_device_end_tile;
+ }
+ fz_catch(ctx)
+ {
+ jclass exClass;
+
+ fz_free(ctx, jdev);
+ throwOutOfMemoryError(env, "Failed to create fz_java_device");
+ dev = NULL;
+ }
+ return dev;
+}
+
+/* Conversion functions: Java to C */
+static inline fz_colorspace *fz_colorspace_from_ColorSpace(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_colorspace *, (*env)->GetLongField(env, jobj, colorspace_fid));
+}
+
+
+static fz_device *fz_device_from_Device(JNIEnv *env, jobject self, fz_context *ctx)
+{
+ fz_device *dev = CAST(fz_device *, (*env)->GetLongField(env, self, device_fid));
+
+ if (dev == NULL)
+ {
+ /* This must be a Java device. Create a native shim. */
+ dev = fz_new_java_device(env, self, ctx);
+ (*env)->SetLongField(env, self, device_fid, jlong_cast(dev));
+ }
+ return dev;
+}
+
+static inline fz_image *fz_image_from_Image(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_image *, (*env)->GetLongField(env, jobj, image_fid));
+}
+
+static inline fz_matrix fz_matrix_from_Matrix(JNIEnv *env, jobject jmat)
+{
+ fz_matrix mat;
+
+ mat.a = (*env)->GetFloatField(env, jmat, matrix_a_fid);
+ mat.b = (*env)->GetFloatField(env, jmat, matrix_b_fid);
+ mat.c = (*env)->GetFloatField(env, jmat, matrix_c_fid);
+ mat.d = (*env)->GetFloatField(env, jmat, matrix_d_fid);
+ mat.e = (*env)->GetFloatField(env, jmat, matrix_e_fid);
+ mat.f = (*env)->GetFloatField(env, jmat, matrix_f_fid);
+
+ return mat;
+}
+
+static inline fz_path *fz_path_from_Path(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_path *, (*env)->GetLongField(env, jobj, path_fid));
+}
+
+static inline fz_rect fz_rect_from_Rect(JNIEnv *env, jobject jrect)
+{
+ fz_rect rect;
+
+ rect.x0 = (*env)->GetFloatField(env, jrect, rect_x0_fid);
+ rect.x1 = (*env)->GetFloatField(env, jrect, rect_x1_fid);
+ rect.y0 = (*env)->GetFloatField(env, jrect, rect_y0_fid);
+ rect.y1 = (*env)->GetFloatField(env, jrect, rect_y1_fid);
+
+ return rect;
+}
+
+static inline fz_shade *fz_shade_from_Shade(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_shade *, (*env)->GetLongField(env, jobj, shade_fid));
+}
+
+static inline fz_stroke_state *fz_stroke_state_from_StrokeState(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_stroke_state *, (*env)->GetLongField(env, jobj, stroke_fid));
+}
+
+static inline fz_text *fz_text_from_Text(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_text *, (*env)->GetLongField(env, jobj, text_fid));
+}
+
+static inline fz_font *fz_font_from_Font(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_font *, (*env)->GetLongField(env, jobj, font_fid));
+}
+
+static inline void fz_color_from_jfloatArray(JNIEnv *env, float *color, int n, jfloatArray jcolor)
+{
+ jsize len = (*env)->GetArrayLength(env, jcolor);
+ if (len > n)
+ len = n;
+ (*env)->GetFloatArrayRegion(env, jcolor, 0, len, color);
+ if (len < n)
+ memset(color+len, 0, (n-len)*sizeof(float));
+}
+
+static inline fz_cookie *fz_cookie_from_Cookie(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_cookie *, (*env)->GetLongField(env, jobj, cookie_fid));
+}
+
+static inline fz_display_list *fz_display_list_from_DisplayList(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_display_list *, (*env)->GetLongField(env, jobj, displaylist_fid));
+}
+
+static inline fz_page *fz_page_from_Page(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_page *, (*env)->GetLongField(env, jobj, page_fid));
+}
+
+static inline fz_document *fz_document_from_Document(JNIEnv *env, jobject jobj)
+{
+ jlong l;
+
+ l = (*env)->GetLongField(env, jobj, document_fid);
+ return CAST(fz_document *, l);
+}
+
+static inline fz_annot *fz_annot_from_Annotation(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_annot *, (*env)->GetLongField(env, jobj, annot_fid));
+}
+
+static inline fz_outline *fz_outline_from_Outline(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_outline *, (*env)->GetLongField(env, jobj, outline_fid));
+}
+
+static inline fz_link *fz_link_from_Link(JNIEnv *env, jobject jobj)
+{
+ return CAST(fz_link *, (*env)->GetLongField(env, jobj, link_fid));
+}
+
+/* Helper function for exception handling */
+
+static void jni_throw(JNIEnv *env, int type, const char *mess)
+{
+ const char *className;
+ int len;
+ jclass cla;
+
+ switch(type)
+ {
+ case FZ_ERROR_TRYLATER:
+ cla = trylaterexception_class;
+ break;
+ default:
+ case FZ_ERROR_GENERIC:
+ cla = exception_class;
+ break;
+ }
+
+ (void)(*env)->ThrowNew(env, cla, mess);
+}
+
+static void jni_rethrow(JNIEnv *env, fz_context *ctx)
+{
+ jni_throw(env, fz_caught(ctx), fz_caught_message(ctx));
+}
+
+/* ColorSpace Interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(ColorSpace_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_colorspace *cs = fz_colorspace_from_ColorSpace(env, self);
+
+ if (ctx == NULL || cs == NULL)
+ return;
+
+ fz_drop_colorspace(ctx, cs);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(ColorSpace_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(ColorSpace_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, colorspace_fid, 0);
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(ColorSpace_getNumComponents)(JNIEnv * env, jobject self)
+{
+ fz_colorspace *cs = fz_colorspace_from_ColorSpace(env, self);
+
+ if (cs == NULL)
+ return 0;
+
+ return cs->n;
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(ColorSpace_newDeviceRGB)(JNIEnv * env, jobject self, jlong size)
+{
+ fz_context *ctx = get_context(env);
+
+ return jlong_cast(fz_device_rgb(ctx));
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(ColorSpace_newDeviceGray)(JNIEnv * env, jobject self, jlong size)
+{
+ fz_context *ctx = get_context(env);
+
+ return jlong_cast(fz_device_gray(ctx));
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(ColorSpace_newDeviceCMYK)(JNIEnv * env, jobject self, jlong size)
+{
+ fz_context *ctx = get_context(env);
+
+ return jlong_cast(fz_device_cmyk(ctx));
+}
+
+/* Device Interface */
+
+typedef struct CDeviceNativeInfo CDeviceNativeInfo;
+
+typedef void (CDeviceLockFn)(JNIEnv *env, CDeviceNativeInfo *info);
+typedef void (CDeviceUnlockFn)(JNIEnv *env, CDeviceNativeInfo *info);
+
+struct CDeviceNativeInfo
+{
+ /* Some devices (like the AndroidDrawDevice, or AwtDrawDevice) need
+ * to lock/unlock the java object around device calls. We have functions
+ * here to do that. Other devices (like the DisplayList device) need
+ * no such locking, so these are NULL. */
+ CDeviceLockFn *lock; /* Function to lock */
+ CDeviceUnlockFn *unlock; /* Function to unlock */
+ jobject object; /* The java object that needs to be locked. */
+
+ /* Conceptually, we support drawing onto a 'plane' of pixels.
+ * The plane is width/height in size. The page is positioned on this
+ * at pageX0,pageY0 -> pageX1,PageY1. We want to redraw the given patch
+ * of this.
+ *
+ * The samples pointer in pixmap is updated on every lock/unlock, to
+ * cope with the object moving in memory.
+ */
+ fz_pixmap *pixmap;
+ int pageX0;
+ int pageY0;
+ int width;
+};
+
+static CDeviceNativeInfo *lockCDevice(JNIEnv *env, jobject self)
+{
+ CDeviceNativeInfo *info;
+
+ info = CAST(CDeviceNativeInfo *, (*env)->GetLongField(env, self, cdevice_nativeinfo_fid));
+ if (info == NULL)
+ {
+ /* Some devices (like the Displaylist device) need no locking,
+ * so have no info. */
+ return NULL;
+ }
+ info->object = (*env)->GetObjectField(env, self, cdevice_nativeresource_fid);
+
+ info->lock(env, info);
+
+ return info;
+}
+
+static void unlockCDevice(JNIEnv *env, CDeviceNativeInfo *info)
+{
+ if (info != NULL)
+ info->unlock(env, info);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Device_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ fz_drop_device(ctx, dev);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Device_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(Device_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, device_fid, 0);
+}
+
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_beginPage)(JNIEnv *env, jobject self, jobject jrect, jobject jctm)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_rect rect = fz_rect_from_Rect(env, jrect);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_begin_page(ctx, dev, &rect, &ctm);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_endPage)(JNIEnv *env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_end_page(ctx, dev);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_fillPath)(JNIEnv *env, jobject self, jobject jpath, int even_odd, jobject jctm, jobject jcs, jfloatArray jcolor, float alpha)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_path *path = fz_path_from_Path(env, jpath);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_colorspace *cs = fz_colorspace_from_ColorSpace(env, jcs);
+ float color[FZ_MAX_COLORS];
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_color_from_jfloatArray(env, color, cs ? cs->n : FZ_MAX_COLORS, jcolor);
+
+ fz_fill_path(ctx, dev, path, even_odd, &ctm, cs, color, alpha);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_strokePath)(JNIEnv *env, jobject self, jobject jpath, jobject jstroke, jobject jctm, jobject jcs, jfloatArray jcolor, float alpha)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_path *path = fz_path_from_Path(env, jpath);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_colorspace *cs = fz_colorspace_from_ColorSpace(env, jcs);
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, jstroke);
+ float color[FZ_MAX_COLORS];
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_color_from_jfloatArray(env, color, cs ? cs->n : FZ_MAX_COLORS, jcolor);
+
+ fz_stroke_path(ctx, dev, path, stroke, &ctm, cs, color, alpha);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_clipPath)(JNIEnv *env, jobject self, jobject jpath, jobject jrect, int even_odd, jobject jctm)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_path *path = fz_path_from_Path(env, jpath);
+ fz_rect rect = fz_rect_from_Rect(env, jrect);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_clip_path(ctx, dev, path, &rect, even_odd, &ctm);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_clipStrokePath)(JNIEnv *env, jobject self, jobject jpath, jobject jrect, jobject jstroke, jobject jctm)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_path *path = fz_path_from_Path(env, jpath);
+ fz_rect rect = fz_rect_from_Rect(env, jrect);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, jstroke);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_clip_stroke_path(ctx, dev, path, &rect, stroke, &ctm);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_fillText)(JNIEnv *env, jobject self, jobject jtext, jobject jctm, jobject jcs, jfloatArray jcolor, float alpha)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_text *text = fz_text_from_Text(env, jtext);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_colorspace *cs = fz_colorspace_from_ColorSpace(env, jcs);
+ float color[FZ_MAX_COLORS];
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_color_from_jfloatArray(env, color, cs ? cs->n : FZ_MAX_COLORS, jcolor);
+
+ fz_fill_text(ctx, dev, text, &ctm, cs, color, alpha);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_strokeText)(JNIEnv *env, jobject self, jobject jtext, jobject jstroke, jobject jctm, jobject jcs, jfloatArray jcolor, float alpha)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_text *text = fz_text_from_Text(env, jtext);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_colorspace *cs = fz_colorspace_from_ColorSpace(env, jcs);
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, jstroke);
+ float color[FZ_MAX_COLORS];
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_color_from_jfloatArray(env, color, cs ? cs->n : FZ_MAX_COLORS, jcolor);
+
+ fz_stroke_text(ctx, dev, text, stroke, &ctm, cs, color, alpha);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_clipText)(JNIEnv *env, jobject self, jobject jtext, jobject jctm)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_text *text = fz_text_from_Text(env, jtext);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_clip_text(ctx, dev, text, &ctm);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_clipStrokeText)(JNIEnv *env, jobject self, jobject jtext, jobject jstroke, jobject jctm)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_text *text = fz_text_from_Text(env, jtext);
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, jstroke);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_clip_stroke_text(ctx, dev, text, stroke, &ctm);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_ignoreText)(JNIEnv *env, jobject self, jobject jtext, jobject jctm)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_text *text = fz_text_from_Text(env, jtext);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_ignore_text(ctx, dev, text, &ctm);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_fillShade)(JNIEnv *env, jobject self, jobject jshade, jobject jctm, float alpha)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_shade *shade = fz_shade_from_Shade(env, jshade);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_fill_shade(ctx, dev, shade, &ctm, alpha);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_fillImage)(JNIEnv *env, jobject self, jobject jimg, jobject jctm, float alpha)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_image *image = fz_image_from_Image(env, jimg);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_fill_image(ctx, dev, image, &ctm, alpha);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_fillImageMask)(JNIEnv *env, jobject self, jobject jimg, jobject jctm, jobject jcs, jfloatArray jcolor, float alpha)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_image *image = fz_image_from_Image(env, jimg);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_colorspace *cs = fz_colorspace_from_ColorSpace(env, jcs);
+ float color[FZ_MAX_COLORS];
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_color_from_jfloatArray(env, color, cs ? cs->n : FZ_MAX_COLORS, jcolor);
+
+ fz_fill_image_mask(ctx, dev, image, &ctm, cs, color, alpha);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_clipImageMask)(JNIEnv *env, jobject self, jobject jimg, jobject jrect, jobject jctm)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_image *image = fz_image_from_Image(env, jimg);
+ fz_rect rect = fz_rect_from_Rect(env, jrect);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_clip_image_mask(ctx, dev, image, &rect, &ctm);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_popClip)(JNIEnv *env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_pop_clip(ctx, dev);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_beginMask)(JNIEnv *env, jobject self, jobject jrect, int luminosity, jobject jcs, jfloatArray jcolor)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_rect rect = fz_rect_from_Rect(env, jrect);
+ fz_colorspace *cs = fz_colorspace_from_ColorSpace(env, jcs);
+ float color[FZ_MAX_COLORS];
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_color_from_jfloatArray(env, color, cs ? cs->n : FZ_MAX_COLORS, jcolor);
+
+ fz_begin_mask(ctx, dev, &rect, luminosity, cs, color);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_endMask)(JNIEnv *env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_end_mask(ctx, dev);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_beginGroup)(JNIEnv *env, jobject self, jobject jrect, int isolated, int knockout, int blendmode, float alpha)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_rect rect = fz_rect_from_Rect(env, jrect);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_begin_group(ctx, dev, &rect, isolated, knockout, blendmode, alpha);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_endGroup)(JNIEnv *env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_end_group(ctx, dev);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(CDevice_beginTile)(JNIEnv *env, jobject self, jobject jarea, jobject jview, float xstep, float ystep, jobject jctm, int id)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_rect area = fz_rect_from_Rect(env, jarea);
+ fz_rect view = fz_rect_from_Rect(env, jview);
+ int i;
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ i = fz_begin_tile_id(ctx, dev, &area, &view, xstep, ystep, &ctm, id);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+
+ return i;
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_endTile)(JNIEnv *env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_device *dev = fz_device_from_Device(env, self, ctx);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || dev == NULL)
+ return;
+
+ info = lockCDevice(env, self);
+
+ fz_try(ctx)
+ {
+ fz_end_tile(ctx, dev);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+/* Draw Device interface */
+static jlong
+newCDevice(JNIEnv *env, jobject self, fz_context *ctx, jobject obj, jint width, jint height, CDeviceLockFn *lock, CDeviceUnlockFn *unlock, int pageX0, int pageY0, int pageX1, int pageY1, int patchX0, int patchY0, int patchX1, int patchY1)
+{
+ fz_device *device = NULL;
+ fz_pixmap *pixmap = NULL;
+ int ret;
+ unsigned char dummy;
+ CDeviceNativeInfo *ninfo = NULL;
+ fz_irect clip, pixbbox;
+
+ if (ctx == NULL)
+ return 0;
+
+ fz_var(pixmap);
+ fz_var(ninfo);
+
+ fz_try(ctx)
+ {
+ //LOGI("DrawDeviceNative: bitmap=%d,%d page=%d,%d->%d,%d patch=%d,%d->%d,%d", width, height, pageX0, pageY0, pageX1, pageY1, patchX0, patchY0, patchX1, patchY1);
+ /* Sanitise patch w.r.t page. */
+ if (patchX0 < pageX0)
+ patchX0 = pageX0;
+ if (patchY0 < pageY0)
+ patchY0 = pageY0;
+ if (patchX1 > pageX1)
+ patchX1 = pageX1;
+ if (patchY1 > pageY1)
+ patchY1 = pageY1;
+
+ clip.x0 = patchX0;
+ clip.y0 = patchY0;
+ clip.x1 = patchX1;
+ clip.y1 = patchY1;
+
+ /* Check for sanity. */
+ //LOGI("clip = %d,%d->%d,%d", clip.x0, clip.y0, clip.x1, clip.y1);
+ if (clip.x0 < 0 || clip.y0 < 0 || clip.x1 > width || clip.y1 > height)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "patch would draw out of bounds!");
+
+ clip.x0 -= pageX0;
+ clip.y0 -= pageY0;
+ clip.x1 -= pageX0;
+ clip.y1 -= pageY0;
+
+ /* pixmaps cannot handle right-edge padding, so the bbox must be expanded to
+ * match the pixels data */
+ pixbbox = clip;
+ pixbbox.x1 = pixbbox.x0 + width;
+ pixmap = fz_new_pixmap_with_bbox_and_data(ctx, fz_device_rgb(ctx), &pixbbox, &dummy);
+ ninfo = fz_malloc(ctx, sizeof(*ninfo));
+ ninfo->pixmap = pixmap;
+ ninfo->lock = lock;
+ ninfo->unlock = unlock;
+ ninfo->pageX0 = pageX0;
+ ninfo->pageY0 = pageY0;
+ ninfo->width = width;
+ ninfo->object = obj;
+ (*env)->SetLongField(env, self, cdevice_nativeinfo_fid, jlong_cast(ninfo));
+ (*env)->SetObjectField(env, self, cdevice_nativeresource_fid, obj);
+ lockCDevice(env,self);
+ fz_clear_pixmap_rect_with_value(ctx, pixmap, 0xff, &clip);
+ unlockCDevice(env,ninfo);
+ device = fz_new_draw_device_with_bbox(ctx, pixmap, &clip);
+ }
+ fz_catch(ctx)
+ {
+ fz_drop_pixmap(ctx, pixmap);
+ fz_free(ctx, ninfo);
+ jni_rethrow(env, ctx);
+ }
+ return jlong_cast(device);
+}
+
+static void androidDrawDevice_lock(JNIEnv *env, CDeviceNativeInfo *info)
+{
+ uint8_t *pixels;
+
+ assert(info != NULL);
+ assert(info->object != NULL);
+
+ if (AndroidBitmap_lockPixels(env, info->object, (void **)&pixels) < 0)
+ {
+ jni_throw(env, FZ_ERROR_GENERIC, "Bitmap lock failed in DrawDevice call");
+ return;
+ }
+
+ /* Now offset pixels to allow for the page offsets */
+ //pixels += sizeof(int32_t) * (info->pageX0 + info->width * info->pageY0);
+
+ info->pixmap->samples = pixels;
+}
+
+static void androidDrawDevice_unlock(JNIEnv *env, CDeviceNativeInfo *info)
+{
+ assert(info != NULL);
+ assert(info->object != NULL);
+
+ if (AndroidBitmap_unlockPixels(env, info->object) < 0)
+ {
+ jni_throw(env, FZ_ERROR_GENERIC, "Bitmap unlock failed in DrawDevice call");
+ }
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(AndroidDrawDevice_newNative)(JNIEnv *env, jobject self, jobject jbitmap, int pageX0, int pageY0, int pageX1, int pageY1, int patchX0, int patchY0, int patchX1, int patchY1)
+{
+ fz_context *ctx = get_context(env);
+ AndroidBitmapInfo info;
+ jlong device = 0;
+ int ret;
+
+ fz_try(ctx)
+ {
+ if ((ret = AndroidBitmap_getInfo(env, jbitmap, &info)) < 0)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "new DrawDevice failed to get bitmap info");
+
+ if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "new DrawDevice failed as bitmap format is not RGBA_8888");
+
+ if (info.stride != info.width*4)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "new DrawDevice failed as bitmap width != stride");
+
+ device = newCDevice(env, self, ctx, jbitmap, info.width, info.height, androidDrawDevice_lock, androidDrawDevice_unlock, pageX0, pageY0, pageX1, pageY1, patchX0, patchY0, patchX1, patchY1);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return device;
+}
+
+static void awtDrawDevice_lock(JNIEnv *env, CDeviceNativeInfo *info)
+{
+ int8_t *pixels;
+
+ assert(info != NULL);
+ assert(info->object != NULL);
+ assert(info->pixmap != NULL);
+
+ //pixels = (unsigned char *)((*env)->GetIntArrayElements(env, info->object, 0));
+
+ /* Now offset pixels to allow for the page offsets */
+ pixels += sizeof(int32_t) * (info->pageX0 + info->width * info->pageY0);
+
+ info->pixmap->samples = pixels;
+}
+
+static void awtDrawDevice_unlock(JNIEnv *env, CDeviceNativeInfo *info)
+{
+ int8_t *pixels = info->pixmap->samples;
+
+ assert(info != NULL);
+ assert(info->object != NULL);
+ assert(info->pixmap != NULL);
+
+ /* Now offset pixels to allow for the page offsets */
+ //pixels -= sizeof(int32_t) * (info->pageX0 + info->width * info->pageY0);
+
+ (*env)->ReleaseIntArrayElements(env, info->object, (int *)(void *)pixels, 0);
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(AwtDrawDevice_newNative)(JNIEnv *env, jobject self, jobject rgba, jint w, jint h, int pageX0, int pageY0, int pageX1, int pageY1, int patchX0, int patchY0, int patchX1, int patchY1)
+{
+ fz_context *ctx = get_context(env);
+
+ return newCDevice(env, self, ctx, rgba, w, h, awtDrawDevice_lock, awtDrawDevice_unlock, pageX0, pageY0, pageX1, pageY1, patchX0, patchY0, patchX1, patchY1);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_finalize)(JNIEnv *env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ CDeviceNativeInfo *ninfo;
+
+ ninfo = CAST(CDeviceNativeInfo *, (*env)->GetLongField(env, self, cdevice_nativeinfo_fid));
+ if (ninfo != NULL)
+ {
+ fz_drop_pixmap(ctx, ninfo->pixmap);
+ fz_free(ctx, ninfo);
+ }
+ (*env)->SetLongField(env, self, cdevice_nativeinfo_fid, 0);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(CDevice_destroy)(JNIEnv *env, jobject self)
+{
+ JNI_FN(CDevice_finalize)(env, self);
+ JNI_FN(Device_finalize)(env, self); /* Super class destroy */
+}
+
+/* Path Interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(Path_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+
+ if (ctx == NULL || path == NULL)
+ return;
+
+ fz_drop_path(ctx, path);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Path_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(Path_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, path_fid, 0);
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(Path_newNative)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = NULL;
+
+ if (ctx == NULL)
+ return 0;
+
+ fz_try(ctx)
+ {
+ path = fz_new_path(ctx);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jlong_cast(path);
+}
+
+JNIEXPORT jobject JNICALL
+JNI_FN(Path_currentPoint)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+ fz_point point;
+ jmethodID cons;
+ jobject jpoint;
+
+ if (ctx == NULL || path == NULL)
+ return NULL;
+
+ fz_try(ctx)
+ {
+ point = fz_currentpoint(ctx, path);
+ jpoint = Point_from_fz_point(ctx, env, point);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jpoint;
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Path_moveTo)(JNIEnv * env, jobject self, float x, float y)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+
+ if (ctx == NULL || path == NULL)
+ return;
+
+ fz_try(ctx)
+ {
+ fz_moveto(ctx, path, x, y);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Path_lineTo)(JNIEnv * env, jobject self, float x, float y)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+
+ if (ctx == NULL || path == NULL)
+ return;
+
+ fz_try(ctx)
+ {
+ fz_lineto(ctx, path, x, y);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Path_curveTo)(JNIEnv * env, jobject self, float cx1, float cy1, float cx2, float cy2, float ex, float ey)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+
+ if (ctx == NULL || path == NULL)
+ return;
+
+ fz_try(ctx)
+ {
+ fz_curveto(ctx, path, cx1, cy1, cx2, cy2, ex, ey);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Path_curveToV)(JNIEnv * env, jobject self, float cx, float cy, float ex, float ey)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+
+ if (ctx == NULL || path == NULL)
+ return;
+
+ fz_try(ctx)
+ {
+ fz_curvetov(ctx, path, cx, cy, ex, ey);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Path_curveToY)(JNIEnv * env, jobject self, float cx, float cy, float ex, float ey)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+
+ if (ctx == NULL || path == NULL)
+ return;
+
+ fz_try(ctx)
+ {
+ fz_curvetoy(ctx, path, cx, cy, ex, ey);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Path_close)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+
+ if (ctx == NULL || path == NULL)
+ return;
+
+ fz_try(ctx)
+ {
+ fz_closepath(ctx, path);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Path_transform)(JNIEnv * env, jobject self, jobject jctm)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+
+ if (ctx == NULL || path == NULL)
+ return;
+
+ fz_try(ctx)
+ {
+ fz_transform_path(ctx, path, &ctm);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(Path_clone)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+ fz_path *path2 = NULL;
+
+ if (ctx == NULL || path == NULL)
+ return 0;
+
+ fz_try(ctx)
+ {
+ path2 = fz_clone_path(ctx, path);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jlong_cast(path2);
+}
+
+JNIEXPORT jobject JNICALL
+JNI_FN(Path_bound)(JNIEnv * env, jobject self, jobject jstroke, jobject jctm)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+ jobject jrect;
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, jstroke);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_rect rect;
+
+ if (ctx == NULL || path == NULL)
+ return NULL;
+
+ fz_try(ctx)
+ {
+ fz_bound_path(ctx, path, stroke, &ctm, &rect);
+
+ jrect = Rect_from_fz_rect(ctx, env, &rect);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jrect;
+}
+
+typedef struct {
+ JNIEnv *env;
+ jobject jproc;
+} pproc_data;
+
+static void
+pathProcMoveTo(fz_context *ctx, void *arg, float x, float y)
+{
+ pproc_data *pproc = (pproc_data *)arg;
+
+ (*pproc->env)->CallVoidMethod(pproc->env, pproc->jproc, pathproc_moveto_mid, x, y);
+}
+
+static void
+pathProcLineTo(fz_context *ctx, void *arg, float x, float y)
+{
+ pproc_data *pproc = (pproc_data *)arg;
+
+ (*pproc->env)->CallVoidMethod(pproc->env, pproc->jproc, pathproc_lineto_mid, x, y);
+}
+
+static void
+pathProcCurveTo(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ pproc_data *pproc = (pproc_data *)arg;
+
+ (*pproc->env)->CallVoidMethod(pproc->env, pproc->jproc, pathproc_curveto_mid, x1, y1, x2, y2, x3, y3);
+}
+
+static void
+pathProcClose(fz_context *ctx, void *arg)
+{
+ pproc_data *pproc = (pproc_data *) arg;
+
+ (*pproc->env)->CallVoidMethod(pproc->env, pproc->jproc, pathproc_close_mid);
+}
+
+static const fz_path_processor path_proc =
+{
+ pathProcMoveTo,
+ pathProcLineTo,
+ pathProcCurveTo,
+ pathProcClose
+};
+
+void JNICALL
+JNI_FN(Path_process)(JNIEnv * env, jobject self, jobject jproc)
+{
+ fz_context *ctx = get_context(env);
+ fz_path *path = fz_path_from_Path(env, self);
+ int i = 0, k = 0;
+ int n;
+ pproc_data data;
+
+ if (path == NULL || jproc == NULL)
+ return;
+
+ data.env = env;
+ data.jproc = jproc;
+
+ fz_process_path(ctx, &path_proc, &data, path);
+}
+
+
+/* StrokeState interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(StrokeState_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, self);
+
+ if (ctx == NULL || stroke == NULL)
+ return;
+
+ fz_drop_stroke_state(ctx, stroke);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(StrokeState_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(StrokeState_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, stroke_fid, 0);
+}
+
+
+JNIEXPORT jlong JNICALL
+JNI_FN(Path_newStrokeState)(JNIEnv * env, jobject self, int startCap, int dashCap, int endCap, int lineJoin, float lineWidth, float miterLimit, float dashPhase, jfloatArray dash)
+{
+ fz_context *ctx = get_context(env);
+ fz_stroke_state *stroke = NULL;
+ jsize len = (*env)->GetArrayLength(env, dash);
+
+ if (ctx == NULL)
+ return 0;
+
+ fz_var(stroke);
+
+ fz_try(ctx)
+ {
+ stroke = fz_new_stroke_state_with_dash_len(ctx, len);
+ stroke->start_cap = startCap;
+ stroke->dash_cap = dashCap;
+ stroke->end_cap = endCap;
+ stroke->linejoin = lineJoin;
+ stroke->linewidth = lineWidth;
+ stroke->miterlimit = miterLimit;
+ stroke->dash_phase = dashPhase;
+ stroke->dash_len = len;
+ (*env)->GetFloatArrayRegion(env, dash, 0, len, &stroke->dash_list[0]);
+ }
+ fz_catch(ctx)
+ {
+ fz_drop_stroke_state(ctx, stroke);
+ jni_rethrow(env, ctx);
+ }
+ return jlong_cast(stroke);
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(StrokeState_getStartCap)(JNIEnv * env, jobject self)
+{
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, self);
+
+ return stroke ? stroke->start_cap : 0;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(StrokeState_getDashCap)(JNIEnv * env, jobject self)
+{
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, self);
+
+ return stroke ? stroke->dash_cap : 0;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(StrokeState_getEndCap)(JNIEnv * env, jobject self)
+{
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, self);
+
+ return stroke ? stroke->end_cap : 0;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(StrokeState_getLineJoin)(JNIEnv * env, jobject self)
+{
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, self);
+
+ return stroke ? stroke->linejoin : 0;
+}
+
+JNIEXPORT float JNICALL
+JNI_FN(StrokeState_getLineWidth)(JNIEnv * env, jobject self)
+{
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, self);
+
+ return stroke ? stroke->linewidth : 0;
+}
+
+JNIEXPORT float JNICALL
+JNI_FN(StrokeState_getMiterLimit)(JNIEnv * env, jobject self)
+{
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, self);
+
+ return stroke ? stroke->miterlimit : 0;
+}
+
+JNIEXPORT float JNICALL
+JNI_FN(StrokeState_getDashPhase)(JNIEnv * env, jobject self)
+{
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, self);
+
+ return stroke ? stroke->dash_phase : 0;
+}
+
+JNIEXPORT jfloatArray JNICALL
+JNI_FN(StrokeState_getDashes)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, self);
+ jfloatArray arr;
+
+ if (stroke->dash_len == 0)
+ return NULL;
+
+ arr = (*env)->NewFloatArray(env, stroke->dash_len);
+ if (arr == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of floatArray failed");
+
+ (*env)->SetFloatArrayRegion(env, arr, 0, stroke->dash_len, &stroke->dash_list[0]);
+
+ return arr;
+}
+
+/* Text interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(Text_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_text *text = fz_text_from_Text(env, self);
+
+ if (ctx == NULL || text == NULL)
+ return;
+
+ fz_drop_text(ctx, text);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Text_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(Text_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, text_fid, 0);
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(Text_clone)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_text *text = fz_text_from_Text(env, self);
+ fz_text *text2 = NULL;
+
+ if (ctx == NULL || text == NULL)
+ return 0;
+
+ fz_try(ctx)
+ {
+ text2 = fz_clone_text(ctx, text);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jlong_cast(text2);
+}
+
+//JNIEXPORT jlong JNICALL
+//JNI_FN(Text_newText)(JNIEnv * env, jobject self, jobject jfont, jobject jctm, int wmode)
+//{
+// fz_context *ctx = get_context(env);
+// fz_text *text = NULL;
+// fz_font *font = fz_font_from_Font(env, jfont);
+// fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+//
+// if (ctx == NULL)
+// return 0;
+//
+// fz_try(ctx)
+// {
+// text = fz_new_text(ctx, font, &ctm, wmode);
+// }
+// fz_catch(ctx)
+// {
+// jni_rethrow(env, ctx);
+// }
+// return jlong_cast(text);
+//}
+
+JNIEXPORT jobject JNICALL
+JNI_FN(Text_bound)(JNIEnv * env, jobject self, jobject jstroke, jobject jctm)
+{
+ fz_context *ctx = get_context(env);
+ fz_text *text = fz_text_from_Text(env, self);
+ fz_stroke_state *stroke = fz_stroke_state_from_StrokeState(env, jstroke);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ jobject jrect;
+ fz_rect rect;
+
+ if (ctx == NULL || text == NULL)
+ return NULL;
+
+ fz_try(ctx)
+ {
+ fz_bound_text(ctx, text, stroke, &ctm, &rect);
+
+ jrect = Rect_from_fz_rect(ctx, env, &rect);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jrect;
+}
+
+//JNIEXPORT void JNICALL
+//JNI_FN(Text_add)(JNIEnv * env, jobject self, int gid, int ucs, float x, float y)
+//{
+// fz_context *ctx = get_context(env);
+// fz_text *text = fz_text_from_Text(env, self);
+//
+// if (ctx == NULL || text == NULL)
+// return;
+//
+// fz_try(ctx)
+// {
+// fz_add_text(ctx, text, gid, ucs, x, y);
+// }
+// fz_catch(ctx)
+// {
+// jni_rethrow(env, ctx);
+// }
+//}
+
+/* Image interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(Image_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_image *image = fz_image_from_Image(env, self);
+
+ if (ctx == NULL || image == NULL)
+ return;
+
+ fz_drop_image(ctx, image);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Image_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(Image_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, image_fid, 0);
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(Image_newImageFromBitmap)(JNIEnv * env, jobject self, jobject jbitmap, jlong jmask)
+{
+ fz_context *ctx = get_context(env);
+ fz_image *mask = CAST(fz_image *, jmask);
+ fz_image *image = NULL;
+ fz_pixmap *pixmap = NULL;
+ AndroidBitmapInfo info;
+ void *pixels;
+ int ret;
+
+ if (ctx == NULL)
+ return 0;
+
+ fz_var(pixmap);
+
+ fz_try(ctx)
+ {
+ if (mask && mask->mask)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "new Image failed as mask cannot be masked");
+
+ if ((ret = AndroidBitmap_getInfo(env, jbitmap, &info)) < 0)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "new Image failed to get bitmap info");
+
+ if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "new Image failed as bitmap format is not RGBA_8888");
+
+ if (info.stride != info.width)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "new Image failed as bitmap width != stride");
+
+ pixmap = fz_new_pixmap(ctx, fz_device_rgb(ctx), info.width, info.height);
+ if (AndroidBitmap_lockPixels(env, jbitmap, &pixels) < 0)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Bitmap lock failed in new Image");
+ memcpy(pixmap->samples, pixels, info.width * info.height * 4);
+ (void)AndroidBitmap_unlockPixels(env, jbitmap);
+
+ image = fz_new_image_from_pixmap(ctx, fz_keep_pixmap(ctx, pixmap), fz_keep_image(ctx, mask));
+ }
+ fz_always(ctx)
+ {
+ fz_drop_pixmap(ctx, pixmap);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jlong_cast(image);
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Image_getWidth)(JNIEnv * env, jobject self)
+{
+ fz_image *image = fz_image_from_Image(env, self);
+
+ return image ? image->w : 0;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Image_getHeight)(JNIEnv * env, jobject self)
+{
+ fz_image *image = fz_image_from_Image(env, self);
+
+ return image ? image->h : 0;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Image_getNumComponents)(JNIEnv * env, jobject self)
+{
+ fz_image *image = fz_image_from_Image(env, self);
+
+ return image ? image->n : 0;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Image_getBitsPerComponent)(JNIEnv * env, jobject self)
+{
+ fz_image *image = fz_image_from_Image(env, self);
+
+ return image ? image->bpc : 0;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Image_getXResolution)(JNIEnv * env, jobject self)
+{
+ fz_image *image = fz_image_from_Image(env, self);
+
+ return image ? image->xres : 0;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Image_getYResolution)(JNIEnv * env, jobject self)
+{
+ fz_image *image = fz_image_from_Image(env, self);
+
+ return image ? image->yres : 0;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Image_getImageMask)(JNIEnv * env, jobject self)
+{
+ fz_image *image = fz_image_from_Image(env, self);
+
+ return image ? image->imagemask : 0;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Image_getInterpolate)(JNIEnv * env, jobject self)
+{
+ fz_image *image = fz_image_from_Image(env, self);
+
+ return image ? image->interpolate : 0;
+}
+
+JNIEXPORT jobject JNICALL
+JNI_FN(Image_getMask)(JNIEnv *env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_image *img = fz_image_from_Image(env, self);
+ jobject jobj;
+
+ if (img == NULL || img->mask == NULL)
+ return NULL;
+
+ jobj = Image_from_fz_image(ctx, env, img->mask);
+ if (jobj != NULL)
+ fz_keep_image(ctx, img->mask);
+
+ return jobj;
+
+died:
+ fz_throw(ctx, FZ_ERROR_GENERIC, "JNI creation of Image(Mask) failed");
+ return NULL;
+}
+
+/* Outline interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(Outline_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_outline *outline = fz_outline_from_Outline(env, self);
+
+ if (ctx == NULL || outline == NULL)
+ return;
+
+ fz_drop_outline(ctx, outline);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Outline_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(Outline_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, outline_fid, 0);
+}
+
+/* Annotation Interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(Annotation_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_annot *annot = fz_annot_from_Annotation(env, self);
+
+ if (ctx == NULL || link == NULL)
+ return;
+
+ fz_drop_annot(ctx, annot);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Annotation_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(Annotation_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, annot_fid, 0);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Annotation_run)(JNIEnv * env, jobject self, jobject jdev, jobject jctm, jobject jcookie)
+{
+ fz_context *ctx = get_context(env);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_cookie *cookie= fz_cookie_from_Cookie(env, jcookie);
+ fz_device *dev = fz_device_from_Device(env, jdev, ctx);
+ jobject jdoc;
+ fz_annot *annot = fz_annot_from_Annotation(env, self);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || self == NULL || jdev == NULL)
+ return;
+
+ fz_var(dev);
+
+ info = lockCDevice(env, jdev);
+
+ fz_try(ctx)
+ {
+ fz_run_annot(ctx, annot, dev, &ctm, cookie);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(Annotation_advance)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_annot *annot;
+
+ if (ctx == NULL)
+ return;
+
+ fz_try(ctx)
+ {
+ annot = fz_annot_from_Annotation(env, self);
+
+ annot = fz_next_annot(ctx, annot);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jlong_cast(annot);
+}
+
+/* Link interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(Link_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_link *link = fz_link_from_Link(env, self);
+
+ if (ctx == NULL || link == NULL)
+ return;
+
+ fz_drop_link(ctx, link);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Link_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(Link_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, link_fid, 0);
+}
+
+/* Document interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(Document_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *doc = fz_document_from_Document(env, self);
+
+ if (ctx == NULL || doc == NULL)
+ return;
+
+ fz_drop_document(ctx, doc);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Document_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(Document_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, document_fid, 0);
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(Document_newNative)(JNIEnv * env, jobject self, jstring jfilename)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *document = NULL;
+ const char *filename = NULL;
+
+ if (ctx == NULL || jfilename == NULL)
+ return 0;
+
+ fz_var(filename);
+
+ fz_try(ctx)
+ {
+ filename = (*env)->GetStringUTFChars(env, jfilename, NULL);
+ if (filename == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to convert filename");
+ document = fz_open_document(ctx, filename);
+ }
+ fz_always(ctx)
+ {
+ (*env)->ReleaseStringUTFChars(env, jfilename, filename);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+
+ return jlong_cast(document);
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Document_needsPassword)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *document = fz_document_from_Document(env, self);
+ int ret;
+
+ if (ctx == NULL || document == NULL)
+ return 0;
+
+ fz_try(ctx)
+ {
+ ret = fz_needs_password(ctx, document);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ ret = 0;
+ }
+ return ret;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Document_authenticatePassword)(JNIEnv * env, jobject self, jstring jpassword)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *document = fz_document_from_Document(env, self);
+ int ret;
+ const char *password = NULL;
+
+ if (ctx == NULL || document == NULL)
+ return 0;
+
+ fz_var(password);
+
+ fz_try(ctx)
+ {
+ if (jpassword == NULL)
+ password = "";
+ else
+ {
+ password = (*env)->GetStringUTFChars(env, jpassword, NULL);
+ if (password == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to convert password");
+ }
+
+ ret = fz_authenticate_password(ctx, document, password);
+ }
+ fz_always(ctx)
+ {
+ if (jpassword != NULL)
+ (*env)->ReleaseStringUTFChars(env, jpassword, password);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ ret = 0;
+ }
+ return ret;
+}
+
+JNIEXPORT int JNICALL
+JNI_FN(Document_countPages)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *document = fz_document_from_Document(env, self);
+ int ret;
+
+ if (ctx == NULL || document == NULL)
+ return 0;
+
+ fz_try(ctx)
+ {
+ ret = fz_count_pages(ctx, document);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ ret = 0;
+ }
+ return ret;
+}
+
+JNIEXPORT jobject JNICALL
+JNI_FN(Document_getPage)(JNIEnv * env, jobject self, int n)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *document = fz_document_from_Document(env, self);
+ fz_page *page = NULL;
+ jobject jpage;
+
+ if (ctx == NULL || document == NULL)
+ return NULL;
+
+ fz_var(page);
+
+ fz_try(ctx)
+ {
+ page = fz_load_page(ctx, document, n);
+ if (page == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "getPage failed");
+
+ jpage = Page_from_fz_page(ctx, env, page);
+ }
+ fz_catch(ctx)
+ {
+ fz_drop_page(ctx, page);
+ jni_rethrow(env, ctx);
+ jpage = NULL;
+ }
+ return jpage;
+}
+
+JNIEXPORT jobject JNICALL
+JNI_FN(Document_getFileFormat)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *document = fz_document_from_Document(env, self);
+ char info[64];
+
+ if (ctx == NULL || document == NULL)
+ return NULL;
+
+ fz_lookup_metadata(ctx, document, FZ_META_FORMAT, info, sizeof(info));
+
+ return (*env)->NewStringUTF(env, info);
+}
+
+JNIEXPORT jboolean JNICALL
+JNI_FN(Document_isUnencryptedPDF)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *document = fz_document_from_Document(env, self);
+ pdf_document *idoc = pdf_specifics(ctx, document);
+ int cryptVer;
+
+ if (idoc == NULL)
+ return JNI_FALSE; // Not a PDF
+
+ cryptVer = pdf_crypt_version(ctx, idoc);
+ return (cryptVer == 0) ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jobject JNICALL
+JNI_FN(Document_getOutline)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_document *document = fz_document_from_Document(env, self);
+ fz_outline *outline = NULL;
+ jobject joutline;
+
+ if (ctx == NULL || document == NULL)
+ return NULL;
+
+ fz_var(outline);
+
+ fz_try(ctx)
+ {
+ outline = fz_load_outline(ctx, document);
+ if (outline == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "getOutline failed");
+
+ joutline = Outline_from_fz_outline(ctx, env, outline);
+ }
+ fz_catch(ctx)
+ {
+ fz_drop_outline(ctx, outline);
+ jni_rethrow(env, ctx);
+ joutline = NULL;
+ }
+ return joutline;
+}
+
+/* Page interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(Page_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_page *page = fz_page_from_Page(env, self);
+
+ if (ctx == NULL || page == NULL)
+ return;
+
+ fz_drop_page(ctx, page);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Page_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(Page_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, page_fid, 0);
+ (*env)->SetLongField(env, self, page_annots_fid, 0);
+}
+
+JNIEXPORT jobject JNICALL
+JNI_FN(Page_bound)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_page *page = fz_page_from_Page(env, self);
+ jobject jrect;
+ fz_rect rect;
+
+ if (ctx == NULL || page == NULL)
+ return NULL;
+
+ fz_try(ctx)
+ {
+ fz_bound_page(ctx, page, &rect);
+
+ jrect = Rect_from_fz_rect(ctx, env, &rect);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jrect;
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Page_run)(JNIEnv * env, jobject self, jobject jdev, jobject jctm, jobject jcookie)
+{
+ fz_context *ctx = get_context(env);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_cookie *cookie = fz_cookie_from_Cookie(env, jcookie);
+ fz_device *dev = fz_device_from_Device(env, jdev, ctx);
+ fz_page *page = fz_page_from_Page(env, self);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL || self == NULL || jdev == NULL)
+ return;
+
+ info = lockCDevice(env, jdev);
+
+ fz_try(ctx)
+ {
+ fz_run_page(ctx, page, dev, &ctm, cookie);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Page_runPageContents)(JNIEnv * env, jobject self, jobject jdev, jobject jctm, jobject jcookie)
+{
+ fz_context *ctx = get_context(env);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_cookie *cookie = fz_cookie_from_Cookie(env, jcookie);
+ fz_device *dev = fz_device_from_Device(env, jdev, ctx);
+ fz_page *page = fz_page_from_Page(env, self);
+ CDeviceNativeInfo *info;
+
+ if (ctx == NULL)
+ return;
+
+ info = lockCDevice(env, jdev);
+
+ fz_try(ctx)
+ {
+ fz_run_page_contents(ctx, page, dev, &ctm, cookie);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT jobject JNICALL
+JNI_FN(Page_getAnnotations)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_page *page = fz_page_from_Page(env, self);
+ jobject jrect;
+ fz_rect rect;
+ fz_annot *annot = NULL;
+ fz_annot *first = NULL;
+ jobject jannots = NULL;
+ int ret;
+ int annot_count;
+ int i;
+
+ if (ctx == NULL || page == NULL)
+ return NULL;
+
+ fz_var(annot);
+ fz_var(jannots);
+
+ fz_try(ctx)
+ {
+ jannots = (*env)->GetObjectField(env, self, page_annots_fid);
+
+ first = fz_first_annot(ctx, page);
+
+ /* Count the annotations */
+ annot = first;
+ for (annot_count = 0; annot != NULL; annot_count++)
+ annot = fz_next_annot(ctx, annot);
+
+ if (annot_count == 0)
+ {
+ /* If no annotations, we don't want an annotation
+ * object stored in the page. */
+ if (jannots != NULL)
+ {
+ (*env)->SetObjectField(env, self, page_annots_fid, NULL);
+ }
+ break; /* No annotations! */
+ }
+
+ jannots = (*env)->NewObjectArray(env, annot_count, annot_class, NULL);
+ if (jannots == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "getAnnotations failed (1)");
+ (*env)->SetObjectField(env, self, page_annots_fid, jannots);
+
+ /* Now run through actually creating the annotation objects */
+ annot = first;
+ for (i = 0; annot != NULL && i < annot_count; i++)
+ {
+ jobject jannot = Annotation_from_fz_annot(ctx, env, annot);
+ (*env)->SetObjectArrayElement(env, jannots, i, jannot);
+ annot = fz_next_annot(ctx, annot);
+ }
+ if (annot != NULL || i != annot_count)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "getAnnotations failed (4)");
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jannots;
+}
+
+/* private native final Link[] getLinks(jlong ctx); */
+
+
+/* Cookie interface */
+
+JNIEXPORT void JNICALL
+JNI_FN(Cookie_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_cookie *cookie = fz_cookie_from_Cookie(env, self);
+
+ if (ctx == NULL || cookie == NULL)
+ return;
+
+ fz_free(ctx, cookie);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Cookie_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(Cookie_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, cookie_fid, 0);
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(Cookie_newNative)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+
+ return jlong_cast(fz_malloc_struct(ctx, fz_cookie));
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(Cookie_abort)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_cookie *cookie = fz_cookie_from_Cookie(env, self);
+
+ if (ctx == NULL || cookie == NULL)
+ return;
+
+ cookie->abort = 1;
+}
+
+/* DisplayList interface */
+JNIEXPORT jlong JNICALL
+JNI_FN(DisplayList_newNative)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+
+ return jlong_cast(fz_new_display_list(ctx));
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(DisplayList_run)(JNIEnv * env, jobject self, jobject jdev, jobject jctm, jobject jrect, jobject jcookie)
+{
+ fz_context *ctx = get_context(env);
+ fz_display_list *list = fz_display_list_from_DisplayList(env, self);
+ fz_matrix ctm = fz_matrix_from_Matrix(env, jctm);
+ fz_cookie *cookie = fz_cookie_from_Cookie(env, jcookie);
+ fz_device *dev = fz_device_from_Device(env, jdev, ctx);
+ CDeviceNativeInfo *info;
+ fz_rect local_rect;
+ fz_rect *rect;
+
+ if (ctx == NULL || self == NULL || jdev == NULL || list == NULL)
+ return;
+
+ /* Use a scissor rectangle if one is supplied */
+ if (jrect == NULL)
+ {
+ rect = NULL;
+ }
+ else
+ {
+ rect = &local_rect;
+ local_rect = fz_rect_from_Rect(env, jrect);
+ }
+
+ info = lockCDevice(env, jdev);
+
+ fz_try(ctx)
+ {
+ fz_run_display_list(ctx, list, dev, &ctm, rect, cookie);
+ }
+ fz_always(ctx)
+ {
+ unlockCDevice(env, info);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(DisplayList_finalize)(JNIEnv * env, jobject self)
+{
+ fz_context *ctx = get_context(env);
+ fz_display_list *list = fz_display_list_from_DisplayList(env, self);
+
+ if (ctx == NULL || list == NULL)
+ return;
+
+ fz_drop_display_list(ctx, list);
+}
+
+JNIEXPORT void JNICALL
+JNI_FN(DisplayList_destroy)(JNIEnv * env, jobject self)
+{
+ JNI_FN(DisplayList_finalize)(env, self);
+
+ (*env)->SetLongField(env, self, displaylist_fid, 0);
+}
+
+JNIEXPORT jlong JNICALL
+JNI_FN(DisplayListDevice_newNative)(JNIEnv *env, jobject self, jobject jlist)
+{
+ fz_context *ctx = get_context(env);
+ fz_display_list *list = fz_display_list_from_DisplayList(env, jlist);
+ fz_device *device = NULL;
+ int ret;
+ unsigned char dummy;
+
+ if (ctx == NULL || list == NULL)
+ return 0;
+
+ fz_try(ctx)
+ {
+ device = fz_new_list_device(ctx, list);
+ }
+ fz_catch(ctx)
+ {
+ jni_rethrow(env, ctx);
+ }
+ return jlong_cast(device);
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/AndroidDrawDevice.java b/platform/android/src/com/artifex/mupdf/fitz/AndroidDrawDevice.java
new file mode 100644
index 00000000..1537f62a
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/AndroidDrawDevice.java
@@ -0,0 +1,19 @@
+package com.artifex.mupdf.fitz;
+
+import android.graphics.Bitmap;
+
+public final class AndroidDrawDevice extends CDevice
+{
+ // Construction
+ public AndroidDrawDevice(Bitmap bitmap, int pageX0, int pageY0, int pageX1, int pageY1, int patchX0, int patchY0, int patchX1, int patchY1)
+ {
+ nativeDevice = newNative(bitmap, pageX0, pageY0, pageX1, pageY1, patchX0, patchY0, patchX1, patchY1);
+ }
+
+ public AndroidDrawDevice(Bitmap bitmap, RectI page, RectI patch)
+ {
+ nativeDevice = newNative(bitmap, page.x0, page.y0, page.x1, page.y1, patch.x0, patch.y0, patch.x1, patch.y1);
+ }
+
+ private native long newNative(Bitmap bitmap, int pageX0, int pageY0, int pageX1, int pageY1, int patchX0, int patchY0, int patchX1, int patchY1);
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Annotation.java b/platform/android/src/com/artifex/mupdf/fitz/Annotation.java
new file mode 100644
index 00000000..6e6dd1c1
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Annotation.java
@@ -0,0 +1,27 @@
+package com.artifex.mupdf.fitz;
+
+public class Annotation
+{
+ // Private data
+ private long nativeAnnot = 0;
+
+ // Construction
+ private Annotation(long ptr)
+ {
+ nativeAnnot = ptr;
+ }
+
+ // Operation
+ public native void run(Device dev, Matrix ctm, Cookie cookie);
+
+ // FIXME: Write accessors
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativeAnnot = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/AwtDrawDevice.java b/platform/android/src/com/artifex/mupdf/fitz/AwtDrawDevice.java
new file mode 100644
index 00000000..4e6fb33d
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/AwtDrawDevice.java
@@ -0,0 +1,12 @@
+package com.artifex.mupdf.fitz;
+
+public final class AwtDrawDevice extends CDevice
+{
+ // Construction
+ public AwtDrawDevice(int rgba[], int width, int height)
+ {
+ nativeDevice = newNative(rgba, width, height);
+ }
+
+ private native long newNative(int rgba[], int width, int height);
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/CDevice.java b/platform/android/src/com/artifex/mupdf/fitz/CDevice.java
new file mode 100644
index 00000000..3bfe9c70
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/CDevice.java
@@ -0,0 +1,49 @@
+package com.artifex.mupdf.fitz;
+
+public abstract class CDevice extends Device
+{
+ // Private data
+ private Object nativeResource = null;
+ protected long nativeInfo = 0;
+
+ // Operation
+ public native final void beginPage(Rect rect, Matrix ctm);
+ public native final void endPage();
+
+ public native final void fillPath(Path path, int even_odd, Matrix ctm, ColorSpace cs, float color[], float alpha);
+ public native final void strokePath(Path path, StrokeState stroke, Matrix ctm, ColorSpace cs, float color[], float alpha);
+ public native final void clipPath(Path path, Rect rect, int even_odd, Matrix ctm);
+ public native final void clipStrokePath(Path path, Rect rect, StrokeState stroke, Matrix ctm);
+
+ public native final void fillText(Text text, Matrix ctm, ColorSpace cs, float color[], float alpha);
+ public native final void strokeText(Text text, StrokeState stroke, Matrix ctm, ColorSpace cs, float color[], float alpha);
+ public native final void clipText(Text text, Matrix ctm, int accumulate);
+ public native final void clipStrokeText(Text text, StrokeState stroke, Matrix ctm);
+ public native final void ignoreText(Text text, Matrix ctm);
+
+ public native final void fillShade(Shade shade, Matrix ctm, float alpha);
+ public native final void fillImage(Image img, Matrix ctm, float alpha);
+ public native final void fillImageMask(Image img, Matrix ctm, ColorSpace cs, float color[], float alpha);
+ public native final void clipImageMask(Image img, Rect rect, Matrix ctm);
+
+ public native final void popClip();
+
+ public native final void beginMask(Rect rect, int luminosity, ColorSpace cs, float bc[]);
+ public native final void endMask();
+ public native final void beginGroup(Rect rect, int isolated, int knockout, int blendmode, float alpha);
+ public native final void endGroup();
+
+ public native final int beginTile(Rect area, Rect view, float xstep, float ystep, Matrix ctm, int id);
+ public native final void endTile();
+
+ // Destruction
+ public final void destroy()
+ {
+ finalize();
+ nativeDevice = 0;
+ nativeResource = null;
+ nativeInfo = 0;
+ }
+
+ protected native final void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/ColorSpace.java b/platform/android/src/com/artifex/mupdf/fitz/ColorSpace.java
new file mode 100644
index 00000000..cad952c0
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/ColorSpace.java
@@ -0,0 +1,34 @@
+package com.artifex.mupdf.fitz;
+
+public class ColorSpace
+{
+ // Private data
+ private long nativeColorSpace;
+
+ // Statics
+ public static ColorSpace DeviceGray = new ColorSpace(newDeviceGray());
+ public static ColorSpace DeviceRGB = new ColorSpace(newDeviceRGB());
+ public static ColorSpace DeviceCMYK = new ColorSpace(newDeviceCMYK());
+
+ private static native long newDeviceGray();
+ private static native long newDeviceRGB();
+ private static native long newDeviceCMYK();
+
+ // Construction
+ private ColorSpace(long l)
+ {
+ nativeColorSpace = l;
+ }
+
+ // Accessors
+ public native int getNumComponents();
+
+ // Destruction
+ public final void destroy()
+ {
+ finalize();
+ nativeColorSpace = 0;
+ }
+
+ protected final native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Context.java b/platform/android/src/com/artifex/mupdf/fitz/Context.java
new file mode 100644
index 00000000..1baafb01
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Context.java
@@ -0,0 +1,20 @@
+package com.artifex.mupdf.fitz;
+
+// This class handles the loading of the MuPDF shared library, together
+// with the ThreadLocal magic to get the required context.
+//
+// The only publicly accessible method here is Context.setStoreSize, which
+// sets the store size to use. This must be called before any other MuPDF
+// function.
+public class Context
+{
+ // Load our native library
+ static
+ {
+ System.loadLibrary("mupdf");
+ }
+
+ // FIXME: We should support the store size being changed dynamically.
+ // This requires changes within the MuPDF core.
+ //public native static void setStoreSize(long newSize);
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Cookie.java b/platform/android/src/com/artifex/mupdf/fitz/Cookie.java
new file mode 100644
index 00000000..a072e018
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Cookie.java
@@ -0,0 +1,30 @@
+package com.artifex.mupdf.fitz;
+
+public class Cookie
+{
+ // Private data
+ private long nativeCookie = 0;
+
+ // Construction
+ public Cookie()
+ {
+ nativeCookie = newNative();
+ }
+
+ private native long newNative();
+
+ // Operation
+ public native void abort();
+
+ //FIXME: Cookie accessors
+
+ // Destruction
+ protected native void finalize();
+
+ public void destroy()
+ {
+ finalize();
+ nativeCookie = 0;
+ }
+
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Device.java b/platform/android/src/com/artifex/mupdf/fitz/Device.java
new file mode 100644
index 00000000..366022e9
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Device.java
@@ -0,0 +1,172 @@
+package com.artifex.mupdf.fitz;
+
+public abstract class Device
+{
+ /* Flags */
+ public static final int FZ_DEVFLAG_MASK = 1;
+ public static final int FZ_DEVFLAG_COLOR = 2;
+ public static final int FZ_DEVFLAG_UNCACHEABLE = 4;
+ public static final int FZ_DEVFLAG_FILLCOLOR_UNDEFINED = 8;
+ public static final int FZ_DEVFLAG_STROKECOLOR_UNDEFINED = 16;
+ public static final int FZ_DEVFLAG_STARTCAP_UNDEFINED = 32;
+ public static final int FZ_DEVFLAG_DASHCAP_UNDEFINED = 64;
+ public static final int FZ_DEVFLAG_ENDCAP_UNDEFINED = 128;
+ public static final int FZ_DEVFLAG_LINEJOIN_UNDEFINED = 256;
+ public static final int FZ_DEVFLAG_MITERLIMIT_UNDEFINED = 512;
+ public static final int FZ_DEVFLAG_LINEWIDTH_UNDEFINED = 1024;
+
+ /* PDF 1.4 -- standard separable */
+ public static final int FZ_BLEND_NORMAL = 0;
+ public static final int FZ_BLEND_MULTIPLY = 1;
+ public static final int FZ_BLEND_SCREEN = 2;
+ public static final int FZ_BLEND_OVERLAY = 3;
+ public static final int FZ_BLEND_DARKEN = 4;
+ public static final int FZ_BLEND_LIGHTEN = 5;
+ public static final int FZ_BLEND_COLOR_DODGE = 6;
+ public static final int FZ_BLEND_COLOR_BURN = 7;
+ public static final int FZ_BLEND_HARD_LIGHT = 8;
+ public static final int FZ_BLEND_SOFT_LIGHT = 9;
+ public static final int FZ_BLEND_DIFFERENCE = 10;
+ public static final int FZ_BLEND_EXCLUSION = 11;
+
+ /* PDF 1.4 -- standard non-separable */
+ public static final int FZ_BLEND_HUE = 12;
+ public static final int FZ_BLEND_SATURATION = 13;
+ public static final int FZ_BLEND_COLOR = 14;
+ public static final int FZ_BLEND_LUMINOSITY = 15;
+
+ /* For packing purposes */
+ public static final int FZ_BLEND_MODEMASK = 15;
+ public static final int FZ_BLEND_ISOLATED = 16;
+ public static final int FZ_BLEND_KNOCKOUT = 32;
+
+ /* To implement your own device in Java, you should define your own
+ * class that extends this one, and override as many of the following
+ * functions as is appropriate. For example:
+ *
+ * class ImageTraceDevice extends Device
+ * {
+ * void fillImage(Image img, Matrix ctx, float alpha) {
+ * Debug.Log("Image!");
+ * }
+ * };
+ *
+ * There is no constructor here, as no one will ever construct a
+ * Device without subclassing.
+ */
+
+ /* Everything under here is private implementation details.
+ * Ideally we'd like to hide these from prying eyes, but Java doesn't
+ * allow that.
+ */
+
+ public static final int FZ_IGNORE_IMAGE = 1;
+ public static final int FZ_IGNORE_SHADE = 2;
+
+ /* None of our device functions do anything. Anyone interested will
+ * override them in a subclass either in Java, or (as a subclass of
+ * CDevice) in C.
+ */
+ public void beginPage(Rect rect, Matrix ctm)
+ {
+ }
+
+ public void endPage()
+ {
+ }
+
+ public void fillPath(Path path, int even_odd, Matrix ctm, ColorSpace cs, float color[], float alpha)
+ {
+ }
+
+ public void strokePath(long ctx, Path path, StrokeState stroke, Matrix ctm, ColorSpace cs, float color[], float alpha)
+ {
+ }
+
+ public void clipPath(Path path, Rect rect, int even_odd, Matrix ctm)
+ {
+ }
+
+ public void clipStrokePath(Path path, Rect rect, StrokeState stroke, Matrix ctm)
+ {
+ }
+
+ public void fillText(Text text, Matrix ctm, ColorSpace cs, float color[], float alpha)
+ {
+ }
+
+ public void strokeText(Text text, StrokeState stroke, Matrix ctm, ColorSpace cs, float color[], float alpha)
+ {
+ }
+
+ public void clipText(Text text, Matrix ctm)
+ {
+ }
+
+ public void clipStrokeText(Text text, StrokeState stroke, Matrix ctm)
+ {
+ }
+
+ public void ignoreText(Text text, Matrix ctm)
+ {
+ }
+
+ public void fillShade(Shade shade, Matrix ctm, float alpha)
+ {
+ }
+
+ public void fillImage(Image img, Matrix ctm, float alpha)
+ {
+ }
+
+ public void fillImageMask(Image img, Matrix ctm, ColorSpace cs, float color[], float alpha)
+ {
+ }
+
+ public void clipImageMask(Image img, Rect rect, Matrix ctm)
+ {
+ }
+
+ public void popClip()
+ {
+ }
+
+ public void beginMask(Rect rect, int luminosity, ColorSpace cs, float bc[])
+ {
+ }
+
+ public void endMask()
+ {
+ }
+
+ public void beginGroup(Rect rect, int isolated, int knockout, int blendmode, float alpha)
+ {
+ }
+
+ public void endGroup()
+ {
+ }
+
+ public int beginTile(Rect area, Rect view, float xstep, float ystep, Matrix ctm, int id)
+ {
+ return 0;
+ }
+
+ public void endTile()
+ {
+ }
+
+ /* An accessor for device hints */
+ final native int getHints();
+ final native void enableDeviceHints(int hints);
+ final native void disableDeviceHints(int hints);
+
+ // Destruction
+ public void destroy()
+ {
+ }
+
+ // Private data.
+ // All java devices MUST leave this as 0.
+ protected long nativeDevice;
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/DisplayList.java b/platform/android/src/com/artifex/mupdf/fitz/DisplayList.java
new file mode 100644
index 00000000..8a2515e4
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/DisplayList.java
@@ -0,0 +1,32 @@
+package com.artifex.mupdf.fitz;
+
+public class DisplayList
+{
+ // Private data
+ protected long nativeDisplayList;
+
+ // Constructions
+ public DisplayList()
+ {
+ nativeDisplayList = newNative();
+ }
+
+ private native long newNative();
+
+ // Operation
+ public native void run(Device device, Matrix ctm, Rect scissor, Cookie cookie);
+
+ public void run(Device device, Matrix ctm, Cookie cookie)
+ {
+ run(device, ctm, null, cookie);
+ }
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativeDisplayList = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/DisplayListDevice.java b/platform/android/src/com/artifex/mupdf/fitz/DisplayListDevice.java
new file mode 100644
index 00000000..de3142dc
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/DisplayListDevice.java
@@ -0,0 +1,14 @@
+package com.artifex.mupdf.fitz;
+
+import android.graphics.Bitmap;
+
+public final class DisplayListDevice extends CDevice
+{
+ // Construction
+ public DisplayListDevice(DisplayList list)
+ {
+ nativeDevice = newNative(list);
+ }
+
+ private native long newNative(DisplayList list);
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Document.java b/platform/android/src/com/artifex/mupdf/fitz/Document.java
new file mode 100644
index 00000000..8c3136df
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Document.java
@@ -0,0 +1,60 @@
+package com.artifex.mupdf.fitz;
+
+import java.lang.ref.WeakReference;
+
+public class Document
+{
+ // Private data
+ private long nativeDocument = 0;
+
+ // Construction
+ public Document(String filename) throws Exception
+ {
+ nativeDocument = newNative(filename);
+ if (nativeDocument == 0)
+ throw(new Exception("Failed to load Document"));
+ }
+ private native final long newNative(String filename);
+
+ // FIXME: Should support opening java streams and from byte buffers etc.
+ // Streams would need to be seekable.
+ public Document(byte buffer[], String magic) throws Exception
+ {
+ nativeDocument = 0;//newFromBufferNative(buffer, magic);
+ if (nativeDocument == 0)
+ throw(new Exception("Failed to load Document"));
+ }
+ //private native final long newFromBufferNative(byte buffer[], String magic);
+
+ //public Document(SeekableStream stream, String magic) throws Exception
+ //{
+ // nativeDocument = newFromStreamNative(stream, magic);
+ // if (nativeDocument == 0)
+ // throw(new Exception("Failed to load Document"));
+ //}
+ //private native final long newFromBufferNative(SeekableStream stream, String magic);
+
+ // Operation
+ public native boolean needsPassword();
+
+ public native boolean authenticatePassword(String password);
+
+ public native int countPages();
+
+ public native Page getPage(int n);
+
+ public native String getFileFormat();
+
+ public native boolean isUnencryptedPDF();
+
+ public native Outline getOutline();
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativeDocument = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Font.java b/platform/android/src/com/artifex/mupdf/fitz/Font.java
new file mode 100644
index 00000000..7630dfa5
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Font.java
@@ -0,0 +1,22 @@
+package com.artifex.mupdf.fitz;
+
+public class Font
+{
+ // Private data
+ private long nativeFont;
+
+ // Construction
+ private Font(long font)
+ {
+ nativeFont = font;
+ }
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativeFont = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Image.java b/platform/android/src/com/artifex/mupdf/fitz/Image.java
new file mode 100644
index 00000000..a736ce5f
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Image.java
@@ -0,0 +1,56 @@
+package com.artifex.mupdf.fitz;
+import android.graphics.Bitmap;
+
+public class Image
+{
+ // Private data
+ private long nativeImage = 0;
+
+ // Construction
+ Image(Bitmap bm) throws Exception
+ {
+ if (bm == null)
+ throw new Exception("null Bitmap passed to Image");
+ nativeImage = newFromBitmapNative(bm, null);
+ }
+
+ Image(Bitmap bm, Image mask) throws Exception
+ {
+ if (bm == null)
+ throw new Exception("null Bitmap passed to Image");
+ nativeImage = newFromBitmapNative(bm, mask);
+ }
+
+ private native final long newFromBitmapNative(Bitmap bm, Image mask);
+
+ // Private constructor for the C to use. Any objects created by the
+ // C are done for purposes of calling back to a java device, and
+ // should therefore be considered const.
+ private Image(long l)
+ {
+ nativeImage = l;
+ }
+
+ // Accessors
+ public native int getWidth();
+ public native int getHeight();
+ public native int getNumComponents();
+ public native int getBitsPerComponent();
+ public native int getXResolution();
+ public native int getYResolution();
+ public native boolean getImageMask();
+ public native boolean getInterpolate();
+ public native Image getMask();
+
+ // FIXME: Get data back?
+ // FIXME: Create images from data or java streams?
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativeImage = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Link.java b/platform/android/src/com/artifex/mupdf/fitz/Link.java
new file mode 100644
index 00000000..7c63fcf9
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Link.java
@@ -0,0 +1,27 @@
+package com.artifex.mupdf.fitz;
+
+public class Link
+{
+ // Private data
+ private long nativeLink = 0;
+
+ // Construction
+ private Link(long l)
+ {
+ nativeLink = l;
+ }
+
+ // Operation
+ public native Link getNext();
+
+ //FIXME: Accessors
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativeLink = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Matrix.java b/platform/android/src/com/artifex/mupdf/fitz/Matrix.java
new file mode 100644
index 00000000..ede57ccc
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Matrix.java
@@ -0,0 +1,59 @@
+package com.artifex.mupdf.fitz;
+
+public class Matrix
+{
+ public float a;
+ public float b;
+ public float c;
+ public float d;
+ public float e;
+ public float f;
+
+ public Matrix(float a, float b, float c, float d, float e, float f)
+ {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ this.e = e;
+ this.f = f;
+ }
+
+ public Matrix(float a, float d)
+ {
+ this.a = a;
+ this.b = 0;
+ this.c = 0;
+ this.d = d;
+ this.e = 0;
+ this.f = 0;
+ }
+
+ public Matrix(float a)
+ {
+ this.a = a;
+ this.b = 0;
+ this.c = 0;
+ this.d = a;
+ this.e = 0;
+ this.f = 0;
+ }
+
+ public Matrix concat(Matrix m)
+ {
+ float a = this.a * m.a + this.b * m.c;
+ float b = this.a * m.b + this.b * m.d;
+ float c = this.c * m.a + this.d * m.c;
+ float d = this.c * m.b + this.d * m.d;
+ float e = this.e * m.a + this.f * m.c + m.e;
+ this.f = this.e * m.b + this.f * m.d + m.f;
+
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ this.e = e;
+
+ return this;
+ }
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Outline.java b/platform/android/src/com/artifex/mupdf/fitz/Outline.java
new file mode 100644
index 00000000..1b808d7f
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Outline.java
@@ -0,0 +1,22 @@
+package com.artifex.mupdf.fitz;
+
+public class Outline
+{
+ // Private data
+ private long nativeOutline = 0;
+
+ // Construction
+ private Outline(long out)
+ {
+ nativeOutline = out;
+ }
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativeOutline = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Page.java b/platform/android/src/com/artifex/mupdf/fitz/Page.java
new file mode 100644
index 00000000..46d598ee
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Page.java
@@ -0,0 +1,37 @@
+package com.artifex.mupdf.fitz;
+
+public class Page
+{
+ // Private data
+ private long nativePage = 0;
+ private Annotation nativeAnnots[];
+
+ // Construction
+ private Page(long page)
+ {
+ nativePage = page;
+ nativeAnnots = null;
+ }
+
+ // Operation
+ public native Rect bound();
+ public native void run(Device dev, Matrix ctm, Cookie cookie);
+ public native void runPageContents(Device dev, Matrix ctm, Cookie cookie);
+ public native Annotation[] getAnnotations();
+
+ // FIXME: Later
+ public native Link[] getLinks();
+
+ // FIXME: Later. Much later.
+ //fz_transition *fz_page_presentation(fz_document *doc, fz_page *page, float *duration);
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativePage = 0;
+ nativeAnnots = null;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Path.java b/platform/android/src/com/artifex/mupdf/fitz/Path.java
new file mode 100644
index 00000000..17257f10
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Path.java
@@ -0,0 +1,82 @@
+package com.artifex.mupdf.fitz;
+
+public class Path implements PathProcessor
+{
+ // Private data
+ private long nativePath = 0;
+
+ // Construction
+ public Path()
+ {
+ nativePath = newNative();
+ }
+
+ private native long newNative();
+
+ private Path(long path)
+ {
+ nativePath = path;
+ }
+
+ public Path(Path old)
+ {
+ nativePath = clone(old);
+ }
+
+ private native long clone(Path old);
+
+ // Operation
+ public native Point currentPoint();
+
+ public void moveTo(Point xy)
+ {
+ moveTo(xy.x, xy.y);
+ }
+
+ public native void moveTo(float x, float y);
+
+ public void lineTo(Point xy)
+ {
+ lineTo(xy.x, xy.y);
+ }
+
+ public native void lineTo(float x, float y);
+
+ public void curveTo(Point c1, Point c2, Point e)
+ {
+ curveTo(c1.x, c1.y, c2.x, c2.y, e.x, e.y);
+ }
+
+ public native void curveTo(float cx1, float cy1, float cx2, float cy2, float ex, float ey);
+
+ public void curveToV(Point c, Point e)
+ {
+ curveToV(c.x, c.y, e.x, e.y);
+ }
+
+ public native void curveToV(float cx, float cy, float ex, float ey);
+
+ public void curveToY(Point c, Point e)
+ {
+ curveToY(c.x, c.y, e.x, e.y);
+ }
+
+ public native void curveToY(float cx, float cy, float ex, float ey);
+
+ public native void close();
+
+ public native void transform(Matrix mat);
+
+ public native Rect bound(StrokeState stroke, Matrix ctm);
+
+ public native void process(PathProcessor proc);
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativePath = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/PathProcessor.java b/platform/android/src/com/artifex/mupdf/fitz/PathProcessor.java
new file mode 100644
index 00000000..71d03c50
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/PathProcessor.java
@@ -0,0 +1,9 @@
+package com.artifex.mupdf.fitz;
+
+public interface PathProcessor
+{
+ public void moveTo(float x, float y);
+ public void lineTo(float x, float y);
+ public void curveTo(float cx1, float cy1, float cx2, float cy2, float ex, float ey);
+ public void close();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Point.java b/platform/android/src/com/artifex/mupdf/fitz/Point.java
new file mode 100644
index 00000000..08989dd7
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Point.java
@@ -0,0 +1,29 @@
+package com.artifex.mupdf.fitz;
+
+public class Point
+{
+ public float x;
+ public float y;
+
+ public Point(float x, float y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ public Point(Point p)
+ {
+ this.x = p.x;
+ this.y = p.y;
+ }
+
+ public Point transform(Matrix tm)
+ {
+ float old_x = this.x;
+
+ this.x = old_x * tm.a + y * tm.c + tm.e;
+ this.y = old_x * tm.b + y * tm.d + tm.f;
+
+ return this;
+ }
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Rect.java b/platform/android/src/com/artifex/mupdf/fitz/Rect.java
new file mode 100644
index 00000000..eb9138cf
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Rect.java
@@ -0,0 +1,79 @@
+package com.artifex.mupdf.fitz;
+
+public class Rect
+{
+ public float x0;
+ public float y0;
+ public float x1;
+ public float y1;
+
+ public Rect(float x0, float y0, float x1, float y1)
+ {
+ this.x0 = x0;
+ this.y0 = y0;
+ this.x1 = x1;
+ this.y1 = y1;
+ }
+
+ public Rect(Rect r)
+ {
+ this.x0 = r.x0;
+ this.y0 = r.y0;
+ this.x1 = r.x1;
+ this.y1 = r.y1;
+ }
+
+ public Rect transform(Matrix tm)
+ {
+ float ax0 = x0 * tm.a;
+ float ax1 = x1 * tm.a;
+
+ if (ax0 > ax1)
+ {
+ float t = ax0;
+ ax0 = ax1;
+ ax1 = t;
+ }
+
+ float cy0 = y0 * tm.c;
+ float cy1 = y1 * tm.c;
+
+ if (cy0 > cy1)
+ {
+ float t = cy0;
+ cy0 = cy1;
+ cy1 = t;
+ }
+ ax0 += cy0 + tm.e;
+ ax1 += cy1 + tm.e;
+
+ float bx0 = x0 * tm.b;
+ float bx1 = x1 * tm.b;
+
+ if (bx0 > bx1)
+ {
+ float t = bx0;
+ bx0 = bx1;
+ bx1 = t;
+ }
+
+ float dy0 = y0 * tm.d;
+ float dy1 = y1 * tm.d;
+
+ if (dy0 > dy1)
+ {
+ float t = dy0;
+ dy0 = dy1;
+ dy1 = t;
+ }
+ bx0 += dy0 + tm.f;
+ bx1 += dy1 + tm.f;
+
+ x0 = ax0;
+ x1 = ax1;
+ y0 = bx0;
+ y1 = bx1;
+
+ return this;
+ }
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/RectI.java b/platform/android/src/com/artifex/mupdf/fitz/RectI.java
new file mode 100644
index 00000000..1f91c778
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/RectI.java
@@ -0,0 +1,79 @@
+package com.artifex.mupdf.fitz;
+
+public class RectI
+{
+ public int x0;
+ public int y0;
+ public int x1;
+ public int y1;
+
+ public RectI(int x0, int y0, int x1, int y1)
+ {
+ this.x0 = x0;
+ this.y0 = y0;
+ this.x1 = x1;
+ this.y1 = y1;
+ }
+
+ public RectI(Rect r)
+ {
+ this.x0 = (int)Math.floor(r.x0);
+ this.y0 = (int)Math.ceil(r.y0);
+ this.x1 = (int)Math.floor(r.x1);
+ this.y1 = (int)Math.ceil(r.y1);
+ }
+
+ public RectI transform(Matrix tm)
+ {
+ float ax0 = x0 * tm.a;
+ float ax1 = x1 * tm.a;
+
+ if (ax0 > ax1)
+ {
+ float t = ax0;
+ ax0 = ax1;
+ ax1 = t;
+ }
+
+ float cy0 = y0 * tm.c;
+ float cy1 = y1 * tm.c;
+
+ if (cy0 > cy1)
+ {
+ float t = cy0;
+ cy0 = cy1;
+ cy1 = t;
+ }
+ ax0 += cy0 + tm.e;
+ ax1 += cy1 + tm.e;
+
+ float bx0 = x0 * tm.b;
+ float bx1 = x1 * tm.b;
+
+ if (bx0 > bx1)
+ {
+ float t = bx0;
+ bx0 = bx1;
+ bx1 = t;
+ }
+
+ float dy0 = y0 * tm.d;
+ float dy1 = y1 * tm.d;
+
+ if (dy0 > dy1)
+ {
+ float t = dy0;
+ dy0 = dy1;
+ dy1 = t;
+ }
+ bx0 += dy0 + tm.f;
+ bx1 += dy1 + tm.f;
+
+ x0 = (int)Math.floor(ax0);
+ x1 = (int)Math.ceil(ax1);
+ y0 = (int)Math.floor(bx0);
+ y1 = (int)Math.ceil(bx1);
+
+ return this;
+ }
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Shade.java b/platform/android/src/com/artifex/mupdf/fitz/Shade.java
new file mode 100644
index 00000000..bfadebc7
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Shade.java
@@ -0,0 +1,28 @@
+package com.artifex.mupdf.fitz;
+
+public class Shade
+{
+ // Private data
+ private long nativeShade = 0;
+
+ // Construction
+ // Private constructor for the C to use. Any objects created by the
+ // C are done for purposes of calling back to a java device, and
+ // should therefore be considered const.
+ private Shade(long l)
+ {
+ nativeShade = l;
+ }
+
+ // FIXME: Constructors for the different types of shade
+ // FIXME: Accessors for shade data
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativeShade = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/StrokeState.java b/platform/android/src/com/artifex/mupdf/fitz/StrokeState.java
new file mode 100644
index 00000000..2f2fcf96
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/StrokeState.java
@@ -0,0 +1,64 @@
+package com.artifex.mupdf.fitz;
+
+import android.graphics.Rect;
+
+public class StrokeState
+{
+ public static final int FZ_LINECAP_BUTT = 0;
+ public static final int FZ_LINECAP_ROUND = 1;
+ public static final int FZ_LINECAP_SQUARE = 2;
+ public static final int FZ_LINECAP_TRIANGLE = 3;
+
+ public static final int FZ_LINEJOIN_MITER = 0;
+ public static final int FZ_LINEJOIN_ROUND = 1;
+ public static final int FZ_LINEJOIN_BEVEL = 2;
+ public static final int FZ_LINEJOIN_MITER_XPS = 3;
+
+ // Private data
+ private long nativeStroke;
+
+ // Construction
+ StrokeState(int startCap, int endCap, int lineJoin, float lineWidth, float miterLimit)
+ {
+ nativeStroke = newNative(startCap, 0, endCap, lineJoin, lineWidth, miterLimit, 0, null);
+ }
+
+ StrokeState(int startCap, int dashCap, int endCap, int lineJoin, float lineWidth, float miterLimit, float dashPhase, float dash[])
+ {
+ nativeStroke = newNative(startCap, dashCap, endCap, lineJoin, lineWidth, miterLimit, dashPhase, dash);
+ }
+
+ private native long newNative(int startCap, int dashCap, int endCap, int lineJoin, float lineWidth, float miterLimit, float dashPhase, float dash[]);
+
+ // Private constructor for the C to use. Any objects created by the
+ // C are done for purposes of calling back to a java device, and
+ // should therefore be considered const. This is fine as we don't
+ // currently provide mechanisms for changing individual elements
+ // of the StrokeState.
+ private StrokeState(long l)
+ {
+ nativeStroke = l;
+ }
+
+ // Operation
+ public native void adjustRectForStroke(Rect rect, Matrix ctm);
+
+ // Accessors
+ public native int getStartCap();
+ public native int getDashCap();
+ public native int getEndCap();
+ public native int getLineJoin();
+ public native float getLineWidth();
+ public native float getMiterLimit();
+ public native float getDashPhase();
+ public native float[] getDashes();
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativeStroke = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/Text.java b/platform/android/src/com/artifex/mupdf/fitz/Text.java
new file mode 100644
index 00000000..eada4635
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/Text.java
@@ -0,0 +1,46 @@
+package com.artifex.mupdf.fitz;
+
+public class Text
+{
+ // Private data
+ private long nativeText = 0;
+ private boolean isConst = false;
+
+ // Cloning
+ public Text(Text old)
+ {
+ nativeText = cloneNative(old);
+ }
+
+ private native long cloneNative(Text old);
+
+ //public Text(Font font, Matrix trm, int wmode)
+ //{
+ // nativeText = newNative(font, trm, wmode);
+ //}
+
+ // Private method used for creating Text entries for a
+ // device implemented in java. These entries should be
+ // immutable.
+ private Text(long ptr)
+ {
+ nativeText = ptr;
+ isConst = true;
+ }
+
+ // Operation
+ public native Rect bound(StrokeState stroke, Matrix ctm);
+
+ //public native void add(int gid, int ucs, float x, float y);
+
+ // FIXME: Write accessors
+
+ // Destruction
+ public void destroy()
+ {
+ finalize();
+ nativeText = 0;
+ }
+
+ protected native void finalize();
+}
diff --git a/platform/android/src/com/artifex/mupdf/fitz/TryLaterException.java b/platform/android/src/com/artifex/mupdf/fitz/TryLaterException.java
new file mode 100644
index 00000000..644c6af1
--- /dev/null
+++ b/platform/android/src/com/artifex/mupdf/fitz/TryLaterException.java
@@ -0,0 +1,9 @@
+package com.artifex.mupdf.fitz;
+
+public class TryLaterException extends Exception
+{
+ TryLaterException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/platform/android/src/com/artifex/mupdfdemo/MuPDFCore.java b/platform/android/src/com/artifex/mupdfdemo/MuPDFCore.java
index de202b3c..da3c20cd 100644
--- a/platform/android/src/com/artifex/mupdfdemo/MuPDFCore.java
+++ b/platform/android/src/com/artifex/mupdfdemo/MuPDFCore.java
@@ -11,7 +11,9 @@ public class MuPDFCore
/* load our native library */
private static boolean gs_so_available = false;
static {
+ System.out.println("Loading dll");
System.loadLibrary("mupdf");
+ System.out.println("Loaded dll");
if (gprfSupportedInternal())
{
try {
diff --git a/platform/win32/jni.vcproj b/platform/win32/jni.vcproj
new file mode 100644
index 00000000..241fabb4
--- /dev/null
+++ b/platform/win32/jni.vcproj
@@ -0,0 +1,441 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="jni"
+ ProjectGUID="{05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}"
+ RootNamespace="jni"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="java"
+ >
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\AndroidDrawDevice.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Annotation.java"
+ >
+ </File>
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\AwtDrawDevice.java"
+ >
+ </File>
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\CDevice.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\ColorSpace.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Context.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Cookie.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Device.java"
+ >
+ </File>
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\DisplayList.java"
+ >
+ </File>
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\DisplayListDevice.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Document.java"
+ >
+ </File>
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\Font.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Image.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Link.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Matrix.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Outline.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Page.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Path.java"
+ >
+ </File>
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\PathProcessor.java"
+ >
+ </File>
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\Point.java"
+ >
+ </File>
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\Rect.java"
+ >
+ </File>
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\RectI.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Shade.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\StrokeState.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdf\fitz\Text.java"
+ >
+ </File>
+ <File
+ RelativePath="..\android\src\com\artifex\mupdf\fitz\TryLaterException.java"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="javaapp"
+ >
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\Annotation.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\ArrayDeque.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\AsyncTask.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\ChoosePDFActivity.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\ChoosePDFAdapter.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\ChoosePDFItem.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\Deque.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\FilePicker.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\LinkInfo.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\LinkInfoExternal.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\LinkInfoInternal.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\LinkInfoRemote.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\LinkInfoVisitor.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\MuPDFActivity.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\MuPDFAlert.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\MuPDFAlertInternal.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\MuPDFCore.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\MuPDFPageAdapter.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\MuPDFPageView.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\MuPDFReaderView.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\MuPDFReflowAdapter.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\MuPDFReflowView.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\MuPDFView.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\OutlineActivity.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\OutlineActivityData.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\OutlineAdapter.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\OutlineItem.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\PageView.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\PrintDialogActivity.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\ReaderView.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\SafeAnimatorInflater.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\SearchTask.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\SearchTaskResult.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\TextChar.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\TextWord.java"
+ >
+ </File>
+ <File
+ RelativePath="..\..\platform\android\src\com\artifex\mupdfdemo\WidgetType.java"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath="..\..\platform\android\jni\mupdf.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\platform\android\jni\mupdf_native.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/platform/win32/mupdf.sln b/platform/win32/mupdf.sln
index b614da1b..8894689d 100644
--- a/platform/win32/mupdf.sln
+++ b/platform/win32/mupdf.sln
@@ -52,6 +52,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupdf-gl", "mupdf-gl.vcproj
{5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jni", "jni.vcproj", "{05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -286,6 +288,21 @@ Global
{CE3A76A8-A28F-4991-8FB9-C9453D922037}.ReleaseOpenssl|Win32.Build.0 = Release|Win32
{CE3A76A8-A28F-4991-8FB9-C9453D922037}.ReleaseOpenssl|x64.ActiveCfg = Release|x64
{CE3A76A8-A28F-4991-8FB9-C9453D922037}.ReleaseOpenssl|x64.Build.0 = Release|x64
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.Debug|Win32.ActiveCfg = Debug|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.Debug|Win32.Build.0 = Debug|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.Debug|x64.ActiveCfg = Debug|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.DebugOpenssl|Win32.ActiveCfg = Debug|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.DebugOpenssl|Win32.Build.0 = Debug|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.DebugOpenssl|x64.ActiveCfg = Debug|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.Memento|Win32.ActiveCfg = Release|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.Memento|Win32.Build.0 = Release|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.Memento|x64.ActiveCfg = Release|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.Release|Win32.ActiveCfg = Release|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.Release|Win32.Build.0 = Release|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.Release|x64.ActiveCfg = Release|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.ReleaseOpenssl|Win32.ActiveCfg = Release|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.ReleaseOpenssl|Win32.Build.0 = Release|Win32
+ {05A1CA5B-9807-4B3A-9954-EFAB8ADE7757}.ReleaseOpenssl|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE