[PATCH] dwrite: Initial support for number substitution
Nikolay Sivov
nsivov at codeweavers.com
Wed May 10 02:30:50 CDT 2017
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/dwrite/analyzer.c | 119 ++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 104 insertions(+), 15 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index 8f32bec694..5ae16a1aae 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -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)
{
--
2.11.0
More information about the wine-patches
mailing list