font.c 101 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * GDI font objects
 *
 * Copyright 1993 Alexandre Julliard
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 *           1997 Alex Korobka
6
 * Copyright 2002,2003 Shachar Shemesh
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
21
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
22

23 24 25
#include "config.h"
#include "wine/port.h"

26
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
27
#include <stdlib.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
28
#include <string.h>
29
#include <assert.h>
30
#include "winerror.h"
31
#include "windef.h"
32
#include "winbase.h"
33
#include "winnls.h"
Michael Stefaniuc's avatar
Michael Stefaniuc committed
34
#include "wownt32.h"
35
#include "gdi_private.h"
36
#include "wine/unicode.h"
37
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
38

39
WINE_DEFAULT_DEBUG_CHANNEL(font);
40

41 42 43 44 45 46 47
  /* 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)
{
48
    double floatWidth;
49 50

    /* Perform operation with floating point */
51
    floatWidth = (double)width * dc->xformVport2World.eM11;
52 53 54 55 56 57 58 59 60
    /* 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)
{
61
    double floatHeight;
62 63

    /* Perform operation with floating point */
64
    floatHeight = (double)height * dc->xformVport2World.eM22;
65 66 67 68
    /* Round to integers */
    return GDI_ROUND(floatHeight);
}

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
static inline INT INTERNAL_XWSTODS(DC *dc, INT width)
{
    POINT pt[2];
    pt[0].x = pt[0].y = 0;
    pt[1].x = width;
    pt[1].y = 0;
    LPtoDP(dc->hSelf, pt, 2);
    return pt[1].x - pt[0].x;
}

static inline INT INTERNAL_YWSTODS(DC *dc, INT height)
{
    POINT pt[2];
    pt[0].x = pt[0].y = 0;
    pt[1].x = 0;
    pt[1].y = height;
    LPtoDP(dc->hSelf, pt, 2);
    return pt[1].y - pt[0].y;
}
88

89
static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
90 91 92 93 94 95 96 97 98 99 100 101 102
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_GetObjectA,    /* pGetObjectA */
    FONT_GetObjectW,    /* pGetObjectW */
    NULL,               /* pUnrealizeObject */
    FONT_DeleteObject   /* pDeleteObject */
};

Alexandre Julliard's avatar
Alexandre Julliard committed
103
#define ENUM_UNICODE	0x00000001
Huw D M Davies's avatar
Huw D M Davies committed
104
#define ENUM_CALLED     0x00000002
Alexandre Julliard's avatar
Alexandre Julliard committed
105

106 107 108 109 110 111
typedef struct
{
    GDIOBJHDR   header;
    LOGFONTW    logfont;
} FONTOBJ;

Alexandre Julliard's avatar
Alexandre Julliard committed
112 113
typedef struct
{
114
  LPLOGFONTW          lpLogFontParam;
115
  FONTENUMPROCW       lpEnumFunc;
116
  LPARAM              lpData;
Huw D M Davies's avatar
Huw D M Davies committed
117
  DWORD               dwFlags;
118
  HDC                 hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
119
} fontEnum32;
120

121 122 123 124
/*
 *  For TranslateCharsetInfo
 */
#define MAXTCIINDEX 32
125
static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
126
  /* ANSI */
