Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/platform/java/jni/context.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/platform/java/jni/context.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,343 @@ +// Copyright (C) 2004-2025 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see <https://www.artifex.com/> or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +/* Context interface */ + +/* Put the fz_context in thread-local storage */ + +#ifdef _WIN32 +static CRITICAL_SECTION mutexes[FZ_LOCK_MAX]; +#else +static pthread_mutex_t mutexes[FZ_LOCK_MAX]; +#endif + +static void lock(void *user, int lock) +{ +#ifdef _WIN32 + EnterCriticalSection(&mutexes[lock]); +#else + (void)pthread_mutex_lock(&mutexes[lock]); +#endif +} + +static void unlock(void *user, int lock) +{ +#ifdef _WIN32 + LeaveCriticalSection(&mutexes[lock]); +#else + (void)pthread_mutex_unlock(&mutexes[lock]); +#endif +} + + +static const fz_locks_context locks = +{ + NULL, /* user */ + lock, + unlock +}; + +static void fin_base_context(JNIEnv *env) +{ + int i; + + fz_drop_context(base_context); + base_context = NULL; + + for (i = 0; i < FZ_LOCK_MAX; i++) +#ifdef _WIN32 + DeleteCriticalSection(&mutexes[i]); +#else + (void)pthread_mutex_destroy(&mutexes[i]); +#endif +} + +#ifndef _WIN32 +static void drop_tls_context(void *arg) +{ + fz_context *ctx = (fz_context *)arg; + + fz_drop_context(ctx); +} +#endif + +static void log_callback(void *user, const char *message) +{ + jboolean detach = JNI_FALSE; + JNIEnv *env = NULL; + jobject jcallback; + jstring jmessage; + jobject jlock; + jmethodID mid; + + env = jni_attach_thread(&detach); + if (env == NULL) + return; + + if (user != NULL) + mid = mid_Context_Log_error; + else + mid = mid_Context_Log_warning; + + jcallback = (*env)->GetStaticObjectField(env, cls_Context, fid_Context_log); + if (jcallback) + { + jlock = (*env)->GetStaticObjectField(env, cls_Context, fid_Context_lock); + (*env)->MonitorEnter(env, jlock); + jmessage = (*env)->NewStringUTF(env, message); + (*env)->CallVoidMethod(env, jcallback, mid, jmessage); + (*env)->DeleteLocalRef(env, jmessage); + (*env)->MonitorExit(env, jlock); + (*env)->DeleteLocalRef(env, jcallback); + (*env)->DeleteLocalRef(env, jlock); + } + + jni_detach_thread(detach); +} + +static int init_base_context(JNIEnv *env) +{ + int i; +#ifdef FZ_JAVA_STORE_SIZE + size_t fz_store_size = FZ_JAVA_STORE_SIZE; +#else + size_t fz_store_size = FZ_STORE_DEFAULT; +#endif + char *env_fz_store_size; + +#ifdef _WIN32 + /* No destructor on windows. We will leak contexts. + * There is no easy way around this, but this page: + * http://stackoverflow.com/questions/3241732/is-there-anyway-to-dynamically-free-thread-local-storage-in-the-win32-apis/3245082#3245082 + * suggests a workaround that we can implement if we + * need to. */ + context_key = TlsAlloc(); + if (context_key == TLS_OUT_OF_INDEXES) + { + LOGE("cannot get thread local storage for storing base context"); + return -1; + } +#else + int ret = pthread_key_create(&context_key, drop_tls_context); + if (ret < 0) + { + LOGE("cannot get thread local storage for storing base context"); + return -1; + } +#endif + + for (i = 0; i < FZ_LOCK_MAX; i++) +#ifdef _WIN32 + InitializeCriticalSection(&mutexes[i]); +#else + (void)pthread_mutex_init(&mutexes[i], NULL); +#endif + + env_fz_store_size = getenv("FZ_JAVA_STORE_SIZE"); + if (env_fz_store_size) + fz_store_size = fz_atoz(env_fz_store_size); + base_context = fz_new_context(NULL, &locks, fz_store_size); + + if (!base_context) + { + LOGE("cannot create base context"); + fin_base_context(env); + return -1; + } + + fz_set_error_callback(base_context, log_callback, (void *) 1); + fz_set_warning_callback(base_context, log_callback, (void *) 0); + + fz_try(base_context) + fz_register_document_handlers(base_context); + fz_catch(base_context) + { + fz_report_error(base_context); + LOGE("cannot register document handlers"); + fin_base_context(env); + return -1; + } + +#ifdef HAVE_ANDROID + fz_install_load_system_font_funcs(base_context, + load_droid_font, + load_droid_cjk_font, + load_droid_fallback_font); +#endif + + return 0; +} + +static fz_context *get_context(JNIEnv *env) +{ + fz_context *ctx = (fz_context *) +#ifdef _WIN32 + TlsGetValue(context_key); + if (ctx == NULL && GetLastError() != ERROR_SUCCESS) jni_throw_run(env, "cannot get context"); +#else + pthread_getspecific(context_key); +#endif + + if (ctx) + return ctx; + + ctx = fz_clone_context(base_context); + if (!ctx) jni_throw_oom(env, "failed to clone fz_context"); + +#ifdef _WIN32 + if (TlsSetValue(context_key, ctx) == 0) jni_throw_run(env, "cannot store context"); +#else + if (pthread_setspecific(context_key, ctx) != 0) jni_throw_run(env, "cannot store context"); +#endif + return ctx; +} + + +JNIEXPORT jint JNICALL +FUN(Context_initNative)(JNIEnv *env, jclass cls) +{ + if (!check_enums()) + 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 0; +} + +JNIEXPORT void JNICALL +FUN(Context_emptyStore)(JNIEnv *env, jclass cls) +{ + fz_context *ctx = get_context(env); + if (!ctx) return; + + fz_empty_store(ctx); +} + +JNIEXPORT void JNICALL +FUN(Context_enableICC)(JNIEnv *env, jclass cls) +{ + fz_context *ctx = get_context(env); + if (!ctx) return; + + fz_enable_icc(ctx); +} + +JNIEXPORT void JNICALL +FUN(Context_disableICC)(JNIEnv *env, jclass cls) +{ + fz_context *ctx = get_context(env); + if (!ctx) return; + + fz_disable_icc(ctx); +} + +JNIEXPORT void JNICALL +FUN(Context_setAntiAliasLevel)(JNIEnv *env, jclass cls, jint level) +{ + fz_context *ctx = get_context(env); + if (!ctx) return; + + fz_set_aa_level(ctx, level); +} + +JNIEXPORT jobject JNICALL +FUN(Context_getVersion)(JNIEnv *env, jclass cls) +{ + fz_context *ctx = get_context(env); + jobject jversion = NULL; + jobject jvs = NULL; + + if (!ctx) return NULL; + + jvs = (*env)->NewStringUTF(env, FZ_VERSION); + if (!jvs || (*env)->ExceptionCheck(env)) + return NULL; + + jversion = (*env)->NewObject(env, cls_Context_Version, mid_Context_Version_init); + if (!jversion || (*env)->ExceptionCheck(env)) + return NULL; + + (*env)->SetIntField(env, jversion, fid_Context_Version_major, FZ_VERSION_MAJOR); + (*env)->SetIntField(env, jversion, fid_Context_Version_minor, FZ_VERSION_MINOR); + (*env)->SetIntField(env, jversion, fid_Context_Version_patch, FZ_VERSION_PATCH); + (*env)->SetObjectField(env, jversion, fid_Context_Version_version, jvs); + + return jversion; +} + +JNIEXPORT void JNICALL +FUN(Context_setUserCSS)(JNIEnv *env, jclass cls, jstring jcss) +{ + fz_context *ctx = get_context(env); + const char *css = NULL; + + if (jcss) + css = (*env)->GetStringUTFChars(env, jcss, NULL); + + fz_try(ctx) + fz_set_user_css(ctx, css); + fz_always(ctx) + if (jcss) + (*env)->ReleaseStringUTFChars(env, jcss, css); + fz_catch(ctx) + jni_rethrow_void(env, ctx); +} + +JNIEXPORT void JNICALL +FUN(Context_useDocumentCSS)(JNIEnv *env, jclass cls, jboolean state) +{ + fz_context *ctx = get_context(env); + + fz_try(ctx) + fz_set_use_document_css(ctx, state); + fz_catch(ctx) + jni_rethrow_void(env, ctx); +} + +JNIEXPORT jboolean JNICALL +FUN(Context_shrinkStore)(JNIEnv *env, jclass cls, jint percent) +{ + fz_context *ctx = get_context(env); + int success = 0; + + if (!ctx) return JNI_FALSE; + if (percent < 0) jni_throw_arg(env, "percent must not be negative"); + if (percent > 100) jni_throw_arg(env, "percent must not be more than 100"); + + fz_try(ctx) + success = fz_shrink_store(ctx, percent); + fz_catch(ctx) + jni_rethrow(env, ctx); + + return success != 0; +}
