diff --git a/dlls/gdi32/bidi.c b/dlls/gdi32/bidi.c index d4881530fd..20fde1385e 100644 --- a/dlls/gdi32/bidi.c +++ b/dlls/gdi32/bidi.c @@ -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; } diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index 50f2c5703a..963dadc8c4 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -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 */ diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index 766668b7a6..10ff13e73e 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -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;