127 128 129 130 131 132 133 134 135
  { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
  { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
  { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
  { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
  { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
  { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
  { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
  { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
  { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
136
  /* reserved by ANSI */
137 138 139 140 141 142 143
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
144
  /* ANSI and OEM */
145 146 147 148 149 150
  { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
  { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
  { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
  { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
  { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
  { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
151
  /* reserved for alternate ANSI and OEM */
152 153 154 155 156 157 158 159
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160
  /* reserved for system */
161 162
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
163 164
};

165
static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
166
{
167 168 169
    memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
    MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
			LF_FACESIZE);
170
    fontW->lfFaceName[LF_FACESIZE-1] = 0;
171 172
}

173
static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
174 175 176 177
{
    memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
    WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
			LF_FACESIZE, NULL, NULL);
178
    fontA->lfFaceName[LF_FACESIZE-1] = 0;
179 180
}

181
static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
182
{
183
    FONT_LogFontWToA( (const LOGFONTW *)fontW, (LPLOGFONTA)fontA);
184 185

    WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
186
			 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
187 188
    fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
    WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
189
			 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
190 191
    fontA->elfStyle[LF_FACESIZE-1] = '\0';
    WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
192
			 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
193 194 195
    fontA->elfScript[LF_FACESIZE-1] = '\0';
}

Alexandre Julliard's avatar
Alexandre Julliard committed
196
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
197 198
 *              TEXTMETRIC conversion functions.
 */
199
static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
200 201 202 203 204 205 206 207 208 209 210 211
{
    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;
212 213 214 215 216 217 218 219 220 221 222
    ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
    if (ptmW->tmCharSet == SYMBOL_CHARSET)
    {
        UINT last_char = ptmW->tmLastChar;
        if (last_char > 0xf000) last_char -= 0xf000;
        ptmA->tmLastChar = min(last_char, 255);
    }
    else
        ptmA->tmLastChar = min(ptmW->tmLastChar, 255);
    ptmA->tmDefaultChar = min(ptmW->tmDefaultChar, 255);
    ptmA->tmBreakChar = min(ptmW->tmBreakChar, 255);
223 224 225 226 227 228 229 230
    ptmA->tmItalic = ptmW->tmItalic;
    ptmA->tmUnderlined = ptmW->tmUnderlined;
    ptmA->tmStruckOut = ptmW->tmStruckOut;
    ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
    ptmA->tmCharSet = ptmW->tmCharSet;
}


231
static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
232
{
233
    FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
234 235 236 237 238
    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));
239 240
}

241 242

/***********************************************************************
243
 *           GdiGetCodePage   (GDI32.@)
244
 */
245
DWORD WINAPI GdiGetCodePage( HDC hdc )
246 247
{
    UINT cp = CP_ACP;
248 249 250 251
    CHARSETINFO csi;
    int charset = GetTextCharset(hdc);

    /* Hmm, nicely designed api this one! */
252
    if(TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET))
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
        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);
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
    return cp;
}

/***********************************************************************
 *           FONT_mbtowc
 *
 * Returns a 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 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;
    INT lenW;
    LPWSTR strW;

    cp = GdiGetCodePage( hdc );
309 310 311

    if(count == -1) count = strlen(str);
    lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
312
    strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
313 314 315
    MultiByteToWideChar(cp, 0, str, count, strW, lenW);
    TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
    if(plenW) *plenW = lenW;
316
    if(pCP) *pCP = cp;
317 318 319 320
    return strW;
}


321 322 323 324 325 326 327
/***********************************************************************
 *           CreateFontIndirectA   (GDI32.@)
 */
HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
{
    LOGFONTW lfW;

328
    if (!plfA) return 0;
329

330 331
    FONT_LogFontAToW( plfA, &lfW );
    return CreateFontIndirectW( &lfW );
332 333 334 335 336 337
}

/***********************************************************************
 *           CreateFontIndirectW   (GDI32.@)
 */
HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
Alexandre Julliard's avatar
Alexandre Julliard committed
338
{
339 340 341 342 343 344 345 346 347 348 349 350
    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;
    HFONT hFont;
    FONTOBJ *fontPtr;

    if (!plf) return 0;

    if (!(fontPtr = GDI_AllocObject( sizeof(FONTOBJ), FONT_MAGIC, (HGDIOBJ *)&hFont,
                                     &font_funcs ))) return 0;

351
    fontPtr->logfont = *plf;
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378

    TRACE("(%d %d %d %d %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;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
379

380 381
    pFaceNameBoldSuffix = strstrW(fontPtr->logfont.lfFaceName, BoldW);
    if (pFaceNameBoldSuffix)
Alexandre Julliard's avatar
Alexandre Julliard committed
382
    {
383 384 385 386
        if (fontPtr->logfont.lfWeight < FW_BOLD)
            fontPtr->logfont.lfWeight = FW_BOLD;
        if (!pFaceNameSuffix || (pFaceNameBoldSuffix < pFaceNameSuffix))
            pFaceNameSuffix = pFaceNameBoldSuffix;
Alexandre Julliard's avatar
Alexandre Julliard committed
387
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
388

389 390 391
    if (pFaceNameSuffix) *pFaceNameSuffix = 0;

    GDI_ReleaseObj( hFont );
Alexandre Julliard's avatar
Alexandre Julliard committed
392 393
    return hFont;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
394

Alexandre Julliard's avatar
Alexandre Julliard committed
395
/*************************************************************************
396
 *           CreateFontA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
397
 */
398 399
HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
                              INT orient, INT weight, DWORD italic,
Alexandre Julliard's avatar
Alexandre Julliard committed
400 401 402
                              DWORD underline, DWORD strikeout, DWORD charset,
                              DWORD outpres, DWORD clippres, DWORD quality,
                              DWORD pitch, LPCSTR name )
Alexandre Julliard's avatar
Alexandre Julliard committed
403
{
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
    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;
419 420

    if (name)
421
	lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
422
    else
423 424 425
	logfont.lfFaceName[0] = '\0';

    return CreateFontIndirectA( &logfont );
Alexandre Julliard's avatar
Alexandre Julliard committed
426 427 428
}

/*************************************************************************
429
 *           CreateFontW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
430
 */
431 432
HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
                              INT orient, INT weight, DWORD italic,
Alexandre Julliard's avatar
Alexandre Julliard committed
433 434 435
                              DWORD underline, DWORD strikeout, DWORD charset,
                              DWORD outpres, DWORD clippres, DWORD quality,
                              DWORD pitch, LPCWSTR name )
Alexandre Julliard's avatar
Alexandre Julliard committed
436
{
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
    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;
452 453 454

    if (name)
	lstrcpynW(logfont.lfFaceName, name,
455
		  sizeof(logfont.lfFaceName) / sizeof(WCHAR));
456
    else
457 458 459
	logfont.lfFaceName[0] = '\0';

    return CreateFontIndirectW( &logfont );
Alexandre Julliard's avatar
Alexandre Julliard committed
460 461 462
}


463 464 465 466 467 468 469 470 471 472 473
/***********************************************************************
 *           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.
 */
474
static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
475 476
{
    HGDIOBJ ret = 0;
477
    DC *dc = get_dc_ptr( hdc );
478 479 480

    if (!dc) return 0;

481 482 483 484 485 486
    if (!GDI_inc_ref_count( handle ))
    {
        release_dc_ptr( dc );
        return 0;
    }

487 488 489
    if (dc->hFont != handle || dc->gdiFont == NULL)
    {
        if(GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_VA_ABLE)
490 491
        {
            FONTOBJ *font = GDI_GetObjPtr( handle, FONT_MAGIC );  /* to grab the GDI lock (FIXME) */
492
            dc->gdiFont = WineEngCreateFontInstance(dc, handle);
493 494
            if (font) GDI_ReleaseObj( handle );
        }
495 496
    }

497
    if (dc->funcs->pSelectFont) ret = dc->funcs->pSelectFont( dc->physDev, handle, dc->gdiFont );
498 499 500

    if (ret && dc->gdiFont) dc->gdiFont = 0;

501
    if (ret == HGDI_ERROR)
502 503
    {
        GDI_dec_ref_count( handle );
504
        ret = 0; /* SelectObject returns 0 on error */
505
    }
506 507 508 509
    else
    {
        ret = dc->hFont;
        dc->hFont = handle;
510
        GDI_dec_ref_count( ret );
511
    }
512
    release_dc_ptr( dc );
513 514 515 516
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
517
/***********************************************************************
518
 *           FONT_GetObjectA
Alexandre Julliard's avatar
Alexandre Julliard committed
519
 */
520
static INT FONT_GetObjectA( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
521
{
522
    FONTOBJ *font = obj;
523
    LOGFONTA lfA;
Alexandre Julliard's avatar
Alexandre Julliard committed
524

525 526
    if(!buffer)
        return sizeof(lfA);
527
    FONT_LogFontWToA( &font->logfont, &lfA );
Alexandre Julliard's avatar
Alexandre Julliard committed
528

529
    if (count > sizeof(lfA)) count = sizeof(lfA);
530
    memcpy( buffer, &lfA, count );
Alexandre Julliard's avatar
Alexandre Julliard committed
531 532
    return count;
}
533

534
/***********************************************************************
535
 *           FONT_GetObjectW
536
 */
537
static INT FONT_GetObjectW( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
538
{
539
    FONTOBJ *font = obj;
540 541
    if(!buffer)
        return sizeof(LOGFONTW);
542
    if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
543
    memcpy( buffer, &font->logfont, count );
544 545
    return count;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
546 547


548 549 550 551 552 553 554 555 556 557
/***********************************************************************
 *           FONT_DeleteObject
 */
static BOOL FONT_DeleteObject( HGDIOBJ handle, void *obj )
{
    WineEngDestroyFontInstance( handle );
    return GDI_FreeObject( handle, obj );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
558
/***********************************************************************
559
 *              FONT_EnumInstance
560 561 562
 *
 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
 *       We have to use other types because of the FONTENUMPROCW definition.
Alexandre Julliard's avatar
Alexandre Julliard committed
563
 */
564 565
static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
                                       DWORD fType, LPARAM lp )
Alexandre Julliard's avatar
Alexandre Julliard committed
566
{
567 568
    fontEnum32 *pfe = (fontEnum32*)lp;
    INT ret = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
569

570
    /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
571 572
    if ((!pfe->lpLogFontParam ||
        pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
573 574
        pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
       (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
Alexandre Julliard's avatar
Alexandre Julliard committed
575 576
    {
	/* convert font metrics */
577 578
        ENUMLOGFONTEXA logfont;
        NEWTEXTMETRICEXA tmA;
Alexandre Julliard's avatar
Alexandre Julliard committed
579

Huw D M Davies's avatar
Huw D M Davies committed
580
        pfe->dwFlags |= ENUM_CALLED;
581 582
        if (!(pfe->dwFlags & ENUM_UNICODE))
        {
583 584 585 586
            FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
            FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
            plf = (LOGFONTW *)&logfont.elfLogFont;
            ptm = (TEXTMETRICW *)&tmA;
587 588
        }

589
        ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
Alexandre Julliard's avatar
Alexandre Julliard committed
590
    }
591
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
592 593 594
}

/***********************************************************************
595
 *		FONT_EnumFontFamiliesEx
Alexandre Julliard's avatar
Alexandre Julliard committed
596
 */
597
static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf,
598
				    FONTENUMPROCW efproc,
599
				    LPARAM lParam, DWORD dwUnicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
600
{
Huw D M Davies's avatar
Huw D M Davies committed
601
    INT ret = 1, ret2;
602
    DC *dc = get_dc_ptr( hDC );
603 604
    fontEnum32 fe32;
    BOOL enum_gdi_fonts;
605 606

    if (!dc) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
607

608 609 610
    if (plf)
        TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName),
	    plf->lfCharSet);
611 612 613 614
    fe32.lpLogFontParam = plf;
    fe32.lpEnumFunc = efproc;
    fe32.lpData = lParam;
    fe32.dwFlags = dwUnicode;
615
    fe32.hdc = hDC;
616

617
    enum_gdi_fonts = GetDeviceCaps(hDC, TEXTCAPS) & TC_VA_ABLE;
Alexandre Julliard's avatar
Alexandre Julliard committed
618

619 620 621 622 623 624
    if (!dc->funcs->pEnumDeviceFonts && !enum_gdi_fonts)
    {
        ret = 0;
        goto done;
    }

625 626
    if (enum_gdi_fonts)
        ret = WineEngEnumFonts( plf, FONT_EnumInstance, (LPARAM)&fe32 );
Huw D M Davies's avatar
Huw D M Davies committed
627
    fe32.dwFlags &= ~ENUM_CALLED;
628 629
    if (ret && dc->funcs->pEnumDeviceFonts) {
	ret2 = dc->funcs->pEnumDeviceFonts( dc->physDev, plf, FONT_EnumInstance, (LPARAM)&fe32 );
Huw D M Davies's avatar
Huw D M Davies committed
630 631 632
	if(fe32.dwFlags & ENUM_CALLED) /* update ret iff a font gets enumed */
	    ret = ret2;
    }
633
 done:
634
    release_dc_ptr( dc );
635
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
636 637 638
}

/***********************************************************************
639
 *              EnumFontFamiliesExW	(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
640
 */
641
INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
642
                                    FONTENUMPROCW efproc,
Alexandre Julliard's avatar
Alexandre Julliard committed
643
                                    LPARAM lParam, DWORD dwFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
644
{
645
    return  FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, ENUM_UNICODE );
Alexandre Julliard's avatar
Alexandre Julliard committed
646 647 648
}

/***********************************************************************
649
 *              EnumFontFamiliesExA	(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
650
 */
651
INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
652
                                    FONTENUMPROCA efproc,
Alexandre Julliard's avatar
Alexandre Julliard committed
653
                                    LPARAM lParam, DWORD dwFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
654
{
655 656 657 658 659 660 661 662
    LOGFONTW lfW, *plfW;

    if (plf)
    {
        FONT_LogFontAToW( plf, &lfW );
        plfW = &lfW;
    }
    else plfW = NULL;
663

664
    return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
665 666 667
}

/***********************************************************************
668
 *              EnumFontFamiliesA	(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
669
 */
670 671
INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
                                  FONTENUMPROCA efproc, LPARAM lpData )
Alexandre Julliard's avatar
Alexandre Julliard committed
672
{
673
    LOGFONTA lf, *plf;
Alexandre Julliard's avatar
Alexandre Julliard committed
674

675 676 677 678
    if (lpFamily)
    {
        if (!*lpFamily) return 1;
        lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
679 680 681
        lf.lfCharSet = DEFAULT_CHARSET;
        lf.lfPitchAndFamily = 0;
        plf = &lf;
682
    }
683
    else plf = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
684

685
    return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
686 687 688
}

/***********************************************************************
689
 *              EnumFontFamiliesW	(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
690
 */
691 692
INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
                                  FONTENUMPROCW efproc, LPARAM lpData )
Alexandre Julliard's avatar
Alexandre Julliard committed
693
{
694
    LOGFONTW lf, *plf;
Alexandre Julliard's avatar
Alexandre Julliard committed
695

696 697 698 699
    if (lpFamily)
    {
        if (!*lpFamily) return 1;
        lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
700 701 702
        lf.lfCharSet = DEFAULT_CHARSET;
        lf.lfPitchAndFamily = 0;
        plf = &lf;
703
    }
704
    else plf = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
705

706
    return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
707 708 709
}

/***********************************************************************
710
 *              EnumFontsA		(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
711
 */
712
INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
Alexandre Julliard's avatar
Alexandre Julliard committed
713
                           LPARAM lpData )
Alexandre Julliard's avatar
Alexandre Julliard committed
714
{
715
    return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
Alexandre Julliard's avatar
Alexandre Julliard committed
716 717 718
}

/***********************************************************************
719
 *              EnumFontsW		(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
720
 */
721
INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
Alexandre Julliard's avatar
Alexandre Julliard committed
722
                           LPARAM lpData )
Alexandre Julliard's avatar
Alexandre Julliard committed
723
{
724
    return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
Alexandre Julliard's avatar
Alexandre Julliard committed
725
}
Alexandre Julliard's avatar
Alexandre Julliard committed
726 727 728


/***********************************************************************
729
 *           GetTextCharacterExtra    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
730
 */
731
INT WINAPI GetTextCharacterExtra( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
732
{
733
    INT ret;
734
    DC *dc = get_dc_ptr( hdc );
735 736
    if (!dc) return 0x80000000;
    ret = dc->charExtra;
737
    release_dc_ptr( dc );
738
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
739 740 741 742
}


/***********************************************************************
743
 *           SetTextCharacterExtra    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
744
 */
745
INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
Alexandre Julliard's avatar
Alexandre Julliard committed
746
{
747
    INT prev;
748
    DC * dc = get_dc_ptr( hdc );
749
    if (!dc) return 0x80000000;
750
    if (dc->funcs->pSetTextCharacterExtra)
751
        prev = dc->funcs->pSetTextCharacterExtra( dc->physDev, extra );
752 753
    else
    {
754 755
        prev = dc->charExtra;
        dc->charExtra = extra;
756
    }
757
    release_dc_ptr( dc );
758
    return prev;
Alexandre Julliard's avatar
Alexandre Julliard committed
759 760 761
}


Alexandre Julliard's avatar
Alexandre Julliard committed
762
/***********************************************************************
763
 *           SetTextJustification    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
764
 */
765
BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
Alexandre Julliard's avatar
Alexandre Julliard committed
766
{
767
    BOOL ret = TRUE;
768
    DC * dc = get_dc_ptr( hdc );
769
    if (!dc) return FALSE;
770
    if (dc->funcs->pSetTextJustification)
771
        ret = dc->funcs->pSetTextJustification( dc->physDev, extra, breaks );
Alexandre Julliard's avatar
Alexandre Julliard committed
772 773
    else
    {
774 775 776 777
        extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
        if (!extra) breaks = 0;
        if (breaks)
        {
778
            dc->breakExtra = extra / breaks;
779
            dc->breakRem   = extra - (breaks * dc->breakExtra);
780 781 782
        }
        else
        {
783 784
            dc->breakExtra = 0;
            dc->breakRem   = 0;
785
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
786
    }
787
    release_dc_ptr( dc );
788
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
789 790
}

Alexandre Julliard's avatar
Alexandre Julliard committed
791

Alexandre Julliard's avatar
Alexandre Julliard committed
792
/***********************************************************************
793
 *           GetTextFaceA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
794
 */
795
INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
796 797 798 799
{
    INT res = GetTextFaceW(hdc, 0, NULL);
    LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
    GetTextFaceW( hdc, res, nameW );
800

801
    if (name)
802
    {
803 804 805 806 807
        if (count)
        {
            res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
            if (res == 0)
                res = count;
808
            name[count-1] = 0;
809 810 811 812 813
            /* GetTextFaceA does NOT include the nul byte in the return count.  */
            res--;
        }
        else
            res = 0;
814
    }
815 816 817 818 819 820 821 822 823 824
    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 )
Alexandre Julliard's avatar
Alexandre Julliard committed
825 826
{
    FONTOBJ *font;
827
    INT     ret = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
828

829
    DC * dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
830
    if (!dc) return 0;
831

832 833 834
    if(dc->gdiFont)
        ret = WineEngGetTextFace(dc->gdiFont, count, name);
    else if ((font = (FONTOBJ *) GDI_GetObjPtr( dc->hFont, FONT_MAGIC )))
835
    {
836
        INT n = strlenW(font->logfont.lfFaceName) + 1;
837 838
        if (name)
        {
839
            lstrcpynW( name, font->logfont.lfFaceName, count );
840
            ret = min(count, n);
841
        }
842
        else ret = n;
843
        GDI_ReleaseObj( dc->hFont );
844
    }
845
    release_dc_ptr( dc );
846
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
847 848 849
}


Alexandre Julliard's avatar
Alexandre Julliard committed
850
/***********************************************************************
851
 *           GetTextExtentPoint32A    (GDI32.@)
852 853
 *
 * See GetTextExtentPoint32W.
Alexandre Julliard's avatar
Alexandre Julliard committed
854
 */
855 856
BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
                                     LPSIZE size )
Alexandre Julliard's avatar
Alexandre Julliard committed
857
{
858
    BOOL ret = FALSE;
859
    INT wlen;
860
    LPWSTR p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
Hidenori Takeshima's avatar
Hidenori Takeshima committed
861

862 863 864
    if (p) {
	ret = GetTextExtentPoint32W( hdc, p, wlen, size );
	HeapFree( GetProcessHeap(), 0, p );
865
    }
866

867
    TRACE("(%p %s %d %p): returning %d x %d\n",
868
          hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
869
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
870 871 872
}


Alexandre Julliard's avatar
Alexandre Julliard committed
873
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
874 875 876
 * GetTextExtentPoint32W [GDI32.@]
 *
 * Computes width/height for a string.
Alexandre Julliard's avatar
Alexandre Julliard committed
877 878 879 880 881 882
 *
 * Computes width and height of the specified string.
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
883
 */
884 885
BOOL WINAPI GetTextExtentPoint32W(
    HDC hdc,     /* [in]  Handle of device context */
Alexandre Julliard's avatar
Alexandre Julliard committed
886
    LPCWSTR str,   /* [in]  Address of text string */
887 888
    INT count,   /* [in]  Number of characters in string */
    LPSIZE size) /* [out] Address of structure for string size */
Alexandre Julliard's avatar
Alexandre Julliard committed
889
{
890
    return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
Alexandre Julliard's avatar
Alexandre Julliard committed
891 892
}

893
/***********************************************************************
894
 * GetTextExtentExPointI [GDI32.@]
895 896 897
 *
 * Computes width and height of the array of glyph indices.
 *
898 899 900 901 902 903 904 905 906
 * PARAMS
 *    hdc     [I] Handle of device context.
 *    indices [I] Glyph index array.
 *    count   [I] Number of glyphs in array.
 *    max_ext [I] Maximum width in glyphs.
 *    nfit    [O] Maximum number of characters.
 *    dxs     [O] Partial string widths.
 *    size    [O] Returned string size.
 *
907 908 909 910
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
911 912
BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
                                   LPINT nfit, LPINT dxs, LPSIZE size )
913 914
{
    BOOL ret = FALSE;
915
    DC * dc = get_dc_ptr( hdc );
916 917 918
    if (!dc) return FALSE;

    if(dc->gdiFont) {
919 920 921
        ret = WineEngGetTextExtentExPointI(dc->gdiFont, indices, count, max_ext, nfit, dxs, size);
        size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
        size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
922
        size->cx += count * dc->charExtra;
923
    }
924 925 926
    else if(dc->funcs->pGetTextExtentExPoint) {
        FIXME("calling GetTextExtentExPoint\n");
        ret = dc->funcs->pGetTextExtentExPoint( dc->physDev, (LPCWSTR)indices,
927
                                                count, max_ext, nfit, dxs, size );
928 929
    }

930
    release_dc_ptr( dc );
931

932
    TRACE("(%p %p %d %p): returning %d x %d\n",
933 934 935 936
          hdc, indices, count, size, size->cx, size->cy );
    return ret;
}

937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
/***********************************************************************
 * GetTextExtentPointI [GDI32.@]
 *
 * Computes width and height of the array of glyph indices.
 *
 * PARAMS
 *    hdc     [I] Handle of device context.
 *    indices [I] Glyph index array.
 *    count   [I] Number of glyphs in array.
 *    size    [O] Returned string size.
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, LPSIZE size )
{
    return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
}

Alexandre Julliard's avatar
Alexandre Julliard committed
957

Alexandre Julliard's avatar
Alexandre Julliard committed
958
/***********************************************************************
959
 *           GetTextExtentPointA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
960
 */
961 962
BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
                                          LPSIZE size )
Alexandre Julliard's avatar
Alexandre Julliard committed
963
{
964
    TRACE("not bug compatible.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
965 966 967 968
    return GetTextExtentPoint32A( hdc, str, count, size );
}

/***********************************************************************
969
 *           GetTextExtentPointW   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
970
 */
971 972
BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
                                          LPSIZE size )
Alexandre Julliard's avatar
Alexandre Julliard committed
973
{
974
    TRACE("not bug compatible.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
975 976 977
    return GetTextExtentPoint32W( hdc, str, count, size );
}

Alexandre Julliard's avatar
Alexandre Julliard committed
978

Alexandre Julliard's avatar
Alexandre Julliard committed
979
/***********************************************************************
980
 *           GetTextExtentExPointA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
981
 */
982
BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
983 984 985 986
				   INT maxExt, LPINT lpnFit,
				   LPINT alpDx, LPSIZE size )
{
    BOOL ret;
987
    INT wlen;
988 989 990 991 992 993 994
    INT *walpDx = NULL;
    LPWSTR p = NULL;
    
    if (alpDx &&
       NULL == (walpDx = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT))))
       return FALSE;
    
995
    p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
996 997 998 999 1000 1001 1002 1003 1004 1005 1006
    ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size);
    if (walpDx)
    {
        INT n = lpnFit ? *lpnFit : wlen;
        INT i, j;
        for(i = 0, j = 0; i < n; i++, j++)
        {
            alpDx[j] = walpDx[i];
            if (IsDBCSLeadByte(str[j])) alpDx[++j] = walpDx[i];
        }
    }
1007
    if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1008
    HeapFree( GetProcessHeap(), 0, p );
1009
    HeapFree( GetProcessHeap(), 0, walpDx );
1010 1011 1012 1013 1014
    return ret;
}


/***********************************************************************
1015
 *           GetTextExtentExPointW    (GDI32.@)
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
 *
 * 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
1026
 * be done by the driver.  However they don't support it yet.  Also I am not
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
 * 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.
1043 1044 1045 1046 1047
 */

BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
				   INT maxExt, LPINT lpnFit,
				   LPINT alpDx, LPSIZE size )
Alexandre Julliard's avatar
Alexandre Julliard committed
1048
{
1049 1050 1051
    INT nFit = 0;
    LPINT dxs = NULL;
    DC *dc;
1052
    BOOL ret = FALSE;
1053
    TEXTMETRICW tm;
Alexandre Julliard's avatar
Alexandre Julliard committed
1054

1055
    TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
1056

1057
    dc = get_dc_ptr(hdc);
1058 1059 1060
    if (! dc)
        return FALSE;

1061 1062
    GetTextMetricsW(hdc, &tm);

1063 1064 1065
    /* If we need to calculate nFit, then we need the partial extents even if
       the user hasn't provided us with an array.  */
    if (lpnFit)
Alexandre Julliard's avatar
Alexandre Julliard committed
1066
    {
1067 1068 1069
	dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
	if (! dxs)
	{
1070
	    release_dc_ptr(dc);
1071 1072 1073
	    SetLastError(ERROR_OUTOFMEMORY);
	    return FALSE;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1074
    }
1075 1076
    else
	dxs = alpDx;
Alexandre Julliard's avatar
Alexandre Julliard committed
1077

1078 1079 1080 1081 1082 1083
    if (dc->gdiFont)
	ret = WineEngGetTextExtentExPoint(dc->gdiFont, str, count,
					  0, NULL, dxs, size);
    else if (dc->funcs->pGetTextExtentExPoint)
	ret = dc->funcs->pGetTextExtentExPoint(dc->physDev, str, count,
					       0, NULL, dxs, size);
Gerald Pfeifer's avatar
Gerald Pfeifer committed
1084

1085 1086 1087
    /* Perform device size to world size transformations.  */
    if (ret)
    {
1088 1089 1090 1091
	INT extra      = dc->charExtra,
        breakExtra = dc->breakExtra,
        breakRem   = dc->breakRem,
        i;
1092 1093 1094 1095 1096 1097

	if (dxs)
	{
	    for (i = 0; i < count; ++i)
	    {
		dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
		dxs[i] += (i+1) * extra;
                if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
                {
                    dxs[i] += breakExtra;
                    if (breakRem > 0)
                    {
                        breakRem--;
                        dxs[i]++;
                    }
                }
1108 1109 1110
		if (dxs[i] <= maxExt)
		    ++nFit;
	    }
1111
            breakRem = dc->breakRem;
1112 1113 1114
	}
	size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
	size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130

        if (!dxs && count > 1 && (breakExtra || breakRem))
        {
            for (i = 0; i < count; i++)
            {
                if (str[i] == tm.tmBreakChar)
                {
                    size->cx += breakExtra;
                    if (breakRem > 0)
                    {
                        breakRem--;
                        (size->cx)++;
                    }
                }
            }
        }
1131 1132 1133 1134 1135
    }

    if (lpnFit)
	*lpnFit = nFit;

1136
    if (! alpDx)
1137 1138
        HeapFree(GetProcessHeap(), 0, dxs);

1139
    release_dc_ptr( dc );
1140

1141
    TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1142
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1143 1144
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1145
/***********************************************************************
1146
 *           GetTextMetricsA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1147
 */
1148
BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
{
    TEXTMETRICW tm32;

    if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
    FONT_TextMetricWToA( &tm32, metrics );
    return TRUE;
}

/***********************************************************************
 *           GetTextMetricsW    (GDI32.@)
 */
BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
{
1162
    BOOL ret = FALSE;
1163
    DC * dc = get_dc_ptr( hdc );
1164
    if (!dc) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1165

1166 1167 1168
    if (dc->gdiFont)
        ret = WineEngGetTextMetrics(dc->gdiFont, metrics);
    else if (dc->funcs->pGetTextMetrics)
1169
        ret = dc->funcs->pGetTextMetrics( dc->physDev, metrics );
1170 1171

    if (ret)
1172
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1173 1174 1175
    /* device layer returns values in device units
     * therefore we have to convert them to logical */

1176 1177 1178
        metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
        metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);

Alexandre Julliard's avatar
Alexandre Julliard committed
1179
#define WDPTOLP(x) ((x<0)?					\
1180 1181
		(-abs(INTERNAL_XDSTOWS(dc, (x)))):		\
		(abs(INTERNAL_XDSTOWS(dc, (x)))))
Alexandre Julliard's avatar
Alexandre Julliard committed
1182
#define HDPTOLP(y) ((y<0)?					\
1183 1184
		(-abs(INTERNAL_YDSTOWS(dc, (y)))):		\
		(abs(INTERNAL_YDSTOWS(dc, (y)))))
1185

Alexandre Julliard's avatar
Alexandre Julliard committed
1186 1187 1188 1189 1190 1191 1192 1193
    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);
1194
        ret = TRUE;
1195 1196
#undef WDPTOLP
#undef HDPTOLP
1197
    TRACE("text metrics:\n"
1198 1199 1200
          "    Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
          "    Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
          "    UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1201
          "    StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1202 1203
          "    PitchAndFamily = %02x\n"
          "    --------------------\n"
1204 1205 1206 1207
          "    InternalLeading = %i\n"
          "    Ascent = %i\n"
          "    Descent = %i\n"
          "    Height = %i\n",
1208 1209 1210 1211 1212 1213 1214 1215 1216
          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 );
1217
    }
1218
    release_dc_ptr( dc );
1219
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1220 1221 1222
}


1223
/***********************************************************************
1224 1225
 *		GetOutlineTextMetricsA (GDI32.@)
 * Gets metrics for TrueType fonts.
1226
 *
1227 1228 1229
 * NOTES
 *    If the supplied buffer isn't big enough Windows partially fills it up to
 *    its given length and returns that length.
1230 1231 1232 1233 1234
 *
 * RETURNS
 *    Success: Non-zero or size of required buffer
 *    Failure: 0
 */
1235 1236 1237 1238
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 */
1239
{
1240 1241 1242
    char buf[512], *ptr;
    UINT ret, needed;
    OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1243
    OUTLINETEXTMETRICA *output = lpOTM;
1244
    INT left, len;
1245

1246 1247 1248
    if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
        return 0;
    if(ret > sizeof(buf))
1249
	lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1250
    GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1251

1252 1253 1254
    needed = sizeof(OUTLINETEXTMETRICA);
    if(lpOTMW->otmpFamilyName)
        needed += WideCharToMultiByte(CP_ACP, 0,
1255
	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1256 1257 1258
				      NULL, 0, NULL, NULL);
    if(lpOTMW->otmpFaceName)
        needed += WideCharToMultiByte(CP_ACP, 0,
1259
	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1260 1261 1262
				      NULL, 0, NULL, NULL);
    if(lpOTMW->otmpStyleName)
        needed += WideCharToMultiByte(CP_ACP, 0,
1263
	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1264 1265 1266
				      NULL, 0, NULL, NULL);
    if(lpOTMW->otmpFullName)
        needed += WideCharToMultiByte(CP_ACP, 0,
1267
	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1268 1269 1270 1271 1272 1273
				      NULL, 0, NULL, NULL);

    if(!lpOTM) {
        ret = needed;
	goto end;
    }
1274

1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313
    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);
1314 1315

    if(lpOTMW->otmpFamilyName) {
1316
        output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1317
	len = WideCharToMultiByte(CP_ACP, 0,
1318
	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1319 1320 1321
				  ptr, left, NULL, NULL);
	left -= len;
	ptr += len;
1322
    } else
1323
        output->otmpFamilyName = 0;
1324 1325

    if(lpOTMW->otmpFaceName) {
1326
        output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1327
	len = WideCharToMultiByte(CP_ACP, 0,
1328
	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1329 1330 1331
				  ptr, left, NULL, NULL);
	left -= len;
	ptr += len;
1332
    } else
1333
        output->otmpFaceName = 0;
1334 1335

    if(lpOTMW->otmpStyleName) {
1336
        output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1337
	len = WideCharToMultiByte(CP_ACP, 0,
1338
	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1339 1340 1341 1342
				  ptr, left, NULL, NULL);
	left -= len;
	ptr += len;
    } else
1343
        output->otmpStyleName = 0;
1344 1345

    if(lpOTMW->otmpFullName) {
1346
        output->otmpFullName = (LPSTR)(ptr - (char*)output);
1347
	len = WideCharToMultiByte(CP_ACP, 0,
1348
	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1349 1350 1351
				  ptr, left, NULL, NULL);
	left -= len;
    } else
1352
        output->otmpFullName = 0;
1353

1354
    assert(left == 0);
1355

1356 1357 1358
    if(output != lpOTM) {
        memcpy(lpOTM, output, cbData);
        HeapFree(GetProcessHeap(), 0, output);
1359 1360 1361

        /* check if the string offsets really fit into the provided size */
        /* FIXME: should we check string length as well? */
1362 1363 1364 1365 1366 1367
        /* make sure that we don't read/write beyond the provided buffer */
        if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
        {
            if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
                lpOTM->otmpFamilyName = 0; /* doesn't fit */
        }
1368

1369 1370 1371 1372 1373 1374
        /* make sure that we don't read/write beyond the provided buffer */
        if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
        {
            if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
                lpOTM->otmpFaceName = 0; /* doesn't fit */
        }
1375

1376 1377 1378 1379 1380 1381
            /* make sure that we don't read/write beyond the provided buffer */
        if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
        {
            if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
                lpOTM->otmpStyleName = 0; /* doesn't fit */
        }
1382

1383 1384 1385 1386 1387 1388
        /* make sure that we don't read/write beyond the provided buffer */
        if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
        {
            if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
                lpOTM->otmpFullName = 0; /* doesn't fit */
        }
1389
    }
1390 1391 1392 1393 1394 1395

end:
    if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
        HeapFree(GetProcessHeap(), 0, lpOTMW);

    return ret;
1396 1397
}

1398

1399
/***********************************************************************
1400
 *           GetOutlineTextMetricsW [GDI32.@]
1401
 */
1402 1403 1404 1405
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 */
1406
{
1407
    DC *dc = get_dc_ptr( hdc );
1408
    OUTLINETEXTMETRICW *output = lpOTM;
1409 1410
    UINT ret;

1411
    TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1412 1413
    if(!dc) return 0;

1414
    if(dc->gdiFont) {
1415 1416 1417 1418 1419 1420 1421
        ret = WineEngGetOutlineTextMetrics(dc->gdiFont, cbData, output);
        if(lpOTM && ret) {
            if(ret > cbData) {
                output = HeapAlloc(GetProcessHeap(), 0, ret);
                WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output);
            }

1422 1423 1424
        output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
        output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);

1425 1426 1427 1428 1429 1430 1431
#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)))))

1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
	    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);
1442 1443 1444
	    output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
	    output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
	    output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
1445 1446 1447 1448 1449 1450
	    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);
1451
	    output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
1452 1453 1454 1455 1456 1457 1458 1459
	    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);
