dwrite: Initial support for number substitution.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2017-05-10 10:30:50 +03:00 committed by Alexandre Julliard
parent 8ef79b023a
commit 5f7848595f

View file

@ -225,6 +225,8 @@ static inline struct dwrite_numbersubstitution *impl_from_IDWriteNumberSubstitut
return CONTAINING_RECORD(iface, struct dwrite_numbersubstitution, IDWriteNumberSubstitution_iface);
}
static struct dwrite_numbersubstitution *unsafe_impl_from_IDWriteNumberSubstitution(IDWriteNumberSubstitution *iface);
static inline struct dwrite_fontfallback *impl_from_IDWriteFontFallback(IDWriteFontFallback *iface)
{
return CONTAINING_RECORD(iface, struct dwrite_fontfallback, IDWriteFontFallback_iface);
@ -1022,6 +1024,75 @@ static UINT32 get_opentype_language(const WCHAR *locale)
return language;
}
static DWRITE_NUMBER_SUBSTITUTION_METHOD get_number_substitutes(IDWriteNumberSubstitution *substitution, WCHAR *digits)
{
struct dwrite_numbersubstitution *numbersubst = unsafe_impl_from_IDWriteNumberSubstitution(substitution);
DWRITE_NUMBER_SUBSTITUTION_METHOD method;
WCHAR isolang[9];
DWORD lctype;
if (!numbersubst)
return DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE;
lctype = numbersubst->ignore_user_override ? LOCALE_NOUSEROVERRIDE : 0;
if (numbersubst->method == DWRITE_NUMBER_SUBSTITUTION_METHOD_FROM_CULTURE) {
DWORD value;
method = DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE;
if (GetLocaleInfoEx(numbersubst->locale, lctype | LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER, (WCHAR *)&value, 2)) {
switch (value)
{
case 0:
method = DWRITE_NUMBER_SUBSTITUTION_METHOD_CONTEXTUAL;
break;
case 2:
method = DWRITE_NUMBER_SUBSTITUTION_METHOD_NATIONAL;
break;
case 1:
default:
if (value != 1)
WARN("Unknown IDIGITSUBSTITUTION value %u, locale %s.\n", value, debugstr_w(numbersubst->locale));
}
}
else
WARN("Failed to get IDIGITSUBSTITUTION for locale %s\n", debugstr_w(numbersubst->locale));
}
else
method = numbersubst->method;
digits[0] = 0;
switch (method)
{
case DWRITE_NUMBER_SUBSTITUTION_METHOD_NATIONAL:
GetLocaleInfoEx(numbersubst->locale, lctype | LOCALE_SNATIVEDIGITS, digits, sizeof(digits)/sizeof(digits[0]));
break;
case DWRITE_NUMBER_SUBSTITUTION_METHOD_CONTEXTUAL:
case DWRITE_NUMBER_SUBSTITUTION_METHOD_TRADITIONAL:
if (GetLocaleInfoEx(numbersubst->locale, LOCALE_SISO639LANGNAME, isolang, sizeof(isolang)/sizeof(isolang[0]))) {
static const WCHAR arW[] = {'a','r',0};
static const WCHAR arabicW[] = {0x640,0x641,0x642,0x643,0x644,0x645,0x646,0x647,0x648,0x649,0};
/* For some Arabic locales Latin digits are returned for SNATIVEDIGITS */
if (!strcmpW(arW, isolang)) {
strcpyW(digits, arabicW);
break;
}
}
GetLocaleInfoEx(numbersubst->locale, lctype | LOCALE_SNATIVEDIGITS, digits, sizeof(digits)/sizeof(digits[0]));
break;
default:
;
}
if (method != DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE && !*digits) {
WARN("Failed to get number substitutes for locale %s, method %d\n", debugstr_w(numbersubst->locale), method);
method = DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE;
}
return method;
}
static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
WCHAR const* text, UINT32 length, IDWriteFontFace* fontface, BOOL is_sideways,
BOOL is_rtl, DWRITE_SCRIPT_ANALYSIS const* analysis, WCHAR const* locale,
@ -1031,10 +1102,12 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
DWRITE_SHAPING_GLYPH_PROPERTIES* glyph_props, UINT32* actual_glyph_count)
{
const struct dwritescript_properties *scriptprops;
DWRITE_NUMBER_SUBSTITUTION_METHOD method;
struct scriptshaping_context context;
struct scriptshaping_cache *cache = NULL;
BOOL update_cluster, need_vertical;
IDWriteFontFace1 *fontface1;
WCHAR digits[11];
WCHAR *string;
UINT32 i, g;
HRESULT hr = S_OK;
@ -1050,8 +1123,11 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
if (max_glyph_count < length)
return E_NOT_SUFFICIENT_BUFFER;
if (substitution)
FIXME("number substitution is not supported.\n");
string = heap_alloc(sizeof(WCHAR)*length);
if (!string)
return E_OUTOFMEMORY;
method = get_number_substitutes(substitution, digits);
for (i = 0; i < length; i++) {
/* FIXME: set to better values */
@ -1066,6 +1142,21 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
text_props[i].reserved = 0;
clustermap[i] = i;
string[i] = text[i];
switch (method)
{
case DWRITE_NUMBER_SUBSTITUTION_METHOD_CONTEXTUAL:
if (!is_rtl)
break;
/* fallthrough */
default:
if (string[i] >= '0' && string[i] <= '9')
string[i] = digits[string[i] - '0'];
break;
case DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE:
;
}
}
for (; i < max_glyph_count; i++) {
@ -1076,10 +1167,6 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
glyph_props[i].reserved = 0;
}
string = heap_alloc(sizeof(WCHAR)*length);
if (!string)
return E_OUTOFMEMORY;
hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
if (FAILED(hr))
WARN("failed to get IDWriteFontFace1\n");
@ -1090,16 +1177,11 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
UINT32 codepoint;
if (!update_cluster) {
codepoint = decode_surrogate_pair(text, i, length);
if (!codepoint) {
codepoint = is_rtl ? bidi_get_mirrored_char(text[i]) : text[i];
string[i] = codepoint;
}
else {
string[i] = text[i];
string[i+1] = text[i+1];
codepoint = decode_surrogate_pair(string, i, length);
if (!codepoint)
codepoint = is_rtl ? bidi_get_mirrored_char(string[i]) : string[i];
else
update_cluster = TRUE;
}
hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, &glyph_indices[g]);
if (FAILED(hr))
@ -1778,6 +1860,13 @@ static const struct IDWriteNumberSubstitutionVtbl numbersubstitutionvtbl = {
dwritenumbersubstitution_Release
};
struct dwrite_numbersubstitution *unsafe_impl_from_IDWriteNumberSubstitution(IDWriteNumberSubstitution *iface)
{
if (!iface || iface->lpVtbl != &numbersubstitutionvtbl)
return NULL;
return CONTAINING_RECORD(iface, struct dwrite_numbersubstitution, IDWriteNumberSubstitution_iface);
}
HRESULT create_numbersubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD method, const WCHAR *locale,
BOOL ignore_user_override, IDWriteNumberSubstitution **ret)
{