[PATCH 5/6] dwrite: Read legacy kerning table directly.

Nikolay Sivov nsivov at codeweavers.com
Mon Mar 8 02:30:50 CST 2021


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/dwrite_private.h |  19 +++--
 dlls/dwrite/font.c           |  32 +++-----
 dlls/dwrite/freetype.c       |  41 ----------
 dlls/dwrite/opentype.c       | 143 +++++++++++++++++++++++++++++++++++
 4 files changed, 165 insertions(+), 70 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 27f4906a00d..a91b8f99d70 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -182,12 +182,13 @@ struct fontfacecached
 
 enum font_flags
 {
-    FONT_IS_SYMBOL                 = 0x00000001,
-    FONT_IS_MONOSPACED             = 0x00000002,
-    FONT_IS_COLORED                = 0x00000004, /* CPAL/COLR support */
-    FONTFACE_HAS_KERNING_PAIRS     = 0x00000008,
-    FONTFACE_VERTICAL_VARIANTS     = 0x00000010,
-    FONTFACE_NO_VERTICAL_VARIANTS  = 0x00000020,
+    FONT_IS_SYMBOL                = 0x00000001,
+    FONT_IS_MONOSPACED            = 0x00000002,
+    FONT_IS_COLORED               = 0x00000004, /* CPAL/COLR support */
+    FONTFACE_KERNING_PAIRS        = 0x00000008,
+    FONTFACE_NO_KERNING_PAIRS     = 0x00000010,
+    FONTFACE_VERTICAL_VARIANTS    = 0x00000020,
+    FONTFACE_NO_VERTICAL_VARIANTS = 0x00000040,
 };
 
 struct dwrite_cmap;
@@ -266,6 +267,7 @@ struct dwrite_fontface
     struct dwrite_fonttable gasp;
     struct dwrite_fonttable cpal;
     struct dwrite_fonttable colr;
+    struct dwrite_fonttable kern;
     DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
 
     DWRITE_FONT_STYLE style;
@@ -407,6 +409,9 @@ extern HRESULT opentype_get_cpal_entries(const struct dwrite_fonttable *table, u
         unsigned int first_entry_index, unsigned int entry_count, DWRITE_COLOR_F *entries) DECLSPEC_HIDDEN;
 extern UINT32 opentype_get_glyph_image_formats(IDWriteFontFace5 *fontface) DECLSPEC_HIDDEN;
 extern DWRITE_CONTAINER_TYPE opentype_analyze_container_type(void const *, UINT32) DECLSPEC_HIDDEN;
+extern HRESULT opentype_get_kerning_pairs(struct dwrite_fontface *fontface, unsigned int count,
+        const UINT16 *glyphs, INT32 *values) DECLSPEC_HIDDEN;
+extern BOOL opentype_has_kerning_pairs(struct dwrite_fontface *fontface) DECLSPEC_HIDDEN;
 
 struct dwrite_colorglyph {
     USHORT layer; /* [0, num_layers) index indicating current layer */
@@ -460,8 +465,6 @@ extern HRESULT freetype_get_glyphrun_outline(IDWriteFontFace5 *fontface, float e
         float const *advances, DWRITE_GLYPH_OFFSET const *offsets, unsigned int count, BOOL is_rtl,
         IDWriteGeometrySink *sink) DECLSPEC_HIDDEN;
 extern UINT16 freetype_get_glyphcount(IDWriteFontFace5 *fontface) DECLSPEC_HIDDEN;
-extern BOOL freetype_has_kerning_pairs(IDWriteFontFace5 *fontface) DECLSPEC_HIDDEN;
-extern INT32 freetype_get_kerning_pair_adjustment(IDWriteFontFace5 *fontface, UINT16 left, UINT16 right) DECLSPEC_HIDDEN;
 extern void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap_desc) DECLSPEC_HIDDEN;
 extern BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap*) DECLSPEC_HIDDEN;
 extern INT32 freetype_get_glyph_advance(IDWriteFontFace5 *fontface, FLOAT emsize, UINT16 index,
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 5a96ccc71a0..1afc72e22c5 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -639,6 +639,8 @@ static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
             IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
         if (fontface->colr.context)
             IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
+        if (fontface->kern.context)
+            IDWriteFontFace5_ReleaseFontTable(iface, fontface->kern.context);
         if (fontface->file)
             IDWriteFontFile_Release(fontface->file);
         if (fontface->stream)
@@ -1155,32 +1157,22 @@ static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontF
 }
 
 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