1460
	    output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
1461 1462 1463
	    output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
	    output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
	    output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1464 1465
#undef WDPTOLP
#undef HDPTOLP
1466 1467 1468 1469 1470
            if(output != lpOTM) {
                memcpy(lpOTM, output, cbData);
                HeapFree(GetProcessHeap(), 0, output);
                ret = cbData;
            }
1471 1472
	}
    }
1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491

    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
		*/
	    }
	}
    }
1492
    release_dc_ptr(dc);
1493
    return ret;
1494
}
1495

1496

Alexandre Julliard's avatar
Alexandre Julliard committed
1497
/***********************************************************************
1498 1499
 *           GetCharWidthW      (GDI32.@)
 *           GetCharWidth32W    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1500
 */
1501
BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1502
                               LPINT buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
1503
{
1504
    UINT i;
1505
    BOOL ret = FALSE;
1506
    DC * dc = get_dc_ptr( hdc );
1507
    if (!dc) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1508

1509 1510 1511
    if (dc->gdiFont)
        ret = WineEngGetCharWidth( dc->gdiFont, firstChar, lastChar, buffer );
    else if (dc->funcs->pGetCharWidth)
1512
        ret = dc->funcs->pGetCharWidth( dc->physDev, firstChar, lastChar, buffer);
1513 1514

    if (ret)
1515 1516 1517
    {
        /* convert device units to logical */
        for( i = firstChar; i <= lastChar; i++, buffer++ )
1518
            *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1519 1520
        ret = TRUE;
    }
1521
    release_dc_ptr( dc );
1522
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1523
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1524

Alexandre Julliard's avatar
Alexandre Julliard committed
1525

Alexandre Julliard's avatar
Alexandre Julliard committed
1526
/***********************************************************************
1527 1528
 *           GetCharWidthA      (GDI32.@)
 *           GetCharWidth32A    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1529
 */
1530
BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1531
                               LPINT buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
1532
{
1533 1534 1535 1536 1537 1538
    INT i, wlen, count = (INT)(lastChar - firstChar + 1);
    LPSTR str;
    LPWSTR wstr;
    BOOL ret = TRUE;

    if(count <= 0) return FALSE;
1539

1540 1541 1542 1543
    str = HeapAlloc(GetProcessHeap(), 0, count);
    for(i = 0; i < count; i++)
	str[i] = (BYTE)(firstChar + i);

1544
    wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559

    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;
Alexandre Julliard's avatar
Alexandre Julliard committed
1560 1561 1562
}


1563 1564
/***********************************************************************
 *           ExtTextOutA    (GDI32.@)
1565 1566
 *
 * See ExtTextOutW.
1567 1568 1569 1570 1571
 */
BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
                         const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
{
    INT wlen;
1572
    UINT codepage;
1573
    LPWSTR p;
1574 1575 1576
    BOOL ret;
    LPINT lpDxW = NULL;

1577 1578 1579
    if (flags & ETO_GLYPH_INDEX)
        return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );

1580
    p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
1581

1582 1583 1584
    if (lpDx) {
        unsigned int i = 0, j = 0;

1585
        lpDxW = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT));
