gdi32: Use usp10 to optionally generate glyphs for bidi strings.

This commit is contained in:
Aric Stewart 2010-05-13 10:43:26 -05:00 committed by Alexandre Julliard
parent 745b5fe8f1
commit 2a8958ec18
3 changed files with 142 additions and 61 deletions

View File

@ -283,46 +283,12 @@ static void resolveWhitespace(int baselevel, const WORD *pcls, BYTE *plevel, int
SetDeferredRun(plevel, cchrun, ich, baselevel);
}
/* 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 BYTE* 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
@ -330,7 +296,7 @@ static void mirror(LPWSTR pszInput, const BYTE* plevel, int cch)
------------------------------------------------------------------------*/
static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, WORD * pclsLine,
BYTE * plevelLine, int cchPara, int fMirror, BOOL * pbrk)
BYTE * plevelLine, int cchPara, BOOL * pbrk)
{
int cchLine = 0;
int done = 0;
@ -354,9 +320,6 @@ 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 */
ScriptLayout(cchLine, plevelLine, run, NULL);
for (i = 0; i < cchLine; i++)
@ -377,20 +340,24 @@ static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, WORD *
/*************************************************************
* BIDI_Reorder
*
* Returns TRUE if reordering was required and done.
*/
BOOL BIDI_Reorder(
HDC hDC, /*[in] Display DC */
LPCWSTR lpString, /* [in] The string for which information is to be returned */
INT uCount, /* [in] Number of WCHARs in string. */
DWORD dwFlags, /* [in] GetCharacterPlacement compatible flags specifying how to process the string */
DWORD dwWineGCP_Flags, /* [in] Wine internal flags - Force paragraph direction */
LPWSTR lpOutString, /* [out] Reordered string */
INT uCountOut, /* [in] Size of output buffer */
UINT *lpOrder /* [out] Logical -> Visual order map */
UINT *lpOrder, /* [out] Logical -> Visual order map */
WORD **lpGlyphs /* [out] reordered, mirrored, shaped glyphs to display */
)
{
WORD *chartype;
BYTE *levels;
unsigned i, done;
unsigned i, done, glyph_i;
int maxItems;
int nItems;
@ -398,6 +365,12 @@ BOOL BIDI_Reorder(
SCRIPT_STATE State;
SCRIPT_ITEM *pItems;
HRESULT res;
SCRIPT_CACHE psc = NULL;
WORD *run_glyphs = NULL;
WORD *pwLogClust = NULL;
SCRIPT_VISATTR *psva = NULL;
DWORD cMaxGlyphs = 0;
BOOL doGlyphs = TRUE;
TRACE("%s, %d, 0x%08x lpOutString=%p, lpOrder=%p\n",
debugstr_wn(lpString, uCount), uCount, dwFlags,
@ -405,6 +378,8 @@ BOOL BIDI_Reorder(
memset(&Control, 0, sizeof(Control));
memset(&State, 0, sizeof(State));
if (lpGlyphs)
*lpGlyphs = NULL;
if (!(dwFlags & GCP_REORDER))
{
@ -412,7 +387,7 @@ BOOL BIDI_Reorder(
return FALSE;
}
if (uCountOut < uCount)
if (lpOutString && uCountOut < uCount)
{
FIXME("lpOutString too small\n");
return FALSE;
@ -471,7 +446,43 @@ BOOL BIDI_Reorder(
return FALSE;
}
if (lpGlyphs)
{
cMaxGlyphs = 1.5 * uCount + 16;
run_glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * cMaxGlyphs);
if (!run_glyphs)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
return FALSE;
}
pwLogClust = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * uCount);
if (!pwLogClust)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
HeapFree(GetProcessHeap(), 0, run_glyphs);
return FALSE;
}
psva = HeapAlloc(GetProcessHeap(),0,sizeof(SCRIPT_VISATTR) * uCount);
if (!psva)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
HeapFree(GetProcessHeap(), 0, run_glyphs);
HeapFree(GetProcessHeap(), 0, pwLogClust);
return FALSE;
}
}
done = 0;
glyph_i = 0;
while (done < uCount)
{
unsigned j;
@ -523,20 +534,23 @@ BOOL BIDI_Reorder(
res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems);
}
for (j = 0; j < nItems; j++)
if (lpOutString || lpOrder)
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;
}
if (lpOutString)
{
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(State.uBidiLevel, lpOutString + done, lpString + done,
chartype, levels, i, 0);
}
/* assign directional types again, but for WS, S this time */
classify(lpString + done, chartype, i);
BidiLines(State.uBidiLevel, lpOutString ? lpOutString + done : NULL, lpString + done,
chartype, levels, i, !(dwFlags & GCP_SYMSWAPOFF), 0);
if (lpOrder)
{
int k, lastgood;
@ -559,11 +573,77 @@ BOOL BIDI_Reorder(
for (k = lastgood; k < j; ++k)
lpOrder[done + k] = done + k;
}
if (lpGlyphs && doGlyphs)
{
int j;
BYTE runOrder[maxItems];
int visOrder[maxItems];
SCRIPT_ITEM *curItem;
for (j = 0; j < nItems; j++)
runOrder[j] = pItems[j].a.s.uBidiLevel;
ScriptLayout(nItems, runOrder, NULL, visOrder);
for (j = 0; j < nItems; j++)
{
int k;
int cChars,cOutGlyphs;
curItem = &pItems[visOrder[j]];
cChars = pItems[visOrder[j]+1].iCharPos - curItem->iCharPos;
res = ScriptShape(hDC, &psc, lpString + done + curItem->iCharPos, cChars, cMaxGlyphs, &curItem->a, run_glyphs, pwLogClust, psva, &cOutGlyphs);
while (res == E_OUTOFMEMORY)
{
cMaxGlyphs *= 2;
run_glyphs = HeapReAlloc(GetProcessHeap(), 0, run_glyphs, sizeof(WORD) * cMaxGlyphs);
if (!run_glyphs)
{
WARN("Out of memory\n");
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
HeapFree(GetProcessHeap(), 0, psva);
HeapFree(GetProcessHeap(), 0, pwLogClust);
HeapFree(GetProcessHeap(), 0, *lpGlyphs);
ScriptFreeCache(&psc);
*lpGlyphs = NULL;
return FALSE;
}
res = ScriptShape(hDC, &psc, lpString + done + curItem->iCharPos, cChars, cMaxGlyphs, &curItem->a, run_glyphs, pwLogClust, psva, &cOutGlyphs);
}
if (res && res != USP_E_SCRIPT_NOT_IN_FONT)
{
FIXME("Unable to shape string (%x)\n",res);
j = nItems;
doGlyphs = FALSE;
HeapFree(GetProcessHeap(), 0, *lpGlyphs);
*lpGlyphs = NULL;
}
else
{
if (*lpGlyphs)
*lpGlyphs = HeapReAlloc(GetProcessHeap(), 0, *lpGlyphs, sizeof(WORD) * (glyph_i + cOutGlyphs));
else
*lpGlyphs = HeapAlloc(GetProcessHeap(), 0, sizeof(WORD) * (glyph_i + cOutGlyphs));
for (k = 0; k < cOutGlyphs; k++)
(*lpGlyphs)[glyph_i+k] = run_glyphs[k];
glyph_i += cOutGlyphs;
}
}
}
done += i;
}
HeapFree(GetProcessHeap(), 0, chartype);
HeapFree(GetProcessHeap(), 0, levels);
HeapFree(GetProcessHeap(), 0, pItems);
HeapFree(GetProcessHeap(), 0, run_glyphs);
HeapFree(GetProcessHeap(), 0, pwLogClust);
HeapFree(GetProcessHeap(), 0, psva);
ScriptFreeCache(&psc);
return TRUE;
}

