[prev in list] [next in list] [prev in thread] [next in thread] 

List:       wine-devel
Subject:    ExtTextOut with rotation and MM_ANISOTROPIC inverted coordinates
From:       Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 () gmx ! net>
Date:       2007-03-30 17:56:05
Message-ID: 460D4F35.6070609 () gmx ! net
[Download RAW message or body]

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/

["create_mf_generated.wmf" (image/x-wmf)]
["create_mf.c" (text/x-csrc)]

#include <windows.h>
#include <stdio.h>

static void print_LPtoDP_map(HDC hdc, int x, int y)
{
    POINT pt = { x, y };

    LPtoDP(hdc, &pt, 1);
    printf("%d,%d -> %d,%d\n", x, y, pt.x, pt.y);
}

static int create_wmf(const char *fname)
{
    static const char txt_string[] = "Should be top->down if not MM_ISOTROPIC mode";
    HMETAFILE hmf;
    HDC hdc;
    LOGFONT lf;
    HFONT hfont;

    hdc = fname ? CreateMetaFile(fname) : GetDC(0);
    if (!hdc)
    {
        printf("CreateMetaFile(%s) failed\n", fname);
    }

//    if (!fname)
    {
//        SetMapMode(hdc, MM_ISOTROPIC);
        SetMapMode(hdc, MM_ANISOTROPIC);
    }

    print_LPtoDP_map(hdc, 100, 100);

    SetWindowExtEx(hdc, 1000, -1000, NULL);
    SetWindowOrgEx(hdc, 0, 0, NULL);

    print_LPtoDP_map(hdc, 100, 100);

    if (!fname)
    {
        SetViewportExtEx(hdc, 1000, 1000, NULL);
        SetViewportOrgEx(hdc, 0, 200, NULL);
    }

    print_LPtoDP_map(hdc, 100, 100);

    memset(&lf, 0, sizeof(lf));
    lf.lfHeight = -20;
//    lf.lfEscapement = 2700;
//    lf.lfOrientation = 2700;
    lf.lfEscapement = 900;
    lf.lfOrientation = 900;
    lf.lfClipPrecision = CLIP_LH_ANGLES;
    strcpy(lf.lfFaceName, "Arial");
    hfont = CreateFontIndirect(&lf);
    SelectObject(hdc, hfont);

    ExtTextOut(hdc, 100, 100, 0, NULL, txt_string, strlen(txt_string), NULL);

    MoveToEx(hdc, 100, 100, NULL);
    LineTo(hdc, 200, 200);
    LineTo(hdc, 200, -100);
    LineTo(hdc, 0, 100);

    DeleteObject(hfont);

    if (fname)
    {
        hmf = CloseMetaFile(hdc);
        DeleteMetaFile(hmf);
    }
    else
        ReleaseDC(0, hdc);

    return 0;
}

int main(int argc, char *argv[])
{
    create_wmf(argc < 2 ? NULL : argv[1]);
    return 0;
}

["wine-fontdirection-24.diff" (text/plain)]

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;





[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic