JNIEXPORT jint JNICALL
Java_sun_font_FontConfigManager_getFontConfigVersion
    (JNIEnv *env, jclass obj) {

    void* libfontconfig;
    FcGetVersionFuncType FcGetVersion;
    int version = 0;

    if ((libfontconfig = openFontConfig()) == NULL) {
        return 0;
    }

    FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");

    if (FcGetVersion == NULL) {
        closeFontConfig(libfontconfig, JNI_FALSE);
        return 0;
    }
    version = (*FcGetVersion)();
    closeFontConfig(libfontconfig, JNI_FALSE);

    return version;
}
JNIEXPORT void JNICALL
Java_sun_font_FontConfigManager_getFontConfig
(JNIEnv *env, jclass obj, jstring localeStr, jobject fcInfoObj,
 jobjectArray fcCompFontArray,  jboolean includeFallbacks) {

    FcNameParseFuncType FcNameParse;
    FcPatternAddStringFuncType FcPatternAddString;
    FcConfigSubstituteFuncType FcConfigSubstitute;
    FcDefaultSubstituteFuncType  FcDefaultSubstitute;
    FcFontMatchFuncType FcFontMatch;
    FcPatternGetStringFuncType FcPatternGetString;
    FcPatternDestroyFuncType FcPatternDestroy;
    FcPatternGetCharSetFuncType FcPatternGetCharSet;
    FcFontSortFuncType FcFontSort;
    FcFontSetDestroyFuncType FcFontSetDestroy;
    FcCharSetUnionFuncType FcCharSetUnion;
    FcCharSetSubtractCountFuncType FcCharSetSubtractCount;
    FcGetVersionFuncType FcGetVersion;
    FcConfigGetCacheDirsFuncType FcConfigGetCacheDirs;
    FcStrListNextFuncType FcStrListNext;
    FcStrListDoneFuncType FcStrListDone;

    int i, arrlen;
    jobject fcCompFontObj;
    jstring fcNameStr, jstr;
    const char *locale, *fcName;
    FcPattern *pattern;
    FcResult result;
    void* libfontconfig;
    jfieldID fcNameID, fcFirstFontID, fcAllFontsID, fcVersionID, fcCacheDirsID;
    jfieldID familyNameID, styleNameID, fullNameID, fontFileID;
    jmethodID fcFontCons;
    char* debugMinGlyphsStr = getenv("J2D_DEBUG_MIN_GLYPHS");

    jclass fcInfoClass =
        (*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigInfo");
    jclass fcCompFontClass =
        (*env)->FindClass(env, "sun/font/FontConfigManager$FcCompFont");
    jclass fcFontClass =
         (*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigFont");

    if (fcInfoObj == NULL || fcCompFontArray == NULL || fcInfoClass == NULL ||
        fcCompFontClass == NULL || fcFontClass == NULL) {
        return;
    }

    fcVersionID = (*env)->GetFieldID(env, fcInfoClass, "fcVersion", "I");

    fcCacheDirsID = (*env)->GetFieldID(env, fcInfoClass, "cacheDirs",
                                       "[Ljava/lang/String;");

    fcNameID = (*env)->GetFieldID(env, fcCompFontClass,
                                  "fcName", "Ljava/lang/String;");
    fcFirstFontID =
        (*env)->GetFieldID(env, fcCompFontClass, "firstFont",
                           "Lsun/font/FontConfigManager$FontConfigFont;");

    fcAllFontsID =
        (*env)->GetFieldID(env, fcCompFontClass, "allFonts",
                           "[Lsun/font/FontConfigManager$FontConfigFont;");

    fcFontCons = (*env)->GetMethodID(env, fcFontClass, "<init>", "()V");

    familyNameID = (*env)->GetFieldID(env, fcFontClass,
                                      "familyName", "Ljava/lang/String;");
    styleNameID = (*env)->GetFieldID(env, fcFontClass,
                                    "styleStr", "Ljava/lang/String;");
    fullNameID = (*env)->GetFieldID(env, fcFontClass,
                                    "fullName", "Ljava/lang/String;");
    fontFileID = (*env)->GetFieldID(env, fcFontClass,
                                    "fontFile", "Ljava/lang/String;");

    if (fcVersionID == NULL || fcCacheDirsID == NULL || fcNameID == NULL ||
        fcFirstFontID == NULL || fcAllFontsID == NULL || fcFontCons == NULL ||
        familyNameID == NULL || styleNameID == NULL || fullNameID == NULL ||
        fontFileID == NULL) {
        return;
    }

    if ((libfontconfig = openFontConfig()) == NULL) {
        return;
    }

    FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");
    FcPatternAddString =
        (FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");
    FcConfigSubstitute =
        (FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");
    FcDefaultSubstitute = (FcDefaultSubstituteFuncType)
        dlsym(libfontconfig, "FcDefaultSubstitute");
    FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");
    FcPatternGetString =
        (FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");
    FcPatternDestroy =
        (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");
    FcPatternGetCharSet =
        (FcPatternGetCharSetFuncType)dlsym(libfontconfig,
                                           "FcPatternGetCharSet");
    FcFontSort =
        (FcFontSortFuncType)dlsym(libfontconfig, "FcFontSort");
    FcFontSetDestroy =
        (FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");
    FcCharSetUnion =
        (FcCharSetUnionFuncType)dlsym(libfontconfig, "FcCharSetUnion");
    FcCharSetSubtractCount =
        (FcCharSetSubtractCountFuncType)dlsym(libfontconfig,
                                              "FcCharSetSubtractCount");
    FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");

    if (FcNameParse          == NULL ||
        FcPatternAddString   == NULL ||
        FcConfigSubstitute   == NULL ||
        FcDefaultSubstitute  == NULL ||
        FcFontMatch          == NULL ||
        FcPatternGetString   == NULL ||
        FcPatternDestroy     == NULL ||
        FcPatternGetCharSet  == NULL ||
        FcFontSetDestroy     == NULL ||
        FcCharSetUnion       == NULL ||
        FcGetVersion         == NULL ||
        FcCharSetSubtractCount == NULL) {/* problem with the library: return.*/
        closeFontConfig(libfontconfig, JNI_FALSE);
        return;
    }

    (*env)->SetIntField(env, fcInfoObj, fcVersionID, (*FcGetVersion)());

    /* Optionally get the cache dir locations. This isn't
     * available until v 2.4.x, but this is OK since on those later versions
     * we can check the time stamps on the cache dirs to see if we
     * are out of date. There are a couple of assumptions here. First
     * that the time stamp on the directory changes when the contents are
     * updated. Secondly that the locations don't change. The latter is
     * most likely if a new version of fontconfig is installed, but we also
     * invalidate the cache if we detect that. Arguably even that is "rare",
     * and most likely is tied to an OS upgrade which gets a new file anyway.
     */
    FcConfigGetCacheDirs =
        (FcConfigGetCacheDirsFuncType)dlsym(libfontconfig,
                                            "FcConfigGetCacheDirs");
    FcStrListNext =
        (FcStrListNextFuncType)dlsym(libfontconfig, "FcStrListNext");
    FcStrListDone =
        (FcStrListDoneFuncType)dlsym(libfontconfig, "FcStrListDone");
    if (FcStrListNext != NULL && FcStrListDone != NULL &&
        FcConfigGetCacheDirs != NULL) {

        FcStrList* cacheDirs;
        FcChar8* cacheDir;
        int cnt = 0;
        jobject cacheDirArray =
            (*env)->GetObjectField(env, fcInfoObj, fcCacheDirsID);
        int max = (*env)->GetArrayLength(env, cacheDirArray);

        cacheDirs = (*FcConfigGetCacheDirs)(NULL);
        if (cacheDirs != NULL) {
            while ((cnt < max) && (cacheDir = (*FcStrListNext)(cacheDirs))) {
                jstr = (*env)->NewStringUTF(env, (const char*)cacheDir);
                (*env)->SetObjectArrayElement(env, cacheDirArray, cnt++, jstr);
            }
            (*FcStrListDone)(cacheDirs);
        }
    }

    locale = (*env)->GetStringUTFChars(env, localeStr, 0);

    arrlen = (*env)->GetArrayLength(env, fcCompFontArray);
    for (i=0; i<arrlen; i++) {
        FcFontSet* fontset;
        int fn, j, fontCount, nfonts;
        unsigned int minGlyphs;
        FcChar8 **family, **styleStr, **fullname, **file;
        jarray fcFontArr;

        fcCompFontObj = (*env)->GetObjectArrayElement(env, fcCompFontArray, i);
        fcNameStr =
            (jstring)((*env)->GetObjectField(env, fcCompFontObj, fcNameID));
        fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);
        if (fcName == NULL) {
            continue;
        }
        pattern = (*FcNameParse)((FcChar8 *)fcName);
        if (pattern == NULL) {
            (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
            closeFontConfig(libfontconfig, JNI_FALSE);
            return;
        }

        /* locale may not usually be necessary as fontconfig appears to apply
         * this anyway based on the user's environment. However we want
         * to use the value of the JDK startup locale so this should take
         * care of it.
         */
        if (locale != NULL) {
            (*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);
        }
        (*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);
        (*FcDefaultSubstitute)(pattern);
        fontset = (*FcFontSort)(NULL, pattern, FcTrue, NULL, &result);
        if (fontset == NULL) {
            (*FcPatternDestroy)(pattern);
            (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
            closeFontConfig(libfontconfig, JNI_FALSE);
            return;
        }

        /* fontconfig returned us "nfonts". If we are just getting the
         * first font, we set nfont to zero. Otherwise we use "nfonts".
         * Next create separate C arrrays of length nfonts for family file etc.
         * Inspect the returned fonts and the ones we like (adds enough glyphs)
         * are added to the arrays and we increment 'fontCount'.
         */
        nfonts = fontset->nfont;
        family   = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
        styleStr = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
        fullname = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
        file     = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
        if (family == NULL || styleStr == NULL ||
            fullname == NULL || file == NULL) {
            if (family != NULL) {
                free(family);
            }
            if (styleStr != NULL) {
                free(styleStr);
            }
            if (fullname != NULL) {
                free(fullname);
            }
            if (file != NULL) {
                free(file);
            }
            (*FcPatternDestroy)(pattern);
            (*FcFontSetDestroy)(fontset);
            (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
            closeFontConfig(libfontconfig, JNI_FALSE);
            return;
        }
        fontCount = 0;
        minGlyphs = 20;
        if (debugMinGlyphsStr != NULL) {
            int val = minGlyphs;
            sscanf(debugMinGlyphsStr, "%5d", &val);
            if (val >= 0 && val <= 65536) {
                minGlyphs = val;
            }
        }
        for (j=0; j<nfonts; j++) {
            FcPattern *fontPattern = fontset->fonts[j];
            FcChar8 *fontformat;
            FcCharSet *unionCharset = NULL, *charset;

            fontformat = NULL;
            (*FcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat);
            /* We only want TrueType fonts but some Linuxes still depend
             * on Type 1 fonts for some Locale support, so we'll allow
             * them there.
             */
            if (fontformat != NULL
                && (strcmp((char*)fontformat, "TrueType") != 0)
#ifdef __linux__
                && (strcmp((char*)fontformat, "Type 1") != 0)
#endif
             ) {
                continue;
            }
            result = (*FcPatternGetCharSet)(fontPattern,
                                            FC_CHARSET, 0, &charset);
            if (result != FcResultMatch) {
                free(family);
                free(family);
                free(styleStr);
                free(file);
                (*FcPatternDestroy)(pattern);
                (*FcFontSetDestroy)(fontset);
                (*env)->ReleaseStringUTFChars(env,
                                              fcNameStr, (const char*)fcName);
                closeFontConfig(libfontconfig, JNI_FALSE);
                return;
            }

            /* We don't want 20 or 30 fonts, so once we hit 10 fonts,
             * then require that they really be adding value. Too many
             * adversely affects load time for minimal value-add.
             * This is still likely far more than we've had in the past.
             */
            if (j==10) {
                minGlyphs = 50;
            }
            if (unionCharset == NULL) {
                unionCharset = charset;
            } else {
                if ((*FcCharSetSubtractCount)(charset, unionCharset)
                    > minGlyphs) {
                    unionCharset = (* FcCharSetUnion)(unionCharset, charset);
                } else {
                    continue;
                }
            }

            fontCount++; // found a font we will use.
            (*FcPatternGetString)(fontPattern, FC_FILE, 0, &file[j]);
            (*FcPatternGetString)(fontPattern, FC_FAMILY, 0, &family[j]);
            (*FcPatternGetString)(fontPattern, FC_STYLE, 0, &styleStr[j]);
            (*FcPatternGetString)(fontPattern, FC_FULLNAME, 0, &fullname[j]);
            if (!includeFallbacks) {
                break;
            }
        }

        /* Once we get here 'fontCount' is the number of returned fonts
         * we actually want to use, so we create 'fcFontArr' of that length.
         * The non-null entries of "family[]" etc are those fonts.
         * Then loop again over all nfonts adding just those non-null ones
         * to 'fcFontArr'. If its null (we didn't want the font)
         * then we don't enter the main body.
         * So we should never get more than 'fontCount' entries.
         */
        if (includeFallbacks) {
            fcFontArr =
                (*env)->NewObjectArray(env, fontCount, fcFontClass, NULL);
            (*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr);
        }
        fn=0;

        for (j=0;j<nfonts;j++) {
            if (family[j] != NULL) {
                jobject fcFont =
                    (*env)->NewObject(env, fcFontClass, fcFontCons);
                jstr = (*env)->NewStringUTF(env, (const char*)family[j]);
                (*env)->SetObjectField(env, fcFont, familyNameID, jstr);
                if (file[j] != NULL) {
                    jstr = (*env)->NewStringUTF(env, (const char*)file[j]);
                    (*env)->SetObjectField(env, fcFont, fontFileID, jstr);
                }
                if (styleStr[j] != NULL) {
                    jstr = (*env)->NewStringUTF(env, (const char*)styleStr[j]);
                    (*env)->SetObjectField(env, fcFont, styleNameID, jstr);
                }
                if (fullname[j] != NULL) {
                    jstr = (*env)->NewStringUTF(env, (const char*)fullname[j]);
                    (*env)->SetObjectField(env, fcFont, fullNameID, jstr);
                }
                if (fn==0) {
                    (*env)->SetObjectField(env, fcCompFontObj,
                                           fcFirstFontID, fcFont);
                }
                if (includeFallbacks) {
                    (*env)->SetObjectArrayElement(env, fcFontArr, fn++,fcFont);
                } else {
                    break;
                }
            }
        }
        (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
        (*FcFontSetDestroy)(fontset);
        (*FcPatternDestroy)(pattern);
        free(family);
        free(styleStr);
        free(fullname);
        free(file);
    }

    /* release resources and close the ".so" */

    if (locale) {
        (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);
    }
    closeFontConfig(libfontconfig, JNI_TRUE);
}
JNIEXPORT jint JNICALL
Java_sun_font_FontConfigManager_getFontConfigAASettings
(JNIEnv *env, jclass obj, jstring localeStr, jstring fcNameStr) {

    FcNameParseFuncType FcNameParse;
    FcPatternAddStringFuncType FcPatternAddString;
    FcConfigSubstituteFuncType FcConfigSubstitute;
    FcDefaultSubstituteFuncType  FcDefaultSubstitute;
    FcFontMatchFuncType FcFontMatch;
    FcPatternGetBoolFuncType FcPatternGetBool;
    FcPatternGetIntegerFuncType FcPatternGetInteger;
    FcPatternDestroyFuncType FcPatternDestroy;

    FcPattern *pattern, *matchPattern;
    FcResult result;
    FcBool antialias = FcFalse;
    int rgba = 0;
    const char *locale=NULL, *fcName=NULL;
    void* libfontconfig;

    if (fcNameStr == NULL || localeStr == NULL) {
        return -1;
    }

    fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);
    if (fcName == NULL) {
        return -1;
    }
    locale = (*env)->GetStringUTFChars(env, localeStr, 0);

    if ((libfontconfig = openFontConfig()) == NULL) {
        (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
        if (locale) {
            (*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale);
        }
        return -1;
    }

    FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");
    FcPatternAddString =
        (FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");
    FcConfigSubstitute =
        (FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");
    FcDefaultSubstitute = (FcDefaultSubstituteFuncType)
        dlsym(libfontconfig, "FcDefaultSubstitute");
    FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");
    FcPatternGetBool = (FcPatternGetBoolFuncType)
        dlsym(libfontconfig, "FcPatternGetBool");
    FcPatternGetInteger = (FcPatternGetIntegerFuncType)
        dlsym(libfontconfig, "FcPatternGetInteger");
    FcPatternDestroy =
        (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");

    if (FcNameParse          == NULL ||
        FcPatternAddString   == NULL ||
        FcConfigSubstitute   == NULL ||
        FcDefaultSubstitute  == NULL ||
        FcFontMatch          == NULL ||
        FcPatternGetBool     == NULL ||
        FcPatternGetInteger  == NULL ||
        FcPatternDestroy     == NULL) { /* problem with the library: return. */

        (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
        if (locale) {
            (*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale);
        }
        closeFontConfig(libfontconfig, JNI_FALSE);
        return -1;
    }


    pattern = (*FcNameParse)((FcChar8 *)fcName);
    if (locale != NULL) {
        (*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);
    }
    (*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);
    (*FcDefaultSubstitute)(pattern);
    matchPattern = (*FcFontMatch)(NULL, pattern, &result);
    /* Perhaps should call FcFontRenderPrepare() here as some pattern
     * elements might change as a result of that call, but I'm not seeing
     * any difference in testing.
     */
    if (matchPattern) {
        (*FcPatternGetBool)(matchPattern, FC_ANTIALIAS, 0, &antialias);
        (*FcPatternGetInteger)(matchPattern, FC_RGBA, 0, &rgba);
        (*FcPatternDestroy)(matchPattern);
    }
    (*FcPatternDestroy)(pattern);

    (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
    if (locale) {
        (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);
    }
    closeFontConfig(libfontconfig, JNI_TRUE);

    if (antialias == FcFalse) {
        return TEXT_AA_OFF;
    } else if (rgba <= FC_RGBA_UNKNOWN || rgba >= FC_RGBA_NONE) {
        return TEXT_AA_ON;
    } else {
        switch (rgba) {
        case FC_RGBA_RGB : return TEXT_AA_LCD_HRGB;
        case FC_RGBA_BGR : return TEXT_AA_LCD_HBGR;
        case FC_RGBA_VRGB : return TEXT_AA_LCD_VRGB;
        case FC_RGBA_VBGR : return TEXT_AA_LCD_VBGR;
        default : return TEXT_AA_LCD_HRGB; // should not get here.
        }
    }
}
JNIEXPORT void JNICALL
Java_sun_font_FontManager_getFontConfig
(JNIEnv *env, jclass obj, jstring localeStr, jobjectArray fontInfoArray) {

    FcNameParseFuncType FcNameParse;
    FcPatternAddStringFuncType FcPatternAddString;
    FcConfigSubstituteFuncType FcConfigSubstitute;
    FcDefaultSubstituteFuncType  FcDefaultSubstitute;
    FcFontMatchFuncType FcFontMatch;
    FcPatternGetStringFuncType FcPatternGetString;
    FcPatternDestroyFuncType FcPatternDestroy;

    int i, arrlen;
    jobject fontInfoObj;
    jstring fcNameStr, jstr;
    const char *locale, *fcName;
    FcPattern *pattern, *matchPattern;
    FcResult result;
    void* libfontconfig;
    jfieldID fcNameID, familyNameID, fontFileID;

    jclass fontInfoArrayClass =
        (*env)->FindClass(env, "[Lsun/font/FontManager$FontConfigInfo;");
    jclass fontInfoClass =
        (*env)->FindClass(env, "sun/font/FontManager$FontConfigInfo");

    if (fontInfoArray == NULL || fontInfoClass == NULL) {
        return;
    }

    fcNameID = (*env)->GetFieldID(env, fontInfoClass,
                                  "fcName", "Ljava/lang/String;");
    familyNameID = (*env)->GetFieldID(env, fontInfoClass,
                                      "familyName", "Ljava/lang/String;");
    fontFileID = (*env)->GetFieldID(env, fontInfoClass,
                                    "fontFile", "Ljava/lang/String;");

    if (fcNameID == NULL || familyNameID == NULL || fontFileID == NULL) {
        return;
    }

    if ((libfontconfig = openFontConfig()) == NULL) {
        return;
    }

    FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");
    FcPatternAddString =
        (FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");
    FcConfigSubstitute =
        (FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");
    FcDefaultSubstitute = (FcDefaultSubstituteFuncType)
        dlsym(libfontconfig, "FcDefaultSubstitute");
    FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");
    FcPatternGetString =
        (FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");
    FcPatternDestroy =
        (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");

    if (FcNameParse          == NULL ||
        FcPatternAddString   == NULL ||
        FcConfigSubstitute   == NULL ||
        FcDefaultSubstitute  == NULL ||
        FcFontMatch          == NULL ||
        FcPatternGetString   == NULL ||
        FcPatternDestroy     == NULL) { /* problem with the library: return. */
        closeFontConfig(libfontconfig, JNI_FALSE);
        return;
    }

    locale = (*env)->GetStringUTFChars(env, localeStr, 0);

    arrlen = (*env)->GetArrayLength(env, fontInfoArray);
    for (i=0; i<arrlen; i++) {
        fontInfoObj = (*env)->GetObjectArrayElement(env, fontInfoArray, i);
        fcNameStr =
            (jstring)((*env)->GetObjectField(env, fontInfoObj, fcNameID));
        fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);
        if (fcName == NULL) {
            continue;
        }
        pattern = (*FcNameParse)((FcChar8 *)fcName);
        /* locale may not usually be necessary as fontconfig appears to apply
         * this anyway based on the user's environment. However we want
         * to use the value of the JDK startup locale so this should take
         * care of it.
         */
        if (locale != NULL) {
            (*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);
        }
        (*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);
        (*FcDefaultSubstitute)(pattern);
        matchPattern = (*FcFontMatch)(NULL, pattern, &result);
        if (matchPattern) {
            FcChar8 *file, *family;

            (*FcPatternGetString)(matchPattern, FC_FILE, 0, &file);
            (*FcPatternGetString)(matchPattern, FC_FAMILY, 0, &family);

            if (file != NULL) {
                jstr = (*env)->NewStringUTF(env, (const char*)file);
                ((*env)->SetObjectField(env, fontInfoObj, fontFileID, jstr));
            }
            if (family != NULL) {
                jstr = (*env)->NewStringUTF(env, (const char*)family);
                ((*env)->SetObjectField(env, fontInfoObj, familyNameID, jstr));
            }
            (*FcPatternDestroy)(matchPattern);
        }
        (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
        (*FcPatternDestroy)(pattern);
    }

    /* release resources and close the ".so" */

    if (locale) {
        (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);
    }
    closeFontConfig(libfontconfig, JNI_TRUE);
}