Added a stub for NetStatisticsGet.
[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, UINT flags,
29                        LPCWSTR str, UINT count,
30                        BOOL bDrawBackground, const INT *lpDx);
31
32 /***********************************************************************
33  *           PSDRV_ExtTextOut
34  */
35 BOOL PSDRV_ExtTextOut( PSDRV_PDEVICE *physDev, INT x, INT y, UINT flags,
36                        const RECT *lprect, LPCWSTR str, UINT count,
37                        const INT *lpDx )
38 {
39     BOOL bResult = TRUE;
40     BOOL bClipped = FALSE;
41     BOOL bOpaque = FALSE;
42     RECT rect;
43
44     TRACE("(x=%d, y=%d, flags=0x%08x, str=%s, count=%d, lpDx=%p)\n", x, y,
45           flags, debugstr_wn(str, count), count, lpDx);
46
47     /* write font if not already written */
48     PSDRV_SetFont(physDev);
49
50     PSDRV_SetClip(physDev);
51
52     /* set clipping and/or draw background */
53     if ((flags & (ETO_CLIPPED | ETO_OPAQUE)) && (lprect != NULL))
54     {
55         rect = *lprect;
56         LPtoDP( physDev->hdc, (POINT *)&rect, 2 );
57         PSDRV_WriteGSave(physDev);
58         PSDRV_WriteRectangle(physDev, rect.left, rect.top, rect.right - rect.left,
59                              rect.bottom - rect.top);
60
61         if (flags & ETO_OPAQUE)
62         {
63             bOpaque = TRUE;
64             PSDRV_WriteGSave(physDev);
65             PSDRV_WriteSetColor(physDev, &physDev->bkColor);
66             PSDRV_WriteFill(physDev);
67             PSDRV_WriteGRestore(physDev);
68         }
69
70         if (flags & ETO_CLIPPED)
71         {
72             bClipped = TRUE;
73             PSDRV_WriteClip(physDev);
74         }
75
76         bResult = PSDRV_Text(physDev, x, y, flags, str, count, !(bClipped && bOpaque), lpDx);
77         PSDRV_WriteGRestore(physDev);
78     }
79     else
80     {
81         bResult = PSDRV_Text(physDev, x, y, flags, str, count, TRUE, lpDx);
82     }
83
84     PSDRV_ResetClip(physDev);
85     return bResult;
86 }
87
88 /***********************************************************************
89  *           PSDRV_Text
90  */
91 static BOOL PSDRV_Text(PSDRV_PDEVICE *physDev, INT x, INT y, UINT flags, LPCWSTR str,
92                        UINT count, BOOL bDrawBackground, const INT *lpDx)
93 {
94     SIZE sz;
95     TEXTMETRICW tm;
96     POINT pt;
97     INT ascent, descent;
98     WORD *glyphs = NULL;
99     DC *dc = physDev->dc;
100     UINT align = GetTextAlign( physDev->hdc );
101     INT char_extra;
102     INT *deltas = NULL;
103     double cosEsc, sinEsc;
104     LOGFONTW lf;
105
106     if (!count)
107         return TRUE;
108
109     GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
110     if(lf.lfEscapement != 0) {
111         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
112         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
113     } else {
114         cosEsc = 1;
115         sinEsc = 0;
116     }
117
118     if(physDev->font.fontloc == Download) {
119         if(flags & ETO_GLYPH_INDEX)
120             glyphs = (LPWORD)str;
121         else {
122             glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
123             GetGlyphIndicesW(physDev->hdc, str, count, glyphs, 0);
124         }
125     }
126
127     if(align & TA_UPDATECP) {
128         x = dc->CursPosX;
129         y = dc->CursPosY;
130     }
131
132     pt.x = x;
133     pt.y = y;
134     LPtoDP(physDev->hdc, &pt, 1);
135     x = pt.x;
136     y = pt.y;
137
138     if(physDev->font.fontloc == Download)
139         GetTextExtentPointI(physDev->hdc, glyphs, count, &sz);
140     else
141         GetTextExtentPoint32W(physDev->hdc, str, count, &sz);
142
143     if((char_extra = GetTextCharacterExtra(physDev->hdc)) != 0) {
144         INT i;
145         SIZE tmpsz;
146
147         deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
148         for(i = 0; i < count; i++) {
149             deltas[i] = char_extra;
150             if(lpDx)
151                 deltas[i] += lpDx[i];
152             else {
153                 if(physDev->font.fontloc == Download)
154                     GetTextExtentPointI(physDev->hdc, glyphs + i, 1, &tmpsz);
155                 else
156                     GetTextExtentPoint32W(physDev->hdc, str + i, 1, &tmpsz);
157                 deltas[i] += tmpsz.cx;
158             }
159         }
160     } else if(lpDx)
161         deltas = (INT*)lpDx;
162
163     if(deltas) {
164         SIZE tmpsz;
165         INT i;
166         /* Get the width of the last char and add on all the offsets */
167         if(physDev->font.fontloc == Download)
168             GetTextExtentPointI(physDev->hdc, glyphs + count - 1, 1, &tmpsz);
169         else
170             GetTextExtentPoint32W(physDev->hdc, str + count - 1, 1, &tmpsz);
171         for(i = 0; i < count-1; i++)
172             tmpsz.cx += deltas[i];
173         sz.cx = tmpsz.cx; /* sz.cy remains untouched */
174     }
175
176     sz.cx = INTERNAL_XWSTODS(dc, sz.cx);
177     sz.cy = INTERNAL_YWSTODS(dc, sz.cy);
178
179     GetTextMetricsW(physDev->hdc, &tm);
180     ascent = INTERNAL_YWSTODS(dc, tm.tmAscent);
181     descent = INTERNAL_YWSTODS(dc, tm.tmDescent);
182
183     TRACE("textAlign = %x\n", align);
184     switch(align & (TA_LEFT | TA_CENTER | TA_RIGHT) ) {
185     case TA_LEFT:
186         if(align & TA_UPDATECP)
187         {
188             POINT pt;
189             pt.x = x + sz.cx * cosEsc;
190             pt.y = y - sz.cx * sinEsc;
191             DPtoLP( physDev->hdc, &pt, 1 );
192             dc->CursPosX = pt.x;
193             dc->CursPosY = pt.y;
194         }
195         break;
196
197     case TA_CENTER:
198         x -= sz.cx * cosEsc / 2;
199         y += sz.cx * sinEsc / 2;
200         break;
201
202     case TA_RIGHT:
203         x -= sz.cx * cosEsc;
204         y += sz.cx * sinEsc;
205         if(align & TA_UPDATECP)
206         {
207             POINT pt;
208             pt.x = x;
209             pt.y = y;
210             DPtoLP( physDev->hdc, &pt, 1 );
211             dc->CursPosX = pt.x;
212             dc->CursPosY = pt.y;
213         }
214         break;
215     }
216
217     switch(align & (TA_TOP | TA_BASELINE | TA_BOTTOM) ) {
218     case TA_TOP:
219         y += ascent * cosEsc;
220         x += ascent * sinEsc;
221         break;
222
223     case TA_BASELINE:
224         break;
225
226     case TA_BOTTOM:
227         y -= descent * cosEsc;
228         x -= descent * sinEsc;
229         break;
230     }
231
232     if ((GetBkMode( physDev->hdc ) != TRANSPARENT) && bDrawBackground)
233     {
234         PSDRV_WriteGSave(physDev);
235         PSDRV_WriteNewPath(physDev);
236         PSDRV_WriteRectangle(physDev, x, y - ascent, sz.cx,
237                              ascent + descent);
238         PSDRV_WriteSetColor(physDev, &physDev->bkColor);
239         PSDRV_WriteFill(physDev);
240         PSDRV_WriteGRestore(physDev);
241     }
242
243     PSDRV_WriteMoveTo(physDev, x, y);
244
245     if(!deltas) {
246         if(physDev->font.fontloc == Download)
247             PSDRV_WriteDownloadGlyphShow(physDev, glyphs, count);
248         else
249             PSDRV_WriteBuiltinGlyphShow(physDev, str, count);
250     }
251     else {
252         INT i;
253         float dx = 0.0, dy = 0.0;
254         float cos_theta = cos(physDev->font.escapement * M_PI / 1800.0);
255         float sin_theta = sin(physDev->font.escapement * M_PI / 1800.0);
256         for(i = 0; i < count-1; i++) {
257             TRACE("lpDx[%d] = %d\n", i, deltas[i]);
258             if(physDev->font.fontloc == Download)
259                 PSDRV_WriteDownloadGlyphShow(physDev, glyphs + i, 1);
260             else
261                 PSDRV_WriteBuiltinGlyphShow(physDev, str + i, 1);
262             dx += deltas[i] * cos_theta;
263             dy -= deltas[i] * sin_theta;
264             PSDRV_WriteMoveTo(physDev, x + INTERNAL_XWSTODS(dc, dx),
265                               y + INTERNAL_YWSTODS(dc, dy));
266         }
267         if(physDev->font.fontloc == Download)
268             PSDRV_WriteDownloadGlyphShow(physDev, glyphs + i, 1);
269         else
270             PSDRV_WriteBuiltinGlyphShow(physDev, str + i, 1);
271         if(deltas != lpDx)
272             HeapFree(GetProcessHeap(), 0, deltas);
273     }
274
275     /*
276      * Underline and strikeout attributes.
277      */
278     if ((tm.tmUnderlined) || (tm.tmStruckOut)) {
279
280         /* Get the thickness and the position for the underline attribute */
281         /* We'll use the same thickness for the strikeout attribute       */
282
283         INT escapement =  physDev->font.escapement;
284
285         /* Do the underline */
286
287         if (tm.tmUnderlined) {
288             PSDRV_WriteNewPath(physDev); /* will be closed by WriteRectangle */
289             if (escapement != 0)  /* rotated text */
290             {
291                 PSDRV_WriteGSave(physDev);  /* save the graphics state */
292                 PSDRV_WriteMoveTo(physDev, x, y); /* move to the start */
293
294                 /* temporarily rotate the coord system */
295                 PSDRV_WriteRotate(physDev, -escapement/10);
296
297                 /* draw the underline relative to the starting point */
298                 PSDRV_WriteRRectangle(physDev, 0, -physDev->font.underlinePosition,
299                                       sz.cx, physDev->font.underlineThickness);
300             }
301             else
302                 PSDRV_WriteRectangle(physDev, x, y - physDev->font.underlinePosition,
303                                      sz.cx, physDev->font.underlineThickness);
304
305             PSDRV_WriteFill(physDev);
306
307             if (escapement != 0)  /* rotated text */
308                 PSDRV_WriteGRestore(physDev);  /* restore the graphics state */
309         }
310
311         /* Do the strikeout */
312
313         if (tm.tmStruckOut) {
314             PSDRV_WriteNewPath(physDev); /* will be closed by WriteRectangle */
315             if (escapement != 0)  /* rotated text */
316             {
317                 PSDRV_WriteGSave(physDev);  /* save the graphics state */
318                 PSDRV_WriteMoveTo(physDev, x, y); /* move to the start */
319
320                 /* temporarily rotate the coord system */
321                 PSDRV_WriteRotate(physDev, -escapement/10);
322
323                 /* draw the line relative to the starting point */
324                 PSDRV_WriteRRectangle(physDev, 0, -physDev->font.strikeoutPosition,
325                                       sz.cx, physDev->font.strikeoutThickness);
326             }
327             else
328                 PSDRV_WriteRectangle(physDev, x, y - physDev->font.strikeoutPosition,
329                                      sz.cx, physDev->font.strikeoutThickness);
330
331             PSDRV_WriteFill(physDev);
332
333             if (escapement != 0)  /* rotated text */
334                 PSDRV_WriteGRestore(physDev);  /* restore the graphics state */
335         }
336     }
337
338     if(glyphs && glyphs != str) HeapFree(GetProcessHeap(), 0, glyphs);
339     return TRUE;
340 }