source: trunk/src/user32/text.c@ 7701

Last change on this file since 7701 was 7701, checked in by sandervl, 24 years ago

logging support added

File size: 23.7 KB
Line 
1/*
2 * USER text functions
3 *
4 * Copyright 1993, 1994 Alexandre Julliard
5 *
6 */
7
8#include <string.h>
9
10#include "windef.h"
11#include "wingdi.h"
12#include "wine/winuser16.h"
13#include "wine/unicode.h"
14#include "winbase.h"
15#include "winerror.h"
16#include "winnls.h"
17#include "user.h"
18#include "debugtools.h"
19
20#ifdef __WIN32OS2__
21#define CACHE_GetPattern55AABrush GetPattern55AABrush
22
23#define MapSL(a) a
24
25#define DBG_LOCALLOG DBG_text
26#include "dbglocal.h"
27
28#endif
29
30DEFAULT_DEBUG_CHANNEL(text);
31
32#define TAB 9
33#define LF 10
34#define CR 13
35#define SPACE 32
36#define PREFIX 38
37
38#define ELLIPSIS "..."
39#define FORWARD_SLASH '/'
40#define BACK_SLASH '\\'
41
42static const WCHAR SPACEW[] = {' ', 0};
43static const WCHAR oW[] = {'o', 0};
44static const WCHAR ELLIPSISW[] = {'.','.','.', 0};
45static const WCHAR FORWARD_SLASHW[] = {'/', 0};
46static const WCHAR BACK_SLASHW[] = {'\\', 0};
47
48#define SWAP_INT(a,b) { int t = a; a = b; b = t; }
49
50static int tabstop = 8;
51static int tabwidth;
52static int spacewidth;
53static int prefix_offset;
54
55/*********************************************************************
56 * Return next line of text from a string.
57 *
58 * hdc - handle to DC.
59 * str - string to parse into lines.
60 * count - length of str.
61 * dest - destination in which to return line.
62 * len - dest buffer size in chars on input, copied length into dest on output.
63 * width - maximum width of line in pixels.
64 * format - format type passed to DrawText.
65 *
66 * Returns pointer to next char in str after end of the line
67 * or NULL if end of str reached.
68 *
69 * FIXME:
70 * GetTextExtentPoint is used to get the width of each character,
71 * rather than GetCharABCWidth... So the whitespace between
72 * characters is ignored, and the reported len is too great.
73 */
74static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count,
75 WCHAR *dest, int *len, int width, WORD format)
76{
77 int i = 0, j = 0, k;
78 int plen = 0;
79 int numspaces;
80 SIZE size;
81 int lasttab = 0;
82 int wb_i = 0, wb_j = 0, wb_count = 0;
83 int maxl = *len;
84
85 while (*count && j < maxl)
86 {
87 switch (str[i])
88 {
89 case CR:
90 case LF:
91 if (!(format & DT_SINGLELINE))
92 {
93 if ((*count > 1) && (str[i] == CR) && (str[i+1] == LF))
94 {
95 (*count)--;
96 i++;
97 }
98 i++;
99 *len = j;
100 (*count)--;
101 return (&str[i]);
102 }
103 dest[j++] = str[i++];
104 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
105 (format & DT_WORDBREAK))
106 {
107 if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size))
108 return NULL;
109 plen += size.cx;
110 }
111 break;
112
113 case PREFIX:
114 if (!(format & DT_NOPREFIX) && *count > 1)
115 {
116 if (str[++i] == PREFIX)
117 (*count)--;
118 else {
119 prefix_offset = j;
120 break;
121 }
122 }
123 dest[j++] = str[i++];
124 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
125 (format & DT_WORDBREAK))
126 {
127 if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size))
128 return NULL;
129 plen += size.cx;
130 }
131 break;
132
133 case TAB:
134 if (format & DT_EXPANDTABS)
135 {
136 wb_i = ++i;
137 wb_j = j;
138 wb_count = *count;
139
140 if (!GetTextExtentPointW(hdc, &dest[lasttab], j - lasttab, &size))
141 return NULL;
142
143 numspaces = (tabwidth - size.cx) / spacewidth;
144 for (k = 0; k < numspaces; k++)
145 dest[j++] = SPACE;
146 plen += tabwidth - size.cx;
147 lasttab = wb_j + numspaces;
148 }
149 else
150 {
151 dest[j++] = str[i++];
152 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
153 (format & DT_WORDBREAK))
154 {
155 if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size))
156 return NULL;
157 plen += size.cx;
158 }
159 }
160 break;
161
162 case SPACE:
163 dest[j++] = str[i++];
164 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
165 (format & DT_WORDBREAK))
166 {
167 wb_i = i;
168 wb_j = j - 1;
169 wb_count = *count;
170 if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size))
171 return NULL;
172 plen += size.cx;
173 }
174 break;
175
176 default:
177 dest[j++] = str[i++];
178 if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
179 (format & DT_WORDBREAK))
180 {
181 if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size))
182 return NULL;
183 plen += size.cx;
184 }
185 }
186
187 (*count)--;
188 if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK))
189 {
190 if (plen > width)
191 {
192 if (format & DT_WORDBREAK)
193 {
194 if (wb_j)
195 {
196 *len = wb_j;
197 *count = wb_count - 1;
198 return (&str[wb_i]);
199 }
200 }
201 else
202 {
203 *len = j;
204 return (&str[i]);
205 }
206 }
207 }
208 }
209
210 *len = j;
211 return NULL;
212}
213
214
215#ifndef __WIN32OS2__
216/***********************************************************************
217 * DrawText (USER.85)
218 */
219INT16 WINAPI DrawText16( HDC16 hdc, LPCSTR str, INT16 count, LPRECT16 rect, UINT16 flags )
220{
221 INT16 ret;
222
223 if (rect)
224 {
225 RECT rect32;
226 CONV_RECT16TO32( rect, &rect32 );
227 ret = DrawTextA( hdc, str, count, &rect32, flags );
228 CONV_RECT32TO16( &rect32, rect );
229 }
230 else ret = DrawTextA( hdc, str, count, NULL, flags);
231 return ret;
232}
233#endif
234
235/***********************************************************************
236 * DrawTextExW (USER32.@)
237 */
238#define MAX_STATIC_BUFFER 1024
239INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count,
240 LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
241{
242 SIZE size;
243 const WCHAR *strPtr;
244 static WCHAR line[MAX_STATIC_BUFFER];
245 int len, lh, count=i_count;
246 int prefix_x = 0;
247 int prefix_end = 0;
248 TEXTMETRICW tm;
249 int lmargin = 0, rmargin = 0;
250 int x = rect->left, y = rect->top;
251 int width = rect->right - rect->left;
252 int max_width = 0;
253
254#ifdef __WIN32OS2__
255 dprintf(("DrawTextExW: %ls, %d , [(%d,%d),(%d,%d)]\n", str, count,
256 rect->left, rect->top, rect->right, rect->bottom));
257#else
258 TRACE("%s, %d , [(%d,%d),(%d,%d)]\n", debugstr_wn (str, count), count,
259 rect->left, rect->top, rect->right, rect->bottom);
260#endif
261
262 if (dtp) TRACE("Params: iTabLength=%d, iLeftMargin=%d, iRightMargin=%d\n",
263 dtp->iTabLength, dtp->iLeftMargin, dtp->iRightMargin);
264
265 if (!str) return 0;
266 if (count == -1) count = strlenW(str);
267 if (count == 0) return 0;
268 strPtr = str;
269
270 GetTextMetricsW(hdc, &tm);
271 if (flags & DT_EXTERNALLEADING)
272 lh = tm.tmHeight + tm.tmExternalLeading;
273 else
274 lh = tm.tmHeight;
275
276 if (dtp)
277 {
278 lmargin = dtp->iLeftMargin * tm.tmAveCharWidth;
279 rmargin = dtp->iRightMargin * tm.tmAveCharWidth;
280 if (!(flags & (DT_CENTER | DT_RIGHT)))
281 x += lmargin;
282 dtp->uiLengthDrawn = 0; /* This param RECEIVES number of chars processed */
283 }
284
285 if (flags & DT_TABSTOP)
286 tabstop = dtp ? dtp->iTabLength : flags >> 8;
287
288 if (flags & DT_EXPANDTABS)
289 {
290 GetTextExtentPointW(hdc, SPACEW, 1, &size);
291 spacewidth = size.cx;
292 GetTextExtentPointW(hdc, oW, 1, &size);
293 tabwidth = size.cx * tabstop;
294 }
295
296 if (flags & DT_CALCRECT) flags |= DT_NOCLIP;
297
298 do
299 {
300 prefix_offset = -1;
301 len = MAX_STATIC_BUFFER;
302 strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags);
303
304 if (prefix_offset != -1)
305 {
306 GetTextExtentPointW(hdc, line, prefix_offset, &size);
307 prefix_x = size.cx;
308 GetTextExtentPointW(hdc, line, prefix_offset + 1, &size);
309 prefix_end = size.cx - 1;
310 }
311
312 if (!GetTextExtentPointW(hdc, line, len, &size)) return 0;
313 if (flags & DT_CENTER) x = (rect->left + rect->right -
314 size.cx) / 2;
315 else if (flags & DT_RIGHT) x = rect->right - size.cx;
316
317 if (flags & DT_SINGLELINE)
318 {
319 if (flags & DT_VCENTER) y = rect->top +
320 (rect->bottom - rect->top) / 2 - size.cy / 2;
321 else if (flags & DT_BOTTOM) y = rect->bottom - size.cy;
322
323 if (flags & (DT_PATH_ELLIPSIS | DT_END_ELLIPSIS | DT_WORD_ELLIPSIS))
324 {
325 WCHAR swapStr[sizeof(line)];
326 WCHAR* fnameDelim = NULL;
327 int totalLen = i_count >= 0 ? i_count : strlenW(str);
328
329 if (size.cx > width)
330 {
331 int fnameLen = totalLen;
332
333 /* allow room for '...' */
334 count = min(totalLen+3, sizeof(line)-3);
335
336 if (flags & DT_WORD_ELLIPSIS)
337 flags |= DT_WORDBREAK;
338
339 if (flags & DT_PATH_ELLIPSIS)
340 {
341 WCHAR* lastBkSlash = NULL;
342 WCHAR* lastFwdSlash = NULL;
343 strncpyW(line, str, totalLen);
344 line[totalLen] = '\0';
345 lastBkSlash = strrchrW(line, BACK_SLASHW[0]);
346 lastFwdSlash = strrchrW(line, FORWARD_SLASHW[0]);
347 fnameDelim = lastBkSlash > lastFwdSlash ? lastBkSlash : lastFwdSlash;
348
349 if (fnameDelim)
350 fnameLen = &line[totalLen] - fnameDelim;
351 else
352 fnameDelim = (WCHAR*)str;
353
354 strcpyW(swapStr, ELLIPSISW);
355 strncpyW(swapStr+strlenW(swapStr), fnameDelim, fnameLen);
356 swapStr[fnameLen+3] = '\0';
357 strncpyW(swapStr+strlenW(swapStr), str, totalLen - fnameLen);
358 swapStr[totalLen+3] = '\0';
359 }
360 else /* DT_END_ELLIPSIS | DT_WORD_ELLIPSIS */
361 {
362 strcpyW(swapStr, ELLIPSISW);
363 strncpyW(swapStr+strlenW(swapStr), str, totalLen);
364 }
365
366 len = MAX_STATIC_BUFFER;
367 TEXT_NextLineW(hdc, swapStr, &count, line, &len, width, flags);
368
369 /* if only the ELLIPSIS will fit, just let it be clipped */
370 len = max(3, len);
371 GetTextExtentPointW(hdc, line, len, &size);
372
373 /* FIXME:
374 * NextLine uses GetTextExtentPoint for each character,
375 * rather than GetCharABCWidth... So the whitespace between
376 * characters is ignored in the width measurement, and the
377 * reported len is too great. To compensate, we must get
378 * the width of the entire line and adjust len accordingly.
379 */
380 while ((size.cx > width) && (len > 3))
381 {
382 line[--len] = '\0';
383 GetTextExtentPointW(hdc, line, len, &size);
384 }
385
386 if (fnameLen < len-3) /* some of the path will fit */
387 {
388 /* put the ELLIPSIS between the path and filename */
389 strncpyW(swapStr, &line[fnameLen+3], len-3-fnameLen);
390 swapStr[len-3-fnameLen] = '\0';
391 strcatW(swapStr, ELLIPSISW);
392 strncpyW(swapStr+strlenW(swapStr), &line[3], fnameLen);
393 }
394 else
395 {
396 /* move the ELLIPSIS to the end */
397 strncpyW(swapStr, &line[3], len-3);
398 swapStr[len-3] = '\0';
399 strcpyW(swapStr+strlenW(swapStr), ELLIPSISW);
400 }
401
402 strncpyW(line, swapStr, len);
403 line[len] = '\0';
404 strPtr = NULL;
405 }
406 if (flags & DT_MODIFYSTRING)
407 strcpyW(str, swapStr);
408 }
409 }
410 if (!(flags & DT_CALCRECT))
411 {
412 if (!ExtTextOutW( hdc, x, y,
413 ((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) |
414 ((flags & DT_RTLREADING) ? ETO_RTLREADING : 0),
415 rect, line, len, NULL )) return 0;
416 if (prefix_offset != -1)
417 {
418 HPEN hpen = CreatePen( PS_SOLID, 1, GetTextColor(hdc) );
419 HPEN oldPen = SelectObject( hdc, hpen );
420 MoveToEx(hdc, x + prefix_x, y + tm.tmAscent + 1, NULL );
421 LineTo(hdc, x + prefix_end + 1, y + tm.tmAscent + 1 );
422 SelectObject( hdc, oldPen );
423 DeleteObject( hpen );
424 }
425 }
426 else if (size.cx > max_width)
427 max_width = size.cx;
428
429 y += lh;
430 if (strPtr)
431 {
432 if (!(flags & DT_NOCLIP))
433 {
434 if (y > rect->bottom - lh)
435 break;
436 }
437 }
438 if (dtp)
439 dtp->uiLengthDrawn += len;
440 }
441 while (strPtr);
442
443 if (flags & DT_CALCRECT)
444 {
445 rect->right = rect->left + max_width;
446 rect->bottom = y;
447 if (dtp)
448 rect->right += lmargin + rmargin;
449 }
450 return y - rect->top;
451}
452
453/***********************************************************************
454 * DrawTextExA (USER32.@)
455 */
456INT WINAPI DrawTextExA( HDC hdc, LPCSTR str, INT count,
457 LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
458{
459 WCHAR *wstr;
460 INT ret = 0;
461 DWORD wcount;
462
463 if (count == -1) count = strlen(str);
464 if (!count) return 0;
465 wcount = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
466 wstr = HeapAlloc(GetProcessHeap(), 0, wcount * sizeof(WCHAR));
467 if (wstr)
468 {
469 MultiByteToWideChar( CP_ACP, 0, str, count, wstr, wcount );
470 ret = DrawTextExW( hdc, wstr, wcount, rect, flags, NULL );
471 if (flags & DT_MODIFYSTRING)
472 WideCharToMultiByte( CP_ACP, 0, wstr, -1, str, count, NULL, NULL );
473 HeapFree(GetProcessHeap(), 0, wstr);
474 }
475 return ret;
476}
477
478/***********************************************************************
479 * DrawTextW (USER32.@)
480 */
481INT WINAPI DrawTextW( HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags )
482{
483 return DrawTextExW(hdc, (LPWSTR)str, count, rect, flags, NULL);
484}
485
486/***********************************************************************
487 * DrawTextA (USER32.@)
488 */
489INT WINAPI DrawTextA( HDC hdc, LPCSTR str, INT count, LPRECT rect, UINT flags )
490{
491 return DrawTextExA( hdc, (LPSTR)str, count, rect, flags, NULL );
492}
493
494/***********************************************************************
495 * TEXT_GrayString
496 *
497 * FIXME: The call to 16-bit code only works because the wine GDI is a 16-bit
498 * heap and we can guarantee that the handles fit in an INT16. We have to
499 * rethink the strategy once the migration to NT handles is complete.
500 * We are going to get a lot of code-duplication once this migration is
501 * completed...
502 *
503 */
504static BOOL TEXT_GrayString(HDC hdc, HBRUSH hb, GRAYSTRINGPROC fn, LPARAM lp, INT len,
505 INT x, INT y, INT cx, INT cy, BOOL unicode, BOOL _32bit)
506{
507 HBITMAP hbm, hbmsave;
508 HBRUSH hbsave;
509 HFONT hfsave;
510 HDC memdc = CreateCompatibleDC(hdc);
511 int slen = len;
512 BOOL retval = TRUE;
513 COLORREF fg, bg;
514
515#ifdef __WIN32OS2__
516 dprintf(("GrayString %x %x %x %x %d (%d,%d)(%d,%d)", hdc, hb, fn, lp, len, x, y, cx, cy));
517 if(!hdc) {
518 DeleteDC(memdc);
519 return FALSE;
520 }
521#else
522 if(!hdc) return FALSE;
523#endif
524
525 if(len == 0)
526 {
527 if(unicode)
528 slen = lstrlenW((LPCWSTR)lp);
529 else if(_32bit)
530 slen = strlen((LPCSTR)lp);
531 else
532 slen = strlen(MapSL(lp));
533 }
534
535 if((cx == 0 || cy == 0) && slen != -1)
536 {
537 SIZE s;
538 if(unicode)
539 GetTextExtentPoint32W(hdc, (LPCWSTR)lp, slen, &s);
540 else if(_32bit)
541 GetTextExtentPoint32A(hdc, (LPCSTR)lp, slen, &s);
542 else
543 GetTextExtentPoint32A(hdc, MapSL(lp), slen, &s);
544 if(cx == 0) cx = s.cx;
545 if(cy == 0) cy = s.cy;
546 }
547
548 hbm = CreateBitmap(cx, cy, 1, 1, NULL);
549 hbmsave = (HBITMAP)SelectObject(memdc, hbm);
550 hbsave = SelectObject( memdc, GetStockObject(BLACK_BRUSH) );
551 PatBlt( memdc, 0, 0, cx, cy, PATCOPY );
552 SelectObject( memdc, hbsave );
553 SetTextColor(memdc, RGB(255, 255, 255));
554 SetBkColor(memdc, RGB(0, 0, 0));
555 hfsave = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
556
557 if(fn)
558 {
559 if(_32bit)
560 retval = fn(memdc, lp, slen);
561 else
562 retval = (BOOL)((BOOL16)((GRAYSTRINGPROC16)fn)((HDC16)memdc, lp, (INT16)slen));
563 }
564 else
565 {
566 if(unicode)
567 TextOutW(memdc, 0, 0, (LPCWSTR)lp, slen);
568 else if(_32bit)
569 TextOutA(memdc, 0, 0, (LPCSTR)lp, slen);
570 else
571 TextOutA(memdc, 0, 0, MapSL(lp), slen);
572 }
573
574 SelectObject(memdc, hfsave);
575
576/*
577 * Windows doc says that the bitmap isn't grayed when len == -1 and
578 * the callback function returns FALSE. However, testing this on
579 * win95 showed otherwise...
580*/
581#ifdef GRAYSTRING_USING_DOCUMENTED_BEHAVIOUR
582 if(retval || len != -1)
583#endif
584 {
585 hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
586 PatBlt(memdc, 0, 0, cx, cy, 0x000A0329);
587 SelectObject(memdc, hbsave);
588 }
589
590 if(hb) hbsave = (HBRUSH)SelectObject(hdc, hb);
591 fg = SetTextColor(hdc, RGB(0, 0, 0));
592 bg = SetBkColor(hdc, RGB(255, 255, 255));
593 BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00E20746);
594 SetTextColor(hdc, fg);
595 SetBkColor(hdc, bg);
596 if(hb) SelectObject(hdc, hbsave);
597
598 SelectObject(memdc, hbmsave);
599 DeleteObject(hbm);
600 DeleteDC(memdc);
601 return retval;
602}
603
604
605#ifndef __WIN32OS2__
606/***********************************************************************
607 * GrayString16 (USER.185)
608 */
609BOOL16 WINAPI GrayString16( HDC16 hdc, HBRUSH16 hbr, GRAYSTRINGPROC16 gsprc,
610 LPARAM lParam, INT16 cch, INT16 x, INT16 y,
611 INT16 cx, INT16 cy )
612{
613 return TEXT_GrayString(hdc, hbr, (GRAYSTRINGPROC)gsprc, lParam, cch,
614 x, y, cx, cy, FALSE, FALSE);
615}
616#endif
617
618/***********************************************************************
619 * GrayStringA (USER32.@)
620 */
621BOOL WINAPI GrayStringA( HDC hdc, HBRUSH hbr, GRAYSTRINGPROC gsprc,
622 LPARAM lParam, INT cch, INT x, INT y,
623 INT cx, INT cy )
624{
625 return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy,
626 FALSE, TRUE);
627}
628
629
630/***********************************************************************
631 * GrayStringW (USER32.@)
632 */
633BOOL WINAPI GrayStringW( HDC hdc, HBRUSH hbr, GRAYSTRINGPROC gsprc,
634 LPARAM lParam, INT cch, INT x, INT y,
635 INT cx, INT cy )
636{
637 return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy,
638 TRUE, TRUE);
639}
640
641/***********************************************************************
642 * TEXT_TabbedTextOut
643 *
644 * Helper function for TabbedTextOut() and GetTabbedTextExtent().
645 * Note: this doesn't work too well for text-alignment modes other
646 * than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
647 */
648static LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCSTR lpstr,
649 INT count, INT cTabStops, const INT16 *lpTabPos16,
650 const INT *lpTabPos32, INT nTabOrg,
651 BOOL fDisplayText )
652{
653 INT defWidth;
654 SIZE extent;
655 int i, tabPos = x;
656 int start = x;
657
658 extent.cx = 0;
659 extent.cy = 0;
660
661 if (cTabStops == 1)
662 {
663 defWidth = lpTabPos32 ? *lpTabPos32 : *lpTabPos16;
664 cTabStops = 0;
665 }
666 else
667 {
668 TEXTMETRICA tm;
669 GetTextMetricsA( hdc, &tm );
670 defWidth = 8 * tm.tmAveCharWidth;
671 }
672
673 while (count > 0)
674 {
675 for (i = 0; i < count; i++)
676 if (lpstr[i] == '\t') break;
677 GetTextExtentPointA( hdc, lpstr, i, &extent );
678 if (lpTabPos32)
679 {
680 while ((cTabStops > 0) &&
681 (nTabOrg + *lpTabPos32 <= x + extent.cx))
682 {
683 lpTabPos32++;
684 cTabStops--;
685 }
686 }
687 else
688 {
689 while ((cTabStops > 0) &&
690 (nTabOrg + *lpTabPos16 <= x + extent.cx))
691 {
692 lpTabPos16++;
693 cTabStops--;
694 }
695 }
696 if (i == count)
697 tabPos = x + extent.cx;
698 else if (cTabStops > 0)
699 tabPos = nTabOrg + (lpTabPos32 ? *lpTabPos32 : *lpTabPos16);
700 else
701 tabPos = nTabOrg + ((x + extent.cx - nTabOrg) / defWidth + 1) * defWidth;
702 if (fDisplayText)
703 {
704 RECT r;
705 r.left = x;
706 r.top = y;
707 r.right = tabPos;
708 r.bottom = y + extent.cy;
709 ExtTextOutA( hdc, x, y,
710 GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
711 &r, lpstr, i, NULL );
712 }
713 x = tabPos;
714 count -= i+1;
715 lpstr += i+1;
716 }
717 return MAKELONG(tabPos - start, extent.cy);
718}
719
720
721#ifndef __WIN32OS2__
722/***********************************************************************
723 * TabbedTextOut (USER.196)
724 */
725LONG WINAPI TabbedTextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR lpstr,
726 INT16 count, INT16 cTabStops,
727 const INT16 *lpTabPos, INT16 nTabOrg )
728{
729 TRACE("%04x %d,%d %s %d\n", hdc, x, y, debugstr_an(lpstr,count), count );
730 return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
731 lpTabPos, NULL, nTabOrg, TRUE );
732}
733#endif
734
735/***********************************************************************
736 * TabbedTextOutA (USER32.@)
737 */
738LONG WINAPI TabbedTextOutA( HDC hdc, INT x, INT y, LPCSTR lpstr, INT count,
739 INT cTabStops, const INT *lpTabPos, INT nTabOrg )
740{
741#ifdef __WIN32OS2__
742 dprintf(("TabbedTextOutA: %04x %d,%d %s %d\n", hdc, x, y, lpstr, count ));
743#else
744 TRACE("%04x %d,%d %s %d\n", hdc, x, y, debugstr_an(lpstr,count), count );
745#endif
746 return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
747 NULL, lpTabPos, nTabOrg, TRUE );
748}
749
750
751/***********************************************************************
752 * TabbedTextOutW (USER32.@)
753 */
754LONG WINAPI TabbedTextOutW( HDC hdc, INT x, INT y, LPCWSTR str, INT count,
755 INT cTabStops, const INT *lpTabPos, INT nTabOrg )
756{
757 LONG ret;
758 LPSTR p;
759 INT acount;
760 UINT codepage = CP_ACP; /* FIXME: get codepage of font charset */
761
762 acount = WideCharToMultiByte(codepage,0,str,count,NULL,0,NULL,NULL);
763 p = HeapAlloc( GetProcessHeap(), 0, acount );
764 if(p == NULL) return 0; /* FIXME: is this the correct return on failure */
765 acount = WideCharToMultiByte(codepage,0,str,count,p,acount,NULL,NULL);
766 ret = TabbedTextOutA( hdc, x, y, p, acount, cTabStops, lpTabPos, nTabOrg );
767 HeapFree( GetProcessHeap(), 0, p );
768 return ret;
769}
770
771
772#ifndef __WIN32OS2__
773/***********************************************************************
774 * GetTabbedTextExtent (USER.197)
775 */
776DWORD WINAPI GetTabbedTextExtent16( HDC16 hdc, LPCSTR lpstr, INT16 count,
777 INT16 cTabStops, const INT16 *lpTabPos )
778{
779 TRACE("%04x %s %d\n", hdc, debugstr_an(lpstr,count), count );
780 return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
781 lpTabPos, NULL, 0, FALSE );
782}
783#endif
784
785/***********************************************************************
786 * GetTabbedTextExtentA (USER32.@)
787 */
788DWORD WINAPI GetTabbedTextExtentA( HDC hdc, LPCSTR lpstr, INT count,
789 INT cTabStops, const INT *lpTabPos )
790{
791#ifdef __WIN32OS2__
792 dprintf(("GetTabbedTextExtentA: %04x %s %d\n", hdc, lpstr, count ));
793#else
794 TRACE("%04x %s %d\n", hdc, debugstr_an(lpstr,count), count );
795#endif
796 return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
797 NULL, lpTabPos, 0, FALSE );
798}
799
800
801/***********************************************************************
802 * GetTabbedTextExtentW (USER32.@)
803 */
804DWORD WINAPI GetTabbedTextExtentW( HDC hdc, LPCWSTR lpstr, INT count,
805 INT cTabStops, const INT *lpTabPos )
806{
807 LONG ret;
808 LPSTR p;
809 INT acount;
810 UINT codepage = CP_ACP; /* FIXME: get codepage of font charset */
811
812 acount = WideCharToMultiByte(codepage,0,lpstr,count,NULL,0,NULL,NULL);
813 p = HeapAlloc( GetProcessHeap(), 0, acount );
814 if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
815 acount = WideCharToMultiByte(codepage,0,lpstr,count,p,acount,NULL,NULL);
816 ret = GetTabbedTextExtentA( hdc, p, acount, cTabStops, lpTabPos );
817 HeapFree( GetProcessHeap(), 0, p );
818 return ret;
819}
Note: See TracBrowser for help on using the repository browser.