gdi32: Move the GSUB table support out of freetype.c.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
0bc752f30d
commit
8631506270
|
@ -359,6 +359,14 @@ CRITICAL_SECTION font_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
|
|||
#define WINE_FONT_DIR "fonts"
|
||||
#endif
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define GET_BE_WORD(x) (x)
|
||||
#define GET_BE_DWORD(x) (x)
|
||||
#else
|
||||
#define GET_BE_WORD(x) RtlUshortByteSwap(x)
|
||||
#define GET_BE_DWORD(x) RtlUlongByteSwap(x)
|
||||
#endif
|
||||
|
||||
static void get_fonts_data_dir_path( const WCHAR *file, WCHAR *path )
|
||||
{
|
||||
static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
|
||||
|
@ -503,6 +511,7 @@ void free_gdi_font( struct gdi_font *font )
|
|||
HeapFree( GetProcessHeap(), 0, font->otm.otmpFullName );
|
||||
HeapFree( GetProcessHeap(), 0, font->gm );
|
||||
HeapFree( GetProcessHeap(), 0, font->kern_pairs );
|
||||
HeapFree( GetProcessHeap(), 0, font->gsub_table );
|
||||
HeapFree( GetProcessHeap(), 0, font );
|
||||
}
|
||||
|
||||
|
@ -570,6 +579,329 @@ void set_gdi_font_glyph_metrics( struct gdi_font *font, UINT index, const GLYPHM
|
|||
font->gm[block][entry].init = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* GSUB table support */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD version;
|
||||
WORD ScriptList;
|
||||
WORD FeatureList;
|
||||
WORD LookupList;
|
||||
} GSUB_Header;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CHAR ScriptTag[4];
|
||||
WORD Script;
|
||||
} GSUB_ScriptRecord;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD ScriptCount;
|
||||
GSUB_ScriptRecord ScriptRecord[1];
|
||||
} GSUB_ScriptList;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CHAR LangSysTag[4];
|
||||
WORD LangSys;
|
||||
} GSUB_LangSysRecord;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD DefaultLangSys;
|
||||
WORD LangSysCount;
|
||||
GSUB_LangSysRecord LangSysRecord[1];
|
||||
} GSUB_Script;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD LookupOrder; /* Reserved */
|
||||
WORD ReqFeatureIndex;
|
||||
WORD FeatureCount;
|
||||
WORD FeatureIndex[1];
|
||||
} GSUB_LangSys;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CHAR FeatureTag[4];
|
||||
WORD Feature;
|
||||
} GSUB_FeatureRecord;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD FeatureCount;
|
||||
GSUB_FeatureRecord FeatureRecord[1];
|
||||
} GSUB_FeatureList;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD FeatureParams; /* Reserved */
|
||||
WORD LookupCount;
|
||||
WORD LookupListIndex[1];
|
||||
} GSUB_Feature;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD LookupCount;
|
||||
WORD Lookup[1];
|
||||
} GSUB_LookupList;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD LookupType;
|
||||
WORD LookupFlag;
|
||||
WORD SubTableCount;
|
||||
WORD SubTable[1];
|
||||
} GSUB_LookupTable;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD CoverageFormat;
|
||||
WORD GlyphCount;
|
||||
WORD GlyphArray[1];
|
||||
} GSUB_CoverageFormat1;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD Start;
|
||||
WORD End;
|
||||
WORD StartCoverageIndex;
|
||||
} GSUB_RangeRecord;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD CoverageFormat;
|
||||
WORD RangeCount;
|
||||
GSUB_RangeRecord RangeRecord[1];
|
||||
} GSUB_CoverageFormat2;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD SubstFormat; /* = 1 */
|
||||
WORD Coverage;
|
||||
WORD DeltaGlyphID;
|
||||
} GSUB_SingleSubstFormat1;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD SubstFormat; /* = 2 */
|
||||
WORD Coverage;
|
||||
WORD GlyphCount;
|
||||
WORD Substitute[1];
|
||||
} GSUB_SingleSubstFormat2;
|
||||
|
||||
static GSUB_Script *GSUB_get_script_table( GSUB_Header *header, const char *tag )
|
||||
{
|
||||
GSUB_ScriptList *script;
|
||||
GSUB_Script *deflt = NULL;
|
||||
int i;
|
||||
|
||||
script = (GSUB_ScriptList *)((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++)
|
||||
{
|
||||
int offset = GET_BE_WORD(script->ScriptRecord[i].Script);
|
||||
GSUB_Script *scr = (GSUB_Script *)((BYTE *)script + offset);
|
||||
if (!memcmp( script->ScriptRecord[i].ScriptTag, tag, 4 )) return scr;
|
||||
if (!memcmp( script->ScriptRecord[i].ScriptTag, "dflt", 4 )) deflt = scr;
|
||||
}
|
||||
return deflt;
|
||||
}
|
||||
|
||||
static GSUB_LangSys *GSUB_get_lang_table( GSUB_Script *script, const char *tag )
|
||||
{
|
||||
int i, offset;
|
||||
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 = (GSUB_LangSys *)((BYTE *)script + offset);
|
||||
if (!memcmp( script->LangSysRecord[i].LangSysTag, tag, 4 )) return lang;
|
||||
}
|
||||
offset = GET_BE_WORD(script->DefaultLangSys);
|
||||
if (offset) return (GSUB_LangSys *)((BYTE *)script + offset);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GSUB_Feature *GSUB_get_feature( GSUB_Header *header, GSUB_LangSys *lang, const char *tag )
|
||||
{
|
||||
int i;
|
||||
const GSUB_FeatureList *feature;
|
||||
|
||||
feature = (GSUB_FeatureList *)((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 (!memcmp( feature->FeatureRecord[index].FeatureTag, tag, 4 ))
|
||||
return (GSUB_Feature *)((BYTE *)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *get_opentype_script( const struct gdi_font *font )
|
||||
{
|
||||
/*
|
||||
* I am not sure if this is the correct way to generate our script tag
|
||||
*/
|
||||
switch (font->charset)
|
||||
{
|
||||
case ANSI_CHARSET: return "latn";
|
||||
case BALTIC_CHARSET: return "latn"; /* ?? */
|
||||
case CHINESEBIG5_CHARSET: return "hani";
|
||||
case EASTEUROPE_CHARSET: return "latn"; /* ?? */
|
||||
case GB2312_CHARSET: return "hani";
|
||||
case GREEK_CHARSET: return "grek";
|
||||
case HANGUL_CHARSET: return "hang";
|
||||
case RUSSIAN_CHARSET: return "cyrl";
|
||||
case SHIFTJIS_CHARSET: return "kana";
|
||||
case TURKISH_CHARSET: return "latn"; /* ?? */
|
||||
case VIETNAMESE_CHARSET: return "latn";
|
||||
case JOHAB_CHARSET: return "latn"; /* ?? */
|
||||
case ARABIC_CHARSET: return "arab";
|
||||
case HEBREW_CHARSET: return "hebr";
|
||||
case THAI_CHARSET: return "thai";
|
||||
default: return "latn";
|
||||
}
|
||||
}
|
||||
|
||||
void *get_GSUB_vert_feature( struct gdi_font *font )
|
||||
{
|
||||
GSUB_Header *header;
|
||||
GSUB_Script *script;
|
||||
GSUB_LangSys *language;
|
||||
GSUB_Feature *feature;
|
||||
DWORD length = font_funcs->get_font_data( font, MS_GSUB_TAG, 0, NULL, 0 );
|
||||
|
||||
if (length == GDI_ERROR) return NULL;
|
||||
|
||||
header = HeapAlloc( GetProcessHeap(), 0, length );
|
||||
font_funcs->get_font_data( font, MS_GSUB_TAG, 0, header, length );
|
||||
TRACE( "Loaded GSUB table of %i bytes\n", length );
|
||||
|
||||
if ((script = GSUB_get_script_table( header, get_opentype_script(font) )))
|
||||
{
|
||||
if ((language = GSUB_get_lang_table( script, "xxxx" ))) /* Need to get Lang tag */
|
||||
{
|
||||
feature = GSUB_get_feature( header, language, "vrt2" );
|
||||
if (!feature) feature = GSUB_get_feature( header, language, "vert" );
|
||||
if (feature)
|
||||
{
|
||||
font->gsub_table = header;
|
||||
return feature;
|
||||
}
|
||||
TRACE("vrt2/vert feature not found\n");
|
||||
}
|
||||
else TRACE("Language not found\n");
|
||||
}
|
||||
else TRACE("Script not found\n");
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, header );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int GSUB_is_glyph_covered( void *table, UINT glyph )
|
||||
{
|
||||
GSUB_CoverageFormat1 *cf1 = table;
|
||||
|
||||
if (GET_BE_WORD(cf1->CoverageFormat) == 1)
|
||||
{
|
||||
int i, count = GET_BE_WORD(cf1->GlyphCount);
|
||||
|
||||
TRACE("Coverage Format 1, %i glyphs\n",count);
|
||||
for (i = 0; i < count; i++) if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) return i;
|
||||
return -1;
|
||||
}
|
||||
else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
|
||||
{
|
||||
int i, count;
|
||||
GSUB_CoverageFormat2 *cf2 = table;
|
||||
|
||||
count = GET_BE_WORD(cf2->RangeCount);
|
||||
TRACE("Coverage Format 2, %i ranges\n",count);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) return -1;
|
||||
if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
|
||||
(glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
|
||||
{
|
||||
return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
|
||||
glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
else ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static UINT GSUB_apply_feature( GSUB_Header *header, GSUB_Feature *feature, UINT glyph )
|
||||
{
|
||||
GSUB_LookupList *lookup = (GSUB_LookupList *)((BYTE *)header + GET_BE_WORD(header->LookupList));
|
||||
int i, j, offset;
|
||||
|
||||
TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
|
||||
for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
|
||||
{
|
||||
GSUB_LookupTable *look;
|
||||
offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
|
||||
look = (GSUB_LookupTable *)((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));
|
||||
if (GET_BE_WORD(look->LookupType) == 1)
|
||||
{
|
||||
for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
|
||||
{
|
||||
GSUB_SingleSubstFormat1 *ssf1;
|
||||
offset = GET_BE_WORD(look->SubTable[j]);
|
||||
ssf1 = (GSUB_SingleSubstFormat1 *)((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( (BYTE *) ssf1 + offset, glyph ) != -1)
|
||||
{
|
||||
TRACE(" Glyph 0x%x ->",glyph);
|
||||
glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
|
||||
TRACE(" 0x%x\n",glyph);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GSUB_SingleSubstFormat2 *ssf2;
|
||||
int index, offset;
|
||||
|
||||
ssf2 = (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( (BYTE *)ssf2 + offset, glyph );
|
||||
TRACE(" Coverage index %i\n",index);
|
||||
if (index != -1)
|
||||
{
|
||||
TRACE(" Glyph is 0x%x ->",glyph);
|
||||
glyph = GET_BE_WORD(ssf2->Substitute[index]);
|
||||
TRACE("0x%x\n",glyph);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else FIXME("We only handle SubType 1\n");
|
||||
}
|
||||
return glyph;
|
||||
}
|
||||
|
||||
UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph )
|
||||
{
|
||||
if (!font->gsub_table) return glyph;
|
||||
return GSUB_apply_feature( font->gsub_table, font->vert_feature, glyph );
|
||||
}
|
||||
|
||||
/* font cache */
|
||||
|
||||
static struct list gdi_font_list = LIST_INIT( gdi_font_list );
|
||||
|
@ -1192,9 +1524,9 @@ static DWORD CDECL font_GetGlyphIndices( PHYSDEV dev, const WCHAR *str, INT coun
|
|||
default_char = font_funcs->get_default_glyph( physdev->font );
|
||||
got_default = TRUE;
|
||||
}
|
||||
glyph = default_char;
|
||||
gi[i] = default_char;
|
||||
}
|
||||
gi[i] = glyph;
|
||||
else gi[i] = get_GSUB_vert_glyph( physdev->font, glyph );
|
||||
}
|
||||
|
||||
LeaveCriticalSection( &font_cs );
|
||||
|
|
|
@ -296,9 +296,6 @@ struct tagGdiFont {
|
|||
/* the following members can be accessed without locking, they are never modified after creation */
|
||||
FT_Face ft_face;
|
||||
struct font_mapping *mapping;
|
||||
GdiFont *base_font;
|
||||
VOID *GSUB_Table;
|
||||
const VOID *vert_feature;
|
||||
};
|
||||
|
||||
static inline GdiFont *get_font_ptr( struct gdi_font *font ) { return font->private; }
|
||||
|
@ -429,7 +426,7 @@ static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N'
|
|||
static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
|
||||
|
||||
static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl);
|
||||
static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
|
||||
static BOOL get_glyph_index_linked( struct gdi_font *font, UINT c, struct gdi_font **linked_font, FT_UInt *glyph, BOOL *vert);
|
||||
static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font );
|
||||
static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font );
|
||||
static void remove_face_from_cache( Face *face );
|
||||
|
@ -469,103 +466,6 @@ static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i'
|
|||
* cga40woa.fon=cga40850.fon
|
||||
*/
|
||||
|
||||
/* These are all structures needed for the GSUB table */
|
||||
|
||||
|
||||
typedef struct {
|
||||
DWORD version;
|
||||
WORD ScriptList;
|
||||
WORD FeatureList;
|
||||
WORD LookupList;
|
||||
} GSUB_Header;
|
||||
|
||||
typedef struct {
|
||||
CHAR ScriptTag[4];
|
||||
WORD Script;
|
||||
} GSUB_ScriptRecord;
|
||||
|
||||
typedef struct {
|
||||
WORD ScriptCount;
|
||||
GSUB_ScriptRecord ScriptRecord[1];
|
||||
} GSUB_ScriptList;
|
||||
|
||||
typedef struct {
|
||||
CHAR LangSysTag[4];
|
||||
WORD LangSys;
|
||||
} GSUB_LangSysRecord;
|
||||
|
||||
typedef struct {
|
||||
WORD DefaultLangSys;
|
||||
WORD LangSysCount;
|
||||
GSUB_LangSysRecord LangSysRecord[1];
|
||||
} GSUB_Script;
|
||||
|
||||
typedef struct {
|
||||
WORD LookupOrder; /* Reserved */
|
||||
WORD ReqFeatureIndex;
|
||||
WORD FeatureCount;
|
||||
WORD FeatureIndex[1];
|
||||
} GSUB_LangSys;
|
||||
|
||||
typedef struct {
|
||||
CHAR FeatureTag[4];
|
||||
WORD Feature;
|
||||
} GSUB_FeatureRecord;
|
||||
|
||||
typedef struct {
|
||||
WORD FeatureCount;
|
||||
GSUB_FeatureRecord FeatureRecord[1];
|
||||
} GSUB_FeatureList;
|
||||
|
||||
typedef struct {
|
||||
WORD FeatureParams; /* Reserved */
|
||||
WORD LookupCount;
|
||||
WORD LookupListIndex[1];
|
||||
} GSUB_Feature;
|
||||
|
||||
typedef struct {
|
||||
WORD LookupCount;
|
||||
WORD Lookup[1];
|
||||
} GSUB_LookupList;
|
||||
|
||||
typedef struct {
|
||||
WORD LookupType;
|
||||
WORD LookupFlag;
|
||||
WORD SubTableCount;
|
||||
WORD SubTable[1];
|
||||
} GSUB_LookupTable;
|
||||
|
||||
typedef struct {
|
||||
WORD CoverageFormat;
|
||||
WORD GlyphCount;
|
||||
WORD GlyphArray[1];
|
||||
} GSUB_CoverageFormat1;
|
||||
|
||||
typedef struct {
|
||||
WORD Start;
|
||||
WORD End;
|
||||
WORD StartCoverageIndex;
|
||||
} GSUB_RangeRecord;
|
||||
|
||||
typedef struct {
|
||||
WORD CoverageFormat;
|
||||
WORD RangeCount;
|
||||
GSUB_RangeRecord RangeRecord[1];
|
||||
} GSUB_CoverageFormat2;
|
||||
|
||||
typedef struct {
|
||||
WORD SubstFormat; /* = 1 */
|
||||
WORD Coverage;
|
||||
WORD DeltaGlyphID;
|
||||
} GSUB_SingleSubstFormat1;
|
||||
|
||||
typedef struct {
|
||||
WORD SubstFormat; /* = 2 */
|
||||
WORD Coverage;
|
||||
WORD GlyphCount;
|
||||
WORD Substitute[1];
|
||||
}GSUB_SingleSubstFormat2;
|
||||
|
||||
#ifdef HAVE_CARBON_CARBON_H
|
||||
static char *find_cache_dir(void)
|
||||
{
|
||||
|
@ -3389,7 +3289,6 @@ static void CDECL freetype_destroy_font( struct gdi_font *gdi_font )
|
|||
|
||||
if (font->ft_face) pFT_Done_Face(font->ft_face);
|
||||
if (font->mapping) unmap_font_file( font->mapping );
|
||||
HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
|
||||
HeapFree(GetProcessHeap(), 0, font);
|
||||
}
|
||||
|
||||
|
@ -3861,143 +3760,6 @@ end:
|
|||
}
|
||||
#endif
|
||||
|
||||
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 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 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 const char* get_opentype_script(const struct gdi_font *font)
|
||||
{
|
||||
/*
|
||||
* I am not sure if this is the correct way to generate our script tag
|
||||
*/
|
||||
|
||||
switch (font->charset)
|
||||
{
|
||||
case ANSI_CHARSET: return "latn";
|
||||
case BALTIC_CHARSET: return "latn"; /* ?? */
|
||||
case CHINESEBIG5_CHARSET: return "hani";
|
||||
case EASTEUROPE_CHARSET: return "latn"; /* ?? */
|
||||
case GB2312_CHARSET: return "hani";
|
||||
case GREEK_CHARSET: return "grek";
|
||||
case HANGUL_CHARSET: return "hang";
|
||||
case RUSSIAN_CHARSET: return "cyrl";
|
||||
case SHIFTJIS_CHARSET: return "kana";
|
||||
case TURKISH_CHARSET: return "latn"; /* ?? */
|
||||
case VIETNAMESE_CHARSET: return "latn";
|
||||
case JOHAB_CHARSET: return "latn"; /* ?? */
|
||||
case ARABIC_CHARSET: return "arab";
|
||||
case HEBREW_CHARSET: return "hebr";
|
||||
case THAI_CHARSET: return "thai";
|
||||
default: return "latn";
|
||||
}
|
||||
}
|
||||
|
||||
static const void *get_GSUB_vert_feature( struct gdi_font *font, void **GSUB_table )
|
||||
{
|
||||
GSUB_Header *header;
|
||||
const GSUB_Script *script;
|
||||
const GSUB_LangSys *language;
|
||||
const GSUB_Feature *feature;
|
||||
DWORD length = freetype_get_font_data( font, MS_GSUB_TAG, 0, NULL, 0 );
|
||||
|
||||
if (length == GDI_ERROR) return NULL;
|
||||
|
||||
header = HeapAlloc( GetProcessHeap(), 0, length );
|
||||
freetype_get_font_data( font, MS_GSUB_TAG, 0, header, length );
|
||||
TRACE( "Loaded GSUB table of %i bytes\n", length );
|
||||
|
||||
script = GSUB_get_script_table(header, get_opentype_script(font));
|
||||
if (!script)
|
||||
{
|
||||
TRACE("Script not found\n");
|
||||
HeapFree( GetProcessHeap(), 0, header );
|
||||
return NULL;
|
||||
}
|
||||
language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
|
||||
if (!language)
|
||||
{
|
||||
TRACE("Language not found\n");
|
||||
HeapFree( GetProcessHeap(), 0, header );
|
||||
return NULL;
|
||||
}
|
||||
feature = GSUB_get_feature(header, language, "vrt2");
|
||||
if (!feature)
|
||||
feature = GSUB_get_feature(header, language, "vert");
|
||||
if (!feature)
|
||||
{
|
||||
TRACE("vrt2/vert feature not found\n");
|
||||
HeapFree( GetProcessHeap(), 0, header );
|
||||
return NULL;
|
||||
}
|
||||
*GSUB_table = header;
|
||||
return feature;
|
||||
}
|
||||
|
||||
static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index )
|
||||
{
|
||||
FT_ULong len;
|
||||
|
@ -4480,7 +4242,7 @@ found_face:
|
|||
ret = get_font_ptr( gdi_font );
|
||||
|
||||
if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
|
||||
ret->vert_feature = get_GSUB_vert_feature( gdi_font, &ret->GSUB_Table );
|
||||
gdi_font->vert_feature = get_GSUB_vert_feature( gdi_font );
|
||||
|
||||
create_child_font_list(ret);
|
||||
|
||||
|
@ -4875,125 +4637,6 @@ static BOOL codepage_sets_default_used(UINT codepage)
|
|||
* GSUB Table handling functions
|
||||
*/
|
||||
|
||||
static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
|
||||
{
|
||||
const GSUB_CoverageFormat1* cf1;
|
||||
|
||||
cf1 = table;
|
||||
|
||||
if (GET_BE_WORD(cf1->CoverageFormat) == 1)
|
||||
{
|
||||
int count = GET_BE_WORD(cf1->GlyphCount);
|
||||
int i;
|
||||
TRACE("Coverage Format 1, %i glyphs\n",count);
|
||||
for (i = 0; i < count; i++)
|
||||
if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
|
||||
{
|
||||
const GSUB_CoverageFormat2* cf2;
|
||||
int i;
|
||||
int count;
|
||||
cf2 = (const GSUB_CoverageFormat2*)cf1;
|
||||
|
||||
count = GET_BE_WORD(cf2->RangeCount);
|
||||
TRACE("Coverage Format 2, %i ranges\n",count);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
|
||||
return -1;
|
||||
if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
|
||||
(glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
|
||||
{
|
||||
return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
|
||||
glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
|
||||
{
|
||||
int i;
|
||||
int offset;
|
||||
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++)
|
||||
{
|
||||
const GSUB_LookupTable *look;
|
||||
offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
|
||||
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));
|
||||
if (GET_BE_WORD(look->LookupType) != 1)
|
||||
FIXME("We only handle SubType 1\n");
|
||||
else
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
|
||||
{
|
||||
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, glyph) != -1)
|
||||
{
|
||||
TRACE(" Glyph 0x%x ->",glyph);
|
||||
glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
|
||||
TRACE(" 0x%x\n",glyph);
|
||||
}
|
||||
}
|
||||
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, glyph);
|
||||
TRACE(" Coverage index %i\n",index);
|
||||
if (index != -1)
|
||||
{
|
||||
TRACE(" Glyph is 0x%x ->",glyph);
|
||||
glyph = GET_BE_WORD(ssf2->Substitute[index]);
|
||||
TRACE("0x%x\n",glyph);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return glyph;
|
||||
}
|
||||
|
||||
|
||||
static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
|
||||
{
|
||||
const GSUB_Header *header;
|
||||
const GSUB_Feature *feature;
|
||||
|
||||
if (!font->GSUB_Table)
|
||||
return glyph;
|
||||
|
||||
header = font->GSUB_Table;
|
||||
feature = font->vert_feature;
|
||||
|
||||
return GSUB_apply_feature(header, feature, glyph);
|
||||
}
|
||||
|
||||
static FT_UInt get_glyph_index_symbol(const GdiFont *font, UINT glyph)
|
||||
{
|
||||
FT_UInt ret;
|
||||
|
@ -5081,10 +4724,7 @@ static BOOL CDECL freetype_get_glyph_index( struct gdi_font *gdi_font, UINT *gly
|
|||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ((*glyph = pFT_Get_Char_Index( font->ft_face, *glyph )))
|
||||
*glyph = get_GSUB_vert_glyph( font, *glyph );
|
||||
|
||||
*glyph = pFT_Get_Char_Index( font->ft_face, *glyph );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -6053,9 +5693,9 @@ static DWORD CDECL freetype_get_glyph_outline( struct gdi_font *incoming_gdi_fon
|
|||
rotated. */
|
||||
} else {
|
||||
BOOL vert;
|
||||
get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
|
||||
get_glyph_index_linked(incoming_gdi_font, glyph, &gdi_font, &glyph_index, &vert);
|
||||
font = get_font_ptr( gdi_font );
|
||||
ft_face = font->ft_face;
|
||||
gdi_font = font->gdi_font;
|
||||
if (!vert && tategaki)
|
||||
tategaki = check_unicode_tategaki(glyph);
|
||||
}
|
||||
|
@ -6595,6 +6235,7 @@ static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
|
|||
child_font->ntmFlags = child_face->ntmFlags;
|
||||
child_font->aa_flags = HIWORD( child_face->flags );
|
||||
child_font->scale_y = gdi_font->scale_y;
|
||||
child_font->base_font = gdi_font;
|
||||
set_gdi_font_names( child_font, child_face->family->family_name,
|
||||
child_face->style_name, child_face->full_name );
|
||||
if (!freetype_load_font( child_font ))
|
||||
|
@ -6603,25 +6244,24 @@ static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
|
|||
return FALSE;
|
||||
}
|
||||
child->font = get_font_ptr( child_font );
|
||||
child->font->base_font = font;
|
||||
TRACE("created child font %p for base %p\n", child->font, font);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
|
||||
static BOOL get_glyph_index_linked( struct gdi_font *gdi_font, UINT c, struct gdi_font **linked_font,
|
||||
FT_UInt *glyph, BOOL* vert)
|
||||
{
|
||||
GdiFont *font = get_font_ptr( gdi_font );
|
||||
FT_UInt g,o;
|
||||
CHILD_FONT *child_font;
|
||||
|
||||
if(font->base_font)
|
||||
font = font->base_font;
|
||||
|
||||
*linked_font = font;
|
||||
if (gdi_font->base_font) gdi_font = gdi_font->base_font;
|
||||
*linked_font = gdi_font;
|
||||
|
||||
if((*glyph = get_glyph_index(font, c)))
|
||||
{
|
||||
o = *glyph;
|
||||
*glyph = get_GSUB_vert_glyph(font, *glyph);
|
||||
*glyph = get_GSUB_vert_glyph(gdi_font, *glyph);
|
||||
*vert = (o != *glyph);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -6638,11 +6278,11 @@ static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font,
|
|||
continue;
|
||||
g = get_glyph_index(child_font->font, c);
|
||||
o = g;
|
||||
g = get_GSUB_vert_glyph(child_font->font, g);
|
||||
g = get_GSUB_vert_glyph(child_font->font->gdi_font, g);
|
||||
if(g)
|
||||
{
|
||||
*glyph = g;
|
||||
*linked_font = child_font->font;
|
||||
*linked_font = child_font->font->gdi_font;
|
||||
*vert = (o != g);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -340,6 +340,9 @@ struct gdi_font
|
|||
BOOL fake_italic : 1;
|
||||
BOOL fake_bold : 1;
|
||||
BOOL scalable : 1;
|
||||
struct gdi_font *base_font;
|
||||
void *gsub_table;
|
||||
void *vert_feature;
|
||||
void *data_ptr;
|
||||
SIZE_T data_size;
|
||||
FILETIME writetime;
|
||||
|
@ -403,6 +406,8 @@ extern BOOL get_gdi_font_glyph_metrics( struct gdi_font *font, UINT index,
|
|||
GLYPHMETRICS *gm, ABC *abc ) DECLSPEC_HIDDEN;
|
||||
extern void set_gdi_font_glyph_metrics( struct gdi_font *font, UINT index,
|
||||
const GLYPHMETRICS *gm, const ABC *abc ) DECLSPEC_HIDDEN;
|
||||
extern void *get_GSUB_vert_feature( struct gdi_font *font ) DECLSPEC_HIDDEN;
|
||||
extern UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph ) DECLSPEC_HIDDEN;
|
||||
extern void font_init(void) DECLSPEC_HIDDEN;
|
||||
extern CRITICAL_SECTION font_cs DECLSPEC_HIDDEN;
|
||||
|
||||
|
|
Loading…
Reference in New Issue