ups10: Reimplement ScriptLayout to properly handle mixed runs.

This commit is contained in:
Aric Stewart 2010-04-13 14:49:20 -05:00 committed by Alexandre Julliard
parent 6c3659c3d4
commit b9c30445c7
5 changed files with 199 additions and 108 deletions

View File

@ -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");

View File

@ -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;
}

View File

@ -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] );
}

View File

@ -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;
}

View File

@ -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);