Newer
Older
/*
* USER text functions
*
* Copyright 1993, 1994 Alexandre Julliard
*
* Contains
* 1. DrawText functions
* 2. GrayString functions
* 3. TabbedText functions
*/
#include <string.h>
#include "windef.h"
#include "wingdi.h"
#include "wine/winuser16.h"
#include "wine/unicode.h"
#include "winbase.h"
#include "winerror.h"
#include "winnls.h"
#include "user.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(text);
/*********************************************************************
*
* DrawText functions
*/
#define TAB 9
#define LF 10
#define CR 13
#define SPACE 32
#define PREFIX 38
#define ELLIPSIS "..."
#define FORWARD_SLASH '/'
#define BACK_SLASH '\\'
static const WCHAR SPACEW[] = {' ', 0};
static const WCHAR oW[] = {'o', 0};
static const WCHAR ELLIPSISW[] = {'.','.','.', 0};
static const WCHAR FORWARD_SLASHW[] = {'/', 0};
static const WCHAR BACK_SLASHW[] = {'\\', 0};
static int tabwidth;
static int spacewidth;
static int prefix_offset;
/*********************************************************************
* Return next line of text from a string.
*
* hdc - handle to DC.
* str - string to parse into lines.
* count - length of str.
* dest - destination in which to return line.
* len - dest buffer size in chars on input, copied length into dest on output.
* width - maximum width of line in pixels.
* format - format type passed to DrawText.
*
* Returns pointer to next char in str after end of the line
* or NULL if end of str reached.
*
* FIXME:
* GetTextExtentPoint is used to get the width of each character,
* rather than GetCharABCWidth... So the whitespace between
* characters is ignored, and the reported len is too great.
*/
static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count,
WCHAR *dest, int *len, int width, WORD format)
{
int i = 0, j = 0, k;
int plen = 0;
int numspaces;
SIZE size;
int lasttab = 0;
int wb_i = 0, wb_j = 0, wb_count = 0;
{
switch (str[i])
{
case CR:
case LF:
if (!(format & DT_SINGLELINE))
{
if ((*count > 1) && (str[i] == CR) && (str[i+1] == LF))
{
(*count)--;
i++;
}
i++;
*len = j;
(*count)--;
return (&str[i]);
}
dest[j++] = str[i++];
if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
(format & DT_WORDBREAK))
{
if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size))
return NULL;
plen += size.cx;
}
break;
case PREFIX:
if (!(format & DT_NOPREFIX) && *count > 1)
{
if (str[++i] == PREFIX)
(*count)--;
else {
prefix_offset = j;
break;
}
}
dest[j++] = str[i++];
if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
(format & DT_WORDBREAK))
{
if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size))
return NULL;
plen += size.cx;
}
break;
case TAB:
if (format & DT_EXPANDTABS)
{
wb_i = ++i;
wb_j = j;
wb_count = *count;
if (!GetTextExtentPointW(hdc, &dest[lasttab], j - lasttab, &size))
return NULL;
numspaces = (tabwidth - size.cx) / spacewidth;
for (k = 0; k < numspaces; k++)
dest[j++] = SPACE;
plen += tabwidth - size.cx;
lasttab = wb_j + numspaces;
}
else
{
dest[j++] = str[i++];
if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
(format & DT_WORDBREAK))
{
if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size))
return NULL;
plen += size.cx;
}
}
break;
case SPACE:
dest[j++] = str[i++];
if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
(format & DT_WORDBREAK))
{
wb_i = i;
wb_j = j - 1;
wb_count = *count;
if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size))
return NULL;
plen += size.cx;
}
break;
default:
dest[j++] = str[i++];
if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) ||
(format & DT_WORDBREAK))
{
if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size))
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
return NULL;
plen += size.cx;
}
}
(*count)--;
if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK))
{
if (plen > width)
{
if (format & DT_WORDBREAK)
{
if (wb_j)
{
*len = wb_j;
*count = wb_count - 1;
return (&str[wb_i]);
}
}
else
{
*len = j;
return (&str[i]);
}
}
}
}
*len = j;
return NULL;
}
/***********************************************************************
#define MAX_STATIC_BUFFER 1024
INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count,
LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
{
SIZE size;
const WCHAR *strPtr;
static WCHAR line[MAX_STATIC_BUFFER];
int len, lh, count=i_count;
int prefix_x = 0;
int prefix_end = 0;
TEXTMETRICW tm;
int lmargin = 0, rmargin = 0;
int x = rect->left, y = rect->top;
int width = rect->right - rect->left;
int max_width = 0;
TRACE("%s, %d , [(%d,%d),(%d,%d)]\n", debugstr_wn (str, count), count,
rect->left, rect->top, rect->right, rect->bottom);
if (dtp) TRACE("Params: iTabLength=%d, iLeftMargin=%d, iRightMargin=%d\n",
dtp->iTabLength, dtp->iLeftMargin, dtp->iRightMargin);
if (!str) return 0;
if (count == -1) count = strlenW(str);
if (count == 0) return 0;
strPtr = str;
GetTextMetricsW(hdc, &tm);
if (flags & DT_EXTERNALLEADING)
lh = tm.tmHeight + tm.tmExternalLeading;
else
lh = tm.tmHeight;
if (dtp)
{
lmargin = dtp->iLeftMargin * tm.tmAveCharWidth;
rmargin = dtp->iRightMargin * tm.tmAveCharWidth;
if (!(flags & (DT_CENTER | DT_RIGHT)))
x += lmargin;
dtp->uiLengthDrawn = 0; /* This param RECEIVES number of chars processed */
}
tabstop = ((flags & DT_TABSTOP) && dtp) ? dtp->iTabLength : 8;
if (flags & DT_EXPANDTABS)
{
GetTextExtentPointW(hdc, SPACEW, 1, &size);
spacewidth = size.cx;
GetTextExtentPointW(hdc, oW, 1, &size);
tabwidth = size.cx * tabstop;
}
if (flags & DT_CALCRECT) flags |= DT_NOCLIP;
do
{
prefix_offset = -1;
strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags);
if (prefix_offset != -1)
{
GetTextExtentPointW(hdc, line, prefix_offset, &size);
prefix_x = size.cx;
GetTextExtentPointW(hdc, line, prefix_offset + 1, &size);
prefix_end = size.cx - 1;
}
if (!GetTextExtentPointW(hdc, line, len, &size)) return 0;
if (flags & DT_CENTER) x = (rect->left + rect->right -
size.cx) / 2;
else if (flags & DT_RIGHT) x = rect->right - size.cx;
if (flags & DT_SINGLELINE)
{
if (flags & DT_VCENTER) y = rect->top +
(rect->bottom - rect->top) / 2 - size.cy / 2;
else if (flags & DT_BOTTOM) y = rect->bottom - size.cy;
if (flags & (DT_PATH_ELLIPSIS | DT_END_ELLIPSIS | DT_WORD_ELLIPSIS))
{
WCHAR swapStr[sizeof(line)];
WCHAR* fnameDelim = NULL;
int totalLen = i_count >= 0 ? i_count : strlenW(str);
if (size.cx > width)
{
int fnameLen = totalLen;
/* allow room for '...' */
count = min(totalLen+3, sizeof(line)-3);
if (flags & DT_WORD_ELLIPSIS)
flags |= DT_WORDBREAK;
if (flags & DT_PATH_ELLIPSIS)
WCHAR* lastBkSlash = NULL;
WCHAR* lastFwdSlash = NULL;
strncpyW(line, str, totalLen);
line[totalLen] = '\0';
lastBkSlash = strrchrW(line, BACK_SLASHW[0]);
lastFwdSlash = strrchrW(line, FORWARD_SLASHW[0]);
fnameDelim = lastBkSlash > lastFwdSlash ? lastBkSlash : lastFwdSlash;
if (fnameDelim)
fnameLen = &line[totalLen] - fnameDelim;
fnameDelim = (WCHAR*)str;
strcpyW(swapStr, ELLIPSISW);
strncpyW(swapStr+strlenW(swapStr), fnameDelim, fnameLen);
swapStr[fnameLen+3] = '\0';
strncpyW(swapStr+strlenW(swapStr), str, totalLen - fnameLen);
swapStr[totalLen+3] = '\0';
}
else /* DT_END_ELLIPSIS | DT_WORD_ELLIPSIS */
{
strcpyW(swapStr, ELLIPSISW);
strncpyW(swapStr+strlenW(swapStr), str, totalLen);
}
TEXT_NextLineW(hdc, swapStr, &count, line, &len, width, flags);
/* if only the ELLIPSIS will fit, just let it be clipped */
len = max(3, len);
GetTextExtentPointW(hdc, line, len, &size);
/* FIXME:
* NextLine uses GetTextExtentPoint for each character,
* rather than GetCharABCWidth... So the whitespace between
* characters is ignored in the width measurement, and the
* reported len is too great. To compensate, we must get
* the width of the entire line and adjust len accordingly.
*/
while ((size.cx > width) && (len > 3))
{
line[--len] = '\0';
GetTextExtentPointW(hdc, line, len, &size);
}
if (fnameLen < len-3) /* some of the path will fit */
{
/* put the ELLIPSIS between the path and filename */
strncpyW(swapStr, &line[fnameLen+3], len-3-fnameLen);
swapStr[len-3-fnameLen] = '\0';
strcatW(swapStr, ELLIPSISW);
strncpyW(swapStr+strlenW(swapStr), &line[3], fnameLen);
}
else
{
/* move the ELLIPSIS to the end */
strncpyW(swapStr, &line[3], len-3);
swapStr[len-3] = '\0';
strcpyW(swapStr+strlenW(swapStr), ELLIPSISW);
}
strncpyW(line, swapStr, len);
line[len] = '\0';
strPtr = NULL;
}
if (flags & DT_MODIFYSTRING)
strcpyW(str, swapStr);
}
if (!(flags & DT_CALCRECT))
{
((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) |
((flags & DT_RTLREADING) ? ETO_RTLREADING : 0),
rect, line, len, NULL )) return 0;
if (prefix_offset != -1)
{
HPEN hpen = CreatePen( PS_SOLID, 1, GetTextColor(hdc) );
HPEN oldPen = SelectObject( hdc, hpen );
MoveToEx(hdc, x + prefix_x, y + tm.tmAscent + 1, NULL );
LineTo(hdc, x + prefix_end + 1, y + tm.tmAscent + 1 );
SelectObject( hdc, oldPen );
DeleteObject( hpen );
}
}
else if (size.cx > max_width)
max_width = size.cx;
y += lh;
if (strPtr)
{
if (!(flags & DT_NOCLIP))
{
if (y > rect->bottom - lh)
break;
}
}
if (dtp)
dtp->uiLengthDrawn += len;
}
while (strPtr);
if (flags & DT_CALCRECT)
{
rect->right = rect->left + max_width;
rect->bottom = y;
if (dtp)
rect->right += lmargin + rmargin;
}
return y - rect->top;
}
/***********************************************************************
INT WINAPI DrawTextExA( HDC hdc, LPSTR str, INT count,
LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
{
WCHAR *wstr;
INT ret = 0;
DWORD wcount;
if (count == -1) count = strlen(str);
if (!count) return 0;
wcount = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 );
wstr = HeapAlloc(GetProcessHeap(), 0, wcount * sizeof(WCHAR));
if (wstr)
{
MultiByteToWideChar( CP_ACP, 0, str, count, wstr, wcount );
ret = DrawTextExW( hdc, wstr, wcount, rect, flags, NULL );
if (flags & DT_MODIFYSTRING)
WideCharToMultiByte( CP_ACP, 0, wstr, -1, str, count, NULL, NULL );
HeapFree(GetProcessHeap(), 0, wstr);
}
return ret;
}
/***********************************************************************
INT WINAPI DrawTextW( HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags )
DRAWTEXTPARAMS dtp;
memset (&dtp, 0, sizeof(dtp));
if (flags & DT_TABSTOP)
{
dtp.iTabLength = (flags >> 8) && 0xff;
flags &= 0xffff00ff;
}
return DrawTextExW(hdc, (LPWSTR)str, count, rect, flags, &dtp);
}
/***********************************************************************
INT WINAPI DrawTextA( HDC hdc, LPCSTR str, INT count, LPRECT rect, UINT flags )
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
DRAWTEXTPARAMS dtp;
memset (&dtp, 0, sizeof(dtp));
if (flags & DT_TABSTOP)
{
dtp.iTabLength = (flags >> 8) && 0xff;
flags &= 0xffff00ff;
}
return DrawTextExA( hdc, (LPSTR)str, count, rect, flags, &dtp );
}
/***********************************************************************
* DrawText (USER.85)
*/
INT16 WINAPI DrawText16( HDC16 hdc, LPCSTR str, INT16 count, LPRECT16 rect, UINT16 flags )
{
INT16 ret;
if (rect)
{
RECT rect32;
CONV_RECT16TO32( rect, &rect32 );
ret = DrawTextA( hdc, str, count, &rect32, flags );
CONV_RECT32TO16( &rect32, rect );
}
else ret = DrawTextA( hdc, str, count, NULL, flags);
return ret;
}
/***********************************************************************
*
* GrayString functions
*/
/* ### start build ### */
extern WORD CALLBACK TEXT_CallTo16_word_wlw(GRAYSTRINGPROC16,WORD,LONG,WORD);
/* ### stop build ### */
struct gray_string_info
{
GRAYSTRINGPROC16 proc;
LPARAM param;
};
/* callback for 16-bit gray string proc */
static BOOL CALLBACK gray_string_callback( HDC hdc, LPARAM param, INT len )
{
const struct gray_string_info *info = (struct gray_string_info *)param;
return TEXT_CallTo16_word_wlw( info->proc, hdc, info->param, len );
}
/***********************************************************************
* TEXT_GrayString
*
* FIXME: The call to 16-bit code only works because the wine GDI is a 16-bit
* heap and we can guarantee that the handles fit in an INT16. We have to
* rethink the strategy once the migration to NT handles is complete.
* We are going to get a lot of code-duplication once this migration is
* completed...
*
*/
static BOOL TEXT_GrayString(HDC hdc, HBRUSH hb, GRAYSTRINGPROC fn, LPARAM lp, INT len,
INT x, INT y, INT cx, INT cy, BOOL unicode, BOOL _32bit)
{
HBITMAP hbm, hbmsave;
HBRUSH hbsave;
HFONT hfsave;
int slen = len;
BOOL retval = TRUE;
COLORREF fg, bg;
if(!hdc) return FALSE;
if (!(memdc = CreateCompatibleDC(hdc))) return FALSE;
if(len == 0)
{
if(unicode)
slen = lstrlenW((LPCWSTR)lp);
else if(_32bit)
slen = strlen((LPCSTR)lp);
else
slen = strlen(MapSL(lp));
}
if((cx == 0 || cy == 0) && slen != -1)
{
SIZE s;
if(unicode)
GetTextExtentPoint32W(hdc, (LPCWSTR)lp, slen, &s);
else if(_32bit)
GetTextExtentPoint32A(hdc, (LPCSTR)lp, slen, &s);
else
GetTextExtentPoint32A(hdc, MapSL(lp), slen, &s);
if(cx == 0) cx = s.cx;
if(cy == 0) cy = s.cy;
}
hbm = CreateBitmap(cx, cy, 1, 1, NULL);
hbmsave = (HBITMAP)SelectObject(memdc, hbm);
hbsave = SelectObject( memdc, GetStockObject(BLACK_BRUSH) );
PatBlt( memdc, 0, 0, cx, cy, PATCOPY );
SelectObject( memdc, hbsave );
SetTextColor(memdc, RGB(255, 255, 255));
SetBkColor(memdc, RGB(0, 0, 0));
hfsave = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
if(fn)
{
if(_32bit)
retval = fn(memdc, lp, slen);
else
retval = (BOOL)((BOOL16)((GRAYSTRINGPROC16)fn)((HDC16)memdc, lp, (INT16)slen));
}
else
{
if(unicode)
TextOutW(memdc, 0, 0, (LPCWSTR)lp, slen);
else if(_32bit)
TextOutA(memdc, 0, 0, (LPCSTR)lp, slen);
else
TextOutA(memdc, 0, 0, MapSL(lp), slen);
}
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
SelectObject(memdc, hfsave);
/*
* Windows doc says that the bitmap isn't grayed when len == -1 and
* the callback function returns FALSE. However, testing this on
* win95 showed otherwise...
*/
#ifdef GRAYSTRING_USING_DOCUMENTED_BEHAVIOUR
if(retval || len != -1)
#endif
{
hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
PatBlt(memdc, 0, 0, cx, cy, 0x000A0329);
SelectObject(memdc, hbsave);
}
if(hb) hbsave = (HBRUSH)SelectObject(hdc, hb);
fg = SetTextColor(hdc, RGB(0, 0, 0));
bg = SetBkColor(hdc, RGB(255, 255, 255));
BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00E20746);
SetTextColor(hdc, fg);
SetBkColor(hdc, bg);
if(hb) SelectObject(hdc, hbsave);
SelectObject(memdc, hbmsave);
DeleteObject(hbm);
DeleteDC(memdc);
return retval;
}
/***********************************************************************
*/
BOOL16 WINAPI GrayString16( HDC16 hdc, HBRUSH16 hbr, GRAYSTRINGPROC16 gsprc,
LPARAM lParam, INT16 cch, INT16 x, INT16 y,
INT16 cx, INT16 cy )
{
struct gray_string_info info;
if (!gsprc) return TEXT_GrayString(hdc, hbr, NULL, lParam, cch, x, y, cx, cy, FALSE, FALSE);
info.proc = gsprc;
info.param = lParam;
return TEXT_GrayString( hdc, hbr, gray_string_callback, (LPARAM)&info,
cch, x, y, cx, cy, FALSE, FALSE);
}
/***********************************************************************
*/
BOOL WINAPI GrayStringA( HDC hdc, HBRUSH hbr, GRAYSTRINGPROC gsprc,
LPARAM lParam, INT cch, INT x, INT y,
INT cx, INT cy )
return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy,
FALSE, TRUE);
}
/***********************************************************************
*/
BOOL WINAPI GrayStringW( HDC hdc, HBRUSH hbr, GRAYSTRINGPROC gsprc,
LPARAM lParam, INT cch, INT x, INT y,
INT cx, INT cy )
return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy,
TRUE, TRUE);
}
/***********************************************************************
*
* TabbedText functions
*/
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
/***********************************************************************
* TEXT_TabbedTextOut
*
* Helper function for TabbedTextOut() and GetTabbedTextExtent().
* Note: this doesn't work too well for text-alignment modes other
* than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
*/
static LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCSTR lpstr,
INT count, INT cTabStops, const INT16 *lpTabPos16,
const INT *lpTabPos32, INT nTabOrg,
BOOL fDisplayText )
{
INT defWidth;
SIZE extent;
int i, tabPos = x;
int start = x;
extent.cx = 0;
extent.cy = 0;
if (cTabStops == 1)
{
defWidth = lpTabPos32 ? *lpTabPos32 : *lpTabPos16;
cTabStops = 0;
}
else
{
TEXTMETRICA tm;
GetTextMetricsA( hdc, &tm );
defWidth = 8 * tm.tmAveCharWidth;
}
while (count > 0)
{
for (i = 0; i < count; i++)
if (lpstr[i] == '\t') break;
GetTextExtentPointA( hdc, lpstr, i, &extent );
if (lpTabPos32)
{
while ((cTabStops > 0) &&
(nTabOrg + *lpTabPos32 <= x + extent.cx))
{
lpTabPos32++;
cTabStops--;
}
}
else
{
while ((cTabStops > 0) &&
(nTabOrg + *lpTabPos16 <= x + extent.cx))
{
lpTabPos16++;
cTabStops--;
}
}
if (i == count)
tabPos = x + extent.cx;
else if (cTabStops > 0)
tabPos = nTabOrg + (lpTabPos32 ? *lpTabPos32 : *lpTabPos16);
else
tabPos = nTabOrg + ((x + extent.cx - nTabOrg) / defWidth + 1) * defWidth;
if (fDisplayText)
{
RECT r;
r.left = x;
r.top = y;
r.right = tabPos;
r.bottom = y + extent.cy;
ExtTextOutA( hdc, x, y,
GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
&r, lpstr, i, NULL );
}
x = tabPos;
count -= i+1;
lpstr += i+1;
}
return MAKELONG(tabPos - start, extent.cy);
}
/***********************************************************************
*/
LONG WINAPI TabbedTextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR lpstr,
INT16 count, INT16 cTabStops,
const INT16 *lpTabPos, INT16 nTabOrg )
{
TRACE("%04x %d,%d %s %d\n", hdc, x, y, debugstr_an(lpstr,count), count );
return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
lpTabPos, NULL, nTabOrg, TRUE );
}
/***********************************************************************
LONG WINAPI TabbedTextOutA( HDC hdc, INT x, INT y, LPCSTR lpstr, INT count,
INT cTabStops, const INT *lpTabPos, INT nTabOrg )
TRACE("%04x %d,%d %s %d\n", hdc, x, y, debugstr_an(lpstr,count), count );
return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops,
NULL, lpTabPos, nTabOrg, TRUE );
}
/***********************************************************************
LONG WINAPI TabbedTextOutW( HDC hdc, INT x, INT y, LPCWSTR str, INT count,
INT cTabStops, const INT *lpTabPos, INT nTabOrg )
{
LONG ret;
LPSTR p;
INT acount;
UINT codepage = CP_ACP; /* FIXME: get codepage of font charset */
acount = WideCharToMultiByte(codepage,0,str,count,NULL,0,NULL,NULL);
p = HeapAlloc( GetProcessHeap(), 0, acount );
if(p == NULL) return 0; /* FIXME: is this the correct return on failure */
acount = WideCharToMultiByte(codepage,0,str,count,p,acount,NULL,NULL);
ret = TabbedTextOutA( hdc, x, y, p, acount, cTabStops, lpTabPos, nTabOrg );
HeapFree( GetProcessHeap(), 0, p );
return ret;
}
/***********************************************************************
DWORD WINAPI GetTabbedTextExtent16( HDC16 hdc, LPCSTR lpstr, INT16 count,
INT16 cTabStops, const INT16 *lpTabPos )
{
TRACE("%04x %s %d\n", hdc, debugstr_an(lpstr,count), count );
return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
lpTabPos, NULL, 0, FALSE );
}
/***********************************************************************
DWORD WINAPI GetTabbedTextExtentA( HDC hdc, LPCSTR lpstr, INT count,
INT cTabStops, const INT *lpTabPos )
TRACE("%04x %s %d\n", hdc, debugstr_an(lpstr,count), count );
return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops,
NULL, lpTabPos, 0, FALSE );
}
/***********************************************************************
DWORD WINAPI GetTabbedTextExtentW( HDC hdc, LPCWSTR lpstr, INT count,
INT cTabStops, const INT *lpTabPos )
{
LONG ret;
LPSTR p;
INT acount;
UINT codepage = CP_ACP; /* FIXME: get codepage of font charset */
acount = WideCharToMultiByte(codepage,0,lpstr,count,NULL,0,NULL,NULL);
p = HeapAlloc( GetProcessHeap(), 0, acount );
if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
acount = WideCharToMultiByte(codepage,0,lpstr,count,p,acount,NULL,NULL);
ret = GetTabbedTextExtentA( hdc, p, acount, cTabStops, lpTabPos );
HeapFree( GetProcessHeap(), 0, p );
return ret;
}