FontBLF: Store Sizes, Styles, and Other Metrics #113432

Merged
Harley Acheson merged 6 commits from Harley/blender:FontMetrics into main 2023-10-14 02:43:56 +02:00
2 changed files with 245 additions and 0 deletions

View File

@ -1344,6 +1344,176 @@ static void blf_font_fill(FontBLF *font)
font->buf_info.col_init[3] = 0;
}
/* Note that the data the following function creates is not yet used.
* But do not remove it as it will be used in the near future - Harley */
static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
{
/* Members with non-zero defaults. */
metrics->weight = 400;
metrics->width = 1.0f;
metrics->spacing = 1.0f;
TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
if (os2_table) {
/* The default (resting) font weight. */
if (os2_table->usWeightClass >= 1 && os2_table->usWeightClass <= 1000) {
metrics->weight = short(os2_table->usWeightClass);
}
/* Width value is one of integers 1-9 with known values. */
if (os2_table->usWidthClass >= 1 && os2_table->usWidthClass <= 9) {
switch (os2_table->usWidthClass) {
case 1:
metrics->width = 0.5f;
break;
case 2:
metrics->width = 0.625f;
break;
case 3:
metrics->width = 0.75f;
break;
case 4:
metrics->width = 0.875f;
break;
case 5:
metrics->width = 1.0f;
break;
case 6:
metrics->width = 1.125f;
break;
case 7:
metrics->width = 1.25f;
break;
case 8:
metrics->width = 1.5f;
break;
case 9:
metrics->width = 2.0f;
break;
}
}
metrics->strikeout_position = short(os2_table->yStrikeoutPosition);
metrics->strikeout_thickness = short(os2_table->yStrikeoutSize);
metrics->subscript_size = short(os2_table->ySubscriptYSize);
metrics->subscript_xoffset = short(os2_table->ySubscriptXOffset);
metrics->subscript_yoffset = short(os2_table->ySubscriptYOffset);
metrics->superscript_size = short(os2_table->ySuperscriptYSize);
metrics->superscript_xoffset = short(os2_table->ySuperscriptXOffset);
metrics->superscript_yoffset = short(os2_table->ySuperscriptYOffset);
metrics->family_class = short(os2_table->sFamilyClass);
metrics->selection_flags = short(os2_table->fsSelection);
metrics->first_charindex = short(os2_table->usFirstCharIndex);
metrics->last_charindex = short(os2_table->usLastCharIndex);
if (os2_table->version > 1) {
metrics->cap_height = short(os2_table->sCapHeight);
metrics->x_height = short(os2_table->sxHeight);
}
}
/* The Post table usually contains a slant value, but in counter-clockwise degrees. */
TT_Postscript *post_table = (TT_Postscript *)FT_Get_Sfnt_Table(face, FT_SFNT_POST);
if (post_table) {
if (post_table->italicAngle != 0) {
metrics->slant = float(post_table->italicAngle) / -65536.0f;
}
}
/* Metrics copied from those gathered by FreeType. */
metrics->units_per_EM = short(face->units_per_EM);
metrics->ascender = short(face->ascender);
metrics->descender = short(face->descender);
metrics->line_height = short(face->height);
metrics->max_advance_width = short(face->max_advance_width);
metrics->max_advance_height = short(face->max_advance_height);
metrics->underline_position = short(face->underline_position);
metrics->underline_thickness = short(face->underline_thickness);
metrics->num_glyphs = int(face->num_glyphs);
metrics->bounding_box.xmin = int(face->bbox.xMin);
metrics->bounding_box.xmax = int(face->bbox.xMax);
metrics->bounding_box.ymin = int(face->bbox.yMin);
metrics->bounding_box.ymax = int(face->bbox.yMax);
if (metrics->cap_height == 0) {
/* Calculate or guess cap height if it is not set in the font. */
FT_UInt gi = FT_Get_Char_Index(face, uint('H'));
if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
metrics->cap_height = short(face->glyph->metrics.height);
}
else {
metrics->cap_height = short(float(metrics->units_per_EM) * 0.7f);
}
}
if (metrics->x_height == 0) {
/* Calculate or guess x-height if it is not set in the font. */
FT_UInt gi = FT_Get_Char_Index(face, uint('x'));
if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
metrics->x_height = short(face->glyph->metrics.height);
}
else {
metrics->x_height = short(float(metrics->units_per_EM) * 0.5f);
}
}
FT_UInt gi = FT_Get_Char_Index(face, uint('o'));
if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
metrics->o_proportion = float(face->glyph->metrics.width) / float(face->glyph->metrics.height);
}
if (metrics->ascender == 0) {
/* Set a sane value for ascender if not set in the font. */
metrics->ascender = short(float(metrics->units_per_EM) * 0.8f);
}
if (metrics->descender == 0) {
/* Set a sane value for descender if not set in the font. */
metrics->descender = metrics->ascender - metrics->units_per_EM;
}
if (metrics->weight == 400 && face->style_flags & FT_STYLE_FLAG_BOLD) {
/* Normal weight yet this is an bold font, so set a sane weight value. */
metrics->weight = 700;
}
if (metrics->slant == 0.0f && face->style_flags & FT_STYLE_FLAG_ITALIC) {
/* No slant yet this is an italic font, so set a sane slant value. */
metrics->slant = 8.0f;
}
if (metrics->underline_position == 0) {
metrics->underline_position = short(float(metrics->units_per_EM) * -0.2f);
}
if (metrics->underline_thickness == 0) {
metrics->underline_thickness = short(float(metrics->units_per_EM) * 0.07f);
}
if (metrics->strikeout_position == 0) {
metrics->strikeout_position = short(float(metrics->x_height) * 0.6f);
}
if (metrics->strikeout_thickness == 0) {
metrics->strikeout_thickness = metrics->underline_thickness;
}
if (metrics->subscript_size == 0) {
metrics->subscript_size = short(float(metrics->units_per_EM) * 0.6f);
}
if (metrics->subscript_yoffset == 0) {
metrics->subscript_yoffset = short(float(metrics->units_per_EM) * 0.075f);
}
if (metrics->superscript_size == 0) {
metrics->superscript_size = short(float(metrics->units_per_EM) * 0.6f);
}
if (metrics->superscript_yoffset == 0) {
metrics->superscript_yoffset = short(float(metrics->units_per_EM) * 0.35f);
}
}
bool blf_ensure_face(FontBLF *font)
{
if (font->face) {
@ -1431,6 +1601,9 @@ bool blf_ensure_face(FontBLF *font)
FT_Get_MM_Var(font->face, &(font->variations));
}
blf_ensure_size(font);
blf_font_metrics(font->face, &font->metrics);
/* Save TrueType table with bits to quickly test most unicode block coverage. */
TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
if (os2_table) {

View File

@ -209,6 +209,75 @@ typedef struct FontBufInfoBLF {
} FontBufInfoBLF;
typedef struct FontMetrics {
/** This font's default weight, 100-900, 400 is normal. */
short weight;
/** This font's default width, 1 is normal, 2 is twice as wide. */
float width;
/** This font's slant in clockwise degrees, 0 being upright. */
float slant;
/** This font's default spacing, 1 is normal. */
float spacing;
/** Number of font units in an EM square. 2048, 1024, 1000 are typical. */
short units_per_EM; /* */
/** Design classification from OS/2 sFamilyClass. */
short family_class;
/** Style classification from OS/2 fsSelection. */
short selection_flags;
/** Total number of glyphs in the font. */
int num_glyphs;
/** Minimum Unicode index, typically 0x0020. */
short first_charindex;
/** Maximum Unicode index, or 0xFFFF if greater than. */
short last_charindex;
/**
* Bounds that can contain every glyph in the font when in default positions. Can be used for
* maximum ascender, minimum descender. Can be out by a pixel when hinting. Does not change with
* variation axis changes. */
rcti bounding_box;
/**
* Positive number of font units from baseline to top of typical capitals. Can be slightly more
* than cap height when head serifs, terminals, or apexes extend above cap line. */
short ascender;
/** Negative (!) number of font units from baseline to bottom of letters like "gjpqy". */
short descender;
/** Positive number of font units between consecutive baselines. */
short line_height;
/** Font units from baseline to lowercase mean line, typically to top of "x". */
short x_height;
/** Font units from baseline to top of capital letters, specifically "H". */
short cap_height;
/** Ratio width to heigh of lowercase "O". Reliable indication of font proportion. */
float o_proportion;
/** Font unit maximum horizontal advance for all glyphs in font. Can help with wrapping. */
short max_advance_width;
/** As above but only for vertical layout fonts, otherwise is set to line_height value. */
short max_advance_height;
/** Negative (!) number of font units below baseline to center (!) of underlining stem. */
short underline_position;
/** thickness of the underline in font units. */
short underline_thickness;
/** Positive number of font units above baseline to the top (!) of strikeout stroke. */
short strikeout_position;
/** thickness of the strikeout line in font units. */
short strikeout_thickness;
/** EM size font units of recommended subscript letters. */
short subscript_size;
/** Horizontal offset before first subscript character, typically 0. */
short subscript_xoffset;
/** Postive number of font units above baseline for subscript characters. */
short subscript_yoffset;
/** EM size font units of recommended superscript letters. */
short superscript_size;
/** Horizontal offset before first superscript character, typically 0. */
short superscript_xoffset;
/** Postive (!) number of font units below baseline for subscript characters. */
short superscript_yoffset;
} FontMetrics;
typedef struct FontBLF {
/** Full path to font file or NULL if from memory. */
char *filepath;
@ -307,6 +376,9 @@ typedef struct FontBLF {
/** Copy of the font->face->face_flags, in case we don't have a face loaded. */
FT_Long face_flags;
/** Details about the font's design and style and sizes (in unsized font units). */
FontMetrics metrics;
/** Data for buffer usage (drawing into a texture buffer) */
FontBufInfoBLF buf_info;