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