1249 lines
33 KiB
C
1249 lines
33 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifdef UNIX
|
|
#ifndef HAVE_POSIX_TERMIOS
|
|
#include <sys/ioctl.h>
|
|
#include <termio.h>
|
|
#else
|
|
#ifndef HAVE_TCGETATTR
|
|
#define HAVE_TCGETATTR
|
|
#endif /* HAVE_TCGETATTR */
|
|
#ifndef HAVE_TCSETATTR
|
|
#define HAVE_TCSETATTR
|
|
#endif /* HAVE_TCSETATTR */
|
|
#include <termios.h>
|
|
#endif /* HAVE_POSIX_TERMIOS */
|
|
#endif
|
|
|
|
/* Define the `getch()' function. On Unix systems, it is an alias */
|
|
/* for `getchar()', and the debugger front end must ensure that the */
|
|
/* `stdin' file descriptor is not in line-by-line input mode. */
|
|
#ifndef UNIX
|
|
#include <conio.h>
|
|
#else
|
|
#define getch getchar
|
|
#endif
|
|
|
|
|
|
#include "freetype.h"
|
|
#include "ttobjs.h"
|
|
#include "ttdriver.h"
|
|
#include "ttinterp.h"
|
|
|
|
|
|
FT_Library library; /* root library object */
|
|
FT_Memory memory; /* system object */
|
|
FT_Driver driver; /* truetype driver */
|
|
TT_Face face; /* truetype face */
|
|
TT_Size size; /* truetype size */
|
|
TT_GlyphSlot glyph; /* truetype glyph slot */
|
|
TT_ExecContext exec; /* truetype execution context */
|
|
TT_Error error;
|
|
|
|
TT_CodeRange_Tag debug_coderange = tt_coderange_glyph;
|
|
|
|
typedef FT_Byte ByteStr[2];
|
|
typedef FT_Byte WordStr[4];
|
|
typedef FT_Byte LongStr[8];
|
|
typedef FT_Byte DebugStr[128];
|
|
|
|
static DebugStr tempStr;
|
|
|
|
#undef PACK
|
|
#define PACK( x, y ) ((x << 4) | y)
|
|
|
|
static const TT_Byte Pop_Push_Count[256] =
|
|
{
|
|
/* opcodes are gathered in groups of 16 */
|
|
/* please keep the spaces as they are */
|
|
|
|
/* SVTCA y */ PACK( 0, 0 ),
|
|
/* SVTCA x */ PACK( 0, 0 ),
|
|
/* SPvTCA y */ PACK( 0, 0 ),
|
|
/* SPvTCA x */ PACK( 0, 0 ),
|
|
/* SFvTCA y */ PACK( 0, 0 ),
|
|
/* SFvTCA x */ PACK( 0, 0 ),
|
|
/* SPvTL // */ PACK( 2, 0 ),
|
|
/* SPvTL + */ PACK( 2, 0 ),
|
|
/* SFvTL // */ PACK( 2, 0 ),
|
|
/* SFvTL + */ PACK( 2, 0 ),
|
|
/* SPvFS */ PACK( 2, 0 ),
|
|
/* SFvFS */ PACK( 2, 0 ),
|
|
/* GPV */ PACK( 0, 2 ),
|
|
/* GFV */ PACK( 0, 2 ),
|
|
/* SFvTPv */ PACK( 0, 0 ),
|
|
/* ISECT */ PACK( 5, 0 ),
|
|
|
|
/* SRP0 */ PACK( 1, 0 ),
|
|
/* SRP1 */ PACK( 1, 0 ),
|
|
/* SRP2 */ PACK( 1, 0 ),
|
|
/* SZP0 */ PACK( 1, 0 ),
|
|
/* SZP1 */ PACK( 1, 0 ),
|
|
/* SZP2 */ PACK( 1, 0 ),
|
|
/* SZPS */ PACK( 1, 0 ),
|
|
/* SLOOP */ PACK( 1, 0 ),
|
|
/* RTG */ PACK( 0, 0 ),
|
|
/* RTHG */ PACK( 0, 0 ),
|
|
/* SMD */ PACK( 1, 0 ),
|
|
/* ELSE */ PACK( 0, 0 ),
|
|
/* JMPR */ PACK( 1, 0 ),
|
|
/* SCvTCi */ PACK( 1, 0 ),
|
|
/* SSwCi */ PACK( 1, 0 ),
|
|
/* SSW */ PACK( 1, 0 ),
|
|
|
|
/* DUP */ PACK( 1, 2 ),
|
|
/* POP */ PACK( 1, 0 ),
|
|
/* CLEAR */ PACK( 0, 0 ),
|
|
/* SWAP */ PACK( 2, 2 ),
|
|
/* DEPTH */ PACK( 0, 1 ),
|
|
/* CINDEX */ PACK( 1, 1 ),
|
|
/* MINDEX */ PACK( 1, 0 ),
|
|
/* AlignPTS */ PACK( 2, 0 ),
|
|
/* INS_$28 */ PACK( 0, 0 ),
|
|
/* UTP */ PACK( 1, 0 ),
|
|
/* LOOPCALL */ PACK( 2, 0 ),
|
|
/* CALL */ PACK( 1, 0 ),
|
|
/* FDEF */ PACK( 1, 0 ),
|
|
/* ENDF */ PACK( 0, 0 ),
|
|
/* MDAP[0] */ PACK( 1, 0 ),
|
|
/* MDAP[1] */ PACK( 1, 0 ),
|
|
|
|
/* IUP[0] */ PACK( 0, 0 ),
|
|
/* IUP[1] */ PACK( 0, 0 ),
|
|
/* SHP[0] */ PACK( 0, 0 ),
|
|
/* SHP[1] */ PACK( 0, 0 ),
|
|
/* SHC[0] */ PACK( 1, 0 ),
|
|
/* SHC[1] */ PACK( 1, 0 ),
|
|
/* SHZ[0] */ PACK( 1, 0 ),
|
|
/* SHZ[1] */ PACK( 1, 0 ),
|
|
/* SHPIX */ PACK( 1, 0 ),
|
|
/* IP */ PACK( 0, 0 ),
|
|
/* MSIRP[0] */ PACK( 2, 0 ),
|
|
/* MSIRP[1] */ PACK( 2, 0 ),
|
|
/* AlignRP */ PACK( 0, 0 ),
|
|
/* RTDG */ PACK( 0, 0 ),
|
|
/* MIAP[0] */ PACK( 2, 0 ),
|
|
/* MIAP[1] */ PACK( 2, 0 ),
|
|
|
|
/* NPushB */ PACK( 0, 0 ),
|
|
/* NPushW */ PACK( 0, 0 ),
|
|
/* WS */ PACK( 2, 0 ),
|
|
/* RS */ PACK( 1, 1 ),
|
|
/* WCvtP */ PACK( 2, 0 ),
|
|
/* RCvt */ PACK( 1, 1 ),
|
|
/* GC[0] */ PACK( 1, 1 ),
|
|
/* GC[1] */ PACK( 1, 1 ),
|
|
/* SCFS */ PACK( 2, 0 ),
|
|
/* MD[0] */ PACK( 2, 1 ),
|
|
/* MD[1] */ PACK( 2, 1 ),
|
|
/* MPPEM */ PACK( 0, 1 ),
|
|
/* MPS */ PACK( 0, 1 ),
|
|
/* FlipON */ PACK( 0, 0 ),
|
|
/* FlipOFF */ PACK( 0, 0 ),
|
|
/* DEBUG */ PACK( 1, 0 ),
|
|
|
|
/* LT */ PACK( 2, 1 ),
|
|
/* LTEQ */ PACK( 2, 1 ),
|
|
/* GT */ PACK( 2, 1 ),
|
|
/* GTEQ */ PACK( 2, 1 ),
|
|
/* EQ */ PACK( 2, 1 ),
|
|
/* NEQ */ PACK( 2, 1 ),
|
|
/* ODD */ PACK( 1, 1 ),
|
|
/* EVEN */ PACK( 1, 1 ),
|
|
/* IF */ PACK( 1, 0 ),
|
|
/* EIF */ PACK( 0, 0 ),
|
|
/* AND */ PACK( 2, 1 ),
|
|
/* OR */ PACK( 2, 1 ),
|
|
/* NOT */ PACK( 1, 1 ),
|
|
/* DeltaP1 */ PACK( 1, 0 ),
|
|
/* SDB */ PACK( 1, 0 ),
|
|
/* SDS */ PACK( 1, 0 ),
|
|
|
|
/* ADD */ PACK( 2, 1 ),
|
|
/* SUB */ PACK( 2, 1 ),
|
|
/* DIV */ PACK( 2, 1 ),
|
|
/* MUL */ PACK( 2, 1 ),
|
|
/* ABS */ PACK( 1, 1 ),
|
|
/* NEG */ PACK( 1, 1 ),
|
|
/* FLOOR */ PACK( 1, 1 ),
|
|
/* CEILING */ PACK( 1, 1 ),
|
|
/* ROUND[0] */ PACK( 1, 1 ),
|
|
/* ROUND[1] */ PACK( 1, 1 ),
|
|
/* ROUND[2] */ PACK( 1, 1 ),
|
|
/* ROUND[3] */ PACK( 1, 1 ),
|
|
/* NROUND[0] */ PACK( 1, 1 ),
|
|
/* NROUND[1] */ PACK( 1, 1 ),
|
|
/* NROUND[2] */ PACK( 1, 1 ),
|
|
/* NROUND[3] */ PACK( 1, 1 ),
|
|
|
|
/* WCvtF */ PACK( 2, 0 ),
|
|
/* DeltaP2 */ PACK( 1, 0 ),
|
|
/* DeltaP3 */ PACK( 1, 0 ),
|
|
/* DeltaCn[0] */ PACK( 1, 0 ),
|
|
/* DeltaCn[1] */ PACK( 1, 0 ),
|
|
/* DeltaCn[2] */ PACK( 1, 0 ),
|
|
/* SROUND */ PACK( 1, 0 ),
|
|
/* S45Round */ PACK( 1, 0 ),
|
|
/* JROT */ PACK( 2, 0 ),
|
|
/* JROF */ PACK( 2, 0 ),
|
|
/* ROFF */ PACK( 0, 0 ),
|
|
/* INS_$7B */ PACK( 0, 0 ),
|
|
/* RUTG */ PACK( 0, 0 ),
|
|
/* RDTG */ PACK( 0, 0 ),
|
|
/* SANGW */ PACK( 1, 0 ),
|
|
/* AA */ PACK( 1, 0 ),
|
|
|
|
/* FlipPT */ PACK( 0, 0 ),
|
|
/* FlipRgON */ PACK( 2, 0 ),
|
|
/* FlipRgOFF */ PACK( 2, 0 ),
|
|
/* INS_$83 */ PACK( 0, 0 ),
|
|
/* INS_$84 */ PACK( 0, 0 ),
|
|
/* ScanCTRL */ PACK( 1, 0 ),
|
|
/* SDVPTL[0] */ PACK( 2, 0 ),
|
|
/* SDVPTL[1] */ PACK( 2, 0 ),
|
|
/* GetINFO */ PACK( 1, 1 ),
|
|
/* IDEF */ PACK( 1, 0 ),
|
|
/* ROLL */ PACK( 3, 3 ),
|
|
/* MAX */ PACK( 2, 1 ),
|
|
/* MIN */ PACK( 2, 1 ),
|
|
/* ScanTYPE */ PACK( 1, 0 ),
|
|
/* InstCTRL */ PACK( 2, 0 ),
|
|
/* INS_$8F */ PACK( 0, 0 ),
|
|
|
|
/* INS_$90 */ PACK( 0, 0 ),
|
|
/* INS_$91 */ PACK( 0, 0 ),
|
|
/* INS_$92 */ PACK( 0, 0 ),
|
|
/* INS_$93 */ PACK( 0, 0 ),
|
|
/* INS_$94 */ PACK( 0, 0 ),
|
|
/* INS_$95 */ PACK( 0, 0 ),
|
|
/* INS_$96 */ PACK( 0, 0 ),
|
|
/* INS_$97 */ PACK( 0, 0 ),
|
|
/* INS_$98 */ PACK( 0, 0 ),
|
|
/* INS_$99 */ PACK( 0, 0 ),
|
|
/* INS_$9A */ PACK( 0, 0 ),
|
|
/* INS_$9B */ PACK( 0, 0 ),
|
|
/* INS_$9C */ PACK( 0, 0 ),
|
|
/* INS_$9D */ PACK( 0, 0 ),
|
|
/* INS_$9E */ PACK( 0, 0 ),
|
|
/* INS_$9F */ PACK( 0, 0 ),
|
|
|
|
/* INS_$A0 */ PACK( 0, 0 ),
|
|
/* INS_$A1 */ PACK( 0, 0 ),
|
|
/* INS_$A2 */ PACK( 0, 0 ),
|
|
/* INS_$A3 */ PACK( 0, 0 ),
|
|
/* INS_$A4 */ PACK( 0, 0 ),
|
|
/* INS_$A5 */ PACK( 0, 0 ),
|
|
/* INS_$A6 */ PACK( 0, 0 ),
|
|
/* INS_$A7 */ PACK( 0, 0 ),
|
|
/* INS_$A8 */ PACK( 0, 0 ),
|
|
/* INS_$A9 */ PACK( 0, 0 ),
|
|
/* INS_$AA */ PACK( 0, 0 ),
|
|
/* INS_$AB */ PACK( 0, 0 ),
|
|
/* INS_$AC */ PACK( 0, 0 ),
|
|
/* INS_$AD */ PACK( 0, 0 ),
|
|
/* INS_$AE */ PACK( 0, 0 ),
|
|
/* INS_$AF */ PACK( 0, 0 ),
|
|
|
|
/* PushB[0] */ PACK( 0, 1 ),
|
|
/* PushB[1] */ PACK( 0, 2 ),
|
|
/* PushB[2] */ PACK( 0, 3 ),
|
|
/* PushB[3] */ PACK( 0, 4 ),
|
|
/* PushB[4] */ PACK( 0, 5 ),
|
|
/* PushB[5] */ PACK( 0, 6 ),
|
|
/* PushB[6] */ PACK( 0, 7 ),
|
|
/* PushB[7] */ PACK( 0, 8 ),
|
|
/* PushW[0] */ PACK( 0, 1 ),
|
|
/* PushW[1] */ PACK( 0, 2 ),
|
|
/* PushW[2] */ PACK( 0, 3 ),
|
|
/* PushW[3] */ PACK( 0, 4 ),
|
|
/* PushW[4] */ PACK( 0, 5 ),
|
|
/* PushW[5] */ PACK( 0, 6 ),
|
|
/* PushW[6] */ PACK( 0, 7 ),
|
|
/* PushW[7] */ PACK( 0, 8 ),
|
|
|
|
/* MDRP[00] */ PACK( 1, 0 ),
|
|
/* MDRP[01] */ PACK( 1, 0 ),
|
|
/* MDRP[02] */ PACK( 1, 0 ),
|
|
/* MDRP[03] */ PACK( 1, 0 ),
|
|
/* MDRP[04] */ PACK( 1, 0 ),
|
|
/* MDRP[05] */ PACK( 1, 0 ),
|
|
/* MDRP[06] */ PACK( 1, 0 ),
|
|
/* MDRP[07] */ PACK( 1, 0 ),
|
|
/* MDRP[08] */ PACK( 1, 0 ),
|
|
/* MDRP[09] */ PACK( 1, 0 ),
|
|
/* MDRP[10] */ PACK( 1, 0 ),
|
|
/* MDRP[11] */ PACK( 1, 0 ),
|
|
/* MDRP[12] */ PACK( 1, 0 ),
|
|
/* MDRP[13] */ PACK( 1, 0 ),
|
|
/* MDRP[14] */ PACK( 1, 0 ),
|
|
/* MDRP[15] */ PACK( 1, 0 ),
|
|
|
|
/* MDRP[16] */ PACK( 1, 0 ),
|
|
/* MDRP[17] */ PACK( 1, 0 ),
|
|
/* MDRP[18] */ PACK( 1, 0 ),
|
|
/* MDRP[19] */ PACK( 1, 0 ),
|
|
/* MDRP[20] */ PACK( 1, 0 ),
|
|
/* MDRP[21] */ PACK( 1, 0 ),
|
|
/* MDRP[22] */ PACK( 1, 0 ),
|
|
/* MDRP[23] */ PACK( 1, 0 ),
|
|
/* MDRP[24] */ PACK( 1, 0 ),
|
|
/* MDRP[25] */ PACK( 1, 0 ),
|
|
/* MDRP[26] */ PACK( 1, 0 ),
|
|
/* MDRP[27] */ PACK( 1, 0 ),
|
|
/* MDRP[28] */ PACK( 1, 0 ),
|
|
/* MDRP[29] */ PACK( 1, 0 ),
|
|
/* MDRP[30] */ PACK( 1, 0 ),
|
|
/* MDRP[31] */ PACK( 1, 0 ),
|
|
|
|
/* MIRP[00] */ PACK( 2, 0 ),
|
|
/* MIRP[01] */ PACK( 2, 0 ),
|
|
/* MIRP[02] */ PACK( 2, 0 ),
|
|
/* MIRP[03] */ PACK( 2, 0 ),
|
|
/* MIRP[04] */ PACK( 2, 0 ),
|
|
/* MIRP[05] */ PACK( 2, 0 ),
|
|
/* MIRP[06] */ PACK( 2, 0 ),
|
|
/* MIRP[07] */ PACK( 2, 0 ),
|
|
/* MIRP[08] */ PACK( 2, 0 ),
|
|
/* MIRP[09] */ PACK( 2, 0 ),
|
|
/* MIRP[10] */ PACK( 2, 0 ),
|
|
/* MIRP[11] */ PACK( 2, 0 ),
|
|
/* MIRP[12] */ PACK( 2, 0 ),
|
|
/* MIRP[13] */ PACK( 2, 0 ),
|
|
/* MIRP[14] */ PACK( 2, 0 ),
|
|
/* MIRP[15] */ PACK( 2, 0 ),
|
|
|
|
/* MIRP[16] */ PACK( 2, 0 ),
|
|
/* MIRP[17] */ PACK( 2, 0 ),
|
|
/* MIRP[18] */ PACK( 2, 0 ),
|
|
/* MIRP[19] */ PACK( 2, 0 ),
|
|
/* MIRP[20] */ PACK( 2, 0 ),
|
|
/* MIRP[21] */ PACK( 2, 0 ),
|
|
/* MIRP[22] */ PACK( 2, 0 ),
|
|
/* MIRP[23] */ PACK( 2, 0 ),
|
|
/* MIRP[24] */ PACK( 2, 0 ),
|
|
/* MIRP[25] */ PACK( 2, 0 ),
|
|
/* MIRP[26] */ PACK( 2, 0 ),
|
|
/* MIRP[27] */ PACK( 2, 0 ),
|
|
/* MIRP[28] */ PACK( 2, 0 ),
|
|
/* MIRP[29] */ PACK( 2, 0 ),
|
|
/* MIRP[30] */ PACK( 2, 0 ),
|
|
/* MIRP[31] */ PACK( 2, 0 )
|
|
};
|
|
|
|
|
|
static const FT_String* OpStr[256] = {
|
|
"SVTCA y", /* Set vectors to coordinate axis y */
|
|
"SVTCA x", /* Set vectors to coordinate axis x */
|
|
"SPvTCA y", /* Set Proj. vec. to coord. axis y */
|
|
"SPvTCA x", /* Set Proj. vec. to coord. axis x */
|
|
"SFvTCA y", /* Set Free. vec. to coord. axis y */
|
|
"SFvTCA x", /* Set Free. vec. to coord. axis x */
|
|
"SPvTL //", /* Set Proj. vec. parallel to segment */
|
|
"SPvTL +", /* Set Proj. vec. normal to segment */
|
|
"SFvTL //", /* Set Free. vec. parallel to segment */
|
|
"SFvTL +", /* Set Free. vec. normal to segment */
|
|
"SPvFS", /* Set Proj. vec. from stack */
|
|
"SFvFS", /* Set Free. vec. from stack */
|
|
"GPV", /* Get projection vector */
|
|
"GFV", /* Get freedom vector */
|
|
"SFvTPv", /* Set free. vec. to proj. vec. */
|
|
"ISECT", /* compute intersection */
|
|
|
|
"SRP0", /* Set reference point 0 */
|
|
"SRP1", /* Set reference point 1 */
|
|
"SRP2", /* Set reference point 2 */
|
|
"SZP0", /* Set Zone Pointer 0 */
|
|
"SZP1", /* Set Zone Pointer 1 */
|
|
"SZP2", /* Set Zone Pointer 2 */
|
|
"SZPS", /* Set all zone pointers */
|
|
"SLOOP", /* Set loop counter */
|
|
"RTG", /* Round to Grid */
|
|
"RTHG", /* Round to Half-Grid */
|
|
"SMD", /* Set Minimum Distance */
|
|
"ELSE", /* Else */
|
|
"JMPR", /* Jump Relative */
|
|
"SCvTCi", /* Set CVT */
|
|
"SSwCi", /* */
|
|
"SSW", /* */
|
|
|
|
"DUP",
|
|
"POP",
|
|
"CLEAR",
|
|
"SWAP",
|
|
"DEPTH",
|
|
"CINDEX",
|
|
"MINDEX",
|
|
"AlignPTS",
|
|
"INS_$28",
|
|
"UTP",
|
|
"LOOPCALL",
|
|
"CALL",
|
|
"FDEF",
|
|
"ENDF",
|
|
"MDAP[-]",
|
|
"MDAP[r]",
|
|
|
|
"IUP[y]",
|
|
"IUP[x]",
|
|
"SHP[0]",
|
|
"SHP[1]",
|
|
"SHC[0]",
|
|
"SHC[1]",
|
|
"SHZ[0]",
|
|
"SHZ[1]",
|
|
"SHPIX",
|
|
"IP",
|
|
"MSIRP[0]",
|
|
"MSIRP[1]",
|
|
"AlignRP",
|
|
"RTDG",
|
|
"MIAP[-]",
|
|
"MIAP[r]",
|
|
|
|
"NPushB",
|
|
"NPushW",
|
|
"WS",
|
|
"RS",
|
|
"WCvtP",
|
|
"RCvt",
|
|
"GC[0]",
|
|
"GC[1]",
|
|
"SCFS",
|
|
"MD[0]",
|
|
"MD[1]",
|
|
"MPPEM",
|
|
"MPS",
|
|
"FlipON",
|
|
"FlipOFF",
|
|
"DEBUG",
|
|
|
|
"LT",
|
|
"LTEQ",
|
|
"GT",
|
|
"GTEQ",
|
|
"EQ",
|
|
"NEQ",
|
|
"ODD",
|
|
"EVEN",
|
|
"IF",
|
|
"EIF",
|
|
"AND",
|
|
"OR",
|
|
"NOT",
|
|
"DeltaP1",
|
|
"SDB",
|
|
"SDS",
|
|
|
|
"ADD",
|
|
"SUB",
|
|
"DIV",
|
|
"MUL",
|
|
"ABS",
|
|
"NEG",
|
|
"FLOOR",
|
|
"CEILING",
|
|
"ROUND[G]",
|
|
"ROUND[B]",
|
|
"ROUND[W]",
|
|
"ROUND[?]",
|
|
"NROUND[G]",
|
|
"NROUND[B]",
|
|
"NROUND[W]",
|
|
"NROUND[?]",
|
|
|
|
"WCvtF",
|
|
"DeltaP2",
|
|
"DeltaP3",
|
|
"DeltaC1",
|
|
"DeltaC2",
|
|
"DeltaC3",
|
|
"SROUND",
|
|
"S45Round",
|
|
"JROT",
|
|
"JROF",
|
|
"ROFF",
|
|
"INS_$7B",
|
|
"RUTG",
|
|
"RDTG",
|
|
"SANGW",
|
|
"AA",
|
|
|
|
"FlipPT",
|
|
"FlipRgON",
|
|
"FlipRgOFF",
|
|
"INS_$83",
|
|
"INS_$84",
|
|
"ScanCTRL",
|
|
"SDPVTL[0]",
|
|
"SDPVTL[1]",
|
|
"GetINFO",
|
|
"IDEF",
|
|
"ROLL",
|
|
"MAX",
|
|
"MIN",
|
|
"ScanTYPE",
|
|
"IntCTRL",
|
|
"INS_$8F",
|
|
|
|
"INS_$90",
|
|
"INS_$91",
|
|
"INS_$92",
|
|
"INS_$93",
|
|
"INS_$94",
|
|
"INS_$95",
|
|
"INS_$96",
|
|
"INS_$97",
|
|
"INS_$98",
|
|
"INS_$99",
|
|
"INS_$9A",
|
|
"INS_$9B",
|
|
"INS_$9C",
|
|
"INS_$9D",
|
|
"INS_$9E",
|
|
"INS_$9F",
|
|
|
|
"INS_$A0",
|
|
"INS_$A1",
|
|
"INS_$A2",
|
|
"INS_$A3",
|
|
"INS_$A4",
|
|
"INS_$A5",
|
|
"INS_$A6",
|
|
"INS_$A7",
|
|
"INS_$A8",
|
|
"INS_$A9",
|
|
"INS_$AA",
|
|
"INS_$AB",
|
|
"INS_$AC",
|
|
"INS_$AD",
|
|
"INS_$AE",
|
|
"INS_$AF",
|
|
|
|
"PushB[0]",
|
|
"PushB[1]",
|
|
"PushB[2]",
|
|
"PushB[3]",
|
|
"PushB[4]",
|
|
"PushB[5]",
|
|
"PushB[6]",
|
|
"PushB[7]",
|
|
"PushW[0]",
|
|
"PushW[1]",
|
|
"PushW[2]",
|
|
"PushW[3]",
|
|
"PushW[4]",
|
|
"PushW[5]",
|
|
"PushW[6]",
|
|
"PushW[7]",
|
|
|
|
"MDRP[G]",
|
|
"MDRP[B]",
|
|
"MDRP[W]",
|
|
"MDRP[?]",
|
|
"MDRP[rG]",
|
|
"MDRP[rB]",
|
|
"MDRP[rW]",
|
|
"MDRP[r?]",
|
|
"MDRP[mG]",
|
|
"MDRP[mB]",
|
|
"MDRP[mW]",
|
|
"MDRP[m?]",
|
|
"MDRP[mrG]",
|
|
"MDRP[mrB]",
|
|
"MDRP[mrW]",
|
|
"MDRP[mr?]",
|
|
"MDRP[pG]",
|
|
"MDRP[pB]",
|
|
|
|
"MDRP[pW]",
|
|
"MDRP[p?]",
|
|
"MDRP[prG]",
|
|
"MDRP[prB]",
|
|
"MDRP[prW]",
|
|
"MDRP[pr?]",
|
|
"MDRP[pmG]",
|
|
"MDRP[pmB]",
|
|
"MDRP[pmW]",
|
|
"MDRP[pm?]",
|
|
"MDRP[pmrG]",
|
|
"MDRP[pmrB]",
|
|
"MDRP[pmrW]",
|
|
"MDRP[pmr?]",
|
|
|
|
"MIRP[G]",
|
|
"MIRP[B]",
|
|
"MIRP[W]",
|
|
"MIRP[?]",
|
|
"MIRP[rG]",
|
|
"MIRP[rB]",
|
|
"MIRP[rW]",
|
|
"MIRP[r?]",
|
|
"MIRP[mG]",
|
|
"MIRP[mB]",
|
|
"MIRP[mW]",
|
|
"MIRP[m?]",
|
|
"MIRP[mrG]",
|
|
"MIRP[mrB]",
|
|
"MIRP[mrW]",
|
|
"MIRP[mr?]",
|
|
"MIRP[pG]",
|
|
"MIRP[pB]",
|
|
|
|
"MIRP[pW]",
|
|
"MIRP[p?]",
|
|
"MIRP[prG]",
|
|
"MIRP[prB]",
|
|
"MIRP[prW]",
|
|
"MIRP[pr?]",
|
|
"MIRP[pmG]",
|
|
"MIRP[pmB]",
|
|
"MIRP[pmW]",
|
|
"MIRP[pm?]",
|
|
"MIRP[pmrG]",
|
|
"MIRP[pmrB]",
|
|
"MIRP[pmrW]",
|
|
"MIRP[pmr?]"
|
|
};
|
|
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Init_Keyboard : set the input file descriptor to char-by-char
|
|
* mode on Unix..
|
|
*
|
|
*********************************************************************/
|
|
|
|
#ifdef UNIX
|
|
|
|
struct termios old_termio;
|
|
|
|
static
|
|
void Init_Keyboard( void )
|
|
{
|
|
struct termios termio;
|
|
|
|
#ifndef HAVE_TCGETATTR
|
|
ioctl( 0, TCGETS, &old_termio );
|
|
#else
|
|
tcgetattr( 0, &old_termio );
|
|
#endif
|
|
|
|
termio = old_termio;
|
|
|
|
/* termio.c_lflag &= ~(ICANON+ECHO+ECHOE+ECHOK+ECHONL+ECHOKE); */
|
|
termio.c_lflag &= ~(ICANON+ECHO+ECHOE+ECHOK+ECHONL);
|
|
|
|
#ifndef HAVE_TCSETATTR
|
|
ioctl( 0, TCSETS, &termio );
|
|
#else
|
|
tcsetattr( 0, TCSANOW, &termio );
|
|
#endif
|
|
}
|
|
|
|
static
|
|
void Reset_Keyboard( void )
|
|
{
|
|
#ifndef HAVE_TCSETATTR
|
|
ioctl( 0, TCSETS, &old_termio );
|
|
#else
|
|
tcsetattr( 0, TCSANOW, &old_termio );
|
|
#endif
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static
|
|
void Init_Keyboard( void )
|
|
{
|
|
}
|
|
|
|
static
|
|
void Reset_Keyboard( void )
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void Panic( const char* message )
|
|
{
|
|
fprintf( stderr, "%s\n error code = 0x%04x\n", message, error );
|
|
Reset_Keyboard();
|
|
exit(1);
|
|
}
|
|
|
|
|
|
/******************************************************************
|
|
*
|
|
* Function : Calc_Length
|
|
*
|
|
* Description : Computes the length in bytes of current opcode.
|
|
*
|
|
*****************************************************************/
|
|
|
|
#define CUR (*exc)
|
|
|
|
|
|
static void Calc_Length( TT_ExecContext exc )
|
|
{
|
|
CUR.opcode = CUR.code[CUR.IP];
|
|
|
|
switch ( CUR.opcode )
|
|
{
|
|
case 0x40:
|
|
if ( CUR.IP + 1 >= CUR.codeSize )
|
|
Panic( "code range overflow !!" );
|
|
|
|
CUR.length = CUR.code[CUR.IP + 1] + 2;
|
|
break;
|
|
|
|
case 0x41:
|
|
if ( CUR.IP + 1 >= CUR.codeSize )
|
|
Panic( "code range overflow !!" );
|
|
|
|
CUR.length = CUR.code[CUR.IP + 1] * 2 + 2;
|
|
break;
|
|
|
|
case 0xB0:
|
|
case 0xB1:
|
|
case 0xB2:
|
|
case 0xB3:
|
|
case 0xB4:
|
|
case 0xB5:
|
|
case 0xB6:
|
|
case 0xB7:
|
|
CUR.length = CUR.opcode - 0xB0 + 2;
|
|
break;
|
|
|
|
case 0xB8:
|
|
case 0xB9:
|
|
case 0xBA:
|
|
case 0xBB:
|
|
case 0xBC:
|
|
case 0xBD:
|
|
case 0xBE:
|
|
case 0xBF:
|
|
CUR.length = (CUR.opcode - 0xB8) * 2 + 3;
|
|
break;
|
|
|
|
default:
|
|
CUR.length = 1;
|
|
break;
|
|
}
|
|
|
|
/* make sure result is in range */
|
|
|
|
if ( CUR.IP + CUR.length > CUR.codeSize )
|
|
Panic( "code range overflow !!" );
|
|
}
|
|
|
|
|
|
/* Disassemble the current line */
|
|
/* */
|
|
const FT_String* Cur_U_Line( TT_ExecContext exec )
|
|
{
|
|
FT_String s[32];
|
|
FT_Int op, i, n;
|
|
|
|
op = exec->code[ exec->IP ];
|
|
|
|
sprintf( tempStr, "%04lx: %02hx %s", exec->IP, op, OpStr[op] );
|
|
|
|
if ( op == 0x40 )
|
|
{
|
|
n = exec->code[ exec->IP+1 ];
|
|
sprintf( s, "(%d)", n );
|
|
strncat( tempStr, s, 8 );
|
|
|
|
if ( n > 20 ) n = 20; /* limit output */
|
|
|
|
for ( i = 0; i < n; i++ )
|
|
{
|
|
sprintf( s, " $%02hx", exec->code[ exec->IP+i+2 ] );
|
|
strncat( tempStr, s, 8 );
|
|
}
|
|
}
|
|
else if ( op == 0x41 )
|
|
{
|
|
n = exec->code[ exec->IP+1 ];
|
|
sprintf( s, "(%d)", n );
|
|
strncat( tempStr, s, 8 );
|
|
|
|
if (n > 20) n = 20; /* limit output */
|
|
|
|
for ( i = 0; i < n; i++ )
|
|
{
|
|
sprintf( s, " $%02hx%02hx", exec->code[ exec->IP+i*2+2 ],
|
|
exec->code[ exec->IP+i*2+3 ] );
|
|
strncat( tempStr, s, 8 );
|
|
}
|
|
}
|
|
else if ( (op & 0xF8) == 0xB0 )
|
|
{
|
|
n = op-0xB0;
|
|
|
|
for ( i=0; i <= n; i++ )
|
|
{
|
|
sprintf( s, " $%02hx", exec->code[ exec->IP+i+1 ] );
|
|
strncat( tempStr, s, 8 );
|
|
}
|
|
}
|
|
else if ( (op & 0xF8) == 0xB8 )
|
|
{
|
|
n = op-0xB8;
|
|
|
|
for ( i = 0; i <= n; i++ )
|
|
{
|
|
sprintf( s, " $%02hx%02hx", exec->code[ exec->IP+i*2+1 ],
|
|
exec->code[ exec->IP+i*2+2 ] );
|
|
strncat( tempStr, s, 8 );
|
|
}
|
|
}
|
|
|
|
return (FT_String*)tempStr;
|
|
}
|
|
|
|
|
|
static
|
|
TT_Error RunIns( TT_ExecContext exc )
|
|
{
|
|
FT_Int A, diff, key;
|
|
FT_Long next_IP;
|
|
FT_Char ch, oldch = '\0', *temp;
|
|
|
|
TT_Error error = 0;
|
|
|
|
FT_GlyphZone save;
|
|
FT_GlyphZone pts;
|
|
|
|
const FT_String* round_str[8] =
|
|
{
|
|
"to half-grid",
|
|
"to grid",
|
|
"to double grid",
|
|
"down to grid",
|
|
"up to grid",
|
|
"off",
|
|
"super",
|
|
"super 45"
|
|
};
|
|
|
|
/* only debug the requested code range */
|
|
if (exc->curRange != (TT_Int)debug_coderange)
|
|
return TT_RunIns(exc);
|
|
|
|
exc->pts.n_points = exc->zp0.n_points;
|
|
exc->pts.n_contours = exc->zp0.n_contours;
|
|
|
|
pts = exc->pts;
|
|
|
|
|
|
save.n_points = pts.n_points;
|
|
save.n_contours = pts.n_contours;
|
|
|
|
save.org = (TT_Vector*)malloc( 2 * sizeof( TT_F26Dot6 ) *
|
|
save.n_points );
|
|
save.cur = (TT_Vector*)malloc( 2 * sizeof( TT_F26Dot6 ) *
|
|
save.n_points );
|
|
save.tags = (TT_Byte*)malloc( save.n_points );
|
|
|
|
exc->instruction_trap = 1;
|
|
|
|
do
|
|
{
|
|
if ( CUR.IP < CUR.codeSize )
|
|
{
|
|
Calc_Length( exc );
|
|
|
|
CUR.args = CUR.top - (Pop_Push_Count[CUR.opcode] >> 4);
|
|
|
|
/* `args' is the top of the stack once arguments have been popped. */
|
|
/* One can also interpret it as the index of the last argument. */
|
|
|
|
/* Print the current line. We use a 80-columns console with the */
|
|
/* following formatting: */
|
|
/* */
|
|
/* [loc]:[addr] [opcode] [disassemby] [a][b]|[c][d] */
|
|
/* */
|
|
|
|
{
|
|
char temp[80];
|
|
int n, col, pop;
|
|
int args = CUR.args;
|
|
|
|
sprintf( temp, "%78c\n", ' ' );
|
|
|
|
/* first letter of location */
|
|
switch ( CUR.curRange )
|
|
{
|
|
case tt_coderange_glyph:
|
|
temp[0] = 'g';
|
|
break;
|
|
case tt_coderange_cvt:
|
|
temp[0] = 'c';
|
|
break;
|
|
default:
|
|
temp[0] = 'f';
|
|
}
|
|
|
|
/* current IP */
|
|
sprintf( temp+1, "%04lx: %02x %-36.36s",
|
|
CUR.IP,
|
|
CUR.opcode,
|
|
Cur_U_Line(&CUR) );
|
|
|
|
strncpy( temp+46, " (", 2 );
|
|
|
|
args = CUR.top - 1;
|
|
pop = Pop_Push_Count[CUR.opcode] >> 4;
|
|
col = 48;
|
|
for ( n = 6; n > 0; n-- )
|
|
{
|
|
if ( pop == 0 )
|
|
temp[col-1] = (temp[col-1] == '(' ? ' ' : ')' );
|
|
|
|
if ( args < CUR.top && args >= 0 )
|
|
sprintf( temp+col, "%04lx", CUR.stack[args] );
|
|
else
|
|
sprintf( temp+col, " " );
|
|
|
|
temp[col+4] = ' ';
|
|
col += 5;
|
|
pop--;
|
|
args--;
|
|
}
|
|
temp[78] = '\n';
|
|
temp[79] = '\0';
|
|
printf( "%s", temp );
|
|
}
|
|
|
|
/* First, check for empty stack and overflow */
|
|
if ( CUR.args < 0 )
|
|
{
|
|
printf( "ERROR : Too Few Arguments\n" );
|
|
CUR.error = TT_Err_Too_Few_Arguments;
|
|
goto LErrorLabel_;
|
|
}
|
|
|
|
CUR.new_top = CUR.args + (Pop_Push_Count[CUR.opcode] & 15);
|
|
|
|
/* new_top is the new top of the stack, after the instruction's */
|
|
/* execution. top will be set to new_top after the 'case' */
|
|
|
|
if ( CUR.new_top > CUR.stackSize )
|
|
{
|
|
printf( "ERROR : Stack overflow\n" );
|
|
CUR.error = TT_Err_Stack_Overflow;
|
|
goto LErrorLabel_;
|
|
}
|
|
}
|
|
else
|
|
printf( "End of program reached.\n" );
|
|
|
|
key = 0;
|
|
do
|
|
{
|
|
/* read keyboard */
|
|
|
|
ch = getch();
|
|
|
|
switch ( ch )
|
|
{
|
|
/* Help - show keybindings */
|
|
case '?':
|
|
printf( "TTDebug Help\n\n" );
|
|
printf( "? Show this page\n" );
|
|
printf( "q Quit debugger\n" );
|
|
printf( "n Skip to next instruction\n" );
|
|
printf( "s Step into\n" );
|
|
printf( "v Show vector info\n" );
|
|
printf( "g Show graphics state\n" );
|
|
printf( "p Show points zone\n\n" );
|
|
break;
|
|
|
|
/* Show vectors */
|
|
case 'v':
|
|
printf( "freedom (%04hx,%04hx)\n", exc->GS.freeVector.x,
|
|
exc->GS.freeVector.y );
|
|
printf( "projection (%04hx,%04hx)\n", exc->GS.projVector.x,
|
|
exc->GS.projVector.y );
|
|
printf( "dual (%04hx,%04hx)\n\n", exc->GS.dualVector.x,
|
|
exc->GS.dualVector.y );
|
|
break;
|
|
|
|
/* Show graphics state */
|
|
case 'g':
|
|
printf( "rounding %s\n", round_str[exc->GS.round_state] );
|
|
printf( "min dist %04lx\n", exc->GS.minimum_distance );
|
|
printf( "cvt_cutin %04lx\n", exc->GS.control_value_cutin );
|
|
break;
|
|
|
|
/* Show points table */
|
|
case 'p':
|
|
for ( A = 0; A < exc->pts.n_points; A++ )
|
|
{
|
|
printf( "%02hx ", A );
|
|
printf( "%08lx,%08lx - ", pts.org[A].x, pts.org[A].y );
|
|
printf( "%08lx,%08lx\n", pts.cur[A].x, pts.cur[A].y );
|
|
}
|
|
printf(( "\n" ));
|
|
break;
|
|
|
|
default:
|
|
key = 1;
|
|
}
|
|
} while ( !key );
|
|
|
|
MEM_Copy( save.org, pts.org, pts.n_points * sizeof ( TT_Vector ) );
|
|
MEM_Copy( save.cur, pts.cur, pts.n_points * sizeof ( TT_Vector ) );
|
|
MEM_Copy( save.tags, pts.tags, pts.n_points );
|
|
|
|
/* a return indicate the last command */
|
|
if (ch == '\r')
|
|
ch = oldch;
|
|
|
|
switch ( ch )
|
|
{
|
|
/* Quit debugger */
|
|
case 'q':
|
|
goto LErrorLabel_;
|
|
|
|
/* Step over */
|
|
case 'n':
|
|
if ( exc->IP < exc->codeSize )
|
|
{
|
|
/* `step over' is equivalent to `step into' except if */
|
|
/* the current opcode is a CALL or LOOPCALL */
|
|
if ( CUR.opcode != 0x2a && CUR.opcode != 0x2b )
|
|
goto Step_into;
|
|
|
|
/* otherwise, loop execution until we reach the next opcode */
|
|
next_IP = CUR.IP + CUR.length;
|
|
while ( exc->IP != next_IP )
|
|
{
|
|
if ( ( error = TT_RunIns( exc ) ) )
|
|
goto LErrorLabel_;
|
|
}
|
|
}
|
|
oldch = ch;
|
|
break;
|
|
|
|
/* Step into */
|
|
case 's':
|
|
if ( exc->IP < exc->codeSize )
|
|
|
|
Step_into:
|
|
if ( ( error = TT_RunIns( exc ) ) )
|
|
goto LErrorLabel_;
|
|
oldch = ch;
|
|
break;
|
|
|
|
default:
|
|
printf( "unknown command. Press ? for help\n" );
|
|
oldch = '\0';
|
|
}
|
|
|
|
for ( A = 0; A < pts.n_points; A++ )
|
|
{
|
|
diff = 0;
|
|
if ( save.org[A].x != pts.org[A].x ) diff |= 1;
|
|
if ( save.org[A].y != pts.org[A].y ) diff |= 2;
|
|
if ( save.cur[A].x != pts.cur[A].x ) diff |= 4;
|
|
if ( save.cur[A].y != pts.cur[A].y ) diff |= 8;
|
|
if ( save.tags[A] != pts.tags[A] ) diff |= 16;
|
|
|
|
if ( diff )
|
|
{
|
|
printf( "%02hx ", A );
|
|
|
|
if ( diff & 16 ) temp = "(%01hx)"; else temp = " %01hx ";
|
|
printf( temp, save.tags[A] & 7 );
|
|
|
|
if ( diff & 1 ) temp = "(%08lx)"; else temp = " %08lx ";
|
|
printf( temp, save.org[A].x );
|
|
|
|
if ( diff & 2 ) temp = "(%08lx)"; else temp = " %08lx ";
|
|
printf( temp, save.org[A].y );
|
|
|
|
if ( diff & 4 ) temp = "(%08lx)"; else temp = " %08lx ";
|
|
printf( temp, save.cur[A].x );
|
|
|
|
if ( diff & 8 ) temp = "(%08lx)"; else temp = " %08lx ";
|
|
printf( temp, save.cur[A].y );
|
|
|
|
printf( "\n" );
|
|
|
|
printf( "%02hx ", A );
|
|
|
|
if ( diff & 16 ) temp = "[%01hx]"; else temp = " %01hx ";
|
|
printf( temp, pts.tags[A] & 7 );
|
|
|
|
if ( diff & 1 ) temp = "[%08lx]"; else temp = " %08lx ";
|
|
printf( temp, pts.org[A].x );
|
|
|
|
if ( diff & 2 ) temp = "[%08lx]"; else temp = " %08lx ";
|
|
printf( temp, pts.org[A].y );
|
|
|
|
if ( diff & 4 ) temp = "[%08lx]"; else temp = " %08lx ";
|
|
printf( temp, pts.cur[A].x );
|
|
|
|
if ( diff & 8 ) temp = "[%08lx]"; else temp = " %08lx ";
|
|
printf( temp, pts.cur[A].y );
|
|
|
|
printf( "\n\n" );
|
|
}
|
|
}
|
|
} while ( TRUE );
|
|
|
|
LErrorLabel_:
|
|
|
|
if (error)
|
|
Panic( "error during execution" );
|
|
return error;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
void Usage()
|
|
{
|
|
fprintf( stderr, "ttdebug - a simply TrueType font debugger\n" );
|
|
fprintf( stderr, "(c) The FreeType project - www.freetype.org\n" );
|
|
fprintf( stderr, "-------------------------------------------\n\n" );
|
|
|
|
fprintf( stderr, "usage : ttdebug [options] glyph size fontfile[.ttf]\n\n" );
|
|
|
|
fprintf( stderr, " glyph - glyph index within the font file. Can be negative to query \n" );
|
|
fprintf( stderr, " the debugging of the font 'cvt' program\n\n" );
|
|
|
|
fprintf( stderr, " size - size of glyph in pixels\n\n" );
|
|
|
|
fprintf( stderr, " fontfile - a valid TrueType file.\n\n" );
|
|
|
|
fprintf( stderr, " valid options are:\n\n" );
|
|
fprintf( stderr, " -d : Dump mode. Shows the glyph program and exit immediately\n" );
|
|
fprintf( stderr, " -n : Non-interactive mode. Dumps the execution trace and exit\n" );
|
|
|
|
exit(1);
|
|
}
|
|
|
|
|
|
int dump_mode;
|
|
int non_interactive_mode;
|
|
char* file_name;
|
|
int glyph_index;
|
|
int glyph_size;
|
|
|
|
int main( int argc, char** argv )
|
|
{
|
|
char valid;
|
|
|
|
/* Check number of arguments */
|
|
if ( argc < 4 ) Usage();
|
|
|
|
/* Check options */
|
|
dump_mode = 0;
|
|
non_interactive_mode = 0;
|
|
|
|
argv++;
|
|
while (argv[0][0] == '-')
|
|
{
|
|
valid = 0;
|
|
switch (argv[0][1])
|
|
{
|
|
case 'd':
|
|
dump_mode = 1;
|
|
valid = 1;
|
|
break;
|
|
|
|
case 'n':
|
|
non_interactive_mode = 1;
|
|
valid = 1;
|
|
break;
|
|
|
|
default:
|
|
;
|
|
}
|
|
|
|
if (valid)
|
|
{
|
|
argv++;
|
|
argc--;
|
|
if (argc < 4) Usage();
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
/* Get Glyph index */
|
|
if ( sscanf( argv[0], "%d", &glyph_index ) != 1 )
|
|
{
|
|
printf( "invalid glyph index = %s\n", argv[1] );
|
|
Usage();
|
|
}
|
|
|
|
/* Get Glyph size */
|
|
if ( sscanf( argv[1], "%d", &glyph_size ) != 1 )
|
|
{
|
|
printf( "invalid glyph size = %s\n", argv[1] );
|
|
Usage();
|
|
}
|
|
|
|
/* Get file name */
|
|
file_name = argv[2];
|
|
|
|
Init_Keyboard();
|
|
|
|
/* Init library, read face object, get driver, create size */
|
|
error = FT_Init_FreeType( &library );
|
|
if (error) Panic( "could not initialise FreeType library" );
|
|
|
|
memory = library->memory;
|
|
driver = FT_Get_Driver( library, "truetype" );
|
|
if (!driver) Panic( "could not find the TrueType driver in FreeType 2\n" );
|
|
|
|
FT_Set_Debug_Hook( library,
|
|
FT_DEBUG_HOOK_TRUETYPE,
|
|
(FT_DebugHook_Func)RunIns );
|
|
|
|
error = FT_New_Face( library, file_name, 0, (FT_Face*)&face );
|
|
if (error) Panic( "could not open font resource" );
|
|
|
|
/* find driver and check format */
|
|
if ( face->root.driver != driver )
|
|
{
|
|
error = FT_Err_Invalid_File_Format;
|
|
Panic( "This is not a TrueType font" );
|
|
}
|
|
|
|
size = (TT_Size)face->root.size;
|
|
|
|
if (glyph_index < 0)
|
|
{
|
|
exec = TT_New_Context( face );
|
|
size->debug = 1;
|
|
size->context = exec;
|
|
|
|
error = FT_Set_Char_Size( (FT_Face)face, glyph_size << 6, glyph_size << 6, 72, 72 );
|
|
if (error) Panic( "could not set character sizes" );
|
|
}
|
|
else
|
|
{
|
|
error = FT_Set_Char_Size( (FT_Face)face, glyph_size << 6, glyph_size << 6, 72, 72 );
|
|
if (error) Panic( "could not set character sizes" );
|
|
|
|
glyph = (TT_GlyphSlot)face->root.glyph;
|
|
|
|
/* Now load glyph */
|
|
error = FT_Load_Glyph( (FT_Face)face, glyph_index, FT_LOAD_DEFAULT );
|
|
if (error) Panic( "could not load glyph" );
|
|
}
|
|
|
|
Reset_Keyboard();
|
|
return 0;
|
|
}
|