Removed some more trailing whitespace.
[wine] / dlls / wineps / text.c
1 /*
2  *      PostScript driver text functions
3  *
4  *      Copyright 1998  Huw D M Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <string.h>
21 #include "gdi.h"
22 #include "psdrv.h"
23 #include "wine/debug.h"
24 #include "winspool.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
27
28 static BOOL PSDRV_Text(PSDRV_PDEVICE *physDev, INT x, INT y, LPCWSTR str, UINT count,
29                        BOOL bDrawBackground, const INT *lpDx);
30
31 /***********************************************************************
32  *           PSDRV_ExtTextOut
33  */
34 BOOL PSDRV_ExtTextOut( PSDRV_PDEVICE *physDev, INT x, INT y, UINT flags,
35                        const RECT *lprect, LPCWSTR str, UINT count,
36                        const INT *lpDx )
37 {
38     BOOL bResult = TRUE;
39     BOOL bClipped = FALSE;
40     BOOL bOpaque = FALSE;
41     RECT rect;
42
43     TRACE("(x=%d, y=%d, flags=0x%08x, str=%s, count=%d, lpDx=%p)\n", x, y,
44           flags, debugstr_wn(str, count), count, lpDx);
45
46     /* write font if not already written */
47     PSDRV_SetFont(physDev);
48
49     /* set clipping and/or draw background */
50     if ((flags & (ETO_CLIPPED | ETO_OPAQUE)) && (lprect != NULL))
51     {
52         rect = *lprect;
53         LPtoDP( physDev->hdc, (POINT *)&rect, 2 );
54         PSDRV_WriteGSave(physDev);
55         PSDRV_WriteRectangle(physDev, rect.left, rect.top, rect.right - rect.left,
56                              rect.bottom - rect.top);
57
58         if (flags & ETO_OPAQUE)
59         {
60             bOpaque = TRUE;
61             PSDRV_WriteGSave(physDev);
62             PSDRV_WriteSetColor(physDev, &physDev->bkColor);
63             PSDRV_WriteFill(physDev);
64             PSDRV_WriteGRestore(physDev);
65         }
66
67         if (flags & ETO_CLIPPED)
68         {
69             bClipped = TRUE;
70             PSDRV_WriteClip(physDev);
71         }
72
73         bResult = PSDRV_Text(physDev, x, y, str, count, !(bClipped && bOpaque), lpDx);
74         PSDRV_WriteGRestore(physDev);
75     }
76     else
77     {
78         bResult = PSDRV_Text(physDev, x, y, str, count, TRUE, lpDx);
79     }
80
81     return bResult;
82 }
83
84 /***********************************************************************
85  *           PSDRV_Text
86  */
87 static BOOL PSDRV_Text(PSDRV_PDEVICE *physDev, INT x, INT y, LPCWSTR str, UINT count,
88                        BOOL bDrawBackground, const INT *lpDx)
89 {
90     LPWSTR strbuf;
91     SIZE sz;
92     DC *dc = physDev->dc;
93     UINT align = GetTextAlign( physDev->hdc );
94
95     if (!count)
96         return TRUE;
97
98     strbuf = HeapAlloc( PSDRV_Heap, 0, (count + 1) * sizeof(WCHAR));
99     if(!strbuf) {
100         WARN("HeapAlloc failed\n");
101         return FALSE;
102     }
103
104     if(align & TA_UPDATECP) {
105         x = dc->CursPosX;
106         y = dc->CursPosY;
107     }
108
109     x = INTERNAL_XWPTODP(dc, x, y);
110     y = INTERNAL_YWPTODP(dc, x, y);
111
112     GetTextExtentPoint32W(physDev->hdc, str, count, &sz);
113     if(lpDx) {
114         SIZE tmpsz;
115         INT i;
116         /* Get the width of the last char and add on all the offsets */
117         GetTextExtentPoint32W(physDev->hdc, str + count - 1, 1, &tmpsz);
118         for(i = 0; i < count-1; i++)
119             tmpsz.cx += lpDx[i];
120         sz.cx = tmpsz.cx; /* sz.cy remains untouched */
121     }
122
123     sz.cx = INTERNAL_XWSTODS(dc, sz.cx);
124     sz.cy = INTERNAL_YWSTODS(dc, sz.cy);
125     TRACE("textAlign = %x\n", align);
126     switch(align & (TA_LEFT | TA_CENTER | TA_RIGHT) ) {
127     case TA_LEFT:
128         if(align & TA_UPDATECP) {
129             dc->CursPosX = INTERNAL_XDPTOWP(dc, x + sz.cx, y);
130         }
131         break;
132
133     case TA_CENTER:
134         x -= sz.cx/2;
135         break;
136
137     case TA_RIGHT:
138         x -= sz.cx;
139         if(align & TA_UPDATECP) {
140             dc->CursPosX = INTERNAL_XDPTOWP(dc, x, y);
141         }
142         break;
143     }
144
145     switch(align & (TA_TOP | TA_BASELINE | TA_BOTTOM) ) {
146     case TA_TOP:
147         y += physDev->font.tm.tmAscent;
148         break;
149
150     case TA_BASELINE:
151         break;
152
153     case TA_BOTTOM:
154         y -= physDev->font.tm.tmDescent;
155         break;
156     }
157
158     memcpy(strbuf, str, count * sizeof(WCHAR));
159     *(strbuf + count) = '\0';
160
161     if ((GetBkMode( physDev->hdc ) != TRANSPARENT) && bDrawBackground)
162     {
163         PSDRV_WriteGSave(physDev);
164         PSDRV_WriteNewPath(physDev);
165         PSDRV_WriteRectangle(physDev, x, y - physDev->font.tm.tmAscent, sz.cx,
166                              physDev->font.tm.tmAscent +
167                              physDev->font.tm.tmDescent);
168         PSDRV_WriteSetColor(physDev, &physDev->bkColor);
169         PSDRV_WriteFill(physDev);
170         PSDRV_WriteGRestore(physDev);
171     }
172
173     PSDRV_WriteMoveTo(physDev, x, y);
174
175     if(!lpDx)
176         PSDRV_WriteGlyphShow(physDev, strbuf, lstrlenW(strbuf));
177     else {
178         INT i;
179         float dx = 0.0, dy = 0.0;
180         float cos_theta = cos(physDev->font.escapement * M_PI / 1800.0);
181         float sin_theta = sin(physDev->font.escapement * M_PI / 1800.0);
182         for(i = 0; i < count-1; i++) {
183             TRACE("lpDx[%d] = %d\n", i, lpDx[i]);
184             PSDRV_WriteGlyphShow(physDev, &strbuf[i], 1);
185             dx += lpDx[i] * cos_theta;
186             dy -= lpDx[i] * sin_theta;
187             PSDRV_WriteMoveTo(physDev, x + INTERNAL_XWSTODS(dc, dx),
188                               y + INTERNAL_YWSTODS(dc, dy));
189         }
190         PSDRV_WriteGlyphShow(physDev, &strbuf[i], 1);
191     }
192
193     /*
194      * Underline and strikeout attributes.
195      */
196     if ((physDev->font.tm.tmUnderlined) || (physDev->font.tm.tmStruckOut)) {
197
198         /* Get the thickness and the position for the underline attribute */
199         /* We'll use the same thickness for the strikeout attribute       */
200
201         float thick = physDev->font.afm->UnderlineThickness * physDev->font.scale;
202         float pos   = -physDev->font.afm->UnderlinePosition * physDev->font.scale;
203         SIZE size;
204         INT escapement =  physDev->font.escapement;
205
206         TRACE("Position = %f Thickness %f Escapement %d\n",
207               pos, thick, escapement);
208
209         /* Get the width of the text */
210
211         PSDRV_GetTextExtentPoint(physDev, strbuf, lstrlenW(strbuf), &size);
212         size.cx = INTERNAL_XWSTODS(dc, size.cx);
213
214         /* Do the underline */
215
216         if (physDev->font.tm.tmUnderlined) {
217             PSDRV_WriteNewPath(physDev); /* will be closed by WriteRectangle */
218             if (escapement != 0)  /* rotated text */
219             {
220                 PSDRV_WriteGSave(physDev);  /* save the graphics state */
221                 PSDRV_WriteMoveTo(physDev, x, y); /* move to the start */
222
223                 /* temporarily rotate the coord system */
224                 PSDRV_WriteRotate(physDev, -escapement/10);
225
226                 /* draw the underline relative to the starting point */
227                 PSDRV_WriteRRectangle(physDev, 0, (INT)pos, size.cx, (INT)thick);
228             }
229             else
230                 PSDRV_WriteRectangle(physDev, x, y + (INT)pos, size.cx, (INT)thick);
231
232             PSDRV_WriteFill(physDev);
233
234             if (escapement != 0)  /* rotated text */
235                 PSDRV_WriteGRestore(physDev);  /* restore the graphics state */
236         }
237
238         /* Do the strikeout */
239
240         if (physDev->font.tm.tmStruckOut) {
241             pos = -physDev->font.tm.tmAscent / 2;
242             PSDRV_WriteNewPath(physDev); /* will be closed by WriteRectangle */
243             if (escapement != 0)  /* rotated text */
244             {
245                 PSDRV_WriteGSave(physDev);  /* save the graphics state */
246                 PSDRV_WriteMoveTo(physDev, x, y); /* move to the start */
247
248                 /* temporarily rotate the coord system */
249                 PSDRV_WriteRotate(physDev, -escapement/10);
250
251                 /* draw the underline relative to the starting point */
252                 PSDRV_WriteRRectangle(physDev, 0, (INT)pos, size.cx, (INT)thick);
253             }
254             else
255                 PSDRV_WriteRectangle(physDev, x, y + (INT)pos, size.cx, (INT)thick);
256
257             PSDRV_WriteFill(physDev);
258
259             if (escapement != 0)  /* rotated text */
260                 PSDRV_WriteGRestore(physDev);  /* restore the graphics state */
261         }
262     }
263
264     HeapFree(PSDRV_Heap, 0, strbuf);
265     return TRUE;
266 }