usp10: Improve ScriptItemize with a SCRIPT_CONTROL and SCRIPT_STATE set.
Reduce bidi duplications from gdi32 by using the newly corrected usp10 functions.
This commit is contained in:
parent
50aa0215a7
commit
6c3659c3d4
|
@ -8,6 +8,7 @@ IMPORTLIB = gdi32
|
|||
IMPORTS = advapi32 kernel32 ntdll
|
||||
EXTRAINCL = @FREETYPEINCL@ @FONTCONFIGINCL@
|
||||
EXTRALIBS = @CARBONLIB@
|
||||
DELAYIMPORTS = usp10
|
||||
|
||||
C_SRCS = \
|
||||
bidi.c \
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright 2003 Shachar Shemesh
|
||||
* Copyright 2007 Maarten Lankhorst
|
||||
* Copyright 2010 CodeWeavers, Aric Stewart
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -47,14 +48,12 @@
|
|||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winnls.h"
|
||||
#include "usp10.h"
|
||||
#include "wine/debug.h"
|
||||
#include "gdi_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(bidi);
|
||||
|
||||
#define ASSERT(x) do { if (!(x)) FIXME("assert failed: %s\n", #x); } while(0)
|
||||
#define MAX_LEVEL 61
|
||||
|
||||
/* HELPER FUNCTIONS AND DECLARATIONS */
|
||||
|
||||
#define odd(x) ((x) & 1)
|
||||
|
@ -250,571 +249,6 @@ static int resolveParagraphs(WORD *types, int cch)
|
|||
return ich;
|
||||
}
|
||||
|
||||
/* RESOLVE EXPLICIT */
|
||||
|
||||
static WORD GreaterEven(int i)
|
||||
{
|
||||
return odd(i) ? i + 1 : i + 2;
|
||||
}
|
||||
|
||||
static WORD GreaterOdd(int i)
|
||||
{
|
||||
return odd(i) ? i + 2 : i + 1;
|
||||
}
|
||||
|
||||
static WORD EmbeddingDirection(int level)
|
||||
{
|
||||
return odd(level) ? R : L;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Function: resolveExplicit
|
||||
|
||||
Recursively resolves explicit embedding levels and overrides.
|
||||
Implements rules X1-X9, of the Unicode Bidirectional Algorithm.
|
||||
|
||||
Input: Base embedding level and direction
|
||||
Character count
|
||||
|
||||
Output: Array of embedding levels
|
||||
|
||||
In/Out: Array of direction classes
|
||||
|
||||
|
||||
Note: The function uses two simple counters to keep track of
|
||||
matching explicit codes and PDF. Use the default argument for
|
||||
the outermost call. The nesting counter counts the recursion
|
||||
depth and not the embedding level.
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
static int resolveExplicit(int level, int dir, WORD *pcls, WORD *plevel, int cch, int nNest)
|
||||
{
|
||||
/* always called with a valid nesting level
|
||||
nesting levels are != embedding levels */
|
||||
int nLastValid = nNest;
|
||||
int ich = 0;
|
||||
|
||||
/* check input values */
|
||||
ASSERT(nNest >= 0 && level >= 0 && level <= MAX_LEVEL);
|
||||
|
||||
/* process the text */
|
||||
for (; ich < cch; ich++)
|
||||
{
|
||||
WORD cls = pcls[ich];
|
||||
switch (cls)
|
||||
{
|
||||
case LRO:
|
||||
case LRE:
|
||||
nNest++;
|
||||
if (GreaterEven(level) <= MAX_LEVEL - (cls == LRO ? 2 : 0))
|
||||
{
|
||||
plevel[ich] = GreaterEven(level);
|
||||
pcls[ich] = BN;
|
||||
ich += resolveExplicit(plevel[ich], (cls == LRE ? N : L),
|
||||
&pcls[ich+1], &plevel[ich+1],
|
||||
cch - (ich+1), nNest);
|
||||
nNest--;
|
||||
continue;
|
||||
}
|
||||
cls = pcls[ich] = BN;
|
||||
break;
|
||||
|
||||
case RLO:
|
||||
case RLE:
|
||||
nNest++;
|
||||
if (GreaterOdd(level) <= MAX_LEVEL - (cls == RLO ? 2 : 0))
|
||||
{
|
||||
plevel[ich] = GreaterOdd(level);
|
||||
pcls[ich] = BN;
|
||||
ich += resolveExplicit(plevel[ich], (cls == RLE ? N : R),
|
||||
&pcls[ich+1], &plevel[ich+1],
|
||||
cch - (ich+1), nNest);
|
||||
nNest--;
|
||||
continue;
|
||||
}
|
||||
cls = pcls[ich] = BN;
|
||||
break;
|
||||
|
||||
case PDF:
|
||||
cls = pcls[ich] = BN;
|
||||
if (nNest)
|
||||
{
|
||||
if (nLastValid < nNest)
|
||||
{
|
||||
nNest--;
|
||||
}
|
||||
else
|
||||
{
|
||||
cch = ich; /* break the loop, but complete body */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply the override */
|
||||
if (dir != N)
|
||||
{
|
||||
cls = dir;
|
||||
}
|
||||
plevel[ich] = level;
|
||||
if (pcls[ich] != BN)
|
||||
pcls[ich] = cls;
|
||||
}
|
||||
|
||||
return ich;
|
||||
}
|
||||
|
||||
/* RESOLVE WEAK TYPES */
|
||||
|
||||
enum states /* possible states */
|
||||
{
|
||||
xa, /* arabic letter */
|
||||
xr, /* right letter */
|
||||
xl, /* left letter */
|
||||
|
||||
ao, /* arabic lett. foll by ON */
|
||||
ro, /* right lett. foll by ON */
|
||||
lo, /* left lett. foll by ON */
|
||||
|
||||
rt, /* ET following R */
|
||||
lt, /* ET following L */
|
||||
|
||||
cn, /* EN, AN following AL */
|
||||
ra, /* arabic number foll R */
|
||||
re, /* european number foll R */
|
||||
la, /* arabic number foll L */
|
||||
le, /* european number foll L */
|
||||
|
||||
ac, /* CS following cn */
|
||||
rc, /* CS following ra */
|
||||
rs, /* CS,ES following re */
|
||||
lc, /* CS following la */
|
||||
ls, /* CS,ES following le */
|
||||
|
||||
ret, /* ET following re */
|
||||
let, /* ET following le */
|
||||
} ;
|
||||
|
||||
static const int stateWeak[][10] =
|
||||
{
|
||||
/* N, L, R, AN, EN, AL,NSM, CS, ES, ET */
|
||||
/*xa*/ { ao, xl, xr, cn, cn, xa, xa, ao, ao, ao }, /* arabic letter */
|
||||
/*xr*/ { ro, xl, xr, ra, re, xa, xr, ro, ro, rt }, /* right letter */
|
||||
/*xl*/ { lo, xl, xr, la, le, xa, xl, lo, lo, lt }, /* left letter */
|
||||
|
||||
/*ao*/ { ao, xl, xr, cn, cn, xa, ao, ao, ao, ao }, /* arabic lett. foll by ON*/
|
||||
/*ro*/ { ro, xl, xr, ra, re, xa, ro, ro, ro, rt }, /* right lett. foll by ON */
|
||||
/*lo*/ { lo, xl, xr, la, le, xa, lo, lo, lo, lt }, /* left lett. foll by ON */
|
||||
|
||||
/*rt*/ { ro, xl, xr, ra, re, xa, rt, ro, ro, rt }, /* ET following R */
|
||||
/*lt*/ { lo, xl, xr, la, le, xa, lt, lo, lo, lt }, /* ET following L */
|
||||
|
||||
/*cn*/ { ao, xl, xr, cn, cn, xa, cn, ac, ao, ao }, /* EN, AN following AL */
|
||||
/*ra*/ { ro, xl, xr, ra, re, xa, ra, rc, ro, rt }, /* arabic number foll R */
|
||||
/*re*/ { ro, xl, xr, ra, re, xa, re, rs, rs,ret }, /* european number foll R */
|
||||
/*la*/ { lo, xl, xr, la, le, xa, la, lc, lo, lt }, /* arabic number foll L */
|
||||
/*le*/ { lo, xl, xr, la, le, xa, le, ls, ls,let }, /* european number foll L */
|
||||
|
||||
/*ac*/ { ao, xl, xr, cn, cn, xa, ao, ao, ao, ao }, /* CS following cn */
|
||||
/*rc*/ { ro, xl, xr, ra, re, xa, ro, ro, ro, rt }, /* CS following ra */
|
||||
/*rs*/ { ro, xl, xr, ra, re, xa, ro, ro, ro, rt }, /* CS,ES following re */
|
||||
/*lc*/ { lo, xl, xr, la, le, xa, lo, lo, lo, lt }, /* CS following la */
|
||||
/*ls*/ { lo, xl, xr, la, le, xa, lo, lo, lo, lt }, /* CS,ES following le */
|
||||
|
||||
/*ret*/{ ro, xl, xr, ra, re, xa,ret, ro, ro,ret }, /* ET following re */
|
||||
/*let*/{ lo, xl, xr, la, le, xa,let, lo, lo,let }, /* ET following le */
|
||||
};
|
||||
|
||||
enum actions /* possible actions */
|
||||
{
|
||||
/* primitives */
|
||||
IX = 0x100, /* increment */
|
||||
XX = 0xF, /* no-op */
|
||||
|
||||
/* actions */
|
||||
xxx = (XX << 4) + XX, /* no-op */
|
||||
xIx = IX + xxx, /* increment run */
|
||||
xxN = (XX << 4) + ON, /* set current to N */
|
||||
xxE = (XX << 4) + EN, /* set current to EN */
|
||||
xxA = (XX << 4) + AN, /* set current to AN */
|
||||
xxR = (XX << 4) + R, /* set current to R */
|
||||
xxL = (XX << 4) + L, /* set current to L */
|
||||
Nxx = (ON << 4) + 0xF, /* set run to neutral */
|
||||
Axx = (AN << 4) + 0xF, /* set run to AN */
|
||||
ExE = (EN << 4) + EN, /* set run to EN, set current to EN */
|
||||
NIx = (ON << 4) + 0xF + IX, /* set run to N, increment */
|
||||
NxN = (ON << 4) + ON, /* set run to N, set current to N */
|
||||
NxR = (ON << 4) + R, /* set run to N, set current to R */
|
||||
NxE = (ON << 4) + EN, /* set run to N, set current to EN */
|
||||
|
||||
AxA = (AN << 4) + AN, /* set run to AN, set current to AN */
|
||||
NxL = (ON << 4) + L, /* set run to N, set current to L */
|
||||
LxL = (L << 4) + L, /* set run to L, set current to L */
|
||||
} ;
|
||||
|
||||
static const int actionWeak[][10] =
|
||||
{
|
||||
/* N, L, R, AN, EN, AL, NSM, CS, ES, ET */
|
||||
/*xa*/ { xxx, xxx, xxx, xxx, xxA, xxR, xxR, xxN, xxN, xxN }, /* arabic letter */
|
||||
/*xr*/ { xxx, xxx, xxx, xxx, xxE, xxR, xxR, xxN, xxN, xIx }, /* right letter */
|
||||
/*xl*/ { xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xIx }, /* left letter */
|
||||
|
||||
/*ao*/ { xxx, xxx, xxx, xxx, xxA, xxR, xxN, xxN, xxN, xxN }, /* arabic lett. foll by ON */
|
||||
/*ro*/ { xxx, xxx, xxx, xxx, xxE, xxR, xxN, xxN, xxN, xIx }, /* right lett. foll by ON */
|
||||
/*lo*/ { xxx, xxx, xxx, xxx, xxL, xxR, xxN, xxN, xxN, xIx }, /* left lett. foll by ON */
|
||||
|
||||
/*rt*/ { Nxx, Nxx, Nxx, Nxx, ExE, NxR, xIx, NxN, NxN, xIx }, /* ET following R */
|
||||
/*lt*/ { Nxx, Nxx, Nxx, Nxx, LxL, NxR, xIx, NxN, NxN, xIx }, /* ET following L */
|
||||
|
||||
/*cn*/ { xxx, xxx, xxx, xxx, xxA, xxR, xxA, xIx, xxN, xxN }, /* EN, AN following AL */
|
||||
/*ra*/ { xxx, xxx, xxx, xxx, xxE, xxR, xxA, xIx, xxN, xIx }, /* arabic number foll R */
|
||||
/*re*/ { xxx, xxx, xxx, xxx, xxE, xxR, xxE, xIx, xIx, xxE }, /* european number foll R */
|
||||
/*la*/ { xxx, xxx, xxx, xxx, xxL, xxR, xxA, xIx, xxN, xIx }, /* arabic number foll L */
|
||||
/*le*/ { xxx, xxx, xxx, xxx, xxL, xxR, xxL, xIx, xIx, xxL }, /* european number foll L */
|
||||
|
||||
/*ac*/ { Nxx, Nxx, Nxx, Axx, AxA, NxR, NxN, NxN, NxN, NxN }, /* CS following cn */
|
||||
/*rc*/ { Nxx, Nxx, Nxx, Axx, NxE, NxR, NxN, NxN, NxN, NIx }, /* CS following ra */
|
||||
/*rs*/ { Nxx, Nxx, Nxx, Nxx, ExE, NxR, NxN, NxN, NxN, NIx }, /* CS,ES following re */
|
||||
/*lc*/ { Nxx, Nxx, Nxx, Axx, NxL, NxR, NxN, NxN, NxN, NIx }, /* CS following la */
|
||||
/*ls*/ { Nxx, Nxx, Nxx, Nxx, LxL, NxR, NxN, NxN, NxN, NIx }, /* CS,ES following le */
|
||||
|
||||
/*ret*/{ xxx, xxx, xxx, xxx, xxE, xxR, xxE, xxN, xxN, xxE }, /* ET following re */
|
||||
/*let*/{ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xxL }, /* ET following le */
|
||||
};
|
||||
|
||||
static int GetDeferredType(int action)
|
||||
{
|
||||
return (action >> 4) & 0xF;
|
||||
}
|
||||
|
||||
static int GetResolvedType(int action)
|
||||
{
|
||||
return action & 0xF;
|
||||
}
|
||||
|
||||
/* Note on action table:
|
||||
|
||||
States can be of two kinds:
|
||||
- Immediate Resolution State, where each input token
|
||||
is resolved as soon as it is seen. These states have
|
||||
only single action codes (xxN) or the no-op (xxx)
|
||||
for static input tokens.
|
||||
- Deferred Resolution State, where input tokens either
|
||||
either extend the run (xIx) or resolve its Type (e.g. Nxx).
|
||||
|
||||
Input classes are of three kinds
|
||||
- Static Input Token, where the class of the token remains
|
||||
unchanged on output (AN, L, N, R)
|
||||
- Replaced Input Token, where the class of the token is
|
||||
always replaced on output (AL, BN, NSM, CS, ES, ET)
|
||||
- Conditional Input Token, where the class of the token is
|
||||
changed on output in some, but not all, cases (EN)
|
||||
|
||||
Where tokens are subject to change, a double action
|
||||
(e.g. NxA, or NxN) is _required_ after deferred states,
|
||||
resolving both the deferred state and changing the current token.
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Function: resolveWeak
|
||||
|
||||
Resolves the directionality of numeric and other weak character types
|
||||
|
||||
Implements rules X10 and W1-W6 of the Unicode Bidirectional Algorithm.
|
||||
|
||||
Input: Array of embedding levels
|
||||
Character count
|
||||
|
||||
In/Out: Array of directional classes
|
||||
|
||||
Note: On input only these directional classes are expected
|
||||
AL, HL, R, L, ON, BN, NSM, AN, EN, ES, ET, CS,
|
||||
------------------------------------------------------------------------*/
|
||||
static void resolveWeak(int baselevel, WORD *pcls, WORD *plevel, int cch)
|
||||
{
|
||||
int state = odd(baselevel) ? xr : xl;
|
||||
int cls;
|
||||
|
||||
int level = baselevel;
|
||||
int action, clsRun, clsNew;
|
||||
int cchRun = 0;
|
||||
int ich = 0;
|
||||
|
||||
for (; ich < cch; ich++)
|
||||
{
|
||||
/* ignore boundary neutrals */
|
||||
if (pcls[ich] == BN)
|
||||
{
|
||||
/* must flatten levels unless at a level change; */
|
||||
plevel[ich] = level;
|
||||
|
||||
/* lookahead for level changes */
|
||||
if (ich + 1 == cch && level != baselevel)
|
||||
{
|
||||
/* have to fixup last BN before end of the loop, since
|
||||
* its fix-upped value will be needed below the assert */
|
||||
pcls[ich] = EmbeddingDirection(level);
|
||||
}
|
||||
else if (ich + 1 < cch && level != plevel[ich+1] && pcls[ich+1] != BN)
|
||||
{
|
||||
/* fixup LAST BN in front / after a level run to make
|
||||
* it act like the SOR/EOR in rule X10 */
|
||||
int newlevel = plevel[ich+1];
|
||||
if (level > newlevel) {
|
||||
newlevel = level;
|
||||
}
|
||||
plevel[ich] = newlevel;
|
||||
|
||||
/* must match assigned level */
|
||||
pcls[ich] = EmbeddingDirection(newlevel);
|
||||
level = plevel[ich+1];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* don't interrupt runs */
|
||||
if (cchRun)
|
||||
{
|
||||
cchRun++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(pcls[ich] <= BN);
|
||||
cls = pcls[ich];
|
||||
|
||||
action = actionWeak[state][cls];
|
||||
|
||||
/* resolve the directionality for deferred runs */
|
||||
clsRun = GetDeferredType(action);
|
||||
if (clsRun != XX)
|
||||
{
|
||||
SetDeferredRun(pcls, cchRun, ich, clsRun);
|
||||
cchRun = 0;
|
||||
}
|
||||
|
||||
/* resolve the directionality class at the current location */
|
||||
clsNew = GetResolvedType(action);
|
||||
if (clsNew != XX)
|
||||
pcls[ich] = clsNew;
|
||||
|
||||
/* increment a deferred run */
|
||||
if (IX & action)
|
||||
cchRun++;
|
||||
|
||||
state = stateWeak[state][cls];
|
||||
}
|
||||
|
||||
/* resolve any deferred runs
|
||||
* use the direction of the current level to emulate PDF */
|
||||
cls = EmbeddingDirection(level);
|
||||
|
||||
/* resolve the directionality for deferred runs */
|
||||
clsRun = GetDeferredType(actionWeak[state][cls]);
|
||||
if (clsRun != XX)
|
||||
SetDeferredRun(pcls, cchRun, ich, clsRun);
|
||||
}
|
||||
|
||||
/* RESOLVE NEUTRAL TYPES */
|
||||
|
||||
/* action values */
|
||||
enum neutralactions
|
||||
{
|
||||
/* action to resolve previous input */
|
||||
nL = L, /* resolve EN to L */
|
||||
En = 3 << 4, /* resolve neutrals run to embedding level direction */
|
||||
Rn = R << 4, /* resolve neutrals run to strong right */
|
||||
Ln = L << 4, /* resolved neutrals run to strong left */
|
||||
In = (1<<8), /* increment count of deferred neutrals */
|
||||
LnL = (1<<4)+L, /* set run and EN to L */
|
||||
};
|
||||
|
||||
static int GetDeferredNeutrals(int action, int level)
|
||||
{
|
||||
action = (action >> 4) & 0xF;
|
||||
if (action == (En >> 4))
|
||||
return EmbeddingDirection(level);
|
||||
else
|
||||
return action;
|
||||
}
|
||||
|
||||
static int GetResolvedNeutrals(int action)
|
||||
{
|
||||
action = action & 0xF;
|
||||
if (action == In)
|
||||
return 0;
|
||||
else
|
||||
return action;
|
||||
}
|
||||
|
||||
/* state values */
|
||||
enum resolvestates
|
||||
{
|
||||
/* new temporary class */
|
||||
r, /* R and characters resolved to R */
|
||||
l, /* L and characters resolved to L */
|
||||
rn, /* N preceded by right */
|
||||
ln, /* N preceded by left */
|
||||
a, /* AN preceded by left (the abbreviation 'la' is used up above) */
|
||||
na, /* N preceded by a */
|
||||
} ;
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Notes:
|
||||
|
||||
By rule W7, whenever a EN is 'dominated' by an L (including start of
|
||||
run with embedding direction = L) it is resolved to, and further treated
|
||||
as L.
|
||||
|
||||
This leads to the need for 'a' and 'na' states.
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
static const int actionNeutrals[][5] =
|
||||
{
|
||||
/* N, L, R, AN, EN = cls */
|
||||
{ In, 0, 0, 0, 0 }, /* r right */
|
||||
{ In, 0, 0, 0, L }, /* l left */
|
||||
|
||||
{ In, En, Rn, Rn, Rn }, /* rn N preceded by right */
|
||||
{ In, Ln, En, En, LnL}, /* ln N preceded by left */
|
||||
|
||||
{ In, 0, 0, 0, L }, /* a AN preceded by left */
|
||||
{ In, En, Rn, Rn, En }, /* na N preceded by a */
|
||||
} ;
|
||||
|
||||
static const int stateNeutrals[][5] =
|
||||
{
|
||||
/* N, L, R, AN, EN */
|
||||
{ rn, l, r, r, r }, /* r right */
|
||||
{ ln, l, r, a, l }, /* l left */
|
||||
|
||||
{ rn, l, r, r, r }, /* rn N preceded by right */
|
||||
{ ln, l, r, a, l }, /* ln N preceded by left */
|
||||
|
||||
{ na, l, r, a, l }, /* a AN preceded by left */
|
||||
{ na, l, r, a, l }, /* na N preceded by la */
|
||||
} ;
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Function: resolveNeutrals
|
||||
|
||||
Resolves the directionality of neutral character types.
|
||||
|
||||
Implements rules W7, N1 and N2 of the Unicode Bidi Algorithm.
|
||||
|
||||
Input: Array of embedding levels
|
||||
Character count
|
||||
Baselevel
|
||||
|
||||
In/Out: Array of directional classes
|
||||
|
||||
Note: On input only these directional classes are expected
|
||||
R, L, N, AN, EN and BN
|
||||
|
||||
W8 resolves a number of ENs to L
|
||||
------------------------------------------------------------------------*/
|
||||
static void resolveNeutrals(int baselevel, WORD *pcls, const WORD *plevel, int cch)
|
||||
{
|
||||
/* the state at the start of text depends on the base level */
|
||||
int state = odd(baselevel) ? r : l;
|
||||
int cls;
|
||||
|
||||
int cchRun = 0;
|
||||
int level = baselevel;
|
||||
|
||||
int action, clsRun, clsNew;
|
||||
int ich = 0;
|
||||
for (; ich < cch; ich++)
|
||||
{
|
||||
/* ignore boundary neutrals */
|
||||
if (pcls[ich] == BN)
|
||||
{
|
||||
/* include in the count for a deferred run */
|
||||
if (cchRun)
|
||||
cchRun++;
|
||||
|
||||
/* skip any further processing */
|
||||
continue;
|
||||
}
|
||||
|
||||
ASSERT(pcls[ich] < 5); /* "Only N, L, R, AN, EN are allowed" */
|
||||
cls = pcls[ich];
|
||||
|
||||
action = actionNeutrals[state][cls];
|
||||
|
||||
/* resolve the directionality for deferred runs */
|
||||
clsRun = GetDeferredNeutrals(action, level);
|
||||
if (clsRun != N)
|
||||
{
|
||||
SetDeferredRun(pcls, cchRun, ich, clsRun);
|
||||
cchRun = 0;
|
||||
}
|
||||
|
||||
/* resolve the directionality class at the current location */
|
||||
clsNew = GetResolvedNeutrals(action);
|
||||
if (clsNew != N)
|
||||
pcls[ich] = clsNew;
|
||||
|
||||
if (In & action)
|
||||
cchRun++;
|
||||
|
||||
state = stateNeutrals[state][cls];
|
||||
level = plevel[ich];
|
||||
}
|
||||
|
||||
/* resolve any deferred runs */
|
||||
cls = EmbeddingDirection(level); /* eor has type of current level */
|
||||
|
||||
/* resolve the directionality for deferred runs */
|
||||
clsRun = GetDeferredNeutrals(actionNeutrals[state][cls], level);
|
||||
if (clsRun != N)
|
||||
SetDeferredRun(pcls, cchRun, ich, clsRun);
|
||||
}
|
||||
|
||||
/* RESOLVE IMPLICIT */
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Function: resolveImplicit
|
||||
|
||||
Recursively resolves implicit embedding levels.
|
||||
Implements rules I1 and I2 of the Unicode Bidirectional Algorithm.
|
||||
|
||||
Input: Array of direction classes
|
||||
Character count
|
||||
Base level
|
||||
|
||||
In/Out: Array of embedding levels
|
||||
|
||||
Note: levels may exceed 15 on output.
|
||||
Accepted subset of direction classes
|
||||
R, L, AN, EN
|
||||
------------------------------------------------------------------------*/
|
||||
static const WORD addLevel[][4] =
|
||||
{
|
||||
/* L, R, AN, EN */
|
||||
/* even */ { 0, 1, 2, 2, },
|
||||
/* odd */ { 1, 0, 1, 1, }
|
||||
|
||||
};
|
||||
|
||||
static void resolveImplicit(const WORD * pcls, WORD *plevel, int cch)
|
||||
{
|
||||
int ich = 0;
|
||||
for (; ich < cch; ich++)
|
||||
{
|
||||
/* cannot resolve bn here, since some bn were resolved to strong
|
||||
* types in resolveWeak. To remove these we need the original
|
||||
* types, which are available again in resolveWhiteSpace */
|
||||
if (pcls[ich] == BN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ASSERT(pcls[ich] > 0); /* "No Neutrals allowed to survive here." */
|
||||
ASSERT(pcls[ich] < 5); /* "Out of range." */
|
||||
plevel[ich] += addLevel[odd(plevel[ich])][pcls[ich] - 1];
|
||||
}
|
||||
}
|
||||
|
||||
/* REORDER */
|
||||
/*------------------------------------------------------------------------
|
||||
Function: resolveLines
|
||||
|
@ -1057,13 +491,24 @@ BOOL BIDI_Reorder(
|
|||
UINT *lpOrder /* [out] Logical -> Visual order map */
|
||||
)
|
||||
{
|
||||
WORD *levels;
|
||||
WORD *chartype;
|
||||
unsigned i, baselevel = 0, done;
|
||||
WORD *levels;
|
||||
unsigned i, done;
|
||||
|
||||
int maxItems;
|
||||
int nItems;
|
||||
SCRIPT_CONTROL Control;
|
||||
SCRIPT_STATE State;
|
||||
SCRIPT_ITEM *pItems;
|
||||
HRESULT res;
|
||||
|
||||
TRACE("%s, %d, 0x%08x lpOutString=%p, lpOrder=%p\n",
|
||||
debugstr_wn(lpString, uCount), uCount, dwFlags,
|
||||
lpOutString, lpOrder);
|
||||
|
||||
memset(&Control, 0, sizeof(Control));
|
||||
memset(&State, 0, sizeof(State));
|
||||
|
||||
if (!(dwFlags & GCP_REORDER))
|
||||
{
|
||||
FIXME("Asked to reorder without reorder flag set\n");
|
||||
|
@ -1076,8 +521,7 @@ BOOL BIDI_Reorder(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
chartype = HeapAlloc(GetProcessHeap(), 0, uCount * 2 * sizeof(WORD));
|
||||
levels = chartype + uCount;
|
||||
chartype = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD));
|
||||
if (!chartype)
|
||||
{
|
||||
WARN("Out of memory\n");
|
||||
|
@ -1087,8 +531,48 @@ BOOL BIDI_Reorder(
|
|||
if (lpOutString)
|
||||
memcpy(lpOutString, lpString, uCount * sizeof(WCHAR));
|
||||
|
||||
if (WINE_GCPW_FORCE_RTL == (dwWineGCP_Flags&WINE_GCPW_DIR_MASK))
|
||||
baselevel = 1;
|
||||
/* Verify reordering will be required */
|
||||
if ((WINE_GCPW_FORCE_RTL == (dwWineGCP_Flags&WINE_GCPW_DIR_MASK)) ||
|
||||
((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_RTL))
|
||||
State.uBidiLevel = 1;
|
||||
else
|
||||
{
|
||||
done = 1;
|
||||
classify(lpString, chartype, uCount);
|
||||
for (i = 0; i < uCount; i++)
|
||||
switch (chartype[i])
|
||||
{
|
||||
case R:
|
||||
case AL:
|
||||
case RLE:
|
||||
case RLO:
|
||||
done = 0;
|
||||
break;
|
||||
}
|
||||
if (done)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, chartype);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
levels = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD));
|
||||
if (!levels)
|
||||
{
|
||||
WARN("Out of memory\n");
|
||||
HeapFree(GetProcessHeap(), 0, chartype);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
maxItems = 5;
|
||||
pItems = HeapAlloc(GetProcessHeap(),0, maxItems * sizeof(SCRIPT_ITEM));
|
||||
if (!pItems)
|
||||
{
|
||||
WARN("Out of memory\n");
|
||||
HeapFree(GetProcessHeap(), 0, chartype);
|
||||
HeapFree(GetProcessHeap(), 0, levels);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
done = 0;
|
||||
while (done < uCount)
|
||||
|
@ -1108,43 +592,54 @@ BOOL BIDI_Reorder(
|
|||
}
|
||||
|
||||
if ((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_RTL)
|
||||
baselevel = 1;
|
||||
State.uBidiLevel = 1;
|
||||
else if ((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_LTR)
|
||||
baselevel = 0;
|
||||
State.uBidiLevel = 0;
|
||||
|
||||
if (dwWineGCP_Flags & WINE_GCPW_LOOSE_MASK)
|
||||
{
|
||||
for (j = 0; j < i; ++j)
|
||||
if (chartype[j] == L)
|
||||
{
|
||||
baselevel = 0;
|
||||
State.uBidiLevel = 0;
|
||||
break;
|
||||
}
|
||||
else if (chartype[j] == R || chartype[j] == AL)
|
||||
{
|
||||
baselevel = 1;
|
||||
State.uBidiLevel = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* resolve explicit */
|
||||
resolveExplicit(baselevel, N, chartype, levels, i, 0);
|
||||
res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems);
|
||||
while (res == E_OUTOFMEMORY)
|
||||
{
|
||||
maxItems = maxItems * 2;
|
||||
pItems = HeapReAlloc(GetProcessHeap(), 0, pItems, sizeof(SCRIPT_ITEM) * maxItems);
|
||||
if (!pItems)
|
||||
{
|
||||
WARN("Out of memory\n");
|
||||
HeapFree(GetProcessHeap(), 0, chartype);
|
||||
HeapFree(GetProcessHeap(), 0, levels);
|
||||
return FALSE;
|
||||
}
|
||||
res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems);
|
||||
}
|
||||
|
||||
/* resolve weak */
|
||||
resolveWeak(baselevel, chartype, levels, i);
|
||||
|
||||
/* resolve neutrals */
|
||||
resolveNeutrals(baselevel, chartype, levels, i);
|
||||
|
||||
/* resolveImplicit */
|
||||
resolveImplicit(chartype, levels, i);
|
||||
for (j = 0; j < nItems; j++)
|
||||
{
|
||||
int k;
|
||||
for (k = pItems[j].iCharPos; k < pItems[j+1].iCharPos; k++)
|
||||
levels[k] = pItems[j].a.s.uBidiLevel;
|
||||
}
|
||||
|
||||
/* assign directional types again, but for WS, S this time */
|
||||
classify(lpString + done, chartype, i);
|
||||
|
||||
BidiLines(baselevel, lpOutString ? lpOutString + done : NULL, lpString + done,
|
||||
BidiLines(State.uBidiLevel, lpOutString ? lpOutString + done : NULL, lpString + done,
|
||||
chartype, levels, i, !(dwFlags & GCP_SYMSWAPOFF), 0);
|
||||
|
||||
|
||||
if (lpOrder)
|
||||
{
|
||||
int k, lastgood;
|
||||
|
@ -1171,5 +666,7 @@ BOOL BIDI_Reorder(
|
|||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, chartype);
|
||||
HeapFree(GetProcessHeap(), 0, levels);
|
||||
HeapFree(GetProcessHeap(), 0, pItems);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ IMPORTLIB = usp10
|
|||
IMPORTS = gdi32 kernel32
|
||||
|
||||
C_SRCS = \
|
||||
bidi.c \
|
||||
usp10.c
|
||||
|
||||
@MAKE_DLL_RULES@
|
||||
|
|
|
@ -0,0 +1,829 @@
|
|||
/*
|
||||
* Uniscribe BiDirectional handling
|
||||
*
|
||||
* Copyright 2003 Shachar Shemesh
|
||||
* Copyright 2007 Maarten Lankhorst
|
||||
* Copyright 2010 CodeWeavers, Aric Stewart
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* Code derived from the modified reference implementation
|
||||
* that was found in revision 17 of http://unicode.org/reports/tr9/
|
||||
* "Unicode Standard Annex #9: THE BIDIRECTIONAL ALGORITHM"
|
||||
*
|
||||
* -- Copyright (C) 1999-2005, ASMUS, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of the Unicode data files and any associated documentation (the
|
||||
* "Data Files") or Unicode software and any associated documentation (the
|
||||
* "Software") to deal in the Data Files or Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, and/or sell copies of the Data Files or Software,
|
||||
* and to permit persons to whom the Data Files or Software are furnished
|
||||
* to do so, provided that (a) the above copyright notice(s) and this
|
||||
* permission notice appear with all copies of the Data Files or Software,
|
||||
* (b) both the above copyright notice(s) and this permission notice appear
|
||||
* in associated documentation, and (c) there is clear notice in each
|
||||
* modified Data File or in the Software as well as in the documentation
|
||||
* associated with the Data File(s) or Software that the data or software
|
||||
* has been modified.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winnls.h"
|
||||
#include "usp10.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "usp10_internal.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(bidi);
|
||||
|
||||
#define ASSERT(x) do { if (!(x)) FIXME("assert failed: %s\n", #x); } while(0)
|
||||
#define MAX_LEVEL 61
|
||||
|
||||
/* HELPER FUNCTIONS AND DECLARATIONS */
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Bidirectional Character Types
|
||||
|
||||
as defined by the Unicode Bidirectional Algorithm Table 3-7.
|
||||
|
||||
Note:
|
||||
|
||||
The list of bidirectional character types here is not grouped the
|
||||
same way as the table 3-7, since the numberic values for the types
|
||||
are chosen to keep the state and action tables compact.
|
||||
------------------------------------------------------------------------*/
|
||||
enum directions
|
||||
{
|
||||
/* input types */
|
||||
/* ON MUST be zero, code relies on ON = N = 0 */
|
||||
ON = 0, /* Other Neutral */
|
||||
L, /* Left Letter */
|
||||
R, /* Right Letter */
|
||||
AN, /* Arabic Number */
|
||||
EN, /* European Number */
|
||||
AL, /* Arabic Letter (Right-to-left) */
|
||||
NSM, /* Non-spacing Mark */
|
||||
CS, /* Common Separator */
|
||||
ES, /* European Separator */
|
||||
ET, /* European Terminator (post/prefix e.g. $ and %) */
|
||||
|
||||
/* resolved types */
|
||||
BN, /* Boundary neutral (type of RLE etc after explicit levels) */
|
||||
|
||||
/* input types, */
|
||||
S, /* Segment Separator (TAB) // used only in L1 */
|
||||
WS, /* White space // used only in L1 */
|
||||
B, /* Paragraph Separator (aka as PS) */
|
||||
|
||||
/* types for explicit controls */
|
||||
RLO, /* these are used only in X1-X9 */
|
||||
RLE,
|
||||
LRO,
|
||||
LRE,
|
||||
PDF,
|
||||
|
||||
/* resolved types, also resolved directions */
|
||||
N = ON, /* alias, where ON, WS and S are treated the same */
|
||||
};
|
||||
|
||||
/* HELPER FUNCTIONS */
|
||||
|
||||
/* grep -r ';BN;' data.txt | grep -v [0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F] | sed -e s@\;.*@@ -e s/^..../0x\&,\ / | xargs echo */
|
||||
static const WCHAR BNs[] = {
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
|
||||
0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016,
|
||||
0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x007F, 0x0080, 0x0081, 0x0082,
|
||||
0x0083, 0x0084, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C,
|
||||
0x008D, 0x008E, 0x008F, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095,
|
||||
0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E,
|
||||
0x009F, 0x00AD, 0x070F, 0x200B, 0x200C, 0x200D, 0x2060, 0x2061, 0x2062,
|
||||
0x2063, 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F, 0xFEFF
|
||||
};
|
||||
|
||||
/* Idem, but with ';R;' instead of ';BN;' */
|
||||
static const WCHAR Rs[] = {
|
||||
0x05BE, 0x05C0, 0x05C3, 0x05C6, 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4,
|
||||
0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD,
|
||||
0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6,
|
||||
0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4,
|
||||
0x07C0, 0x07C1, 0x07C2, 0x07C3, 0x07C4, 0x07C5, 0x07C6, 0x07C7, 0x07C8,
|
||||
0x07C9, 0x07CA, 0x07CB, 0x07CC, 0x07CD, 0x07CE, 0x07CF, 0x07D0, 0x07D1,
|
||||
0x07D2, 0x07D3, 0x07D4, 0x07D5, 0x07D6, 0x07D7, 0x07D8, 0x07D9, 0x07DA,
|
||||
0x07DB, 0x07DC, 0x07DD, 0x07DE, 0x07DF, 0x07E0, 0x07E1, 0x07E2, 0x07E3,
|
||||
0x07E4, 0x07E5, 0x07E6, 0x07E7, 0x07E8, 0x07E9, 0x07EA, 0x07F4, 0x07F5,
|
||||
0x07FA, 0x200F, 0xFB1D, 0xFB1F, 0xFB20, 0xFB21, 0xFB22, 0xFB23, 0xFB24,
|
||||
0xFB25, 0xFB26, 0xFB27, 0xFB28, 0xFB2A, 0xFB2B, 0xFB2C, 0xFB2D, 0xFB2E,
|
||||
0xFB2F, 0xFB30, 0xFB31, 0xFB32, 0xFB33, 0xFB34, 0xFB35, 0xFB36, 0xFB38,
|
||||
0xFB39, 0xFB3A, 0xFB3B, 0xFB3C, 0xFB3E, 0xFB40, 0xFB41, 0xFB43, 0xFB44,
|
||||
0xFB46, 0xFB47, 0xFB48, 0xFB49, 0xFB4A, 0xFB4B, 0xFB4C, 0xFB4D, 0xFB4E,
|
||||
0xFB4F
|
||||
};
|
||||
|
||||
/* Convert the incomplete win32 table to some slightly more useful data */
|
||||
static void classify(LPCWSTR lpString, WORD *chartype, DWORD uCount, const SCRIPT_CONTROL *c)
|
||||
{
|
||||
unsigned i, j;
|
||||
GetStringTypeW(CT_CTYPE2, lpString, uCount, chartype);
|
||||
for (i = 0; i < uCount; ++i)
|
||||
switch (chartype[i])
|
||||
{
|
||||
case C2_LEFTTORIGHT: chartype[i] = L; break;
|
||||
case C2_RIGHTTOLEFT:
|
||||
chartype[i] = AL;
|
||||
for (j = 0; j < sizeof(Rs)/sizeof(WCHAR); ++j)
|
||||
if (Rs[j] == lpString[i])
|
||||
{
|
||||
chartype[i] = R;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case C2_EUROPENUMBER: chartype[i] = EN; break;
|
||||
case C2_EUROPESEPARATOR:
|
||||
if (c->fLegacyBidiClass && (lpString[i] == '-' || lpString[i] =='+'))
|
||||
chartype[i] = N;
|
||||
else if (c->fLegacyBidiClass && lpString[i] == '/')
|
||||
chartype[i] = CS;
|
||||
else
|
||||
chartype[i] = ES; break;
|
||||
case C2_EUROPETERMINATOR: chartype[i] = ET; break;
|
||||
case C2_ARABICNUMBER: chartype[i] = AN; break;
|
||||
case C2_COMMONSEPARATOR: chartype[i] = CS; break;
|
||||
case C2_BLOCKSEPARATOR: chartype[i] = B; break;
|
||||
case C2_SEGMENTSEPARATOR: chartype[i] = S; break;
|
||||
case C2_WHITESPACE: chartype[i] = WS; break;
|
||||
case C2_OTHERNEUTRAL:
|
||||
switch (lpString[i])
|
||||
{
|
||||
case 0x202A: chartype[i] = LRE; break;
|
||||
case 0x202B: chartype[i] = RLE; break;
|
||||
case 0x202C: chartype[i] = PDF; break;
|
||||
case 0x202D: chartype[i] = LRO; break;
|
||||
case 0x202E: chartype[i] = RLO; break;
|
||||
default: chartype[i] = ON; break;
|
||||
}
|
||||
break;
|
||||
case C2_NOTAPPLICABLE:
|
||||
chartype[i] = NSM;
|
||||
for (j = 0; j < sizeof(BNs)/sizeof(WCHAR); ++j)
|
||||
if (BNs[j] == lpString[i])
|
||||
{
|
||||
chartype[i] = BN;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* According to BiDi spec, unassigned characters default to L */
|
||||
FIXME("Unhandled character type: %04x\n", chartype[i]);
|
||||
chartype[i] = L;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int i = iStart - 1;
|
||||
for (; i >= iStart - cval; i--)
|
||||
{
|
||||
pval[i] = nval;
|
||||
}
|
||||
}
|
||||
|
||||
/* RESOLVE EXPLICIT */
|
||||
|
||||
static WORD GreaterEven(int i)
|
||||
{
|
||||
return odd(i) ? i + 1 : i + 2;
|
||||
}
|
||||
|
||||
static WORD GreaterOdd(int i)
|
||||
{
|
||||
return odd(i) ? i + 2 : i + 1;
|
||||
}
|
||||
|
||||
static WORD EmbeddingDirection(int level)
|
||||
{
|
||||
return odd(level) ? R : L;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Function: resolveExplicit
|
||||
|
||||
Recursively resolves explicit embedding levels and overrides.
|
||||
Implements rules X1-X9, of the Unicode Bidirectional Algorithm.
|
||||
|
||||
Input: Base embedding level and direction
|
||||
Character count
|
||||
|
||||
Output: Array of embedding levels
|
||||
|
||||
In/Out: Array of direction classes
|
||||
|
||||
|
||||
Note: The function uses two simple counters to keep track of
|
||||
matching explicit codes and PDF. Use the default argument for
|
||||
the outermost call. The nesting counter counts the recursion
|
||||
depth and not the embedding level.
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
static int resolveExplicit(int level, int dir, WORD *pcls, WORD *plevel, int cch, int nNest)
|
||||
{
|
||||
/* always called with a valid nesting level
|
||||
nesting levels are != embedding levels */
|
||||
int nLastValid = nNest;
|
||||
int ich = 0;
|
||||
|
||||
/* check input values */
|
||||
ASSERT(nNest >= 0 && level >= 0 && level <= MAX_LEVEL);
|
||||
|
||||
/* process the text */
|
||||
for (; ich < cch; ich++)
|
||||
{
|
||||
WORD cls = pcls[ich];
|
||||
switch (cls)
|
||||
{
|
||||
case LRO:
|
||||
case LRE:
|
||||
nNest++;
|
||||
if (GreaterEven(level) <= MAX_LEVEL - (cls == LRO ? 2 : 0))
|
||||
{
|
||||
plevel[ich] = GreaterEven(level);
|
||||
pcls[ich] = BN;
|
||||
ich += resolveExplicit(plevel[ich], (cls == LRE ? N : L),
|
||||
&pcls[ich+1], &plevel[ich+1],
|
||||
cch - (ich+1), nNest);
|
||||
nNest--;
|
||||
continue;
|
||||
}
|
||||
cls = pcls[ich] = BN;
|
||||
break;
|
||||
|
||||
case RLO:
|
||||
case RLE:
|
||||
nNest++;
|
||||
if (GreaterOdd(level) <= MAX_LEVEL - (cls == RLO ? 2 : 0))
|
||||
{
|
||||
plevel[ich] = GreaterOdd(level);
|
||||
pcls[ich] = BN;
|
||||
ich += resolveExplicit(plevel[ich], (cls == RLE ? N : R),
|
||||
&pcls[ich+1], &plevel[ich+1],
|
||||
cch - (ich+1), nNest);
|
||||
nNest--;
|
||||
continue;
|
||||
}
|
||||
cls = pcls[ich] = BN;
|
||||
break;
|
||||
|
||||
case PDF:
|
||||
cls = pcls[ich] = BN;
|
||||
if (nNest)
|
||||
{
|
||||
if (nLastValid < nNest)
|
||||
{
|
||||
nNest--;
|
||||
}
|
||||
else
|
||||
{
|
||||
cch = ich; /* break the loop, but complete body */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply the override */
|
||||
if (dir != N)
|
||||
{
|
||||
cls = dir;
|
||||
}
|
||||
plevel[ich] = level;
|
||||
if (pcls[ich] != BN)
|
||||
pcls[ich] = cls;
|
||||
}
|
||||
|
||||
return ich;
|
||||
}
|
||||
|
||||
/* RESOLVE WEAK TYPES */
|
||||
|
||||
enum states /* possible states */
|
||||
{
|
||||
xa, /* arabic letter */
|
||||
xr, /* right letter */
|
||||
xl, /* left letter */
|
||||
|
||||
ao, /* arabic lett. foll by ON */
|
||||
ro, /* right lett. foll by ON */
|
||||
lo, /* left lett. foll by ON */
|
||||
|
||||
rt, /* ET following R */
|
||||
lt, /* ET following L */
|
||||
|
||||
cn, /* EN, AN following AL */
|
||||
ra, /* arabic number foll R */
|
||||
re, /* european number foll R */
|
||||
la, /* arabic number foll L */
|
||||
le, /* european number foll L */
|
||||
|
||||
ac, /* CS following cn */
|
||||
rc, /* CS following ra */
|
||||
rs, /* CS,ES following re */
|
||||
lc, /* CS following la */
|
||||
ls, /* CS,ES following le */
|
||||
|
||||
ret, /* ET following re */
|
||||
let, /* ET following le */
|
||||
} ;
|
||||
|
||||
static const int stateWeak[][10] =
|
||||
{
|
||||
/* N, L, R, AN, EN, AL,NSM, CS, ES, ET */
|
||||
/*xa*/ { ao, xl, xr, cn, cn, xa, xa, ao, ao, ao }, /* arabic letter */
|
||||
/*xr*/ { ro, xl, xr, ra, re, xa, xr, ro, ro, rt }, /* right letter */
|
||||
/*xl*/ { lo, xl, xr, la, le, xa, xl, lo, lo, lt }, /* left letter */
|
||||
|
||||
/*ao*/ { ao, xl, xr, cn, cn, xa, ao, ao, ao, ao }, /* arabic lett. foll by ON*/
|
||||
/*ro*/ { ro, xl, xr, ra, re, xa, ro, ro, ro, rt }, /* right lett. foll by ON */
|
||||
/*lo*/ { lo, xl, xr, la, le, xa, lo, lo, lo, lt }, /* left lett. foll by ON */
|
||||
|
||||
/*rt*/ { ro, xl, xr, ra, re, xa, rt, ro, ro, rt }, /* ET following R */
|
||||
/*lt*/ { lo, xl, xr, la, le, xa, lt, lo, lo, lt }, /* ET following L */
|
||||
|
||||
/*cn*/ { ao, xl, xr, cn, cn, xa, cn, ac, ao, ao }, /* EN, AN following AL */
|
||||
/*ra*/ { ro, xl, xr, ra, re, xa, ra, rc, ro, rt }, /* arabic number foll R */
|
||||
/*re*/ { ro, xl, xr, ra, re, xa, re, rs, rs,ret }, /* european number foll R */
|
||||
/*la*/ { lo, xl, xr, la, le, xa, la, lc, lo, lt }, /* arabic number foll L */
|
||||
/*le*/ { lo, xl, xr, la, le, xa, le, ls, ls,let }, /* european number foll L */
|
||||
|
||||
/*ac*/ { ao, xl, xr, cn, cn, xa, ao, ao, ao, ao }, /* CS following cn */
|
||||
/*rc*/ { ro, xl, xr, ra, re, xa, ro, ro, ro, rt }, /* CS following ra */
|
||||
/*rs*/ { ro, xl, xr, ra, re, xa, ro, ro, ro, rt }, /* CS,ES following re */
|
||||
/*lc*/ { lo, xl, xr, la, le, xa, lo, lo, lo, lt }, /* CS following la */
|
||||
/*ls*/ { lo, xl, xr, la, le, xa, lo, lo, lo, lt }, /* CS,ES following le */
|
||||
|
||||
/*ret*/{ ro, xl, xr, ra, re, xa,ret, ro, ro,ret }, /* ET following re */
|
||||
/*let*/{ lo, xl, xr, la, le, xa,let, lo, lo,let }, /* ET following le */
|
||||
};
|
||||
|
||||
enum actions /* possible actions */
|
||||
{
|
||||
/* primitives */
|
||||
IX = 0x100, /* increment */
|
||||
XX = 0xF, /* no-op */
|
||||
|
||||
/* actions */
|
||||
xxx = (XX << 4) + XX, /* no-op */
|
||||
xIx = IX + xxx, /* increment run */
|
||||
xxN = (XX << 4) + ON, /* set current to N */
|
||||
xxE = (XX << 4) + EN, /* set current to EN */
|
||||
xxA = (XX << 4) + AN, /* set current to AN */
|
||||
xxR = (XX << 4) + R, /* set current to R */
|
||||
xxL = (XX << 4) + L, /* set current to L */
|
||||
Nxx = (ON << 4) + 0xF, /* set run to neutral */
|
||||
Axx = (AN << 4) + 0xF, /* set run to AN */
|
||||
ExE = (EN << 4) + EN, /* set run to EN, set current to EN */
|
||||
NIx = (ON << 4) + 0xF + IX, /* set run to N, increment */
|
||||
NxN = (ON << 4) + ON, /* set run to N, set current to N */
|
||||
NxR = (ON << 4) + R, /* set run to N, set current to R */
|
||||
NxE = (ON << 4) + EN, /* set run to N, set current to EN */
|
||||
|
||||
AxA = (AN << 4) + AN, /* set run to AN, set current to AN */
|
||||
NxL = (ON << 4) + L, /* set run to N, set current to L */
|
||||
LxL = (L << 4) + L, /* set run to L, set current to L */
|
||||
} ;
|
||||
|
||||
static const int actionWeak[][10] =
|
||||
{
|
||||
/* N, L, R, AN, EN, AL, NSM, CS, ES, ET */
|
||||
/*xa*/ { xxx, xxx, xxx, xxx, xxA, xxR, xxR, xxN, xxN, xxN }, /* arabic letter */
|
||||
/*xr*/ { xxx, xxx, xxx, xxx, xxE, xxR, xxR, xxN, xxN, xIx }, /* right letter */
|
||||
/*xl*/ { xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xIx }, /* left letter */
|
||||
|
||||
/*ao*/ { xxx, xxx, xxx, xxx, xxA, xxR, xxN, xxN, xxN, xxN }, /* arabic lett. foll by ON */
|
||||
/*ro*/ { xxx, xxx, xxx, xxx, xxE, xxR, xxN, xxN, xxN, xIx }, /* right lett. foll by ON */
|
||||
/*lo*/ { xxx, xxx, xxx, xxx, xxL, xxR, xxN, xxN, xxN, xIx }, /* left lett. foll by ON */
|
||||
|
||||
/*rt*/ { Nxx, Nxx, Nxx, Nxx, ExE, NxR, xIx, NxN, NxN, xIx }, /* ET following R */
|
||||
/*lt*/ { Nxx, Nxx, Nxx, Nxx, LxL, NxR, xIx, NxN, NxN, xIx }, /* ET following L */
|
||||
|
||||
/*cn*/ { xxx, xxx, xxx, xxx, xxA, xxR, xxA, xIx, xxN, xxN }, /* EN, AN following AL */
|
||||
/*ra*/ { xxx, xxx, xxx, xxx, xxE, xxR, xxA, xIx, xxN, xIx }, /* arabic number foll R */
|
||||
/*re*/ { xxx, xxx, xxx, xxx, xxE, xxR, xxE, xIx, xIx, xxE }, /* european number foll R */
|
||||
/*la*/ { xxx, xxx, xxx, xxx, xxL, xxR, xxA, xIx, xxN, xIx }, /* arabic number foll L */
|
||||
/*le*/ { xxx, xxx, xxx, xxx, xxL, xxR, xxL, xIx, xIx, xxL }, /* european number foll L */
|
||||
|
||||
/*ac*/ { Nxx, Nxx, Nxx, Axx, AxA, NxR, NxN, NxN, NxN, NxN }, /* CS following cn */
|
||||
/*rc*/ { Nxx, Nxx, Nxx, Axx, NxE, NxR, NxN, NxN, NxN, NIx }, /* CS following ra */
|
||||
/*rs*/ { Nxx, Nxx, Nxx, Nxx, ExE, NxR, NxN, NxN, NxN, NIx }, /* CS,ES following re */
|
||||
/*lc*/ { Nxx, Nxx, Nxx, Axx, NxL, NxR, NxN, NxN, NxN, NIx }, /* CS following la */
|
||||
/*ls*/ { Nxx, Nxx, Nxx, Nxx, LxL, NxR, NxN, NxN, NxN, NIx }, /* CS,ES following le */
|
||||
|
||||
/*ret*/{ xxx, xxx, xxx, xxx, xxE, xxR, xxE, xxN, xxN, xxE }, /* ET following re */
|
||||
/*let*/{ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xxL }, /* ET following le */
|
||||
};
|
||||
|
||||
static int GetDeferredType(int action)
|
||||
{
|
||||
return (action >> 4) & 0xF;
|
||||
}
|
||||
|
||||
static int GetResolvedType(int action)
|
||||
{
|
||||
return action & 0xF;
|
||||
}
|
||||
|
||||
/* Note on action table:
|
||||
|
||||
States can be of two kinds:
|
||||
- Immediate Resolution State, where each input token
|
||||
is resolved as soon as it is seen. These states have
|
||||
only single action codes (xxN) or the no-op (xxx)
|
||||
for static input tokens.
|
||||
- Deferred Resolution State, where input tokens either
|
||||
either extend the run (xIx) or resolve its Type (e.g. Nxx).
|
||||
|
||||
Input classes are of three kinds
|
||||
- Static Input Token, where the class of the token remains
|
||||
unchanged on output (AN, L, N, R)
|
||||
- Replaced Input Token, where the class of the token is
|
||||
always replaced on output (AL, BN, NSM, CS, ES, ET)
|
||||
- Conditional Input Token, where the class of the token is
|
||||
changed on output in some, but not all, cases (EN)
|
||||
|
||||
Where tokens are subject to change, a double action
|
||||
(e.g. NxA, or NxN) is _required_ after deferred states,
|
||||
resolving both the deferred state and changing the current token.
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Function: resolveWeak
|
||||
|
||||
Resolves the directionality of numeric and other weak character types
|
||||
|
||||
Implements rules X10 and W1-W6 of the Unicode Bidirectional Algorithm.
|
||||
|
||||
Input: Array of embedding levels
|
||||
Character count
|
||||
|
||||
In/Out: Array of directional classes
|
||||
|
||||
Note: On input only these directional classes are expected
|
||||
AL, HL, R, L, ON, BN, NSM, AN, EN, ES, ET, CS,
|
||||
------------------------------------------------------------------------*/
|
||||
static void resolveWeak(int baselevel, WORD *pcls, WORD *plevel, int cch)
|
||||
{
|
||||
int state = odd(baselevel) ? xr : xl;
|
||||
int cls;
|
||||
|
||||
int level = baselevel;
|
||||
int action, clsRun, clsNew;
|
||||
int cchRun = 0;
|
||||
int ich = 0;
|
||||
|
||||
for (; ich < cch; ich++)
|
||||
{
|
||||
/* ignore boundary neutrals */
|
||||
if (pcls[ich] == BN)
|
||||
{
|
||||
/* must flatten levels unless at a level change; */
|
||||
plevel[ich] = level;
|
||||
|
||||
/* lookahead for level changes */
|
||||
if (ich + 1 == cch && level != baselevel)
|
||||
{
|
||||
/* have to fixup last BN before end of the loop, since
|
||||
* its fix-upped value will be needed below the assert */
|
||||
pcls[ich] = EmbeddingDirection(level);
|
||||
}
|
||||
else if (ich + 1 < cch && level != plevel[ich+1] && pcls[ich+1] != BN)
|
||||
{
|
||||
/* fixup LAST BN in front / after a level run to make
|
||||
* it act like the SOR/EOR in rule X10 */
|
||||
int newlevel = plevel[ich+1];
|
||||
if (level > newlevel) {
|
||||
newlevel = level;
|
||||
}
|
||||
plevel[ich] = newlevel;
|
||||
|
||||
/* must match assigned level */
|
||||
pcls[ich] = EmbeddingDirection(newlevel);
|
||||
level = plevel[ich+1];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* don't interrupt runs */
|
||||
if (cchRun)
|
||||
{
|
||||
cchRun++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(pcls[ich] <= BN);
|
||||
cls = pcls[ich];
|
||||
|
||||
action = actionWeak[state][cls];
|
||||
|
||||
/* resolve the directionality for deferred runs */
|
||||
clsRun = GetDeferredType(action);
|
||||
if (clsRun != XX)
|
||||
{
|
||||
SetDeferredRun(pcls, cchRun, ich, clsRun);
|
||||
cchRun = 0;
|
||||
}
|
||||
|
||||
/* resolve the directionality class at the current location */
|
||||
clsNew = GetResolvedType(action);
|
||||
if (clsNew != XX)
|
||||
pcls[ich] = clsNew;
|
||||
|
||||
/* increment a deferred run */
|
||||
if (IX & action)
|
||||
cchRun++;
|
||||
|
||||
state = stateWeak[state][cls];
|
||||
}
|
||||
|
||||
/* resolve any deferred runs
|
||||
* use the direction of the current level to emulate PDF */
|
||||
cls = EmbeddingDirection(level);
|
||||
|
||||
/* resolve the directionality for deferred runs */
|
||||
clsRun = GetDeferredType(actionWeak[state][cls]);
|
||||
if (clsRun != XX)
|
||||
SetDeferredRun(pcls, cchRun, ich, clsRun);
|
||||
}
|
||||
|
||||
/* RESOLVE NEUTRAL TYPES */
|
||||
|
||||
/* action values */
|
||||
enum neutralactions
|
||||
{
|
||||
/* action to resolve previous input */
|
||||
nL = L, /* resolve EN to L */
|
||||
En = 3 << 4, /* resolve neutrals run to embedding level direction */
|
||||
Rn = R << 4, /* resolve neutrals run to strong right */
|
||||
Ln = L << 4, /* resolved neutrals run to strong left */
|
||||
In = (1<<8), /* increment count of deferred neutrals */
|
||||
LnL = (1<<4)+L, /* set run and EN to L */
|
||||
};
|
||||
|
||||
static int GetDeferredNeutrals(int action, int level)
|
||||
{
|
||||
action = (action >> 4) & 0xF;
|
||||
if (action == (En >> 4))
|
||||
return EmbeddingDirection(level);
|
||||
else
|
||||
return action;
|
||||
}
|
||||
|
||||
static int GetResolvedNeutrals(int action)
|
||||
{
|
||||
action = action & 0xF;
|
||||
if (action == In)
|
||||
return 0;
|
||||
else
|
||||
return action;
|
||||
}
|
||||
|
||||
/* state values */
|
||||
enum resolvestates
|
||||
{
|
||||
/* new temporary class */
|
||||
r, /* R and characters resolved to R */
|
||||
l, /* L and characters resolved to L */
|
||||
rn, /* N preceded by right */
|
||||
ln, /* N preceded by left */
|
||||
a, /* AN preceded by left (the abbreviation 'la' is used up above) */
|
||||
na, /* N preceded by a */
|
||||
} ;
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Notes:
|
||||
|
||||
By rule W7, whenever a EN is 'dominated' by an L (including start of
|
||||
run with embedding direction = L) it is resolved to, and further treated
|
||||
as L.
|
||||
|
||||
This leads to the need for 'a' and 'na' states.
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
static const int actionNeutrals[][5] =
|
||||
{
|
||||
/* N, L, R, AN, EN = cls */
|
||||
{ In, 0, 0, 0, 0 }, /* r right */
|
||||
{ In, 0, 0, 0, L }, /* l left */
|
||||
|
||||
{ In, En, Rn, Rn, Rn }, /* rn N preceded by right */
|
||||
{ In, Ln, En, En, LnL}, /* ln N preceded by left */
|
||||
|
||||
{ In, 0, 0, 0, L }, /* a AN preceded by left */
|
||||
{ In, En, Rn, Rn, En }, /* na N preceded by a */
|
||||
} ;
|
||||
|
||||
static const int stateNeutrals[][5] =
|
||||
{
|
||||
/* N, L, R, AN, EN */
|
||||
{ rn, l, r, r, r }, /* r right */
|
||||
{ ln, l, r, a, l }, /* l left */
|
||||
|
||||
{ rn, l, r, r, r }, /* rn N preceded by right */
|
||||
{ ln, l, r, a, l }, /* ln N preceded by left */
|
||||
|
||||
{ na, l, r, a, l }, /* a AN preceded by left */
|
||||
{ na, l, r, a, l }, /* na N preceded by la */
|
||||
} ;
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Function: resolveNeutrals
|
||||
|
||||
Resolves the directionality of neutral character types.
|
||||
|
||||
Implements rules W7, N1 and N2 of the Unicode Bidi Algorithm.
|
||||
|
||||
Input: Array of embedding levels
|
||||
Character count
|
||||
Baselevel
|
||||
|
||||
In/Out: Array of directional classes
|
||||
|
||||
Note: On input only these directional classes are expected
|
||||
R, L, N, AN, EN and BN
|
||||
|
||||
W8 resolves a number of ENs to L
|
||||
------------------------------------------------------------------------*/
|
||||
static void resolveNeutrals(int baselevel, WORD *pcls, const WORD *plevel, int cch)
|
||||
{
|
||||
/* the state at the start of text depends on the base level */
|
||||
int state = odd(baselevel) ? r : l;
|
||||
int cls;
|
||||
|
||||
int cchRun = 0;
|
||||
int level = baselevel;
|
||||
|
||||
int action, clsRun, clsNew;
|
||||
int ich = 0;
|
||||
for (; ich < cch; ich++)
|
||||
{
|
||||
/* ignore boundary neutrals */
|
||||
if (pcls[ich] == BN)
|
||||
{
|
||||
/* include in the count for a deferred run */
|
||||
if (cchRun)
|
||||
cchRun++;
|
||||
|
||||
/* skip any further processing */
|
||||
continue;
|
||||
}
|
||||
|
||||
ASSERT(pcls[ich] < 5); /* "Only N, L, R, AN, EN are allowed" */
|
||||
cls = pcls[ich];
|
||||
|
||||
action = actionNeutrals[state][cls];
|
||||
|
||||
/* resolve the directionality for deferred runs */
|
||||
clsRun = GetDeferredNeutrals(action, level);
|
||||
if (clsRun != N)
|
||||
{
|
||||
SetDeferredRun(pcls, cchRun, ich, clsRun);
|
||||
cchRun = 0;
|
||||
}
|
||||
|
||||
/* resolve the directionality class at the current location */
|
||||
clsNew = GetResolvedNeutrals(action);
|
||||
if (clsNew != N)
|
||||
pcls[ich] = clsNew;
|
||||
|
||||
if (In & action)
|
||||
cchRun++;
|
||||
|
||||
state = stateNeutrals[state][cls];
|
||||
level = plevel[ich];
|
||||
}
|
||||
|
||||
/* resolve any deferred runs */
|
||||
cls = EmbeddingDirection(level); /* eor has type of current level */
|
||||
|
||||
/* resolve the directionality for deferred runs */
|
||||
clsRun = GetDeferredNeutrals(actionNeutrals[state][cls], level);
|
||||
if (clsRun != N)
|
||||
SetDeferredRun(pcls, cchRun, ich, clsRun);
|
||||
}
|
||||
|
||||
/* RESOLVE IMPLICIT */
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Function: resolveImplicit
|
||||
|
||||
Recursively resolves implicit embedding levels.
|
||||
Implements rules I1 and I2 of the Unicode Bidirectional Algorithm.
|
||||
|
||||
Input: Array of direction classes
|
||||
Character count
|
||||
Base level
|
||||
|
||||
In/Out: Array of embedding levels
|
||||
|
||||
Note: levels may exceed 15 on output.
|
||||
Accepted subset of direction classes
|
||||
R, L, AN, EN
|
||||
------------------------------------------------------------------------*/
|
||||
static const WORD addLevel[][4] =
|
||||
{
|
||||
/* L, R, AN, EN */
|
||||
/* even */ { 0, 1, 2, 2, },
|
||||
/* odd */ { 1, 0, 1, 1, }
|
||||
|
||||
};
|
||||
|
||||
static void resolveImplicit(const WORD * pcls, WORD *plevel, int cch)
|
||||
{
|
||||
int ich = 0;
|
||||
for (; ich < cch; ich++)
|
||||
{
|
||||
/* cannot resolve bn here, since some bn were resolved to strong
|
||||
* types in resolveWeak. To remove these we need the original
|
||||
* types, which are available again in resolveWhiteSpace */
|
||||
if (pcls[ich] == BN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ASSERT(pcls[ich] > 0); /* "No Neutrals allowed to survive here." */
|
||||
ASSERT(pcls[ich] < 5); /* "Out of range." */
|
||||
plevel[ich] += addLevel[odd(plevel[ich])][pcls[ich] - 1];
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* BIDI_DeterminLevels
|
||||
*/
|
||||
BOOL BIDI_DetermineLevels(
|
||||
LPCWSTR lpString, /* [in] The string for which information is to be returned */
|
||||
INT uCount, /* [in] Number of WCHARs in string. */
|
||||
const SCRIPT_STATE *s,
|
||||
const SCRIPT_CONTROL *c,
|
||||
WORD *lpOutLevels /* [out] final string levels */
|
||||
)
|
||||
{
|
||||
WORD *chartype;
|
||||
unsigned baselevel = 0,j;
|
||||
TRACE("%s, %d", debugstr_wn(lpString, uCount), uCount);
|
||||
|
||||
chartype = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD));
|
||||
if (!chartype)
|
||||
{
|
||||
WARN("Out of memory\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
baselevel = s->uBidiLevel;
|
||||
|
||||
classify(lpString, chartype, uCount, c);
|
||||
|
||||
for (j = 0; j < uCount; ++j)
|
||||
switch(chartype[j])
|
||||
{
|
||||
case B:
|
||||
case S:
|
||||
case WS:
|
||||
case ON: chartype[j] = N;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
/* resolve explicit */
|
||||
resolveExplicit(baselevel, N, chartype, lpOutLevels, uCount, 0);
|
||||
|
||||
/* resolve weak */
|
||||
resolveWeak(baselevel, chartype, lpOutLevels, uCount);
|
||||
|
||||
/* resolve neutrals */
|
||||
resolveNeutrals(baselevel, chartype, lpOutLevels, uCount);
|
||||
|
||||
/* resolveImplicit */
|
||||
resolveImplicit(chartype, lpOutLevels, uCount);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, chartype);
|
||||
return TRUE;
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright 2006 Jeff Latimer
|
||||
* Copyright 2006 Hans Leidekker
|
||||
* Copyright 2010 CodeWeavers, Aric Stewart
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -30,6 +31,262 @@
|
|||
#include <windows.h>
|
||||
#include <usp10.h>
|
||||
|
||||
static void test_ScriptItemize( void )
|
||||
{
|
||||
static const WCHAR test1[] = {'t', 'e', 's', 't',0};
|
||||
static const WCHAR test2[] = {'1','2','3','-','5','2',0x064a,0x064f,0x0633,0x0627,0x0648,0x0650,0x064a,'7','1','.',0};
|
||||
static const WCHAR test3[] =
|
||||
{0x0e04,0x0e27,0x0e32,0x0e21,0x0e1e,0x0e22,0x0e32,0x0e22,0x0e32, 0x0e21
|
||||
,0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e44,0x0e2b,0x0e19
|
||||
,0x0e04,0x0e27,0x0e32,0x0e21,0x0e2a, 0x0e33,0x0e40,0x0e23,0x0e47,0x0e08,
|
||||
0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e19,0x0e31,0x0e48,0x0e19,0};
|
||||
static const WCHAR test4[] = {'1','2','3','-','5','2',' ','i','s',' ','7','1','.',0};
|
||||
static const WCHAR test5[] =
|
||||
{0x0627,0x0644,0x0635,0x0651,0x0650,0x062d,0x0629,0x064f,' ',0x062a,0x064e,
|
||||
0x0627,0x062c,0x064c,' ',0x0639,0x064e,0x0644,0x0649,' ',
|
||||
0x0631,0x064f,0x0624,0x0648,0x0633,0x0650,' ',0x0627,0x0644
|
||||
,0x0623,0x0635,0x0650,0x062d,0x0651,0x064e,0x0627,0x0621,0x0650,0};
|
||||
SCRIPT_ITEM items[10];
|
||||
SCRIPT_CONTROL Control;
|
||||
SCRIPT_STATE State;
|
||||
HRESULT hr;
|
||||
int nItems;
|
||||
|
||||
memset(&Control, 0, sizeof(Control));
|
||||
memset(&State, 0, sizeof(State));
|
||||
|
||||
hr = ScriptItemize(NULL, 4, 10, &Control, &State, items, NULL);
|
||||
ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pwcInChars is NULL\n");
|
||||
|
||||
hr = ScriptItemize(test1, 4, 10, &Control, &State, NULL, NULL);
|
||||
ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pItems is NULL\n");
|
||||
|
||||
hr = ScriptItemize(test1, 4, 1, &Control, &State, items, NULL);
|
||||
ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cMaxItems < 2.");
|
||||
|
||||
hr = ScriptItemize(test1, 0, 10, NULL, NULL, items, &nItems);
|
||||
ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cInChars is 0\n");
|
||||
|
||||
hr = ScriptItemize(test1, 4, 10, NULL, NULL, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 1, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
|
||||
State.uBidiLevel = 0;
|
||||
hr = ScriptItemize(test1, 4, 10, &Control, &State, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 1, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
|
||||
State.uBidiLevel = 1;
|
||||
hr = ScriptItemize(test1, 4, 10, &Control, &State, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 1, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
todo_wine ok(items[0].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
|
||||
|
||||
hr = ScriptItemize(test2, 16, 10, NULL, NULL, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 6, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[1].iCharPos == 3, "Wrong CharPos \n");
|
||||
ok(items[1].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[1].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[1].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[2].iCharPos == 4, "Wrong CharPos \n");
|
||||
ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[2].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[2].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[3].iCharPos == 6, "Wrong CharPos \n");
|
||||
ok(items[3].a.fRTL == 1, "Wrong fRTL\n");
|
||||
ok(items[3].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[3].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
|
||||
ok(items[4].iCharPos == 13, "Wrong CharPos \n");
|
||||
ok(items[4].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[4].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[4].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[5].iCharPos == 15, "Wrong CharPos \n");
|
||||
ok(items[5].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[5].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[5].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
|
||||
State.uBidiLevel = 0;
|
||||
hr = ScriptItemize(test2, 16, 10, &Control, &State, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 4, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
todo_wine ok(items[0].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
|
||||
ok(items[1].iCharPos == 6, "Wrong CharPos \n");
|
||||
ok(items[1].a.fRTL == 1, "Wrong fRTL\n");
|
||||
ok(items[1].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[1].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
|
||||
ok(items[2].iCharPos == 13, "Wrong CharPos \n");
|
||||
ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
|
||||
todo_wine ok(items[2].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[2].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
|
||||
ok(items[3].iCharPos == 15, "Wrong CharPos \n");
|
||||
ok(items[3].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[3].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[3].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
|
||||
State.uBidiLevel = 1;
|
||||
hr = ScriptItemize(test2, 16, 10, &Control, &State, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 4, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
todo_wine ok(items[0].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
|
||||
ok(items[1].iCharPos == 6, "Wrong CharPos \n");
|
||||
ok(items[1].a.fRTL == 1, "Wrong fRTL\n");
|
||||
ok(items[1].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[1].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
|
||||
ok(items[2].iCharPos == 13, "Wrong CharPos \n");
|
||||
ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
|
||||
todo_wine ok(items[2].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[2].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
|
||||
ok(items[3].iCharPos == 15, "Wrong CharPos \n");
|
||||
ok(items[3].a.fRTL == 1, "Wrong fRTL\n");
|
||||
ok(items[3].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[3].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
|
||||
|
||||
hr = ScriptItemize(test3, 41, 10, NULL, NULL, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 1, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
|
||||
State.uBidiLevel = 0;
|
||||
hr = ScriptItemize(test3, 41, 10, &Control, &State, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 1, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
|
||||
State.uBidiLevel = 1;
|
||||
hr = ScriptItemize(test3, 41, 10, &Control, &State, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 1, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
todo_wine ok(items[0].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
|
||||
|
||||
hr = ScriptItemize(test4, 12, 10, NULL, NULL, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 5, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[1].iCharPos == 3, "Wrong CharPos \n");
|
||||
ok(items[1].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[1].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[1].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[2].iCharPos == 4, "Wrong CharPos \n");
|
||||
ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[2].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[2].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[3].iCharPos == 7, "Wrong CharPos \n");
|
||||
ok(items[3].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[3].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[3].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[4].iCharPos == 10, "Wrong CharPos \n");
|
||||
ok(items[4].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[4].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[4].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
|
||||
State.uBidiLevel = 0;
|
||||
hr = ScriptItemize(test4, 12, 10, &Control, &State, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 5, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[1].iCharPos == 3, "Wrong CharPos \n");
|
||||
ok(items[1].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[1].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[1].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[2].iCharPos == 4, "Wrong CharPos \n");
|
||||
ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[2].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[2].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[3].iCharPos == 7, "Wrong CharPos \n");
|
||||
ok(items[3].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[3].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[3].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
ok(items[4].iCharPos == 10, "Wrong CharPos \n");
|
||||
ok(items[4].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[4].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[4].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
|
||||
|
||||
State.uBidiLevel = 1;
|
||||
hr = ScriptItemize(test4, 12, 10, &Control, &State, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
todo_wine ok(nItems == 4, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
|
||||
todo_wine ok(items[0].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
|
||||
ok(items[1].iCharPos == 6, "Wrong CharPos \n");
|
||||
ok(items[1].a.fRTL == 1, "Wrong fRTL\n");
|
||||
ok(items[1].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[1].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
|
||||
ok(items[2].iCharPos == 7, "Wrong CharPos \n");
|
||||
ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[2].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
ok(items[2].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
|
||||
todo_wine ok(items[3].iCharPos == 10, "Wrong CharPos \n");
|
||||
ok(items[3].a.fRTL == 0, "Wrong fRTL\n");
|
||||
ok(items[3].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
|
||||
todo_wine ok(items[3].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
|
||||
|
||||
hr = ScriptItemize(test5, 38, 10, NULL, NULL, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 1, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 1, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
|
||||
|
||||
State.uBidiLevel = 0;
|
||||
hr = ScriptItemize(test5, 38, 10, &Control, &State, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 1, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 1, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
|
||||
|
||||
State.uBidiLevel = 1;
|
||||
hr = ScriptItemize(test5, 38, 10, &Control, &State, items, &nItems);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(nItems == 1, "Wrong number of items\n");
|
||||
ok(items[0].iCharPos == 0, "Wrong CharPos \n");
|
||||
ok(items[0].a.fRTL == 1, "Wrong fRTL\n");
|
||||
ok(items[0].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
|
||||
ok(items[0].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
|
||||
}
|
||||
|
||||
|
||||
static void test_ScriptShape(HDC hdc)
|
||||
{
|
||||
static const WCHAR test1[] = {'t', 'e', 's', 't',0};
|
||||
|
@ -43,12 +300,6 @@ static void test_ScriptShape(HDC hdc)
|
|||
GOFFSET offset[4];
|
||||
ABC abc[4];
|
||||
|
||||
hr = ScriptItemize(NULL, 4, 2, NULL, NULL, items, NULL);
|
||||
ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr);
|
||||
|
||||
hr = ScriptItemize(test1, 4, 2, NULL, NULL, NULL, NULL);
|
||||
ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr);
|
||||
|
||||
hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL);
|
||||
ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
|
||||
ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
|
||||
|
@ -143,28 +394,6 @@ static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256
|
|||
ok( ppSp[5]->langid == 9, "Langid[5] not = to 9\n"); /* Check a known value to ensure */
|
||||
/* ptrs work */
|
||||
|
||||
|
||||
/* This set of tests are to check that the various edits in ScriptIemize work */
|
||||
cInChars = 5; /* Length of test without NULL */
|
||||
cMaxItems = 1; /* Check threshold value */
|
||||
hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
|
||||
ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cMaxItems < 2. Was %d\n",
|
||||
cMaxItems);
|
||||
cInChars = 5;
|
||||
cMaxItems = 255;
|
||||
hr = ScriptItemize(NULL, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
|
||||
ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pwcInChars is NULL\n");
|
||||
|
||||
cInChars = 5;
|
||||
cMaxItems = 255;
|
||||
hr = ScriptItemize(TestItem1, 0, cMaxItems, NULL, NULL, pItem, &pcItems);
|
||||
ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cInChars is 0\n");
|
||||
|
||||
cInChars = 5;
|
||||
cMaxItems = 255;
|
||||
hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, NULL, &pcItems);
|
||||
ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pItems is NULL\n");
|
||||
|
||||
/* This is a valid test that will cause parsing to take place */
|
||||
cInChars = 5;
|
||||
cMaxItems = 255;
|
||||
|
@ -1397,6 +1626,7 @@ START_TEST(usp10)
|
|||
|
||||
hfont = SelectObject(hdc, CreateFontIndirectA(&lf));
|
||||
|
||||
test_ScriptItemize();
|
||||
test_ScriptItemIzeShapePlace(hdc,pwOutGlyphs);
|
||||
test_ScriptGetCMap(hdc, pwOutGlyphs);
|
||||
test_ScriptCacheGetHeight(hdc);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright 2005 Steven Edwards for CodeWeavers
|
||||
* Copyright 2006 Hans Leidekker
|
||||
* Copyright 2010 CodeWeavers, Aric Stewart
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -32,6 +33,8 @@
|
|||
#include "winnls.h"
|
||||
#include "usp10.h"
|
||||
|
||||
#include "usp10_internal.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
|
@ -524,6 +527,7 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
|
|||
|
||||
int cnt = 0, index = 0;
|
||||
int New_Script = SCRIPT_UNDEFINED;
|
||||
WORD *levels = NULL;
|
||||
|
||||
TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
|
||||
psControl, psState, pItems, pcItems);
|
||||
|
@ -531,6 +535,24 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
|
|||
if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (psState && psControl)
|
||||
{
|
||||
int i;
|
||||
levels = heap_alloc_zero(cInChars * sizeof(WORD));
|
||||
if (!levels)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels);
|
||||
for (i = 0; i < cInChars; i++)
|
||||
if (levels[i]!=levels[0])
|
||||
break;
|
||||
if (i >= cInChars)
|
||||
{
|
||||
heap_free(levels);
|
||||
levels = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pItems[index].iCharPos = 0;
|
||||
memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
|
||||
|
||||
|
@ -549,15 +571,29 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
|
|||
if (pwcInChars[cnt] >= Latin_start && pwcInChars[cnt] <= Latin_stop)
|
||||
pItems[index].a.eScript = Script_Latin;
|
||||
|
||||
if (pItems[index].a.eScript == Script_Arabic)
|
||||
if (levels)
|
||||
{
|
||||
pItems[index].a.fRTL = odd(levels[cnt]);
|
||||
pItems[index].a.fLayoutRTL = odd(levels[cnt]);
|
||||
pItems[index].a.s.uBidiLevel = levels[cnt];
|
||||
}
|
||||
else if (pItems[index].a.eScript == Script_Arabic)
|
||||
{
|
||||
pItems[index].a.s.uBidiLevel = 1;
|
||||
pItems[index].a.fRTL = 1;
|
||||
pItems[index].a.fLayoutRTL = 1;
|
||||
}
|
||||
|
||||
TRACE("New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
|
||||
New_Script, pItems[index].a.eScript, index, cnt,
|
||||
|
||||
TRACE("New_Level=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
|
||||
levels?levels[cnt]:-1, New_Script, pItems[index].a.eScript, index, cnt,
|
||||
pItems[index].iCharPos);
|
||||
|
||||
for (cnt=1; cnt < cInChars; cnt++)
|
||||
{
|
||||
if (levels && (levels[cnt] == pItems[index].a.s.uBidiLevel))
|
||||
continue;
|
||||
|
||||
if (pwcInChars[cnt] == '\r')
|
||||
New_Script = Script_CR;
|
||||
else
|
||||
|
@ -578,9 +614,9 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
|
|||
else
|
||||
New_Script = SCRIPT_UNDEFINED;
|
||||
|
||||
if (New_Script != pItems[index].a.eScript)
|
||||
if ((levels && (levels[cnt] != pItems[index].a.s.uBidiLevel)) || New_Script != pItems[index].a.eScript)
|
||||
{
|
||||
TRACE("New_Script=%d, eScript=%d ", New_Script, pItems[index].a.eScript);
|
||||
TRACE("New_Level = %i, New_Script=%d, eScript=%d ", levels?levels[cnt]:-1, New_Script, pItems[index].a.eScript);
|
||||
index++;
|
||||
if (index+1 > cMaxItems)
|
||||
return E_OUTOFMEMORY;
|
||||
|
@ -588,9 +624,18 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
|
|||
pItems[index].iCharPos = cnt;
|
||||
memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
|
||||
|
||||
if (New_Script == Script_Arabic)
|
||||
if (levels)
|
||||
{
|
||||
pItems[index].a.fRTL = odd(levels[cnt]);
|
||||
pItems[index].a.fLayoutRTL = odd(levels[cnt]);
|
||||
pItems[index].a.s.uBidiLevel = levels[cnt];
|
||||
}
|
||||
else if (New_Script == Script_Arabic)
|
||||
{
|
||||
pItems[index].a.s.uBidiLevel = 1;
|
||||
|
||||
pItems[index].a.fRTL = 1;
|
||||
pItems[index].a.fLayoutRTL = 1;
|
||||
}
|
||||
pItems[index].a.eScript = New_Script;
|
||||
|
||||
TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
|
||||
|
@ -610,6 +655,7 @@ HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItem
|
|||
/* Set SCRIPT_ITEM */
|
||||
pItems[index+1].iCharPos = cnt; /* the last + 1 item
|
||||
contains the ptr to the lastchar */
|
||||
heap_free(levels);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Implementation of Uniscribe Script Processor (usp10.dll)
|
||||
*
|
||||
* Copyright 2010 CodeWeavers, Aric Stewart
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*/
|
||||
|
||||
#define odd(x) ((x) & 1)
|
||||
|
||||
BOOL BIDI_DetermineLevels( LPCWSTR lpString, INT uCount, const SCRIPT_STATE *s,
|
||||
const SCRIPT_CONTROL *c, WORD *lpOutLevels );
|
Loading…
Reference in New Issue