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