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 */ 26extern JavaVM *_JVM; 27 28/* Local data associated with pdf_render_st instances */ 29typedef 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 43static jclass gPdfRenderClass; 44static jmethodID gPdfRenderOpenDocument, gPdfRenderGetPageSize, gPdfRenderRenderPageStripe; 45static jclass gSizeDClass; 46static jmethodID gSizeDGetHeight, gSizeDGetWidth; 47 48static 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 60static 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 76static 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 95static 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 108void 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 126void 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 133pdf_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}