The code here is not cleaned up yet. There are still some duplications with the system GetCharacterPlacement. Also, order is not implemented yet.
Changelog Shachar Shemesh <winecode@shemesh.biz> objects/text.c
* Call internal version of GetCharacterPlacement, that knows how to handle paragraph direction properly (ExtTextOutW) * Add parsing to ExtTextOutW of flags to find out whether this is a right or left paragraph.
dlls/gdi/bidi.c
* Copied definition of the original GetCharacterPlacement. Replaced the BiDi code with a call to the ICU library. * Added extra argument to the internal GCP, to determine paragraph direction.
-- Shachar Shemesh Open Source integration consultant Home page & resume - http://www.shemesh.biz/
diff -u -r wine.ref/dlls/gdi/bidi.c wine.patch/dlls/gdi/bidi.c --- wine.ref/dlls/gdi/bidi.c 2003-05-30 01:21:31.000000000 +0300 +++ wine.patch/dlls/gdi/bidi.c 2003-05-30 01:22:35.000000000 +0300 @@ -19,6 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <winbase.h> +#include <wingdi.h> #include <wine/debug.h> #include <wine/library.h> #include <dlfcn.h> @@ -34,7 +35,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(bidi); -BOOL BidiAvail=FALSE; +BOOL BidiAvail = FALSE; /************************************************************* * WineEngInit @@ -43,7 +44,124 @@ */ BOOL WineBidiInit(void) { - return TRUE; + BidiAvail=TRUE; + return BidiAvail; } -#endif /* HAVE_BIDI */ +DWORD Wine_GCPW(HDC hdc, /* [in] Device context for which the rendering is to be done */ + LPCWSTR lpString, /* [in] The string for which information is to be returned */ + INT uCount, /* [in] Number of WORDS in string. */ + INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */ + GCP_RESULTSW * lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */ + DWORD dwFlags, /* [in] Flags specifying how to process the string */ + DWORD dwWineGCP_Flags /* [in] Wine internal flags - Force paragraph direction */ + ) +{ + DWORD ret = 0; + SIZE size; + UINT i, nSet; + + TRACE("%s, %d, %d, 0x%08lx\n", + debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags); + + TRACE + ("lStructSize=%ld, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n" + "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n", + lpResults->lStructSize, lpResults->lpOutString, + lpResults->lpOrder, lpResults->lpDx, lpResults->lpCaretPos, + lpResults->lpClass, lpResults->lpGlyphs, lpResults->nGlyphs, + lpResults->nMaxFit); + + if (dwFlags & (~GCP_REORDER)) + FIXME("flags 0x%08lx ignored\n", dwFlags); + if (lpResults->lpCaretPos) + FIXME("caret positions not implemented\n"); + if (lpResults->lpClass) + FIXME("classes not implemented\n"); + + nSet = (UINT) uCount; + if (nSet > lpResults->nGlyphs) + nSet = lpResults->nGlyphs; + + /* return number of initialized fields */ + lpResults->nGlyphs = nSet; + + if (dwFlags == 0) { + /* Treat the case where no special handling was requested in a fastpath way */ + /* copy will do if the GCP_REORDER flag is not set */ + if (lpResults->lpOutString) + for (i = 0; i < nSet && lpString[i] != 0; ++i) + lpResults->lpOutString[i] = lpString[i]; + + if (lpResults->lpOrder) { + for (i = 0; i < nSet; i++) + lpResults->lpOrder[i] = i; + } + } + + if ((dwFlags & GCP_REORDER) != 0) { + UBiDi *bidi; + UErrorCode err=0; + UBiDiLevel level; + + bidi=ubidi_open(); + if( bidi==NULL ) { + WARN("Failed to allocate structure\n"); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + + switch( dwWineGCP_Flags&WINE_GCPW_DIR_MASK ) + { + case WINE_GCPW_FORCE_LTR: + level=0; + break; + case WINE_GCPW_FORCE_RTL: + level=1; + break; + case WINE_GCPW_LOOSE_LTR: + level=UBIDI_DEFAULT_LTR; + break; + case WINE_GCPW_LOOSE_RTL: + level=UBIDI_DEFAULT_RTL; + break; + } + + ubidi_setPara( bidi, lpString, uCount, level, NULL, &err ); + if( lpResults->lpOutString!=NULL ) { + ubidi_writeReordered( bidi, lpResults->lpOutString, uCount, + (dwFlags&GCP_SYMSWAPOFF)?0:UBIDI_DO_MIRRORING, &err ); + } + + ubidi_close( bidi ); + + if( U_FAILURE(err) ) { + FIXME("ICU Library return error code %d.\n", err ); + FIXME("Please report this error to wine-devel@winehq.org so we can place " + "descriptive Windows error codes here\n"); + SetLastError(ERROR_INVALID_LEVEL); /* This error is cryptic enough not to mean anything, I hope */ + + return 0; + } + } + + /* FIXME: Will use the placement chars */ + if (lpResults->lpDx) { + int c; + for (i = 0; i < nSet; i++) { + if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c)) + lpResults->lpDx[i] = c; + } + } + + if (lpResults->lpGlyphs) + GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0); + + if (GetTextExtentPoint32W(hdc, lpString, uCount, &size)) + ret = MAKELONG(size.cx, size.cy); + + return ret; +} + +#endif /* HAVE_BIDI */ + diff -u -r wine.ref/dlls/gdi/gdibidi.h wine.patch/dlls/gdi/gdibidi.h --- wine.ref/dlls/gdi/gdibidi.h 2003-05-30 01:21:31.000000000 +0300 +++ wine.patch/dlls/gdi/gdibidi.h 2003-05-30 01:22:41.000000000 +0300 @@ -28,15 +28,38 @@ BOOL WineBidiInit(void); +DWORD Wine_GCPW(HDC hdc, /* [in] Device context for which the rendering is to be done */ + LPCWSTR lpString, /* [in] The string for which information is to be returned */ + INT uCount, /* [in] Number of WORDS in string. */ + INT nMaxExtent, /* [in] Maximum extent the string is to take (in HDC logical units) */ + GCP_RESULTSW * lpResults, /* [in/out] A pointer to a GCP_RESULTSW struct */ + DWORD dwFlags, /* [in] Flags specifying how to process the string */ + DWORD dwWineFlags /* [in] Wine internal flags - Force paragraph direction */ + ); + #define HAVE_BIDI 1 #else /* HAVE_ICU */ -#define BidiAvail FALSE -#define WineBidiInit() FALSE +/* Replace all the functions with their return code on error */ +#define BidiAvail (FALSE) +#define WineBidiInit() (FALSE) + +#define Wine_GCPW(p1,p2,p3,p4,p5,p6,p7) (0) #undef HAVE_BIDI #endif /* HAVE_ICU */ +/* Wine_GCPW Flags */ +/* Directionality - + * LOOSE means that the paragraph dir is only set if there is no strong character. + * FORCE means override the characters in the paragraph. + */ +#define WINE_GCPW_FORCE_LTR 0 +#define WINE_GCPW_FORCE_RTL 1 +#define WINE_GCPW_LOOSE_LTR 2 +#define WINE_GCPW_LOOSE_RTL 3 +#define WINE_GCPW_DIR_MASK 3 + #endif /* __WINE_GDI_BIDI_H */ diff -u -r wine.ref/objects/text.c wine.patch/objects/text.c --- wine.ref/objects/text.c 2003-03-24 21:27:53.000000000 +0200 +++ wine.patch/objects/text.c 2003-05-30 01:22:20.000000000 +0300 @@ -2,6 +2,7 @@ * text functions * * Copyright 1993, 1994 Alexandre Julliard + * Copyright 2003 Shachar Shemesh * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,14 +21,16 @@ #include <string.h> -#include "windef.h" -#include "wingdi.h" -#include "wine/winuser16.h" -#include "winbase.h" -#include "winerror.h" -#include "gdi.h" -#include "wine/debug.h" -#include "winnls.h" +#include <windef.h> +#include <wingdi.h> +#include <wine/winuser16.h> +#include <winbase.h> +#include <winerror.h> +#include <gdi.h> +#include <wine/debug.h> +#include <winnls.h> + +#include "gdibidi.h" WINE_DEFAULT_DEBUG_CHANNEL(text); @@ -157,10 +160,9 @@ FIXME("called on an open path\n"); else if(dc->funcs->pExtTextOut) { - if( !(flags&(ETO_GLYPH_INDEX|ETO_IGNORELANGUAGE)) ) + if( !(flags&(ETO_GLYPH_INDEX|ETO_IGNORELANGUAGE)) && BidiAvail ) { - /* The caller did not specify that language processing was already done, - * and the font idetifies iteself as requiring language processing. + /* The caller did not specify that language processing was already done. */ GCP_RESULTSW gcp; @@ -174,7 +176,9 @@ gcp.nGlyphs=0; gcp.nMaxFit=0; - GetCharacterPlacementW(hdc, str, count, 0, &gcp, GCP_REORDER ); + Wine_GCPW(hdc, str, count, 0, &gcp, GCP_REORDER, + ((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)? + WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR ); ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags|ETO_IGNORELANGUAGE, lprect,gcp.lpOutString,count,lpDx);