diff options
-rw-r--r-- | fonttosfnt.h | 23 | ||||
-rw-r--r-- | read.c | 37 | ||||
-rw-r--r-- | struct.c | 125 | ||||
-rw-r--r-- | util.c | 13 | ||||
-rw-r--r-- | write.c | 49 |
5 files changed, 176 insertions, 71 deletions
diff --git a/fonttosfnt.h b/fonttosfnt.h index 202ab5a..a05e036 100644 --- a/fonttosfnt.h +++ b/fonttosfnt.h @@ -86,6 +86,22 @@ typedef struct _FontNameEntry { char *value; } FontNameEntryRec, *FontNameEntryPtr; +typedef struct _Metrics { + int height; + int maxX; + int minX; + int maxY; + int minY; + int xHeight; + int capHeight; + int maxAwidth; + int awidth; + int ascent; + int descent; + int underlinePosition; + int underlineThickness; +} MetricsRec, *MetricsPtr; + typedef struct _Font { int numNames; struct _FontNameEntry *names; @@ -93,8 +109,8 @@ typedef struct _Font { int weight; /* as in the OS/2 table */ int width; /* as in the OS/2 table */ int italicAngle; /* degrees c-clockwise from the vertical */ - int underlinePosition; - int underlineThickness; + MetricsRec pxMetrics; + MetricsRec metrics; unsigned foundry; struct _Strike *strikes; } FontRec, *FontPtr; @@ -153,7 +169,7 @@ int findCode(CmapPtr, int); BitmapPtr strikeBitmapIndex(StrikePtr, CmapPtr, int); void strikeMetrics(StrikePtr, int*, int*, int*, int*, int*); int glyphMetrics(FontPtr, int, int*, int*, int*, int*, int*); -void fontMetrics(FontPtr, int*, int*, int*, int*, int*); +void fontMetrics(FontPtr, MetricsPtr); int maxIndex(CmapPtr); int readFile(char *filename, FontPtr); @@ -173,6 +189,7 @@ int macTime(int *, unsigned *); unsigned faceFoundry(FT_Face); char *faceEncoding(FT_Face); int faceFlags(FT_Face); +int faceIntProp(FT_Face, const char *); int faceWeight(FT_Face); int faceWidth(FT_Face); int faceItalicAngle(FT_Face); @@ -258,30 +258,6 @@ readFile(char *filename, FontPtr font) i++; #endif font->numNames = i; - - font->flags = faceFlags(face) | (symbol ? FACE_SYMBOL : 0); - font->weight = faceWeight(face); - font->width = faceWidth(face); - font->foundry = faceFoundry(face); - font->italicAngle = faceItalicAngle(face); - - rc = FT_Get_BDF_Property(face, "UNDERLINE_POSITION", &prop); - if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) - font->underlinePosition = - (double)prop.u.integer / face->available_sizes[0].height * - TWO_SIXTEENTH; - else - font->underlinePosition = - - 1.5 / face->available_sizes[0].height * TWO_SIXTEENTH; - - rc = FT_Get_BDF_Property(face, "UNDERLINE_THICKNESS", &prop); - if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) - font->underlineThickness = - (double)prop.u.integer / face->available_sizes[0].height * - TWO_SIXTEENTH; - else - font->underlineThickness = - 1.0 / face->available_sizes[0].height * TWO_SIXTEENTH; } if(face->num_fixed_sizes == 0) { @@ -304,6 +280,19 @@ readFile(char *filename, FontPtr font) return -1; } + font->flags = faceFlags(face) | (symbol ? FACE_SYMBOL : 0); + font->weight = faceWeight(face); + font->width = faceWidth(face); + font->foundry = faceFoundry(face); + font->italicAngle = faceItalicAngle(face); + font->pxMetrics.height = face->available_sizes[0].height; + font->pxMetrics.xHeight = faceIntProp(face, "X_HEIGHT"); + font->pxMetrics.capHeight = faceIntProp(face, "CAP_HEIGHT"); + font->pxMetrics.ascent = faceIntProp(face, "FONT_ASCENT"); + font->pxMetrics.descent = faceIntProp(face, "FONT_DESCENT"); + font->pxMetrics.underlinePosition = faceIntProp(face, "UNDERLINE_POSITION"); + font->pxMetrics.underlineThickness = faceIntProp(face, "UNDERLINE_THICKNESS"); + for(int i = 0; i < face->num_fixed_sizes; i++) { if(verbose_flag) fprintf(stderr, "size %d: %dx%d\n", @@ -42,8 +42,32 @@ makeFont(void) font->weight = 500; font->width = 5; font->italicAngle = 0; - font->underlinePosition = - TWO_SIXTEENTH; - font->underlineThickness = TWO_SIXTEENTH; + font->pxMetrics.height = UNDEF; + font->pxMetrics.maxX = UNDEF; + font->pxMetrics.minX = UNDEF; + font->pxMetrics.maxY = UNDEF; + font->pxMetrics.minY = UNDEF; + font->pxMetrics.xHeight = UNDEF; + font->pxMetrics.capHeight = UNDEF; + font->pxMetrics.maxAwidth = UNDEF; + font->pxMetrics.awidth = UNDEF; + font->pxMetrics.ascent = UNDEF; + font->pxMetrics.descent = UNDEF; + font->pxMetrics.underlinePosition = UNDEF; + font->pxMetrics.underlineThickness = UNDEF; + font->metrics.height = UNDEF; + font->metrics.maxX = UNDEF; + font->metrics.minX = UNDEF; + font->metrics.maxY = UNDEF; + font->metrics.minY = UNDEF; + font->metrics.xHeight = UNDEF; + font->metrics.capHeight = UNDEF; + font->metrics.maxAwidth = UNDEF; + font->metrics.awidth = UNDEF; + font->metrics.ascent = UNDEF; + font->metrics.descent = UNDEF; + font->metrics.underlinePosition = UNDEF; + font->metrics.underlineThickness = UNDEF; font->foundry = makeName("UNKN"); font->strikes = NULL; return font; @@ -480,31 +504,90 @@ glyphMetrics(FontPtr font, int code, } void -fontMetrics(FontPtr font, - int *max_awidth_return, - int *min_x_return, int *min_y_return, - int *max_x_return, int *max_y_return) +fontMetrics(FontPtr font, MetricsPtr metrics) { int i, rc; - int max_awidth = 0; - int min_x = 10000 * 65536, min_y = 10000 * 65536; - int max_x = -10000 * 65536, max_y = -10000 * 65536; + double sumAwidth = 0; + unsigned count = 0; + + metrics->height = UNDEF /* TODO */; + metrics->maxAwidth = 0; + metrics->maxX = -10000 * TWO_SIXTEENTH; + metrics->maxY = -10000 * TWO_SIXTEENTH; + metrics->minX = 10000 * TWO_SIXTEENTH; + metrics->minY = 10000 * TWO_SIXTEENTH; + metrics->ascent = UNDEF; + metrics->descent = UNDEF; + metrics->underlinePosition = UNDEF; + metrics->underlineThickness = UNDEF; + for(i = 0; i < FONT_CODES; i++) { int awidth, x0, y0, x1, y1; rc = glyphMetrics(font, i, &awidth, &x0, &y0, &x1, &y1); if(rc < 0) continue; - if(awidth > max_awidth) - max_awidth = awidth; - if(x0 < min_x) min_x = x0; - if(y0 < min_y) min_y = y0; - if(x1 > max_x) max_x = x1; - if(y1 > max_y) max_y = y1; + + if(awidth > metrics->maxAwidth) metrics->maxAwidth = awidth; + if(x0 < metrics->minX) metrics->minX = x0; + if(y0 < metrics->minY) metrics->minY = y0; + if(x1 > metrics->maxX) metrics->maxX = x1; + if(y1 > metrics->maxY) metrics->maxY = y1; + + if(awidth > 0) { + sumAwidth += awidth; + count++; + } } - if(max_awidth_return) *max_awidth_return = max_awidth; - if(min_x_return) *min_x_return = min_x; - if(min_y_return) *min_y_return = min_y; - if(max_x_return) *max_x_return = max_x; - if(max_y_return) *max_y_return = max_y; -} + if (count) metrics->awidth = sumAwidth / count; + + if(font->pxMetrics.ascent == UNDEF) + metrics->ascent = metrics->maxY; + else + metrics->ascent = + font->pxMetrics.ascent + * TWO_SIXTEENTH / font->pxMetrics.height; + + if(font->pxMetrics.descent == UNDEF) + metrics->descent = metrics->minY; + else + metrics->descent = + font->pxMetrics.descent + * TWO_SIXTEENTH / font->pxMetrics.height; + + if(font->pxMetrics.capHeight == UNDEF) + /* TODO get ascent of letter 'X' - how to do lookups of ascii codes ? */ + metrics->capHeight = metrics->ascent; + else + metrics->capHeight = + font->pxMetrics.capHeight + * TWO_SIXTEENTH / font->pxMetrics.height; + + if(font->pxMetrics.xHeight == UNDEF) + /* TODO get ascent of letter 'x' - how to do lookups of ascii codes ? */ + metrics->xHeight = metrics->ascent * 2 / 3; + else + metrics->xHeight = + font->pxMetrics.xHeight + * TWO_SIXTEENTH / font->pxMetrics.height; + + if(font->pxMetrics.underlinePosition == UNDEF) + metrics->underlinePosition = - metrics->descent * 2; + else + metrics->underlinePosition = + font->pxMetrics.underlinePosition + * TWO_SIXTEENTH / font->pxMetrics.height; + + if(font->pxMetrics.underlineThickness == UNDEF) + /* TODO: this could be refined according to + * X Logical Font Description Conventions (xlfd.txt) + * by also considering the font weight. */ + /* make sure thickness is at least one pixel. */ + metrics->underlineThickness = + TWO_SIXTEENTH + / (font->pxMetrics.height < 9 ? font->pxMetrics.height : 9); + else + metrics->underlineThickness = + font->pxMetrics.underlineThickness + * TWO_SIXTEENTH / font->pxMetrics.height; +} @@ -391,6 +391,19 @@ faceFlags(FT_Face face) return flags; } +int +faceIntProp(FT_Face face, const char *name) +{ + int rc; + BDF_PropertyRec prop; + + rc = FT_Get_BDF_Property(face, name, &prop); + if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) + return prop.u.integer; + else + return UNDEF; +} + char * faceEncoding(FT_Face face) { @@ -61,7 +61,6 @@ static int writemaxp(FILE*, FontPtr); static int writename(FILE*, FontPtr); static int writepost(FILE*, FontPtr); -int max_awidth, min_x, min_y, max_x, max_y; static CmapPtr current_cmap = NULL; static int numglyphs, nummetrics; static int write_error_occurred, read_error_occurred; @@ -219,7 +218,7 @@ writeFile(char *filename, FontPtr font) int offset[15], length[15]; StrikePtr strike; - fontMetrics(font, &max_awidth, &min_x, &min_y, &max_x, &max_y); + fontMetrics(font, &font->metrics); out = fopen(filename, "wb+"); if(out == NULL) @@ -451,10 +450,12 @@ writehead(FILE* out, FontPtr font) writeLONG(out, time_hi); /* modified */ writeULONG(out, time_lo); - writeUSHORT(out, FONT_UNITS_FLOOR(min_x)); - writeUSHORT(out, FONT_UNITS_FLOOR(min_y)); - writeUSHORT(out, FONT_UNITS_CEIL(max_x)); - writeUSHORT(out, FONT_UNITS_CEIL(max_y)); + /* bounding box for all glyphs */ + writeUSHORT(out, FONT_UNITS_FLOOR(font->metrics.minX)); + writeUSHORT(out, FONT_UNITS_FLOOR(font->metrics.minY)); + writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.maxX)); + writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.maxY)); + writeUSHORT(out, font->flags); /* macStyle */ writeUSHORT(out, 1); /* lowestRecPPEM */ writeSHORT(out, 0); /* fontDirectionHint */ @@ -849,13 +850,15 @@ writehhea(FILE* out, FontPtr font) degreesToFraction(font->italicAngle, &num, &den); writeULONG(out, 0x00010000); /* version */ - writeSHORT(out, FONT_UNITS_CEIL(max_y)); /* ascender */ - writeSHORT(out, FONT_UNITS_FLOOR(min_y)); /* descender */ + writeSHORT(out, FONT_UNITS_CEIL(font->metrics.ascent)); /* ascender */ + writeSHORT(out, 0-FONT_UNITS_CEIL(font->metrics.descent)); /* descender */ writeSHORT(out, 0); /* lineGap */ - writeUSHORT(out, FONT_UNITS(max_awidth)); /* advanceWidthMax */ - writeSHORT(out, FONT_UNITS_FLOOR(min_x)); /* minLeftSideBearing */ - writeSHORT(out, FONT_UNITS_FLOOR(min_x)); /* minRightSideBearing */ - writeSHORT(out, FONT_UNITS_CEIL(max_x)); /* xMaxExtent */ + writeUSHORT(out, FONT_UNITS(font->metrics.maxAwidth)); /* advanceWidthMax */ + /* TODO: the next three are not calculated according to spec, are they ? + * https://docs.microsoft.com/en-us/typography/opentype/spec/hhea */ + writeSHORT(out, FONT_UNITS_FLOOR(font->metrics.minX)); /* minLeftSideBearing */ + writeSHORT(out, FONT_UNITS_FLOOR(font->metrics.minX)); /* minRightSideBearing */ + writeSHORT(out, FONT_UNITS_CEIL(font->metrics.maxX)); /* xMaxExtent */ writeSHORT(out, den); /* caretSlopeRise */ writeSHORT(out, num); /* caretSlopeRun */ writeSHORT(out, 0); /* reserved */ @@ -974,8 +977,8 @@ writepost(FILE* out, FontPtr font) writeULONG(out, 0x00030000); /* FormatType */ writeULONG(out, font->italicAngle); /* italicAngle */ - writeSHORT(out, FONT_UNITS(font->underlinePosition)); - writeSHORT(out, FONT_UNITS(font->underlineThickness)); + writeSHORT(out, FONT_UNITS(font->metrics.underlinePosition)); + writeSHORT(out, FONT_UNITS(font->metrics.underlineThickness)); writeULONG(out, fixed_pitch); /* isFixedPitch */ writeULONG(out, 0); /* minMemType42 */ writeULONG(out, 0); /* maxMemType42 */ @@ -990,7 +993,7 @@ writeOS2(FILE* out, FontPtr font) int i; writeUSHORT(out, 0x0001); - writeSHORT(out, FONT_UNITS(max_awidth / 2)); /* xAvgCharWidth; */ + writeSHORT(out, FONT_UNITS(font->metrics.awidth)); /* xAvgCharWidth; */ writeUSHORT(out, font->weight); /* usWeightClass; */ writeUSHORT(out, font->width); /* usWidthClass; */ writeSHORT(out, 0); /* fsType; */ @@ -1002,7 +1005,7 @@ writeOS2(FILE* out, FontPtr font) writeSHORT(out, UNITS_PER_EM / 5); /* ySuperscriptYSize; */ writeSHORT(out, 0); /* ySuperscriptXOffset; */ writeSHORT(out, UNITS_PER_EM / 5); /* ySuperscriptYOffset; */ - writeSHORT(out, FONT_UNITS(font->underlineThickness)); + writeSHORT(out, FONT_UNITS(font->metrics.underlineThickness)); /* yStrikeoutSize; */ writeSHORT(out, UNITS_PER_EM / 4); /* yStrikeoutPosition; */ writeSHORT(out, 0); /* sFamilyClass; */ @@ -1023,11 +1026,11 @@ writeOS2(FILE* out, FontPtr font) writeUSHORT(out, i); /* fsSelection; */ writeUSHORT(out, 0x20); /* usFirstCharIndex; */ writeUSHORT(out, 0xFFFD); /* usLastCharIndex; */ - writeUSHORT(out, FONT_UNITS_CEIL(max_y)); /* sTypoAscender; */ - writeUSHORT(out, FONT_UNITS_FLOOR(min_y)); /* sTypoDescender; */ + writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.ascent)); /* sTypoAscender; */ + writeUSHORT(out, FONT_UNITS_FLOOR(font->metrics.descent)); /* sTypoDescender; */ writeUSHORT(out, 0); /* sTypoLineGap; */ - writeUSHORT(out, FONT_UNITS_CEIL(max_y)); /* usWinAscent; */ - writeUSHORT(out, -FONT_UNITS_FLOOR(min_y)); /* usWinDescent; */ + writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.maxY)); /* usWinAscent; */ + writeUSHORT(out, -FONT_UNITS_FLOOR(font->metrics.minY)); /* usWinDescent; */ writeULONG(out, 3); /* ulCodePageRange1; */ writeULONG(out, 0); /* ulCodePageRange2; */ return 0; @@ -1067,11 +1070,11 @@ writePCLT(FILE* out, FontPtr font) writeULONG(out, 0x00010000); /* version */ writeULONG(out, 0); /* FontNumber */ - writeUSHORT(out, FONT_UNITS(max_awidth)); /* pitch */ - writeUSHORT(out, FONT_UNITS(max_y)); /* xHeight */ + writeUSHORT(out, FONT_UNITS(font->metrics.maxAwidth)); /* pitch */ + writeUSHORT(out, FONT_UNITS(font->metrics.xHeight)); /* xHeight */ writeUSHORT(out, style); /* style */ writeUSHORT(out, 6 << 12); /* TypeFamily */ - writeUSHORT(out, FONT_UNITS(max_y)); /* CapHeight */ + writeUSHORT(out, FONT_UNITS(font->metrics.xHeight)); /* CapHeight */ writeUSHORT(out, 0); /* SymbolSet */ writeCHARs(out, name, 16); /* TypeFace */ writeBYTEs(out, charComplement, 8); /* CharacterComplement */ |