ExtTextOut with rotation and MM_ANISOTROPIC inverted coordinates

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Fri Mar 30 12:56:05 CDT 2007


Hi,

I have a problem with rotated Text displayed by ExtTextOut after
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, 1000, -1000, NULL);
Basically, giving one negative parameter to SetWindowExtEx should
reverse the direction (clockwise/counterclockwise) in which
rotation is done. It works in Windows, but has no effect in wine.

The patch I created uses a side effect of the WMF file I had as
test case, basically it sets lfClipPrecision = CLIP_LH_ANGLES
and triggers direction inversion based on that instead of checking
the WindowExtEx settings. That is of course wrong, but it is
available almost everywhere in the text output paths and served
me nicely as "inverse rotation" flag.

Instead of abusing lfClipPrecision, what should we use? The
SetWindowExtEx call sets some_matrix.eM11 to a negative value
if its first argument is negative and eM22 to a negative value
if its second argument is negative.
So checking (eM11 * eM22 < 0) && (mapmode == MM_ANISOTROPIC)
should be the correct solution. Problem: You can't always check
these things because the dc is not available everywhere.
In case you have a GdiFont, you can check
    (font->font_desc.matrix.eM11 * font->font_desc.matrix.eM22 < 0)
or in case you have a LOGFONT
    (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
I have not tested whether the parameters of the current dc,
the parameters at the time CreateFontIndirect was run or the
parameters at the time SelectObject(hdc, hfont) was run are
responsible for the rotation inversion.


What works?
With the patch, lfClipPrecision = CLIP_LH_ANGLES has the effect
SetWindowExtEx(hdc, positivevalue, negativevalue, NULL) should
have. Exception: The text is clipped at the border, while Windows
auto-extends the borders to avoid clipping.

What doesn't work?
SetWindowExtEx(hdc, positivevalue, negativevalue, NULL) still
has no effect on the rotation angle.

Attached are:
create_mf.c: Testcase in C (thanks to Dmitry Timoshkov, who
   created the C code from a reduced WMF testcase I sent him)
create_mf_generated.wmf: WMF file output by ./create_mf file.wmf
wine-fontdirection-24.diff: Preliminary patch described above

If somebody can take a look at the patch and mangle it so
that it does the right thing, I'd be very grateful.

Regards,
Carl-Daniel
-- 
http://www.hailfinger.org/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: create_mf_generated.wmf
Type: image/x-wmf
Size: 222 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20070330/d2174185/create_mf_generated.bin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: create_mf.c
Type: text/x-csrc
Size: 1733 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20070330/d2174185/create_mf.c
-------------- next part --------------
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index ea2e66c..40d76c4 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -1944,6 +1944,10 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x,
     {
         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
+        if (lf.lfClipPrecision & CLIP_LH_ANGLES)
+        {
+            sinEsc = - sinEsc;
+        }
     }
     else
     {
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index f7b1220..730725a 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -2675,10 +2675,10 @@ GdiFont *WineEngCreateFontInstance(DC *d
     if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
     can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
 
-    TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
+    TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d clipprecision %d\n",
 	  debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
 	  lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
-	  lf.lfEscapement);
+	  lf.lfEscapement, lf.lfClipPrecision);
 
     /* check the cache first */
     if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
@@ -2946,6 +2946,10 @@ found:
     }
 
     ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
+    if (lf.lfClipPrecision & CLIP_LH_ANGLES)
+    {
+    	ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? 3600 - (lf.lfOrientation % 3600) : 0;
+    }
     ret->name = strdupW(family->FamilyName);
     ret->underline = lf.lfUnderline ? 0xff : 0;
     ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
diff --git a/dlls/gdi32/path.c b/dlls/gdi32/path.c
index af756b3..bc326ab 100644
--- a/dlls/gdi32/path.c
+++ b/dlls/gdi32/path.c
@@ -1363,6 +1363,10 @@ BOOL PATH_ExtTextOut(DC *dc, INT x, INT
     {
         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
+        if (lf.lfClipPrecision & CLIP_LH_ANGLES)
+        {
+            sinEsc = - sinEsc;
+        }
     } else
     {
         cosEsc = 1;
diff --git a/dlls/wineps.drv/font.c b/dlls/wineps.drv/font.c
index 9e0ae39..7bfc53c 100644
--- a/dlls/wineps.drv/font.c
+++ b/dlls/wineps.drv/font.c
@@ -108,6 +108,10 @@ HFONT PSDRV_SelectFont( PSDRV_PDEVICE *p
     }
 
     physDev->font.escapement = lf.lfEscapement;
+    if (lf.lfClipPrecision & CLIP_LH_ANGLES)
+    {
+        physDev->font.escapement = lf.lfEscapement ? 3600 - (lf.lfEscapement % 3600) : 0;
+    }
     physDev->font.set = FALSE;
 
     if(gdiFont && !subst) {
diff --git a/dlls/wineps.drv/text.c b/dlls/wineps.drv/text.c
index 59ac7c7..f6bd58c 100644
--- a/dlls/wineps.drv/text.c
+++ b/dlls/wineps.drv/text.c
@@ -105,6 +105,10 @@ static BOOL PSDRV_Text(PSDRV_PDEVICE *ph
     if(lf.lfEscapement != 0) {
         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
+        if (lf.lfClipPrecision & CLIP_LH_ANGLES)
+        {
+            sinEsc = - sinEsc;
+        }
     } else {
         cosEsc = 1;
         sinEsc = 0;
diff --git a/dlls/winex11.drv/xfont.c b/dlls/winex11.drv/xfont.c
index 60bd70d..3ecd3dc 100644
--- a/dlls/winex11.drv/xfont.c
+++ b/dlls/winex11.drv/xfont.c
@@ -944,6 +944,10 @@ static BOOL LFD_ComposeLFD( const fontOb
        if (fo->lf.lfEscapement) {
 	   /* escapement is in tenths of degrees, theta is in radians */
 	   double theta = M_PI*fo->lf.lfEscapement/1800.;
+           if (fo->lf.lfClipPrecision & CLIP_LH_ANGLES)
+           {
+               theta = - theta;
+           }
 	   LFD_AngleMatrix(h_string, h, theta);
        }
        else
diff --git a/dlls/winex11.drv/xrender.c b/dlls/winex11.drv/xrender.c
index e03540e..76d4e04 100644
--- a/dlls/winex11.drv/xrender.c
+++ b/dlls/winex11.drv/xrender.c
@@ -1136,6 +1136,10 @@ BOOL X11DRV_XRender_ExtTextOut( X11DRV_P
     if(lf.lfEscapement != 0) {
         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
+        if (lf.lfClipPrecision & CLIP_LH_ANGLES)
+        {
+            sinEsc = - sinEsc;
+        }
     } else {
         cosEsc = 1;
         sinEsc = 0;


More information about the wine-devel mailing list