text.c 8.12 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * X11 graphics driver text functions
 *
 * Copyright 1993,1994 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

Patrik Stridvall's avatar
Patrik Stridvall committed
21 22
#include "config.h"

23
#include <stdarg.h>
Patrik Stridvall's avatar
Patrik Stridvall committed
24
#include <stdlib.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25
#include <math.h>
26 27

#include "windef.h"
28
#include "winbase.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
29
#include "x11font.h"
30
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
31

32
WINE_DEFAULT_DEBUG_CHANNEL(text);
33

Alexandre Julliard's avatar
Alexandre Julliard committed
34
#define SWAP_INT(a,b)  { int t = a; a = b; b = t; }
Alexandre Julliard's avatar
Alexandre Julliard committed
35
#define IROUND(x) (int)((x)>0? (x)+0.5 : (x) - 0.5)
Alexandre Julliard's avatar
Alexandre Julliard committed
36

37

Alexandre Julliard's avatar
Alexandre Julliard committed
38 39 40
/***********************************************************************
 *           X11DRV_ExtTextOut
 */
41
BOOL
42
X11DRV_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
43
                   const RECT *lprect, LPCWSTR wstr, UINT count,
44
                   const INT *lpDx )
Alexandre Julliard's avatar
Alexandre Julliard committed
45
{
46
    unsigned int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
47 48
    fontObject*		pfo;
    XFontStruct*	font;
49
    BOOL		rotated = FALSE;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
50
    XChar2b		*str2b = NULL;
51
    BOOL		dibUpdateFlag = FALSE;
52
    BOOL                result = TRUE;
53
    HRGN                saved_region = 0;
54

55
    if(physDev->has_gdi_font)
56
        return X11DRV_XRender_ExtTextOut(physDev, x, y, flags, lprect, wstr, count, lpDx);
57

58
    if (!X11DRV_SetupGCForText( physDev )) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
59

60
    pfo = XFONT_GetFontObject( physDev->font );
Alexandre Julliard's avatar
Alexandre Julliard committed
61
    font = pfo->fs;
62

Alexandre Julliard's avatar
Alexandre Julliard committed
63 64
    if (pfo->lf.lfEscapement && pfo->lpX11Trans)
        rotated = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
65

66
    TRACE("hdc=%p df=%04x %d,%d %s, %d  flags=%d lpDx=%p\n",
67
	  physDev->hdc, (UINT16)(physDev->font), x, y,
68
	  debugstr_wn (wstr, count), count, flags, lpDx);
Alexandre Julliard's avatar
Alexandre Julliard committed
69

70
    if (lprect != NULL) TRACE("\trect=(%d,%d - %d,%d)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
71 72 73 74 75 76 77
                                     lprect->left, lprect->top,
                                     lprect->right, lprect->bottom );

      /* Draw the rectangle */

    if (flags & ETO_OPAQUE)
    {
78
        X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
79
        dibUpdateFlag = TRUE;
80 81 82
        wine_tsx11_lock();
        XSetForeground( gdi_display, physDev->gc, physDev->backgroundPixel );
        XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
83
                        physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
84
                        lprect->right - lprect->left, lprect->bottom - lprect->top );
85
        wine_tsx11_unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
86
    }
87
    if (!count) goto END;  /* Nothing more to do */
Alexandre Julliard's avatar
Alexandre Julliard committed
88 89 90 91 92 93


      /* Set the clip region */

    if (flags & ETO_CLIPPED)
    {
94 95
        HRGN clip_region;

96
        clip_region = CreateRectRgnIndirect( lprect );
97 98 99 100 101
        /* make a copy of the current device region */
        saved_region = CreateRectRgn( 0, 0, 0, 0 );
        CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
        X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
        DeleteObject( clip_region );
Alexandre Julliard's avatar
Alexandre Julliard committed
102 103 104 105
    }

      /* Draw the text background if necessary */

106 107
    if (!dibUpdateFlag)
    {
108
        X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
109 110 111
        dibUpdateFlag = TRUE;
    }

112

Alexandre Julliard's avatar
Alexandre Julliard committed
113
    /* Draw the text (count > 0 verified) */
114
    if (!(str2b = X11DRV_cptable[pfo->fi->cptable].punicode_to_char2b( pfo, wstr, count )))
115
        goto FAIL;
Alexandre Julliard's avatar
Alexandre Julliard committed
116

117 118 119
    wine_tsx11_lock();
    XSetForeground( gdi_display, physDev->gc, physDev->textPixel );
    wine_tsx11_unlock();
120
    if(!rotated)
