/* * This file is part of libbluray * Copyright (C) 2012 libbluray * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include "util.h" #include "util/logging.h" #include "util/macro.h" #ifdef HAVE_FT2 #include #include FT_FREETYPE_H #endif #ifdef HAVE_FONTCONFIG #include "util/strutl.h" #include #endif #if defined(_WIN32) && defined (HAVE_FT2) #define NEED_WIN32_FONTS #endif #ifdef NEED_WIN32_FONTS #include "file/dirs.h" // win32_get_font_dir #include #endif #include "java_awt_BDFontMetrics.h" /* Disable some warnings */ #if defined __GNUC__ #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #ifdef __cplusplus #define CPP_EXTERN extern #else #define CPP_EXTERN #endif /* * Windows fonts */ #ifdef NEED_WIN32_FONTS typedef struct { int bold; int italic; char *filename; } SEARCH_DATA; static int CALLBACK EnumFontCallbackW(const ENUMLOGFONTEXW *lpelfe, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam) { const LOGFONTW *lplf = &lpelfe->elfLogFont; const wchar_t *font_name = lpelfe->elfFullName; SEARCH_DATA *data = (SEARCH_DATA *)lParam; int index = 0; HKEY hKey; wchar_t wvalue[MAX_PATH]; wchar_t wdata[256]; if (type & RASTER_FONTTYPE) { return 1; } /* match attributes */ if (data->italic >= 0 && (!!lplf->lfItalic != !!data->italic)) { return 1; } if (data->bold >= 0 && ((data->bold && lplf->lfWeight <= FW_MEDIUM) || (!data->bold && lplf->lfWeight >= FW_SEMIBOLD))) { return 1; } if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 0, KEY_READ, &hKey) != ERROR_SUCCESS) { return 0; } while (!data->filename) { DWORD wvalue_len = MAX_PATH - 1; DWORD wdata_len = 255; LONG result = RegEnumValueW(hKey, index++, wvalue, &wvalue_len, NULL, NULL, (LPBYTE)wdata, &wdata_len); if (result != ERROR_SUCCESS) { RegCloseKey(hKey); return result; } if (!_wcsicmp(wvalue, font_name)) { size_t len = WideCharToMultiByte(CP_UTF8, 0, wdata, -1, NULL, 0, NULL, NULL); if (len != 0) { data->filename = (char *)malloc(len); WideCharToMultiByte(CP_UTF8, 0, wdata, -1, data->filename, len, NULL, NULL); break; } } } RegCloseKey(hKey); return 0; } static char *_win32_resolve_font(const char *family, int style) { LOGFONTW lf; HDC hDC; SEARCH_DATA data = {style & 2, style & 1, NULL}; memset(&lf, 0, sizeof(lf)); lf.lfCharSet = DEFAULT_CHARSET; int length = MultiByteToWideChar(CP_UTF8, 0, family, -1, lf.lfFaceName, LF_FACESIZE); if (!length) { return NULL; } hDC = GetDC(NULL); EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)&EnumFontCallbackW, (LPARAM)&data, 0); ReleaseDC(NULL, hDC); if (!data.filename) { return win32_get_font_dir("arial.ttf"); } if (!strchr(data.filename, '\\')) { char *tmp = win32_get_font_dir(data.filename); X_FREE(data.filename); return tmp; } return data.filename; } #endif /* NEED_WIN32_FONTS */ /* * fontconfig */ #ifdef HAVE_FONTCONFIG static FcConfig *_get_fc_lib(JNIEnv * env, jclass cls) { jfieldID fid = (*env)->GetStaticFieldID(env, cls, "fcLib", "J"); jlong fcLib = (*env)->GetStaticLongField (env, cls, fid); FcConfig *lib = (FcConfig *)(intptr_t)fcLib; if (lib) { return lib; } lib = FcInitLoadConfigAndFonts(); (*env)->SetStaticLongField (env, cls, fid, (jlong)(intptr_t)lib); if (!lib) { BD_DEBUG(DBG_BDJ | DBG_CRIT, "Loading fontconfig failed\n"); } return lib; } #endif #ifdef HAVE_FONTCONFIG static void _unload_fc_lib(JNIEnv * env, jclass cls) { jfieldID fid = (*env)->GetStaticFieldID(env, cls, "fcLib", "J"); jlong fcLib = (*env)->GetStaticLongField (env, cls, fid); if (fcLib) { FcConfig *lib = (FcConfig *)(intptr_t)fcLib; (*env)->SetStaticLongField (env, cls, fid, 0); FcConfigDestroy(lib); } } #endif #ifdef HAVE_FONTCONFIG static void _fill_fc_pattern(FcPattern *pat, const char *font_family, jint fontStyle) { int weight = (fontStyle & 1) ? FC_WEIGHT_EXTRABOLD : FC_WEIGHT_NORMAL; int slant = (fontStyle & 2) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN; if (strncmp(font_family, "mono", 4)) { /* mono, monospace, monospaced */ FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)font_family); } else { FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)"monospace"); } FcPatternAddBool (pat, FC_OUTLINE, FcTrue); FcPatternAddInteger(pat, FC_SLANT, slant); FcPatternAddInteger(pat, FC_WEIGHT, weight); } #endif #ifdef HAVE_FONTCONFIG static char *_fontconfig_resolve_font(FcConfig *lib, const char *font_family, jint font_style) { FcResult result = FcResultMatch; FcPattern *pat, *font; FcChar8 *fc_filename = NULL; char *filename = NULL; pat = FcPatternCreate(); if (!pat) { return NULL; } _fill_fc_pattern(pat, font_family, font_style); FcDefaultSubstitute(pat); if (!FcConfigSubstitute(lib, pat, FcMatchPattern)) { FcPatternDestroy(pat); return NULL; } font = FcFontMatch(lib, pat, &result); FcPatternDestroy(pat); if (!font || result == FcResultNoMatch) { return NULL; } if (FcResultMatch == FcPatternGetString(font, FC_FILE, 0, &fc_filename)) { filename = str_dup((const char*)fc_filename); } FcPatternDestroy(font); return filename; } #endif /* * Font resolver */ JNIEXPORT void JNICALL Java_java_awt_BDFontMetrics_unloadFontConfigN(JNIEnv * env, jclass cls) { #ifdef HAVE_FONTCONFIG _unload_fc_lib(env, cls); #endif } JNIEXPORT jstring JNICALL Java_java_awt_BDFontMetrics_resolveFontN(JNIEnv * env, jclass cls, jstring jfont_family, jint font_style) { const char *font_family = (*env)->GetStringUTFChars(env, jfont_family, NULL); char *filename = NULL; jstring jfilename = NULL; #ifdef HAVE_FONTCONFIG FcConfig *lib = _get_fc_lib(env, cls); if (lib) { filename = _fontconfig_resolve_font(lib, font_family, font_style); } #elif defined(NEED_WIN32_FONTS) filename = _win32_resolve_font(font_family, font_style); #else BD_DEBUG(DBG_BDJ | DBG_CRIT, "BD-J font config support not compiled in\n"); #endif if (filename) { jfilename = (*env)->NewStringUTF(env, (const char*)filename); X_FREE(filename); } (*env)->ReleaseStringUTFChars(env, jfont_family, font_family); return jfilename; } /* * Font metrics (freetype) */ JNIEXPORT jlong JNICALL Java_java_awt_BDFontMetrics_initN(JNIEnv * env, jclass cls) { #ifdef HAVE_FT2 FT_Library ftLib; if (!FT_Init_FreeType(&ftLib)) { return (jlong)(intptr_t)ftLib; } BD_DEBUG(DBG_BDJ | DBG_CRIT, "Loading FreeType2 failed\n"); #else BD_DEBUG(DBG_BDJ | DBG_CRIT, "BD-J font support not compiled in\n"); #endif return 0; } JNIEXPORT void JNICALL Java_java_awt_BDFontMetrics_destroyN(JNIEnv * env, jclass cls, jlong ftLib) { #ifdef HAVE_FT2 FT_Library lib = (FT_Library)(intptr_t)ftLib; if (!lib) { return; } FT_Done_FreeType(lib); Java_java_awt_BDFontMetrics_unloadFontConfigN(env, cls); #endif } JNIEXPORT jobjectArray JNICALL Java_java_awt_BDFontMetrics_getFontFamilyAndStyleN(JNIEnv * env, jclass cls, jlong ftLib, jstring fontName) { jobjectArray array = bdj_make_array(env, "java/lang/String", 2); #ifdef HAVE_FT2 const char *name; FT_Face ftFace; FT_Error result; FT_Library lib = (FT_Library)(intptr_t)ftLib; jstring jfamily, jstyle; if (!lib) { return NULL; } name = (*env)->GetStringUTFChars(env, fontName, NULL); result = FT_New_Face(lib, name, 0, &ftFace); (*env)->ReleaseStringUTFChars(env, fontName, name); if (result) { return NULL; } jfamily = (*env)->NewStringUTF(env, ftFace->family_name); jstyle = (*env)->NewStringUTF(env, ftFace->style_name); FT_Done_Face(ftFace); (*env)->SetObjectArrayElement(env, array, 0, jfamily); (*env)->SetObjectArrayElement(env, array, 1, jstyle); #endif return array; } JNIEXPORT jlong JNICALL Java_java_awt_BDFontMetrics_loadFontN(JNIEnv * env, jobject obj, jlong ftLib, jstring fontName, jint size) { #ifdef HAVE_FT2 const char *name; FT_Face ftFace; FT_Error result; jclass cls; jfieldID fid; FT_Library lib = (FT_Library)(intptr_t)ftLib; if (!lib) { return 0; } name = (*env)->GetStringUTFChars(env, fontName, NULL); result = FT_New_Face(lib, name, 0, &ftFace); (*env)->ReleaseStringUTFChars(env, fontName, name); if (result) return 0; FT_Set_Char_Size(ftFace, 0, size << 6, 0, 0); cls = (*env)->GetObjectClass(env, obj); fid = (*env)->GetFieldID(env, cls, "ascent", "I"); (*env)->SetIntField (env, obj, fid, ftFace->size->metrics.ascender >> 6); fid = (*env)->GetFieldID(env, cls, "descent", "I"); (*env)->SetIntField (env, obj, fid, -ftFace->size->metrics.descender >> 6); fid = (*env)->GetFieldID(env, cls, "leading", "I"); (*env)->SetIntField (env, obj, fid, (ftFace->size->metrics.height - ftFace->size->metrics.ascender + ftFace->size->metrics.descender) >> 6); fid = (*env)->GetFieldID(env, cls, "maxAdvance", "I"); (*env)->SetIntField (env, obj, fid, ftFace->size->metrics.max_advance >> 6); return (jlong)(intptr_t)ftFace; #else /* HAVE_FT2 */ return 0; #endif /* HAVE_FT2 */ } JNIEXPORT void JNICALL Java_java_awt_BDFontMetrics_destroyFontN(JNIEnv *env, jobject obj, jlong ftFace) { #ifdef HAVE_FT2 FT_Face face = (FT_Face)(intptr_t)ftFace; if (!face) { return; } FT_Done_Face(face); #endif } JNIEXPORT jint JNICALL Java_java_awt_BDFontMetrics_charWidthN(JNIEnv * env, jobject obj, jlong ftFace, jchar c) { #ifdef HAVE_FT2 FT_Face face = (FT_Face)(intptr_t)ftFace; if (!face) { return 0; } if (FT_Load_Char(face, c, FT_LOAD_DEFAULT)) return 0; return face->glyph->metrics.horiAdvance >> 6; #else return 0; #endif } JNIEXPORT jint JNICALL Java_java_awt_BDFontMetrics_stringWidthN(JNIEnv * env, jobject obj, jlong ftFace, jstring string) { #ifdef HAVE_FT2 jsize length; const jchar *chars; jint i, width; FT_Face face = (FT_Face)(intptr_t)ftFace; if (!face) { return 0; } length = (*env)->GetStringLength(env, string); if (length <= 0) return 0; chars = (*env)->GetStringCritical(env, string, NULL); if (chars == NULL) return 0; for (i = 0, width = 0; i < length; i++) { if (FT_Load_Char(face, chars[i], FT_LOAD_DEFAULT) == 0) { width += face->glyph->metrics.horiAdvance >> 6; } } (*env)->ReleaseStringCritical(env, string, chars); return width; #else /* HAVE_FT2 */ return 0; #endif /* HAVE_FT2 */ } JNIEXPORT jint JNICALL Java_java_awt_BDFontMetrics_charsWidthN(JNIEnv * env, jobject obj, jlong ftFace, jcharArray charArray, jint offset, jint length) { #ifdef HAVE_FT2 jchar *chars; jint i, width; FT_Face face = (FT_Face)(intptr_t)ftFace; if (!face) { return 0; } chars = (jchar *)malloc(sizeof(jchar) * length); if (chars == NULL) return 0; (*env)->GetCharArrayRegion(env, charArray, offset, length, chars); if ((*env)->ExceptionCheck(env)) { free(chars); return 0; } for (i = 0, width = 0; i < length; i++) { if (FT_Load_Char(face, chars[i], FT_LOAD_DEFAULT) == 0) { width += face->glyph->metrics.horiAdvance >> 6; } } free(chars); return width; #else /* HAVE_FT2 */ return 0; #endif /* HAVE_FT2 */ } #define CC (char*)(uintptr_t) /* cast a literal from (const char*) */ #define VC (void*)(uintptr_t) /* cast function pointer to void* */ BD_PRIVATE CPP_EXTERN const JNINativeMethod Java_java_awt_BDFontMetrics_methods[] = { /* AUTOMATICALLY GENERATED */ { CC("initN"), CC("()J"), VC(Java_java_awt_BDFontMetrics_initN), }, { CC("destroyN"), CC("(J)V"), VC(Java_java_awt_BDFontMetrics_destroyN), }, { CC("resolveFontN"), CC("(Ljava/lang/String;I)Ljava/lang/String;"), VC(Java_java_awt_BDFontMetrics_resolveFontN), }, { CC("unloadFontConfigN"), CC("()V"), VC(Java_java_awt_BDFontMetrics_unloadFontConfigN), }, { CC("getFontFamilyAndStyleN"), CC("(JLjava/lang/String;)[Ljava/lang/String;"), VC(Java_java_awt_BDFontMetrics_getFontFamilyAndStyleN), }, { CC("loadFontN"), CC("(JLjava/lang/String;I)J"), VC(Java_java_awt_BDFontMetrics_loadFontN), }, { CC("destroyFontN"), CC("(J)V"), VC(Java_java_awt_BDFontMetrics_destroyFontN), }, { CC("charWidthN"), CC("(JC)I"), VC(Java_java_awt_BDFontMetrics_charWidthN), }, { CC("stringWidthN"), CC("(JLjava/lang/String;)I"), VC(Java_java_awt_BDFontMetrics_stringWidthN), }, { CC("charsWidthN"), CC("(J[CII)I"), VC(Java_java_awt_BDFontMetrics_charsWidthN), }, }; BD_PRIVATE CPP_EXTERN const int Java_java_awt_BDFontMetrics_methods_count = sizeof(Java_java_awt_BDFontMetrics_methods)/sizeof(Java_java_awt_BDFontMetrics_methods[0]);