From 4ffd3e6af611fe6f2358e43811c13a13dbfd86df Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Thu, 12 Aug 2010 14:58:46 -0500 Subject: [PATCH] usp10: Add Syriac contextual shaping. --- dlls/usp10/shape.c | 123 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/dlls/usp10/shape.c b/dlls/usp10/shape.c index 0afcf8024a7..1d4da21f765 100644 --- a/dlls/usp10/shape.c +++ b/dlls/usp10/shape.c @@ -41,6 +41,7 @@ typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*, WCHAR*, INT, WORD*, INT*, INT); static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs); +static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs); extern const unsigned short wine_shaping_table[]; extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4]; @@ -58,7 +59,11 @@ enum joined_forms { Xn=0, Xr, Xl, - Xm + Xm, + /* Syriac Alaph */ + Afj, + Afn, + Afx }; #ifdef WORDS_BIGENDIAN @@ -244,7 +249,11 @@ static const char* contextual_features[] = "isol", "fina", "init", - "medi" + "medi", + /* Syriac Alaph */ + "med2", + "fin2", + "fin3" }; static OPENTYPE_FEATURE_RECORD standard_features[] = @@ -294,7 +303,7 @@ static const ScriptShapeData ShapingData[] = {{ arabic_features, 6}, "arab", ContextualShape_Arabic}, {{ arabic_features, 6}, "arab", ContextualShape_Arabic}, {{ hebrew_features, 1}, "hebr", NULL}, - {{ syriac_features, 4}, "syrc", NULL}, + {{ syriac_features, 4}, "syrc", ContextualShape_Syriac}, {{ arabic_features, 6}, "arab", ContextualShape_Arabic}, }; @@ -829,6 +838,18 @@ static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, W return GSUB_E_NOFEATURE; } +static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen) +{ + if (i + delta < 0) + return 0; + if ( i+ delta >= cchLen) + return 0; + + i += delta; + + return chars[i]; +} + static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa) { if (i + delta < 0) @@ -864,6 +885,14 @@ static inline BOOL left_join_causing(CHAR joining_type) return (joining_type == jtR || joining_type == jtD || joining_type == jtC); } +static inline BOOL word_break_causing(WCHAR chr) +{ + /* we are working within a string of characters already guareented to + be within one script, Syriac, so we do not worry about any characers + other than the space character outside of that range */ + return (chr == 0 || chr == 0x20 ); +} + /* * ContextualShape_Arabic */ @@ -949,6 +978,94 @@ static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *p HeapFree(GetProcessHeap(),0,context_type); } +/* + * ContextualShape_Syriac + */ + +#define ALAPH 0x710 +#define DALATH 0x715 +#define RISH 0x72A + +static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs) +{ + CHAR *context_type; + INT *context_shape; + INT dirR, dirL; + int i; + + if (*pcGlyphs != cChars) + { + ERR("Number of Glyphs and Chars need to match at the beginning\n"); + return; + } + + if (!psa->fLogicalOrder && psa->fRTL) + { + dirR = 1; + dirL = -1; + } + else + { + dirR = -1; + dirL = 1; + } + + if (!psc->GSUB_Table) + psc->GSUB_Table = load_gsub_table(hdc); + + if (!psc->GSUB_Table) + return; + + context_type = HeapAlloc(GetProcessHeap(),0,cChars); + context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars); + + for (i = 0; i < cChars; i++) + context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)]; + + for (i = 0; i < cChars; i++) + { + if (pwcChars[i] == ALAPH) + { + WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars); + + if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars))) + context_shape[i] = Afj; + else if ( rchar != DALATH && rchar != RISH && +!left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && +word_break_causing(neighbour_char(i,dirL,pwcChars,cChars))) + context_shape[i] = Afn; + else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars))) + context_shape[i] = Afx; + } + else if (context_type[i] == jtR && +right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) + context_shape[i] = Xr; + else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa))) + context_shape[i] = Xl; + else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)) && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) + context_shape[i] = Xm; + else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) + context_shape[i] = Xr; + else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa))) + context_shape[i] = Xl; + else + context_shape[i] = Xn; + } + + /* Contextual Shaping */ + i = 0; + while(i < *pcGlyphs) + { + INT nextIndex; + nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc->GSUB_Table, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]); + if (nextIndex > GSUB_E_NOGLYPH) + i = nextIndex; + } + + HeapFree(GetProcessHeap(),0,context_shape); + HeapFree(GetProcessHeap(),0,context_type); +} + void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs) { if (ShapingData[psa->eScript].contextProc)