Fixed 0 count handling in PSDRV_Text.
[wine/multimedia.git] / dlls / wineps / text.c
blob596360c78cd26af4f931252a2641bd7367ab9de5
1 /*
2 * PostScript driver text functions
4 * Copyright 1998 Huw D M Davies
6 */
7 #include <string.h>
8 #include "psdrv.h"
9 #include "debugtools.h"
10 #include "winspool.h"
12 DEFAULT_DEBUG_CHANNEL(psdrv);
14 static BOOL PSDRV_Text(DC *dc, INT x, INT y, LPCWSTR str, UINT count,
15 BOOL bDrawBackground, const INT *lpDx);
17 /***********************************************************************
18 * PSDRV_ExtTextOut
20 BOOL PSDRV_ExtTextOut( DC *dc, INT x, INT y, UINT flags,
21 const RECT *lprect, LPCWSTR str, UINT count,
22 const INT *lpDx )
24 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
25 BOOL bResult = TRUE;
26 BOOL bClipped = FALSE;
27 BOOL bOpaque = FALSE;
28 RECT rect;
30 TRACE("(x=%d, y=%d, flags=0x%08x, str=%s, count=%d, lpDx=%p)\n", x, y,
31 flags, debugstr_wn(str, count), count, lpDx);
33 /* write font if not already written */
34 PSDRV_SetFont(dc);
36 /* set clipping and/or draw background */
37 if ((flags & (ETO_CLIPPED | ETO_OPAQUE)) && (lprect != NULL))
39 rect.left = INTERNAL_XWPTODP(dc, lprect->left, lprect->top);
40 rect.right = INTERNAL_XWPTODP(dc, lprect->right, lprect->bottom);
41 rect.top = INTERNAL_YWPTODP(dc, lprect->left, lprect->top);
42 rect.bottom = INTERNAL_YWPTODP(dc, lprect->right, lprect->bottom);
44 PSDRV_WriteGSave(dc);
45 PSDRV_WriteRectangle(dc, rect.left, rect.top, rect.right - rect.left,
46 rect.bottom - rect.top);
48 if (flags & ETO_OPAQUE)
50 bOpaque = TRUE;
51 PSDRV_WriteGSave(dc);
52 PSDRV_WriteSetColor(dc, &physDev->bkColor);
53 PSDRV_WriteFill(dc);
54 PSDRV_WriteGRestore(dc);
57 if (flags & ETO_CLIPPED)
59 bClipped = TRUE;
60 PSDRV_WriteClip(dc);
63 bResult = PSDRV_Text(dc, x, y, str, count, !(bClipped && bOpaque), lpDx);
64 PSDRV_WriteGRestore(dc);
66 else
68 bResult = PSDRV_Text(dc, x, y, str, count, TRUE, lpDx);
71 return bResult;
74 /***********************************************************************
75 * PSDRV_Text
77 static BOOL PSDRV_Text(DC *dc, INT x, INT y, LPCWSTR str, UINT count,
78 BOOL bDrawBackground, const INT *lpDx)
80 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
81 LPWSTR strbuf;
82 SIZE sz;
84 if (!count)
85 return TRUE;
87 strbuf = HeapAlloc( PSDRV_Heap, 0, (count + 1) * sizeof(WCHAR));
88 if(!strbuf) {
89 WARN("HeapAlloc failed\n");
90 return FALSE;
93 if(dc->textAlign & TA_UPDATECP) {
94 x = dc->CursPosX;
95 y = dc->CursPosY;
98 x = INTERNAL_XWPTODP(dc, x, y);
99 y = INTERNAL_YWPTODP(dc, x, y);
101 GetTextExtentPoint32W(dc->hSelf, str, count, &sz);
102 if(lpDx) {
103 SIZE tmpsz;
104 INT i;
105 /* Get the width of the last char and add on all the offsets */
106 GetTextExtentPoint32W(dc->hSelf, str + count - 1, 1, &tmpsz);
107 for(i = 0; i < count-1; i++)
108 tmpsz.cx += lpDx[i];
109 sz.cx = tmpsz.cx; /* sz.cy remains untouched */
112 sz.cx = INTERNAL_XWSTODS(dc, sz.cx);
113 sz.cy = INTERNAL_YWSTODS(dc, sz.cy);
114 TRACE("textAlign = %x\n", dc->textAlign);
115 switch(dc->textAlign & (TA_LEFT | TA_CENTER | TA_RIGHT) ) {
116 case TA_LEFT:
117 if(dc->textAlign & TA_UPDATECP) {
118 dc->CursPosX = INTERNAL_XDPTOWP(dc, x + sz.cx, y);
120 break;
122 case TA_CENTER:
123 x -= sz.cx/2;
124 break;
126 case TA_RIGHT:
127 x -= sz.cx;
128 if(dc->textAlign & TA_UPDATECP) {
129 dc->CursPosX = INTERNAL_XDPTOWP(dc, x, y);
131 break;
134 switch(dc->textAlign & (TA_TOP | TA_BASELINE | TA_BOTTOM) ) {
135 case TA_TOP:
136 y += physDev->font.tm.tmAscent;
137 break;
139 case TA_BASELINE:
140 break;
142 case TA_BOTTOM:
143 y -= physDev->font.tm.tmDescent;
144 break;
147 memcpy(strbuf, str, count * sizeof(WCHAR));
148 *(strbuf + count) = '\0';
150 if ((dc->backgroundMode != TRANSPARENT) && (bDrawBackground != FALSE))
152 PSDRV_WriteGSave(dc);
153 PSDRV_WriteNewPath(dc);
154 PSDRV_WriteRectangle(dc, x, y - physDev->font.tm.tmAscent, sz.cx,
155 physDev->font.tm.tmAscent +
156 physDev->font.tm.tmDescent);
157 PSDRV_WriteSetColor(dc, &physDev->bkColor);
158 PSDRV_WriteFill(dc);
159 PSDRV_WriteGRestore(dc);
162 PSDRV_WriteMoveTo(dc, x, y);
164 if(!lpDx)
165 PSDRV_WriteShow(dc, strbuf, lstrlenW(strbuf));
166 else {
167 INT i;
168 float dx = 0.0, dy = 0.0;
169 float cos_theta = cos(physDev->font.escapement * M_PI / 1800.0);
170 float sin_theta = sin(physDev->font.escapement * M_PI / 1800.0);
171 for(i = 0; i < count-1; i++) {
172 TRACE("lpDx[%d] = %d\n", i, lpDx[i]);
173 PSDRV_WriteShow(dc, &strbuf[i], 1);
174 dx += lpDx[i] * cos_theta;
175 dy -= lpDx[i] * sin_theta;
176 PSDRV_WriteMoveTo(dc, x + INTERNAL_XWSTODS(dc, dx),
177 y + INTERNAL_YWSTODS(dc, dy));
179 PSDRV_WriteShow(dc, &strbuf[i], 1);
183 * Underline and strikeout attributes.
185 if ((physDev->font.tm.tmUnderlined) || (physDev->font.tm.tmStruckOut)) {
187 /* Get the thickness and the position for the underline attribute */
188 /* We'll use the same thickness for the strikeout attribute */
190 float thick = physDev->font.afm->UnderlineThickness * physDev->font.scale;
191 float pos = -physDev->font.afm->UnderlinePosition * physDev->font.scale;
192 SIZE size;
193 INT escapement = physDev->font.escapement;
195 TRACE("Position = %f Thickness %f Escapement %d\n",
196 pos, thick, escapement);
198 /* Get the width of the text */
200 PSDRV_GetTextExtentPoint(dc, strbuf, lstrlenW(strbuf), &size);
201 size.cx = INTERNAL_XWSTODS(dc, size.cx);
203 /* Do the underline */
205 if (physDev->font.tm.tmUnderlined) {
206 if (escapement != 0) /* rotated text */
208 PSDRV_WriteGSave(dc); /* save the graphics state */
209 PSDRV_WriteMoveTo(dc, x, y); /* move to the start */
211 /* temporarily rotate the coord system */
212 PSDRV_WriteRotate(dc, -escapement/10);
214 /* draw the underline relative to the starting point */
215 PSDRV_WriteRRectangle(dc, 0, (INT)pos, size.cx, (INT)thick);
217 else
218 PSDRV_WriteRectangle(dc, x, y + (INT)pos, size.cx, (INT)thick);
220 PSDRV_WriteFill(dc);
222 if (escapement != 0) /* rotated text */
223 PSDRV_WriteGRestore(dc); /* restore the graphics state */
226 /* Do the strikeout */
228 if (physDev->font.tm.tmStruckOut) {
229 pos = -physDev->font.tm.tmAscent / 2;
231 if (escapement != 0) /* rotated text */
233 PSDRV_WriteGSave(dc); /* save the graphics state */
234 PSDRV_WriteMoveTo(dc, x, y); /* move to the start */
236 /* temporarily rotate the coord system */
237 PSDRV_WriteRotate(dc, -escapement/10);
239 /* draw the underline relative to the starting point */
240 PSDRV_WriteRRectangle(dc, 0, (INT)pos, size.cx, (INT)thick);
242 else
243 PSDRV_WriteRectangle(dc, x, y + (INT)pos, size.cx, (INT)thick);
245 PSDRV_WriteFill(dc);
247 if (escapement != 0) /* rotated text */
248 PSDRV_WriteGRestore(dc); /* restore the graphics state */
252 HeapFree(PSDRV_Heap, 0, strbuf);
253 return TRUE;