HRESULT opentype_get_font_table(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE type, UINT32 font_index, UINT32 tag, const void **table_data, void **table_context, UINT32 *table_size, BOOL *found) { HRESULT hr; TTC_SFNT_V1 *font_header = NULL; void *sfnt_context; TT_TableRecord *table_record = NULL; void *table_record_context; int table_count, table_offset = 0; int i; if (found) *found = FALSE; if (table_size) *table_size = 0; if (type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) { const TTC_Header_V1 *ttc_header; void * ttc_context; hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context); if (SUCCEEDED(hr)) { table_offset = GET_BE_DWORD(ttc_header->OffsetTable[0]); if (font_index >= GET_BE_DWORD(ttc_header->numFonts)) hr = E_INVALIDARG; else hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context); IDWriteFontFileStream_ReleaseFileFragment(stream, ttc_context); } } else hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context); if (FAILED(hr)) return hr; table_count = GET_BE_WORD(font_header->numTables); table_offset += sizeof(*font_header); for (i = 0; i < table_count; i++) { hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context); if (FAILED(hr)) break; if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag) break; IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context); table_offset += sizeof(*table_record); } IDWriteFontFileStream_ReleaseFileFragment(stream, sfnt_context); if (SUCCEEDED(hr) && i < table_count) { int offset = GET_BE_DWORD(table_record->offset); int length = GET_BE_DWORD(table_record->length); IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context); if (found) *found = TRUE; if (table_size) *table_size = length; hr = IDWriteFontFileStream_ReadFileFragment(stream, table_data, offset, length, table_context); } return hr; }
void opentype_get_font_properties(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE type, UINT32 index, struct dwrite_font_props *props) { void *os2_context, *head_context; const TT_OS2_V2 *tt_os2; const TT_HEAD *tt_head; opentype_get_font_table(stream, type, index, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL); opentype_get_font_table(stream, type, index, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL); /* default stretch, weight and style to normal */ props->stretch = DWRITE_FONT_STRETCH_NORMAL; props->weight = DWRITE_FONT_WEIGHT_NORMAL; props->style = DWRITE_FONT_STYLE_NORMAL; memset(&props->panose, 0, sizeof(props->panose)); /* DWRITE_FONT_STRETCH enumeration values directly match font data values */ if (tt_os2) { if (GET_BE_WORD(tt_os2->usWidthClass) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED) props->stretch = GET_BE_WORD(tt_os2->usWidthClass); props->weight = GET_BE_WORD(tt_os2->usWeightClass); memcpy(&props->panose, &tt_os2->panose, sizeof(props->panose)); TRACE("stretch=%d, weight=%d\n", props->stretch, props->weight); } if (tt_head) { USHORT macStyle = GET_BE_WORD(tt_head->macStyle); if (macStyle & 0x0002) props->style = DWRITE_FONT_STYLE_ITALIC; } if (tt_os2) IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context); if (tt_head) IDWriteFontFileStream_ReleaseFileFragment(stream, head_context); }
HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported) { /* TODO: Do font validation */ DWRITE_FONT_FACE_TYPE face; const void *font_data; const char* tag; void *context; HRESULT hr; hr = IDWriteFontFileStream_ReadFileFragment(stream, &font_data, 0, sizeof(TTC_Header_V1), &context); if (FAILED(hr)) return hr; tag = font_data; *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN; face = DWRITE_FONT_FACE_TYPE_UNKNOWN; *font_count = 0; if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_TTCF_TAG) { const TTC_Header_V1 *header = font_data; *font_count = GET_BE_DWORD(header->numFonts); *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION; face = DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION; } else if (GET_BE_DWORD(*(DWORD*)font_data) == 0x10000) { *font_count = 1; *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE; face = DWRITE_FONT_FACE_TYPE_TRUETYPE; } else if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_OTTO_TAG) { *file_type = DWRITE_FONT_FILE_TYPE_CFF; face = DWRITE_FONT_FACE_TYPE_CFF; } if (face_type) *face_type = face; *supported = is_face_type_supported(face); IDWriteFontFileStream_ReleaseFileFragment(stream, context); return S_OK; }
void opentype_get_font_metrics(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index, DWRITE_FONT_METRICS1 *metrics, DWRITE_CARET_METRICS *caret) { void *os2_context, *head_context, *post_context, *hhea_context; const TT_OS2_V2 *tt_os2; const TT_HEAD *tt_head; const TT_POST *tt_post; const TT_HHEA *tt_hhea; memset(metrics, 0, sizeof(*metrics)); opentype_get_font_table(stream, face_type, face_index, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL); opentype_get_font_table(stream, face_type, face_index, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL); opentype_get_font_table(stream, face_type, face_index, MS_POST_TAG, (const void**)&tt_post, &post_context, NULL, NULL); opentype_get_font_table(stream, face_type, face_index, MS_HHEA_TAG, (const void**)&tt_hhea, &hhea_context, NULL, NULL); if (tt_head) { metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm); metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin); metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax); metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax); metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin); } if (caret) { if (tt_hhea) { caret->slopeRise = GET_BE_WORD(tt_hhea->caretSlopeRise); caret->slopeRun = GET_BE_WORD(tt_hhea->caretSlopeRun); caret->offset = GET_BE_WORD(tt_hhea->caretOffset); } else { caret->slopeRise = 0; caret->slopeRun = 0; caret->offset = 0; } } if (tt_os2) { USHORT version = GET_BE_WORD(tt_os2->version); metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent); metrics->descent = GET_BE_WORD(tt_os2->usWinDescent); /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */ if (tt_hhea) { SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender); INT32 linegap; linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) - metrics->ascent - metrics->descent; metrics->lineGap = linegap > 0 ? linegap : 0; } metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition); metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize); metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset); /* Y offset is stored as positive offset below baseline */ metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset); metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize); metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize); metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset); metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset); metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize); metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize); /* version 2 fields */ if (version >= 2) { metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight); metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight); } /* version 4 fields */ if (version >= 4) { if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) { SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender); metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender); metrics->descent = descent < 0 ? -descent : 0; metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap); metrics->hasTypographicMetrics = TRUE; } } } if (tt_post) { metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition); metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness); } /* estimate missing metrics */ if (metrics->xHeight == 0) metrics->xHeight = metrics->designUnitsPerEm / 2; if (metrics->capHeight == 0) metrics->capHeight = metrics->designUnitsPerEm * 7 / 10; if (tt_os2) IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context); if (tt_head) IDWriteFontFileStream_ReleaseFileFragment(stream, head_context); if (tt_post) IDWriteFontFileStream_ReleaseFileFragment(stream, post_context); if (tt_hhea) IDWriteFontFileStream_ReleaseFileFragment(stream, hhea_context); }