/* * ftlib.c * * This file is part of the ttf2pk package. * * Copyright 1997-1999, 2000, 2002, 2003 by * Frederic Loyer * Werner Lemberg * * Copyright (C) 2012 by * Peter Breitenlohner */ #include #include #include #include #include #include FT_FREETYPE_H #include FT_TRUETYPE_TABLES_H #include FT_OPENTYPE_VALIDATE_H #include "ttf2tfm.h" #include "ttfenc.h" #include "errormsg.h" #include "newobj.h" #include "ftlib.h" #define Macintosh_platform 1 #define Macintosh_encoding 0 #define Microsoft_platform 3 #define Microsoft_Symbol_encoding 0 #define Microsoft_Unicode_encoding 1 #define TTAG_GSUB FT_MAKE_TAG('G', 'S', 'U', 'B') #define SCRIPT_kana FT_MAKE_TAG('k', 'a', 'n', 'a') #define SCRIPT_hani FT_MAKE_TAG('h', 'a', 'n', 'i') #define SCRIPT_hang FT_MAKE_TAG('h', 'a', 'n', 'g') #define LANGUAGE_JAN FT_MAKE_TAG('J', 'A', 'N', ' ') #define LANGUAGE_CHN FT_MAKE_TAG('C', 'H', 'N', ' ') #define LANGUAGE_KOR FT_MAKE_TAG('K', 'O', 'R', ' ') #define FEATURE_vert FT_MAKE_TAG('v', 'e', 'r', 't') FT_Library engine; FT_Face face; FT_Matrix matrix1, matrix2; int dpi, ptsize; Boolean has_gsub; TT_OS2 *os2; TT_Postscript *postscript; FT_Byte *GSUB_table; FT_ULong GSUB_length; FT_ULong GSUB_ptr; FT_ULong Script_List_ptr; FT_ULong Feature_List_ptr; FT_ULong Lookup_List_ptr; static inline void need (FT_ULong needed) { if (GSUB_ptr + needed > GSUB_length) oops("GSUB: Unexpected end of table."); } static inline FT_Byte get_Byte(void) { return GSUB_table[GSUB_ptr++]; } static inline signed char get_SByte(void) { return (signed char) GSUB_table[GSUB_ptr++]; } static FT_UShort get_UShort(void) { unsigned int cc; cc = get_Byte() << 8; cc |= get_Byte(); return (FT_UShort) cc; } #if 0 /* unised */ static FT_Short get_Short(void) { int cc; cc = get_SByte() << 8; cc |= get_Byte(); return (FT_Short) cc; } #endif static FT_ULong get_ULong(void) { unsigned int cc; cc = get_Byte() << 24; cc |= get_Byte() << 16; cc |= get_Byte() << 8; cc |= get_Byte(); return (FT_ULong) cc; } #if 0 /* unised */ static FT_Long get_Long(void) { int cc; cc = get_SByte() << 24; cc |= get_Byte() << 16; cc |= get_Byte() << 8; cc |= get_Byte(); return (FT_Long) cc; } #endif #if 0 FT_UShort in_string[2]; TTO_GSUBHeader gsub_; TTO_GSUBHeader *gsub; TTO_GSUB_String in, out; #endif void FTopen (char *filename, Font *fnt, Boolean do_tfm, Boolean quiet) { FT_Error error; int i; unsigned short num_cmap, cmap_plat=0, cmap_enc=0; #if 0 FT_UShort script_index, language_index, feature_index; FT_UShort req_feature_index = 0xFFFF; #endif if ((error = FT_Init_FreeType(&engine))) oops("Cannot initialize FreeType engine (error code = 0x%x).", error); #if 0 if (fnt->rotate) if ((error = FT_Init_GSUB_Extension(engine))) oops("Cannot initialize GSUB support (error code = 0x%x).", error); #endif /* * Load face. */ if ((error = FT_New_Face(engine, filename, 0, &face))) oops("Cannot open `%s'.", filename); if (face->num_faces == 1) { if (fnt->fontindex != 0) { warning("This isn't a TrueType collection.\n" "Parameter `%s' is ignored.", do_tfm ? "-f" : "Fontindex"); fnt->fontindex = 0; } fnt->fontindexparam = NULL; } else { if (fnt->fontindex != 0) { /* * Now we try to open the proper font in a collection. */ FT_Done_Face(face); if ((error = FT_New_Face(engine, filename, (FT_Long)fnt->fontindex, &face))) oops("Cannot open font %lu in TrueType Collection `%s'.", fnt->fontindex, filename); } } if (do_tfm) { /* * Get the OS/2 table. */ if ((os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2)) == NULL) oops("Cannot find OS/2 table for `%s'.", filename); /* * Get the Postscript table. */ if ((postscript = FT_Get_Sfnt_Table(face, ft_sfnt_post)) == NULL) oops("Cannot find Postscript table for `%s'.", filename); } if ((error = FT_Set_Char_Size(face, ptsize * 64, ptsize * 64, dpi, dpi))) oops("Cannot set character size (error code = 0x%x).", error); matrix1.xx = (FT_Fixed)(floor(fnt->efactor * 1024) * (1<<16)/1024); matrix1.xy = (FT_Fixed)(floor(fnt->slant * 1024) * (1<<16)/1024); matrix1.yx = (FT_Fixed)0; matrix1.yy = (FT_Fixed)(1<<16); if (fnt->rotate) { matrix2.xx = 0; matrix2.yx = 1L << 16; matrix2.xy = -matrix2.yx; matrix2.yy = matrix2.xx; } if (do_tfm) { fnt->units_per_em = face->units_per_EM; fnt->fixedpitch = postscript->isFixedPitch; fnt->italicangle = postscript->italicAngle / 65536.0; fnt->xheight = os2->sxHeight * 1000 / fnt->units_per_em; } if (fnt->PSnames != Only) { num_cmap = face->num_charmaps; for (i = 0; i < num_cmap; i++) { cmap_plat=face->charmaps[i]->platform_id; cmap_enc=face->charmaps[i]->encoding_id; if (cmap_plat == fnt->pid && cmap_enc == fnt->eid) break; } if (i == num_cmap) { fprintf(stderr, "%s: ERROR: Invalid platform and/or encoding ID.\n", progname); if (num_cmap == 1) fprintf(stderr, " The only valid PID/EID pair is"); else fprintf(stderr, " Valid PID/EID pairs are:\n"); for (i = 0; i < num_cmap; i++) { cmap_plat=face->charmaps[i]->platform_id; cmap_enc=face->charmaps[i]->encoding_id; fprintf(stderr, " (%i,%i)\n", cmap_plat, cmap_enc); } fprintf(stderr, "\n"); exit(1); } if ((error = FT_Set_Charmap(face, face->charmaps[i]))) oops("Cannot load cmap (error code = 0x%x).", error); } if (fnt->PSnames) { if (!FT_HAS_GLYPH_NAMES(face)) oops("This font does not support PS names."); } else if (cmap_plat == Microsoft_platform && cmap_enc == Microsoft_Unicode_encoding) set_encoding_scheme(encUnicode, fnt); else if (cmap_plat == Macintosh_platform && cmap_enc == Macintosh_encoding) set_encoding_scheme(encMac, fnt); else set_encoding_scheme(encFontSpecific, fnt); if (fnt->rotate) { if ((error = FT_Load_Sfnt_Table(face, TTAG_GSUB, 0, NULL, &GSUB_length))) { warning("No GSUB data available " "for vertical glyph presentation forms."); return; } GSUB_table = mymalloc(GSUB_length); if ((error = FT_Load_Sfnt_Table(face, TTAG_GSUB, 0, GSUB_table, &GSUB_length))) { warning("Cannot load GSUB table (error code = 0x%x).", error); return; } need(10); if (get_ULong() != 0x00010000) oops("GSUB: Bad version."); Script_List_ptr = get_UShort(); warning("GSUB: Script List at 0x%04x.", Script_List_ptr); Feature_List_ptr = get_UShort(); warning("GSUB: Feature List at 0x%04x.", Feature_List_ptr); Lookup_List_ptr = get_UShort(); warning("GSUB: Lookup List at 0x%04x.", Lookup_List_ptr); GSUB_ptr = Script_List_ptr; need(2); { FT_UShort Script_Count = get_UShort(); need (6 * Script_Count); for (i = 0; i < Script_Count; i++) { FT_Tag tag = get_ULong(); FT_ULong Script_ptr = Script_List_ptr + get_UShort(); warning("Script[%d] '%c%c%c%c' at 0x%04x.", i, tag >> 24, (tag >> 16) & 0xff, (tag >> 8) & 0xff, tag & 0xff, Script_ptr); } } has_gsub = True; // exit(1); #if 0 gsub = &gsub_; error = FT_Load_GSUB_Table(face, gsub, NULL); if (!error) has_gsub = True; else if (error != FT_Err_Table_Missing) warning("Cannot load GSUB table (error code = 0x%x).", error); else warning("No GSUB data available " "for vertical glyph presentation forms."); /* we check for the `vert' feature in Chinese, Japanese, and Korean */ error = FT_GSUB_Select_Script(gsub, SCRIPT_kana, &script_index); if (error) goto check_hani; error = FT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, 0xFFFF, &feature_index); if (error) { error = FT_GSUB_Select_Language(gsub, LANGUAGE_JAN, script_index, &language_index, &req_feature_index); if (error) goto check_hani; error = FT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, language_index, &feature_index); if (error) goto check_hani; else goto Done; } else goto Done; check_hani: error = FT_GSUB_Select_Script(gsub, SCRIPT_hani, &script_index); if (error) goto check_hang; error = FT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, 0xFFFF, &feature_index); if (error) { error = FT_GSUB_Select_Language(gsub, LANGUAGE_CHN, script_index, &language_index, &req_feature_index); if (error) goto check_hang; error = FT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, language_index, &feature_index); if (error) goto check_hang; else goto Done; } else goto Done; check_hang: error = FT_GSUB_Select_Script(gsub, SCRIPT_hang, &script_index); if (error) goto Done; error = FT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, 0xFFFF, &feature_index); if (error) { error = FT_GSUB_Select_Language(gsub, LANGUAGE_KOR, script_index, &language_index, &req_feature_index); if (error) goto Done; error = FT_GSUB_Select_Feature(gsub, FEATURE_vert, script_index, language_index, &feature_index); } Done: if (error) { warning("There is no data for vertical typesetting in GSUB table."); has_gsub = False; } if (req_feature_index != 0xFFFF) FT_GSUB_Add_Feature(gsub, req_feature_index, ALL_GLYPHS); FT_GSUB_Add_Feature(gsub, feature_index, ALL_GLYPHS); in.length = 1; in.pos = 0; in.string = in_string; in.properties = NULL; out.pos = 0; out.allocated = 0; out.string = NULL; out.properties = NULL; #endif } } int Get_Vert (int Num) { warning("GSUB: Looking for vertical form of glyph %d.", Num); #if 0 in_string[0] = Num; error = FT_GSUB_Apply_String(gsub, &in, &out); if (error && error != OTL_Err_Not_Covered) warning("Cannot get the vertical glyph form for glyph index %d.", Num); else Num = out.string[0]; #endif return Num; }