Implementation of the reordering algorithm by calling ICU's reordering
functions.
diff --git a/dlls/gdi/Makefile.in b/dlls/gdi/Makefile.in
index 9da6e23..f4692ff 100644
--- a/dlls/gdi/Makefile.in
+++ b/dlls/gdi/Makefile.in
@@ -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 \
diff --git a/dlls/gdi/bidi.c b/dlls/gdi/bidi.c
new file mode 100644
index 0000000..d3fe31b
--- /dev/null
+++ b/dlls/gdi/bidi.c
@@ -0,0 +1,114 @@
+
+/*
+ * 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 "config.h"
+
+#ifdef HAVE_UNICODE_UBIDI_H
+#include <unicode/ubidi.h>
+#endif
+
+#include "winbase.h"
+#include "wingdi.h"
+#include "wine/debug.h"
+#include "gdi.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(bidi);
+
+#if HAVE_ICU
+BOOL BidiAvail = TRUE;
+#else
+BOOL BidiAvail = FALSE;
+#endif
+
+
+/*************************************************************
+ * BIDI_Reorder
+ */
+BOOL 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 */
+ )
+{
+#ifdef HAVE_ICU
+ 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;
+#else /* HAVE_ICU */
+ return FALSE;
+#endif /* HAVE_ICU */
+}
diff --git a/include/gdi.h b/include/gdi.h
index 798ab63..2126756 100644
--- a/include/gdi.h
+++ b/include/gdi.h
@@ -464,6 +464,22 @@
extern void DC_InitDC( DC * dc );
extern void DC_UpdateXforms( DC * dc );
+/* bidi.c */
+
+/* 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
+extern BOOL BIDI_Reorder( LPCWSTR lpString, INT uCount, DWORD dwFlags, DWORD dwWineGCP_Flags,
+ LPWSTR lpOutString, INT uCountOut, UINT *lpOrder );
+extern BOOL BidiAvail;
+
/* clipping.c */
extern void CLIPPING_UpdateGCRegion( DC * dc );
diff --git a/objects/font.c b/objects/font.c
index a44bee2..d0063aa 100644
--- a/objects/font.c
+++ b/objects/font.c
@@ -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
@@ -1989,105 +1990,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);
+ BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
+ nSet, lpResults->lpOrder );
}
/* FIXME: Will use the placement chars */
diff --git a/objects/text.c b/objects/text.c
index b3b8570..c490940 100644
--- a/objects/text.c
+++ b/objects/text.c
@@ -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
@@ -155,34 +156,26 @@
{
if(PATH_IsPathOpen(dc->path))
FIXME("called on an open path\n");
- else if(dc->funcs->pExtTextOut)
- {
- if( !(flags&(ETO_GLYPH_INDEX|ETO_IGNORELANGUAGE)) )
- {
- /* The caller did not specify that language processing was already done,
- * and the font idetifies iteself as requiring language processing.
- */
- GCP_RESULTSW gcp;
+ else if(dc->funcs->pExtTextOut)
+ {
+ if( !(flags&(ETO_GLYPH_INDEX|ETO_IGNORELANGUAGE)) && BidiAvail )
+ {
+ /* The caller did not specify that language processing was already done.
+ */
+ LPWSTR lpReorderedString=HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
- 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;
+ 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 );
- GetCharacterPlacementW(hdc, str, count, 0, &gcp, GCP_REORDER );
-
- ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags|ETO_IGNORELANGUAGE,
- lprect,gcp.lpOutString,count,lpDx);
- HeapFree(GetProcessHeap(), 0, gcp.lpOutString);
- } else
- ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags,lprect,str,count,lpDx);
- }
- GDI_ReleaseObj( hdc );
+ ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags|ETO_IGNORELANGUAGE,
+ lprect,lpReorderedString,count,lpDx);
+ HeapFree(GetProcessHeap(), 0, lpReorderedString);
+ } else
+ ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags,lprect,str,count,lpDx);
+ }
+ GDI_ReleaseObj( hdc );
}
return ret;
}