[User32|RTL]
[reactos.git] / reactos / win32ss / user / user32 / windows / font.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * PROJECT: ReactOS user32.dll
21 * FILE: win32ss/user/user32/windows/font.c
22 * PURPOSE: Draw Text
23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
24 * UPDATE HISTORY:
25 * 09-05-2001 CSH Created
26 */
27
28 /* INCLUDES ******************************************************************/
29
30 #include <user32.h>
31
32 #include <wine/debug.h>
33
34 WINE_DEFAULT_DEBUG_CHANNEL(text);
35
36 DWORD WINAPI GdiGetCodePage(HDC hdc);
37
38 INT WINAPI DrawTextExWorker( HDC hdc, LPWSTR str, INT i_count,
39 LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp );
40
41
42 /* FUNCTIONS *****************************************************************/
43
44
45 /***********************************************************************
46 * TEXT_TabbedTextOut
47 *
48 * Helper function for TabbedTextOut() and GetTabbedTextExtent().
49 * Note: this doesn't work too well for text-alignment modes other
50 * than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
51 */
52 /* WINE synced 22-May-2006 */
53 LONG TEXT_TabbedTextOut( HDC hdc,
54 INT x,
55 INT y,
56 LPCWSTR lpstr,
57 INT count,
58 INT cTabStops,
59 const INT *lpTabPos,
60 INT nTabOrg,
61 BOOL fDisplayText )
62 {
63 INT defWidth;
64 SIZE extent;
65 int i, j;
66 int start = x;
67 TEXTMETRICW tm;
68
69 if (!lpTabPos)
70 cTabStops=0;
71
72 GetTextMetricsW( hdc, &tm );
73
74 if (cTabStops == 1)
75 {
76 defWidth = *lpTabPos;
77 cTabStops = 0;
78 }
79 else
80 {
81 defWidth = 8 * tm.tmAveCharWidth;
82 }
83
84 while (count > 0)
85 {
86 RECT r;
87 INT x0;
88 x0 = x;
89 r.left = x0;
90 /* chop the string into substrings of 0 or more <tabs>
91 * possibly followed by 1 or more normal characters */
92 for (i = 0; i < count; i++)
93 if (lpstr[i] != '\t') break;
94 for (j = i; j < count; j++)
95 if (lpstr[j] == '\t') break;
96 /* get the extent of the normal character part */
97 GetTextExtentPointW( hdc, lpstr + i, j - i , &extent );
98 /* and if there is a <tab>, calculate its position */
99 if( i) {
100 /* get x coordinate for the drawing of this string */
101 for (; cTabStops > i; lpTabPos++, cTabStops--)
102 {
103 if( nTabOrg + abs( *lpTabPos) > x) {
104 if( lpTabPos[ i - 1] >= 0) {
105 /* a left aligned tab */
106 x = nTabOrg + lpTabPos[ i-1] + extent.cx;
107 break;
108 }
109 else
110 {
111 /* if tab pos is negative then text is right-aligned
112 * to tab stop meaning that the string extends to the
113 * left, so we must subtract the width of the string */
114 if (nTabOrg - lpTabPos[ i - 1] - extent.cx > x)
115 {
116 x = nTabOrg - lpTabPos[ i - 1];
117 x0 = x - extent.cx;
118 break;
119 }
120 }
121 }
122 }
123 /* if we have run out of tab stops and we have a valid default tab
124 * stop width then round x up to that width */
125 if ((cTabStops <= i) && (defWidth > 0)) {
126 x0 = nTabOrg + ((x - nTabOrg) / defWidth + i) * defWidth;
127 x = x0 + extent.cx;
128 } else if ((cTabStops <= i) && (defWidth < 0)) {
129 x = nTabOrg + ((x - nTabOrg + extent.cx) / -defWidth + i)
130 * -defWidth;
131 x0 = x - extent.cx;
132 }
133 } else
134 x += extent.cx;
135
136 if (fDisplayText)
137 {
138 r.top = y;
139 r.right = x;
140 r.bottom = y + extent.cy;
141
142 ExtTextOutW( hdc, x0, y, GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
143 &r, lpstr + i, j - i, NULL );
144 }
145 count -= j;
146 lpstr += j;
147 }
148
149 if(!extent.cy)
150 extent.cy = tm.tmHeight;
151
152 return MAKELONG(x - start, extent.cy);
153 }
154
155 /*
156 * @implemented
157 */
158 LONG
159 WINAPI
160 TabbedTextOutA(
161 HDC hDC,
162 int X,
163 int Y,
164 LPCSTR lpString,
165 int nCount,
166 int nTabPositions,
167 CONST INT *lpnTabStopPositions,
168 int nTabOrigin)
169 {
170 LONG ret;
171 DWORD len;
172 LPWSTR strW;
173 UINT cp = GdiGetCodePage( hDC ); // CP_ACP
174
175 len = MultiByteToWideChar(cp, 0, lpString, nCount, NULL, 0);
176 if (!len) return 0;
177 strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
178 if (!strW) return 0;
179 MultiByteToWideChar(cp, 0, lpString, nCount, strW, len);
180 ret = TabbedTextOutW(hDC, X, Y, strW, len, nTabPositions, lpnTabStopPositions, nTabOrigin);
181 HeapFree(GetProcessHeap(), 0, strW);
182 return ret;
183 }
184
185 /*
186 * @implemented
187 */
188 LONG
189 WINAPI
190 TabbedTextOutW(
191 HDC hDC,
192 int X,
193 int Y,
194 LPCWSTR lpString,
195 int nCount,
196 int nTabPositions,
197 CONST INT *lpnTabStopPositions,
198 int nTabOrigin)
199 {
200 return TEXT_TabbedTextOut(hDC, X, Y, lpString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin, TRUE);
201 }
202
203 /* WINE synced 22-May-2006 */
204 /*
205 * @implemented
206 */
207 DWORD
208 WINAPI
209 GetTabbedTextExtentA(
210 HDC hDC,
211 LPCSTR lpString,
212 int nCount,
213 int nTabPositions,
214 CONST INT *lpnTabStopPositions)
215 {
216 LONG ret;
217 UINT cp = GdiGetCodePage( hDC ); // CP_ACP
218 DWORD len;
219 LPWSTR strW;
220
221 len = MultiByteToWideChar(cp, 0, lpString, nCount, NULL, 0);
222 if (!len) return 0;
223 strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
224 if (!strW) return 0;
225 MultiByteToWideChar(cp, 0, lpString, nCount, strW, len);
226 ret = GetTabbedTextExtentW(hDC, strW, len, nTabPositions, lpnTabStopPositions);
227 HeapFree(GetProcessHeap(), 0, strW);
228 return ret;
229 }
230
231 /*
232 * @implemented
233 */
234 DWORD
235 WINAPI
236 GetTabbedTextExtentW(
237 HDC hDC,
238 LPCWSTR lpString,
239 int nCount,
240 int nTabPositions,
241 CONST INT *lpnTabStopPositions)
242 {
243 return TEXT_TabbedTextOut(hDC, 0, 0, lpString, nCount, nTabPositions, lpnTabStopPositions, 0, FALSE);
244 }
245
246
247 /***********************************************************************
248 * DrawTextExW (USER32.@)
249 *
250 * The documentation on the extra space required for DT_MODIFYSTRING at MSDN
251 * is not quite complete, especially with regard to \0. We will assume that
252 * the returned string could have a length of up to i_count+3 and also have
253 * a trailing \0 (which would be 4 more than a not-null-terminated string but
254 * 3 more than a null-terminated string). If this is not so then increase
255 * the allowance in DrawTextExA.
256 */
257 #define MAX_BUFFER 1024
258 /*
259 * @implemented
260 *
261 * Synced with Wine Staging 1.7.37
262 */
263 INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count,
264 LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
265 {
266 return DrawTextExWorker( hdc, str, i_count, rect, flags, dtp );
267 }
268
269 /***********************************************************************
270 * DrawTextExA (USER32.@)
271 *
272 * If DT_MODIFYSTRING is specified then there must be room for up to
273 * 4 extra characters. We take great care about just how much modified
274 * string we return.
275 *
276 * @implemented
277 *
278 * Synced with Wine Staging 1.7.37
279 */
280 INT WINAPI DrawTextExA( HDC hdc, LPSTR str, INT count,
281 LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
282 {
283 WCHAR *wstr;
284 WCHAR *p;
285 INT ret = 0;
286 int i;
287 DWORD wcount;
288 DWORD wmax;
289 DWORD amax;
290 UINT cp;
291
292 if (!count) return 0;
293 if (!str && count > 0) return 0;
294 if( !str || ((count == -1) && !(count = strlen(str))))
295 {
296 int lh;
297 TEXTMETRICA tm;
298
299 if (dtp && dtp->cbSize != sizeof(DRAWTEXTPARAMS))
300 return 0;
301
302 GetTextMetricsA(hdc, &tm);
303 if (flags & DT_EXTERNALLEADING)
304 lh = tm.tmHeight + tm.tmExternalLeading;
305 else
306 lh = tm.tmHeight;
307
308 if( flags & DT_CALCRECT)
309 {
310 rect->right = rect->left;
311 if( flags & DT_SINGLELINE)
312 rect->bottom = rect->top + lh;
313 else
314 rect->bottom = rect->top;
315 }
316 return lh;
317 }
318 cp = GdiGetCodePage( hdc );
319 wcount = MultiByteToWideChar( cp, 0, str, count, NULL, 0 );
320 wmax = wcount;
321 amax = count;
322 if (flags & DT_MODIFYSTRING)
323 {
324 wmax += 4;
325 amax += 4;
326 }
327 wstr = HeapAlloc(GetProcessHeap(), 0, wmax * sizeof(WCHAR));
328 if (wstr)
329 {
330 MultiByteToWideChar( cp, 0, str, count, wstr, wcount );
331 if (flags & DT_MODIFYSTRING)
332 for (i=4, p=wstr+wcount; i--; p++) *p=0xFFFE;
333 /* Initialise the extra characters so that we can see which ones
334 * change. U+FFFE is guaranteed to be not a unicode character and
335 * so will not be generated by DrawTextEx itself.
336 */
337 ret = DrawTextExW( hdc, wstr, wcount, rect, flags, dtp );
338 if (flags & DT_MODIFYSTRING)
339 {
340 /* Unfortunately the returned string may contain multiple \0s
341 * and so we need to measure it ourselves.
342 */
343 for (i=4, p=wstr+wcount; i-- && *p != 0xFFFE; p++) wcount++;
344 WideCharToMultiByte( cp, 0, wstr, wcount, str, amax, NULL, NULL );
345 }
346 HeapFree(GetProcessHeap(), 0, wstr);
347 }
348 return ret;
349 }
350
351 /***********************************************************************
352 * DrawTextW (USER32.@)
353 *
354 * @implemented
355 * Synced with Wine Staging 1.7.37
356 */
357 INT WINAPI DrawTextW( HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags )
358 {
359 DRAWTEXTPARAMS dtp;
360
361 memset (&dtp, 0, sizeof(dtp));
362 dtp.cbSize = sizeof(dtp);
363 if (flags & DT_TABSTOP)
364 {
365 dtp.iTabLength = (flags >> 8) & 0xff;
366 flags &= 0xffff00ff;
367 }
368 return DrawTextExW(hdc, (LPWSTR)str, count, rect, flags, &dtp);
369 }
370
371 /***********************************************************************
372 * DrawTextA (USER32.@)
373 *
374 * @implemented
375 * Synced with Wine Staging 1.7.37
376 */
377 INT WINAPI DrawTextA( HDC hdc, LPCSTR str, INT count, LPRECT rect, UINT flags )
378 {
379 DRAWTEXTPARAMS dtp;
380
381 memset (&dtp, 0, sizeof(dtp));
382 dtp.cbSize = sizeof(dtp);
383 if (flags & DT_TABSTOP)
384 {
385 dtp.iTabLength = (flags >> 8) & 0xff;
386 flags &= 0xffff00ff;
387 }
388 return DrawTextExA( hdc, (LPSTR)str, count, rect, flags, &dtp );
389 }