Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
So I'm sending this last series now as it seems everybody rushes for their patches to go in before the freeze, and as it should not have any conflict with 196676-196680, or with the other series on the ML as it's mostly only touching freetype.c, it'll leave more time for review.
With 196676-196680 applied, this brings some ~250ms improvement to prefix startup (from 1.25s to 1s runtime on average for "cmd /c exit"), and 50ms improvement to process startup (from 0.15s to 0.1s on average).
(I probably changed my test setup a bit and upgraded some font packages since the other series so it's not exactly comparable with the previous numbers, but the improvement indicated was measured in a consistent way with / without this series applied)
dlls/gdi32/freetype.c | 124 +++++++++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 33 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 1ee02795bed..00334b470c8 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -1092,65 +1092,123 @@ fail: return NULL; }
+struct unix_face +{ + FT_Face ft_face; + BOOL scalable; + UINT num_faces; + WCHAR *family_name; + WCHAR *second_name; +}; + +static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr, DWORD data_size, + UINT face_index, DWORD flags ) +{ + struct unix_face *This; + struct stat st; + int fd; + + TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n", + unix_name, face_index, data_ptr, data_size, flags ); + + if (unix_name) + { + if ((fd = open( unix_name, O_RDONLY )) == -1) return NULL; + if (fstat( fd, &st ) == -1) + { + close( fd ); + return NULL; + } + data_size = st.st_size; + data_ptr = mmap( NULL, data_size, PROT_READ, MAP_PRIVATE, fd, 0 ); + close( fd ); + if (data_ptr == MAP_FAILED) return NULL; + } + + if (!(This = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This) ))) goto done; + + if (!(This->ft_face = new_ft_face( unix_name, data_ptr, data_size, face_index, flags & ADDFONT_ALLOW_BITMAP ))) + { + RtlFreeHeap( GetProcessHeap(), 0, This ); + This = NULL; + } + else + { + This->scalable = FT_IS_SCALABLE( This->ft_face ); + This->num_faces = This->ft_face->num_faces; + + This->family_name = ft_face_get_family_name( This->ft_face, system_lcid ); + This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) ); + + /* try to find another secondary name, preferring the lowest langids */ + if (!RtlCompareUnicodeStrings( This->family_name, lstrlenW( This->family_name ), + This->second_name, lstrlenW( This->second_name ), TRUE )) + { + RtlFreeHeap( GetProcessHeap(), 0, This->second_name ); + This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) ); + if (!RtlCompareUnicodeStrings( This->family_name, lstrlenW( This->family_name ), + This->second_name, lstrlenW( This->second_name ), TRUE )) + { + RtlFreeHeap( GetProcessHeap(), 0, This->second_name ); + This->second_name = NULL; + } + } + } + +done: + if (unix_name) munmap( data_ptr, data_size ); + return This; +} + +static void unix_face_destroy( struct unix_face *This ) +{ + pFT_Done_Face( This->ft_face ); + RtlFreeHeap( GetProcessHeap(), 0, This->second_name ); + RtlFreeHeap( GetProcessHeap(), 0, This->family_name ); + RtlFreeHeap( GetProcessHeap(), 0, This ); +} + static int add_unix_face( const char *unix_name, const WCHAR *file, void *data_ptr, SIZE_T data_size, DWORD face_index, DWORD flags, DWORD *num_faces ) { + struct unix_face *unix_face; struct bitmap_font_size size; FONTSIGNATURE fs; - FT_Face ft_face; - WCHAR *family_name, *second_name, *style_name, *full_name; + WCHAR *style_name, *full_name; int ret;
if (num_faces) *num_faces = 0;
- if (!(ft_face = new_ft_face( unix_name, data_ptr, data_size, face_index, flags & ADDFONT_ALLOW_BITMAP ))) + if (!(unix_face = unix_face_create( unix_name, data_ptr, data_size, face_index, flags ))) return 0;
- if (ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */ + if (unix_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */ { TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name)); - pFT_Done_Face( ft_face ); + unix_face_destroy( unix_face ); return 0; }
- family_name = ft_face_get_family_name( ft_face, system_lcid ); - second_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) ); - style_name = ft_face_get_style_name( ft_face, system_lcid ); - full_name = ft_face_get_full_name( ft_face, system_lcid ); - - /* try to find another secondary name, preferring the lowest langids */ - if (!RtlCompareUnicodeStrings( family_name, lstrlenW(family_name), - second_name, lstrlenW(second_name), TRUE )) - { - RtlFreeHeap( GetProcessHeap(), 0, second_name ); - second_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) ); - if (!RtlCompareUnicodeStrings( family_name, lstrlenW(family_name), - second_name, lstrlenW(second_name), TRUE )) - { - RtlFreeHeap( GetProcessHeap(), 0, second_name ); - second_name = NULL; - } - } + style_name = ft_face_get_style_name( unix_face->ft_face, system_lcid ); + full_name = ft_face_get_full_name( unix_face->ft_face, system_lcid );
- get_fontsig( ft_face, &fs ); - if (!FT_IS_SCALABLE( ft_face )) get_bitmap_size( ft_face, &size ); + get_fontsig( unix_face->ft_face, &fs ); + if (!unix_face->scalable) get_bitmap_size( unix_face->ft_face, &size ); if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
- ret = callback_funcs->add_gdi_face( family_name, second_name, style_name, full_name, file, - data_ptr, data_size, face_index, fs, get_ntm_flags( ft_face ), - get_font_version( ft_face ), flags, - FT_IS_SCALABLE(ft_face) ? NULL : &size ); + ret = callback_funcs->add_gdi_face( unix_face->family_name, unix_face->second_name, style_name, full_name, + file, data_ptr, data_size, face_index, fs, get_ntm_flags( unix_face->ft_face ), + get_font_version( unix_face->ft_face ), flags, + unix_face->scalable ? NULL : &size );
TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n", fs.fsCsb[0], fs.fsCsb[1], fs.fsUsb[0], fs.fsUsb[1], fs.fsUsb[2], fs.fsUsb[3]);
- RtlFreeHeap( GetProcessHeap(), 0, family_name ); - RtlFreeHeap( GetProcessHeap(), 0, second_name ); RtlFreeHeap( GetProcessHeap(), 0, style_name ); RtlFreeHeap( GetProcessHeap(), 0, full_name );
- if (num_faces) *num_faces = ft_face->num_faces; - pFT_Done_Face( ft_face ); + if (num_faces) *num_faces = unix_face->num_faces; + unix_face_destroy( unix_face ); return ret; }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/freetype.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 00334b470c8..cb993034d09 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -1099,6 +1099,12 @@ struct unix_face UINT num_faces; WCHAR *family_name; WCHAR *second_name; + WCHAR *style_name; + WCHAR *full_name; + DWORD ntm_flags; + DWORD font_version; + FONTSIGNATURE fs; + struct bitmap_font_size size; };
static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr, DWORD data_size, @@ -1153,6 +1159,14 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr This->second_name = NULL; } } + + This->style_name = ft_face_get_style_name( This->ft_face, system_lcid ); + This->full_name = ft_face_get_full_name( This->ft_face, system_lcid ); + + This->ntm_flags = get_ntm_flags( This->ft_face ); + This->font_version = get_font_version( This->ft_face ); + if (!This->scalable) get_bitmap_size( This->ft_face, &This->size ); + get_fontsig( This->ft_face, &This->fs ); }
done: @@ -1163,6 +1177,8 @@ done: static void unix_face_destroy( struct unix_face *This ) { pFT_Done_Face( This->ft_face ); + RtlFreeHeap( GetProcessHeap(), 0, This->full_name ); + RtlFreeHeap( GetProcessHeap(), 0, This->style_name ); RtlFreeHeap( GetProcessHeap(), 0, This->second_name ); RtlFreeHeap( GetProcessHeap(), 0, This->family_name ); RtlFreeHeap( GetProcessHeap(), 0, This ); @@ -1172,9 +1188,6 @@ static int add_unix_face( const char *unix_name, const WCHAR *file, void *data_p DWORD face_index, DWORD flags, DWORD *num_faces ) { struct unix_face *unix_face; - struct bitmap_font_size size; - FONTSIGNATURE fs; - WCHAR *style_name, *full_name; int ret;
if (num_faces) *num_faces = 0; @@ -1189,23 +1202,14 @@ static int add_unix_face( const char *unix_name, const WCHAR *file, void *data_p return 0; }
- style_name = ft_face_get_style_name( unix_face->ft_face, system_lcid ); - full_name = ft_face_get_full_name( unix_face->ft_face, system_lcid ); - - get_fontsig( unix_face->ft_face, &fs ); - if (!unix_face->scalable) get_bitmap_size( unix_face->ft_face, &size ); if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
- ret = callback_funcs->add_gdi_face( unix_face->family_name, unix_face->second_name, style_name, full_name, - file, data_ptr, data_size, face_index, fs, get_ntm_flags( unix_face->ft_face ), - get_font_version( unix_face->ft_face ), flags, - unix_face->scalable ? NULL : &size ); + ret = callback_funcs->add_gdi_face( unix_face->family_name, unix_face->second_name, unix_face->style_name, unix_face->full_name, + file, data_ptr, data_size, face_index, unix_face->fs, unix_face->ntm_flags, + unix_face->font_version, flags, unix_face->scalable ? NULL : &unix_face->size );
- TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n", - fs.fsCsb[0], fs.fsCsb[1], fs.fsUsb[0], fs.fsUsb[1], fs.fsUsb[2], fs.fsUsb[3]); - - RtlFreeHeap( GetProcessHeap(), 0, style_name ); - RtlFreeHeap( GetProcessHeap(), 0, full_name ); + TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n", unix_face->fs.fsCsb[0], unix_face->fs.fsCsb[1], + unix_face->fs.fsUsb[0], unix_face->fs.fsUsb[1], unix_face->fs.fsUsb[2], unix_face->fs.fsUsb[3]);
if (num_faces) *num_faces = unix_face->num_faces; unix_face_destroy( unix_face );
Signed-off-by: Huw Davies huw@codeweavers.com
Mostly taken from dwrite source, adapted to make it more flexible.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/Makefile.in | 1 + dlls/gdi32/freetype.c | 11 ++ dlls/gdi32/gdi_private.h | 7 ++ dlls/gdi32/opentype.c | 220 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 239 insertions(+) create mode 100644 dlls/gdi32/opentype.c
diff --git a/dlls/gdi32/Makefile.in b/dlls/gdi32/Makefile.in index a965e80001c..910450b9f64 100644 --- a/dlls/gdi32/Makefile.in +++ b/dlls/gdi32/Makefile.in @@ -42,6 +42,7 @@ C_SRCS = \ mfdrv/objects.c \ mfdrv/text.c \ opengl.c \ + opentype.c \ painting.c \ palette.c \ path.c \ diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index cb993034d09..686f2b54682 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -1110,8 +1110,10 @@ struct unix_face static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr, DWORD data_size, UINT face_index, DWORD flags ) { + const struct ttc_sfnt_v1 *ttc_sfnt_v1; struct unix_face *This; struct stat st; + DWORD face_count; int fd;
TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n", @@ -1138,11 +1140,20 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr RtlFreeHeap( GetProcessHeap(), 0, This ); This = NULL; } + else if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 )) + { + This->scalable = TRUE; + This->num_faces = face_count; + } else { + WARN( "unable to parse font, falling back to FreeType\n" ); This->scalable = FT_IS_SCALABLE( This->ft_face ); This->num_faces = This->ft_face->num_faces; + }
+ if (This) + { This->family_name = ft_face_get_family_name( This->ft_face, system_lcid ); This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) );
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index b9a06415538..a529cb0890c 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -414,6 +414,13 @@ struct font_callback_funcs
extern void font_init(void) DECLSPEC_HIDDEN;
+/* opentype.c */ + +struct ttc_sfnt_v1; + +extern BOOL opentype_get_ttc_sfnt_v1( const void *data, size_t size, DWORD index, DWORD *count, + const struct ttc_sfnt_v1 **ttc_sfnt_v1 ) DECLSPEC_HIDDEN; + /* gdiobj.c */ extern HGDIOBJ alloc_gdi_handle( void *obj, WORD type, const struct gdi_obj_funcs *funcs ) DECLSPEC_HIDDEN; extern void *free_gdi_handle( HGDIOBJ handle ) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/opentype.c b/dlls/gdi32/opentype.c new file mode 100644 index 00000000000..2363439cdc5 --- /dev/null +++ b/dlls/gdi32/opentype.c @@ -0,0 +1,220 @@ +/* + * Copyright 2020 Rémi Bernon for CodeWeavers + * Copyright 2014 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include <stdarg.h> +#include <stdlib.h> + +#include "windef.h" +#include "winbase.h" + +#include "wine/debug.h" + +#include "gdi_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(font); + +#define MS_OTTO_TAG MS_MAKE_TAG('O','T','T','O') +#define MS_HEAD_TAG MS_MAKE_TAG('h','e','a','d') +#define MS_HHEA_TAG MS_MAKE_TAG('h','h','e','a') +#define MS_OS_2_TAG MS_MAKE_TAG('O','S','/','2') +#define MS_EBSC_TAG MS_MAKE_TAG('E','B','S','C') +#define MS_EBDT_TAG MS_MAKE_TAG('E','B','D','T') +#define MS_CBDT_TAG MS_MAKE_TAG('C','B','D','T') + +#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 + +#include "pshpack2.h" +struct ttc_header_v1 +{ + CHAR TTCTag[4]; + DWORD Version; + DWORD numFonts; + DWORD OffsetTable[1]; +}; + +struct ttc_sfnt_v1 +{ + DWORD version; + WORD numTables; + WORD searchRange; + WORD entrySelector; + WORD rangeShift; +}; + +struct tt_tablerecord +{ + DWORD tag; + DWORD checkSum; + DWORD offset; + DWORD length; +}; + +struct tt_os2_v1 +{ + USHORT version; + SHORT xAvgCharWidth; + USHORT usWeightClass; + USHORT usWidthClass; + SHORT fsType; + SHORT ySubscriptXSize; + SHORT ySubscriptYSize; + SHORT ySubscriptXOffset; + SHORT ySubscriptYOffset; + SHORT ySuperscriptXSize; + SHORT ySuperscriptYSize; + SHORT ySuperscriptXOffset; + SHORT ySuperscriptYOffset; + SHORT yStrikeoutSize; + SHORT yStrikeoutPosition; + SHORT sFamilyClass; + PANOSE panose; + ULONG ulUnicodeRange1; + ULONG ulUnicodeRange2; + ULONG ulUnicodeRange3; + ULONG ulUnicodeRange4; + CHAR achVendID[4]; + USHORT fsSelection; + USHORT usFirstCharIndex; + USHORT usLastCharIndex; + /* According to the Apple spec, original version didn't have the below fields, + * version numbers were taken from the OpenType spec. + */ + /* version 0 (TrueType 1.5) */ + USHORT sTypoAscender; + USHORT sTypoDescender; + USHORT sTypoLineGap; + USHORT usWinAscent; + USHORT usWinDescent; + /* version 1 (TrueType 1.66) */ + ULONG ulCodePageRange1; + ULONG ulCodePageRange2; +}; +#include "poppack.h" + +static BOOL opentype_get_table_ptr( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, + UINT32 table_tag, const void **table_ptr, UINT32 *table_size ) +{ + const struct tt_tablerecord *table_record; + UINT16 i, table_count; + UINT32 offset, length; + + if (!ttc_sfnt_v1) return FALSE; + + table_record = (const struct tt_tablerecord *)(ttc_sfnt_v1 + 1); + table_count = GET_BE_WORD( ttc_sfnt_v1->numTables ); + for (i = 0; i < table_count; i++, table_record++) + { + if (table_record->tag != table_tag) continue; + offset = GET_BE_DWORD( table_record->offset ); + length = GET_BE_DWORD( table_record->length ); + if (size < offset + length) return FALSE; + if (table_size && length < *table_size) return FALSE; + + if (table_ptr) *table_ptr = (const char *)data + offset; + if (table_size) *table_size = length; + return TRUE; + } + + return FALSE; +} + +static BOOL opentype_get_tt_os2_v1( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, + const struct tt_os2_v1 **tt_os2_v1 ) +{ + UINT32 table_size = sizeof(**tt_os2_v1); + return opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_OS_2_TAG, (const void **)tt_os2_v1, &table_size ); +} + +BOOL opentype_get_ttc_sfnt_v1( const void *data, size_t size, DWORD index, DWORD *count, const struct ttc_sfnt_v1 **ttc_sfnt_v1 ) +{ + const struct ttc_header_v1 *ttc_header_v1 = data; + const struct tt_os2_v1 *tt_os2_v1; + UINT32 offset, fourcc; + + *ttc_sfnt_v1 = NULL; + *count = 1; + + if (size < sizeof(fourcc)) return FALSE; + memcpy( &fourcc, data, sizeof(fourcc) ); + + switch (fourcc) + { + default: + WARN( "unsupported font format %x\n", fourcc ); + return FALSE; + case MS_TTCF_TAG: + if (size < sizeof(ttc_header_v1)) return FALSE; + if (index >= (*count = GET_BE_DWORD( ttc_header_v1->numFonts ))) return FALSE; + offset = GET_BE_DWORD( ttc_header_v1->OffsetTable[index] ); + break; + case 0x00000100: + case MS_OTTO_TAG: + offset = 0; + break; + } + + if (size < offset + sizeof(**ttc_sfnt_v1)) return FALSE; + *ttc_sfnt_v1 = (const struct ttc_sfnt_v1 *)((const char *)data + offset); + + if (!opentype_get_table_ptr( data, size, *ttc_sfnt_v1, MS_HEAD_TAG, NULL, NULL )) + { + WARN( "unsupported sfnt font: missing head table.\n" ); + return FALSE; + } + + if (!opentype_get_table_ptr( data, size, *ttc_sfnt_v1, MS_HHEA_TAG, NULL, NULL )) + { + WARN( "unsupported sfnt font: missing hhea table.\n" ); + return FALSE; + } + + if (!opentype_get_tt_os2_v1( data, size, *ttc_sfnt_v1, &tt_os2_v1 )) + { + WARN( "unsupported sfnt font: missing OS/2 table.\n" ); + return FALSE; + } + + /* Wine uses ttfs as an intermediate step in building its bitmap fonts; + we don't want to load these. */ + if (!memcmp( tt_os2_v1->achVendID, "Wine", sizeof(tt_os2_v1->achVendID) ) && + opentype_get_table_ptr( data, size, *ttc_sfnt_v1, MS_EBSC_TAG, NULL, NULL )) + { + TRACE( "ignoring wine bitmap-only sfnt font.\n" ); + return FALSE; + } + + if (opentype_get_table_ptr( data, size, *ttc_sfnt_v1, MS_EBDT_TAG, NULL, NULL ) || + opentype_get_table_ptr( data, size, *ttc_sfnt_v1, MS_CBDT_TAG, NULL, NULL )) + { + WARN( "unsupported sfnt font: embedded bitmap data.\n" ); + return FALSE; + } + + return TRUE; +}
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/freetype.c | 131 ++++++++++- dlls/gdi32/gdi_private.h | 18 ++ dlls/gdi32/opentype.c | 459 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 603 insertions(+), 5 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 686f2b54682..06bc29ff86a 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -1092,6 +1092,86 @@ fail: return NULL; }
+struct family_names_data +{ + LANGID primary_langid; + struct opentype_name family_name; + struct opentype_name second_name; + BOOL primary_seen; + BOOL english_seen; +}; + +static BOOL search_family_names_callback( LANGID langid, struct opentype_name *name, void *user ) +{ + struct family_names_data *data = user; + + if (langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) + { + data->english_seen = TRUE; + if (data->primary_langid == langid) data->primary_seen = TRUE; + + if (!data->family_name.bytes) data->family_name = *name; + else if (data->primary_langid != langid) data->second_name = *name; + } + else if (data->primary_langid == langid) + { + data->primary_seen = TRUE; + if (!data->second_name.bytes) data->second_name = data->family_name; + data->family_name = *name; + } + else if (!data->second_name.bytes) data->second_name = *name; + + if (data->family_name.bytes && data->second_name.bytes && data->primary_seen && data->english_seen) + return TRUE; + return FALSE; +} + +struct face_name_data +{ + LANGID primary_langid; + struct opentype_name face_name;; +}; + +static BOOL search_face_name_callback( LANGID langid, struct opentype_name *name, void *user ) +{ + struct face_name_data *data = user; + + if (langid == data->primary_langid || (langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) && !data->face_name.bytes)) + data->face_name = *name; + + return langid == data->primary_langid; +} + +static WCHAR *decode_opentype_name( struct opentype_name *name ) +{ + CPTABLEINFO codepage_info; + USHORT *codepage_ptr; + SIZE_T codepage_size; + WCHAR buffer[512]; + DWORD len; + + if (!name->codepage) + { + len = min( ARRAY_SIZE(buffer), name->length / sizeof(WCHAR) ); + while (len--) buffer[len] = GET_BE_WORD( ((WORD *)name->bytes)[len] ); + len = min( ARRAY_SIZE(buffer), name->length / sizeof(WCHAR) ); + } + else + { + NtGetNlsSectionPtr( 11, name->codepage, NULL, (void **)&codepage_ptr, &codepage_size ); + RtlInitCodePageTable( codepage_ptr, &codepage_info ); + RtlCustomCPToUnicodeN( &codepage_info, buffer, sizeof(buffer), &len, name->bytes, name->length ); + len /= sizeof(WCHAR); + NtUnmapViewOfSection( GetCurrentProcess(), codepage_ptr ); + } + + buffer[ARRAY_SIZE(buffer) - 1] = 0; + if (len == ARRAY_SIZE(buffer)) WARN("Truncated font name %s -> %s\n", debugstr_an(name->bytes, name->length), debugstr_w(buffer)); + else buffer[len] = 0; + + return strdupW( buffer ); +} + struct unix_face { FT_Face ft_face; @@ -1110,11 +1190,14 @@ struct unix_face static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr, DWORD data_size, UINT face_index, DWORD flags ) { + static const WCHAR space_w[] = {' ',0}; + const struct ttc_sfnt_v1 *ttc_sfnt_v1; + const struct tt_name_v0 *tt_name_v0; struct unix_face *This; struct stat st; DWORD face_count; - int fd; + int fd, length;
TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n", unix_name, face_index, data_ptr, data_size, flags ); @@ -1140,20 +1223,55 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr RtlFreeHeap( GetProcessHeap(), 0, This ); This = NULL; } - else if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 )) + else if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 ) && + opentype_get_tt_name_v0( data_ptr, data_size, ttc_sfnt_v1, &tt_name_v0 )) { + struct family_names_data family_names; + struct face_name_data style_name; + struct face_name_data full_name; + LANGID primary_langid = system_lcid; + This->scalable = TRUE; This->num_faces = face_count; + + memset( &family_names, 0, sizeof(family_names) ); + family_names.primary_langid = primary_langid; + opentype_enum_family_names( tt_name_v0, search_family_names_callback, &family_names ); + This->family_name = decode_opentype_name( &family_names.family_name ); + This->second_name = decode_opentype_name( &family_names.second_name ); + + memset( &style_name, 0, sizeof(style_name) ); + style_name.primary_langid = primary_langid; + opentype_enum_style_names( tt_name_v0, search_face_name_callback, &style_name ); + This->style_name = decode_opentype_name( &style_name.face_name ); + + memset( &full_name, 0, sizeof(full_name) ); + style_name.primary_langid = primary_langid; + opentype_enum_full_names( tt_name_v0, search_face_name_callback, &full_name ); + This->full_name = decode_opentype_name( &full_name.face_name ); + + TRACE( "parsed font names family_name %s, second_name %s, primary_seen %d, english_seen %d, " + "full_name %s, style_name %s\n", + debugstr_w(This->family_name), debugstr_w(This->second_name), + family_names.primary_seen, family_names.english_seen, + debugstr_w(This->full_name), debugstr_w(This->style_name) ); + + if (!This->full_name && This->family_name && This->style_name) + { + length = lstrlenW( This->family_name ) + lstrlenW( space_w ) + lstrlenW( This->style_name ) + 1; + This->full_name = RtlAllocateHeap( GetProcessHeap(), 0, length * sizeof(WCHAR) ); + lstrcpyW( This->full_name, This->family_name ); + lstrcatW( This->full_name, space_w ); + lstrcatW( This->full_name, This->style_name ); + WARN( "full name not found, using %s instead\n", debugstr_w(This->full_name) ); + } } else { WARN( "unable to parse font, falling back to FreeType\n" ); This->scalable = FT_IS_SCALABLE( This->ft_face ); This->num_faces = This->ft_face->num_faces; - }
- if (This) - { This->family_name = ft_face_get_family_name( This->ft_face, system_lcid ); This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) );
@@ -1173,7 +1291,10 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr
This->style_name = ft_face_get_style_name( This->ft_face, system_lcid ); This->full_name = ft_face_get_full_name( This->ft_face, system_lcid ); + }
+ if (This) + { This->ntm_flags = get_ntm_flags( This->ft_face ); This->font_version = get_font_version( This->ft_face ); if (!This->scalable) get_bitmap_size( This->ft_face, &This->size ); diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index a529cb0890c..9a988d08d7e 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -417,9 +417,27 @@ extern void font_init(void) DECLSPEC_HIDDEN; /* opentype.c */
struct ttc_sfnt_v1; +struct tt_name_v0; + +struct opentype_name +{ + DWORD codepage; + DWORD length; + const void *bytes; +};
extern BOOL opentype_get_ttc_sfnt_v1( const void *data, size_t size, DWORD index, DWORD *count, const struct ttc_sfnt_v1 **ttc_sfnt_v1 ) DECLSPEC_HIDDEN; +extern BOOL opentype_get_tt_name_v0( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, + const struct tt_name_v0 **tt_name_v0 ) DECLSPEC_HIDDEN; + +typedef BOOL ( *opentype_enum_names_cb )( LANGID langid, struct opentype_name *name, void *user ); +extern BOOL opentype_enum_family_names( const struct tt_name_v0 *tt_name_v0, + opentype_enum_names_cb callback, void *user ) DECLSPEC_HIDDEN; +extern BOOL opentype_enum_style_names( const struct tt_name_v0 *tt_name_v0, + opentype_enum_names_cb callback, void *user ) DECLSPEC_HIDDEN; +extern BOOL opentype_enum_full_names( const struct tt_name_v0 *tt_name_v0, + opentype_enum_names_cb callback, void *user ) DECLSPEC_HIDDEN;
/* gdiobj.c */ extern HGDIOBJ alloc_gdi_handle( void *obj, WORD type, const struct gdi_obj_funcs *funcs ) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/opentype.c b/dlls/gdi32/opentype.c index 2363439cdc5..4200b08d318 100644 --- a/dlls/gdi32/opentype.c +++ b/dlls/gdi32/opentype.c @@ -26,6 +26,7 @@
#include "windef.h" #include "winbase.h" +#include "winnls.h"
#include "wine/debug.h"
@@ -40,6 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(font); #define MS_EBSC_TAG MS_MAKE_TAG('E','B','S','C') #define MS_EBDT_TAG MS_MAKE_TAG('E','B','D','T') #define MS_CBDT_TAG MS_MAKE_TAG('C','B','D','T') +#define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
#ifdef WORDS_BIGENDIAN #define GET_BE_WORD(x) (x) @@ -115,8 +117,125 @@ struct tt_os2_v1 ULONG ulCodePageRange1; ULONG ulCodePageRange2; }; + +struct tt_namerecord +{ + WORD platformID; + WORD encodingID; + WORD languageID; + WORD nameID; + WORD length; + WORD offset; +}; + +struct tt_name_v0 +{ + WORD format; + WORD count; + WORD stringOffset; + struct tt_namerecord nameRecord[1]; +}; #include "poppack.h"
+enum OPENTYPE_PLATFORM_ID +{ + OPENTYPE_PLATFORM_UNICODE = 0, + OPENTYPE_PLATFORM_MAC, + OPENTYPE_PLATFORM_ISO, + OPENTYPE_PLATFORM_WIN, + OPENTYPE_PLATFORM_CUSTOM +}; + +enum TT_NAME_WIN_ENCODING_ID +{ + TT_NAME_WIN_ENCODING_SYMBOL = 0, + TT_NAME_WIN_ENCODING_UNICODE_BMP, + TT_NAME_WIN_ENCODING_SJIS, + TT_NAME_WIN_ENCODING_PRC, + TT_NAME_WIN_ENCODING_BIG5, + TT_NAME_WIN_ENCODING_WANSUNG, + TT_NAME_WIN_ENCODING_JOHAB, + TT_NAME_WIN_ENCODING_RESERVED1, + TT_NAME_WIN_ENCODING_RESERVED2, + TT_NAME_WIN_ENCODING_RESERVED3, + TT_NAME_WIN_ENCODING_UNICODE_FULL +}; + +enum TT_NAME_UNICODE_ENCODING_ID +{ + TT_NAME_UNICODE_ENCODING_1_0 = 0, + TT_NAME_UNICODE_ENCODING_1_1, + TT_NAME_UNICODE_ENCODING_ISO_10646, + TT_NAME_UNICODE_ENCODING_2_0_BMP, + TT_NAME_UNICODE_ENCODING_2_0_FULL, + TT_NAME_UNICODE_ENCODING_VAR, + TT_NAME_UNICODE_ENCODING_FULL, +}; + +enum TT_NAME_MAC_ENCODING_ID +{ + TT_NAME_MAC_ENCODING_ROMAN = 0, + TT_NAME_MAC_ENCODING_JAPANESE, + TT_NAME_MAC_ENCODING_TRAD_CHINESE, + TT_NAME_MAC_ENCODING_KOREAN, + TT_NAME_MAC_ENCODING_ARABIC, + TT_NAME_MAC_ENCODING_HEBREW, + TT_NAME_MAC_ENCODING_GREEK, + TT_NAME_MAC_ENCODING_RUSSIAN, + TT_NAME_MAC_ENCODING_RSYMBOL, + TT_NAME_MAC_ENCODING_DEVANAGARI, + TT_NAME_MAC_ENCODING_GURMUKHI, + TT_NAME_MAC_ENCODING_GUJARATI, + TT_NAME_MAC_ENCODING_ORIYA, + TT_NAME_MAC_ENCODING_BENGALI, + TT_NAME_MAC_ENCODING_TAMIL, + TT_NAME_MAC_ENCODING_TELUGU, + TT_NAME_MAC_ENCODING_KANNADA, + TT_NAME_MAC_ENCODING_MALAYALAM, + TT_NAME_MAC_ENCODING_SINHALESE, + TT_NAME_MAC_ENCODING_BURMESE, + TT_NAME_MAC_ENCODING_KHMER, + TT_NAME_MAC_ENCODING_THAI, + TT_NAME_MAC_ENCODING_LAOTIAN, + TT_NAME_MAC_ENCODING_GEORGIAN, + TT_NAME_MAC_ENCODING_ARMENIAN, + TT_NAME_MAC_ENCODING_SIMPL_CHINESE, + TT_NAME_MAC_ENCODING_TIBETAN, + TT_NAME_MAC_ENCODING_MONGOLIAN, + TT_NAME_MAC_ENCODING_GEEZ, + TT_NAME_MAC_ENCODING_SLAVIC, + TT_NAME_MAC_ENCODING_VIETNAMESE, + TT_NAME_MAC_ENCODING_SINDHI, + TT_NAME_MAC_ENCODING_UNINTERPRETED +}; + +enum OPENTYPE_NAME_ID +{ + OPENTYPE_NAME_COPYRIGHT_NOTICE = 0, + OPENTYPE_NAME_FAMILY, + OPENTYPE_NAME_SUBFAMILY, + OPENTYPE_NAME_UNIQUE_IDENTIFIER, + OPENTYPE_NAME_FULLNAME, + OPENTYPE_NAME_VERSION_STRING, + OPENTYPE_NAME_POSTSCRIPT, + OPENTYPE_NAME_TRADEMARK, + OPENTYPE_NAME_MANUFACTURER, + OPENTYPE_NAME_DESIGNER, + OPENTYPE_NAME_DESCRIPTION, + OPENTYPE_NAME_VENDOR_URL, + OPENTYPE_NAME_DESIGNER_URL, + OPENTYPE_NAME_LICENSE_DESCRIPTION, + OPENTYPE_NAME_LICENSE_INFO_URL, + OPENTYPE_NAME_RESERVED_ID15, + OPENTYPE_NAME_TYPOGRAPHIC_FAMILY, + OPENTYPE_NAME_TYPOGRAPHIC_SUBFAMILY, + OPENTYPE_NAME_COMPATIBLE_FULLNAME, + OPENTYPE_NAME_SAMPLE_TEXT, + OPENTYPE_NAME_POSTSCRIPT_CID, + OPENTYPE_NAME_WWS_FAMILY, + OPENTYPE_NAME_WWS_SUBFAMILY +}; + static BOOL opentype_get_table_ptr( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, UINT32 table_tag, const void **table_ptr, UINT32 *table_size ) { @@ -151,6 +270,306 @@ static BOOL opentype_get_tt_os2_v1( const void *data, size_t size, const struct return opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_OS_2_TAG, (const void **)tt_os2_v1, &table_size ); }
+static UINT get_name_record_codepage( enum OPENTYPE_PLATFORM_ID platform, USHORT encoding ) +{ + switch (platform) + { + case OPENTYPE_PLATFORM_UNICODE: + return 0; + case OPENTYPE_PLATFORM_MAC: + switch (encoding) + { + case TT_NAME_MAC_ENCODING_ROMAN: + return 10000; + case TT_NAME_MAC_ENCODING_JAPANESE: + return 10001; + case TT_NAME_MAC_ENCODING_TRAD_CHINESE: + return 10002; + case TT_NAME_MAC_ENCODING_KOREAN: + return 10003; + case TT_NAME_MAC_ENCODING_ARABIC: + return 10004; + case TT_NAME_MAC_ENCODING_HEBREW: + return 10005; + case TT_NAME_MAC_ENCODING_GREEK: + return 10006; + case TT_NAME_MAC_ENCODING_RUSSIAN: + return 10007; + case TT_NAME_MAC_ENCODING_SIMPL_CHINESE: + return 10008; + case TT_NAME_MAC_ENCODING_THAI: + return 10021; + default: + FIXME( "encoding %u not handled, platform %d.\n", encoding, platform ); + break; + } + break; + case OPENTYPE_PLATFORM_WIN: + switch (encoding) + { + case TT_NAME_WIN_ENCODING_SYMBOL: + case TT_NAME_WIN_ENCODING_UNICODE_BMP: + case TT_NAME_WIN_ENCODING_UNICODE_FULL: + return 0; + case TT_NAME_WIN_ENCODING_SJIS: + return 932; + case TT_NAME_WIN_ENCODING_PRC: + return 936; + case TT_NAME_WIN_ENCODING_BIG5: + return 950; + case TT_NAME_WIN_ENCODING_WANSUNG: + return 20949; + case TT_NAME_WIN_ENCODING_JOHAB: + return 1361; + default: + FIXME( "encoding %u not handled, platform %d.\n", encoding, platform ); + break; + } + break; + default: + FIXME( "unknown platform %d\n", platform ); + break; + } + + return 0; +} + +static const LANGID mac_langid_table[] = +{ + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT), + MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_PORTUGUESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), + MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT), + MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_MALTESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_CHINESE_TRADITIONAL, SUBLANG_DEFAULT), + MAKELANGID(LANG_URDU, SUBLANG_DEFAULT), + MAKELANGID(LANG_HINDI, SUBLANG_DEFAULT), + MAKELANGID(LANG_THAI, SUBLANG_DEFAULT), + MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_ESTONIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_LATVIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_SAMI, SUBLANG_DEFAULT), + MAKELANGID(LANG_FAEROESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_FARSI, SUBLANG_DEFAULT), + MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_DEFAULT), + MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), + MAKELANGID(LANG_IRISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_ALBANIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT), + MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT), + MAKELANGID(LANG_SLOVENIAN, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_SERBIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_MACEDONIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_BELARUSIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_UZBEK, SUBLANG_DEFAULT), + MAKELANGID(LANG_KAZAK, SUBLANG_DEFAULT), + MAKELANGID(LANG_AZERI, SUBLANG_AZERI_CYRILLIC), + 0, + MAKELANGID(LANG_ARMENIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_GEORGIAN, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_KYRGYZ, SUBLANG_DEFAULT), + MAKELANGID(LANG_TAJIK, SUBLANG_DEFAULT), + MAKELANGID(LANG_TURKMEN, SUBLANG_DEFAULT), + MAKELANGID(LANG_MONGOLIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_MONGOLIAN, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), + MAKELANGID(LANG_PASHTO, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_KASHMIRI, SUBLANG_DEFAULT), + MAKELANGID(LANG_SINDHI, SUBLANG_DEFAULT), + MAKELANGID(LANG_TIBETAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_NEPALI, SUBLANG_DEFAULT), + MAKELANGID(LANG_SANSKRIT, SUBLANG_DEFAULT), + MAKELANGID(LANG_MARATHI, SUBLANG_DEFAULT), + MAKELANGID(LANG_BENGALI, SUBLANG_DEFAULT), + MAKELANGID(LANG_ASSAMESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_GUJARATI, SUBLANG_DEFAULT), + MAKELANGID(LANG_PUNJABI, SUBLANG_DEFAULT), + MAKELANGID(LANG_ORIYA, SUBLANG_DEFAULT), + MAKELANGID(LANG_MALAYALAM, SUBLANG_DEFAULT), + MAKELANGID(LANG_KANNADA, SUBLANG_DEFAULT), + MAKELANGID(LANG_TAMIL, SUBLANG_DEFAULT), + MAKELANGID(LANG_TELUGU, SUBLANG_DEFAULT), + MAKELANGID(LANG_SINHALESE, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_KHMER, SUBLANG_DEFAULT), + MAKELANGID(LANG_LAO, SUBLANG_DEFAULT), + MAKELANGID(LANG_VIETNAMESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_MALAY, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_AMHARIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_TIGRIGNA, SUBLANG_DEFAULT), + 0, + 0, + MAKELANGID(LANG_SWAHILI, SUBLANG_DEFAULT), + 0, + 0, + 0, + MAKELANGID(LANG_MALAGASY, SUBLANG_DEFAULT), + MAKELANGID(LANG_ESPERANTO, SUBLANG_DEFAULT), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + MAKELANGID(LANG_WELSH, SUBLANG_DEFAULT), + MAKELANGID(LANG_BASQUE, SUBLANG_DEFAULT), + MAKELANGID(LANG_CATALAN, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_QUECHUA, SUBLANG_DEFAULT), + 0, + 0, + MAKELANGID(LANG_TATAR, SUBLANG_DEFAULT), + MAKELANGID(LANG_UIGHUR, SUBLANG_DEFAULT), + 0, + 0, + 0, + MAKELANGID(LANG_GALICIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_AFRIKAANS, SUBLANG_DEFAULT), + MAKELANGID(LANG_BRETON, SUBLANG_DEFAULT), + MAKELANGID(LANG_INUKTITUT, SUBLANG_DEFAULT), + MAKELANGID(LANG_SCOTTISH_GAELIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_MANX_GAELIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), + 0, + 0, + MAKELANGID(LANG_GREENLANDIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), +}; + +static LANGID get_name_record_langid( enum OPENTYPE_PLATFORM_ID platform, USHORT encoding, USHORT language ) +{ + switch (platform) + { + case OPENTYPE_PLATFORM_WIN: + return language; + case OPENTYPE_PLATFORM_MAC: + if (language < ARRAY_SIZE(mac_langid_table)) return mac_langid_table[language]; + WARN( "invalid mac lang id %d\n", language ); + break; + case OPENTYPE_PLATFORM_UNICODE: + switch (encoding) + { + case TT_NAME_UNICODE_ENCODING_1_0: + case TT_NAME_UNICODE_ENCODING_ISO_10646: + case TT_NAME_UNICODE_ENCODING_2_0_BMP: + if (language < ARRAY_SIZE(mac_langid_table)) return mac_langid_table[language]; + WARN( "invalid unicode lang id %d\n", language ); + break; + default: + break; + } + default: + FIXME( "unknown platform %d\n", platform ); + break; + } + + return MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); +} + +static BOOL opentype_enum_font_names( const struct tt_name_v0 *header, enum OPENTYPE_PLATFORM_ID platform, + enum OPENTYPE_NAME_ID name, opentype_enum_names_cb callback, void *user ) +{ + const char *name_data; + USHORT i, name_count, encoding, language, length, offset; + USHORT platform_id = GET_BE_WORD( platform ), name_id = GET_BE_WORD( name ); + LANGID langid; + BOOL ret = FALSE; + + switch (GET_BE_WORD( header->format )) + { + case 0: + case 1: + break; + default: + FIXME( "unsupported name format %d\n", GET_BE_WORD( header->format ) ); + return FALSE; + } + + name_data = (const char *)header + GET_BE_WORD( header->stringOffset ); + name_count = GET_BE_WORD( header->count ); + for (i = 0; i < name_count; i++) + { + const struct tt_namerecord *record = &header->nameRecord[i]; + struct opentype_name opentype_name; + + if (record->nameID != name_id) continue; + if (record->platformID != platform_id) continue; + + language = GET_BE_WORD( record->languageID ); + if (language >= 0x8000) + { + FIXME( "handle name format 1\n" ); + continue; + } + + encoding = GET_BE_WORD( record->encodingID ); + offset = GET_BE_WORD( record->offset ); + length = GET_BE_WORD( record->length ); + langid = get_name_record_langid( platform, encoding, language ); + + opentype_name.codepage = get_name_record_codepage( platform, encoding ); + opentype_name.length = length; + opentype_name.bytes = name_data + offset; + + if ((ret = callback( langid, &opentype_name, user ))) break; + } + + return ret; +} + BOOL opentype_get_ttc_sfnt_v1( const void *data, size_t size, DWORD index, DWORD *count, const struct ttc_sfnt_v1 **ttc_sfnt_v1 ) { const struct ttc_header_v1 *ttc_header_v1 = data; @@ -218,3 +637,43 @@ BOOL opentype_get_ttc_sfnt_v1( const void *data, size_t size, DWORD index, DWORD
return TRUE; } + +BOOL opentype_get_tt_name_v0( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, + const struct tt_name_v0 **tt_name_v0 ) +{ + UINT32 table_size = sizeof(**tt_name_v0); + return opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_NAME_TAG, (const void **)tt_name_v0, &table_size ); +} + +BOOL opentype_enum_family_names( const struct tt_name_v0 *header, opentype_enum_names_cb callback, void *user ) +{ + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_WIN, OPENTYPE_NAME_FAMILY, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_MAC, OPENTYPE_NAME_FAMILY, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_UNICODE, OPENTYPE_NAME_FAMILY, callback, user )) + return TRUE; + return FALSE; +} + +BOOL opentype_enum_style_names( const struct tt_name_v0 *header, opentype_enum_names_cb callback, void *user ) +{ + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_WIN, OPENTYPE_NAME_SUBFAMILY, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_MAC, OPENTYPE_NAME_SUBFAMILY, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_UNICODE, OPENTYPE_NAME_SUBFAMILY, callback, user )) + return TRUE; + return FALSE; +} + +BOOL opentype_enum_full_names( const struct tt_name_v0 *header, opentype_enum_names_cb callback, void *user ) +{ + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_WIN, OPENTYPE_NAME_FULLNAME, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_MAC, OPENTYPE_NAME_FULLNAME, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_UNICODE, OPENTYPE_NAME_FULLNAME, callback, user )) + return TRUE; + return FALSE; +}
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This makes a tiny difference to the dump_gdi_font_list report, for some fonts that do not have any bit set in fs->fsCsb[0]. This is the case for instance for Noto Arabic font family. We were previously filling it with FS_LATIN1 as fallback because FreeType reported some charmap encoded with FT_ENCODING_APPLE_ROMAN, but I don't think it was correct.
dlls/gdi32/freetype.c | 7 ++-- dlls/gdi32/gdi_private.h | 3 ++ dlls/gdi32/opentype.c | 91 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 4 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 06bc29ff86a..f9d82644176 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -1224,7 +1224,9 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr This = NULL; } else if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 ) && - opentype_get_tt_name_v0( data_ptr, data_size, ttc_sfnt_v1, &tt_name_v0 )) + opentype_get_tt_name_v0( data_ptr, data_size, ttc_sfnt_v1, &tt_name_v0 ) && + opentype_get_properties( data_ptr, data_size, ttc_sfnt_v1, &This->font_version, + &This->fs, &This->ntm_flags )) { struct family_names_data family_names; struct face_name_data style_name; @@ -1291,10 +1293,7 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr
This->style_name = ft_face_get_style_name( This->ft_face, system_lcid ); This->full_name = ft_face_get_full_name( This->ft_face, system_lcid ); - }
- if (This) - { This->ntm_flags = get_ntm_flags( This->ft_face ); This->font_version = get_font_version( This->ft_face ); if (!This->scalable) get_bitmap_size( This->ft_face, &This->size ); diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index 9a988d08d7e..8d917a795c0 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -439,6 +439,9 @@ extern BOOL opentype_enum_style_names( const struct tt_name_v0 *tt_name_v0, extern BOOL opentype_enum_full_names( const struct tt_name_v0 *tt_name_v0, opentype_enum_names_cb callback, void *user ) DECLSPEC_HIDDEN;
+extern BOOL opentype_get_properties( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, + DWORD *version, FONTSIGNATURE *fs, DWORD *ntm_flags ) DECLSPEC_HIDDEN; + /* gdiobj.c */ extern HGDIOBJ alloc_gdi_handle( void *obj, WORD type, const struct gdi_obj_funcs *funcs ) DECLSPEC_HIDDEN; extern void *free_gdi_handle( HGDIOBJ handle ) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/opentype.c b/dlls/gdi32/opentype.c index 4200b08d318..67af44dfe91 100644 --- a/dlls/gdi32/opentype.c +++ b/dlls/gdi32/opentype.c @@ -42,6 +42,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(font); #define MS_EBDT_TAG MS_MAKE_TAG('E','B','D','T') #define MS_CBDT_TAG MS_MAKE_TAG('C','B','D','T') #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e') +#define MS_CFF__TAG MS_MAKE_TAG('C','F','F',' ')
#ifdef WORDS_BIGENDIAN #define GET_BE_WORD(x) (x) @@ -135,6 +136,28 @@ struct tt_name_v0 WORD stringOffset; struct tt_namerecord nameRecord[1]; }; + +struct tt_head +{ + USHORT majorVersion; + USHORT minorVersion; + ULONG revision; + ULONG checksumadj; + ULONG magic; + USHORT flags; + USHORT unitsPerEm; + ULONGLONG created; + ULONGLONG modified; + SHORT xMin; + SHORT yMin; + SHORT xMax; + SHORT yMax; + USHORT macStyle; + USHORT lowestRecPPEM; + SHORT direction_hint; + SHORT index_format; + SHORT glyphdata_format; +}; #include "poppack.h"
enum OPENTYPE_PLATFORM_ID @@ -236,6 +259,20 @@ enum OPENTYPE_NAME_ID OPENTYPE_NAME_WWS_SUBFAMILY };
+enum OS2_FSSELECTION +{ + OS2_FSSELECTION_ITALIC = 1 << 0, + OS2_FSSELECTION_UNDERSCORE = 1 << 1, + OS2_FSSELECTION_NEGATIVE = 1 << 2, + OS2_FSSELECTION_OUTLINED = 1 << 3, + OS2_FSSELECTION_STRIKEOUT = 1 << 4, + OS2_FSSELECTION_BOLD = 1 << 5, + OS2_FSSELECTION_REGULAR = 1 << 6, + OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7, + OS2_FSSELECTION_WWS = 1 << 8, + OS2_FSSELECTION_OBLIQUE = 1 << 9 +}; + static BOOL opentype_get_table_ptr( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, UINT32 table_tag, const void **table_ptr, UINT32 *table_size ) { @@ -270,6 +307,13 @@ static BOOL opentype_get_tt_os2_v1( const void *data, size_t size, const struct return opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_OS_2_TAG, (const void **)tt_os2_v1, &table_size ); }
+static BOOL opentype_get_tt_head( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, + const struct tt_head **tt_head ) +{ + UINT32 table_size = sizeof(**tt_head); + return opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_HEAD_TAG, (const void **)tt_head, &table_size ); +} + static UINT get_name_record_codepage( enum OPENTYPE_PLATFORM_ID platform, USHORT encoding ) { switch (platform) @@ -677,3 +721,50 @@ BOOL opentype_enum_full_names( const struct tt_name_v0 *header, opentype_enum_na return TRUE; return FALSE; } + +BOOL opentype_get_properties( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, + DWORD *version, FONTSIGNATURE *fs, DWORD *ntm_flags ) +{ + const struct tt_os2_v1 *tt_os2_v1; + const struct tt_head *tt_head; + const void *cff_header; + UINT32 table_size = 0; + USHORT idx, selection; + DWORD flags = 0; + + if (!opentype_get_tt_head( data, size, ttc_sfnt_v1, &tt_head )) return FALSE; + if (!opentype_get_tt_os2_v1( data, size, ttc_sfnt_v1, &tt_os2_v1 )) return FALSE; + + *version = GET_BE_DWORD( tt_head->revision ); + + fs->fsUsb[0] = GET_BE_DWORD( tt_os2_v1->ulUnicodeRange1 ); + fs->fsUsb[1] = GET_BE_DWORD( tt_os2_v1->ulUnicodeRange2 ); + fs->fsUsb[2] = GET_BE_DWORD( tt_os2_v1->ulUnicodeRange3 ); + fs->fsUsb[3] = GET_BE_DWORD( tt_os2_v1->ulUnicodeRange4 ); + + if (tt_os2_v1->version == 0) + { + idx = GET_BE_WORD( tt_os2_v1->usFirstCharIndex ); + if (idx >= 0xf000 && idx < 0xf100) fs->fsCsb[0] = FS_SYMBOL; + else fs->fsCsb[0] = FS_LATIN1; + fs->fsCsb[1] = 0; + } + else + { + fs->fsCsb[0] = GET_BE_DWORD( tt_os2_v1->ulCodePageRange1 ); + fs->fsCsb[1] = GET_BE_DWORD( tt_os2_v1->ulCodePageRange2 ); + } + + selection = GET_BE_WORD( tt_os2_v1->fsSelection ); + + if (selection & OS2_FSSELECTION_ITALIC) flags |= NTM_ITALIC; + if (selection & OS2_FSSELECTION_BOLD) flags |= NTM_BOLD; + if (selection & OS2_FSSELECTION_REGULAR) flags |= NTM_REGULAR; + if (flags == 0) flags = NTM_REGULAR; + + if (opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_CFF__TAG, &cff_header, &table_size )) + flags |= NTM_PS_OPENTYPE; + + *ntm_flags = flags; + return TRUE; +}
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
We keep FreeType code path as it's still used for some corner cases like WinFNT fonts, although we could also implement the parsing of such fonts ourselves in a similar way.
dlls/gdi32/freetype.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index f9d82644176..0ffd2f8f34a 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -1218,15 +1218,10 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr
if (!(This = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This) ))) goto done;
- if (!(This->ft_face = new_ft_face( unix_name, data_ptr, data_size, face_index, flags & ADDFONT_ALLOW_BITMAP ))) - { - RtlFreeHeap( GetProcessHeap(), 0, This ); - This = NULL; - } - else if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 ) && - opentype_get_tt_name_v0( data_ptr, data_size, ttc_sfnt_v1, &tt_name_v0 ) && - opentype_get_properties( data_ptr, data_size, ttc_sfnt_v1, &This->font_version, - &This->fs, &This->ntm_flags )) + if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 ) && + opentype_get_tt_name_v0( data_ptr, data_size, ttc_sfnt_v1, &tt_name_v0 ) && + opentype_get_properties( data_ptr, data_size, ttc_sfnt_v1, &This->font_version, + &This->fs, &This->ntm_flags )) { struct family_names_data family_names; struct face_name_data style_name; @@ -1268,7 +1263,7 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr WARN( "full name not found, using %s instead\n", debugstr_w(This->full_name) ); } } - else + else if ((This->ft_face = new_ft_face( unix_name, data_ptr, data_size, face_index, flags & ADDFONT_ALLOW_BITMAP ))) { WARN( "unable to parse font, falling back to FreeType\n" ); This->scalable = FT_IS_SCALABLE( This->ft_face ); @@ -1299,6 +1294,11 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr if (!This->scalable) get_bitmap_size( This->ft_face, &This->size ); get_fontsig( This->ft_face, &This->fs ); } + else + { + RtlFreeHeap( GetProcessHeap(), 0, This ); + This = NULL; + }
done: if (unix_name) munmap( data_ptr, data_size ); @@ -1307,7 +1307,7 @@ done:
static void unix_face_destroy( struct unix_face *This ) { - pFT_Done_Face( This->ft_face ); + if (This->ft_face) pFT_Done_Face( This->ft_face ); RtlFreeHeap( GetProcessHeap(), 0, This->full_name ); RtlFreeHeap( GetProcessHeap(), 0, This->style_name ); RtlFreeHeap( GetProcessHeap(), 0, This->second_name );
Signed-off-by: Huw Davies huw@codeweavers.com