1586
        while(i < count) {
1587
            if(IsDBCSLeadByteEx(codepage, str[i])) {
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
                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 );
1600
    HeapFree( GetProcessHeap(), 0, lpDxW );
1601 1602 1603 1604 1605 1606
    return ret;
}


/***********************************************************************
 *           ExtTextOutW    (GDI32.@)
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633
 *
 * 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
1634 1635 1636 1637 1638
 */
BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
                         const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
{
    BOOL ret = FALSE;
1639
    LPWSTR reordered_str = (LPWSTR)str;
1640
    WORD *glyphs = NULL;
1641 1642 1643 1644 1645 1646 1647 1648 1649
    UINT align = GetTextAlign( hdc );
    POINT pt;
    TEXTMETRICW tm;
    LOGFONTW lf;
    double cosEsc, sinEsc;
    INT *deltas = NULL, char_extra;
    SIZE sz;
    RECT rc;
    BOOL done_extents = FALSE;
1650
    INT width = 0, xwidth = 0, ywidth = 0;
1651
    DWORD type;
1652
    DC * dc = get_dc_ptr( hdc );
1653
    INT breakRem;
1654 1655 1656

    if (!dc) return FALSE;

1657 1658
    breakRem = dc->breakRem;

1659 1660 1661
    if (flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY))
        FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n");

1662
    if (!dc->funcs->pExtTextOut && !PATH_IsPathOpen(dc->path))
1663
    {
1664
        release_dc_ptr( dc );
1665 1666 1667
        return ret;
    }

1668
    update_dc( dc );
1669 1670 1671 1672
    type = GetObjectType(hdc);
    if(type == OBJ_METADC || type == OBJ_ENHMETADC)
    {
        ret = dc->funcs->pExtTextOut(dc->physDev, x, y, flags, lprect, str, count, lpDx);
1673
        release_dc_ptr( dc );
1674 1675
        return ret;
    }
1676 1677 1678

    if (!lprect)
        flags &= ~ETO_CLIPPED;
1679
        
1680
    if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695
    {
        reordered_str = 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,
                      reordered_str, count, NULL );
    
        flags |= ETO_IGNORELANGUAGE;
    }

    TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
          lprect, debugstr_wn(str, count), count, lpDx);

    if(flags & ETO_GLYPH_INDEX)
1696
        glyphs = reordered_str;
1697 1698

    if(lprect)
1699
        TRACE("rect: %d,%d - %d,%d\n", lprect->left, lprect->top, lprect->right,
1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752
              lprect->bottom);
    TRACE("align = %x bkmode = %x mapmode = %x\n", align, GetBkMode(hdc), GetMapMode(hdc));

    if(align & TA_UPDATECP)
    {
        GetCurrentPositionEx( hdc, &pt );
        x = pt.x;
        y = pt.y;
    }

    GetTextMetricsW(hdc, &tm);
    GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);

    if(!(tm.tmPitchAndFamily & TMPF_VECTOR)) /* Non-scalable fonts shouldn't be rotated */
        lf.lfEscapement = 0;

    if(lf.lfEscapement != 0)
    {
        cosEsc = cos(lf.lfEscapement * M_PI / 1800);
        sinEsc = sin(lf.lfEscapement * M_PI / 1800);
    }
    else
    {
        cosEsc = 1;
        sinEsc = 0;
    }

    if(flags & (ETO_CLIPPED | ETO_OPAQUE))
    {
        if(!lprect)
        {
            if(flags & ETO_GLYPH_INDEX)
                GetTextExtentPointI(hdc, glyphs, count, &sz);
            else
                GetTextExtentPointW(hdc, reordered_str, count, &sz);

            done_extents = TRUE;
            rc.left = x;
            rc.top = y;
            rc.right = x + sz.cx;
            rc.bottom = y + sz.cy;
        }
        else
        {
            rc = *lprect;
        }

        LPtoDP(hdc, (POINT*)&rc, 2);

        if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
        if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
    }

1753
    if ((flags & ETO_OPAQUE) && !PATH_IsPathOpen(dc->path))
1754
        dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1755

1756
    if(count == 0)
1757 1758
    {
        ret = TRUE;
1759
        goto done;
1760
    }
1761 1762 1763 1764 1765 1766 1767 1768

    pt.x = x;
    pt.y = y;
    LPtoDP(hdc, &pt, 1);
    x = pt.x;
    y = pt.y;

    char_extra = GetTextCharacterExtra(hdc);
1769
    if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
1770 1771 1772 1773 1774
    {
        UINT i;
        SIZE tmpsz;
        deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
        for(i = 0; i < count; i++)
1775
        {
1776 1777 1778
            if(lpDx && (flags & ETO_PDY))
                deltas[i] = lpDx[i*2] + char_extra;
            else if(lpDx)
1779 1780
                deltas[i] = lpDx[i] + char_extra;
            else
1781
            {
1782 1783 1784 1785
                if(flags & ETO_GLYPH_INDEX)
                    GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
                else
                    GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
1786

1787 1788 1789
                deltas[i] = tmpsz.cx;
            }
            
1790
            if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
1791 1792
            {
                deltas[i] = deltas[i] + dc->breakExtra;
1793 1794 1795 1796 1797
                if (breakRem > 0)
                {
                    breakRem--;
                    deltas[i]++;
                }
1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835
            }
            deltas[i] = INTERNAL_XWSTODS(dc, deltas[i]);
            width += deltas[i];
        }
    }
    else
    {
        if(!done_extents)
        {
            if(flags & ETO_GLYPH_INDEX)
                GetTextExtentPointI(hdc, glyphs, count, &sz);
            else
                GetTextExtentPointW(hdc, reordered_str, count, &sz);
            done_extents = TRUE;
        }
        width = INTERNAL_XWSTODS(dc, sz.cx);
    }
    xwidth = width * cosEsc;
    ywidth = width * sinEsc;

    tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent));
    tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent));
    switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) )
    {
    case TA_LEFT:
        if (align & TA_UPDATECP)
        {
            pt.x = x + xwidth;
            pt.y = y - ywidth;
            DPtoLP(hdc, &pt, 1);
            MoveToEx(hdc, pt.x, pt.y, NULL);
        }
        break;

    case TA_CENTER:
        x -= xwidth / 2;
        y += ywidth / 2;
        break;
1836

1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865
    case TA_RIGHT:
        x -= xwidth;
        y += ywidth;
        if (align & TA_UPDATECP)
        {
            pt.x = x;
            pt.y = y;
            DPtoLP(hdc, &pt, 1);
            MoveToEx(hdc, pt.x, pt.y, NULL);
        }
        break;
    }

    switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
    {
    case TA_TOP:
        y += tm.tmAscent * cosEsc;
        x += tm.tmAscent * sinEsc;
        break;

    case TA_BOTTOM:
        y -= tm.tmDescent * cosEsc;
        x -= tm.tmDescent * sinEsc;
        break;

    case TA_BASELINE:
        break;
    }

1866
    if (GetBkMode(hdc) != TRANSPARENT && !PATH_IsPathOpen(dc->path))
1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
    {
        if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
        {
            if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
               y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
            {
                RECT rc;
                rc.left = x;
                rc.right = x + width;
                rc.top = y - tm.tmAscent;
                rc.bottom = y + tm.tmDescent;
                dc->funcs->pExtTextOut(dc->physDev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1879
            }
1880 1881
        }
    }
1882

1883 1884 1885 1886
    if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
    {
        HFONT orig_font = dc->hFont, cur_font;
        UINT glyph;
1887 1888
        INT span = 0, *offsets = NULL;
        unsigned int i;
1889

1890
        glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
1891 1892 1893 1894 1895 1896 1897
        for(i = 0; i < count; i++)
        {
            WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
            if(cur_font != dc->hFont)
            {
                if(!offsets)
                {
1898
                    unsigned int j;
1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917
                    offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
                    offsets[0] = 0;
                    if(!deltas)
                    {
                        SIZE tmpsz;
                        for(j = 1; j < count; j++)
                        {
                            GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
                            offsets[j] = offsets[j-1] + INTERNAL_XWSTODS(dc, tmpsz.cx);
                        }
                    }
                    else
                    {
                        for(j = 1; j < count; j++)
                            offsets[j] = offsets[j-1] + deltas[j];
                    }
                }
                if(span)
                {
1918 1919 1920 1921 1922 1923
                    if (PATH_IsPathOpen(dc->path))
                        ret = PATH_ExtTextOut(dc, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
                                              (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
                                              glyphs, span, deltas ? deltas + i - span : NULL);
                    else
                        dc->funcs->pExtTextOut(dc->physDev, x + offsets[i - span] * cosEsc, y - offsets[i - span] * sinEsc,
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933
                                           (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
                                           glyphs, span, deltas ? deltas + i - span : NULL);
                    span = 0;
                }
                SelectObject(hdc, cur_font);
            }
            glyphs[span++] = glyph;

            if(i == count - 1)
            {
1934 1935 1936 1937 1938 1939 1940
                if (PATH_IsPathOpen(dc->path))
                    ret = PATH_ExtTextOut(dc, x + (offsets ? offsets[count - span] * cosEsc : 0),
                                          y - (offsets ? offsets[count - span] * sinEsc : 0),
                                          (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
                                          glyphs, span, deltas ? deltas + count - span : NULL);
                else
                    ret = dc->funcs->pExtTextOut(dc->physDev, x + (offsets ? offsets[count - span] * cosEsc : 0),
1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956
                                             y - (offsets ? offsets[count - span] * sinEsc : 0),
                                             (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc,
                                             glyphs, span, deltas ? deltas + count - span : NULL);
                SelectObject(hdc, orig_font);
                HeapFree(GetProcessHeap(), 0, offsets);
           }
        }
    }
    else
    {
        if(!(flags & ETO_GLYPH_INDEX) && dc->gdiFont)
        {
            glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
            GetGlyphIndicesW(hdc, reordered_str, count, glyphs, 0);
            flags |= ETO_GLYPH_INDEX;
        }
1957 1958 1959 1960 1961 1962

        if (PATH_IsPathOpen(dc->path))
            ret = PATH_ExtTextOut(dc, x, y, (flags & ~ETO_OPAQUE), &rc,
                                  glyphs ? glyphs : reordered_str, count, deltas);
        else
            ret = dc->funcs->pExtTextOut(dc->physDev, x, y, (flags & ~ETO_OPAQUE), &rc,
1963
                                     glyphs ? glyphs : reordered_str, count, deltas);
1964
    }
1965

1966 1967 1968 1969 1970 1971 1972
done:
    HeapFree(GetProcessHeap(), 0, deltas);
    if(glyphs != reordered_str)
        HeapFree(GetProcessHeap(), 0, glyphs);
    if(reordered_str != str)
        HeapFree(GetProcessHeap(), 0, reordered_str);

1973
    release_dc_ptr( dc );
1974 1975

    if (ret && (lf.lfUnderline || lf.lfStrikeOut))
1976 1977 1978
    {
        int underlinePos, strikeoutPos;
        int underlineWidth, strikeoutWidth;
1979
        UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
1980 1981
        OUTLINETEXTMETRICW* otm = NULL;

1982
        if(!size)
1983 1984 1985 1986 1987 1988 1989 1990
        {
            underlinePos = 0;
            underlineWidth = tm.tmAscent / 20 + 1;
            strikeoutPos = tm.tmAscent / 2;
            strikeoutWidth = underlineWidth;
        }
        else
        {
1991 1992
            otm = HeapAlloc(GetProcessHeap(), 0, size);
            GetOutlineTextMetricsW(hdc, size, otm);
1993 1994 1995 1996
            underlinePos = otm->otmsUnderscorePosition;
            underlineWidth = otm->otmsUnderscoreSize;
            strikeoutPos = otm->otmsStrikeoutPosition;
            strikeoutWidth = otm->otmsStrikeoutSize;
1997
            HeapFree(GetProcessHeap(), 0, otm);
1998 1999
        }

2000
        if (PATH_IsPathOpen(dc->path))
2001
        {
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039
            POINT pts[5];
            HPEN hpen;
            HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));

            hbrush = SelectObject(hdc, hbrush);
            hpen = SelectObject(hdc, GetStockObject(NULL_PEN));

            if (lf.lfUnderline)
            {
                pts[0].x = x - underlinePos * sinEsc;
                pts[0].y = y - underlinePos * cosEsc;
                pts[1].x = x + xwidth - underlinePos * sinEsc;
                pts[1].y = y - ywidth - underlinePos * cosEsc;
                pts[2].x = pts[1].x + underlineWidth * sinEsc;
                pts[2].y = pts[1].y + underlineWidth * cosEsc;
                pts[3].x = pts[0].x + underlineWidth * sinEsc;
                pts[3].y = pts[0].y + underlineWidth * cosEsc;
                pts[4].x = pts[0].x;
                pts[4].y = pts[0].y;
                DPtoLP(hdc, pts, 5);
                Polygon(hdc, pts, 5);
            }

            if (lf.lfStrikeOut)
            {
                pts[0].x = x - strikeoutPos * sinEsc;
                pts[0].y = y - strikeoutPos * cosEsc;
                pts[1].x = x + xwidth - strikeoutPos * sinEsc;
                pts[1].y = y - ywidth - strikeoutPos * cosEsc;
                pts[2].x = pts[1].x + strikeoutWidth * sinEsc;
                pts[2].y = pts[1].y + strikeoutWidth * cosEsc;
                pts[3].x = pts[0].x + strikeoutWidth * sinEsc;
                pts[3].y = pts[0].y + strikeoutWidth * cosEsc;
                pts[4].x = pts[0].x;
                pts[4].y = pts[0].y;
                DPtoLP(hdc, pts, 5);
                Polygon(hdc, pts, 5);
            }
2040

2041 2042 2043 2044 2045
            SelectObject(hdc, hpen);
            hbrush = SelectObject(hdc, hbrush);
            DeleteObject(hbrush);
        }
        else
2046 2047
        {
            POINT pts[2], oldpt;
2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078
            HPEN hpen;

            if (lf.lfUnderline)
            {
                hpen = CreatePen(PS_SOLID, underlineWidth, GetTextColor(hdc));
                hpen = SelectObject(hdc, hpen);
                pts[0].x = x;
                pts[0].y = y;
                pts[1].x = x + xwidth;
                pts[1].y = y - ywidth;
                DPtoLP(hdc, pts, 2);
                MoveToEx(hdc, pts[0].x - underlinePos * sinEsc, pts[0].y - underlinePos * cosEsc, &oldpt);
                LineTo(hdc, pts[1].x - underlinePos * sinEsc, pts[1].y - underlinePos * cosEsc);
                MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
                DeleteObject(SelectObject(hdc, hpen));
            }

            if (lf.lfStrikeOut)
            {
                hpen = CreatePen(PS_SOLID, strikeoutWidth, GetTextColor(hdc));
                hpen = SelectObject(hdc, hpen);
                pts[0].x = x;
                pts[0].y = y;
                pts[1].x = x + xwidth;
                pts[1].y = y - ywidth;
                DPtoLP(hdc, pts, 2);
                MoveToEx(hdc, pts[0].x - strikeoutPos * sinEsc, pts[0].y - strikeoutPos * cosEsc, &oldpt);
                LineTo(hdc, pts[1].x - strikeoutPos * sinEsc, pts[1].y - strikeoutPos * cosEsc);
                MoveToEx(hdc, oldpt.x, oldpt.y, NULL);
                DeleteObject(SelectObject(hdc, hpen));
            }
2079 2080
        }
    }
2081

2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
    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.@)
 *
2107
 * See PolyTextOutW.
2108
 */
2109
BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122
{
    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
2123 2124 2125 2126
 *
 * RETURNS
 *  TRUE:  Success.
 *  FALSE: Failure.
2127
 */
2128
BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2129 2130 2131 2132 2133 2134 2135 2136
{
    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;
}


2137
/* FIXME: all following APIs ******************************************/
2138

Alexandre Julliard's avatar
Alexandre Julliard committed
2139

Alexandre Julliard's avatar
Alexandre Julliard committed
2140
/***********************************************************************
2141
 *           SetMapperFlags    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2142
 */
2143
DWORD WINAPI SetMapperFlags( HDC hDC, DWORD dwFlag )
Alexandre Julliard's avatar
Alexandre Julliard committed
2144
{
2145
    DC *dc = get_dc_ptr( hDC );
2146
    DWORD ret = 0;
2147 2148
    if(!dc) return 0;
    if(dc->funcs->pSetMapperFlags)
2149
    {
2150
        ret = dc->funcs->pSetMapperFlags( dc->physDev, dwFlag );
2151 2152
        /* FIXME: ret is just a success flag, we should return a proper value */
    }
2153
    else
2154
        FIXME("(%p, 0x%08x): stub - harmless\n", hDC, dwFlag);
2155
    release_dc_ptr( dc );
2156
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2157 2158
}

2159
/***********************************************************************
2160
 *          GetAspectRatioFilterEx  (GDI32.@)
2161
 */
2162
BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2163
{
2164
  FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2165 2166
  return FALSE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2167

Alexandre Julliard's avatar
Alexandre Julliard committed
2168 2169

/***********************************************************************
2170
 *           GetCharABCWidthsA   (GDI32.@)
2171 2172
 *
 * See GetCharABCWidthsW.
Alexandre Julliard's avatar
Alexandre Julliard committed
2173
 */
2174 2175
BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
                                  LPABC abc )
Alexandre Julliard's avatar
Alexandre Julliard committed
2176
{
2177 2178 2179 2180 2181 2182
    INT i, wlen, count = (INT)(lastChar - firstChar + 1);
    LPSTR str;
    LPWSTR wstr;
    BOOL ret = TRUE;

    if(count <= 0) return FALSE;
2183

2184 2185 2186 2187
    str = HeapAlloc(GetProcessHeap(), 0, count);
    for(i = 0; i < count; i++)
	str[i] = (BYTE)(firstChar + i);

2188
    wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL);
2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203

    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;
Alexandre Julliard's avatar
Alexandre Julliard committed
2204 2205 2206
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2207
/******************************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
2208 2209 2210
 * GetCharABCWidthsW [GDI32.@]
 *
 * Retrieves widths of characters in range.
Alexandre Julliard's avatar
Alexandre Julliard committed
2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223
 *
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
2224
 */
2225 2226
BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
                                   LPABC abc )
Alexandre Julliard's avatar
Alexandre Julliard committed
2227
{
2228
    DC *dc = get_dc_ptr(hdc);
2229
    unsigned int i;
2230
    BOOL ret = FALSE;
2231

2232 2233
    if (!dc) return FALSE;

2234 2235
    if (!abc)
    {
2236
        release_dc_ptr( dc );
2237 2238 2239
        return FALSE;
    }

2240 2241 2242 2243 2244 2245 2246 2247 2248 2249
    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);
2250 2251 2252 2253 2254 2255
            abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
            abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
	}
        ret = TRUE;
    }

2256
    release_dc_ptr( dc );
2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282
    return ret;
}


/******************************************************************************
 * GetCharABCWidthsI [GDI32.@]
 *
 * Retrieves widths of characters in range.
 *
 * PARAMS
 *    hdc       [I] Handle of device context
 *    firstChar [I] First glyphs in range to query
 *    count     [I] Last glyphs in range to query
 *    pgi       [i] Array of glyphs to query
 *    abc       [O] Address of character-width structure
 *
 * NOTES
 *    Only works with TrueType fonts
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
                               LPWORD pgi, LPABC abc)
{
2283
    DC *dc = get_dc_ptr(hdc);
2284 2285 2286 2287 2288
    unsigned int i;
    BOOL ret = FALSE;

    if (!dc) return FALSE;

2289 2290
    if (!abc)
    {
2291
        release_dc_ptr( dc );
2292 2293 2294
        return FALSE;
    }

2295 2296 2297 2298 2299 2300 2301 2302
    if(dc->gdiFont)
        ret = WineEngGetCharABCWidthsI( dc->gdiFont, firstChar, count, pgi, abc );
    else
        FIXME(": stub\n");

    if (ret)
    {
        /* convert device units to logical */
2303
        for( i = 0; i < count; i++, abc++ ) {
2304
            abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2305 2306
            abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
            abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2307
	}
2308
        ret = TRUE;
2309
    }
2310

2311
    release_dc_ptr( dc );
2312
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2313 2314
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2315

Alexandre Julliard's avatar
Alexandre Julliard committed
2316
/***********************************************************************
2317
 *           GetGlyphOutlineA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2318
 */
2319 2320
DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
                                 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
Alexandre Julliard's avatar
Alexandre Julliard committed
2321
                                 LPVOID lpBuffer, const MAT2 *lpmat2 )
Alexandre Julliard's avatar
Alexandre Julliard committed
2322
{
2323 2324 2325 2326 2327
    LPWSTR p = NULL;
    DWORD ret;
    UINT c;

    if(!(fuFormat & GGO_GLYPH_INDEX)) {
2328 2329 2330 2331 2332 2333 2334 2335 2336 2337
        int len;
        char mbchs[2];
        if(uChar > 0xff) { /* but, 2 bytes character only */
            len = 2;
            mbchs[0] = (uChar & 0xff00) >> 8;
            mbchs[1] = (uChar & 0xff);
        } else {
            len = 1;
            mbchs[0] = (uChar & 0xff);
        }
2338
        p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
2339 2340 2341 2342 2343
	c = p[0];
    } else
        c = uChar;
    ret = GetGlyphOutlineW(hdc, c, fuFormat, lpgm, cbBuffer, lpBuffer,
			   lpmat2);
2344
    HeapFree(GetProcessHeap(), 0, p);
2345
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2346 2347
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2348
/***********************************************************************
2349
 *           GetGlyphOutlineW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2350
 */
2351 2352
DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
                                 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
Alexandre Julliard's avatar
Alexandre Julliard committed
2353
                                 LPVOID lpBuffer, const MAT2 *lpmat2 )
Alexandre Julliard's avatar
Alexandre Julliard committed
2354
{
2355
    DC *dc = get_dc_ptr(hdc);
2356 2357
    DWORD ret;

2358
    TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2359
	  hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2360 2361 2362 2363 2364 2365 2366 2367 2368

    if(!dc) return GDI_ERROR;

    if(dc->gdiFont)
      ret = WineEngGetGlyphOutline(dc->gdiFont, uChar, fuFormat, lpgm,
				   cbBuffer, lpBuffer, lpmat2);
    else
      ret = GDI_ERROR;

2369
    release_dc_ptr( dc );
2370
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2371
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2372

Alexandre Julliard's avatar
Alexandre Julliard committed
2373

Alexandre Julliard's avatar
Alexandre Julliard committed
2374
/***********************************************************************
2375
 *           CreateScalableFontResourceA   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2376
 */
2377
BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
Alexandre Julliard's avatar
Alexandre Julliard committed
2378 2379 2380
                                             LPCSTR lpszResourceFile,
                                             LPCSTR lpszFontFile,
                                             LPCSTR lpszCurrentPath )
Alexandre Julliard's avatar
Alexandre Julliard committed
2381
{
2382 2383 2384 2385 2386
    LPWSTR lpszResourceFileW = NULL;
    LPWSTR lpszFontFileW = NULL;
    LPWSTR lpszCurrentPathW = NULL;
    int len;
    BOOL ret;
2387

2388 2389 2390 2391 2392 2393
    if (lpszResourceFile)
    {
        len = MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, NULL, 0);
        lpszResourceFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
        MultiByteToWideChar(CP_ACP, 0, lpszResourceFile, -1, lpszResourceFileW, len);
    }
2394

2395 2396 2397 2398 2399
    if (lpszFontFile)
    {
        len = MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, NULL, 0);
        lpszFontFileW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
        MultiByteToWideChar(CP_ACP, 0, lpszFontFile, -1, lpszFontFileW, len);
2400
    }
2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416

    if (lpszCurrentPath)
    {
        len = MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, NULL, 0);
        lpszCurrentPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
        MultiByteToWideChar(CP_ACP, 0, lpszCurrentPath, -1, lpszCurrentPathW, len);
    }

    ret = CreateScalableFontResourceW(fHidden, lpszResourceFileW,
            lpszFontFileW, lpszCurrentPathW);

    HeapFree(GetProcessHeap(), 0, lpszResourceFileW);
    HeapFree(GetProcessHeap(), 0, lpszFontFileW);
    HeapFree(GetProcessHeap(), 0, lpszCurrentPathW);

    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2417 2418
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2419
/***********************************************************************
2420
 *           CreateScalableFontResourceW   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2421
 */
2422
BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
Alexandre Julliard's avatar
Alexandre Julliard committed
2423 2424 2425
                                             LPCWSTR lpszResourceFile,
                                             LPCWSTR lpszFontFile,
                                             LPCWSTR lpszCurrentPath )
Alexandre Julliard's avatar
Alexandre Julliard committed
2426
{
2427 2428 2429 2430 2431 2432
    HANDLE f;
    FIXME("(%d,%s,%s,%s): stub\n",
          fHidden, debugstr_w(lpszResourceFile), debugstr_w(lpszFontFile),
          debugstr_w(lpszCurrentPath) );

    /* fHidden=1 - only visible for the calling app, read-only, not
Austin English's avatar
Austin English committed
2433
     * enumerated with EnumFonts/EnumFontFamilies
2434 2435 2436 2437 2438 2439 2440 2441 2442
     * lpszCurrentPath can be NULL
     */

    /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
    if ((f = CreateFileW(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
        CloseHandle(f);
        SetLastError(ERROR_FILE_EXISTS);
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2443
    return FALSE; /* create failed */
Alexandre Julliard's avatar
Alexandre Julliard committed
2444 2445
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2446
/*************************************************************************
2447
 *             GetKerningPairsA   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2448
 */
2449
DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2450
                               LPKERNINGPAIR kern_pairA )
Alexandre Julliard's avatar
Alexandre Julliard committed
2451
{
2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464
    INT charset;
    CHARSETINFO csi;
    CPINFO cpi;
    DWORD i, total_kern_pairs, kern_pairs_copied = 0;
    KERNINGPAIR *kern_pairW;

    if (!cPairs && kern_pairA)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }

    charset = GetTextCharset(hDC);
2465
    if (!TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET))
2466 2467 2468 2469
    {
        FIXME("Can't find codepage for charset %d\n", charset);
        return 0;
    }
2470 2471 2472 2473 2474
    /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
     * to fail on an invalid character for CP_SYMBOL.
     */
    cpi.DefaultChar[0] = 0;
    if (csi.ciACP != CP_SYMBOL && !GetCPInfo(csi.ciACP, &cpi))
2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495
    {
        FIXME("Can't find codepage %u info\n", csi.ciACP);
        return 0;
    }
    TRACE("charset %d => codepage %u\n", charset, csi.ciACP);

    total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
    if (!total_kern_pairs) return 0;

    kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
    GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);

    for (i = 0; i < total_kern_pairs; i++)
    {
        char first, second;

        if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
            continue;

        if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
            continue;
Alexandre Julliard's avatar
Alexandre Julliard committed
2496

2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515
        if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
            continue;

        if (kern_pairA)
        {
            if (kern_pairs_copied >= cPairs) break;

            kern_pairA->wFirst = (BYTE)first;
            kern_pairA->wSecond = (BYTE)second;
            kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
            kern_pairA++;
        }
        kern_pairs_copied++;
    }

    HeapFree(GetProcessHeap(), 0, kern_pairW);

    return kern_pairs_copied;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2516 2517

/*************************************************************************
2518
 *             GetKerningPairsW   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2519
 */
2520 2521
DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
                                 LPKERNINGPAIR lpKerningPairs )
Alexandre Julliard's avatar
Alexandre Julliard committed
2522
{
2523
    DC *dc;
2524
    DWORD ret = 0;
2525

2526
    TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2527

2528 2529 2530 2531 2532 2533
    if (!cPairs && lpKerningPairs)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }

2534
    dc = get_dc_ptr(hDC);
2535 2536 2537 2538 2539
    if (!dc) return 0;

    if (dc->gdiFont)
        ret = WineEngGetKerningPairs(dc->gdiFont, cPairs, lpKerningPairs);

2540
    release_dc_ptr( dc );
2541
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2542
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2543

Alexandre Julliard's avatar
Alexandre Julliard committed
2544
/*************************************************************************
2545
 * TranslateCharsetInfo [GDI32.@]
2546 2547
 *
 * Fills a CHARSETINFO structure for a character set, code page, or
2548
 * font. This allows making the correspondence between different labels
2549
 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2550 2551 2552 2553 2554 2555 2556 2557 2558
 * 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.
 *
 */
2559
BOOL WINAPI TranslateCharsetInfo(
2560
  LPDWORD lpSrc, /* [in]
2561 2562 2563 2564
       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
		 */
2565
  LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
Jon Griffiths's avatar
Jon Griffiths committed
2566 2567
  DWORD flags /* [in] determines interpretation of lpSrc */)
{
2568 2569 2570 2571 2572 2573
    int index = 0;
    switch (flags) {
    case TCI_SRCFONTSIG:
	while (!(*lpSrc>>index & 0x0001) && index<MAXTCIINDEX) index++;
      break;
    case TCI_SRCCODEPAGE:
2574
      while (PtrToUlong(lpSrc) != FONT_tci[index].ciACP && index < MAXTCIINDEX) index++;
2575 2576
      break;
    case TCI_SRCCHARSET:
2577
      while (PtrToUlong(lpSrc) != FONT_tci[index].ciCharset && index < MAXTCIINDEX) index++;
2578 2579 2580 2581 2582
      break;
    default:
      return FALSE;
    }
    if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2583
    *lpCs = FONT_tci[index];
Alexandre Julliard's avatar
Alexandre Julliard committed
2584 2585 2586
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2587
/*************************************************************************
2588
 *             GetFontLanguageInfo   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2589
 */
2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600
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;
2601

2602
	DWORD result=0;
2603

2604 2605 2606 2607 2608
	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;
2609

2610 2611
	if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
		result|=GCP_DIACRITIC;
2612

2613 2614
	if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
		result|=FLI_GLYPHS;
2615

2616 2617
	if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
		result|=GCP_GLYPHSHAPE;
2618

2619 2620
	if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
		result|=GCP_KASHIDA;
2621

2622 2623 2624 2625 2626
	if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
		result|=GCP_LIGATE;

	if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
		result|=GCP_USEKERNING;
2627

2628 2629 2630 2631
        /* 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;
2632

2633
	return result;
Alexandre Julliard's avatar
Alexandre Julliard committed
2634 2635
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2636

Alexandre Julliard's avatar
Alexandre Julliard committed
2637
/*************************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
2638 2639 2640
 * GetFontData [GDI32.@]
 *
 * Retrieve data for TrueType font.
Alexandre Julliard's avatar
Alexandre Julliard committed
2641 2642 2643
 *
 * RETURNS
 *
2644
 * success: Number of bytes returned
Alexandre Julliard's avatar
Alexandre Julliard committed
2645 2646 2647 2648
 * failure: GDI_ERROR
 *
 * NOTES
 *
2649
 * Calls SetLastError()
Alexandre Julliard's avatar
Alexandre Julliard committed
2650 2651
 *
 */
2652
DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
Alexandre Julliard's avatar
Alexandre Julliard committed
2653 2654
    LPVOID buffer, DWORD length)
{
2655
    DC *dc = get_dc_ptr(hdc);
Huw D M Davies's avatar
Huw D M Davies committed
2656 2657 2658 2659 2660 2661 2662
    DWORD ret = GDI_ERROR;

    if(!dc) return GDI_ERROR;

    if(dc->gdiFont)
      ret = WineEngGetFontData(dc->gdiFont, table, offset, buffer, length);

2663
    release_dc_ptr( dc );
Huw D M Davies's avatar
Huw D M Davies committed
2664
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2665
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2666

2667 2668 2669 2670 2671 2672 2673 2674 2675 2676
/*************************************************************************
 * GetGlyphIndicesA [GDI32.@]
 */
DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
			      LPWORD pgi, DWORD flags)
{
    DWORD ret;
    WCHAR *lpstrW;
    INT countW;

2677
    TRACE("(%p, %s, %d, %p, 0x%x)\n",
2678
          hdc, debugstr_an(lpstr, count), count, pgi, flags);
2679

2680
    lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692
    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)
{
2693
    DC *dc = get_dc_ptr(hdc);
2694 2695
    DWORD ret = GDI_ERROR;

2696
    TRACE("(%p, %s, %d, %p, 0x%x)\n",
2697
          hdc, debugstr_wn(lpstr, count), count, pgi, flags);
2698 2699 2700 2701 2702 2703

    if(!dc) return GDI_ERROR;

    if(dc->gdiFont)
	ret = WineEngGetGlyphIndices(dc->gdiFont, lpstr, count, pgi, flags);

2704
    release_dc_ptr( dc );
2705 2706 2707
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2708
/*************************************************************************
2709
 * GetCharacterPlacementA [GDI32.@]
2710
 *
2711 2712
 * See GetCharacterPlacementW.
 *
2713 2714
 * NOTES:
 *  the web browser control of ie4 calls this with dwFlags=0
Alexandre Julliard's avatar
Alexandre Julliard committed
2715 2716
 */
DWORD WINAPI
2717 2718
GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
			 INT nMaxExtent, GCP_RESULTSA *lpResults,
Alexandre Julliard's avatar
Alexandre Julliard committed
2719 2720
			 DWORD dwFlags)
{
2721
    WCHAR *lpStringW;
2722
    INT uCountW;
2723 2724
    GCP_RESULTSW resultsW;
    DWORD ret;
2725
    UINT font_cp;
2726

2727
    TRACE("%s, %d, %d, 0x%08x\n",
2728
          debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
2729

2730 2731
    /* both structs are equal in size */
    memcpy(&resultsW, lpResults, sizeof(resultsW));
2732

2733
    lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
2734 2735
    if(lpResults->lpOutString)
        resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
2736

2737 2738
    ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);

2739 2740 2741
    lpResults->nGlyphs = resultsW.nGlyphs;
    lpResults->nMaxFit = resultsW.nMaxFit;

2742
    if(lpResults->lpOutString) {
2743
        WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
2744
                            lpResults->lpOutString, uCount, NULL, NULL );
2745
    }
2746

2747 2748
    HeapFree(GetProcessHeap(), 0, lpStringW);
    HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
2749 2750

    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2751 2752 2753
}

/*************************************************************************
2754
 * GetCharacterPlacementW [GDI32.@]
2755 2756 2757 2758 2759 2760
 *
 *   Retrieve information about a string. This includes the width, reordering,
 *   Glyphing and so on.
 *
 * RETURNS
 *
Francois Gouget's avatar
Francois Gouget committed
2761
 *   The width and height of the string if successful, 0 if failed.
2762 2763 2764 2765
 *
 * BUGS
 *
 *   All flags except GCP_REORDER are not yet implemented.
Austin English's avatar
Austin English committed
2766
 *   Reordering is not 100% compliant to the Windows BiDi method.
2767
 *   Caret positioning is not yet implemented for BiDi.
2768 2769
 *   Classes are not yet implemented.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
2770 2771
 */
DWORD WINAPI
2772
GetCharacterPlacementW(
2773 2774 2775 2776 2777 2778
		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 */
2779
		)
Alexandre Julliard's avatar
Alexandre Julliard committed
2780
{
2781 2782
    DWORD ret=0;
    SIZE size;
2783
    UINT i, nSet;
2784

2785
    TRACE("%s, %d, %d, 0x%08x\n",
2786
          debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
2787

2788 2789
    TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
          "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
2790 2791 2792
	    lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
	    lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
	    lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
2793

2794
    if(dwFlags&(~GCP_REORDER))			FIXME("flags 0x%08x ignored\n", dwFlags);
2795
    if(lpResults->lpClass)	FIXME("classes not implemented\n");
2796 2797
    if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
        FIXME("Caret positions for complex scripts not implemented\n");
2798

2799 2800 2801
	nSet = (UINT)uCount;
	if(nSet > lpResults->nGlyphs)
		nSet = lpResults->nGlyphs;
2802

2803 2804
	/* return number of initialized fields */
	lpResults->nGlyphs = nSet;
2805

2806
	if((dwFlags&GCP_REORDER)==0 )
2807 2808 2809 2810
	{
		/* 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)
2811
                    memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
2812 2813 2814 2815 2816 2817

		if(lpResults->lpOrder)
		{
			for(i = 0; i < nSet; i++)
				lpResults->lpOrder[i] = i;
		}
2818
	} else
2819
	{
2820 2821
            BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
                          nSet, lpResults->lpOrder );
2822
	}
2823

2824 2825 2826 2827 2828 2829 2830 2831 2832 2833
	/* 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;
		}
	}
2834

2835 2836 2837 2838 2839 2840 2841 2842 2843 2844
    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);
    }
   
2845 2846 2847
    if(lpResults->lpGlyphs)
	GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);

2848 2849 2850 2851
    if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
      ret = MAKELONG(size.cx, size.cy);

    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2852
}
2853 2854

/*************************************************************************
2855
 *      GetCharABCWidthsFloatA [GDI32.@]
2856 2857
 *
 * See GetCharABCWidthsFloatW.
2858
 */
2859
BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2860
{
2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872
    INT i, wlen, count = (INT)(last - first + 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)(first + i);

2873
    wstr = FONT_mbtowc( hdc, str, count, &wlen, NULL );
2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888

    for (i = 0; i < wlen; i++)
    {
        if (!GetCharABCWidthsFloatW( hdc, wstr[i], wstr[i], abcf ))
        {
            ret = FALSE;
            break;
        }
        abcf++;
    }

    HeapFree( GetProcessHeap(), 0, str );
    HeapFree( GetProcessHeap(), 0, wstr );

    return ret;
2889 2890 2891
}

/*************************************************************************
2892
 *      GetCharABCWidthsFloatW [GDI32.@]
2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909
 *
 * Retrieves widths of a range of characters.
 *
 * PARAMS
 *    hdc   [I] Handle to device context.
 *    first [I] First character in range to query.
 *    last  [I] Last character in range to query.
 *    abcf  [O] Array of LPABCFLOAT structures.
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 *
 * BUGS
 *    Only works with TrueType fonts. It also doesn't return real
 *    floats but converted integers because it's implemented on
 *    top of GetCharABCWidthsW.
2910
 */
2911
BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
2912
{
2913
    ABC *abc, *abc_base;
2914 2915 2916 2917 2918
    unsigned int i, size = sizeof(ABC) * (last - first + 1);
    BOOL ret;

    TRACE("%p, %d, %d, %p - partial stub\n", hdc, first, last, abcf);

2919
    abc = abc_base = HeapAlloc( GetProcessHeap(), 0, size );
2920 2921 2922
    if (!abc) return FALSE;

    ret = GetCharABCWidthsW( hdc, first, last, abc );
2923
    if (ret)
2924 2925 2926 2927 2928 2929 2930 2931
    {
        for (i = first; i <= last; i++, abc++, abcf++)
        {
            abcf->abcfA = abc->abcA;
            abcf->abcfB = abc->abcB;
            abcf->abcfC = abc->abcC;
        }
    }
2932
    HeapFree( GetProcessHeap(), 0, abc_base );
2933
    return ret;
2934 2935 2936
}

/*************************************************************************
2937
 *      GetCharWidthFloatA [GDI32.@]
2938
 */
2939 2940
BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
		                    UINT iLastChar, PFLOAT pxBuffer)
2941
{
2942 2943
    FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
    return 0;
2944 2945 2946
}

/*************************************************************************
2947
 *      GetCharWidthFloatW [GDI32.@]
2948
 */
2949 2950
BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
		                    UINT iLastChar, PFLOAT pxBuffer)
2951
{
2952 2953
    FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
    return 0;
2954
}
2955

2956 2957 2958 2959 2960 2961 2962 2963

/***********************************************************************
 *								       *
 *           Font Resource API					       *
 *								       *
 ***********************************************************************/

/***********************************************************************
2964
 *           AddFontResourceA    (GDI32.@)
2965 2966 2967
 */
INT WINAPI AddFontResourceA( LPCSTR str )
{
2968
    return AddFontResourceExA( str, 0, NULL);
2969 2970 2971
}

/***********************************************************************
2972
 *           AddFontResourceW    (GDI32.@)
2973 2974 2975
 */
INT WINAPI AddFontResourceW( LPCWSTR str )
{
2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994
    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;
}

2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013
static BOOL CALLBACK load_enumed_resource(HMODULE hModule, LPCWSTR type, LPWSTR name, LONG_PTR lParam)
{
    HRSRC rsrc = FindResourceW(hModule, name, type);
    HGLOBAL hMem = LoadResource(hModule, rsrc);
    LPVOID *pMem = LockResource(hMem);
    int *num_total = (int *)lParam;
    DWORD num_in_res;

    TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type));
    if (!AddFontMemResourceEx(pMem, SizeofResource(hModule, rsrc), NULL, &num_in_res))
    {
        ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule, hMem);
        return FALSE;
    }

    *num_total += num_in_res;
    return TRUE;
}

3014 3015 3016 3017 3018
/***********************************************************************
 *           AddFontResourceExW    (GDI32.@)
 */
INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
{
3019 3020 3021
    int ret = WineEngAddFontResourceEx(str, fl, pdv);
    if (ret == 0)
    {
3022
        /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3023 3024 3025 3026 3027 3028
        HMODULE hModule = LoadLibraryExW(str, NULL, LOAD_LIBRARY_AS_DATAFILE);
        if (hModule != NULL)
        {
            int num_resources = 0;
            LPWSTR rt_font = (LPWSTR)((ULONG_PTR)8);  /* we don't want to include winuser.h */

3029
            TRACE("WineEndAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3030 3031 3032 3033 3034 3035 3036
                wine_dbgstr_w(str));
            if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
                ret = num_resources;
            FreeLibrary(hModule);
        }
    }
    return ret;
3037 3038 3039
}

/***********************************************************************
3040
 *           RemoveFontResourceA    (GDI32.@)
3041 3042 3043
 */
BOOL WINAPI RemoveFontResourceA( LPCSTR str )
{
3044
    return RemoveFontResourceExA(str, 0, 0);
3045 3046 3047
}

/***********************************************************************
3048
 *           RemoveFontResourceW    (GDI32.@)
3049 3050 3051
 */
BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
{
3052 3053 3054
    return RemoveFontResourceExW(str, 0, 0);
}

3055 3056 3057 3058 3059
/***********************************************************************
 *           AddFontMemResourceEx    (GDI32.@)
 */
HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
{
3060
    return WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, pcFonts);
3061 3062
}

3063 3064 3065 3066 3067 3068 3069 3070 3071
/***********************************************************************
 *           RemoveFontMemResourceEx    (GDI32.@)
 */
BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
{
    FIXME("(%p) stub\n", fh);
    return TRUE;
}

3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092
/***********************************************************************
 *           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);
3093
}
3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109

/***********************************************************************
 *           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;
3110
    DC *dc = get_dc_ptr(hdc);
3111

3112 3113 3114 3115
    if (dc)
    {
        if (dc->gdiFont)
            ret = WineEngGetTextCharsetInfo(dc->gdiFont, fs, flags);
3116

3117
        release_dc_ptr( dc );
3118
    }
3119 3120 3121 3122 3123

    if (ret == DEFAULT_CHARSET && fs)
        memset(fs, 0, sizeof(FONTSIGNATURE));
    return ret;
}
3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163

/***********************************************************************
 *           GdiGetCharDimensions    (GDI32.@)
 *
 * Gets the average width of the characters in the English alphabet.
 *
 * PARAMS
 *  hdc    [I] Handle to the device context to measure on.
 *  lptm   [O] Pointer to memory to store the text metrics into.
 *  height [O] On exit, the maximum height of characters in the English alphabet.
 *
 * RETURNS
 *  The average width of characters in the English alphabet.
 *
 * NOTES
 *  This function is used by the dialog manager to get the size of a dialog
 *  unit. It should also be used by other pieces of code that need to know
 *  the size of a dialog unit in logical units without having access to the
 *  window handle of the dialog.
 *  Windows caches the font metrics from this function, but we don't and
 *  there doesn't appear to be an immediate advantage to do so.
 *
 * SEE ALSO
 *  GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
 */
LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
{
    SIZE sz;
    static const WCHAR alphabet[] = {
        'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
        'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
        'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};

    if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;

    if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;

    if (height) *height = sz.cy;
    return (sz.cx / 26 + 1) / 2;
}
3164 3165 3166 3167 3168 3169

BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
{
    FIXME("(%d): stub\n", fEnableEUDC);
    return FALSE;
}
3170 3171 3172

/***********************************************************************
 *           GetCharWidthI    (GDI32.@)
3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188
 *
 * Retrieve widths of characters.
 *
 * PARAMS
 *  hdc    [I] Handle to a device context.
 *  first  [I] First glyph in range to query.
 *  count  [I] Number of glyph indices to query.
 *  glyphs [I] Array of glyphs to query.
 *  buffer [O] Buffer to receive character widths.
 *
 * NOTES
 *  Only works with TrueType fonts.
 *
 * RETURNS
 *  Success: TRUE
 *  Failure: FALSE
3189
 */
3190
BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3191
{
3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210
    ABC *abc;
    unsigned int i;

    TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);

    if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
        return FALSE;

    if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
    {
        HeapFree(GetProcessHeap(), 0, abc);
        return FALSE;
    }

    for (i = 0; i < count; i++)
        buffer[i] = abc->abcA + abc->abcB + abc->abcC;

    HeapFree(GetProcessHeap(), 0, abc);
    return TRUE;
3211 3212 3213 3214
}

/***********************************************************************
 *           GetFontUnicodeRanges    (GDI32.@)
3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225
 *
 *  Retrieve a list of supported Unicode characters in a font.
 *
 *  PARAMS
 *   hdc  [I] Handle to a device context.
 *   lpgs [O] GLYPHSET structure specifying supported character ranges.
 *
 *  RETURNS
 *   Success: Number of bytes written to the buffer pointed to by lpgs.
 *   Failure: 0
 *
3226 3227 3228
 */
DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
{
3229
    DWORD ret = 0;
3230
    DC *dc = get_dc_ptr(hdc);
3231 3232 3233 3234 3235 3236

    TRACE("(%p, %p)\n", hdc, lpgs);

    if (!dc) return 0;

    if (dc->gdiFont) ret = WineEngGetFontUnicodeRanges(dc->gdiFont, lpgs);
3237
    release_dc_ptr(dc);
3238
    return ret;
3239
}
3240 3241 3242 3243 3244 3245 3246


/*************************************************************
 *           FontIsLinked    (GDI32.@)
 */
BOOL WINAPI FontIsLinked(HDC hdc)
{
3247
    DC *dc = get_dc_ptr(hdc);
3248 3249 3250 3251
    BOOL ret = FALSE;

    if (!dc) return FALSE;
    if (dc->gdiFont) ret = WineEngFontIsLinked(dc->gdiFont);
3252
    release_dc_ptr(dc);
3253 3254 3255
    TRACE("returning %d\n", ret);
    return ret;
}
3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282

/*************************************************************
 *           GdiRealizationInfo    (GDI32.@)
 *
 * Returns a structure that contains some font information.
 */
typedef struct
{
    DWORD flags;       /* 1 for bitmap fonts, 3 for scalable fonts */
    DWORD unknown1;    /* keeps incrementing - num of fonts that have been created or selected into a dc ?? */
    DWORD unknown2;    /* fixed for a given font - looks like it could be the order of the face in the font list or the order
                          in which the face was first rendered. */
} realization_info_t;

BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
{
    UINT otm_size;
    FIXME("(%p, %p): stub!\n", hdc, info);

    info->flags = 1;
    otm_size = GetOutlineTextMetricsW(hdc, 0, NULL);
    if(otm_size) info->flags |= 2;  /* scalable */

    info->unknown1 = -1;
    info->unknown2 = -1;
    return TRUE;
}