Alexandre Julliard's avatar
Alexandre Julliard committed
121
    {
122 123 124 125
        if (!lpDx)
        {
            X11DRV_cptable[pfo->fi->cptable].pDrawString(
                           pfo, gdi_display, physDev->drawable, physDev->gc,
126
                           physDev->dc_rect.left + x, physDev->dc_rect.top + y, str2b, count );
127 128 129 130 131 132 133 134 135 136
        }
        else
        {
            XTextItem16 *items, *pitem;

            pitem = items = HeapAlloc( GetProcessHeap(), 0,
                                       count * sizeof(XTextItem16) );
            if(items == NULL) goto FAIL;

            for(i = 0; i < count; i++)
Alexandre Julliard's avatar
Alexandre Julliard committed
137
            {
138 139 140 141 142
                pitem->chars  = str2b + i;
                pitem->delta  = lpDx[i];
                pitem->nchars = 1;
                pitem->font   = None;
                pitem++;
143
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
144

145 146
            X11DRV_cptable[pfo->fi->cptable].pDrawText( pfo, gdi_display,
                                  physDev->drawable, physDev->gc,
147
                                  physDev->dc_rect.left + x, physDev->dc_rect.top + y, items, pitem - items );
148 149
            HeapFree( GetProcessHeap(), 0, items );
        }
150 151
    }
    else /* rotated */
152
    {
153 154 155
        /* have to render character by character. */
        double offset = 0.0;
        int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
156

157 158 159 160
        for (i=0; i<count; i++)
        {
            int char_metric_offset = str2b[i].byte2 + (str2b[i].byte1 << 8)
                - font->min_char_or_byte2;
161
            int x_i = IROUND((double) (physDev->dc_rect.left + x) + offset *
162
                             pfo->lpX11Trans->a / pfo->lpX11Trans->pixelsize );
163
            int y_i = IROUND((double) (physDev->dc_rect.top + y) - offset *
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
                             pfo->lpX11Trans->b / pfo->lpX11Trans->pixelsize );

            X11DRV_cptable[pfo->fi->cptable].pDrawString(
                                    pfo, gdi_display, physDev->drawable, physDev->gc,
                                    x_i, y_i, &str2b[i], 1);
            if (lpDx)
            {
                offset += lpDx[i];
            }
            else
            {
                offset += (double) (font->per_char ?
                                    font->per_char[char_metric_offset].attributes:
                                    font->min_bounds.attributes)
                    * pfo->lpX11Trans->pixelsize / 1000.0;
            }
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
181
    }
182
    HeapFree( GetProcessHeap(), 0, str2b );
Alexandre Julliard's avatar
Alexandre Julliard committed
183

184 185 186 187 188 189
    if (flags & ETO_CLIPPED)
    {
        /* restore the device region */
        X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
        DeleteObject( saved_region );
    }
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
190
    goto END;
191

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
192
FAIL:
193
    HeapFree( GetProcessHeap(), 0, str2b );
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
194
    result = FALSE;
195

196
END:
197
    if (dibUpdateFlag) X11DRV_UnlockDIBSection( physDev, TRUE );
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
198
    return result;
Alexandre Julliard's avatar
Alexandre Julliard committed
199
}
Alexandre Julliard's avatar
Alexandre Julliard committed
200

201 202

/***********************************************************************
203
 *           X11DRV_GetTextExtentExPoint
204
 */
205 206
BOOL X11DRV_GetTextExtentExPoint( X11DRV_PDEVICE *physDev, LPCWSTR str, INT count,
                                  INT maxExt, LPINT lpnFit, LPINT alpDx, LPSIZE size )
207 208 209 210 211
{
    fontObject* pfo = XFONT_GetFontObject( physDev->font );

    TRACE("%s %d\n", debugstr_wn(str,count), count);
    if( pfo ) {
212 213
	XChar2b *p = X11DRV_cptable[pfo->fi->cptable].punicode_to_char2b( pfo, str, count );
	if (!p) return FALSE;
214 215
        if( !pfo->lpX11Trans ) {
	    int dir, ascent, descent;
216 217
	    int info_width;
	    X11DRV_cptable[pfo->fi->cptable].pTextExtents( pfo, p,
218 219
				count, &dir, &ascent, &descent, &info_width,
				maxExt, lpnFit, alpDx );
220

221 222
          size->cx = info_width;
          size->cy = pfo->fs->ascent + pfo->fs->descent;
223 224
	} else {
	    INT i;
225
	    INT nfit = 0;
226
	    float x = 0.0, y = 0.0;
227
	    float scaled_x = 0.0, pixsize = pfo->lpX11Trans->pixelsize;
228
	    /* FIXME: Deal with *_char_or_byte2 != 0 situations */
229
	    for(i = 0; i < count; i++) {
230 231
	        x += pfo->fs->per_char ?
	   pfo->fs->per_char[p[i].byte2 - pfo->fs->min_char_or_byte2].attributes :
232
	   pfo->fs->min_bounds.attributes;
233 234 235 236 237
	        scaled_x = x * pixsize / 1000.0;
	        if (alpDx)
	            alpDx[i] = scaled_x;
	        if (scaled_x <= maxExt)
	            ++nfit;
238 239 240
	    }
	    y = pfo->lpX11Trans->RAW_ASCENT + pfo->lpX11Trans->RAW_DESCENT;
	    TRACE("x = %f y = %f\n", x, y);
241 242
	    size->cx = x * pfo->lpX11Trans->pixelsize / 1000.0;
	    size->cy = y * pfo->lpX11Trans->pixelsize / 1000.0;
243 244
	    if (lpnFit)
	        *lpnFit = nfit;
245 246 247
	}
	size->cx *= pfo->rescale;
	size->cy *= pfo->rescale;
248
	HeapFree( GetProcessHeap(), 0, p );
249 250 251 252
	return TRUE;
    }
    return FALSE;
}