Home | History | Annotate | Download | only in plugins
      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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 }