[PATCH 5/5] dwrite: Use better font matching algorithm based on weight/stretch/style triples

Nikolay Sivov nsivov at codeweavers.com
Mon Aug 10 05:51:28 CDT 2015


---

-------------- next part --------------
>From 3688b7e163c3511053acd2276ab3a943f32dea2a Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov at codeweavers.com>
Date: Sat, 8 Aug 2015 11:38:18 +0300
Subject: [PATCH 5/5] dwrite: Use better font matching algorithm based on
 weight/stretch/style triples

---
 dlls/dwrite/font.c       | 103 ++++++++++++++++++++++++++++++++++++-----------
 dlls/dwrite/tests/font.c |   2 +-
 2 files changed, 80 insertions(+), 25 deletions(-)

diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 6036720..eda6378 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -42,6 +42,12 @@ static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
 
+struct dwrite_font_propvec {
+    FLOAT stretch;
+    FLOAT style;
+    FLOAT weight;
+};
+
 struct dwrite_font_data {
     LONG ref;
 
@@ -49,6 +55,8 @@ struct dwrite_font_data {
     DWRITE_FONT_STRETCH stretch;
     DWRITE_FONT_WEIGHT weight;
     DWRITE_PANOSE panose;
+    struct dwrite_font_propvec propvec;
+
     DWRITE_FONT_METRICS1 metrics;
     IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1];
 
@@ -257,6 +265,23 @@ static void* get_fontface_table(struct dwrite_fontface *fontface, UINT32 tag, st
     return table->data;
 }
 
+static void init_font_prop_vec(const struct dwrite_font_props *props, struct dwrite_font_propvec *vec)
+{
+    vec->stretch = ((INT32)props->stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
+    vec->style = props->style * 7.0f;
+    vec->weight = ((INT32)props->weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
+}
+
+static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
+{
+    return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
+}
+
+static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
+{
+    return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
+}
+
 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
 {
     return get_fontface_table(fontface, MS_CMAP_TAG, &fontface->cmap);
@@ -1552,14 +1577,44 @@ static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily *iface,
     return clone_localizedstring(This->data->familyname, names);
 }
 
-static inline BOOL is_matching_font_style(DWRITE_FONT_STYLE style, DWRITE_FONT_STYLE font_style)
+static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
+    const struct dwrite_font_propvec *req)
 {
-    if (style == font_style)
+    FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
+    FLOAT next_to_req = get_font_prop_vec_distance(next, req);
+    FLOAT cur_req_prod, next_req_prod;
+
+    if (next_to_req < cur_to_req)
         return TRUE;
 
-    if (((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE)) && font_style == DWRITE_FONT_STYLE_NORMAL)
+    if (next_to_req > cur_to_req)
+        return FALSE;
+
+    cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
+    next_req_prod = get_font_prop_vec_dotproduct(next, req);
+
+    if (next_req_prod > cur_req_prod)
         return TRUE;
 
+    if (next_req_prod < cur_req_prod)
+        return FALSE;
+
+    if (next->stretch > cur->stretch)
+        return TRUE;
+    if (next->stretch < cur->stretch)
+        return FALSE;
+
+    if (next->style > cur->style)
+        return TRUE;
+    if (next->style < cur->style)
+        return FALSE;
+
+    if (next->weight > cur->weight)
+        return TRUE;
+    if (next->weight < cur->weight)
+        return FALSE;
+
+    /* full match, no reason to prefer new variant */
     return FALSE;
 }
 
@@ -1567,35 +1622,34 @@ static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily *i
     DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
 {
     struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
-    UINT32 min_weight_diff = ~0u;
-    int found = -1, i;
+    struct dwrite_font_props reqprops = { style, stretch, weight };
+    DWRITE_FONT_SIMULATIONS simulations;
+    struct dwrite_font_propvec req;
+    struct dwrite_font_data *match;
+    UINT32 i;
 
     TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
 
-    for (i = 0; i < This->data->font_count; i++) {
-        if (is_matching_font_style(style, This->data->fonts[i]->style) && stretch == This->data->fonts[i]->stretch) {
-            DWRITE_FONT_WEIGHT font_weight = This->data->fonts[i]->weight;
-            UINT32 weight_diff = abs(font_weight - weight);
-            if (weight_diff < min_weight_diff) {
-                min_weight_diff = weight_diff;
-                found = i;
-            }
-        }
+    if (This->data->font_count == 0) {
+        *font = NULL;
+        return DWRITE_E_NOFONT;
     }
 
-    if (found != -1) {
-        DWRITE_FONT_SIMULATIONS simulations = DWRITE_FONT_SIMULATIONS_NONE;
+    init_font_prop_vec(&reqprops, &req);
+    match = This->data->fonts[0];
 
-        if (((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE)) &&
-            This->data->fonts[found]->style == DWRITE_FONT_STYLE_NORMAL) {
-            simulations = DWRITE_FONT_SIMULATIONS_OBLIQUE;
-        }
-        return create_font(This->data->fonts[found], iface, simulations, font);
+    for (i = 1; i < This->data->font_count; i++) {
+        if (is_better_font_match(&This->data->fonts[i]->propvec, &match->propvec, &req))
+            match = This->data->fonts[i];
     }
-    else {
-        *font = NULL;
-        return DWRITE_E_NOFONT;
+
+    simulations = DWRITE_FONT_SIMULATIONS_NONE;
+    if (((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE)) &&
+        match->style == DWRITE_FONT_STYLE_NORMAL) {
+        simulations = DWRITE_FONT_SIMULATIONS_OBLIQUE;
     }
+
+    return create_font(match, iface, simulations, font);
 }
 
 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight,
@@ -1941,6 +1995,7 @@ static HRESULT init_font_data(IDWriteFactory2 *factory, IDWriteFontFile *file, U
     data->stretch = props.stretch;
     data->weight = props.weight;
     data->panose = props.panose;
+    init_font_prop_vec(&props, &data->propvec);
 
     if (tt_os2)
         IDWriteFontFileStream_ReleaseFileFragment(*stream, os2_context);
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index 0664a9a..7ee5c8a 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -705,7 +705,7 @@ todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
     weight = IDWriteFont_GetWeight(font);
-    ok(weight == DWRITE_FONT_WEIGHT_NORMAL || broken(weight == DWRITE_FONT_WEIGHT_BOLD) /* win7 w/o SP */,
+    ok(weight == DWRITE_FONT_WEIGHT_NORMAL || weight == DWRITE_FONT_WEIGHT_BOLD,
         "got %d\n", weight);
     IDWriteFont_Release(font);
 
-- 
2.1.4



More information about the wine-patches mailing list