Rémi Bernon : gdi32: Introduce new opentype font parsing helpers.

Alexandre Julliard julliard at winehq.org
Thu Dec 3 15:35:58 CST 2020


Module: wine
Branch: master
Commit: e338d046976064d6f050591f1c99fa1ddd4077b7
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=e338d046976064d6f050591f1c99fa1ddd4077b7

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Tue Dec  1 15:54:48 2020 +0100

gdi32: Introduce new opentype font parsing helpers.

Mostly taken from dwrite source, adapted to make it more flexible.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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(+)

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;
+}




More information about the wine-cvs mailing list