Changelog: Shachar Shemesh <winecode@shemesh.biz>
* dlls/gdi/bidi.c, dlls/gdi/gdibidi.h and dlls/gdi/Makefile.in o Implementation of the reordering algorithm by calling ICU's reordering functions. o Adding the new files to the makefile * objects/gdiobj.c o Initializing the new subsystem. * objects/test.c and objects/font.c o Calling the Bidi infrastructure from bidi.c instead of implementing small, insufficient parts of the BiDi algorithm inline. * include/config.h.in o Added HAVE_ICU and HAVE_UNICODE_UBIDI_H to the config header file (configure is already checking for these, and will correctly generate them).
Enjoy!
-- Shachar Shemesh Open Source integration consultant Home page & resume - http://www.shemesh.biz/
Index: dlls/gdi/Makefile.in =================================================================== RCS file: /home/sun/sources/cvs/wine/dlls/gdi/Makefile.in,v retrieving revision 1.52 diff -u -r1.52 Makefile.in --- dlls/gdi/Makefile.in 20 Jun 2003 21:38:10 -0000 1.52 +++ dlls/gdi/Makefile.in 21 Jun 2003 05:31:18 -0000 @@ -41,6 +41,7 @@ $(TOPOBJDIR)/objects/pen.c \ $(TOPOBJDIR)/objects/region.c \ $(TOPOBJDIR)/objects/text.c \ + bidi.c \ driver.c \ enhmfdrv/bitblt.c \ enhmfdrv/dc.c \ Index: include/config.h.in =================================================================== RCS file: /home/sun/sources/cvs/wine/include/config.h.in,v retrieving revision 1.157 diff -u -r1.157 config.h.in --- include/config.h.in 20 Jun 2003 23:26:56 -0000 1.157 +++ include/config.h.in 21 Jun 2003 05:24:57 -0000 @@ -77,6 +77,12 @@ /* Define to 1 if you have the `fpclass' function. */ #undef HAVE_FPCLASS +/* Define if the ICU library is available for static linking */ +#undef HAVE_ICU + +/* Define if the bidi header is available for ICU */ +#undef HAVE_UNICODE_UBIDI_H + /* Define if FreeType 2 is installed */ #undef HAVE_FREETYPE Index: objects/font.c =================================================================== RCS file: /home/sun/sources/cvs/wine/objects/font.c,v retrieving revision 1.100 diff -u -r1.100 font.c --- objects/font.c 23 Jun 2003 20:51:06 -0000 1.100 +++ objects/font.c 24 Jun 2003 18:45:25 -0000 @@ -3,6 +3,7 @@ * * Copyright 1993 Alexandre Julliard * 1997 Alex Korobka + * Copyright 2002,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 @@ -19,18 +20,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "config.h" -#include "wine/port.h" +#include <config.h> +#include <wine/port.h> #include <stdlib.h> #include <string.h> #include <assert.h> -#include "winerror.h" -#include "winnls.h" -#include "wownt32.h" -#include "gdi.h" -#include "wine/unicode.h" -#include "wine/debug.h" +#include <winerror.h> +#include <winnls.h> +#include <wownt32.h> +#include <gdi.h> +#include <wine/unicode.h> +#include <wine/debug.h> +#include "gdibidi.h" WINE_DEFAULT_DEBUG_CHANNEL(font); WINE_DECLARE_DEBUG_CHANNEL(gdi); @@ -1989,105 +1991,22 @@ /* return number of initialized fields */ lpResults->nGlyphs = nSet; - if(dwFlags==0) + if((dwFlags&GCP_REORDER)==0 || !BidiAvail) { /* 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]; + strncpyW( lpResults->lpOutString, lpString, nSet ); if(lpResults->lpOrder) { for(i = 0; i < nSet; i++) lpResults->lpOrder[i] = i; } - } - - if((dwFlags&GCP_REORDER)!=0) + } else { - WORD *pwCharType; - int run_end; - /* Keep a static table that translates the C2 types to something meaningful */ - /* 1 - left to right - * -1 - right to left - * 0 - neutral - */ - static const int chardir[]={ 0, 1, -1, 1, 0, 0, -1, 0, 0, 0, 0, 0 }; - - WARN("The BiDi algorythm doesn't conform to Windows' yet\n"); - if( (pwCharType=HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD)))==NULL ) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - - return 0; - } - - /* Fill in the order array with directionality values */ - GetStringTypeW(CT_CTYPE2, lpString, uCount, pwCharType); - - /* The complete and correct (at least according to MS) BiDi algorythm is not - * yet implemented here. Instead, we just make sure that consecutive runs of - * the same direction (or neutral) are ordered correctly. We also assign Neutrals - * that are between runs of opposing directions the base (ok, always LTR) dir. - * While this is a LONG way from a BiDi algorithm, it does produce more or less - * readable results. - */ - for( i=0; i<uCount; i+=run_end ) - { - for( run_end=1; i+run_end<uCount && - (chardir[pwCharType[i+run_end]]==chardir[pwCharType[i]] || - chardir[pwCharType[i+run_end]]==0); ++run_end ) - ; - - if( chardir[pwCharType[i]]==1 || chardir[pwCharType[i]]==0 ) - { - /* A LTR run */ - if(lpResults->lpOutString) - { - int j; - for( j=0; j<run_end; j++ ) - { - lpResults->lpOutString[i+j]=lpString[i+j]; - } - } - - if(lpResults->lpOrder) - { - int j; - for( j=0; j<run_end; j++ ) - lpResults->lpOrder[i+j] = i+j; - } - } else - { - /* A RTL run */ - - /* Since, at this stage, the paragraph context is always LTR, - * remove any neutrals from the end of this run. - */ - if( chardir[pwCharType[i]]!=0 ) - while( chardir[pwCharType[i+run_end-1]]==0 ) - --run_end; - - if(lpResults->lpOutString) - { - int j; - for( j=0; j<run_end; j++ ) - { - lpResults->lpOutString[i+j]=lpString[i+run_end-j-1]; - } - } - - if(lpResults->lpOrder) - { - int j; - for( j=0; j<run_end; j++ ) - lpResults->lpOrder[i+j] = i+run_end-j-1; - } - } - } - - HeapFree(GetProcessHeap(), 0, pwCharType); + Wine_BiDi_reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString, + nSet, lpResults->lpOrder ); } /* FIXME: Will use the placement chars */ Index: objects/gdiobj.c =================================================================== RCS file: /home/sun/sources/cvs/wine/objects/gdiobj.c,v retrieving revision 1.87 diff -u -r1.87 gdiobj.c --- objects/gdiobj.c 21 May 2003 18:28:49 -0000 1.87 +++ objects/gdiobj.c 14 Jun 2003 14:44:31 -0000 @@ -34,6 +34,7 @@ #include "palette.h" #include "gdi.h" #include "wine/debug.h" +#include "gdibidi.h" WINE_DEFAULT_DEBUG_CHANNEL(gdi); @@ -627,6 +628,8 @@ if (hkey) RegCloseKey( hkey ); WineEngInit(); + + WineBidiInit(); return TRUE; } Index: objects/text.c =================================================================== RCS file: /home/sun/sources/cvs/wine/objects/text.c,v retrieving revision 1.52 diff -u -r1.52 text.c --- objects/text.c 23 Jun 2003 20:51:06 -0000 1.52 +++ objects/text.c 24 Jun 2003 18:45:25 -0000 @@ -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,28 +160,20 @@ 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; - - gcp.lStructSize=sizeof(gcp); - gcp.lpOutString=HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR)); - gcp.lpOrder=NULL; - gcp.lpDx=NULL; - gcp.lpCaretPos=NULL; - gcp.lpClass=NULL; - gcp.lpGlyphs=NULL; - gcp.nGlyphs=0; - gcp.nMaxFit=0; + LPWSTR lpReorderedString=HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR)); - GetCharacterPlacementW(hdc, str, count, 0, &gcp, GCP_REORDER ); + Wine_BiDi_reorder( str, count, GCP_REORDER, + ((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)? + WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR, + lpReorderedString, count, NULL ); ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags|ETO_IGNORELANGUAGE, - lprect,gcp.lpOutString,count,lpDx); - HeapFree(GetProcessHeap(), 0, gcp.lpOutString); + lprect,lpReorderedString,count,lpDx); + HeapFree(GetProcessHeap(), 0, lpReorderedString); } else ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags,lprect,str,count,lpDx); } --- /dev/null 2003-01-06 20:21:43.000000000 +0200 +++ dlls/gdi/bidi.c 2003-05-31 15:52:20.000000000 +0300 @@ -0,0 +1,120 @@ + +/* + * GDI BiDirectional handling + * + * 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 + * 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., 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> + +/* As this is not an exported include, it's important not to turn it into a <> + * quotes + */ +#include "gdibidi.h" + +#if HAVE_BIDI + +#include <unicode/ubidi.h> + +WINE_DEFAULT_DEBUG_CHANNEL(bidi); + +BOOL BidiAvail = FALSE; + +/************************************************************* + * WineEngInit + * + * Initialize FreeType library and create a list of available faces + */ +BOOL WineBidiInit(void) +{ + BidiAvail=TRUE; + return BidiAvail; +} + +BOOL Wine_BiDi_reorder( + 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 */ + ) +{ + TRACE("%s, %d, 0x%08lx\n", + debugstr_wn(lpString, uCount), uCount, dwFlags); + + TRACE("lpOutString=%p, lpOrder=%p", lpOutString, lpOrder ); + + 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 FALSE; + } + + 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( lpOutString!=NULL ) { + ubidi_writeReordered( bidi, lpOutString, uCount, + (dwFlags&GCP_SYMSWAPOFF)?0:UBIDI_DO_MIRRORING, &err ); + } + + if( lpOrder!=NULL ) { + ubidi_getLogicalMap( bidi, lpOrder, &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 FALSE; + } + } + + return TRUE; +} + +#endif /* HAVE_BIDI */ + --- /dev/null 2003-01-06 20:21:43.000000000 +0200 +++ dlls/gdi/gdibidi.h 2003-06-14 17:38:42.000000000 +0300 @@ -0,0 +1,65 @@ +/* + * GDI BiDi definitions + * + * 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 + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __WINE_GDI_BIDI_H +#define __WINE_GDI_BIDI_H + +#include <config.h> + +#if HAVE_ICU + +extern BOOL BidiAvail; + +BOOL WineBidiInit(void); + +BOOL Wine_BiDi_reorder( + 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 */ + ); + +#define HAVE_BIDI 1 + +#else /* HAVE_ICU */ + +/* Replace all the functions with their return code on error */ +#define BidiAvail (FALSE) +#define WineBidiInit() (FALSE) +#define Wine_BiDi_reorder(p1,p2,p3,p4,p5,p6,p7) (FALSE) + +#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 */