void opentype_get_font_properties(const void *os2, const void *head, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style) { TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2; TT_HEAD *tt_head = (TT_HEAD*)head; /* default stretch, weight and style to normal */ *stretch = DWRITE_FONT_STRETCH_NORMAL; *weight = DWRITE_FONT_WEIGHT_NORMAL; *style = DWRITE_FONT_STYLE_NORMAL; /* 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) *stretch = GET_BE_WORD(tt_os2->usWidthClass); *weight = GET_BE_WORD(tt_os2->usWeightClass); TRACE("stretch=%d, weight=%d\n", *stretch, *weight); } if (tt_head) { USHORT macStyle = GET_BE_WORD(tt_head->macStyle); if (macStyle & 0x0002) *style = DWRITE_FONT_STYLE_ITALIC; } }
static UINT calc_ppem_for_height(HDC hdc, LONG height) { BYTE os2[78]; /* size of version 0 table */ BYTE hhea[8]; /* just enough to get the ascender and descender */ LONG ascent = 0, descent = 0; UINT emsize; if(height < 0) return -height; if(GetFontData(hdc, MS_MAKE_TAG('O','S','/','2'), 0, os2, sizeof(os2)) == sizeof(os2)) { ascent = GET_BE_WORD(os2 + 74); /* usWinAscent */ descent = GET_BE_WORD(os2 + 76); /* usWinDescent */ } if(ascent + descent == 0) { if(GetFontData(hdc, MS_MAKE_TAG('h','h','e','a'), 0, hhea, sizeof(hhea)) == sizeof(hhea)) { ascent = (signed short)GET_BE_WORD(hhea + 4); /* Ascender */ descent = -(signed short)GET_BE_WORD(hhea + 6); /* Descender */ } } if(ascent + descent == 0) return height; get_bbox(hdc, NULL, &emsize); return MulDiv(emsize, height, ascent + descent); }
static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr) { WORD num_ratios, i, group_offset = 0; struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1); BYTE dev_x_ratio = 1, dev_y_ratio = 1; num_ratios = GET_BE_WORD(hdr->numRatios); for (i = 0; i < num_ratios; i++) { if (!ratios[i].bCharSet) continue; if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 && ratios[i].yEndRatio == 0) || (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio && ratios[i].yEndRatio >= dev_y_ratio)) { group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i)); break; } } if (group_offset) return (const struct VDMX_group *)((BYTE *)hdr + group_offset); return NULL; }
BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 *descent) { const struct VDMX_Header *hdr = (const struct VDMX_Header*)data; const struct VDMX_group *group; const struct VDMX_vTable *tables; WORD recs, i; if (!data) return FALSE; group = find_vdmx_group(hdr); if (!group) return FALSE; recs = GET_BE_WORD(group->recs); if (emsize < group->startsz || emsize >= group->endsz) return FALSE; tables = (const struct VDMX_vTable *)(group + 1); for (i = 0; i < recs; i++) { WORD ppem = GET_BE_WORD(tables[i].yPelHeight); if (ppem > emsize) { FIXME("interpolate %d\n", emsize); return FALSE; } if (ppem == emsize) { *ascent = (SHORT)GET_BE_WORD(tables[i].yMax); *descent = -(SHORT)GET_BE_WORD(tables[i].yMin); return TRUE; } } return FALSE; }
void opentype_cmap_get_glyphindex(void *data, UINT32 utf32c, UINT16 *pgi) { CMAP_Header *CMAP_Table = data; int i; *pgi = 0; for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) { WORD type; WORD *table; if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3) continue; table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset)); type = GET_BE_WORD(*table); TRACE("table type %i\n", type); switch (type) { case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING: CMAP4_GetGlyphIndex((CMAP_SegmentMapping_0*) table, utf32c, pgi); break; case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE: CMAP12_GetGlyphIndex((CMAP_SegmentedCoverage*) table, utf32c, pgi); break; default: TRACE("table type %i unhandled.\n", type); } if (*pgi) return; } }
static inline const OT_Script *opentype_get_script(const OT_ScriptList *scriptlist, UINT32 scripttag) { UINT16 j; for (j = 0; j < GET_BE_WORD(scriptlist->ScriptCount); j++) { const char *tag = scriptlist->ScriptRecord[j].ScriptTag; if (scripttag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3])) return (OT_Script*)((BYTE*)scriptlist + GET_BE_WORD(scriptlist->ScriptRecord[j].Script)); } return NULL; }
static inline const OT_LangSys *opentype_get_langsys(const OT_Script *script, UINT32 languagetag) { UINT16 j; for (j = 0; j < GET_BE_WORD(script->LangSysCount); j++) { const char *tag = script->LangSysRecord[j].LangSysTag; if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3])) return (OT_LangSys*)((BYTE*)script + GET_BE_WORD(script->LangSysRecord[j].LangSys)); } return NULL; }
/**************************************************************************** * get_bbox * * This retrieves the bounding box of the font in font units as well as * the size of the emsquare. To avoid having to worry about mapping mode and * the font size we'll get the data directly from the TrueType HEAD table rather * than using GetOutlineTextMetrics. */ static BOOL get_bbox(PSDRV_PDEVICE *physDev, RECT *rc, UINT *emsize) { BYTE head[54]; /* the head table is 54 bytes long */ if(GetFontData(physDev->hdc, MS_MAKE_TAG('h','e','a','d'), 0, head, sizeof(head)) == GDI_ERROR) { ERR("Can't retrieve head table\n"); return FALSE; } *emsize = GET_BE_WORD(head + 18); /* unitsPerEm */ rc->left = (signed short)GET_BE_WORD(head + 36); /* xMin */ rc->bottom = (signed short)GET_BE_WORD(head + 38); /* yMin */ rc->right = (signed short)GET_BE_WORD(head + 40); /* xMax */ rc->top = (signed short)GET_BE_WORD(head + 42); /* yMax */ return TRUE; }
static void opentype_add_font_features(const GPOS_GSUB_Header *header, const OT_LangSys *langsys, UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags) { const OT_FeatureList *features = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList)); UINT16 j; for (j = 0; j < GET_BE_WORD(langsys->FeatureCount); j++) { const OT_FeatureRecord *feature = &features->FeatureRecord[langsys->FeatureIndex[j]]; const char *tag = feature->FeatureTag; if (*count < max_tagcount) tags[*count] = DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]); (*count)++; } }
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; }
/**************************************************************************** * get_bbox * * This retrieves the bounding box of the font in font units as well as * the size of the emsquare. To avoid having to worry about mapping mode and * the font size we'll get the data directly from the TrueType HEAD table rather * than using GetOutlineTextMetrics. */ static UINT get_bbox(HDC hdc, RECT *rc) { BYTE head[54]; /* the head table is 54 bytes long */ if(GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, head, sizeof(head)) == GDI_ERROR) { ERR("Can't retrieve head table\n"); return 0; } if(rc) { rc->left = (signed short)GET_BE_WORD(head + 36); /* xMin */ rc->bottom = (signed short)GET_BE_WORD(head + 38); /* yMin */ rc->right = (signed short)GET_BE_WORD(head + 40); /* xMax */ rc->top = (signed short)GET_BE_WORD(head + 42); /* yMax */ } return GET_BE_WORD(head + 18); /* unitsPerEm */ }
static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag) { int i; const GSUB_FeatureList *feature; feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList)); TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount)); for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++) { int index = GET_BE_WORD(lang->FeatureIndex[i]); if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0) { const GSUB_Feature *feat; feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature)); return feat; } } return NULL; }
static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int i; int out_index = GSUB_E_NOGLYPH; const GSUB_LookupList *lookup; lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList)); TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount)); for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++) { out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count); if (out_index != GSUB_E_NOGLYPH) break; } if (out_index == GSUB_E_NOGLYPH) TRACE("lookups found no glyphs\n"); return out_index; }
static BOOL get_glyf_pos(TYPE42 *t42, DWORD index, DWORD *start, DWORD *end) { WORD loca_format = GET_BE_WORD(t42->tables[t42->head_tab].data + 50); TRACE("loca_format = %d\n", loca_format); switch(loca_format) { case 0: *start = GET_BE_WORD(((WORD*)t42->tables[t42->loca_tab].data) + index); *start <<= 1; *end = GET_BE_WORD(((WORD*)t42->tables[t42->loca_tab].data) + index + 1); *end <<= 1; break; case 1: *start = GET_BE_DWORD(((DWORD*)t42->tables[t42->loca_tab].data) + index); *end = GET_BE_DWORD(((DWORD*)t42->tables[t42->loca_tab].data) + index + 1); break; default: ERR("Unknown loca_format %d\n", loca_format); return FALSE; } return TRUE; }
static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int j; TRACE("Single Substitution Subtable\n"); for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) { int offset; const GSUB_SingleSubstFormat1 *ssf1; offset = GET_BE_WORD(look->SubTable[j]); ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset); if (GET_BE_WORD(ssf1->SubstFormat) == 1) { int offset = GET_BE_WORD(ssf1->Coverage); TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID)); if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1) { TRACE(" Glyph 0x%x ->",glyphs[glyph_index]); glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID); TRACE(" 0x%x\n",glyphs[glyph_index]); return glyph_index + 1; } } else { const GSUB_SingleSubstFormat2 *ssf2; INT index; INT offset; ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1; offset = GET_BE_WORD(ssf1->Coverage); TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount)); index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]); TRACE(" Coverage index %i\n",index); if (index != -1) { TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]); glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]); TRACE("0x%x\n",glyphs[glyph_index]); return glyph_index + 1; } } } return GSUB_E_NOGLYPH; }
static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int j; TRACE("Alternate Substitution Subtable\n"); for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) { int offset; const GSUB_AlternateSubstFormat1 *asf1; INT index; offset = GET_BE_WORD(look->SubTable[j]); asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset); offset = GET_BE_WORD(asf1->Coverage); index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]); if (index != -1) { const GSUB_AlternateSet *as; offset = GET_BE_WORD(asf1->AlternateSet[index]); as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset); FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount)); TRACE(" Glyph 0x%x ->",glyphs[glyph_index]); glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]); TRACE(" 0x%x\n",glyphs[glyph_index]); return glyph_index + 1; } } return GSUB_E_NOGLYPH; }
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); }
static BOOL get_font_metrics(HDC hdc, struct font_metrics *fm) { OUTLINETEXTMETRICW otm; TT_OS2_V2 tt_os2; TT_HHEA tt_hori; LONG size; UINT16 line_gap; otm.otmSize = sizeof(otm); if (!GetOutlineTextMetricsW(hdc, otm.otmSize, &otm)) return FALSE; fm->em_height = otm.otmEMSquare; fm->dpi = GetDeviceCaps(hdc, LOGPIXELSY); memset(&tt_hori, 0, sizeof(tt_hori)); if (GetFontData(hdc, MS_HHEA_TAG, 0, &tt_hori, sizeof(tt_hori)) != GDI_ERROR) { fm->ascent = GET_BE_WORD(tt_hori.Ascender); fm->descent = -GET_BE_WORD(tt_hori.Descender); TRACE("hhea: ascent %d, descent %d\n", fm->ascent, fm->descent); line_gap = GET_BE_WORD(tt_hori.LineGap); fm->line_spacing = fm->ascent + fm->descent + line_gap; TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing); if (fm->ascent + fm->descent != 0) return TRUE; } size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0); if (size == GDI_ERROR) return FALSE; if (size > sizeof(tt_os2)) size = sizeof(tt_os2); memset(&tt_os2, 0, sizeof(tt_os2)); if (GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size) != size) return FALSE; fm->ascent = GET_BE_WORD(tt_os2.usWinAscent); fm->descent = GET_BE_WORD(tt_os2.usWinDescent); TRACE("usWinAscent %u, usWinDescent %u\n", fm->ascent, fm->descent); if (fm->ascent + fm->descent == 0) { fm->ascent = GET_BE_WORD(tt_os2.sTypoAscender); fm->descent = GET_BE_WORD(tt_os2.sTypoDescender); TRACE("sTypoAscender %u, sTypoDescender %u\n", fm->ascent, fm->descent); } line_gap = GET_BE_WORD(tt_os2.sTypoLineGap); fm->line_spacing = fm->ascent + fm->descent + line_gap; TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing); return TRUE; }
HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count) { CMAP_Header *CMAP_Table = data; int i, k = 0; if (!CMAP_Table) return E_FAIL; *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table); for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++) { WORD type; WORD *table; int j; if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3) continue; table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset)); type = GET_BE_WORD(*table); TRACE("table type %i\n", type); switch (type) { case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING: { CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table; UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2; UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count)); for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) { ranges[k].first = GET_BE_WORD(startCode[j]); ranges[k].last = GET_BE_WORD(format->endCode[j]); } break; } case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE: { CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table; for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) { ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode); ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode); } break; } default: FIXME("table type %i unhandled.\n", type); } } return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK; }
static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int offset; const GSUB_LookupTable *look; offset = GET_BE_WORD(lookup->Lookup[lookup_index]); look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset); TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount)); switch(GET_BE_WORD(look->LookupType)) { case 1: return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count); case 3: return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count); case 4: return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count); case 6: return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count); default: FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType)); } return GSUB_E_NOGLYPH; }
static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag) { const GSUB_ScriptList *script; const GSUB_Script *deflt = NULL; int i; script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList)); TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount)); for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++) { const GSUB_Script *scr; int offset; offset = GET_BE_WORD(script->ScriptRecord[i].Script); scr = (const GSUB_Script*)((const BYTE*)script + offset); if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0) return scr; if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0) deflt = scr; } return deflt; }
static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table) { UINT32 count = 0; int i; for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) { WORD type; WORD *table; if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3) continue; table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset)); type = GET_BE_WORD(*table); TRACE("table type %i\n", type); switch (type) { case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING: { CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table; count += GET_BE_WORD(format->segCountX2)/2; break; } case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE: { CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table; count += GET_BE_DWORD(format->nGroups); break; } default: FIXME("table type %i unhandled.\n", type); } } return count; }
VOID OpenType_CMAP_GetGlyphIndex(LPVOID data, DWORD utf32c, LPWORD pgi, DWORD flags) { int i; CMAP_Header *CMAP_Table = NULL; if (flags & GGI_MARK_NONEXISTING_GLYPHS) *pgi = 0xffff; else *pgi = 0; CMAP_Table = data; for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++) { WORD type; WORD *table; if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3) continue; table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset)); type = GET_BE_WORD(*table); TRACE("Type %i\n", type); /* Break when we find a handled type */ switch(type) { case 4: CMAP4_GetGlyphIndex((CMAP_SegmentMapping_0*) table, utf32c, pgi); break; case 12: CMAP12_GetGlyphIndex((CMAP_SegmentedCoverage*) table, utf32c, pgi); break; default: TRACE("Type %i unhandled.\n", type); } } }
static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag) { int i; int offset; const GSUB_LangSys *Lang; TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount)); for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++) { offset = GET_BE_WORD(script->LangSysRecord[i].LangSys); Lang = (const GSUB_LangSys*)((const BYTE*)script + offset); if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0) return Lang; } offset = GET_BE_WORD(script->DefaultLangSys); if (offset) { Lang = (const GSUB_LangSys*)((const BYTE*)script + offset); return Lang; } return NULL; }
static BOOL is_fake_italic( HDC hdc ) { TEXTMETRICW tm; BYTE head[54]; /* the head table is 54 bytes long */ WORD mac_style; GetTextMetricsW( hdc, &tm ); if (!tm.tmItalic) return FALSE; if (GetFontData( hdc, MS_MAKE_TAG('h','e','a','d'), 0, head, sizeof(head) ) == GDI_ERROR) return FALSE; mac_style = GET_BE_WORD( head + 44 ); TRACE( "mac style %04x\n", mac_style ); return !(mac_style & 2); }
HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scripttag, UINT32 languagetag, UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags) { UINT32 tables[2] = { MS_GSUB_TAG, MS_GPOS_TAG }; HRESULT hr; UINT8 i; *count = 0; for (i = 0; i < sizeof(tables)/sizeof(tables[0]); i++) { const OT_ScriptList *scriptlist; const GPOS_GSUB_Header *header; const OT_Script *script; const void *ptr; void *context; UINT32 size; BOOL exists; exists = FALSE; hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists); if (FAILED(hr)) return hr; if (!exists) continue; header = (const GPOS_GSUB_Header*)ptr; scriptlist = (const OT_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList)); script = opentype_get_script(scriptlist, scripttag); if (script) { const OT_LangSys *langsys = opentype_get_langsys(script, languagetag); if (langsys) opentype_add_font_features(header, langsys, max_tagcount, count, tags); } IDWriteFontFace_ReleaseFontTable(fontface, context); } return *count > max_tagcount ? E_NOT_SUFFICIENT_BUFFER : S_OK; }
BOOL T42_download_glyph(PSDRV_PDEVICE *physDev, DOWNLOAD *pdl, DWORD index, char *glyph_name) { DWORD start, end, i; char *buf; TYPE42 *t42; const char glyph_def[] = "/%s findfont exch 1 index\n" "havetype42gdir\n" "{/GlyphDirectory get begin %d exch def end}\n" "{/sfnts get 4 index get 3 index 2 index putinterval pop}\n" "ifelse\n" "/CharStrings get\n" "begin\n" " /%s %d def\n" "end\n" "pop pop\n"; TRACE("%d %s\n", index, glyph_name); assert(pdl->type == Type42); t42 = pdl->typeinfo.Type42; if(index < t42->glyph_sent_size) { if(t42->glyph_sent[index]) return TRUE; } else { t42->glyph_sent_size = (index / GLYPH_SENT_INC + 1) * GLYPH_SENT_INC; t42->glyph_sent = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, t42->glyph_sent, t42->glyph_sent_size * sizeof(*(t42->glyph_sent))); } if(!get_glyf_pos(t42, index, &start, &end)) return FALSE; TRACE("start = %x end = %x\n", start, end); if(GET_BE_WORD(t42->tables[t42->glyf_tab].data + start) == 0xffff) { /* Composite glyph */ BYTE *sg_start = t42->tables[t42->glyf_tab].data + start + 10; DWORD sg_flags, sg_index; char sg_name[MAX_G_NAME + 1]; do { sg_flags = GET_BE_WORD(sg_start); sg_index = GET_BE_WORD(sg_start + 2); TRACE("Sending subglyph %04x for glyph %04x\n", sg_index, index); get_glyph_name(physDev->hdc, sg_index, sg_name); T42_download_glyph(physDev, pdl, sg_index, sg_name); sg_start += 4; if(sg_flags & ARG_1_AND_2_ARE_WORDS) sg_start += 4; else sg_start += 2; if(sg_flags & WE_HAVE_A_SCALE) sg_start += 2; else if(sg_flags & WE_HAVE_AN_X_AND_Y_SCALE) sg_start += 4; else if(sg_flags & WE_HAVE_A_TWO_BY_TWO) sg_start += 8; } while(sg_flags & MORE_COMPONENTS); } for(i = 1; t42->glyf_blocks[i]; i++) if(start < t42->glyf_blocks[i]) break; buf = HeapAlloc(GetProcessHeap(), 0, sizeof(glyph_def) + strlen(pdl->ps_name) + 100); /* we don't have a string for the gdir and glyf tables, but we do have a string for the TT header. So the offset we need is tables - 2 */ sprintf(buf, "%d %d\n", t42->num_of_written_tables - 2 + i, start - t42->glyf_blocks[i-1]); PSDRV_WriteSpool(physDev, buf, strlen(buf)); PSDRV_WriteSpool(physDev, "<", 1); for(i = start; i < end; i++) { sprintf(buf, "%02x", *(t42->tables[t42->glyf_tab].data + i)); PSDRV_WriteSpool(physDev, buf, strlen(buf)); if((i - start) % 16 == 15) PSDRV_WriteSpool(physDev, "\n", 1); } PSDRV_WriteSpool(physDev, ">\n", 2); sprintf(buf, glyph_def, pdl->ps_name, index, glyph_name, index); PSDRV_WriteSpool(physDev, buf, strlen(buf)); t42->glyph_sent[index] = TRUE; HeapFree(GetProcessHeap(), 0, buf); return TRUE; }
TYPE42 *T42_download_header(PSDRV_PDEVICE *physDev, char *ps_name, RECT *bbox, UINT emsize) { DWORD i, j, tablepos, nb_blocks, glyf_off = 0, loca_off = 0, cur_off; WORD num_of_tables = sizeof(tables_templ) / sizeof(tables_templ[0]) - 1; char *buf; TYPE42 *t42; static const char start[] = /* name, fontbbox */ "25 dict begin\n" " /FontName /%s def\n" " /Encoding 256 array 0 1 255{1 index exch /.notdef put} for\n" " def\n" " /PaintType 0 def\n" " /FontMatrix [1 0 0 1 0 0] def\n" " /FontBBox [%f %f %f %f] def\n" " /FontType 42 def\n" " /CharStrings 256 dict begin\n" " /.notdef 0 def\n" " currentdict end def\n" " /sfnts [\n"; static const char TT_offset_table[] = "<00010000%04x%04x%04x%04x\n"; static const char TT_table_dir_entry[] = "%08x%08x%08x%08x\n"; static const char storage[] ="]\nhavetype42gdir{pop}{{string} forall}ifelse\n"; static const char end[] = "] def\n" "havetype42gdir{/GlyphDirectory 256 dict def\n" " sfnts 0 get dup\n" " %d <6c6f6378000000000000000000000000> putinterval\n" /* replace loca entry with dummy locx */ " %d <676c6678000000000000000000000000> putinterval\n" /* replace glyf entry with dummy glfx */ " }if\n" "currentdict end dup /FontName get exch definefont pop\n"; t42 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*t42)); memcpy(t42->tables, tables_templ, sizeof(tables_templ)); t42->loca_tab = t42->glyf_tab = t42->head_tab = t42->hmtx_tab = -1; t42->emsize = emsize; t42->num_of_written_tables = 0; for(i = 0; i < num_of_tables; i++) { LoadTable(physDev->hdc, t42->tables + i); if(t42->tables[i].len > 0xffff && t42->tables[i].write) break; if(t42->tables[i].write) t42->num_of_written_tables++; if(t42->tables[i].MS_tag == MS_MAKE_TAG('l','o','c','a')) t42->loca_tab = i; else if(t42->tables[i].MS_tag == MS_MAKE_TAG('g','l','y','f')) t42->glyf_tab = i; else if(t42->tables[i].MS_tag == MS_MAKE_TAG('h','e','a','d')) t42->head_tab = i; else if(t42->tables[i].MS_tag == MS_MAKE_TAG('h','m','t','x')) t42->hmtx_tab = i; else if(t42->tables[i].MS_tag == MS_MAKE_TAG('m','a','x','p')) t42->maxp_tab = i; } if(i < num_of_tables) { TRACE("Table %d has length %d. Will use Type 1 font instead.\n", i, t42->tables[i].len); T42_free(t42); return NULL; } t42->glyph_sent_size = GLYPH_SENT_INC; t42->glyph_sent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, t42->glyph_sent_size * sizeof(*(t42->glyph_sent))); buf = HeapAlloc(GetProcessHeap(), 0, sizeof(start) + strlen(ps_name) + 100); push_lc_numeric("C"); sprintf(buf, start, ps_name, (float)bbox->left / emsize, (float)bbox->bottom / emsize, (float)bbox->right / emsize, (float)bbox->top / emsize); pop_lc_numeric(); PSDRV_WriteSpool(physDev, buf, strlen(buf)); t42->num_of_written_tables++; /* explicitly add glyf */ sprintf(buf, TT_offset_table, t42->num_of_written_tables, t42->num_of_written_tables, t42->num_of_written_tables, t42->num_of_written_tables); PSDRV_WriteSpool(physDev, buf, strlen(buf)); tablepos = 12 + t42->num_of_written_tables * 16; cur_off = 12; for(i = 0; i < num_of_tables; i++) { if(!t42->tables[i].write) continue; sprintf(buf, TT_table_dir_entry, FLIP_ORDER(t42->tables[i].MS_tag), t42->tables[i].check, t42->tables[i].len ? tablepos : 0, t42->tables[i].len); PSDRV_WriteSpool(physDev, buf, strlen(buf)); tablepos += ((t42->tables[i].len + 3) & ~3); if(t42->tables[i].MS_tag == MS_MAKE_TAG('l','o','c','a')) loca_off = cur_off; cur_off += 16; } sprintf(buf, TT_table_dir_entry, FLIP_ORDER(t42->tables[t42->glyf_tab].MS_tag), t42->tables[t42->glyf_tab].check, tablepos, t42->tables[t42->glyf_tab].len); PSDRV_WriteSpool(physDev, buf, strlen(buf)); PSDRV_WriteSpool(physDev, "00>\n", 4); /* add an extra byte for old PostScript rips */ glyf_off = cur_off; for(i = 0; i < num_of_tables; i++) { if(t42->tables[i].len == 0 || !t42->tables[i].write) continue; PSDRV_WriteSpool(physDev, "<", 1); for(j = 0; j < ((t42->tables[i].len + 3) & ~3); j++) { sprintf(buf, "%02x", t42->tables[i].data[j]); PSDRV_WriteSpool(physDev, buf, strlen(buf)); if(j % 16 == 15) PSDRV_WriteSpool(physDev, "\n", 1); } PSDRV_WriteSpool(physDev, "00>\n", 4); /* add an extra byte for old PostScript rips */ } /* glyf_blocks is a 0 terminated list, holding the start offset of each block. For simplicity glyf_blocks[0] is 0 */ nb_blocks = 2; t42->glyf_blocks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nb_blocks + 1) * sizeof(DWORD)); for(i = 0; i < GET_BE_WORD(t42->tables[t42->maxp_tab].data + 4); i++) { DWORD start, end, size; get_glyf_pos(t42, i, &start, &end); size = end - t42->glyf_blocks[nb_blocks-2]; if(size > 0x2000 && t42->glyf_blocks[nb_blocks-1] % 4 == 0) { nb_blocks++; t42->glyf_blocks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, t42->glyf_blocks, (nb_blocks + 1) * sizeof(DWORD)); } t42->glyf_blocks[nb_blocks-1] = end; } PSDRV_WriteSpool(physDev, "[ ", 2); for(i = 1; t42->glyf_blocks[i]; i++) { sprintf(buf,"%d ", t42->glyf_blocks[i] - t42->glyf_blocks[i-1] + 1); /* again add one byte for old PostScript rips */ PSDRV_WriteSpool(physDev, buf, strlen(buf)); if(i % 8 == 0) PSDRV_WriteSpool(physDev, "\n", 1); } PSDRV_WriteSpool(physDev, storage, sizeof(storage) - 1); sprintf(buf, end, loca_off, glyf_off); PSDRV_WriteSpool(physDev, buf, strlen(buf)); HeapFree(GetProcessHeap(), 0, buf); return t42; }
/**************************************************************************** * get_download_name */ static void get_download_name(PHYSDEV dev, LPOUTLINETEXTMETRICA potm, char **str) { int len; char *p; DWORD size; size = GetFontData(dev->hdc, MS_MAKE_TAG('n','a','m','e'), 0, NULL, 0); if(size != 0 && size != GDI_ERROR) { BYTE *name = HeapAlloc(GetProcessHeap(), 0, size); if(name) { USHORT count, i; BYTE *strings; struct { USHORT platform_id; USHORT encoding_id; USHORT language_id; USHORT name_id; USHORT length; USHORT offset; } *name_record; GetFontData(dev->hdc, MS_MAKE_TAG('n','a','m','e'), 0, name, size); count = GET_BE_WORD(name + 2); strings = name + GET_BE_WORD(name + 4); name_record = (typeof(name_record))(name + 6); for(i = 0; i < count; i++, name_record++) { name_record->platform_id = GET_BE_WORD(&name_record->platform_id); name_record->encoding_id = GET_BE_WORD(&name_record->encoding_id); name_record->language_id = GET_BE_WORD(&name_record->language_id); name_record->name_id = GET_BE_WORD(&name_record->name_id); name_record->length = GET_BE_WORD(&name_record->length); name_record->offset = GET_BE_WORD(&name_record->offset); if(name_record->platform_id == 1 && name_record->encoding_id == 0 && name_record->language_id == 0 && name_record->name_id == 6) { TRACE("Got Mac PS name %s\n", debugstr_an((char*)strings + name_record->offset, name_record->length)); *str = HeapAlloc(GetProcessHeap(), 0, name_record->length + 1); memcpy(*str, strings + name_record->offset, name_record->length); *(*str + name_record->length) = '\0'; HeapFree(GetProcessHeap(), 0, name); return; } if(name_record->platform_id == 3 && name_record->encoding_id == 1 && name_record->language_id == 0x409 && name_record->name_id == 6) { WCHAR *unicode = HeapAlloc(GetProcessHeap(), 0, name_record->length + 2); DWORD len; int c; for(c = 0; c < name_record->length / 2; c++) unicode[c] = GET_BE_WORD(strings + name_record->offset + c * 2); unicode[c] = 0; TRACE("Got Windows PS name %s\n", debugstr_w(unicode)); len = WideCharToMultiByte(1252, 0, unicode, -1, NULL, 0, NULL, NULL); *str = HeapAlloc(GetProcessHeap(), 0, len); WideCharToMultiByte(1252, 0, unicode, -1, *str, len, NULL, NULL); HeapFree(GetProcessHeap(), 0, unicode); HeapFree(GetProcessHeap(), 0, name); return; } } TRACE("Unable to find PostScript name\n"); HeapFree(GetProcessHeap(), 0, name); } } len = strlen((char*)potm + (ptrdiff_t)potm->otmpFullName) + 1; *str = HeapAlloc(GetProcessHeap(),0,len); strcpy(*str, (char*)potm + (ptrdiff_t)potm->otmpFullName); p = *str; while((p = strchr(p, ' '))) *p = '_'; return; }
void opentype_get_font_metrics(const void *os2, const void *head, const void *post, DWRITE_FONT_METRICS1 *metrics) { TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2; TT_HEAD *tt_head = (TT_HEAD*)head; TT_POST *tt_post = (TT_POST*)post; memset(metrics, 0, sizeof(*metrics)); if (tt_os2) { metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender); metrics->descent = GET_BE_WORD(tt_os2->sTypoDescender); metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap); metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight); metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight); 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); } 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 (tt_post) { metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition); metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness); } }