1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 * Copyright (C) 2016 Mopria Alliance, Inc.
4 * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 #include <jni.h>
19 #include <malloc.h>
20 #include "wprint_mupdf.h"
21 #include "wprint_debug.h"
22
23 #define TAG "pdf_render"
24
25 /* Global reference to JVM */
26 extern JavaVM *_JVM;
27
28 /* Local data associated with pdf_render_st instances */
29 typedef struct pdf_render_st {
30 /* Public interface. Must be first. */
31 pdf_render_ifc_t ifc;
32
33 /* JNI environment */
34 JNIEnv *env;
35
36 /* true if the env was created for this thread */
37 bool needDetach;
38
39 /* Reference to associated PdfRender object */
40 jobject obj;
41 } pdf_render_st_t;
42
43 static jclass gPdfRenderClass;
44 static jmethodID gPdfRenderOpenDocument, gPdfRenderGetPageSize, gPdfRenderRenderPageStripe;
45 static jclass gSizeDClass;
46 static jmethodID gSizeDGetHeight, gSizeDGetWidth;
47
openDocument(pdf_render_ifc_t * obj,const char * fileName)48 static int openDocument(pdf_render_ifc_t *obj, const char *fileName) {
49 LOGD("getPageCount %p %s", obj, fileName);
50 if (!gPdfRenderClass) return ERROR;
51
52 pdf_render_st_t *self = (pdf_render_st_t *) obj;
53 jstring fileNameString = (*self->env)->NewStringUTF(self->env, fileName);
54 int count = (*self->env)->CallIntMethod(self->env, self->obj, gPdfRenderOpenDocument,
55 fileNameString);
56 LOGD("getPageCount %p %s returning %d", obj, fileName, count);
57 return count;
58 }
59
getPageAttributes(pdf_render_ifc_t * obj,int page,double * width,double * height)60 static int getPageAttributes(pdf_render_ifc_t *obj, int page, double *width, double *height) {
61 LOGD("getPageAttributes %p %d", obj, page);
62 if (!gPdfRenderClass) return ERROR;
63
64 pdf_render_st_t *self = (pdf_render_st_t *) obj;
65
66 jobject size = (*self->env)->CallObjectMethod(self->env, self->obj, gPdfRenderGetPageSize,
67 page);
68 if (size == NULL) return ERROR;
69
70 // Extract width/height and return them
71 *width = (double) (*self->env)->CallDoubleMethod(self->env, size, gSizeDGetWidth);
72 *height = (double) (*self->env)->CallDoubleMethod(self->env, size, gSizeDGetHeight);
73 return OK;
74 }
75
renderPageStripe(pdf_render_ifc_t * obj,int page,int width,int height,float zoom,char * buffer)76 static int renderPageStripe(pdf_render_ifc_t *obj, int page, int width, int height, float zoom,
77 char *buffer) {
78 LOGD("renderPageStripe %p %d", obj, page);
79 if (!gPdfRenderClass) return ERROR;
80
81 pdf_render_st_t *self = (pdf_render_st_t *) obj;
82
83 int bufferSize = width * height * 3;
84 jobject byteBuffer = (*self->env)->NewDirectByteBuffer(self->env, buffer, bufferSize);
85
86 if (!(*self->env)->CallBooleanMethod(self->env, self->obj, gPdfRenderRenderPageStripe, page,
87 0, width, height, (double) zoom, byteBuffer)) {
88 return ERROR;
89 }
90
91 (*self->env)->DeleteLocalRef(self->env, byteBuffer);
92 return OK;
93 }
94
destroy(pdf_render_ifc_t * obj)95 static void destroy(pdf_render_ifc_t *obj) {
96 LOGD("destroy %p", obj);
97 pdf_render_st_t *self = (pdf_render_st_t *) obj;
98
99 (*self->env)->DeleteGlobalRef(self->env, self->obj);
100
101 if (self->needDetach) {
102 (*_JVM)->DetachCurrentThread(_JVM);
103 }
104
105 free(self);
106 }
107
pdf_render_init(JNIEnv * env)108 void pdf_render_init(JNIEnv *env) {
109 LOGD("pdf_render_init");
110
111 /* Lock down global class references and look up method IDs */
112 gPdfRenderClass = (*env)->NewGlobalRef(env, (*env)->FindClass(env,
113 "com/android/bips/jni/PdfRender"));
114 gPdfRenderOpenDocument = (*env)->GetMethodID(env, gPdfRenderClass, "openDocument",
115 "(Ljava/lang/String;)I");
116 gPdfRenderGetPageSize = (*env)->GetMethodID(env, gPdfRenderClass, "getPageSize",
117 "(I)Lcom/android/bips/jni/SizeD;");
118 gPdfRenderRenderPageStripe = (*env)->GetMethodID(env, gPdfRenderClass, "renderPageStripe",
119 "(IIIIDLjava/nio/ByteBuffer;)Z");
120
121 gSizeDClass = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "com/android/bips/jni/SizeD"));
122 gSizeDGetWidth = (*env)->GetMethodID(env, gSizeDClass, "getWidth", "()D");
123 gSizeDGetHeight = (*env)->GetMethodID(env, gSizeDClass, "getHeight", "()D");
124 }
125
pdf_render_deinit(JNIEnv * env)126 void pdf_render_deinit(JNIEnv *env) {
127 LOGD("pdf_render_deinit");
128 (*env)->DeleteGlobalRef(env, gPdfRenderClass);
129 (*env)->DeleteGlobalRef(env, gSizeDClass);
130 gPdfRenderClass = 0;
131 }
132
create_pdf_render_ifc()133 pdf_render_ifc_t *create_pdf_render_ifc() {
134 LOGD("create_pdf_render_ifc");
135
136 pdf_render_st_t *self;
137
138 // Set up the interface
139 self = (pdf_render_st_t *) malloc(sizeof(pdf_render_st_t));
140 if (!self) return NULL;
141
142 self->ifc.openDocument = openDocument;
143 self->ifc.getPageAttributes = getPageAttributes;
144 self->ifc.renderPageStripe = renderPageStripe;
145 self->ifc.destroy = destroy;
146
147 // Get the environment
148 jint result = (*_JVM)->GetEnv(_JVM, (void **) &self->env, JNI_VERSION_1_6);
149 if (result == JNI_EDETACHED) {
150 self->needDetach = true;
151 if ((*_JVM)->AttachCurrentThread(_JVM, &self->env, NULL) < 0) {
152 LOGE("AttachCurrentThread failed");
153 free(self);
154 return NULL;
155 }
156 } else {
157 self->needDetach = false;
158 }
159
160 // Get the object
161 jmethodID methodId = (*self->env)->GetStaticMethodID(self->env, gPdfRenderClass, "getInstance",
162 "(Landroid/content/Context;)Lcom/android/bips/jni/PdfRender;");
163 jobject instance = (*self->env)->CallStaticObjectMethod(self->env, gPdfRenderClass, methodId,
164 NULL);
165 self->obj = (*self->env)->NewGlobalRef(self->env, instance);
166
167 return &self->ifc;
168 }