[PATCH] gdi32: Support special 'ttcf' tag in GetFontData(), fix individual collection item offset

Nikolay Sivov nsivov at codeweavers.com
Thu Aug 11 17:47:39 CDT 2016


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/gdi32/freetype.c | 53 ++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 44 insertions(+), 9 deletions(-)

diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index 5ddfc6a..f4aab0b 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -210,8 +210,10 @@ MAKE_FUNCPTR(FcPatternGetString);
 
 #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
 
 #ifndef WINE_FONT_DIR
@@ -394,6 +396,8 @@ struct tagGdiFont {
     int codepage;
     BOOL fake_italic;
     BOOL fake_bold;
+    BOOL is_ttc_item;
+    ULONG ttc_item_offset;
     BYTE underline;
     BYTE strikeout;
     INT orientation;
@@ -2189,7 +2193,7 @@ static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_da
             !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
             !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
         {
-            TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
+            TRACE("Font %s/%p lacks either an OS/2, hhea or head table.\n"
                   "Skipping this font.\n", debugstr_a(file), font_data_ptr);
             goto fail;
         }
@@ -4535,6 +4539,9 @@ static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
     font->ft_face = ft_face;
 
     if(FT_IS_SCALABLE(ft_face)) {
+        FT_ULong len;
+        DWORD header;
+
         /* load the VDMX table if we have one */
         font->ppem = load_VDMX(font, height);
         if(font->ppem == 0)
@@ -4543,6 +4550,22 @@ static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
 
         if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
             WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
+
+        /* see if it's a TTC */
+        len = sizeof(header);
+        if (!pFT_Load_Sfnt_Table(ft_face, 0, 0, (void*)&header, &len)) {
+            const DWORD ttcf = 0x66637474;
+
+            if ((font->is_ttc_item = header == ttcf))
+            {
+                len = sizeof(font->ttc_item_offset);
+                if (pFT_Load_Sfnt_Table(ft_face, 0, (3 + face->face_index) * sizeof(DWORD),
+                        (void*)&font->ttc_item_offset, &len))
+                    font->ttc_item_offset = 0;
+                else
+                    font->ttc_item_offset = GET_BE_DWORD(font->ttc_item_offset);
+            }
+        }
     } else {
         font->ppem = height;
         if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
@@ -4638,12 +4661,18 @@ static void free_font(GdiFont *font)
     HeapFree(GetProcessHeap(), 0, font);
 }
 
+#define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
+          ( ( (FT_ULong)_x4 << 24 ) |     \
+            ( (FT_ULong)_x3 << 16 ) |     \
+            ( (FT_ULong)_x2 <<  8 ) |     \
+              (FT_ULong)_x1         )
 
 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
 {
     FT_Face ft_face = font->ft_face;
     FT_ULong len;
     FT_Error err;
+    DWORD tag;
 
     if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
 
@@ -4652,7 +4681,17 @@ static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf
     else
         len = cbData;
 
-    table = RtlUlongByteSwap( table );  /* MS tags differ in endianness from FT ones */
+    table = RtlUlongByteSwap( tag = table );  /* MS tags differ in endianness from FT ones */
+
+    /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
+       0 tag means to read from start of collection member data. */
+    if (font->is_ttc_item)
+    {
+        if (tag == MS_MAKE_TAG('t','t','c','f'))
+            table = 0;
+        else if (tag == 0)
+            offset += font->ttc_item_offset;
+    }
 
     /* make sure value of len is the value freetype says it needs */
     if (buf && len)
@@ -4664,10 +4703,7 @@ static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf
     err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
     if (err)
     {
-        TRACE("Can't find table %c%c%c%c\n",
-              /* bytes were reversed */
-              HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
-              HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
+        TRACE("Can't find table %s\n", debugstr_an((char*)&tag, 4));
 	return GDI_ERROR;
     }
     return len;
@@ -8246,9 +8282,8 @@ static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOI
         return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
     }
 
-    TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
-          physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
-          LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
+    TRACE("font=%p, table=%s, offset=0x%x, buf=%p, cbData=0x%x\n",
+          physdev->font, debugstr_an((char*)&table, 4), offset, buf, cbData);
 
     return get_font_data( physdev->font, table, offset, buf, cbData );
 }
-- 
2.8.1




More information about the wine-patches mailing list