Commit b9c30445 authored by Aric Stewart's avatar Aric Stewart Committed by Alexandre Julliard

ups10: Reimplement ScriptLayout to properly handle mixed runs.

parent 6c3659c3
...@@ -192,22 +192,9 @@ static void classify(LPCWSTR lpString, WORD *chartype, DWORD uCount) ...@@ -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 */ /* Set a run of cval values at locations all prior to, but not including */
/* iStart, to the new value nval. */ /* 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; int i = iStart - 1;
for (; i >= iStart - cval; i--) for (; i >= iStart - cval; i--)
...@@ -299,10 +286,10 @@ static int resolveLines(LPCWSTR pszInput, BOOL * pbrk, int cch) ...@@ -299,10 +286,10 @@ static int resolveLines(LPCWSTR pszInput, BOOL * pbrk, int cch)
a real implementation, cch and the initial pointer values a real implementation, cch and the initial pointer values
would have to be adjusted. 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 cchrun = 0;
int oldlevel = baselevel; BYTE oldlevel = baselevel;
int ich = 0; int ich = 0;
for (; ich < cch; ich++) for (; ich < cch; ich++)
...@@ -340,67 +327,6 @@ static void resolveWhitespace(int baselevel, const WORD *pcls, WORD *plevel, int ...@@ -340,67 +327,6 @@ static void resolveWhitespace(int baselevel, const WORD *pcls, WORD *plevel, int
SetDeferredRun(plevel, cchrun, ich, baselevel); 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 */ /* DISPLAY OPTIONS */
/*----------------------------------------------------------------------- /*-----------------------------------------------------------------------
Function: mirror Function: mirror
...@@ -418,7 +344,7 @@ static int reorder(int baselevel, LPWSTR pszText, const WORD* plevel, int cch) ...@@ -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 A full implementation would need to substitute mirrored glyphs even
for characters that are not paired (e.g. integral sign). 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; static int warn_once;
int i; int i;
...@@ -448,9 +374,18 @@ static void mirror(LPWSTR pszInput, const WORD* plevel, int cch) ...@@ -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, 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 cchLine = 0;
int done = 0;
int *run;
run = HeapAlloc(GetProcessHeap(), 0, cchPara * sizeof(int));
if (!run)
{
WARN("Out of memory\n");
return;
}
do do
{ {
...@@ -462,11 +397,14 @@ static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, WORD * ...@@ -462,11 +397,14 @@ static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, WORD *
if (pszOutLine) if (pszOutLine)
{ {
int i;
if (fMirror) if (fMirror)
mirror(pszOutLine, plevelLine, cchLine); mirror(pszOutLine, plevelLine, cchLine);
/* reorder each line in place */ /* 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; pszLine += cchLine;
...@@ -474,8 +412,11 @@ static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, WORD * ...@@ -474,8 +412,11 @@ static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, WORD *
pbrk += pbrk ? cchLine : 0; pbrk += pbrk ? cchLine : 0;
pclsLine += cchLine; pclsLine += cchLine;
cchPara -= cchLine; cchPara -= cchLine;
done += cchLine;
} while (cchPara); } while (cchPara);
HeapFree(GetProcessHeap(), 0, run);
} }
/************************************************************* /*************************************************************
...@@ -492,7 +433,7 @@ BOOL BIDI_Reorder( ...@@ -492,7 +433,7 @@ BOOL BIDI_Reorder(
) )
{ {
WORD *chartype; WORD *chartype;
WORD *levels; BYTE *levels;
unsigned i, done; unsigned i, done;
int maxItems; int maxItems;
...@@ -556,7 +497,7 @@ BOOL BIDI_Reorder( ...@@ -556,7 +497,7 @@ BOOL BIDI_Reorder(
} }
} }
levels = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD)); levels = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(BYTE));
if (!levels) if (!levels)
{ {
WARN("Out of memory\n"); WARN("Out of memory\n");
......
...@@ -827,3 +827,98 @@ BOOL BIDI_DetermineLevels( ...@@ -827,3 +827,98 @@ BOOL BIDI_DetermineLevels(
HeapFree(GetProcessHeap(), 0, chartype); HeapFree(GetProcessHeap(), 0, chartype);
return TRUE; 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;
}
...@@ -1379,20 +1379,55 @@ static void test_ScriptGetGlyphABCWidth(HDC hdc) ...@@ -1379,20 +1379,55 @@ static void test_ScriptGetGlyphABCWidth(HDC hdc)
static void test_ScriptLayout(void) static void test_ScriptLayout(void)
{ {
HRESULT hr; HRESULT hr;
static const BYTE levels[][5] = static const BYTE levels[][10] =
{ {
{ 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 2, 2, 2, 2, 2 }, { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
{ 3, 3, 3, 3, 3 }, { 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 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 4, 3, 2, 1, 0 }, { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
{ 0, 1, 2, 3, 4 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 4, 3, 2, 1, 0 } { 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])]; int i, j, vistolog[sizeof(levels[0])], logtovis[sizeof(levels[0])];
hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis); hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis);
...@@ -1408,14 +1443,14 @@ static void test_ScriptLayout(void) ...@@ -1408,14 +1443,14 @@ static void test_ScriptLayout(void)
for (j = 0; j < sizeof(levels[i]); j++) 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", "failure: levels[%d][%d] = %d, vistolog[%d] = %d\n",
i, j, levels[i][j], j, vistolog[j] ); i, j, levels[i][j], j, vistolog[j] );
} }
for (j = 0; j < sizeof(levels[i]); 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", "failure: levels[%d][%d] = %d, logtovis[%d] = %d\n",
i, j, levels[i][j], j, logtovis[j] ); i, j, levels[i][j], j, logtovis[j] );
} }
......
...@@ -1619,28 +1619,45 @@ HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, AB ...@@ -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) 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); TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
if (!level || (!vistolog && !logtovis)) if (!level || (!vistolog && !logtovis))
return E_INVALIDARG; 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) for( ich = 0; ich < runs; ich++)
{ indexs[ich] = ich;
if (vistolog) *vistolog++ = j;
if (logtovis) *logtovis++ = j; ich = 0;
j--; while (ich < runs)
} ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
else for (ich = 0; ich < runs; ich++)
{ vistolog[ich] = indexs[ich];
if (vistolog) *vistolog++ = k; }
if (logtovis) *logtovis++ = k;
k++;
} 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; return S_OK;
} }
......
...@@ -23,3 +23,6 @@ ...@@ -23,3 +23,6 @@
BOOL BIDI_DetermineLevels( LPCWSTR lpString, INT uCount, const SCRIPT_STATE *s, BOOL BIDI_DetermineLevels( LPCWSTR lpString, INT uCount, const SCRIPT_STATE *s,
const SCRIPT_CONTROL *c, WORD *lpOutLevels ); 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);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment