[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