ups10: Reimplement ScriptLayout to properly handle mixed runs.
This commit is contained in:
parent
6c3659c3d4
commit
b9c30445c7
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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] );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue