| /* | 
 |  * GDI font objects | 
 |  * | 
 |  * Copyright 1993 Alexandre Julliard | 
 |  *           1997 Alex Korobka | 
 |  * Copyright 2002,2003 Shachar Shemesh | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, write to the Free Software | 
 |  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
 |  */ | 
 |  | 
 | #include "config.h" | 
 | #include "wine/port.h" | 
 |  | 
 | #include <stdarg.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <assert.h> | 
 | #include "winerror.h" | 
 | #include "windef.h" | 
 | #include "winbase.h" | 
 | #include "winnls.h" | 
 | #include "wownt32.h" | 
 | #include "gdi.h" | 
 | #include "gdi_private.h" | 
 | #include "wine/unicode.h" | 
 | #include "wine/debug.h" | 
 |  | 
 | WINE_DEFAULT_DEBUG_CHANNEL(font); | 
 | WINE_DECLARE_DEBUG_CHANNEL(gdi); | 
 |  | 
 |   /* Device -> World size conversion */ | 
 |  | 
 | /* Performs a device to world transformation on the specified width (which | 
 |  * is in integer format). | 
 |  */ | 
 | static inline INT INTERNAL_XDSTOWS(DC *dc, INT width) | 
 | { | 
 |     FLOAT floatWidth; | 
 |  | 
 |     /* Perform operation with floating point */ | 
 |     floatWidth = (FLOAT)width * dc->xformVport2World.eM11; | 
 |     /* Round to integers */ | 
 |     return GDI_ROUND(floatWidth); | 
 | } | 
 |  | 
 | /* Performs a device to world transformation on the specified size (which | 
 |  * is in integer format). | 
 |  */ | 
 | static inline INT INTERNAL_YDSTOWS(DC *dc, INT height) | 
 | { | 
 |     FLOAT floatHeight; | 
 |  | 
 |     /* Perform operation with floating point */ | 
 |     floatHeight = (FLOAT)height * dc->xformVport2World.eM22; | 
 |     /* Round to integers */ | 
 |     return GDI_ROUND(floatHeight); | 
 | } | 
 |  | 
 |  | 
 | static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, void *obj, HDC hdc ); | 
 | static INT FONT_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer ); | 
 | static INT FONT_GetObjectA( HGDIOBJ handle, void *obj, INT count, LPVOID buffer ); | 
 | static INT FONT_GetObjectW( HGDIOBJ handle, void *obj, INT count, LPVOID buffer ); | 
 | static BOOL FONT_DeleteObject( HGDIOBJ handle, void *obj ); | 
 |  | 
 | static const struct gdi_obj_funcs font_funcs = | 
 | { | 
 |     FONT_SelectObject,  /* pSelectObject */ | 
 |     FONT_GetObject16,   /* pGetObject16 */ | 
 |     FONT_GetObjectA,    /* pGetObjectA */ | 
 |     FONT_GetObjectW,    /* pGetObjectW */ | 
 |     NULL,               /* pUnrealizeObject */ | 
 |     FONT_DeleteObject   /* pDeleteObject */ | 
 | }; | 
 |  | 
 | #define ENUM_UNICODE	0x00000001 | 
 | #define ENUM_CALLED     0x00000002 | 
 |  | 
 | typedef struct | 
 | { | 
 |     GDIOBJHDR   header; | 
 |     LOGFONTW    logfont; | 
 | } FONTOBJ; | 
 |  | 
 | typedef struct | 
 | { | 
 |   LPLOGFONT16           lpLogFontParam; | 
 |   FONTENUMPROC16        lpEnumFunc; | 
 |   LPARAM                lpData; | 
 |  | 
 |   LPNEWTEXTMETRICEX16   lpTextMetric; | 
 |   LPENUMLOGFONTEX16     lpLogFont; | 
 |   SEGPTR                segTextMetric; | 
 |   SEGPTR                segLogFont; | 
 |   DWORD                 dwFlags; | 
 |   HDC                   hdc; | 
 |   DC                   *dc; | 
 |   PHYSDEV               physDev; | 
 | } fontEnum16; | 
 |  | 
 | typedef struct | 
 | { | 
 |   LPLOGFONTW          lpLogFontParam; | 
 |   FONTENUMPROCW       lpEnumFunc; | 
 |   LPARAM              lpData; | 
 |   DWORD               dwFlags; | 
 |   HDC                 hdc; | 
 |   DC                 *dc; | 
 |   PHYSDEV             physDev; | 
 | } fontEnum32; | 
 |  | 
 | /* | 
 |  *  For TranslateCharsetInfo | 
 |  */ | 
 | #define FS(x) {{0,0,0,0},{0x1<<(x),0}} | 
 | #define MAXTCIINDEX 32 | 
 | static const CHARSETINFO FONT_tci[MAXTCIINDEX] = { | 
 |   /* ANSI */ | 
 |   { ANSI_CHARSET, 1252, FS(0)}, | 
 |   { EASTEUROPE_CHARSET, 1250, FS(1)}, | 
 |   { RUSSIAN_CHARSET, 1251, FS(2)}, | 
 |   { GREEK_CHARSET, 1253, FS(3)}, | 
 |   { TURKISH_CHARSET, 1254, FS(4)}, | 
 |   { HEBREW_CHARSET, 1255, FS(5)}, | 
 |   { ARABIC_CHARSET, 1256, FS(6)}, | 
 |   { BALTIC_CHARSET, 1257, FS(7)}, | 
 |   { VIETNAMESE_CHARSET, 1258, FS(8)}, | 
 |   /* reserved by ANSI */ | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   /* ANSI and OEM */ | 
 |   { THAI_CHARSET,  874,  FS(16)}, | 
 |   { SHIFTJIS_CHARSET, 932, FS(17)}, | 
 |   { GB2312_CHARSET, 936, FS(18)}, | 
 |   { HANGEUL_CHARSET, 949, FS(19)}, | 
 |   { CHINESEBIG5_CHARSET, 950, FS(20)}, | 
 |   { JOHAB_CHARSET, 1361, FS(21)}, | 
 |   /* reserved for alternate ANSI and OEM */ | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   /* reserved for system */ | 
 |   { DEFAULT_CHARSET, 0, FS(0)}, | 
 |   { SYMBOL_CHARSET, CP_SYMBOL, FS(31)}, | 
 | }; | 
 |  | 
 | /*********************************************************************** | 
 |  *              LOGFONT conversion functions. | 
 |  */ | 
 | static void FONT_LogFontWTo16( const LOGFONTW* font32, LPLOGFONT16 font16 ) | 
 | { | 
 |     font16->lfHeight = font32->lfHeight; | 
 |     font16->lfWidth = font32->lfWidth; | 
 |     font16->lfEscapement = font32->lfEscapement; | 
 |     font16->lfOrientation = font32->lfOrientation; | 
 |     font16->lfWeight = font32->lfWeight; | 
 |     font16->lfItalic = font32->lfItalic; | 
 |     font16->lfUnderline = font32->lfUnderline; | 
 |     font16->lfStrikeOut = font32->lfStrikeOut; | 
 |     font16->lfCharSet = font32->lfCharSet; | 
 |     font16->lfOutPrecision = font32->lfOutPrecision; | 
 |     font16->lfClipPrecision = font32->lfClipPrecision; | 
 |     font16->lfQuality = font32->lfQuality; | 
 |     font16->lfPitchAndFamily = font32->lfPitchAndFamily; | 
 |     WideCharToMultiByte( CP_ACP, 0, font32->lfFaceName, -1, | 
 |                          font16->lfFaceName, LF_FACESIZE, NULL, NULL ); | 
 |     font16->lfFaceName[LF_FACESIZE-1] = 0; | 
 | } | 
 |  | 
 | static void FONT_LogFont16ToW( const LOGFONT16 *font16, LPLOGFONTW font32 ) | 
 | { | 
 |     font32->lfHeight = font16->lfHeight; | 
 |     font32->lfWidth = font16->lfWidth; | 
 |     font32->lfEscapement = font16->lfEscapement; | 
 |     font32->lfOrientation = font16->lfOrientation; | 
 |     font32->lfWeight = font16->lfWeight; | 
 |     font32->lfItalic = font16->lfItalic; | 
 |     font32->lfUnderline = font16->lfUnderline; | 
 |     font32->lfStrikeOut = font16->lfStrikeOut; | 
 |     font32->lfCharSet = font16->lfCharSet; | 
 |     font32->lfOutPrecision = font16->lfOutPrecision; | 
 |     font32->lfClipPrecision = font16->lfClipPrecision; | 
 |     font32->lfQuality = font16->lfQuality; | 
 |     font32->lfPitchAndFamily = font16->lfPitchAndFamily; | 
 |     MultiByteToWideChar( CP_ACP, 0, font16->lfFaceName, -1, font32->lfFaceName, LF_FACESIZE ); | 
 |     font32->lfFaceName[LF_FACESIZE-1] = 0; | 
 | } | 
 |  | 
 | static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW ) | 
 | { | 
 |     memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE); | 
 |     MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName, | 
 | 			LF_FACESIZE); | 
 |     fontW->lfFaceName[LF_FACESIZE-1] = 0; | 
 | } | 
 |  | 
 | static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA ) | 
 | { | 
 |     memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE); | 
 |     WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName, | 
 | 			LF_FACESIZE, NULL, NULL); | 
 |     fontA->lfFaceName[LF_FACESIZE-1] = 0; | 
 | } | 
 |  | 
 | static void FONT_EnumLogFontExWTo16( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEX16 font16 ) | 
 | { | 
 |     FONT_LogFontWTo16( (LPLOGFONTW)fontW, (LPLOGFONT16)font16); | 
 |  | 
 |     WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1, | 
 | 			 font16->elfFullName, LF_FULLFACESIZE, NULL, NULL ); | 
 |     font16->elfFullName[LF_FULLFACESIZE-1] = '\0'; | 
 |     WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1, | 
 | 			 font16->elfStyle, LF_FACESIZE, NULL, NULL ); | 
 |     font16->elfStyle[LF_FACESIZE-1] = '\0'; | 
 |     WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1, | 
 | 			 font16->elfScript, LF_FACESIZE, NULL, NULL ); | 
 |     font16->elfScript[LF_FACESIZE-1] = '\0'; | 
 | } | 
 |  | 
 | static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA ) | 
 | { | 
 |     FONT_LogFontWToA( (LPLOGFONTW)fontW, (LPLOGFONTA)fontA); | 
 |  | 
 |     WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1, | 
 | 			 fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL ); | 
 |     fontA->elfFullName[LF_FULLFACESIZE-1] = '\0'; | 
 |     WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1, | 
 | 			 fontA->elfStyle, LF_FACESIZE, NULL, NULL ); | 
 |     fontA->elfStyle[LF_FACESIZE-1] = '\0'; | 
 |     WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1, | 
 | 			 fontA->elfScript, LF_FACESIZE, NULL, NULL ); | 
 |     fontA->elfScript[LF_FACESIZE-1] = '\0'; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              TEXTMETRIC conversion functions. | 
 |  */ | 
 | static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA ) | 
 | { | 
 |     ptmA->tmHeight = ptmW->tmHeight; | 
 |     ptmA->tmAscent = ptmW->tmAscent; | 
 |     ptmA->tmDescent = ptmW->tmDescent; | 
 |     ptmA->tmInternalLeading = ptmW->tmInternalLeading; | 
 |     ptmA->tmExternalLeading = ptmW->tmExternalLeading; | 
 |     ptmA->tmAveCharWidth = ptmW->tmAveCharWidth; | 
 |     ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth; | 
 |     ptmA->tmWeight = ptmW->tmWeight; | 
 |     ptmA->tmOverhang = ptmW->tmOverhang; | 
 |     ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX; | 
 |     ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY; | 
 |     ptmA->tmFirstChar = ptmW->tmFirstChar > 255 ? 255 : ptmW->tmFirstChar; | 
 |     ptmA->tmLastChar = ptmW->tmLastChar > 255 ? 255 : ptmW->tmLastChar; | 
 |     ptmA->tmDefaultChar = ptmW->tmDefaultChar > 255 ? 255 : ptmW->tmDefaultChar; | 
 |     ptmA->tmBreakChar = ptmW->tmBreakChar > 255 ? 255 : ptmW->tmBreakChar; | 
 |     ptmA->tmItalic = ptmW->tmItalic; | 
 |     ptmA->tmUnderlined = ptmW->tmUnderlined; | 
 |     ptmA->tmStruckOut = ptmW->tmStruckOut; | 
 |     ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily; | 
 |     ptmA->tmCharSet = ptmW->tmCharSet; | 
 | } | 
 |  | 
 |  | 
 | static void FONT_NewTextMetricExWTo16(const NEWTEXTMETRICEXW *ptmW, LPNEWTEXTMETRICEX16 ptm16 ) | 
 | { | 
 |     ptm16->ntmTm.tmHeight = ptmW->ntmTm.tmHeight; | 
 |     ptm16->ntmTm.tmAscent = ptmW->ntmTm.tmAscent; | 
 |     ptm16->ntmTm.tmDescent = ptmW->ntmTm.tmDescent; | 
 |     ptm16->ntmTm.tmInternalLeading = ptmW->ntmTm.tmInternalLeading; | 
 |     ptm16->ntmTm.tmExternalLeading = ptmW->ntmTm.tmExternalLeading; | 
 |     ptm16->ntmTm.tmAveCharWidth = ptmW->ntmTm.tmAveCharWidth; | 
 |     ptm16->ntmTm.tmMaxCharWidth = ptmW->ntmTm.tmMaxCharWidth; | 
 |     ptm16->ntmTm.tmWeight = ptmW->ntmTm.tmWeight; | 
 |     ptm16->ntmTm.tmOverhang = ptmW->ntmTm.tmOverhang; | 
 |     ptm16->ntmTm.tmDigitizedAspectX = ptmW->ntmTm.tmDigitizedAspectX; | 
 |     ptm16->ntmTm.tmDigitizedAspectY = ptmW->ntmTm.tmDigitizedAspectY; | 
 |     ptm16->ntmTm.tmFirstChar = ptmW->ntmTm.tmFirstChar > 255 ? 255 : ptmW->ntmTm.tmFirstChar; | 
 |     ptm16->ntmTm.tmLastChar = ptmW->ntmTm.tmLastChar > 255 ? 255 : ptmW->ntmTm.tmLastChar; | 
 |     ptm16->ntmTm.tmDefaultChar = ptmW->ntmTm.tmDefaultChar > 255 ? 255 : ptmW->ntmTm.tmDefaultChar; | 
 |     ptm16->ntmTm.tmBreakChar = ptmW->ntmTm.tmBreakChar > 255 ? 255 : ptmW->ntmTm.tmBreakChar; | 
 |     ptm16->ntmTm.tmItalic = ptmW->ntmTm.tmItalic; | 
 |     ptm16->ntmTm.tmUnderlined = ptmW->ntmTm.tmUnderlined; | 
 |     ptm16->ntmTm.tmStruckOut = ptmW->ntmTm.tmStruckOut; | 
 |     ptm16->ntmTm.tmPitchAndFamily = ptmW->ntmTm.tmPitchAndFamily; | 
 |     ptm16->ntmTm.tmCharSet = ptmW->ntmTm.tmCharSet; | 
 |     ptm16->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags; | 
 |     ptm16->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM; | 
 |     ptm16->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight; | 
 |     ptm16->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth; | 
 |     memcpy(&ptm16->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE)); | 
 | } | 
 |  | 
 | static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA ) | 
 | { | 
 |     FONT_TextMetricWToA((LPTEXTMETRICW)ptmW, (LPTEXTMETRICA)ptmA); | 
 |     ptmA->ntmTm.ntmFlags = ptmW->ntmTm.ntmFlags; | 
 |     ptmA->ntmTm.ntmSizeEM = ptmW->ntmTm.ntmSizeEM; | 
 |     ptmA->ntmTm.ntmCellHeight = ptmW->ntmTm.ntmCellHeight; | 
 |     ptmA->ntmTm.ntmAvgWidth = ptmW->ntmTm.ntmAvgWidth; | 
 |     memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE)); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           FONT_mbtowc | 
 |  * | 
 |  * Returns a '\0' terminated Unicode translation of str using the | 
 |  * charset of the currently selected font in hdc.  If count is -1 then | 
 |  * str is assumed to be '\0' terminated, otherwise it contains the | 
 |  * number of bytes to convert.  If plenW is non-NULL, on return it | 
 |  * will point to the number of WCHARs (excluding the '\0') that have | 
 |  * been written.  If pCP is non-NULL, on return it will point to the | 
 |  * codepage used in the conversion. | 
 |  * The caller should free the returned LPWSTR from the process | 
 |  * heap itself. | 
 |  */ | 
 | static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP) | 
 | { | 
 |     UINT cp = CP_ACP; | 
 |     INT lenW; | 
 |     LPWSTR strW; | 
 |     CHARSETINFO csi; | 
 |     int charset = GetTextCharset(hdc); | 
 |  | 
 |     /* Hmm, nicely designed api this one! */ | 
 |     if(TranslateCharsetInfo((DWORD*)charset, &csi, TCI_SRCCHARSET)) | 
 |         cp = csi.ciACP; | 
 |     else { | 
 |         switch(charset) { | 
 |         case OEM_CHARSET: | 
 |             cp = GetOEMCP(); | 
 |             break; | 
 |         case DEFAULT_CHARSET: | 
 |             cp = GetACP(); | 
 |             break; | 
 |  | 
 |         case VISCII_CHARSET: | 
 |         case TCVN_CHARSET: | 
 |         case KOI8_CHARSET: | 
 |         case ISO3_CHARSET: | 
 |         case ISO4_CHARSET: | 
 |         case ISO10_CHARSET: | 
 |         case CELTIC_CHARSET: | 
 |             /* FIXME: These have no place here, but because x11drv | 
 |                enumerates fonts with these (made up) charsets some apps | 
 |                might use them and then the FIXME below would become | 
 |                annoying.  Now we could pick the intended codepage for | 
 |                each of these, but since it's broken anyway we'll just | 
 |                use CP_ACP and hope it'll go away... | 
 |             */ | 
 |             cp = CP_ACP; | 
 |             break; | 
 |  | 
 |         default: | 
 |             FIXME("Can't find codepage for charset %d\n", charset); | 
 |             break; | 
 |         } | 
 |     } | 
 |  | 
 |     TRACE("charset %d => cp %d\n", charset, cp); | 
 |  | 
 |     if(count == -1) count = strlen(str); | 
 |     lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0); | 
 |     strW = HeapAlloc(GetProcessHeap(), 0, (lenW + 1) * sizeof(WCHAR)); | 
 |     MultiByteToWideChar(cp, 0, str, count, strW, lenW); | 
 |     strW[lenW] = '\0'; | 
 |     TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW)); | 
 |     if(plenW) *plenW = lenW; | 
 |     if(pCP) *pCP = cp; | 
 |     return strW; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           CreateFontIndirectA   (GDI32.@) | 
 |  */ | 
 | HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA ) | 
 | { | 
 |     LOGFONTW lfW; | 
 |  | 
 |     if (plfA) { | 
 | 	FONT_LogFontAToW( plfA, &lfW ); | 
 | 	return CreateFontIndirectW( &lfW ); | 
 |      } else | 
 | 	return CreateFontIndirectW( NULL ); | 
 |  | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           CreateFontIndirectW   (GDI32.@) | 
 |  */ | 
 | HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf ) | 
 | { | 
 |     HFONT hFont = 0; | 
 |  | 
 |     if (plf) | 
 |     { | 
 |         FONTOBJ* fontPtr; | 
 | 	if ((fontPtr = GDI_AllocObject( sizeof(FONTOBJ), FONT_MAGIC, | 
 | 					(HGDIOBJ *)&hFont, &font_funcs ))) | 
 | 	{ | 
 |             static const WCHAR ItalicW[] = {' ','I','t','a','l','i','c','\0'}; | 
 |             static const WCHAR BoldW[]   = {' ','B','o','l','d','\0'}; | 
 |             WCHAR *pFaceNameItalicSuffix, *pFaceNameBoldSuffix; | 
 |             WCHAR* pFaceNameSuffix = NULL; | 
 |  | 
 | 	    memcpy( &fontPtr->logfont, plf, sizeof(LOGFONTW) ); | 
 |  | 
 | 	    TRACE("(%ld %ld %ld %ld %x %d %x %d %d) %s %s %s %s => %p\n", | 
 |                   plf->lfHeight, plf->lfWidth, | 
 |                   plf->lfEscapement, plf->lfOrientation, | 
 |                   plf->lfPitchAndFamily, | 
 | 		  plf->lfOutPrecision, plf->lfClipPrecision, | 
 | 		  plf->lfQuality, plf->lfCharSet, | 
 |                   debugstr_w(plf->lfFaceName), | 
 |                   plf->lfWeight > 400 ? "Bold" : "", | 
 |                   plf->lfItalic ? "Italic" : "", | 
 |                   plf->lfUnderline ? "Underline" : "", hFont); | 
 |  | 
 | 	    if (plf->lfEscapement != plf->lfOrientation) { | 
 | 	      /* this should really depend on whether GM_ADVANCED is set */ | 
 | 	      fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement; | 
 | 	      WARN("orientation angle %f set to " | 
 |                    "escapement angle %f for new font %p\n", | 
 |                    plf->lfOrientation/10., plf->lfEscapement/10., hFont); | 
 | 	    } | 
 |  | 
 |             pFaceNameItalicSuffix = strstrW(fontPtr->logfont.lfFaceName, ItalicW); | 
 |             if (pFaceNameItalicSuffix) { | 
 |                 fontPtr->logfont.lfItalic = TRUE; | 
 |                 pFaceNameSuffix = pFaceNameItalicSuffix; | 
 |             } | 
 |  | 
 |             pFaceNameBoldSuffix = strstrW(fontPtr->logfont.lfFaceName, BoldW); | 
 |             if (pFaceNameBoldSuffix) { | 
 |                 if (fontPtr->logfont.lfWeight < FW_BOLD) { | 
 |                     fontPtr->logfont.lfWeight = FW_BOLD; | 
 |                 } | 
 |                 if (!pFaceNameSuffix || | 
 |                     (pFaceNameBoldSuffix < pFaceNameSuffix)) { | 
 |                     pFaceNameSuffix = pFaceNameBoldSuffix; | 
 |                 } | 
 |             } | 
 |  | 
 |             if (pFaceNameSuffix) *pFaceNameSuffix = 0; | 
 |  | 
 | 	    GDI_ReleaseObj( hFont ); | 
 | 	} | 
 |     } | 
 |     else WARN("(NULL) => NULL\n"); | 
 |  | 
 |     return hFont; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  *           CreateFontA    (GDI32.@) | 
 |  */ | 
 | HFONT WINAPI CreateFontA( INT height, INT width, INT esc, | 
 |                               INT orient, INT weight, DWORD italic, | 
 |                               DWORD underline, DWORD strikeout, DWORD charset, | 
 |                               DWORD outpres, DWORD clippres, DWORD quality, | 
 |                               DWORD pitch, LPCSTR name ) | 
 | { | 
 |     LOGFONTA logfont; | 
 |  | 
 |     logfont.lfHeight = height; | 
 |     logfont.lfWidth = width; | 
 |     logfont.lfEscapement = esc; | 
 |     logfont.lfOrientation = orient; | 
 |     logfont.lfWeight = weight; | 
 |     logfont.lfItalic = italic; | 
 |     logfont.lfUnderline = underline; | 
 |     logfont.lfStrikeOut = strikeout; | 
 |     logfont.lfCharSet = charset; | 
 |     logfont.lfOutPrecision = outpres; | 
 |     logfont.lfClipPrecision = clippres; | 
 |     logfont.lfQuality = quality; | 
 |     logfont.lfPitchAndFamily = pitch; | 
 |  | 
 |     if (name) | 
 | 	lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName)); | 
 |     else | 
 | 	logfont.lfFaceName[0] = '\0'; | 
 |  | 
 |     return CreateFontIndirectA( &logfont ); | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  *           CreateFontW    (GDI32.@) | 
 |  */ | 
 | HFONT WINAPI CreateFontW( INT height, INT width, INT esc, | 
 |                               INT orient, INT weight, DWORD italic, | 
 |                               DWORD underline, DWORD strikeout, DWORD charset, | 
 |                               DWORD outpres, DWORD clippres, DWORD quality, | 
 |                               DWORD pitch, LPCWSTR name ) | 
 | { | 
 |     LOGFONTW logfont; | 
 |  | 
 |     logfont.lfHeight = height; | 
 |     logfont.lfWidth = width; | 
 |     logfont.lfEscapement = esc; | 
 |     logfont.lfOrientation = orient; | 
 |     logfont.lfWeight = weight; | 
 |     logfont.lfItalic = italic; | 
 |     logfont.lfUnderline = underline; | 
 |     logfont.lfStrikeOut = strikeout; | 
 |     logfont.lfCharSet = charset; | 
 |     logfont.lfOutPrecision = outpres; | 
 |     logfont.lfClipPrecision = clippres; | 
 |     logfont.lfQuality = quality; | 
 |     logfont.lfPitchAndFamily = pitch; | 
 |  | 
 |     if (name) | 
 | 	lstrcpynW(logfont.lfFaceName, name, | 
 | 		  sizeof(logfont.lfFaceName) / sizeof(WCHAR)); | 
 |     else | 
 | 	logfont.lfFaceName[0] = '\0'; | 
 |  | 
 |     return CreateFontIndirectW( &logfont ); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           FONT_SelectObject | 
 |  * | 
 |  * If the driver supports vector fonts we create a gdi font first and | 
 |  * then call the driver to give it a chance to supply its own device | 
 |  * font.  If the driver wants to do this it returns TRUE and we can | 
 |  * delete the gdi font, if the driver wants to use the gdi font it | 
 |  * should return FALSE, to signal an error return GDI_ERROR.  For | 
 |  * drivers that don't support vector fonts they must supply their own | 
 |  * font. | 
 |  */ | 
 | static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, void *obj, HDC hdc ) | 
 | { | 
 |     HGDIOBJ ret = 0; | 
 |     DC *dc = DC_GetDCPtr( hdc ); | 
 |  | 
 |     if (!dc) return 0; | 
 |  | 
 |     if (dc->hFont != handle || dc->gdiFont == NULL) | 
 |     { | 
 |         if(GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_VA_ABLE) | 
 |             dc->gdiFont = WineEngCreateFontInstance(dc, handle); | 
 |     } | 
 |  | 
 |     if (dc->funcs->pSelectFont) ret = dc->funcs->pSelectFont( dc->physDev, handle, dc->gdiFont ); | 
 |  | 
 |     if (ret && dc->gdiFont) dc->gdiFont = 0; | 
 |  | 
 |     if (ret == HGDI_ERROR) | 
 |         ret = 0; /* SelectObject returns 0 on error */ | 
 |     else | 
 |     { | 
 |         ret = dc->hFont; | 
 |         dc->hFont = handle; | 
 |     } | 
 |     GDI_ReleaseObj( hdc ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           FONT_GetObject16 | 
 |  */ | 
 | static INT FONT_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer ) | 
 | { | 
 |     FONTOBJ *font = obj; | 
 |     LOGFONT16 lf16; | 
 |  | 
 |     FONT_LogFontWTo16( &font->logfont, &lf16 ); | 
 |  | 
 |     if (count > sizeof(LOGFONT16)) count = sizeof(LOGFONT16); | 
 |     memcpy( buffer, &lf16, count ); | 
 |     return count; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           FONT_GetObjectA | 
 |  */ | 
 | static INT FONT_GetObjectA( HGDIOBJ handle, void *obj, INT count, LPVOID buffer ) | 
 | { | 
 |     FONTOBJ *font = obj; | 
 |     LOGFONTA lfA; | 
 |  | 
 |     if(!buffer) | 
 |         return sizeof(lfA); | 
 |     FONT_LogFontWToA( &font->logfont, &lfA ); | 
 |  | 
 |     if (count > sizeof(lfA)) count = sizeof(lfA); | 
 |     memcpy( buffer, &lfA, count ); | 
 |     return count; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           FONT_GetObjectW | 
 |  */ | 
 | static INT FONT_GetObjectW( HGDIOBJ handle, void *obj, INT count, LPVOID buffer ) | 
 | { | 
 |     FONTOBJ *font = obj; | 
 |     if(!buffer) | 
 |         return sizeof(LOGFONTW); | 
 |     if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW); | 
 |     memcpy( buffer, &font->logfont, count ); | 
 |     return count; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           FONT_DeleteObject | 
 |  */ | 
 | static BOOL FONT_DeleteObject( HGDIOBJ handle, void *obj ) | 
 | { | 
 |     WineEngDestroyFontInstance( handle ); | 
 |     return GDI_FreeObject( handle, obj ); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *              FONT_EnumInstance16 | 
 |  * | 
 |  * Called by the device driver layer to pass font info | 
 |  * down to the application. | 
 |  * | 
 |  * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW. | 
 |  *       We have to use other types because of the FONTENUMPROCW definition. | 
 |  */ | 
 | static INT CALLBACK FONT_EnumInstance16( const LOGFONTW *plf, const TEXTMETRICW *ptm, | 
 |                                          DWORD fType, LPARAM lp ) | 
 | { | 
 |     fontEnum16 *pfe = (fontEnum16*)lp; | 
 |     INT ret = 1; | 
 |     DC *dc; | 
 |  | 
 |     if( pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET || | 
 |         pfe->lpLogFontParam->lfCharSet == plf->lfCharSet ) | 
 |     { | 
 |         WORD args[7]; | 
 |         DWORD result; | 
 |  | 
 |         FONT_EnumLogFontExWTo16((const ENUMLOGFONTEXW *)plf, pfe->lpLogFont); | 
 |         FONT_NewTextMetricExWTo16((const NEWTEXTMETRICEXW *)ptm, pfe->lpTextMetric); | 
 |         pfe->dwFlags |= ENUM_CALLED; | 
 |         GDI_ReleaseObj( pfe->hdc );  /* release the GDI lock */ | 
 |  | 
 |         args[6] = SELECTOROF(pfe->segLogFont); | 
 |         args[5] = OFFSETOF(pfe->segLogFont); | 
 |         args[4] = SELECTOROF(pfe->segTextMetric); | 
 |         args[3] = OFFSETOF(pfe->segTextMetric); | 
 |         args[2] = fType; | 
 |         args[1] = HIWORD(pfe->lpData); | 
 |         args[0] = LOWORD(pfe->lpData); | 
 |         WOWCallback16Ex( (DWORD)pfe->lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &result ); | 
 |         ret = LOWORD(result); | 
 |  | 
 |         /* get the lock again and make sure the DC is still valid */ | 
 |         dc = DC_GetDCPtr( pfe->hdc ); | 
 |         if (!dc || dc != pfe->dc || dc->physDev != pfe->physDev) | 
 |         { | 
 |             if (dc) GDI_ReleaseObj( pfe->hdc ); | 
 |             pfe->hdc = 0;  /* make sure we don't try to release it later on */ | 
 |             ret = 0; | 
 |         } | 
 |     } | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              FONT_EnumInstance | 
 |  * | 
 |  * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW. | 
 |  *       We have to use other types because of the FONTENUMPROCW definition. | 
 |  */ | 
 | static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm, | 
 |                                        DWORD fType, LPARAM lp ) | 
 | { | 
 |     fontEnum32 *pfe = (fontEnum32*)lp; | 
 |     INT ret = 1; | 
 |     DC *dc; | 
 |  | 
 |     /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */ | 
 |     if((pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET || | 
 |         pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) && | 
 |        (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) ) | 
 |     { | 
 | 	/* convert font metrics */ | 
 |         ENUMLOGFONTEXA logfont; | 
 |         NEWTEXTMETRICEXA tmA; | 
 |  | 
 |         pfe->dwFlags |= ENUM_CALLED; | 
 |         if (!(pfe->dwFlags & ENUM_UNICODE)) | 
 |         { | 
 |             FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont); | 
 |             FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA ); | 
 |             plf = (LOGFONTW *)&logfont.elfLogFont; | 
 |             ptm = (TEXTMETRICW *)&tmA; | 
 |         } | 
 |         GDI_ReleaseObj( pfe->hdc );  /* release the GDI lock */ | 
 |  | 
 |         ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData ); | 
 |  | 
 |         /* get the lock again and make sure the DC is still valid */ | 
 |         dc = DC_GetDCPtr( pfe->hdc ); | 
 |         if (!dc || dc != pfe->dc || dc->physDev != pfe->physDev) | 
 |         { | 
 |             if (dc) GDI_ReleaseObj( pfe->hdc ); | 
 |             pfe->hdc = 0;  /* make sure we don't try to release it later on */ | 
 |             ret = 0; | 
 |         } | 
 |     } | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              EnumFontFamiliesEx	(GDI.613) | 
 |  */ | 
 | INT16 WINAPI EnumFontFamiliesEx16( HDC16 hDC, LPLOGFONT16 plf, | 
 |                                    FONTENUMPROC16 efproc, LPARAM lParam, | 
 |                                    DWORD dwFlags) | 
 | { | 
 |     fontEnum16 fe16; | 
 |     INT16	ret = 1, ret2; | 
 |     DC* 	dc = DC_GetDCPtr( HDC_32(hDC) ); | 
 |     NEWTEXTMETRICEX16 tm16; | 
 |     ENUMLOGFONTEX16 lf16; | 
 |     LOGFONTW lfW; | 
 |     BOOL enum_gdi_fonts; | 
 |  | 
 |     if (!dc) return 0; | 
 |     FONT_LogFont16ToW(plf, &lfW); | 
 |  | 
 |     fe16.hdc = HDC_32(hDC); | 
 |     fe16.dc = dc; | 
 |     fe16.physDev = dc->physDev; | 
 |     fe16.lpLogFontParam = plf; | 
 |     fe16.lpEnumFunc = efproc; | 
 |     fe16.lpData = lParam; | 
 |     fe16.lpTextMetric = &tm16; | 
 |     fe16.lpLogFont = &lf16; | 
 |     fe16.segTextMetric = MapLS( &tm16 ); | 
 |     fe16.segLogFont = MapLS( &lf16 ); | 
 |     fe16.dwFlags = 0; | 
 |  | 
 |     enum_gdi_fonts = GetDeviceCaps(fe16.hdc, TEXTCAPS) & TC_VA_ABLE; | 
 |  | 
 |     if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts) | 
 |     { | 
 |         ret = 0; | 
 |         goto done; | 
 |     } | 
 |  | 
 |     if (enum_gdi_fonts) | 
 |         ret = WineEngEnumFonts( &lfW, FONT_EnumInstance16, (LPARAM)&fe16 ); | 
 |     fe16.dwFlags &= ~ENUM_CALLED; | 
 |     if (ret && dc->funcs->pEnumDeviceFonts) { | 
 | 	ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, &lfW, FONT_EnumInstance16, (LPARAM)&fe16 ); | 
 | 	if(fe16.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */ | 
 | 	    ret = ret2; | 
 |     } | 
 | done: | 
 |     UnMapLS( fe16.segTextMetric ); | 
 |     UnMapLS( fe16.segLogFont ); | 
 |     if (fe16.hdc) GDI_ReleaseObj( fe16.hdc ); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *		FONT_EnumFontFamiliesEx | 
 |  */ | 
 | static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, | 
 | 				    FONTENUMPROCW efproc, | 
 | 				    LPARAM lParam, DWORD dwUnicode) | 
 | { | 
 |     INT ret = 1, ret2; | 
 |     DC *dc = DC_GetDCPtr( hDC ); | 
 |     fontEnum32 fe32; | 
 |     BOOL enum_gdi_fonts; | 
 |  | 
 |     if (!dc) return 0; | 
 |  | 
 |     TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), | 
 | 	  plf->lfCharSet); | 
 |     fe32.lpLogFontParam = plf; | 
 |     fe32.lpEnumFunc = efproc; | 
 |     fe32.lpData = lParam; | 
 |     fe32.dwFlags = dwUnicode; | 
 |     fe32.hdc = hDC; | 
 |     fe32.dc = dc; | 
 |     fe32.physDev = dc->physDev; | 
 |  | 
 |     enum_gdi_fonts = GetDeviceCaps(hDC, TEXTCAPS) & TC_VA_ABLE; | 
 |  | 
 |     if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts) | 
 |     { | 
 |         ret = 0; | 
 |         goto done; | 
 |     } | 
 |  | 
 |     if (enum_gdi_fonts) | 
 |         ret = WineEngEnumFonts( plf, FONT_EnumInstance, (LPARAM)&fe32 ); | 
 |     fe32.dwFlags &= ~ENUM_CALLED; | 
 |     if (ret && dc->funcs->pEnumDeviceFonts) { | 
 | 	ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, plf, FONT_EnumInstance, (LPARAM)&fe32 ); | 
 | 	if(fe32.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */ | 
 | 	    ret = ret2; | 
 |     } | 
 |  done: | 
 |     if (fe32.hdc) GDI_ReleaseObj( fe32.hdc ); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              EnumFontFamiliesExW	(GDI32.@) | 
 |  */ | 
 | INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf, | 
 |                                     FONTENUMPROCW efproc, | 
 |                                     LPARAM lParam, DWORD dwFlags ) | 
 | { | 
 |     return  FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, ENUM_UNICODE ); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              EnumFontFamiliesExA	(GDI32.@) | 
 |  */ | 
 | INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf, | 
 |                                     FONTENUMPROCA efproc, | 
 |                                     LPARAM lParam, DWORD dwFlags) | 
 | { | 
 |     LOGFONTW lfW; | 
 |     FONT_LogFontAToW( plf, &lfW ); | 
 |  | 
 |     return FONT_EnumFontFamiliesEx( hDC, &lfW, (FONTENUMPROCW)efproc, lParam, 0); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              EnumFontFamilies	(GDI.330) | 
 |  */ | 
 | INT16 WINAPI EnumFontFamilies16( HDC16 hDC, LPCSTR lpFamily, | 
 |                                  FONTENUMPROC16 efproc, LPARAM lpData ) | 
 | { | 
 |     LOGFONT16	lf; | 
 |  | 
 |     lf.lfCharSet = DEFAULT_CHARSET; | 
 |     if( lpFamily ) lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE ); | 
 |     else lf.lfFaceName[0] = '\0'; | 
 |  | 
 |     return EnumFontFamiliesEx16( hDC, &lf, efproc, lpData, 0 ); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              EnumFontFamiliesA	(GDI32.@) | 
 |  */ | 
 | INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily, | 
 |                                   FONTENUMPROCA efproc, LPARAM lpData ) | 
 | { | 
 |     LOGFONTA	lf; | 
 |  | 
 |     lf.lfCharSet = DEFAULT_CHARSET; | 
 |     if( lpFamily ) lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE ); | 
 |     else lf.lfFaceName[0] = lf.lfFaceName[1] = '\0'; | 
 |  | 
 |     return EnumFontFamiliesExA( hDC, &lf, efproc, lpData, 0 ); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              EnumFontFamiliesW	(GDI32.@) | 
 |  */ | 
 | INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily, | 
 |                                   FONTENUMPROCW efproc, LPARAM lpData ) | 
 | { | 
 |     LOGFONTW  lf; | 
 |  | 
 |     lf.lfCharSet = DEFAULT_CHARSET; | 
 |     if( lpFamily ) lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE ); | 
 |     else lf.lfFaceName[0] = 0; | 
 |  | 
 |     return EnumFontFamiliesExW( hDC, &lf, efproc, lpData, 0 ); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              EnumFonts		(GDI.70) | 
 |  */ | 
 | INT16 WINAPI EnumFonts16( HDC16 hDC, LPCSTR lpName, FONTENUMPROC16 efproc, | 
 |                           LPARAM lpData ) | 
 | { | 
 |     return EnumFontFamilies16( hDC, lpName, efproc, lpData ); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              EnumFontsA		(GDI32.@) | 
 |  */ | 
 | INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc, | 
 |                            LPARAM lpData ) | 
 | { | 
 |     return EnumFontFamiliesA( hDC, lpName, efproc, lpData ); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              EnumFontsW		(GDI32.@) | 
 |  */ | 
 | INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc, | 
 |                            LPARAM lpData ) | 
 | { | 
 |     return EnumFontFamiliesW( hDC, lpName, efproc, lpData ); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextCharacterExtra    (GDI32.@) | 
 |  */ | 
 | INT WINAPI GetTextCharacterExtra( HDC hdc ) | 
 | { | 
 |     INT ret; | 
 |     DC *dc = DC_GetDCPtr( hdc ); | 
 |     if (!dc) return 0x80000000; | 
 |     ret = dc->charExtra; | 
 |     GDI_ReleaseObj( hdc ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           SetTextCharacterExtra    (GDI32.@) | 
 |  */ | 
 | INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra ) | 
 | { | 
 |     INT prev; | 
 |     DC * dc = DC_GetDCPtr( hdc ); | 
 |     if (!dc) return 0x80000000; | 
 |     if (dc->funcs->pSetTextCharacterExtra) | 
 |         prev = dc->funcs->pSetTextCharacterExtra( dc->physDev, extra ); | 
 |     else | 
 |     { | 
 |         prev = dc->charExtra; | 
 |         dc->charExtra = extra; | 
 |     } | 
 |     GDI_ReleaseObj( hdc ); | 
 |     return prev; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           SetTextJustification    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks ) | 
 | { | 
 |     BOOL ret = TRUE; | 
 |     DC * dc = DC_GetDCPtr( hdc ); | 
 |     if (!dc) return FALSE; | 
 |     if (dc->funcs->pSetTextJustification) | 
 |         ret = dc->funcs->pSetTextJustification( dc->physDev, extra, breaks ); | 
 |     else | 
 |     { | 
 |         extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX); | 
 |         if (!extra) breaks = 0; | 
 |         if (breaks) | 
 |         { | 
 |             dc->breakExtra = extra / breaks; | 
 |             dc->breakRem   = extra - (breaks * dc->breakExtra); | 
 |         } | 
 |         else | 
 |         { | 
 |             dc->breakExtra = 0; | 
 |             dc->breakRem   = 0; | 
 |         } | 
 |     } | 
 |     GDI_ReleaseObj( hdc ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextFaceA    (GDI32.@) | 
 |  */ | 
 | INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name ) | 
 | { | 
 |     INT res = GetTextFaceW(hdc, 0, NULL); | 
 |     LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 ); | 
 |     GetTextFaceW( hdc, res, nameW ); | 
 |  | 
 |     if (name) | 
 |     { | 
 |         if (count && !WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, count, NULL, NULL)) | 
 |             name[count-1] = 0; | 
 |         res = strlen(name); | 
 |     } | 
 |     else | 
 |         res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL); | 
 |     HeapFree( GetProcessHeap(), 0, nameW ); | 
 |     return res; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextFaceW    (GDI32.@) | 
 |  */ | 
 | INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name ) | 
 | { | 
 |     FONTOBJ *font; | 
 |     INT     ret = 0; | 
 |  | 
 |     DC * dc = DC_GetDCPtr( hdc ); | 
 |     if (!dc) return 0; | 
 |  | 
 |     if(dc->gdiFont) | 
 |         ret = WineEngGetTextFace(dc->gdiFont, count, name); | 
 |     else if ((font = (FONTOBJ *) GDI_GetObjPtr( dc->hFont, FONT_MAGIC ))) | 
 |     { | 
 |         if (name) | 
 |         { | 
 |             lstrcpynW( name, font->logfont.lfFaceName, count ); | 
 |             ret = strlenW(name); | 
 |         } | 
 |         else ret = strlenW(font->logfont.lfFaceName) + 1; | 
 |         GDI_ReleaseObj( dc->hFont ); | 
 |     } | 
 |     GDI_ReleaseObj( hdc ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextExtentPoint32A    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count, | 
 |                                      LPSIZE size ) | 
 | { | 
 |     BOOL ret = FALSE; | 
 |     INT wlen; | 
 |     LPWSTR p = FONT_mbtowc(hdc, str, count, &wlen, NULL); | 
 |  | 
 |     if (p) { | 
 | 	ret = GetTextExtentPoint32W( hdc, p, wlen, size ); | 
 | 	HeapFree( GetProcessHeap(), 0, p ); | 
 |     } | 
 |  | 
 |     TRACE("(%p %s %d %p): returning %ld x %ld\n", | 
 |           hdc, debugstr_an (str, count), count, size, size->cx, size->cy ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  * GetTextExtentPoint32W [GDI32.@] | 
 |  * | 
 |  * Computes width/height for a string. | 
 |  * | 
 |  * Computes width and height of the specified string. | 
 |  * | 
 |  * RETURNS | 
 |  *    Success: TRUE | 
 |  *    Failure: FALSE | 
 |  */ | 
 | BOOL WINAPI GetTextExtentPoint32W( | 
 |     HDC hdc,     /* [in]  Handle of device context */ | 
 |     LPCWSTR str,   /* [in]  Address of text string */ | 
 |     INT count,   /* [in]  Number of characters in string */ | 
 |     LPSIZE size) /* [out] Address of structure for string size */ | 
 | { | 
 |     BOOL ret = FALSE; | 
 |     DC * dc = DC_GetDCPtr( hdc ); | 
 |     if (!dc) return FALSE; | 
 |  | 
 |     if(dc->gdiFont) | 
 |         ret = WineEngGetTextExtentPoint(dc->gdiFont, str, count, size); | 
 |     else if(dc->funcs->pGetTextExtentPoint) | 
 |         ret = dc->funcs->pGetTextExtentPoint( dc->physDev, str, count, size ); | 
 |  | 
 |     if (ret) | 
 |     { | 
 | 	size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx)); | 
 | 	size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy)); | 
 |         size->cx += count * dc->charExtra + dc->breakRem; | 
 |     } | 
 |  | 
 |     GDI_ReleaseObj( hdc ); | 
 |  | 
 |     TRACE("(%p %s %d %p): returning %ld x %ld\n", | 
 |           hdc, debugstr_wn (str, count), count, size, size->cx, size->cy ); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  * GetTextExtentPointI [GDI32.@] | 
 |  * | 
 |  * Computes width and height of the array of glyph indices. | 
 |  * | 
 |  * RETURNS | 
 |  *    Success: TRUE | 
 |  *    Failure: FALSE | 
 |  */ | 
 | BOOL WINAPI GetTextExtentPointI( | 
 |     HDC hdc,     /* [in]  Handle of device context */ | 
 |     const WORD *indices,   /* [in]  Address of glyph index array */ | 
 |     INT count,   /* [in]  Number of glyphs in array */ | 
 |     LPSIZE size) /* [out] Address of structure for string size */ | 
 | { | 
 |     BOOL ret = FALSE; | 
 |     DC * dc = DC_GetDCPtr( hdc ); | 
 |     if (!dc) return FALSE; | 
 |  | 
 |     if(dc->gdiFont) { | 
 |         ret = WineEngGetTextExtentPointI(dc->gdiFont, indices, count, size); | 
 | 	size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx)); | 
 | 	size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy)); | 
 |         size->cx += count * dc->charExtra; | 
 |     } | 
 |     else if(dc->funcs->pGetTextExtentPoint) { | 
 |         FIXME("calling GetTextExtentPoint\n"); | 
 |         ret = dc->funcs->pGetTextExtentPoint( dc->physDev, (LPCWSTR)indices, count, size ); | 
 |     } | 
 |  | 
 |     GDI_ReleaseObj( hdc ); | 
 |  | 
 |     TRACE("(%p %p %d %p): returning %ld x %ld\n", | 
 |           hdc, indices, count, size, size->cx, size->cy ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextExtentPointA    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count, | 
 |                                           LPSIZE size ) | 
 | { | 
 |     TRACE("not bug compatible.\n"); | 
 |     return GetTextExtentPoint32A( hdc, str, count, size ); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextExtentPointW   (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count, | 
 |                                           LPSIZE size ) | 
 | { | 
 |     TRACE("not bug compatible.\n"); | 
 |     return GetTextExtentPoint32W( hdc, str, count, size ); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextExtentExPointA    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count, | 
 | 				   INT maxExt, LPINT lpnFit, | 
 | 				   LPINT alpDx, LPSIZE size ) | 
 | { | 
 |     BOOL ret; | 
 |     INT wlen; | 
 |     LPWSTR p = FONT_mbtowc( hdc, str, count, &wlen, NULL); | 
 |     ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, alpDx, size); | 
 |     if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL); | 
 |     HeapFree( GetProcessHeap(), 0, p ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextExtentExPointW    (GDI32.@) | 
 |  * | 
 |  * Return the size of the string as it would be if it was output properly by | 
 |  * e.g. TextOut. | 
 |  * | 
 |  * This should include | 
 |  * - Intercharacter spacing | 
 |  * - justification spacing (not yet done) | 
 |  * - kerning? see below | 
 |  * | 
 |  * Kerning.  Since kerning would be carried out by the rendering code it should | 
 |  * be done by the driver.  However they don't support it yet.  Also I am not | 
 |  * yet persuaded that (certainly under Win95) any kerning is actually done. | 
 |  * | 
 |  * str: According to MSDN this should be null-terminated.  That is not true; a | 
 |  *      null will not terminate it early. | 
 |  * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less | 
 |  *       than count.  I have seen it be either the size of the full string or | 
 |  *       1 less than the size of the full string.  I have not seen it bear any | 
 |  *       resemblance to the portion that would fit. | 
 |  * lpnFit: What exactly is fitting?  Stupidly, in my opinion, it includes the | 
 |  *         trailing intercharacter spacing and any trailing justification. | 
 |  * | 
 |  * FIXME | 
 |  * Currently we do this by measuring each character etc.  We should do it by | 
 |  * passing the request to the driver, perhaps by extending the | 
 |  * pGetTextExtentPoint function to take the alpDx argument.  That would avoid | 
 |  * thinking about kerning issues and rounding issues in the justification. | 
 |  */ | 
 |  | 
 | BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, | 
 | 				   INT maxExt, LPINT lpnFit, | 
 | 				   LPINT alpDx, LPSIZE size ) | 
 | { | 
 |     int index, nFit, extent; | 
 |     SIZE tSize; | 
 |     BOOL ret = FALSE; | 
 |  | 
 |     TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt); | 
 |  | 
 |     size->cx = size->cy = nFit = extent = 0; | 
 |     for(index = 0; index < count; index++) | 
 |     { | 
 |  	if(!GetTextExtentPoint32W( hdc, str, 1, &tSize )) goto done; | 
 |         /* GetTextExtentPoint includes intercharacter spacing. */ | 
 |         /* FIXME - justification needs doing yet.  Remember that the base | 
 |          * data will not be in logical coordinates. | 
 |          */ | 
 | 	extent += tSize.cx; | 
 | 	if( !lpnFit || extent <= maxExt ) | 
 |         /* It is allowed to be equal. */ | 
 |         { | 
 | 	    nFit++; | 
 | 	    if( alpDx ) alpDx[index] = extent; | 
 |         } | 
 | 	if( tSize.cy > size->cy ) size->cy = tSize.cy; | 
 | 	str++; | 
 |     } | 
 |     size->cx = extent; | 
 |     if(lpnFit) *lpnFit = nFit; | 
 |     ret = TRUE; | 
 |  | 
 |     TRACE("returning %d %ld x %ld\n",nFit,size->cx,size->cy); | 
 |  | 
 | done: | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextMetricsA    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics ) | 
 | { | 
 |     TEXTMETRICW tm32; | 
 |  | 
 |     if (!GetTextMetricsW( hdc, &tm32 )) return FALSE; | 
 |     FONT_TextMetricWToA( &tm32, metrics ); | 
 |     return TRUE; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextMetricsW    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics ) | 
 | { | 
 |     BOOL ret = FALSE; | 
 |     DC * dc = DC_GetDCPtr( hdc ); | 
 |     if (!dc) return FALSE; | 
 |  | 
 |     if (dc->gdiFont) | 
 |         ret = WineEngGetTextMetrics(dc->gdiFont, metrics); | 
 |     else if (dc->funcs->pGetTextMetrics) | 
 |         ret = dc->funcs->pGetTextMetrics( dc->physDev, metrics ); | 
 |  | 
 |     if (ret) | 
 |     { | 
 |     /* device layer returns values in device units | 
 |      * therefore we have to convert them to logical */ | 
 |  | 
 | #define WDPTOLP(x) ((x<0)?					\ | 
 | 		(-abs(INTERNAL_XDSTOWS(dc, (x)))):		\ | 
 | 		(abs(INTERNAL_XDSTOWS(dc, (x))))) | 
 | #define HDPTOLP(y) ((y<0)?					\ | 
 | 		(-abs(INTERNAL_YDSTOWS(dc, (y)))):		\ | 
 | 		(abs(INTERNAL_YDSTOWS(dc, (y))))) | 
 |  | 
 |     metrics->tmHeight           = HDPTOLP(metrics->tmHeight); | 
 |     metrics->tmAscent           = HDPTOLP(metrics->tmAscent); | 
 |     metrics->tmDescent          = HDPTOLP(metrics->tmDescent); | 
 |     metrics->tmInternalLeading  = HDPTOLP(metrics->tmInternalLeading); | 
 |     metrics->tmExternalLeading  = HDPTOLP(metrics->tmExternalLeading); | 
 |     metrics->tmAveCharWidth     = WDPTOLP(metrics->tmAveCharWidth); | 
 |     metrics->tmMaxCharWidth     = WDPTOLP(metrics->tmMaxCharWidth); | 
 |     metrics->tmOverhang         = WDPTOLP(metrics->tmOverhang); | 
 |         ret = TRUE; | 
 | #undef WDPTOLP | 
 | #undef HDPTOLP | 
 |     TRACE("text metrics:\n" | 
 |           "    Weight = %03li\t FirstChar = %i\t AveCharWidth = %li\n" | 
 |           "    Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %li\n" | 
 |           "    UnderLined = %01i\t DefaultChar = %i\t Overhang = %li\n" | 
 |           "    StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n" | 
 |           "    PitchAndFamily = %02x\n" | 
 |           "    --------------------\n" | 
 |           "    InternalLeading = %li\n" | 
 |           "    Ascent = %li\n" | 
 |           "    Descent = %li\n" | 
 |           "    Height = %li\n", | 
 |           metrics->tmWeight, metrics->tmFirstChar, metrics->tmAveCharWidth, | 
 |           metrics->tmItalic, metrics->tmLastChar, metrics->tmMaxCharWidth, | 
 |           metrics->tmUnderlined, metrics->tmDefaultChar, metrics->tmOverhang, | 
 |           metrics->tmStruckOut, metrics->tmBreakChar, metrics->tmCharSet, | 
 |           metrics->tmPitchAndFamily, | 
 |           metrics->tmInternalLeading, | 
 |           metrics->tmAscent, | 
 |           metrics->tmDescent, | 
 |           metrics->tmHeight ); | 
 |     } | 
 |     GDI_ReleaseObj( hdc ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  * GetOutlineTextMetrics [GDI.308]  Gets metrics for TrueType fonts. | 
 |  * | 
 |  * NOTES | 
 |  *    lpOTM should be LPOUTLINETEXTMETRIC | 
 |  * | 
 |  * RETURNS | 
 |  *    Success: Non-zero or size of required buffer | 
 |  *    Failure: 0 | 
 |  */ | 
 | UINT16 WINAPI GetOutlineTextMetrics16( | 
 |     HDC16 hdc,    /* [in]  Handle of device context */ | 
 |     UINT16 cbData, /* [in]  Size of metric data array */ | 
 |     LPOUTLINETEXTMETRIC16 lpOTM)  /* [out] Address of metric data array */ | 
 | { | 
 |     FIXME("(%04x,%04x,%p): stub\n", hdc,cbData,lpOTM); | 
 |     return 0; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *		GetOutlineTextMetricsA (GDI32.@) | 
 |  * Gets metrics for TrueType fonts. | 
 |  * | 
 |  * NOTES | 
 |  *    If the supplied buffer isn't big enough Windows partially fills it up to | 
 |  *    its given length and returns that length. | 
 |  * | 
 |  * RETURNS | 
 |  *    Success: Non-zero or size of required buffer | 
 |  *    Failure: 0 | 
 |  */ | 
 | UINT WINAPI GetOutlineTextMetricsA( | 
 |     HDC hdc,    /* [in]  Handle of device context */ | 
 |     UINT cbData, /* [in]  Size of metric data array */ | 
 |     LPOUTLINETEXTMETRICA lpOTM)  /* [out] Address of metric data array */ | 
 | { | 
 |     char buf[512], *ptr; | 
 |     UINT ret, needed; | 
 |     OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf; | 
 |     OUTLINETEXTMETRICA *output = lpOTM; | 
 |     INT left, len; | 
 |  | 
 |     if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0) | 
 |         return 0; | 
 |     if(ret > sizeof(buf)) | 
 | 	lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret); | 
 |     GetOutlineTextMetricsW(hdc, ret, lpOTMW); | 
 |  | 
 |     needed = sizeof(OUTLINETEXTMETRICA); | 
 |     if(lpOTMW->otmpFamilyName) | 
 |         needed += WideCharToMultiByte(CP_ACP, 0, | 
 | 	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1, | 
 | 				      NULL, 0, NULL, NULL); | 
 |     if(lpOTMW->otmpFaceName) | 
 |         needed += WideCharToMultiByte(CP_ACP, 0, | 
 | 	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1, | 
 | 				      NULL, 0, NULL, NULL); | 
 |     if(lpOTMW->otmpStyleName) | 
 |         needed += WideCharToMultiByte(CP_ACP, 0, | 
 | 	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1, | 
 | 				      NULL, 0, NULL, NULL); | 
 |     if(lpOTMW->otmpFullName) | 
 |         needed += WideCharToMultiByte(CP_ACP, 0, | 
 | 	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1, | 
 | 				      NULL, 0, NULL, NULL); | 
 |  | 
 |     if(!lpOTM) { | 
 |         ret = needed; | 
 | 	goto end; | 
 |     } | 
 |  | 
 |     TRACE("needed = %d\n", needed); | 
 |     if(needed > cbData) | 
 |         /* Since the supplied buffer isn't big enough, we'll alloc one | 
 |            that is and memcpy the first cbData bytes into the lpOTM at | 
 |            the end. */ | 
 |         output = HeapAlloc(GetProcessHeap(), 0, needed); | 
 |  | 
 |     ret = output->otmSize = min(needed, cbData); | 
 |     FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics ); | 
 |     output->otmFiller = 0; | 
 |     output->otmPanoseNumber = lpOTMW->otmPanoseNumber; | 
 |     output->otmfsSelection = lpOTMW->otmfsSelection; | 
 |     output->otmfsType = lpOTMW->otmfsType; | 
 |     output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise; | 
 |     output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun; | 
 |     output->otmItalicAngle = lpOTMW->otmItalicAngle; | 
 |     output->otmEMSquare = lpOTMW->otmEMSquare; | 
 |     output->otmAscent = lpOTMW->otmAscent; | 
 |     output->otmDescent = lpOTMW->otmDescent; | 
 |     output->otmLineGap = lpOTMW->otmLineGap; | 
 |     output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight; | 
 |     output->otmsXHeight = lpOTMW->otmsXHeight; | 
 |     output->otmrcFontBox = lpOTMW->otmrcFontBox; | 
 |     output->otmMacAscent = lpOTMW->otmMacAscent; | 
 |     output->otmMacDescent = lpOTMW->otmMacDescent; | 
 |     output->otmMacLineGap = lpOTMW->otmMacLineGap; | 
 |     output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM; | 
 |     output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize; | 
 |     output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset; | 
 |     output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize; | 
 |     output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset; | 
 |     output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize; | 
 |     output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition; | 
 |     output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize; | 
 |     output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition; | 
 |  | 
 |  | 
 |     ptr = (char*)(output + 1); | 
 |     left = needed - sizeof(*output); | 
 |  | 
 |     if(lpOTMW->otmpFamilyName) { | 
 |         output->otmpFamilyName = (LPSTR)(ptr - (char*)output); | 
 | 	len = WideCharToMultiByte(CP_ACP, 0, | 
 | 	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1, | 
 | 				  ptr, left, NULL, NULL); | 
 | 	left -= len; | 
 | 	ptr += len; | 
 |     } else | 
 |         output->otmpFamilyName = 0; | 
 |  | 
 |     if(lpOTMW->otmpFaceName) { | 
 |         output->otmpFaceName = (LPSTR)(ptr - (char*)output); | 
 | 	len = WideCharToMultiByte(CP_ACP, 0, | 
 | 	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1, | 
 | 				  ptr, left, NULL, NULL); | 
 | 	left -= len; | 
 | 	ptr += len; | 
 |     } else | 
 |         output->otmpFaceName = 0; | 
 |  | 
 |     if(lpOTMW->otmpStyleName) { | 
 |         output->otmpStyleName = (LPSTR)(ptr - (char*)output); | 
 | 	len = WideCharToMultiByte(CP_ACP, 0, | 
 | 	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1, | 
 | 				  ptr, left, NULL, NULL); | 
 | 	left -= len; | 
 | 	ptr += len; | 
 |     } else | 
 |         output->otmpStyleName = 0; | 
 |  | 
 |     if(lpOTMW->otmpFullName) { | 
 |         output->otmpFullName = (LPSTR)(ptr - (char*)output); | 
 | 	len = WideCharToMultiByte(CP_ACP, 0, | 
 | 	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1, | 
 | 				  ptr, left, NULL, NULL); | 
 | 	left -= len; | 
 |     } else | 
 |         output->otmpFullName = 0; | 
 |  | 
 |     assert(left == 0); | 
 |  | 
 |     if(output != lpOTM) { | 
 |         memcpy(lpOTM, output, cbData); | 
 |         HeapFree(GetProcessHeap(), 0, output); | 
 |     } | 
 |  | 
 | end: | 
 |     if(lpOTMW != (OUTLINETEXTMETRICW *)buf) | 
 |         HeapFree(GetProcessHeap(), 0, lpOTMW); | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetOutlineTextMetricsW [GDI32.@] | 
 |  */ | 
 | UINT WINAPI GetOutlineTextMetricsW( | 
 |     HDC hdc,    /* [in]  Handle of device context */ | 
 |     UINT cbData, /* [in]  Size of metric data array */ | 
 |     LPOUTLINETEXTMETRICW lpOTM)  /* [out] Address of metric data array */ | 
 | { | 
 |     DC *dc = DC_GetDCPtr( hdc ); | 
 |     OUTLINETEXTMETRICW *output = lpOTM; | 
 |     UINT ret; | 
 |  | 
 |     TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM); | 
 |     if(!dc) return 0; | 
 |  | 
 |     if(dc->gdiFont) { | 
 |         ret = WineEngGetOutlineTextMetrics(dc->gdiFont, cbData, output); | 
 |         if(lpOTM && ret) { | 
 |             if(ret > cbData) { | 
 |                 output = HeapAlloc(GetProcessHeap(), 0, ret); | 
 |                 WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output); | 
 |             } | 
 |  | 
 | #define WDPTOLP(x) ((x<0)?					\ | 
 | 		(-abs(INTERNAL_XDSTOWS(dc, (x)))):		\ | 
 | 		(abs(INTERNAL_XDSTOWS(dc, (x))))) | 
 | #define HDPTOLP(y) ((y<0)?					\ | 
 | 		(-abs(INTERNAL_YDSTOWS(dc, (y)))):		\ | 
 | 		(abs(INTERNAL_YDSTOWS(dc, (y))))) | 
 |  | 
 | 	    output->otmTextMetrics.tmHeight           = HDPTOLP(output->otmTextMetrics.tmHeight); | 
 | 	    output->otmTextMetrics.tmAscent           = HDPTOLP(output->otmTextMetrics.tmAscent); | 
 | 	    output->otmTextMetrics.tmDescent          = HDPTOLP(output->otmTextMetrics.tmDescent); | 
 | 	    output->otmTextMetrics.tmInternalLeading  = HDPTOLP(output->otmTextMetrics.tmInternalLeading); | 
 | 	    output->otmTextMetrics.tmExternalLeading  = HDPTOLP(output->otmTextMetrics.tmExternalLeading); | 
 | 	    output->otmTextMetrics.tmAveCharWidth     = WDPTOLP(output->otmTextMetrics.tmAveCharWidth); | 
 | 	    output->otmTextMetrics.tmMaxCharWidth     = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth); | 
 | 	    output->otmTextMetrics.tmOverhang         = WDPTOLP(output->otmTextMetrics.tmOverhang); | 
 | 	    output->otmAscent = HDPTOLP(output->otmAscent); | 
 | 	    output->otmDescent = HDPTOLP(output->otmDescent); | 
 | 	    output->otmLineGap = HDPTOLP(output->otmLineGap); | 
 | 	    output->otmsCapEmHeight = HDPTOLP(output->otmsCapEmHeight); | 
 | 	    output->otmsXHeight = HDPTOLP(output->otmsXHeight); | 
 | 	    output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top); | 
 | 	    output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom); | 
 | 	    output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left); | 
 | 	    output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right); | 
 | 	    output->otmMacAscent = HDPTOLP(output->otmMacAscent); | 
 | 	    output->otmMacDescent = HDPTOLP(output->otmMacDescent); | 
 | 	    output->otmMacLineGap = HDPTOLP(output->otmMacLineGap); | 
 | 	    output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x); | 
 | 	    output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y); | 
 | 	    output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x); | 
 | 	    output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y); | 
 | 	    output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x); | 
 | 	    output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y); | 
 | 	    output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x); | 
 | 	    output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y); | 
 | 	    output->otmsStrikeoutSize = HDPTOLP(output->otmsStrikeoutSize); | 
 | 	    output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition); | 
 | 	    output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize); | 
 | 	    output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition); | 
 | #undef WDPTOLP | 
 | #undef HDPTOLP | 
 |             if(output != lpOTM) { | 
 |                 memcpy(lpOTM, output, cbData); | 
 |                 HeapFree(GetProcessHeap(), 0, output); | 
 |                 ret = cbData; | 
 |             } | 
 | 	} | 
 |     } | 
 |  | 
 |     else { /* This stuff was in GetOutlineTextMetricsA, I've moved it here | 
 | 	      but really this should just be a return 0. */ | 
 |  | 
 |         ret = sizeof(*lpOTM); | 
 |         if (lpOTM) { | 
 | 	    if(cbData < ret) | 
 | 	        ret = 0; | 
 | 	    else { | 
 | 	        memset(lpOTM, 0, ret); | 
 | 		lpOTM->otmSize = sizeof(*lpOTM); | 
 | 		GetTextMetricsW(hdc, &lpOTM->otmTextMetrics); | 
 | 		/* | 
 | 		  Further fill of the structure not implemented, | 
 | 		  Needs real values for the structure members | 
 | 		*/ | 
 | 	    } | 
 | 	} | 
 |     } | 
 |     GDI_ReleaseObj(hdc); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetCharWidthW      (GDI32.@) | 
 |  *           GetCharWidth32W    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar, | 
 |                                LPINT buffer ) | 
 | { | 
 |     UINT i; | 
 |     BOOL ret = FALSE; | 
 |     DC * dc = DC_GetDCPtr( hdc ); | 
 |     if (!dc) return FALSE; | 
 |  | 
 |     if (dc->gdiFont) | 
 |         ret = WineEngGetCharWidth( dc->gdiFont, firstChar, lastChar, buffer ); | 
 |     else if (dc->funcs->pGetCharWidth) | 
 |         ret = dc->funcs->pGetCharWidth( dc->physDev, firstChar, lastChar, buffer); | 
 |  | 
 |     if (ret) | 
 |     { | 
 |         /* convert device units to logical */ | 
 |         for( i = firstChar; i <= lastChar; i++, buffer++ ) | 
 |             *buffer = INTERNAL_XDSTOWS(dc, *buffer); | 
 |         ret = TRUE; | 
 |     } | 
 |     GDI_ReleaseObj( hdc ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetCharWidthA      (GDI32.@) | 
 |  *           GetCharWidth32A    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar, | 
 |                                LPINT buffer ) | 
 | { | 
 |     INT i, wlen, count = (INT)(lastChar - firstChar + 1); | 
 |     LPSTR str; | 
 |     LPWSTR wstr; | 
 |     BOOL ret = TRUE; | 
 |  | 
 |     if(count <= 0) return FALSE; | 
 |  | 
 |     str = HeapAlloc(GetProcessHeap(), 0, count); | 
 |     for(i = 0; i < count; i++) | 
 | 	str[i] = (BYTE)(firstChar + i); | 
 |  | 
 |     wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL); | 
 |  | 
 |     for(i = 0; i < wlen; i++) | 
 |     { | 
 | 	if(!GetCharWidth32W(hdc, wstr[i], wstr[i], buffer)) | 
 | 	{ | 
 | 	    ret = FALSE; | 
 | 	    break; | 
 | 	} | 
 | 	buffer++; | 
 |     } | 
 |  | 
 |     HeapFree(GetProcessHeap(), 0, str); | 
 |     HeapFree(GetProcessHeap(), 0, wstr); | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           ExtTextOutA    (GDI32.@) | 
 |  * | 
 |  * See ExtTextOutW. | 
 |  */ | 
 | BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags, | 
 |                          const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx ) | 
 | { | 
 |     INT wlen; | 
 |     UINT codepage; | 
 |     LPWSTR p = FONT_mbtowc(hdc, str, count, &wlen, &codepage); | 
 |     BOOL ret; | 
 |     LPINT lpDxW = NULL; | 
 |  | 
 |     if (lpDx) { | 
 |         unsigned int i = 0, j = 0; | 
 |  | 
 |         lpDxW = (LPINT)HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT)); | 
 |         while(i < count) { | 
 |             if(IsDBCSLeadByteEx(codepage, str[i])) { | 
 |                 lpDxW[j++] = lpDx[i] + lpDx[i+1]; | 
 |                 i = i + 2; | 
 |             } else { | 
 |                 lpDxW[j++] = lpDx[i]; | 
 |                 i = i + 1; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW ); | 
 |  | 
 |     HeapFree( GetProcessHeap(), 0, p ); | 
 |     HeapFree( GetProcessHeap(), 0, lpDxW ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           ExtTextOutW    (GDI32.@) | 
 |  * | 
 |  * Draws text using the currently selected font, background color, and text color. | 
 |  *  | 
 |  *  | 
 |  * PARAMS | 
 |  *    x,y    [I] coordinates of string | 
 |  *    flags  [I] | 
 |  *        ETO_GRAYED - undocumented on MSDN | 
 |  *        ETO_OPAQUE - use background color for fill the rectangle | 
 |  *        ETO_CLIPPED - clipping text to the rectangle | 
 |  *        ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather | 
 |  *                          than encoded characters. Implies ETO_IGNORELANGUAGE | 
 |  *        ETO_RTLREADING - Paragraph is basically a right-to-left paragraph. | 
 |  *                         Affects BiDi ordering | 
 |  *        ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering | 
 |  *        ETO_PDY - unimplemented | 
 |  *        ETO_NUMERICSLATIN - unimplemented always assumed - | 
 |  *                            do not translate numbers into locale representations | 
 |  *        ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form | 
 |  *    lprect [I] dimensions for clipping or/and opaquing | 
 |  *    str    [I] text string | 
 |  *    count  [I] number of symbols in string | 
 |  *    lpDx   [I] optional parameter with distance between drawing characters | 
 |  * | 
 |  * RETURNS | 
 |  *    Success: TRUE | 
 |  *    Failure: FALSE | 
 |  */ | 
 | BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags, | 
 |                          const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx ) | 
 | { | 
 |     BOOL ret = FALSE; | 
 |     DC * dc = DC_GetDCUpdate( hdc ); | 
 |     if (dc) | 
 |     { | 
 |         if (flags&(ETO_NUMERICSLOCAL|ETO_NUMERICSLATIN|ETO_PDY)) | 
 |             FIXME("flags ETO_NUMERICSLOCAL|ETO_NUMERICSLATIN|ETO_PDY unimplemented\n"); | 
 |  | 
 |         if(PATH_IsPathOpen(dc->path)) | 
 |             FIXME("called on an open path\n"); | 
 |         else if(dc->funcs->pExtTextOut) | 
 |         { | 
 |             if( !(flags&(ETO_GLYPH_INDEX|ETO_IGNORELANGUAGE)) && BidiAvail && count>0 ) | 
 |             { | 
 |                 /* The caller did not specify that language processing was already done. | 
 |                  */ | 
 |                 LPWSTR lpReorderedString=HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR)); | 
 |  | 
 |                 BIDI_Reorder( str, count, GCP_REORDER, | 
 |                               ((flags&ETO_RTLREADING)!=0 || (GetTextAlign(hdc)&TA_RTLREADING)!=0)? | 
 |                               WINE_GCPW_FORCE_RTL:WINE_GCPW_FORCE_LTR, | 
 |                               lpReorderedString, count, NULL ); | 
 |  | 
 |                 ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags|ETO_IGNORELANGUAGE, | 
 |                                              lprect,lpReorderedString,count,lpDx,dc->breakExtra); | 
 |                 HeapFree(GetProcessHeap(), 0, lpReorderedString); | 
 |             } else | 
 |                 ret = dc->funcs->pExtTextOut(dc->physDev,x,y,flags,lprect,str,count, | 
 |                                              lpDx,dc->breakExtra); | 
 |         } | 
 |         GDI_ReleaseObj( hdc ); | 
 |     } | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           TextOutA    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, LPCSTR str, INT count ) | 
 | { | 
 |     return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL ); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           TextOutW    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI TextOutW(HDC hdc, INT x, INT y, LPCWSTR str, INT count) | 
 | { | 
 |     return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL ); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *		PolyTextOutA (GDI32.@) | 
 |  * | 
 |  * Draw several Strings | 
 |  */ | 
 | BOOL WINAPI PolyTextOutA ( HDC hdc,               /* [in] Handle to device context */ | 
 |                            PPOLYTEXTA pptxt,      /* [in] Array of strings */ | 
 |                            INT cStrings )         /* [in] Number of strings in array */ | 
 | { | 
 |     for (; cStrings>0; cStrings--, pptxt++) | 
 |         if (!ExtTextOutA( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx )) | 
 |             return FALSE; | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *		PolyTextOutW (GDI32.@) | 
 |  * | 
 |  * Draw several Strings | 
 |  */ | 
 | BOOL WINAPI PolyTextOutW ( HDC hdc,               /* [in] Handle to device context */ | 
 |                            PPOLYTEXTW pptxt,      /* [in] Array of strings */ | 
 |                            INT cStrings )         /* [in] Number of strings in array */ | 
 | { | 
 |     for (; cStrings>0; cStrings--, pptxt++) | 
 |         if (!ExtTextOutW( hdc, pptxt->x, pptxt->y, pptxt->uiFlags, &pptxt->rcl, pptxt->lpstr, pptxt->n, pptxt->pdx )) | 
 |             return FALSE; | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | /* FIXME: all following APIs ******************************************/ | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           SetMapperFlags    (GDI32.@) | 
 |  */ | 
 | DWORD WINAPI SetMapperFlags( HDC hDC, DWORD dwFlag ) | 
 | { | 
 |     DC *dc = DC_GetDCPtr( hDC ); | 
 |     DWORD ret = 0; | 
 |     if(!dc) return 0; | 
 |     if(dc->funcs->pSetMapperFlags) | 
 |         ret = dc->funcs->pSetMapperFlags( dc->physDev, dwFlag ); | 
 |     else | 
 |         FIXME("(%p, 0x%08lx): stub - harmless\n", hDC, dwFlag); | 
 |     GDI_ReleaseObj( hDC ); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *          GetAspectRatioFilterEx  (GDI.486) | 
 |  */ | 
 | BOOL16 WINAPI GetAspectRatioFilterEx16( HDC16 hdc, LPSIZE16 pAspectRatio ) | 
 | { | 
 |   FIXME("(%04x, %p): -- Empty Stub !\n", hdc, pAspectRatio); | 
 |   return FALSE; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *          GetAspectRatioFilterEx  (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio ) | 
 | { | 
 |   FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio); | 
 |   return FALSE; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetCharABCWidthsA   (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar, | 
 |                                   LPABC abc ) | 
 | { | 
 |     INT i, wlen, count = (INT)(lastChar - firstChar + 1); | 
 |     LPSTR str; | 
 |     LPWSTR wstr; | 
 |     BOOL ret = TRUE; | 
 |  | 
 |     if(count <= 0) return FALSE; | 
 |  | 
 |     str = HeapAlloc(GetProcessHeap(), 0, count); | 
 |     for(i = 0; i < count; i++) | 
 | 	str[i] = (BYTE)(firstChar + i); | 
 |  | 
 |     wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL); | 
 |  | 
 |     for(i = 0; i < wlen; i++) | 
 |     { | 
 | 	if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc)) | 
 | 	{ | 
 | 	    ret = FALSE; | 
 | 	    break; | 
 | 	} | 
 | 	abc++; | 
 |     } | 
 |  | 
 |     HeapFree(GetProcessHeap(), 0, str); | 
 |     HeapFree(GetProcessHeap(), 0, wstr); | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /****************************************************************************** | 
 |  * GetCharABCWidthsW [GDI32.@] | 
 |  * | 
 |  * Retrieves widths of characters in range. | 
 |  * | 
 |  * PARAMS | 
 |  *    hdc       [I] Handle of device context | 
 |  *    firstChar [I] First character in range to query | 
 |  *    lastChar  [I] Last character in range to query | 
 |  *    abc       [O] Address of character-width structure | 
 |  * | 
 |  * NOTES | 
 |  *    Only works with TrueType fonts | 
 |  * | 
 |  * RETURNS | 
 |  *    Success: TRUE | 
 |  *    Failure: FALSE | 
 |  */ | 
 | BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar, | 
 |                                    LPABC abc ) | 
 | { | 
 |     DC *dc = DC_GetDCPtr(hdc); | 
 |     unsigned int i; | 
 |     BOOL ret = FALSE; | 
 |  | 
 |     if(dc->gdiFont) | 
 |         ret = WineEngGetCharABCWidths( dc->gdiFont, firstChar, lastChar, abc ); | 
 |     else | 
 |         FIXME(": stub\n"); | 
 |  | 
 |     if (ret) | 
 |     { | 
 |         /* convert device units to logical */ | 
 |         for( i = firstChar; i <= lastChar; i++, abc++ ) { | 
 |             abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA); | 
 |             abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB); | 
 |             abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC); | 
 | 	} | 
 |         ret = TRUE; | 
 |     } | 
 |  | 
 |     GDI_ReleaseObj(hdc); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetGlyphOutline    (GDI.309) | 
 |  */ | 
 | DWORD WINAPI GetGlyphOutline16( HDC16 hdc, UINT16 uChar, UINT16 fuFormat, | 
 |                                 LPGLYPHMETRICS16 lpgm, DWORD cbBuffer, | 
 |                                 LPVOID lpBuffer, const MAT2 *lpmat2 ) | 
 | { | 
 |     FIXME("(%04x, '%c', %04x, %p, %ld, %p, %p): stub\n", | 
 | 	  hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 ); | 
 |     return ~0UL; /* failure */ | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetGlyphOutlineA    (GDI32.@) | 
 |  */ | 
 | DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat, | 
 |                                  LPGLYPHMETRICS lpgm, DWORD cbBuffer, | 
 |                                  LPVOID lpBuffer, const MAT2 *lpmat2 ) | 
 | { | 
 |     LPWSTR p = NULL; | 
 |     DWORD ret; | 
 |     UINT c; | 
 |  | 
 |     if(!(fuFormat & GGO_GLYPH_INDEX)) { | 
 |         p = FONT_mbtowc(hdc, (char*)&uChar, 1, NULL, NULL); | 
 | 	c = p[0]; | 
 |     } else | 
 |         c = uChar; | 
 |     ret = GetGlyphOutlineW(hdc, c, fuFormat, lpgm, cbBuffer, lpBuffer, | 
 | 			   lpmat2); | 
 |     HeapFree(GetProcessHeap(), 0, p); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetGlyphOutlineW    (GDI32.@) | 
 |  */ | 
 | DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat, | 
 |                                  LPGLYPHMETRICS lpgm, DWORD cbBuffer, | 
 |                                  LPVOID lpBuffer, const MAT2 *lpmat2 ) | 
 | { | 
 |     DC *dc = DC_GetDCPtr(hdc); | 
 |     DWORD ret; | 
 |  | 
 |     TRACE("(%p, %04x, %04x, %p, %ld, %p, %p)\n", | 
 | 	  hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 ); | 
 |  | 
 |     if(!dc) return GDI_ERROR; | 
 |  | 
 |     if(dc->gdiFont) | 
 |       ret = WineEngGetGlyphOutline(dc->gdiFont, uChar, fuFormat, lpgm, | 
 | 				   cbBuffer, lpBuffer, lpmat2); | 
 |     else | 
 |       ret = GDI_ERROR; | 
 |  | 
 |     GDI_ReleaseObj(hdc); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           CreateScalableFontResourceA   (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden, | 
 |                                              LPCSTR lpszResourceFile, | 
 |                                              LPCSTR lpszFontFile, | 
 |                                              LPCSTR lpszCurrentPath ) | 
 | { | 
 |     HANDLE f; | 
 |  | 
 |     /* fHidden=1 - only visible for the calling app, read-only, not | 
 |      * enumbered with EnumFonts/EnumFontFamilies | 
 |      * lpszCurrentPath can be NULL | 
 |      */ | 
 |     FIXME("(%ld,%s,%s,%s): stub\n", | 
 |           fHidden, debugstr_a(lpszResourceFile), debugstr_a(lpszFontFile), | 
 |           debugstr_a(lpszCurrentPath) ); | 
 |  | 
 |     /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */ | 
 |     if ((f = CreateFileA(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) { | 
 |         CloseHandle(f); | 
 |         SetLastError(ERROR_FILE_EXISTS); | 
 |         return FALSE; | 
 |     } | 
 |     return FALSE; /* create failed */ | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           CreateScalableFontResourceW   (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden, | 
 |                                              LPCWSTR lpszResourceFile, | 
 |                                              LPCWSTR lpszFontFile, | 
 |                                              LPCWSTR lpszCurrentPath ) | 
 | { | 
 |     FIXME("(%ld,%p,%p,%p): stub\n", | 
 | 	  fHidden, lpszResourceFile, lpszFontFile, lpszCurrentPath ); | 
 |     return FALSE; /* create failed */ | 
 | } | 
 |  | 
 |  | 
 | /************************************************************************* | 
 |  *             GetRasterizerCaps   (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes) | 
 | { | 
 |   lprs->nSize = sizeof(RASTERIZER_STATUS); | 
 |   lprs->wFlags = TT_AVAILABLE|TT_ENABLED; | 
 |   lprs->nLanguageID = 0; | 
 |   return TRUE; | 
 | } | 
 |  | 
 |  | 
 | /************************************************************************* | 
 |  *             GetKerningPairsA   (GDI32.@) | 
 |  */ | 
 | DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs, | 
 |                                LPKERNINGPAIR lpKerningPairs ) | 
 | { | 
 |     return GetKerningPairsW( hDC, cPairs, lpKerningPairs ); | 
 | } | 
 |  | 
 |  | 
 | /************************************************************************* | 
 |  *             GetKerningPairsW   (GDI32.@) | 
 |  */ | 
 | DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs, | 
 |                                  LPKERNINGPAIR lpKerningPairs ) | 
 | { | 
 |     unsigned int i; | 
 |     FIXME("(%p,%ld,%p): almost empty stub!\n", hDC, cPairs, lpKerningPairs); | 
 |     for (i = 0; i < cPairs; i++) | 
 |         lpKerningPairs[i].iKernAmount = 0; | 
 |     return 0; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  * TranslateCharsetInfo [GDI32.@] | 
 |  * | 
 |  * Fills a CHARSETINFO structure for a character set, code page, or | 
 |  * font. This allows making the correspondance between different labelings | 
 |  * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges) | 
 |  * of the same encoding. | 
 |  * | 
 |  * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used, | 
 |  * only one codepage should be set in *lpSrc. | 
 |  * | 
 |  * RETURNS | 
 |  *   TRUE on success, FALSE on failure. | 
 |  * | 
 |  */ | 
 | BOOL WINAPI TranslateCharsetInfo( | 
 |   LPDWORD lpSrc, /* [in] | 
 |        if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE | 
 |        if flags == TCI_SRCCHARSET: a character set value | 
 |        if flags == TCI_SRCCODEPAGE: a code page value | 
 | 		 */ | 
 |   LPCHARSETINFO lpCs, /* [out] structure to receive charset information */ | 
 |   DWORD flags /* [in] determines interpretation of lpSrc */) | 
 | { | 
 |     int index = 0; | 
 |     switch (flags) { | 
 |     case TCI_SRCFONTSIG: | 
 | 	while (!(*lpSrc>>index & 0x0001) && index<MAXTCIINDEX) index++; | 
 |       break; | 
 |     case TCI_SRCCODEPAGE: | 
 |       while ((UINT) (lpSrc) != FONT_tci[index].ciACP && index < MAXTCIINDEX) index++; | 
 |       break; | 
 |     case TCI_SRCCHARSET: | 
 |       while ((UINT) (lpSrc) != FONT_tci[index].ciCharset && index < MAXTCIINDEX) index++; | 
 |       break; | 
 |     default: | 
 |       return FALSE; | 
 |     } | 
 |     if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE; | 
 |     memcpy(lpCs, &FONT_tci[index], sizeof(CHARSETINFO)); | 
 |     return TRUE; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  *             GetFontLanguageInfo   (GDI32.@) | 
 |  */ | 
 | DWORD WINAPI GetFontLanguageInfo(HDC hdc) | 
 | { | 
 | 	FONTSIGNATURE fontsig; | 
 | 	static const DWORD GCP_DBCS_MASK=0x003F0000, | 
 | 		GCP_DIACRITIC_MASK=0x00000000, | 
 | 		FLI_GLYPHS_MASK=0x00000000, | 
 | 		GCP_GLYPHSHAPE_MASK=0x00000040, | 
 | 		GCP_KASHIDA_MASK=0x00000000, | 
 | 		GCP_LIGATE_MASK=0x00000000, | 
 | 		GCP_USEKERNING_MASK=0x00000000, | 
 | 		GCP_REORDER_MASK=0x00000060; | 
 |  | 
 | 	DWORD result=0; | 
 |  | 
 | 	GetTextCharsetInfo( hdc, &fontsig, 0 ); | 
 | 	/* We detect each flag we return using a bitmask on the Codepage Bitfields */ | 
 |  | 
 | 	if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 ) | 
 | 		result|=GCP_DBCS; | 
 |  | 
 | 	if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 ) | 
 | 		result|=GCP_DIACRITIC; | 
 |  | 
 | 	if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 ) | 
 | 		result|=FLI_GLYPHS; | 
 |  | 
 | 	if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 ) | 
 | 		result|=GCP_GLYPHSHAPE; | 
 |  | 
 | 	if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 ) | 
 | 		result|=GCP_KASHIDA; | 
 |  | 
 | 	if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 ) | 
 | 		result|=GCP_LIGATE; | 
 |  | 
 | 	if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 ) | 
 | 		result|=GCP_USEKERNING; | 
 |  | 
 |         /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */ | 
 |         if( GetTextAlign( hdc) & TA_RTLREADING ) | 
 |             if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 ) | 
 |                     result|=GCP_REORDER; | 
 |  | 
 | 	return result; | 
 | } | 
 |  | 
 |  | 
 | /************************************************************************* | 
 |  * GetFontData [GDI32.@] | 
 |  * | 
 |  * Retrieve data for TrueType font. | 
 |  * | 
 |  * RETURNS | 
 |  * | 
 |  * success: Number of bytes returned | 
 |  * failure: GDI_ERROR | 
 |  * | 
 |  * NOTES | 
 |  * | 
 |  * Calls SetLastError() | 
 |  * | 
 |  */ | 
 | DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset, | 
 |     LPVOID buffer, DWORD length) | 
 | { | 
 |     DC *dc = DC_GetDCPtr(hdc); | 
 |     DWORD ret = GDI_ERROR; | 
 |  | 
 |     if(!dc) return GDI_ERROR; | 
 |  | 
 |     if(dc->gdiFont) | 
 |       ret = WineEngGetFontData(dc->gdiFont, table, offset, buffer, length); | 
 |  | 
 |     GDI_ReleaseObj(hdc); | 
 |     return ret; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  * GetGlyphIndicesA [GDI32.@] | 
 |  */ | 
 | DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count, | 
 | 			      LPWORD pgi, DWORD flags) | 
 | { | 
 |     DWORD ret; | 
 |     WCHAR *lpstrW; | 
 |     INT countW; | 
 |  | 
 |     TRACE("(%p, %s, %d, %p, 0x%lx)\n", | 
 |           hdc, debugstr_an(lpstr, count), count, pgi, flags); | 
 |  | 
 |     lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL); | 
 |     ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags); | 
 |     HeapFree(GetProcessHeap(), 0, lpstrW); | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  * GetGlyphIndicesW [GDI32.@] | 
 |  */ | 
 | DWORD WINAPI GetGlyphIndicesW(HDC hdc, LPCWSTR lpstr, INT count, | 
 | 			      LPWORD pgi, DWORD flags) | 
 | { | 
 |     DC *dc = DC_GetDCPtr(hdc); | 
 |     DWORD ret = GDI_ERROR; | 
 |  | 
 |     TRACE("(%p, %s, %d, %p, 0x%lx)\n", | 
 |           hdc, debugstr_wn(lpstr, count), count, pgi, flags); | 
 |  | 
 |     if(!dc) return GDI_ERROR; | 
 |  | 
 |     if(dc->gdiFont) | 
 | 	ret = WineEngGetGlyphIndices(dc->gdiFont, lpstr, count, pgi, flags); | 
 |  | 
 |     GDI_ReleaseObj(hdc); | 
 |     return ret; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  * GetCharacterPlacementA [GDI32.@] | 
 |  * | 
 |  * NOTES: | 
 |  *  the web browser control of ie4 calls this with dwFlags=0 | 
 |  */ | 
 | DWORD WINAPI | 
 | GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount, | 
 | 			 INT nMaxExtent, GCP_RESULTSA *lpResults, | 
 | 			 DWORD dwFlags) | 
 | { | 
 |     WCHAR *lpStringW; | 
 |     INT uCountW; | 
 |     GCP_RESULTSW resultsW; | 
 |     DWORD ret; | 
 |     UINT font_cp; | 
 |  | 
 |     TRACE("%s, %d, %d, 0x%08lx\n", | 
 |           debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags); | 
 |  | 
 |     /* both structs are equal in size */ | 
 |     memcpy(&resultsW, lpResults, sizeof(resultsW)); | 
 |  | 
 |     lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp); | 
 |     if(lpResults->lpOutString) | 
 |         resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW); | 
 |  | 
 |     ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags); | 
 |  | 
 |     if(lpResults->lpOutString) { | 
 |         WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW, | 
 |                             lpResults->lpOutString, uCount, NULL, NULL ); | 
 |     } | 
 |  | 
 |     HeapFree(GetProcessHeap(), 0, lpStringW); | 
 |     HeapFree(GetProcessHeap(), 0, resultsW.lpOutString); | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  * GetCharacterPlacementW [GDI32.@] | 
 |  * | 
 |  *   Retrieve information about a string. This includes the width, reordering, | 
 |  *   Glyphing and so on. | 
 |  * | 
 |  * RETURNS | 
 |  * | 
 |  *   The width and height of the string if successful, 0 if failed. | 
 |  * | 
 |  * BUGS | 
 |  * | 
 |  *   All flags except GCP_REORDER are not yet implemented. | 
 |  *   Reordering is not 100% complient to the Windows BiDi method. | 
 |  *   Caret positioning is not yet implemented for BiDi. | 
 |  *   Classes are not yet implemented. | 
 |  * | 
 |  */ | 
 | DWORD WINAPI | 
 | GetCharacterPlacementW( | 
 | 		HDC hdc,		/* [in] Device context for which the rendering is to be done */ | 
 | 		LPCWSTR lpString,	/* [in] The string for which information is to be returned */ | 
 | 		INT uCount,		/* [in] Number of WORDS in string. */ | 
 | 		INT nMaxExtent,		/* [in] Maximum extent the string is to take (in HDC logical units) */ | 
 | 		GCP_RESULTSW *lpResults,/* [in/out] A pointer to a GCP_RESULTSW struct */ | 
 | 		DWORD dwFlags 		/* [in] Flags specifying how to process the string */ | 
 | 		) | 
 | { | 
 |     DWORD ret=0; | 
 |     SIZE size; | 
 |     UINT i, nSet; | 
 |  | 
 |     TRACE("%s, %d, %d, 0x%08lx\n", | 
 |           debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags); | 
 |  | 
 |     TRACE("lStructSize=%ld, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n" | 
 | 	  "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n", | 
 | 	    lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder, | 
 | 	    lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass, | 
 | 	    lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit); | 
 |  | 
 |     if(dwFlags&(~GCP_REORDER))			FIXME("flags 0x%08lx ignored\n", dwFlags); | 
 |     if(lpResults->lpClass)	FIXME("classes not implemented\n"); | 
 |     if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER)) | 
 |         FIXME("Caret positions for complex scripts not implemented\n"); | 
 |  | 
 | 	nSet = (UINT)uCount; | 
 | 	if(nSet > lpResults->nGlyphs) | 
 | 		nSet = lpResults->nGlyphs; | 
 |  | 
 | 	/* return number of initialized fields */ | 
 | 	lpResults->nGlyphs = nSet; | 
 |  | 
 | 	if((dwFlags&GCP_REORDER)==0 || !BidiAvail) | 
 | 	{ | 
 | 		/* Treat the case where no special handling was requested in a fastpath way */ | 
 | 		/* copy will do if the GCP_REORDER flag is not set */ | 
 | 		if(lpResults->lpOutString) | 
 |                     strncpyW( lpResults->lpOutString, lpString, nSet ); | 
 |  | 
 | 		if(lpResults->lpOrder) | 
 | 		{ | 
 | 			for(i = 0; i < nSet; i++) | 
 | 				lpResults->lpOrder[i] = i; | 
 | 		} | 
 | 	} else | 
 | 	{ | 
 |             BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString, | 
 |                           nSet, lpResults->lpOrder ); | 
 | 	} | 
 |  | 
 | 	/* FIXME: Will use the placement chars */ | 
 | 	if (lpResults->lpDx) | 
 | 	{ | 
 | 		int c; | 
 | 		for (i = 0; i < nSet; i++) | 
 | 		{ | 
 | 			if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c)) | 
 | 				lpResults->lpDx[i]= c; | 
 | 		} | 
 | 	} | 
 |  | 
 |     if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER)) | 
 |     { | 
 |         int pos = 0; | 
 |         | 
 |         lpResults->lpCaretPos[0] = 0; | 
 |         for (i = 1; i < nSet; i++) | 
 |             if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size)) | 
 |                 lpResults->lpCaretPos[i] = (pos += size.cx); | 
 |     } | 
 |     | 
 |     if(lpResults->lpGlyphs) | 
 | 	GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0); | 
 |  | 
 |     if (GetTextExtentPoint32W(hdc, lpString, uCount, &size)) | 
 |       ret = MAKELONG(size.cx, size.cy); | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  *      GetCharABCWidthsFloatA [GDI32.@] | 
 |  */ | 
 | BOOL WINAPI GetCharABCWidthsFloatA(HDC hdc, UINT iFirstChar, UINT iLastChar, | 
 | 		                        LPABCFLOAT lpABCF) | 
 | { | 
 |        FIXME_(gdi)("GetCharABCWidthsFloatA, stub\n"); | 
 |        return 0; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  *      GetCharABCWidthsFloatW [GDI32.@] | 
 |  */ | 
 | BOOL WINAPI GetCharABCWidthsFloatW(HDC hdc, UINT iFirstChar, | 
 | 		                        UINT iLastChar, LPABCFLOAT lpABCF) | 
 | { | 
 |        FIXME_(gdi)("GetCharABCWidthsFloatW, stub\n"); | 
 |        return 0; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  *      GetCharWidthFloatA [GDI32.@] | 
 |  */ | 
 | BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar, | 
 | 		                    UINT iLastChar, PFLOAT pxBuffer) | 
 | { | 
 |        FIXME_(gdi)("GetCharWidthFloatA, stub\n"); | 
 |        return 0; | 
 | } | 
 |  | 
 | /************************************************************************* | 
 |  *      GetCharWidthFloatW [GDI32.@] | 
 |  */ | 
 | BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar, | 
 | 		                    UINT iLastChar, PFLOAT pxBuffer) | 
 | { | 
 |        FIXME_(gdi)("GetCharWidthFloatW, stub\n"); | 
 |        return 0; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *								       * | 
 |  *           Font Resource API					       * | 
 |  *								       * | 
 |  ***********************************************************************/ | 
 |  | 
 | /*********************************************************************** | 
 |  *           AddFontResourceA    (GDI32.@) | 
 |  */ | 
 | INT WINAPI AddFontResourceA( LPCSTR str ) | 
 | { | 
 |     return AddFontResourceExA( str, 0, NULL); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           AddFontResourceW    (GDI32.@) | 
 |  */ | 
 | INT WINAPI AddFontResourceW( LPCWSTR str ) | 
 | { | 
 |     return AddFontResourceExW(str, 0, NULL); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           AddFontResourceExA    (GDI32.@) | 
 |  */ | 
 | INT WINAPI AddFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv ) | 
 | { | 
 |     DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); | 
 |     LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
 |     INT ret; | 
 |  | 
 |     MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len); | 
 |     ret = AddFontResourceExW(strW, fl, pdv); | 
 |     HeapFree(GetProcessHeap(), 0, strW); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           AddFontResourceExW    (GDI32.@) | 
 |  */ | 
 | INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv ) | 
 | { | 
 |     return WineEngAddFontResourceEx(str, fl, pdv); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           RemoveFontResourceA    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI RemoveFontResourceA( LPCSTR str ) | 
 | { | 
 |     return RemoveFontResourceExA(str, 0, 0); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           RemoveFontResourceW    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI RemoveFontResourceW( LPCWSTR str ) | 
 | { | 
 |     return RemoveFontResourceExW(str, 0, 0); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           RemoveFontResourceExA    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI RemoveFontResourceExA( LPCSTR str, DWORD fl, PVOID pdv ) | 
 | { | 
 |     DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); | 
 |     LPWSTR strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
 |     INT ret; | 
 |  | 
 |     MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len); | 
 |     ret = RemoveFontResourceExW(strW, fl, pdv); | 
 |     HeapFree(GetProcessHeap(), 0, strW); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           RemoveFontResourceExW    (GDI32.@) | 
 |  */ | 
 | BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv ) | 
 | { | 
 |     return WineEngRemoveFontResourceEx(str, fl, pdv); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextCharset    (GDI32.@) | 
 |  */ | 
 | UINT WINAPI GetTextCharset(HDC hdc) | 
 | { | 
 |     /* MSDN docs say this is equivalent */ | 
 |     return GetTextCharsetInfo(hdc, NULL, 0); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           GetTextCharsetInfo    (GDI32.@) | 
 |  */ | 
 | UINT WINAPI GetTextCharsetInfo(HDC hdc, LPFONTSIGNATURE fs, DWORD flags) | 
 | { | 
 |     UINT ret = DEFAULT_CHARSET; | 
 |     DC *dc = DC_GetDCPtr(hdc); | 
 |  | 
 |     if (!dc) goto done; | 
 |  | 
 |     if (dc->gdiFont) | 
 |         ret = WineEngGetTextCharsetInfo(dc->gdiFont, fs, flags); | 
 |  | 
 |     GDI_ReleaseObj(hdc); | 
 |  | 
 | done: | 
 |     if (ret == DEFAULT_CHARSET && fs) | 
 |         memset(fs, 0, sizeof(FONTSIGNATURE)); | 
 |     return ret; | 
 | } |