dwrite: Implement font style resolution from name strings.
This commit is contained in:
parent
146df7dab1
commit
5185906006
|
@ -266,11 +266,12 @@ 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)
|
||||
static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
|
||||
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;
|
||||
vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
|
||||
vec->style = style * 7.0f;
|
||||
vec->weight = ((INT32)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)
|
||||
|
@ -1603,7 +1604,6 @@ 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);
|
||||
struct dwrite_font_props reqprops = { style, stretch, weight };
|
||||
DWRITE_FONT_SIMULATIONS simulations;
|
||||
struct dwrite_font_propvec req;
|
||||
struct dwrite_font_data *match;
|
||||
|
@ -1616,7 +1616,7 @@ static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily *i
|
|||
return DWRITE_E_NOFONT;
|
||||
}
|
||||
|
||||
init_font_prop_vec(&reqprops, &req);
|
||||
init_font_prop_vec(weight, stretch, style, &req);
|
||||
match = This->data->fonts[0];
|
||||
|
||||
for (i = 1; i < This->data->font_count; i++) {
|
||||
|
@ -1939,20 +1939,226 @@ HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT init_font_data(IDWriteFactory2 *factory, IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
|
||||
IDWriteFontFileStream **stream, struct dwrite_font_data **ret)
|
||||
static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
|
||||
{
|
||||
void *os2_context, *head_context;
|
||||
const void *tt_os2 = NULL, *tt_head = NULL;
|
||||
struct dwrite_font_props props;
|
||||
struct dwrite_font_data *data;
|
||||
static const WCHAR enusW[] = {'e','n','-','U','S',0};
|
||||
BOOL exists = FALSE;
|
||||
UINT32 index;
|
||||
HRESULT hr;
|
||||
|
||||
buffer[0] = 0;
|
||||
hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
|
||||
if (FAILED(hr) || !exists)
|
||||
return;
|
||||
|
||||
IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
|
||||
}
|
||||
|
||||
static int trim_spaces(WCHAR *in, WCHAR *ret)
|
||||
{
|
||||
int len;
|
||||
|
||||
while (isspaceW(*in))
|
||||
in++;
|
||||
|
||||
len = strlenW(in);
|
||||
while (isspaceW(in[len-1]))
|
||||
len--;
|
||||
|
||||
memcpy(ret, in, len*sizeof(WCHAR));
|
||||
ret[len] = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct name_token {
|
||||
struct list entry;
|
||||
const WCHAR *ptr;
|
||||
INT len;
|
||||
};
|
||||
|
||||
static inline BOOL is_name_separator_char(WCHAR ch)
|
||||
{
|
||||
return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
|
||||
}
|
||||
|
||||
static BOOL match_pattern_list(struct list *tokens, const WCHAR **patterns)
|
||||
{
|
||||
struct name_token *token;
|
||||
const WCHAR *ptr;
|
||||
int i = 0;
|
||||
|
||||
while ((ptr = patterns[++i])) {
|
||||
int len = strlenW(ptr);
|
||||
|
||||
LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
|
||||
if (token->len != len)
|
||||
continue;
|
||||
|
||||
if (!strncmpiW(token->ptr, ptr, len)) {
|
||||
list_remove(&token->entry);
|
||||
heap_free(token);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style)
|
||||
{
|
||||
static const WCHAR itaW[] = {'i','t','a',0};
|
||||
static const WCHAR italW[] = {'i','t','a','l',0};
|
||||
static const WCHAR italicW[] = {'i','t','a','l','i','c',0};
|
||||
static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
|
||||
static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
|
||||
|
||||
static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
|
||||
static const WCHAR obliqueW[] = {'o','b','l','i','q','u','e',0};
|
||||
static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
|
||||
static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
|
||||
static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
|
||||
|
||||
static const WCHAR *italic_patterns[] = {
|
||||
itaW,
|
||||
italW,
|
||||
italicW,
|
||||
cursiveW,
|
||||
kursivW,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const WCHAR *oblique_patterns[] = {
|
||||
inclinedW,
|
||||
obliqueW,
|
||||
backslantedW,
|
||||
backslantW,
|
||||
slantedW,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* italic patterns first */
|
||||
if (match_pattern_list(tokens, italic_patterns))
|
||||
return DWRITE_FONT_STYLE_ITALIC;
|
||||
|
||||
/* oblique patterns */
|
||||
if (match_pattern_list(tokens, oblique_patterns))
|
||||
return DWRITE_FONT_STYLE_OBLIQUE;
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
static void font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
|
||||
{
|
||||
static const WCHAR bookW[] = {'B','o','o','k',0};
|
||||
static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
|
||||
static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
|
||||
static const WCHAR romanW[] = {'R','o','m','a','n',0};
|
||||
static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
|
||||
|
||||
static const WCHAR *regular_patterns[] = {
|
||||
bookW,
|
||||
normalW,
|
||||
regularW,
|
||||
romanW,
|
||||
uprightW,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const WCHAR spaceW[] = {' ',0};
|
||||
WCHAR familynameW[255], facenameW[255];
|
||||
struct name_token *token, *token2;
|
||||
BOOL found = FALSE;
|
||||
struct list tokens;
|
||||
const WCHAR *ptr;
|
||||
int len, i = 0;
|
||||
|
||||
/* remove leading and trailing spaces from family and face name */
|
||||
trim_spaces(familyW, familynameW);
|
||||
len = trim_spaces(faceW, facenameW);
|
||||
|
||||
/* remove rightmost regular variant from face name */
|
||||
while (!found && (ptr = regular_patterns[i++])) {
|
||||
WCHAR *src;
|
||||
int pattern_len = strlenW(ptr);
|
||||
|
||||
if (pattern_len > len)
|
||||
continue;
|
||||
|
||||
src = facenameW + len - pattern_len;
|
||||
while (src >= facenameW) {
|
||||
if (!strncmpiW(src, ptr, pattern_len)) {
|
||||
memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
|
||||
len = strlenW(facenameW);
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
src--;
|
||||
}
|
||||
}
|
||||
|
||||
/* append face name to family name, FIXME check if face name is a substring of family name */
|
||||
if (*facenameW) {
|
||||
strcatW(familynameW, spaceW);
|
||||
strcatW(familynameW, facenameW);
|
||||
}
|
||||
|
||||
/* tokenize with " .-_" */
|
||||
list_init(&tokens);
|
||||
ptr = familynameW;
|
||||
|
||||
while (*ptr) {
|
||||
struct name_token *token = heap_alloc(sizeof(*token));
|
||||
token->ptr = ptr;
|
||||
token->len = 0;
|
||||
|
||||
while (*ptr && !is_name_separator_char(*ptr)) {
|
||||
token->len++;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
/* skip separators */
|
||||
while (is_name_separator_char(*ptr))
|
||||
ptr++;
|
||||
|
||||
list_add_head(&tokens, &token->entry);
|
||||
}
|
||||
|
||||
/* extract and resolve style */
|
||||
font->style = font_extract_style(&tokens, font->style);
|
||||
|
||||
/* TODO: extract stretch */
|
||||
|
||||
/* TODO: extract weight */
|
||||
|
||||
/* TODO: resolve weight */
|
||||
|
||||
/* TODO: resolve stretch */
|
||||
|
||||
/* release tokens */
|
||||
LIST_FOR_EACH_ENTRY_SAFE(token, token2, &tokens, struct name_token, entry) {
|
||||
list_remove(&token->entry);
|
||||
heap_free(token);
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT init_font_data(IDWriteFactory2 *factory, IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
|
||||
IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
|
||||
{
|
||||
struct dwrite_font_props props;
|
||||
struct dwrite_font_data *data;
|
||||
IDWriteFontFileStream *stream;
|
||||
WCHAR familyW[255], faceW[255];
|
||||
HRESULT hr;
|
||||
|
||||
*ret = NULL;
|
||||
data = heap_alloc_zero(sizeof(*data));
|
||||
if (!data)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
hr = get_filestream_from_file(file, stream);
|
||||
hr = get_filestream_from_file(file, &stream);
|
||||
if (FAILED(hr)) {
|
||||
heap_free(data);
|
||||
return hr;
|
||||
|
@ -1966,23 +2172,29 @@ static HRESULT init_font_data(IDWriteFactory2 *factory, IDWriteFontFile *file, D
|
|||
IDWriteFontFile_AddRef(file);
|
||||
IDWriteFactory2_AddRef(factory);
|
||||
|
||||
opentype_get_font_table(*stream, face_type, face_index, MS_OS2_TAG, &tt_os2, &os2_context, NULL, NULL);
|
||||
opentype_get_font_table(*stream, face_type, face_index, MS_HEAD_TAG, &tt_head, &head_context, NULL, NULL);
|
||||
opentype_get_font_properties(stream, face_type, face_index, &props);
|
||||
opentype_get_font_metrics(stream, face_type, face_index, &data->metrics, NULL);
|
||||
opentype_get_font_facename(stream, face_type, face_index, &data->names);
|
||||
|
||||
opentype_get_font_properties(*stream, face_type, face_index, &props);
|
||||
opentype_get_font_metrics(*stream, face_type, face_index, &data->metrics, NULL);
|
||||
opentype_get_font_facename(*stream, face_type, face_index, &data->names);
|
||||
/* get family name from font file */
|
||||
hr = opentype_get_font_familyname(stream, face_type, face_index, family_name);
|
||||
IDWriteFontFileStream_Release(stream);
|
||||
if (FAILED(hr)) {
|
||||
WARN("unable to get family name from font\n");
|
||||
release_font_data(data);
|
||||
return hr;
|
||||
}
|
||||
|
||||
data->style = props.style;
|
||||
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);
|
||||
if (tt_head)
|
||||
IDWriteFontFileStream_ReleaseFileFragment(*stream, head_context);
|
||||
fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
|
||||
fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
|
||||
font_apply_differentiation_rules(data, familyW, faceW);
|
||||
|
||||
init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
|
||||
|
||||
*ret = data;
|
||||
return S_OK;
|
||||
|
@ -2062,28 +2274,17 @@ HRESULT create_font_collection(IDWriteFactory2* factory, IDWriteFontFileEnumerat
|
|||
for (i = 0; i < face_count; i++) {
|
||||
IDWriteLocalizedStrings *family_name = NULL;
|
||||
struct dwrite_font_data *font_data;
|
||||
IDWriteFontFileStream *stream;
|
||||
WCHAR buffer[255];
|
||||
WCHAR familyW[255];
|
||||
UINT32 index;
|
||||
|
||||
/* alloc and init new font data structure */
|
||||
hr = init_font_data(factory, file, face_type, i, &stream, &font_data);
|
||||
hr = init_font_data(factory, file, face_type, i, &family_name, &font_data);
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
|
||||
/* get family name from font file */
|
||||
hr = opentype_get_font_familyname(stream, face_type, i, &family_name);
|
||||
IDWriteFontFileStream_Release(stream);
|
||||
if (FAILED(hr)) {
|
||||
WARN("unable to get family name from font\n");
|
||||
release_font_data(font_data);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[0] = 0;
|
||||
IDWriteLocalizedStrings_GetString(family_name, 0, buffer, sizeof(buffer)/sizeof(WCHAR));
|
||||
fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
|
||||
|
||||
index = collection_find_family(collection, buffer);
|
||||
index = collection_find_family(collection, familyW);
|
||||
if (index != ~0u)
|
||||
hr = fontfamily_add_font(collection->family_data[index], font_data);
|
||||
else {
|
||||
|
|
Loading…
Reference in New Issue