Do not link against -lcups directly, but dynamically load it if
[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     /* set clipping and/or draw background */
51     if ((flags & (ETO_CLIPPED | ETO_OPAQUE)) && (lprect != NULL))
52     {
53         rect = *lprect;
54         LPtoDP( physDev->hdc, (POINT *)&rect, 2 );
55         PSDRV_WriteGSave(physDev);
56         PSDRV_WriteRectangle(physDev, rect.left, rect.top, rect.right - rect.left,
57                              rect.bottom - rect.top);
58
59         if (flags & ETO_OPAQUE)
60         {
61             bOpaque = TRUE;
62             PSDRV_WriteGSave(physDev);
63             PSDRV_WriteSetColor(physDev, &physDev->bkColor);
64             PSDRV_WriteFill(physDev);
65             PSDRV_WriteGRestore(physDev);
66         }
67
68         if (flags & ETO_CLIPPED)
69         {
70             bClipped = TRUE;
71             PSDRV_WriteClip(physDev);
72         }
73
74         bResult = PSDRV_Text(physDev, x, y, flags, str, count, !(bClipped && bOpaque), lpDx);
75         PSDRV_WriteGRestore(physDev);
76     }
77     else
78     {
79         bResult = PSDRV_Text(physDev, x, y, flags, str, count, TRUE, lpDx);
80     }
81
82     return bResult;
83 }
84
85 /***********************************************************************
86  *           PSDRV_Text
87  */
88 static BOOL PSDRV_Text(PSDRV_PDEVICE *physDev, INT x, INT y, UINT flags, LPCWSTR str,
89                        UINT count, BOOL bDrawBackground, const INT *lpDx)
90 {
91     SIZE sz;
92     TEXTMETRICW tm;
93     POINT pt;
94     INT ascent, descent;
95     WORD *glyphs = NULL;
96     DC *dc = physDev->dc;
97     UINT align = GetTextAlign( physDev->hdc );
98
99     if (!count)
100         return TRUE;
101
102
103     if(physDev->font.fontloc == Download) {
104         if(flags & ETO_GLYPH_INDEX)
105             glyphs = (LPWORD)str;
106         else {
107             glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
108             GetGlyphIndicesW(physDev->hdc, str, count, glyphs, 0);
109         }
110     }
111
112     if(align & TA_UPDATECP) {
113         x = dc->CursPosX;
114         y = dc->CursPosY;
115     }
116
117     pt.x = x;
118     pt.y = y;
119     LPtoDP(physDev->hdc, &pt, 1);
120     x = pt.x;
121     y = pt.y;
122
123     if(physDev->font.fontloc == Download)
124         GetTextExtentPointI(physDev->hdc, glyphs, count, &sz);
125     else
126         GetTextExtentPoint32W(physDev->hdc, str, count, &sz);
127
128     if(lpDx) {
129         SIZE tmpsz;
130         INT i;
131         /* Get the width of the last char and add on all the offsets */
132         if(physDev->font.fontloc == Download)
133             GetTextExtentPointI(physDev->hdc, glyphs + count - 1, 1, &tmpsz);
134         else
135             GetTextExtentPoint32W(physDev->hdc, str + count - 1, 1, &tmpsz);
136         for(i = 0; i < count-1; i++)
137             tmpsz.cx += lpDx[i];
138         sz.cx = tmpsz.cx; /* sz.cy remains untouched */
139     }
140
141     sz.cx = INTERNAL_XWSTODS(dc, sz.cx);
142     sz.cy = INTERNAL_YWSTODS(dc, sz.cy);
143
144     GetTextMetricsW(physDev->hdc, &tm);
145     ascent = INTERNAL_YWSTODS(dc, tm.tmAscent);
146     descent = INTERNAL_YWSTODS(dc, tm.tmDescent);
147
148     TRACE("textAlign = %x\n", align);
149     switch(align & (TA_LEFT | TA_CENTER | TA_RIGHT) ) {
150     case TA_LEFT:
151         if(align & TA_UPDATECP)
152         {
153             POINT pt;
154             pt.x = x + sz.cx;
155             pt.y = y;
156             DPtoLP( physDev->hdc, &pt, 1 );
157             dc->CursPosX = pt.x;
158         }
159         break;
160
161     case TA_CENTER:
162         x -= sz.cx/2;
163         break;
164
165     case TA_RIGHT:
166         x -= sz.cx;
167         if(align & TA_UPDATECP)
168         {
169             POINT pt;
170             pt.x = x;
171             pt.y = y;
172             DPtoLP( physDev->hdc, &pt, 1 );
173             dc->CursPosX = pt.x;
174         }
175         break;
176     }
177
178     switch(align & (TA_TOP | TA_BASELINE | TA_BOTTOM) ) {
179     case TA_TOP:
180         y += ascent;
181         break;
182
183     case TA_BASELINE:
184         break;
185
186     case TA_BOTTOM:
187         y -= descent;
188         break;
189     }
190
191     if ((GetBkMode( physDev->hdc ) != TRANSPARENT) && bDrawBackground)
192     {
193         PSDRV_WriteGSave(physDev);
194         PSDRV_WriteNewPath(physDev);
195         PSDRV_WriteRectangle(physDev, x, y - ascent, sz.cx,
196                              ascent + descent);
197         PSDRV_WriteSetColor(physDev, &physDev->bkColor);
198         PSDRV_WriteFill(physDev);
199         PSDRV_WriteGRestore(physDev);
200     }
201
202     PSDRV_WriteMoveTo(physDev, x, y);
203
204     if(!lpDx) {
205         if(physDev->font.fontloc == Download)
206             PSDRV_WriteDownloadGlyphShow(physDev, glyphs, count);
207         else
208             PSDRV_WriteBuiltinGlyphShow(physDev, str, count);
209     }
210     else {
211         INT i;
212         float dx = 0.0, dy = 0.0;
213         float cos_theta = cos(physDev->font.escapement * M_PI / 1800.0);
214         float sin_theta = sin(physDev->font.escapement * M_PI / 1800.0);
215         for(i = 0; i < count-1; i++) {
216             TRACE("lpDx[%d] = %d\n", i, lpDx[i]);
217             if(physDev->font.fontloc == Download)
218                 PSDRV_WriteDownloadGlyphShow(physDev, glyphs + i, 1);
219             else
220                 PSDRV_WriteBuiltinGlyphShow(physDev, str + i, 1);
221             dx += lpDx[i] * cos_theta;
222             dy -= lpDx[i] * sin_theta;
223             PSDRV_WriteMoveTo(physDev, x + INTERNAL_XWSTODS(dc, dx),
224                               y + INTERNAL_YWSTODS(dc, dy));
225         }
226         if(physDev->font.fontloc == Download)
227             PSDRV_WriteDownloadGlyphShow(physDev, glyphs + i, 1);
228         else
229             PSDRV_WriteBuiltinGlyphShow(physDev, str + i, 1);
230     }
231
232     /*
233      * Underline and strikeout attributes.
234      */
235     if ((tm.tmUnderlined) || (tm.tmStruckOut)) {
236
237         /* Get the thickness and the position for the underline attribute */
238         /* We'll use the same thickness for the strikeout attribute       */
239
240         INT escapement =  physDev->font.escapement;
241
242         /* Do the underline */
243
244         if (tm.tmUnderlined) {
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, -physDev->font.underlinePosition,
256                                       sz.cx, physDev->font.underlineThickness);
257             }
258             else
259                 PSDRV_WriteRectangle(physDev, x, y - physDev->font.underlinePosition,
260                                      sz.cx, physDev->font.underlineThickness);
261
262             PSDRV_WriteFill(physDev);
263
264             if (escapement != 0)  /* rotated text */
265                 PSDRV_WriteGRestore(physDev);  /* restore the graphics state */
266         }
267
268         /* Do the strikeout */
269
270         if (tm.tmStruckOut) {
271             PSDRV_WriteNewPath(physDev); /* will be closed by WriteRectangle */
272             if (escapement != 0)  /* rotated text */
273             {
274                 PSDRV_WriteGSave(physDev);  /* save the graphics state */
275                 PSDRV_WriteMoveTo(physDev, x, y); /* move to the start */
276
277                 /* temporarily rotate the coord system */
278                 PSDRV_WriteRotate(physDev, -escapement/10);
279
280                 /* draw the line relative to the starting point */
281                 PSDRV_WriteRRectangle(physDev, 0, -physDev->font.strikeoutPosition,
282                                       sz.cx, physDev->font.strikeoutThickness);
283             }
284             else
285                 PSDRV_WriteRectangle(physDev, x, y - physDev->font.strikeoutPosition,
286                                      sz.cx, physDev->font.strikeoutThickness);
287
288             PSDRV_WriteFill(physDev);
289
290             if (escapement != 0)  /* rotated text */
291                 PSDRV_WriteGRestore(physDev);  /* restore the graphics state */
292         }
293     }
294
295     if(glyphs && glyphs != str) HeapFree(GetProcessHeap(), 0, glyphs);
296     return TRUE;
297 }