Example #1
0
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;
    }
}
Example #2
0
File: download.c Project: bpon/wine
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);
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
    }
}
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
0
/****************************************************************************
 *  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;
}
Example #9
0
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)++;
    }
}
Example #10
0
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;
}
Example #11
0
/****************************************************************************
 *  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 */
}
Example #12
0
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;
}
Example #13
0
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;
}
Example #14
0
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;
}
Example #15
0
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;
}
Example #16
0
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;
}
Example #17
0
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);
}
Example #18
0
File: font.c Project: miurahr/wine
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;
}
Example #19
0
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;
}
Example #20
0
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;
}
Example #21
0
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;
}
Example #22
0
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;
}
Example #23
0
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);
        }
    }
}
Example #24
0
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;
}
Example #25
0
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);
}
Example #26
0
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;
}
Example #27
0
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;
}
Example #28
0
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;
}
Example #29
0
File: download.c Project: bpon/wine
/****************************************************************************
 *  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;
}
Example #30
0
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);
    }
}