-    const UINT16 *indices, INT32 *adjustments)
+    const UINT16 *glyphs, INT32 *values)
 {
     struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
-    UINT32 i;
 
-    TRACE("%p, %u, %p, %p.\n", iface, count, indices, adjustments);
+    TRACE("%p, %u, %p, %p.\n", iface, count, glyphs, values);
 
-    if (!(indices || adjustments) || !count)
+    if (!(glyphs || values) || !count)
         return E_INVALIDARG;
 
-    if (!indices || count == 1) {
-        memset(adjustments, 0, count*sizeof(INT32));
-        return E_INVALIDARG;
-    }
-
-    if (!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS))
+    if (!glyphs || count == 1)
     {
-        memset(adjustments, 0, count*sizeof(INT32));
-        return S_OK;
+        memset(values, 0, count * sizeof(*values));
+        return E_INVALIDARG;
     }
 
-    for (i = 0; i < count-1; i++)
-        adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
-    adjustments[count-1] = 0;
-
-    return S_OK;
+    return opentype_get_kerning_pairs(fontface, count, glyphs, values);
 }
 
 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
@@ -1189,7 +1181,7 @@ static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
 
     TRACE("%p.\n", iface);
 
-    return !!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS);
+    return opentype_has_kerning_pairs(fontface);
 }
 
 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
@@ -4980,6 +4972,7 @@ HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_li
     fontface->gasp.exists = TRUE;
     fontface->cpal.exists = TRUE;
     fontface->colr.exists = TRUE;
+    fontface->kern.exists = TRUE;
     fontface->index = desc->index;
     fontface->simulations = desc->simulations;
     fontface->factory = desc->factory;
@@ -5001,9 +4994,6 @@ HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_li
             fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
         }
     }
-
-    if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace5_iface))
-        fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
     fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
 
     /* Font properties are reused from font object when 'normal' face creation path is used:
diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c
index 32fa4cc97c3..b770caac479 100644
--- a/dlls/dwrite/freetype.c
+++ b/dlls/dwrite/freetype.c
@@ -562,37 +562,6 @@ UINT16 freetype_get_glyphcount(IDWriteFontFace5 *fontface)
     return count;
 }
 
-BOOL freetype_has_kerning_pairs(IDWriteFontFace5 *fontface)
-{
-    BOOL has_kerning_pairs = FALSE;
-    FT_Face face;
-
-    EnterCriticalSection(&freetype_cs);
-    if (pFTC_Manager_LookupFace(cache_manager, fontface, &face) == 0)
-        has_kerning_pairs = !!FT_HAS_KERNING(face);
-    LeaveCriticalSection(&freetype_cs);
-
-    return has_kerning_pairs;
-}
-
-INT32 freetype_get_kerning_pair_adjustment(IDWriteFontFace5 *fontface, UINT16 left, UINT16 right)
-{
-    INT32 adjustment = 0;
-    FT_Face face;
-
-    EnterCriticalSection(&freetype_cs);
-    if (pFTC_Manager_LookupFace(cache_manager, fontface, &face) == 0) {
-        FT_Vector kern;
-        if (FT_HAS_KERNING(face)) {
-            pFT_Get_Kerning(face, left, right, FT_KERNING_UNSCALED, &kern);
-            adjustment = kern.x;
-        }
-    }
-    LeaveCriticalSection(&freetype_cs);
-
-    return adjustment;
-}
-
 static inline void ft_matrix_from_dwrite_matrix(const DWRITE_MATRIX *m, FT_Matrix *ft_matrix)
 {
     ft_matrix->xx =  m->m11 * 0x10000;
@@ -880,16 +849,6 @@ UINT16 freetype_get_glyphcount(IDWriteFontFace5 *fontface)
     return 0;
 }
 
-BOOL freetype_has_kerning_pairs(IDWriteFontFace5 *fontface)
-{
-    return FALSE;
-}
-
-INT32 freetype_get_kerning_pair_adjustment(IDWriteFontFace5 *fontface, UINT16 left, UINT16 right)
-{
-    return 0;
-}
-
 void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap)
 {
     SetRectEmpty(&bitmap->bbox);
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index 45967a12f0a..01bf1ce0a09 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -46,6 +46,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
 #define MS_CBLC_TAG DWRITE_MAKE_OPENTYPE_TAG('C','B','L','C')
 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
 #define MS_META_TAG DWRITE_MAKE_OPENTYPE_TAG('m','e','t','a')
+#define MS_KERN_TAG DWRITE_MAKE_OPENTYPE_TAG('k','e','r','n')
 
 /* 'sbix' formats */
 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
@@ -820,6 +821,19 @@ typedef struct {
     DWORD ExtensionOffset;
 } GSUB_ExtensionPosFormat1;
 
+struct kern_header
+{
+    WORD version;
+    WORD table_count;
+};
+
+struct kern_subtable_header
+{
+    WORD version;
+    WORD length;
+    WORD coverage;
+};
+
 #include "poppack.h"
 
 enum TT_NAME_WINDOWS_ENCODING_ID
@@ -6451,3 +6465,132 @@ HRESULT opentype_get_vertical_glyph_variants(struct dwrite_fontface *fontface, u
 
     return S_OK;
 }