View File

@ -1704,20 +1704,21 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
{
reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
BIDI_Reorder( str, count, GCP_REORDER,
BIDI_Reorder( hdc, str, count, GCP_REORDER,
((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)?
WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR,
reordered_str, count, NULL );
reordered_str, count, NULL, &glyphs );
flags |= ETO_IGNORELANGUAGE;
if (glyphs)
flags |= ETO_GLYPH_INDEX;
}
else if(flags & ETO_GLYPH_INDEX)
glyphs = reordered_str;
TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
lprect, debugstr_wn(str, count), count, lpDx);
if(flags & ETO_GLYPH_INDEX)
glyphs = reordered_str;
if(lprect)
TRACE("rect: %d,%d - %d,%d\n", lprect->left, lprect->top, lprect->right,
lprect->bottom);
@ -2872,8 +2873,8 @@ GetCharacterPlacementW(
}
} else
{
BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
nSet, lpResults->lpOrder );
BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
nSet, lpResults->lpOrder, NULL );
}
/* FIXME: Will use the placement chars */

View File

@ -355,8 +355,8 @@ typedef struct tagBITMAPOBJ
#define WINE_GCPW_DIR_MASK 3
#define WINE_GCPW_LOOSE_MASK 2
extern BOOL BIDI_Reorder( LPCWSTR lpString, INT uCount, DWORD dwFlags, DWORD dwWineGCP_Flags,
LPWSTR lpOutString, INT uCountOut, UINT *lpOrder ) DECLSPEC_HIDDEN;
extern BOOL BIDI_Reorder( HDC hDC, LPCWSTR lpString, INT uCount, DWORD dwFlags, DWORD dwWineGCP_Flags,
LPWSTR lpOutString, INT uCountOut, UINT *lpOrder, WORD **lpGlyphs ) DECLSPEC_HIDDEN;
/* bitmap.c */
extern HBITMAP BITMAP_CopyBitmap( HBITMAP hbitmap ) DECLSPEC_HIDDEN;