gdi: Implement line-by-line phase of the BiDi algorithm.
This commit is contained in:
parent
588c5a90fd
commit
b6f9a30a5d
|
@ -814,6 +814,231 @@ static void resolveImplicit(const WORD * pcls, WORD *plevel, int cch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* REORDER */
|
||||||
|
/*------------------------------------------------------------------------
|
||||||
|
Function: resolveLines
|
||||||
|
|
||||||
|
Breaks a paragraph into lines
|
||||||
|
|
||||||
|
Input: Character count
|
||||||
|
In/Out: Array of characters
|
||||||
|
Array of line break flags
|
||||||
|
|
||||||
|
Returns the count of characters on the first line
|
||||||
|
|
||||||
|
Note: This function only breaks lines at hard line breaks. Other
|
||||||
|
line breaks can be passed in. If pbrk[n] is TRUE, then a break
|
||||||
|
occurs after the character in pszInput[n]. Breaks before the first
|
||||||
|
character are not allowed.
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
static int resolveLines(WCHAR * pszInput, BOOL * pbrk, int cch)
|
||||||
|
{
|
||||||
|
/* skip characters not of type LS */
|
||||||
|
int ich = 0;
|
||||||
|
for(; ich < cch; ich++)
|
||||||
|
{
|
||||||
|
if (pszInput[ich] == (WCHAR)'\n' || (pbrk && pbrk[ich]))
|
||||||
|
{
|
||||||
|
ich++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ich;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------
|
||||||
|
Function: resolveWhiteSpace
|
||||||
|
|
||||||
|
Resolves levels for WS and S
|
||||||
|
Implements rule L1 of the Unicode bidi Algorithm.
|
||||||
|
|
||||||
|
Input: Base embedding level
|
||||||
|
Character count
|
||||||
|
Array of direction classes (for one line of text)
|
||||||
|
|
||||||
|
In/Out: Array of embedding levels (for one line of text)
|
||||||
|
|
||||||
|
Note: this should be applied a line at a time. The default driver
|
||||||
|
code supplied in this file assumes a single line of text; for
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int cchrun = 0;
|
||||||
|
int oldlevel = baselevel;
|
||||||
|
|
||||||
|
int ich = 0;
|
||||||
|
for (; ich < cch; ich++)
|
||||||
|
{
|
||||||
|
switch(pcls[ich])
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
cchrun = 0; /* any other character breaks the run */
|
||||||
|
break;
|
||||||
|
case WS:
|
||||||
|
cchrun++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RLE:
|
||||||
|
case LRE:
|
||||||
|
case LRO:
|
||||||
|
case RLO:
|
||||||
|
case PDF:
|
||||||
|
case BN:
|
||||||
|
plevel[ich] = oldlevel;
|
||||||
|
cchrun++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S:
|
||||||
|
case B:
|
||||||
|
/* reset levels for WS before eot */
|
||||||
|
SetDeferredRun(plevel, cchrun, ich, baselevel);
|
||||||
|
cchrun = 0;
|
||||||
|
plevel[ich] = baselevel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
oldlevel = plevel[ich];
|
||||||
|
}
|
||||||
|
/* reset level before eot */
|
||||||
|
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
|
||||||
|
|
||||||
|
Crudely implements rule L4 of the Unicode Bidirectional Algorithm
|
||||||
|
Demonstrate mirrored brackets, braces and parens
|
||||||
|
|
||||||
|
|
||||||
|
Input: Array of levels
|
||||||
|
Count of characters
|
||||||
|
|
||||||
|
In/Out: Array of characters (should be array of glyph ids)
|
||||||
|
|
||||||
|
Note;
|
||||||
|
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 int warn_once;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cch; ++i)
|
||||||
|
{
|
||||||
|
if (!odd(plevel[i]))
|
||||||
|
continue;
|
||||||
|
/* This needs the data from http://www.unicode.org/Public/UNIDATA/BidiMirroring.txt */
|
||||||
|
if (!warn_once++)
|
||||||
|
FIXME("stub: mirroring of characters not yet implemented\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------
|
||||||
|
Function: BidiLines
|
||||||
|
|
||||||
|
Implements the Line-by-Line phases of the Unicode Bidi Algorithm
|
||||||
|
|
||||||
|
Input: Count of characters
|
||||||
|
flag whether to mirror
|
||||||
|
|
||||||
|
Inp/Out: Input text
|
||||||
|
Array of character directions
|
||||||
|
Array of levels
|
||||||
|
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
static void BidiLines(int baselevel, WCHAR * pszLine, WORD * pclsLine, WORD * plevelLine, int cchPara, int fMirror, BOOL * pbrk)
|
||||||
|
{
|
||||||
|
int cchLine = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* break lines at LS */
|
||||||
|
cchLine = resolveLines(pszLine, pbrk, cchPara);
|
||||||
|
|
||||||
|
/* resolve whitespace */
|
||||||
|
resolveWhitespace(baselevel, pclsLine, plevelLine, cchLine);
|
||||||
|
|
||||||
|
if (fMirror)
|
||||||
|
mirror(pszLine, plevelLine, cchLine);
|
||||||
|
|
||||||
|
/* reorder each line in place */
|
||||||
|
reorder(baselevel, pszLine, plevelLine, cchLine);
|
||||||
|
|
||||||
|
pszLine += cchLine;
|
||||||
|
plevelLine += cchLine;
|
||||||
|
pbrk += pbrk ? cchLine : 0;
|
||||||
|
pclsLine += cchLine;
|
||||||
|
cchPara -= cchLine;
|
||||||
|
|
||||||
|
} while (cchPara);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* BIDI_Reorder
|
* BIDI_Reorder
|
||||||
*/
|
*/
|
||||||
|
@ -915,14 +1140,10 @@ BOOL BIDI_Reorder(
|
||||||
/* resolveImplicit */
|
/* resolveImplicit */
|
||||||
resolveImplicit(chartype, levels, i);
|
resolveImplicit(chartype, levels, i);
|
||||||
|
|
||||||
/* Temporary stub: Just reverse the odd levels */
|
/* assign directional types again, but for WS, S this time */
|
||||||
for (j = lastgood = 0; j < i; ++j)
|
classify(lpOutString + done, chartype, i);
|
||||||
if (levels[j] != levels[lastgood])
|
|
||||||
{
|
BidiLines(baselevel, lpOutString + done, chartype, levels, i, !(dwFlags & GCP_SYMSWAPOFF), 0);
|
||||||
if (odd(levels[lastgood]))
|
|
||||||
reverse(lpOutString + done + lastgood, j - 1);
|
|
||||||
lastgood = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lpOrder)
|
if (lpOrder)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue