/* vi: set sw=4 ts=4: */ /* * CCE - Console Chinese Environment - * Copyright (C) 1998-2003 Rui He (rhe@3eti.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include "defs.h" #include "vc.h" #include "errors.h" #ifdef SUPPORT_FREETYPE_FONT #include "ftfont.h" #include "encfilter.h" #ifdef HAVE_ICONV_H #include #endif #define DEF_RENDER_MODE FT_RENDER_MODE_NORMAL /* FT_RENDER_MODE_MONO */ int UseTTFont, TTFontSize; char *TTFontPathName; int DoAntiAlias = 1; /* Set it to 0 if not doing Anti-Alias */ int ftXOrig, ftYOrig; /* X/Y Origin offset */ static FT_Library ftLibrary; static FT_Face ftFace; #ifdef USE_DYNAMIC_FREETYPELIB static FT_Error (*p_FT_Init_FreeType)( FT_Library *alibrary ); static FT_Error (*p_FT_New_Face)( FT_Library library, const char* filepathname, FT_Long face_index, FT_Face *aface ); static FT_Error (*p_FT_Done_FreeType)( FT_Library library ); static FT_Error (*p_FT_Set_Pixel_Sizes)( FT_Face face, FT_UInt pixel_width, FT_UInt pixel_height ); static FT_Error (*p_FT_Select_Charmap)( FT_Face face, FT_Encoding encoding ); static FT_UInt (*p_FT_Get_Char_Index)( FT_Face face, FT_ULong charcode); static FT_Error (*p_FT_Load_Glyph)( FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags); static FT_Error (*p_FT_Render_Glyph)( FT_GlyphSlot slot, FT_Render_Mode render_mode ); static void *ftLibHandle; static char *ftLibSearchPath[] = { #if defined(__WINDOWS__) "freetype.dll", #else "libfreetype.so", "libfreetype.so.6", "/usr/local/lib/libfreetype.so", "/usr/local/lib/libfreetype.so.6", #endif NULL, }; static int LoadDynamicFreeTypeLibrary(void) { int i; for(i = 0; ftLibSearchPath[i]; i++) { ftLibHandle = dlopen(ftLibSearchPath[i], RTLD_LAZY); if (ftLibHandle) break; } if (!ftLibHandle) { message("Failed to load FREETYPE library %s.\r\n", ftLibSearchPath[0]); return FAILURE; } p_FT_Init_FreeType = dlsym(ftLibHandle, SYMBOL_FT_INIT_FREETYPE ); p_FT_New_Face = dlsym(ftLibHandle, SYMBOL_FT_NEW_FACE ); p_FT_Done_FreeType = dlsym(ftLibHandle, SYMBOL_FT_DONE_FREETYPE ); p_FT_Set_Pixel_Sizes = dlsym(ftLibHandle, SYMBOL_FT_SET_PIXEL_SIZES); p_FT_Select_Charmap = dlsym(ftLibHandle, SYMBOL_FT_SELECT_CHARMAP ); p_FT_Get_Char_Index = dlsym(ftLibHandle, SYMBOL_FT_GET_CHAR_INDEX ); p_FT_Load_Glyph = dlsym(ftLibHandle, SYMBOL_FT_LOAD_GLYPH ); p_FT_Render_Glyph = dlsym(ftLibHandle, SYMBOL_FT_RENDER_GLYPH ); if (!p_FT_Init_FreeType || !p_FT_New_Face || !p_FT_Done_FreeType || !p_FT_Set_Pixel_Sizes || !p_FT_Select_Charmap || !p_FT_Get_Char_Index || !p_FT_Load_Glyph || !p_FT_Render_Glyph) { warn("Can't resolve all the required FreeType routines.\r\n"); dlclose(ftLibHandle); ftLibHandle = NULL; return FAILURE; } return SUCCESS; } static void UnloadDynamicFreeTypeLibrary(void) { if (ftLibHandle) { dlclose(ftLibHandle); ftLibHandle = NULL; } } #endif /* USE_DYNAMIC_FREETYPELIB */ static iconv_t IconvCdAry[CODE_NUM]; /* converstion descriptor from encoding to Unicode */ #define TARGET_ICONV_ENCODING "UTF-16BE" /* UTF-16 may get LE or BE! */ int FreetypeGetGlyph(int encoding, int ch1, int ch2, FT_GlyphSlot *glyph) { static char inbuf[8], outbuf[8], *inptr, *outptr; size_t inleft, outleft; FT_UInt glyph_index; *glyph = NULL; if (ch1 == 0) return -1; /* Empty box */ if (ch2) /* double byte */ { #ifdef HAVE_ICONV if (!IconvCdAry[encoding]) { int i; iconv_t cd; for(i = 0; IconvSrcEncoding[encoding][i]; i++) { if ((cd = iconv_open(TARGET_ICONV_ENCODING, IconvSrcEncoding[encoding][i])) != (iconv_t)-1) break; } if (cd == (iconv_t)-1) { warn("Failed to iconv_open(%s,%s).\r\n", TARGET_ICONV_ENCODING, IconvSrcEncoding[encoding][0]); return -1; } IconvCdAry[encoding] = cd; inbuf[0] = 0x20; /* ASCII SPACE */ inptr = inbuf; outptr = outbuf; inleft = 1; outleft = sizeof(outbuf); iconv(cd, &inptr, &inleft, &outptr, &outleft); /* UTF prefix 0xFE 0xFF */ } inbuf[0] = (u_char)(ch1); inbuf[1] = (u_char)(ch2); inptr = inbuf; outptr = outbuf; inleft = 2; outleft = sizeof(outbuf); if (iconv(IconvCdAry[encoding], &inptr, &inleft, &outptr, &outleft) == (size_t)-1) { #ifdef DEBUG warn("iconv failed: encoding=%d char=0x%02X%02X errno=%d\n", encoding, ch1, ch2, errno); #endif return -1; } ch1 = ((u_char)(outbuf[0]) << 8 | (u_char)(outbuf[1])); /* BE! byte stream */ #else /* HAVE_ICONV */ return -1; #endif } glyph_index = FT_GET_CHAR_INDEX(ftFace, ch1); /* return 0 for undefined glyph */ if (glyph_index == 0 || FT_LOAD_GLYPH(ftFace, glyph_index, FT_LOAD_DEFAULT) || FT_RENDER_GLYPH(ftFace->glyph, DEF_RENDER_MODE)) { #ifdef DEBUG warn("FT_Load_Glyph/Render_Glyph failed Unicode=0x%04X glyph=%d errno=%d\n", ch1, glyph_index, errno); #endif return -1; } *glyph = ftFace->glyph; return 0; } #define FT_ROUNDUP(n, f, EM) ((n)*(f)) % EM ? ((n)*(f))/EM+1 : ((n)*(f))/EM int FreetypeInit (char *fontfile, int fontsize) { #ifdef USE_DYNAMIC_FREETYPELIB if (LoadDynamicFreeTypeLibrary() != SUCCESS) return FAILURE; #endif if (FT_INIT_FREETYPE (&ftLibrary)) { warn("Failed to initialize FreeType library.\r\n"); goto err2; } if (FT_NEW_FACE (ftLibrary, fontfile, 0, &ftFace)) { warn("Failed to open TrueType font %s, errno=%d\r\n", fontfile, errno); goto err; } if (!FT_IS_SCALABLE (ftFace)) { warn("Font %s is not scalable, not TrueType font?\r\n", fontfile); goto err; } if (fontsize <= 0) fontsize = DEFAULT_TTFONT_SIZE; if (fontsize < MIN_TTFONT_SIZE) fontsize = MIN_TTFONT_SIZE; if (fontsize > MAX_TTFONT_SIZE) fontsize = MAX_TTFONT_SIZE; if (FT_SET_PIXEL_SIZES (ftFace, fontsize, fontsize)) /* square shape */ { warn("Failed to do FT_Set_Pixel_Sizes(%d,%d)\r\n", fontsize, fontsize); goto err; } FT_SELECT_CHARMAP(ftFace, FT_ENCODING_UNICODE); /* necessary ? */ ftXOrig = 0; ftYOrig = FT_ROUNDUP(ftFace->bbox.yMax, fontsize, ftFace->units_per_EM); message("Using TrueType font %s, AntiAlias=%s\r\n", fontfile, DoAntiAlias ? "Yes" : "No"); #ifdef DEBUG message("Font family %s, %d glyphs, size %dx%d, yorig=%d.\r\n", ftFace->family_name, ftFace->num_glyphs, fontsize, fontsize, ftYOrig); #endif fontwidth = fontsize/2; fontheight = fontsize; return SUCCESS; err: FT_DONE_FREETYPE (ftLibrary); ftLibrary = NULL; err2: #ifdef USE_DYNAMIC_FREETYPELIB UnloadDynamicFreeTypeLibrary(); #endif return FAILURE; } void FreetypeCleanup (void) { int i; #ifdef HAVE_ICONV for(i = 0; i < CODE_NUM; i++) { if (IconvCdAry[i]) iconv_close(IconvCdAry[i]); IconvCdAry[i] = NULL; } #endif if (ftLibrary) { FT_DONE_FREETYPE (ftLibrary); ftLibrary = NULL; } #ifdef USE_DYNAMIC_FREETYPELIB UnloadDynamicFreeTypeLibrary(); #endif } #endif /* SUPPORT_FREETYPE_FONT */