Attached is an extremely preliminary BiDi patch. Here are the things this patch contains, and the points I would love to hear the list's comments about. This patch is under the LGPL only, at this stage. Changes: * Fixed the heb.nls file so that LANG=he_IL will be accepted * Implemented a skeleton for GetFontLanguageInfo. o I have filled in the skeleton where I knew what to fill it with. I would guess that a lot of stuff is still missing. o I would apretiate input on the aprorpiatness of using GetTextCharsetInfo as the source of information. o I have removed the FIXME, but a lot of stuff is still unimplemented. I didn't quite know what to put there instead. * GetCharacterPlacementW - This is certanly one of the more overloaded functions in the Win32 set (Select object comes to mind as a competitor, and this one has way more execution flows throught it). So far, as far as I could tell, only the flow that matched Latin fonts was implemented. I have added some (very basic) reordering. I would like to hear your comments about the following points: o I followed the autodocumentation instructions. Is this at all still supported or required? o The algorythm I used is far from a good one. It still doesn't support right to left paragraphs, neutral boundry characters, and a bunch of other necessary stuff. All it does, at the moment, is make sure consecutive runs of one direction are, more or less, readable. o I have added a fastpath option when no work is necassary. When all that is supported is reordering, this may make sense. However, I am somewhat worried that when kerning, ligation, glyphing etc. are added, the fastpath will be meaningless. Opinions? * ExtTextOutW o I am calling GetFontLanguageInfo for each and every ExtTextOutW (which is a focus point for all Text rendering functions). What performance implications will that have? Don't forget that what I pay for in asking whether reordering is necessary, I get back in not calling GetCharacterPlacementW, and in not allocating a buffer. Then again, some Unicode fonts will suffer both allocation and no reordering. o I am calling the backend text printing function in two flows. One is using the allocated buffer used for GetCharacterPlacementW, and the other is the original (no point in allocating a buffer if no processing was done). Should I work hard to merge the two calls? o I am assuming that the backend driver will not perform any reordering. I am not sure how correct that assumption is under, say, KDE3 (Hetz?). These are all the questions for the time being. I also need some explanation regarding procedures. Which of the following three are enough, on their own, to cause the patch to be integrated: 1. Attaching it to a bug (assuming that I am the bug's owner) 2. Sending the patch to wine-devel 3. Sending the patch to wine-patches Obviously, 3 is enough on it's own. Assuming I have questions, however, is 2 enough on its own? Is 1 at all necessary if I'm doing 2 or 3? Is this message off topic on wine-devel? on wine-patches? Shachar
Index: dlls/kernel/nls/heb.nls =================================================================== RCS file: /home/wine/wine/dlls/kernel/nls/heb.nls,v retrieving revision 1.3 diff -u -r1.3 heb.nls --- dlls/kernel/nls/heb.nls 19 May 2002 22:23:23 -0000 1.3 +++ dlls/kernel/nls/heb.nls 12 Jun 2002 19:34:02 -0000 @@ -128,6 +128,6 @@ /* LOCVAL(LOCALE_FONTSIGNATURE, "") */ LOCVAL(LOCALE_SISO639LANGNAME,"he") -LOCVAL(LOCALE_SISO3166CTRYNAME,"HE") +LOCVAL(LOCALE_SISO3166CTRYNAME,"IL") /* gregoriansk kalender */ Index: objects/font.c =================================================================== RCS file: /home/wine/wine/objects/font.c,v retrieving revision 1.74 diff -u -r1.74 font.c --- objects/font.c 4 Jun 2002 01:02:52 -0000 1.74 +++ objects/font.c 12 Jun 2002 19:34:04 -0000 @@ -2098,10 +2098,48 @@ /************************************************************************* * GetFontLanguageInfo (GDI32.@) */ -DWORD WINAPI GetFontLanguageInfo(HDC hdc) { - /* return value 0 is correct for most cases anyway */ - FIXME("(%x):stub!\n", hdc); - return 0; +DWORD WINAPI GetFontLanguageInfo(HDC hdc) +{ + FONTSIGNATURE fontsig; + static const DWORD GCP_DBCS_MASK=0x003F0000, + GCP_DIACRITIC_MASK=0x00000000, + FLI_GLYPHS_MASK=0x00000000, + GCP_GLYPHSHAPE_MASK=0x00000040, + GCP_KASHIDA_MASK=0x00000000, + GCP_LIGATE_MASK=0x00000000, + GCP_USEKERNING_MASK=0x00000000, + GCP_REORDER_MASK=0x00000060; + + DWORD result=0; + + GetTextCharsetInfo( hdc, &fontsig, 0 ); + /* We detect each flag we return using a bitmask on the Codepage Bitfields */ + + if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 ) + result|=GCP_DBCS; + + if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 ) + result|=GCP_DIACRITIC; + + if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 ) + result|=FLI_GLYPHS; + + if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 ) + result|=GCP_GLYPHSHAPE; + + if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 ) + result|=GCP_KASHIDA; + + if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 ) + result|=GCP_LIGATE; + + if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 ) + result|=GCP_USEKERNING; + + if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 ) + result|=GCP_REORDER; + + return result; } /************************************************************************* @@ -2235,11 +2273,31 @@ /************************************************************************* * GetCharacterPlacementW [GDI32.@] + * + * Retrieve information about a string. This includes the width, reordering, + * Glyphing and so on. + * + * RETURNS + * + * The width and height of the string if succesful, 0 if failed. + * + * BUGS + * + * All flags except GCP_REORDER are not yet implemented. + * Reordering is not 100% complient to the Windows BiDi method. + * Caret positioning is not yet implemented. + * Classes are not yet implemented. + * */ DWORD WINAPI -GetCharacterPlacementW(HDC hdc, LPCWSTR lpString, INT uCount, - INT nMaxExtent, GCP_RESULTSW *lpResults, - DWORD dwFlags) +GetCharacterPlacementW( + HDC hdc, /* Device context for which the rendering is to be done */ + LPCWSTR lpString, /* The string for which information is to be returned */ + INT uCount, /* Number of WORDS in string. */ + INT nMaxExtent, /* Maximum extent the string is to take (in HDC logical units) */ + GCP_RESULTSW *lpResults, /* A pointer to a GCP_RESULTSW struct */ + DWORD dwFlags /* Flags specifying how to process the string */ + ) { DWORD ret=0; SIZE size; @@ -2254,37 +2312,115 @@ lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass, lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit); - if(dwFlags) FIXME("flags 0x%08lx ignored\n", dwFlags); + 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"); - /* FIXME: reordering not implemented */ - /* copy will do if the GCP_REORDER flag is not set */ - if(lpResults->lpOutString) - lstrcpynW(lpResults->lpOutString, lpString, uCount); - - nSet = (UINT)uCount; - if(nSet > lpResults->nGlyphs) - nSet = lpResults->nGlyphs; - - /* return number of initialized fields */ - lpResults->nGlyphs = nSet; - - if(lpResults->lpOrder) - { - for(i = 0; i < nSet; i++) - lpResults->lpOrder[i] = i; - } - - if (lpResults->lpDx) - { - int c; - for (i = 0; i < nSet; i++) - { - if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c)) - lpResults->lpDx[i]= c; - } - } + 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) + lstrcpynW(lpResults->lpOutString, lpString, uCount); + + if(lpResults->lpOrder) + { + for(i = 0; i < nSet; i++) + lpResults->lpOrder[i] = i; + } + + } 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, 1, 1, -1, 1, 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 list 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 + */ + 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 */ + 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); + } + + /* 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); Index: objects/text.c =================================================================== RCS file: /home/wine/wine/objects/text.c,v retrieving revision 1.45 diff -u -r1.45 text.c --- objects/text.c 31 May 2002 23:06:53 -0000 1.45 +++ objects/text.c 12 Jun 2002 19:34:04 -0000 @@ -170,9 +170,35 @@ { if(PATH_IsPathOpen(dc->path)) FIXME("called on an open path\n"); - else if(dc->funcs->pExtTextOut) - ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags,lprect,str,count,lpDx); - GDI_ReleaseObj( hdc ); + else if(dc->funcs->pExtTextOut) + { + DWORD fontLangInfo=0; + if( !(flags&(ETO_GLYPH_INDEX|ETO_IGNORELANGUAGE)) && + ((fontLangInfo=GetFontLanguageInfo( hdc ))&(GCP_REORDER|GCP_GLYPHSHAPE)) ) + { + /* The caller did not specify that language processing was already done, + * and the font idetifies iteself as requiring language processing. + */ + 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; + + GetCharacterPlacementW(hdc, str, count, 0, &gcp, GCP_REORDER ); + + ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags|ETO_IGNORELANGUAGE, + lprect,gcp.lpOutString,count,lpDx); + } else + ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags,lprect,str,count,lpDx); + } + GDI_ReleaseObj( hdc ); } return ret; }