From b9c30445c70d828d92833333ca54afb46c884447 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Tue, 13 Apr 2010 14:49:20 -0500 Subject: [PATCH] ups10: Reimplement ScriptLayout to properly handle mixed runs. --- dlls/gdi32/bidi.c | 105 ++++++++++---------------------------------- dlls/usp10/bidi.c | 95 +++++++++++++++++++++++++++++++++++++++ dlls/usp10/tests/usp10.c | 59 ++++++++++++++++++++----- dlls/usp10/usp10.c | 45 +++++++++++++------ dlls/usp10/usp10_internal.h | 3 ++ 5 files changed, 199 insertions(+), 108 deletions(-) diff --git a/dlls/gdi32/bidi.c b/dlls/gdi32/bidi.c index 371713749d2..60fff3e58fd 100644 --- a/dlls/gdi32/bidi.c +++ b/dlls/gdi32/bidi.c @@ -192,22 +192,9 @@ static void classify(LPCWSTR lpString, WORD *chartype, DWORD uCount) } } -/* reverse cch characters */ -static void reverse(LPWSTR psz, int cch) -{ - WCHAR chTemp; - int ich = 0; - for (; ich < --cch; ich++) - { - chTemp = psz[ich]; - psz[ich] = psz[cch]; - psz[cch] = chTemp; - } -} - /* Set a run of cval values at locations all prior to, but not including */ /* iStart, to the new value nval. */ -static void SetDeferredRun(WORD *pval, int cval, int iStart, int nval) +static void SetDeferredRun(BYTE *pval, int cval, int iStart, int nval) { int i = iStart - 1; for (; i >= iStart - cval; i--) @@ -299,10 +286,10 @@ static int resolveLines(LPCWSTR pszInput, BOOL * pbrk, int cch) a real implementation, cch and the initial pointer values would have to be adjusted. ------------------------------------------------------------------------*/ -static void resolveWhitespace(int baselevel, const WORD *pcls, WORD *plevel, int cch) +static void resolveWhitespace(int baselevel, const WORD *pcls, BYTE *plevel, int cch) { int cchrun = 0; - int oldlevel = baselevel; + BYTE oldlevel = baselevel; int ich = 0; for (; ich < cch; ich++) @@ -340,67 +327,6 @@ static void resolveWhitespace(int baselevel, const WORD *pcls, WORD *plevel, int SetDeferredRun(plevel, cchrun, ich, baselevel); } - -/*------------------------------------------------------------------------ - Functions: reorder/reorderLevel - - Recursively reorders the display string - "From the highest level down, reverse all characters at that level and - higher, down to the lowest odd level" - - Implements rule L2 of the Unicode bidi Algorithm. - - Input: Array of embedding levels - Character count - Flag enabling reversal (set to false by initial caller) - - In/Out: Text to reorder - - Note: levels may exceed 15 resp. 61 on input. - - Rule L3 - reorder combining marks is not implemented here - Rule L4 - glyph mirroring is implemented as a display option below - - Note: this should be applied a line at a time --------------------------------------------------------------------------*/ -static int reorderLevel(int level, LPWSTR pszText, const WORD* plevel, int cch, BOOL fReverse) -{ - int ich = 0; - - /* true as soon as first odd level encountered */ - fReverse = fReverse || odd(level); - - for (; ich < cch; ich++) - { - if (plevel[ich] < level) - { - break; - } - else if (plevel[ich] > level) - { - ich += reorderLevel(level + 1, pszText + ich, plevel + ich, - cch - ich, fReverse) - 1; - } - } - if (fReverse) - { - reverse(pszText, ich); - } - return ich; -} - -static int reorder(int baselevel, LPWSTR pszText, const WORD* plevel, int cch) -{ - int ich = 0; - - while (ich < cch) - { - ich += reorderLevel(baselevel, pszText + ich, plevel + ich, - cch - ich, FALSE); - } - return ich; -} - /* DISPLAY OPTIONS */ /*----------------------------------------------------------------------- Function: mirror @@ -418,7 +344,7 @@ static int reorder(int baselevel, LPWSTR pszText, const WORD* plevel, int cch) A full implementation would need to substitute mirrored glyphs even for characters that are not paired (e.g. integral sign). -----------------------------------------------------------------------*/ -static void mirror(LPWSTR pszInput, const WORD* plevel, int cch) +static void mirror(LPWSTR pszInput, const BYTE* plevel, int cch) { static int warn_once; int i; @@ -448,9 +374,18 @@ static void mirror(LPWSTR pszInput, const WORD* plevel, int cch) ------------------------------------------------------------------------*/ static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, WORD * pclsLine, - WORD * plevelLine, int cchPara, int fMirror, BOOL * pbrk) + BYTE * plevelLine, int cchPara, int fMirror, BOOL * pbrk) { int cchLine = 0; + int done = 0; + int *run; + + run = HeapAlloc(GetProcessHeap(), 0, cchPara * sizeof(int)); + if (!run) + { + WARN("Out of memory\n"); + return; + } do { @@ -462,11 +397,14 @@ static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, WORD * if (pszOutLine) { + int i; if (fMirror) mirror(pszOutLine, plevelLine, cchLine); /* reorder each line in place */ - reorder(baselevel, pszOutLine, plevelLine, cchLine); + ScriptLayout(cchLine, plevelLine, run, NULL); + for (i = 0; i < cchLine; i++) + pszOutLine[done+run[i]] = pszLine[i]; } pszLine += cchLine; @@ -474,8 +412,11 @@ static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, WORD * pbrk += pbrk ? cchLine : 0; pclsLine += cchLine; cchPara -= cchLine; + done += cchLine; } while (cchPara); + + HeapFree(GetProcessHeap(), 0, run); } /************************************************************* @@ -492,7 +433,7 @@ BOOL BIDI_Reorder( ) { WORD *chartype; - WORD *levels; + BYTE *levels; unsigned i, done; int maxItems; @@ -556,7 +497,7 @@ BOOL BIDI_Reorder( } } - levels = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD)); + levels = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(BYTE)); if (!levels) { WARN("Out of memory\n"); diff --git a/dlls/usp10/bidi.c b/dlls/usp10/bidi.c index 83fe8551eb6..2763453276c 100644 --- a/dlls/usp10/bidi.c +++ b/dlls/usp10/bidi.c @@ -827,3 +827,98 @@ BOOL BIDI_DetermineLevels( HeapFree(GetProcessHeap(), 0, chartype); return TRUE; } + +/* reverse cch indexes */ +static void reverse(int *pidx, int cch) +{ + int temp; + int ich = 0; + for (; ich < --cch; ich++) + { + temp = pidx[ich]; + pidx[ich] = pidx[cch]; + pidx[cch] = temp; + } +} + + +/*------------------------------------------------------------------------ + Functions: reorder/reorderLevel + + Recursively reorders the display string + "From the highest level down, reverse all characters at that level and + higher, down to the lowest odd level" + + Implements rule L2 of the Unicode bidi Algorithm. + + Input: Array of embedding levels + Character count + Flag enabling reversal (set to false by initial caller) + + In/Out: Text to reorder + + Note: levels may exceed 15 resp. 61 on input. + + Rule L3 - reorder combining marks is not implemented here + Rule L4 - glyph mirroring is implemented as a display option below + + Note: this should be applied a line at a time +-------------------------------------------------------------------------*/ +int BIDI_ReorderV2lLevel(int level, int *pIndexs, const BYTE* plevel, int cch, BOOL fReverse) +{ + int ich = 0; + + /* true as soon as first odd level encountered */ + fReverse = fReverse || odd(level); + + for (; ich < cch; ich++) + { + if (plevel[ich] < level) + { + break; + } + else if (plevel[ich] > level) + { + ich += BIDI_ReorderV2lLevel(level + 1, pIndexs + ich, plevel + ich, + cch - ich, fReverse) - 1; + } + } + if (fReverse) + { + reverse(pIndexs, ich); + } + return ich; +} + +/* Applies the reorder in reverse. Taking an already reordered string and returing the original */ +int BIDI_ReorderL2vLevel(int level, int *pIndexs, const BYTE* plevel, int cch, BOOL fReverse) +{ + int ich = 0; + int newlevel = -1; + + /* true as soon as first odd level encountered */ + fReverse = fReverse || odd(level); + + for (; ich < cch; ich++) + { + if (plevel[ich] < level) + break; + else if (plevel[ich] > level) + newlevel = ich; + } + if (fReverse) + { + reverse(pIndexs, ich); + } + + if (newlevel > 1) + { + ich = 0; + for (; ich < cch; ich++) + if (plevel[ich] > level) + ich += BIDI_ReorderL2vLevel(level + 1, pIndexs + ich, plevel + ich, + cch - ich, fReverse) - 1; + } + + return ich; +} diff --git a/dlls/usp10/tests/usp10.c b/dlls/usp10/tests/usp10.c index 83bab3b18cd..1a9301bcaa0 100644 --- a/dlls/usp10/tests/usp10.c +++ b/dlls/usp10/tests/usp10.c @@ -1379,20 +1379,55 @@ static void test_ScriptGetGlyphABCWidth(HDC hdc) static void test_ScriptLayout(void) { HRESULT hr; - static const BYTE levels[][5] = + static const BYTE levels[][10] = { - { 0, 0, 0, 0, 0 }, - { 1, 1, 1, 1, 1 }, - { 2, 2, 2, 2, 2 }, - { 3, 3, 3, 3, 3 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + + { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, + { 1, 1, 1, 2, 2, 2, 1, 1, 1, 1 }, + { 2, 2, 2, 1, 1, 1, 2, 2, 2, 2 }, + { 0, 0, 1, 1, 2, 2, 1, 1, 0, 0 }, + { 1, 1, 2, 2, 3, 3, 2, 2, 1, 1 }, + + { 0, 0, 1, 1, 2, 2, 1, 1, 0, 1 }, + { 1, 0, 1, 2, 2, 1, 2, 1, 0, 1 }, }; - static const int expect[][5] = + static const int expect_l2v[][10] = { - { 0, 1, 2, 3, 4 }, - { 4, 3, 2, 1, 0 }, - { 0, 1, 2, 3, 4 }, - { 4, 3, 2, 1, 0 } + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, + + { 0, 1, 2, 3, 4, 9, 8 ,7 ,6, 5}, +/**/ { 9, 8, 7, 4, 5, 6, 3 ,2 ,1, 0}, +/**/ { 7, 8, 9, 6, 5, 4, 0 ,1 ,2, 3}, + { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9}, + { 9, 8, 2, 3, 5, 4, 6 ,7 ,1, 0}, + + { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9}, +/**/ { 0, 1, 7, 5, 6, 4, 3 ,2 ,8, 9}, }; + static const int expect_v2l[][10] = + { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, + + { 0, 1, 2, 3, 4, 9, 8 ,7 ,6, 5}, + { 9, 8, 7, 6, 3, 4, 5 ,2 ,1, 0}, + { 6, 7, 8, 9, 5, 4, 3 ,0 ,1, 2}, + { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9}, + { 9, 8, 2, 3, 5, 4, 6 ,7 ,1, 0}, + + { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9}, + { 0, 1, 7, 6, 5, 3, 4 ,2 ,8, 9}, + }; + int i, j, vistolog[sizeof(levels[0])], logtovis[sizeof(levels[0])]; hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis); @@ -1408,14 +1443,14 @@ static void test_ScriptLayout(void) for (j = 0; j < sizeof(levels[i]); j++) { - ok(expect[i][j] == vistolog[j], + ok(expect_v2l[i][j] == vistolog[j], "failure: levels[%d][%d] = %d, vistolog[%d] = %d\n", i, j, levels[i][j], j, vistolog[j] ); } for (j = 0; j < sizeof(levels[i]); j++) { - ok(expect[i][j] == logtovis[j], + ok(expect_l2v[i][j] == logtovis[j], "failure: levels[%d][%d] = %d, logtovis[%d] = %d\n", i, j, levels[i][j], j, logtovis[j] ); } diff --git a/dlls/usp10/usp10.c b/dlls/usp10/usp10.c index c42a122ae75..4f8a08be29e 100644 --- a/dlls/usp10/usp10.c +++ b/dlls/usp10/usp10.c @@ -1619,28 +1619,45 @@ HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, AB */ HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis) { - int i, j = runs - 1, k = 0; + int* indexs; + int ich; TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis); if (!level || (!vistolog && !logtovis)) return E_INVALIDARG; - for (i = 0; i < runs; i++) + indexs = heap_alloc(sizeof(int) * runs); + if (!indexs) + return E_OUTOFMEMORY; + + + if (vistolog) { - if (level[i] % 2) - { - if (vistolog) *vistolog++ = j; - if (logtovis) *logtovis++ = j; - j--; - } - else - { - if (vistolog) *vistolog++ = k; - if (logtovis) *logtovis++ = k; - k++; - } + for( ich = 0; ich < runs; ich++) + indexs[ich] = ich; + + ich = 0; + while (ich < runs) + ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE); + for (ich = 0; ich < runs; ich++) + vistolog[ich] = indexs[ich]; + } + + + if (logtovis) + { + for( ich = 0; ich < runs; ich++) + indexs[ich] = ich; + + ich = 0; + while (ich < runs) + ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE); + for (ich = 0; ich < runs; ich++) + logtovis[ich] = indexs[ich]; } + heap_free(indexs); + return S_OK; } diff --git a/dlls/usp10/usp10_internal.h b/dlls/usp10/usp10_internal.h index 6661605ff44..60e4eff14ab 100644 --- a/dlls/usp10/usp10_internal.h +++ b/dlls/usp10/usp10_internal.h @@ -23,3 +23,6 @@ BOOL BIDI_DetermineLevels( LPCWSTR lpString, INT uCount, const SCRIPT_STATE *s, const SCRIPT_CONTROL *c, WORD *lpOutLevels ); + +INT BIDI_ReorderV2lLevel(int level, int *pIndexs, const BYTE* plevel, int cch, BOOL fReverse); +INT BIDI_ReorderL2vLevel(int level, int *pIndexs, const BYTE* plevel, int cch, BOOL fReverse); -- 2.11.4.GIT