Faster serial speed cases for non Linux systems.
[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 "psdrv.h"
22 #include "wine/debug.h"
23 #include "winspool.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
26
27 static BOOL PSDRV_Text(PSDRV_PDEVICE *physDev, INT x, INT y, LPCWSTR str, UINT count,
28                        BOOL bDrawBackground, const INT *lpDx);
29
30 /***********************************************************************
31  *           PSDRV_ExtTextOut
32  */
33 BOOL PSDRV_ExtTextOut( PSDRV_PDEVICE *physDev, INT x, INT y, UINT flags,
34                        const RECT *lprect, LPCWSTR str, UINT count,
35                        const INT *lpDx )
36 {
37     BOOL bResult = TRUE;
38     BOOL bClipped = FALSE;
39     BOOL bOpaque = FALSE;
40     RECT rect;
41     DC *dc = physDev->dc;
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.left = INTERNAL_XWPTODP(dc, lprect->left, lprect->top);
53         rect.right = INTERNAL_XWPTODP(dc, lprect->right, lprect->bottom);
54         rect.top = INTERNAL_YWPTODP(dc, lprect->left, lprect->top);
55         rect.bottom = INTERNAL_YWPTODP(dc, lprect->right, lprect->bottom);
56
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, str, count, !(bClipped && bOpaque), lpDx); 
77         PSDRV_WriteGRestore(physDev);
78     }
79     else
80     {
81         bResult = PSDRV_Text(physDev, x, y, str, count, TRUE, lpDx); 
82     }
83
84     return bResult;
85 }
86
87 /***********************************************************************
88  *           PSDRV_Text
89  */
90 static BOOL PSDRV_Text(PSDRV_PDEVICE *physDev, INT x, INT y, LPCWSTR str, UINT count,
91                        BOOL bDrawBackground, const INT *lpDx)
92 {
93     LPWSTR strbuf;
94     SIZE sz;
95     DC *dc = physDev->dc;
96     UINT align = GetTextAlign( physDev->hdc );
97
98     if (!count)
99         return TRUE;
100
101     strbuf = HeapAlloc( PSDRV_Heap, 0, (count + 1) * sizeof(WCHAR));
102     if(!strbuf) {
103         WARN("HeapAlloc failed\n");
104         return FALSE;
105     }
106
107     if(align & TA_UPDATECP) {
108         x = dc->CursPosX;
109         y = dc->CursPosY;
110     }
111
112     x = INTERNAL_XWPTODP(dc, x, y);
113     y = INTERNAL_YWPTODP(dc, x, y);
114
115     GetTextExtentPoint32W(physDev->hdc, str, count, &sz);
116     if(lpDx) {
117         SIZE tmpsz;
118         INT i;
119         /* Get the width of the last char and add on all the offsets */
120         GetTextExtentPoint32W(physDev->hdc, str + count - 1, 1, &tmpsz);
121         for(i = 0; i < count-1; i++)
122             tmpsz.cx += lpDx[i];
123         sz.cx = tmpsz.cx; /* sz.cy remains untouched */
124     }
125
126     sz.cx = INTERNAL_XWSTODS(dc, sz.cx);
127     sz.cy = INTERNAL_YWSTODS(dc, sz.cy);
128     TRACE("textAlign = %x\n", align);
129     switch(align & (TA_LEFT | TA_CENTER | TA_RIGHT) ) {
130     case TA_LEFT:
131         if(align & TA_UPDATECP) {
132             dc->CursPosX = INTERNAL_XDPTOWP(dc, x + sz.cx, y);
133         }
134         break;
135
136     case TA_CENTER:
137         x -= sz.cx/2;
138         break;
139
140     case TA_RIGHT:
141         x -= sz.cx;
142         if(align & TA_UPDATECP) {
143             dc->CursPosX = INTERNAL_XDPTOWP(dc, x, y);
144         }
145         break;
146     }
147
148     switch(align & (TA_TOP | TA_BASELINE | TA_BOTTOM) ) {
149     case TA_TOP:
150         y += physDev->font.tm.tmAscent;
151         break;
152
153     case TA_BASELINE:
154         break;
155
156     case TA_BOTTOM:
157         y -= physDev->font.tm.tmDescent;
158         break;
159     }
160
161     memcpy(strbuf, str, count * sizeof(WCHAR));
162     *(strbuf + count) = '\0';
163     
164     if ((GetBkMode( physDev->hdc ) != TRANSPARENT) && bDrawBackground)
165     {
166         PSDRV_WriteGSave(physDev);
167         PSDRV_WriteNewPath(physDev);
168         PSDRV_WriteRectangle(physDev, x, y - physDev->font.tm.tmAscent, sz.cx, 
169                              physDev->font.tm.tmAscent + 
170                              physDev->font.tm.tmDescent);
171         PSDRV_WriteSetColor(physDev, &physDev->bkColor);
172         PSDRV_WriteFill(physDev);
173         PSDRV_WriteGRestore(physDev);
174     }
175
176     PSDRV_WriteMoveTo(physDev, x, y);
177     
178     if(!lpDx)
179         PSDRV_WriteGlyphShow(physDev, strbuf, lstrlenW(strbuf));
180     else {
181         INT i;
182         float dx = 0.0, dy = 0.0;
183         float cos_theta = cos(physDev->font.escapement * M_PI / 1800.0);
184         float sin_theta = sin(physDev->font.escapement * M_PI / 1800.0);
185         for(i = 0; i < count-1; i++) {
186             TRACE("lpDx[%d] = %d\n", i, lpDx[i]);
187             PSDRV_WriteGlyphShow(physDev, &strbuf[i], 1);
188             dx += lpDx[i] * cos_theta;
189             dy -= lpDx[i] * sin_theta;
190             PSDRV_WriteMoveTo(physDev, x + INTERNAL_XWSTODS(dc, dx),
191                               y + INTERNAL_YWSTODS(dc, dy));
192         }
193         PSDRV_WriteGlyphShow(physDev, &strbuf[i], 1);
194     }
195
196     /*
197      * Underline and strikeout attributes.
198      */
199     if ((physDev->font.tm.tmUnderlined) || (physDev->font.tm.tmStruckOut)) {
200
201         /* Get the thickness and the position for the underline attribute */
202         /* We'll use the same thickness for the strikeout attribute       */
203
204         float thick = physDev->font.afm->UnderlineThickness * physDev->font.scale;
205         float pos   = -physDev->font.afm->UnderlinePosition * physDev->font.scale;
206         SIZE size;
207         INT escapement =  physDev->font.escapement;
208
209         TRACE("Position = %f Thickness %f Escapement %d\n",
210               pos, thick, escapement);
211
212         /* Get the width of the text */
213
214         PSDRV_GetTextExtentPoint(physDev, strbuf, lstrlenW(strbuf), &size);
215         size.cx = INTERNAL_XWSTODS(dc, size.cx);
216
217         /* Do the underline */
218
219         if (physDev->font.tm.tmUnderlined) {
220             PSDRV_WriteNewPath(physDev); /* will be closed by WriteRectangle */
221             if (escapement != 0)  /* rotated text */
222             {
223                 PSDRV_WriteGSave(physDev);  /* save the graphics state */
224                 PSDRV_WriteMoveTo(physDev, x, y); /* move to the start */
225
226                 /* temporarily rotate the coord system */
227                 PSDRV_WriteRotate(physDev, -escapement/10); 
228                 
229                 /* draw the underline relative to the starting point */
230                 PSDRV_WriteRRectangle(physDev, 0, (INT)pos, size.cx, (INT)thick);
231             }
232             else
233                 PSDRV_WriteRectangle(physDev, x, y + (INT)pos, size.cx, (INT)thick);
234
235             PSDRV_WriteFill(physDev);
236
237             if (escapement != 0)  /* rotated text */
238                 PSDRV_WriteGRestore(physDev);  /* restore the graphics state */
239         }
240
241         /* Do the strikeout */
242
243         if (physDev->font.tm.tmStruckOut) {
244             pos = -physDev->font.tm.tmAscent / 2;
245             PSDRV_WriteNewPath(physDev); /* will be closed by WriteRectangle */
246             if (escapement != 0)  /* rotated text */
247             {
248                 PSDRV_WriteGSave(physDev);  /* save the graphics state */
249                 PSDRV_WriteMoveTo(physDev, x, y); /* move to the start */
250
251                 /* temporarily rotate the coord system */
252                 PSDRV_WriteRotate(physDev, -escapement/10);
253
254                 /* draw the underline relative to the starting point */
255                 PSDRV_WriteRRectangle(physDev, 0, (INT)pos, size.cx, (INT)thick);
256             }
257             else
258                 PSDRV_WriteRectangle(physDev, x, y + (INT)pos, size.cx, (INT)thick);
259
260             PSDRV_WriteFill(physDev);
261
262             if (escapement != 0)  /* rotated text */
263                 PSDRV_WriteGRestore(physDev);  /* restore the graphics state */
264         }
265     }
266
267     HeapFree(PSDRV_Heap, 0, strbuf);
268     return TRUE;
269 }