+
+BOOL opentype_has_kerning_pairs(struct dwrite_fontface *fontface)
+{
+    const struct kern_subtable_header *subtable;
+    struct file_stream_desc stream_desc;
+    const struct kern_header *header;
+    unsigned int offset, count, i;
+
+    if (fontface->flags & (FONTFACE_KERNING_PAIRS | FONTFACE_NO_KERNING_PAIRS))
+        return !!(fontface->flags & FONTFACE_KERNING_PAIRS);
+
+    fontface->flags |= FONTFACE_NO_KERNING_PAIRS;
+
+    stream_desc.stream = fontface->stream;
+    stream_desc.face_type = fontface->type;
+    stream_desc.face_index = fontface->index;
+
+    opentype_get_font_table(&stream_desc, MS_KERN_TAG, &fontface->kern);
+    if (fontface->kern.exists)
+    {
+        if ((header = table_read_ensure(&fontface->kern, 0, sizeof(*header))))
+        {
+            count = GET_BE_WORD(header->table_count);
+            offset = sizeof(*header);
+
+            /* Freetype limits table count this way. */
+            count = min(count, 32);
+
+            /* Check for presence of format 0 subtable with horizontal coverage. */
+            for (i = 0; i < count; ++i)
+            {
+                if (!(subtable = table_read_ensure(&fontface->kern, offset, sizeof(*subtable))))
+                    break;
+
+                if (subtable->version == 0 && GET_BE_WORD(subtable->coverage) & 1)
+                {
+                    fontface->flags &= ~FONTFACE_NO_KERNING_PAIRS;
+                    fontface->flags |= FONTFACE_KERNING_PAIRS;
+                    break;
+                }
+
+                offset += GET_BE_WORD(subtable->length);
+            }
+        }
+    }
+
+    if (fontface->flags & FONTFACE_NO_KERNING_PAIRS && fontface->kern.data)
+        IDWriteFontFileStream_ReleaseFileFragment(stream_desc.stream, fontface->kern.context);
+
+    return !!(fontface->flags & FONTFACE_KERNING_PAIRS);
+}
+
+struct kern_format0_compare_key
+{
+    UINT16 left;
+    UINT16 right;
+};
+
+static int kern_format0_compare(const void *a, const void *b)
+{
+    const struct kern_format0_compare_key *key = a;
+    const WORD *data = b;
+    UINT16 left = GET_BE_WORD(data[0]), right = GET_BE_WORD(data[1]);
+    int ret;
+
+    if ((ret = (int)key->left - (int)left)) return ret;
+    if ((ret = (int)key->right - (int)right)) return ret;
+    return 0;
+}
+
+HRESULT opentype_get_kerning_pairs(struct dwrite_fontface *fontface, unsigned int count,
+        const UINT16 *glyphs, INT32 *values)
+{
+    const struct kern_subtable_header *subtable;
+    unsigned int i, s, offset, pair_count, subtable_count;
+    struct kern_format0_compare_key key;
+    const struct kern_header *header;
+    const WORD *data;
+
+    if (!opentype_has_kerning_pairs(fontface))
+    {
+        memset(values, 0, count * sizeof(*values));
+        return S_OK;
+    }
+
+    subtable_count = table_read_be_word(&fontface->kern, 2);
+    subtable_count = min(subtable_count, 32);
+
+    for (i = 0; i < count - 1; ++i)
+    {
+        offset = sizeof(*header);
+
+        key.left = glyphs[i];
+        key.right = glyphs[i + 1];
+        values[i] = 0;
+
+        for (s = 0; s < subtable_count; ++s)
+        {
+            if (!(subtable = table_read_ensure(&fontface->kern, offset, sizeof(*subtable))))
+                break;
+
+            if (subtable->version == 0 && GET_BE_WORD(subtable->coverage) & 1)
+            {
+                if ((data = table_read_ensure(&fontface->kern, offset, GET_BE_WORD(subtable->length))))
+                {
+                    /* Skip subtable header */
+                    data += 3;
+                    pair_count = GET_BE_WORD(*data);
+                    data += 4;
+                    /* Move to pair data */
+                    if ((data = table_read_ensure(&fontface->kern, offset + 7 * sizeof(*data),
+                            pair_count * 3 * sizeof(*data))))
+                    {
+                        if ((data = bsearch(&key, data, pair_count, 3 * sizeof(*data), kern_format0_compare)))
+                        {
+                            values[i] = (short)GET_BE_WORD(data[2]);
+                            break;
+                        }
+                    }
+                }
+            }
+
+            offset += GET_BE_WORD(subtable->length);
+        }
+    }
+    values[count - 1] = 0;
+
+    return S_OK;
+}
-- 
2.30.1




More information about the wine-devel mailing list