font.c 116 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 <limits.h>
27
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
28
#include <stdlib.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
29
#include <string.h>
30
#include <assert.h>
31
#include "winerror.h"
32
#include "windef.h"
33
#include "winbase.h"
34
#include "winnls.h"
35
#include "winternl.h"
36
#include "gdi_private.h"
37
#include "wine/exception.h"
38
#include "wine/unicode.h"
39
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
40

41 42 43 44 45 46
#ifdef WORDS_BIGENDIAN
#define get_be_word(x) (x)
#else
#define get_be_word(x) RtlUshortByteSwap(x)
#endif

47
WINE_DEFAULT_DEBUG_CHANNEL(font);
48

49 50 51 52 53 54 55
  /* 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)
{
56
    double floatWidth;
57 58

    /* Perform operation with floating point */
59
    floatWidth = (double)width * dc->xformVport2World.eM11;
60 61 62 63 64 65 66 67 68
    /* 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)
{
69
    double floatHeight;
70 71

    /* Perform operation with floating point */
72
    floatHeight = (double)height * dc->xformVport2World.eM22;
73 74 75 76
    /* Round to integers */
    return GDI_ROUND(floatHeight);
}

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
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;
}
96

97
static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc );
98 99
static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer );
static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer );
100
static BOOL FONT_DeleteObject( HGDIOBJ handle );
101 102 103 104 105 106 107 108 109 110

static const struct gdi_obj_funcs font_funcs =
{
    FONT_SelectObject,  /* pSelectObject */
    FONT_GetObjectA,    /* pGetObjectA */
    FONT_GetObjectW,    /* pGetObjectW */
    NULL,               /* pUnrealizeObject */
    FONT_DeleteObject   /* pDeleteObject */
};

111 112 113 114 115 116
typedef struct
{
    GDIOBJHDR   header;
    LOGFONTW    logfont;
} FONTOBJ;

117
struct font_enum
Alexandre Julliard's avatar
Alexandre Julliard committed
118
{
119
  LPLOGFONTW          lpLogFontParam;
120
  FONTENUMPROCW       lpEnumFunc;
121
  LPARAM              lpData;
122
  BOOL                unicode;
123
  HDC                 hdc;
124
  INT                 retval;
125
};
126

127 128 129 130
/*
 *  For TranslateCharsetInfo
 */
#define MAXTCIINDEX 32
131
static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
132
  /* ANSI */
133 134 135 136 137 138 139 140 141
  { 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}} },
142
  /* reserved by ANSI */
143 144 145 146 147 148 149
  { 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}} },
150
  /* ANSI and OEM */
151 152 153 154 155 156
  { 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}} },
157
  /* reserved for alternate ANSI and OEM */
158 159 160 161 162 163 164 165
  { 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}} },
166
  /* reserved for system */
167 168
  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
  { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
169 170
};

171
static void FONT_LogFontAToW( const LOGFONTA *fontA, LPLOGFONTW fontW )
172
{
173 174 175
    memcpy(fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE);
    MultiByteToWideChar(CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
			LF_FACESIZE);
176
    fontW->lfFaceName[LF_FACESIZE-1] = 0;
177 178
}

179
static void FONT_LogFontWToA( const LOGFONTW *fontW, LPLOGFONTA fontA )
180 181 182 183
{
    memcpy(fontA, fontW, sizeof(LOGFONTA) - LF_FACESIZE);
    WideCharToMultiByte(CP_ACP, 0, fontW->lfFaceName, -1, fontA->lfFaceName,
			LF_FACESIZE, NULL, NULL);
184
    fontA->lfFaceName[LF_FACESIZE-1] = 0;
185 186
}

187
static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW *fontW, LPENUMLOGFONTEXA fontA )
188
{
189
    FONT_LogFontWToA( &fontW->elfLogFont, &fontA->elfLogFont );
190 191

    WideCharToMultiByte( CP_ACP, 0, fontW->elfFullName, -1,
192
			 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
193 194
    fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
    WideCharToMultiByte( CP_ACP, 0, fontW->elfStyle, -1,
195
			 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
196 197
    fontA->elfStyle[LF_FACESIZE-1] = '\0';
    WideCharToMultiByte( CP_ACP, 0, fontW->elfScript, -1,
198
			 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
199 200 201
    fontA->elfScript[LF_FACESIZE-1] = '\0';
}

202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
{
    FONT_LogFontAToW( &fontA->elfLogFont, &fontW->elfLogFont );

    MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
			 fontW->elfFullName, LF_FULLFACESIZE );
    fontW->elfFullName[LF_FULLFACESIZE-1] = '\0';
    MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
			 fontW->elfStyle, LF_FACESIZE );
    fontW->elfStyle[LF_FACESIZE-1] = '\0';
    MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
			 fontW->elfScript, LF_FACESIZE );
    fontW->elfScript[LF_FACESIZE-1] = '\0';
}

Alexandre Julliard's avatar
Alexandre Julliard committed
217
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
218 219
 *              TEXTMETRIC conversion functions.
 */
220
static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
221 222 223 224 225 226 227 228 229 230 231 232
{
    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;
233 234 235
    ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
    if (ptmW->tmCharSet == SYMBOL_CHARSET)
    {
236 237
        ptmA->tmFirstChar = 0x1e;
        ptmA->tmLastChar = 0xff;  /* win9x behaviour - we need the OS2 table data to calculate correctly */
238
    }
239
    else if (ptmW->tmPitchAndFamily & TMPF_TRUETYPE)
240 241 242 243
    {
        ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
        ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
    }
244 245 246 247 248
    else
    {
        ptmA->tmFirstChar = min(ptmW->tmFirstChar, 0xff);
        ptmA->tmLastChar  = min(ptmW->tmLastChar,  0xff);
    }
249 250
    ptmA->tmDefaultChar = ptmW->tmDefaultChar;
    ptmA->tmBreakChar = ptmW->tmBreakChar;
251 252 253 254 255 256 257 258
    ptmA->tmItalic = ptmW->tmItalic;
    ptmA->tmUnderlined = ptmW->tmUnderlined;
    ptmA->tmStruckOut = ptmW->tmStruckOut;
    ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
    ptmA->tmCharSet = ptmW->tmCharSet;
}


259
static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRICEXA *ptmA )
260
{
261
    FONT_TextMetricWToA((const TEXTMETRICW *)ptmW, (LPTEXTMETRICA)ptmA);
262 263 264 265 266
    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));
267 268
}

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
static DWORD get_font_ppem( HDC hdc )
{
    TEXTMETRICW tm;
    DWORD ppem;
    DC *dc = get_dc_ptr( hdc );

    if (!dc) return GDI_ERROR;

    GetTextMetricsW( hdc, &tm );
    ppem = abs( INTERNAL_YWSTODS( dc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading ) );
    release_dc_ptr( dc );
    return ppem;
}

#define GASP_GRIDFIT 0x01
#define GASP_DOGRAY  0x02

static BOOL get_gasp_flags( HDC hdc, WORD *flags )
{
    DWORD size, gasp_tag = 0x70736167;
    WORD buf[16]; /* Enough for seven ranges before we need to alloc */
    WORD *alloced = NULL, *ptr = buf;
    WORD num_recs, version;
    DWORD ppem = get_font_ppem( hdc );
    BOOL ret = FALSE;

    *flags = 0;
    if (ppem == GDI_ERROR) return FALSE;

    size = GetFontData( hdc, gasp_tag,  0, NULL, 0 );
    if (size == GDI_ERROR) return FALSE;
    if (size < 4 * sizeof(WORD)) return FALSE;
    if (size > sizeof(buf))
    {
        ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
        if (!ptr) return FALSE;
    }

    GetFontData( hdc, gasp_tag, 0, ptr, size );

    version  = get_be_word( *ptr++ );
    num_recs = get_be_word( *ptr++ );

    if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
    {
        FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
        goto done;
    }

    while (num_recs--)
    {
        *flags = get_be_word( *(ptr + 1) );
        if (ppem <= get_be_word( *ptr )) break;
        ptr += 2;
    }
    TRACE( "got flags %04x for ppem %d\n", *flags, ppem );
    ret = TRUE;

done:
    HeapFree( GetProcessHeap(), 0, alloced );
    return ret;
}
331

332 333 334
UINT get_font_aa_flags( HDC hdc )
{
    LOGFONTW lf;
335
    WORD gasp_flags;
336 337 338 339 340 341 342 343 344 345 346 347

    if (GetObjectType( hdc ) == OBJ_MEMDC)
    {
        BITMAP bm;
        GetObjectW( GetCurrentObject( hdc, OBJ_BITMAP ), sizeof(bm), &bm );
        if (bm.bmBitsPixel <= 8) return GGO_BITMAP;
    }
    else if (GetDeviceCaps( hdc, BITSPIXEL ) <= 8) return GGO_BITMAP;

    GetObjectW( GetCurrentObject( hdc, OBJ_FONT ), sizeof(lf), &lf );
    if (lf.lfQuality == NONANTIALIASED_QUALITY) return GGO_BITMAP;

348 349 350 351
    if (get_gasp_flags( hdc, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
        return GGO_BITMAP;

    /* FIXME, check user prefs */
352 353 354
    return GGO_GRAY4_BITMAP;
}

355
/***********************************************************************
356
 *           GdiGetCodePage   (GDI32.@)
357
 */
358
DWORD WINAPI GdiGetCodePage( HDC hdc )
359 360
{
    UINT cp = CP_ACP;
361
    DC *dc = get_dc_ptr( hdc );
362

363 364 365 366
    if (dc)
    {
        cp = dc->font_code_page;
        release_dc_ptr( dc );
367
    }
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
    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 );
390 391 392

    if(count == -1) count = strlen(str);
    lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
393
    strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
394 395 396
    MultiByteToWideChar(cp, 0, str, count, strW, lenW);
    TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW));
    if(plenW) *plenW = lenW;
397
    if(pCP) *pCP = cp;
398 399 400
    return strW;
}

401
/***********************************************************************
402
 *           CreateFontIndirectExA   (GDI32.@)
403
 */
404
HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *penumexA )
405
{
406
    ENUMLOGFONTEXDVW enumexW;
407

408
    if (!penumexA) return 0;
409

410 411 412
    FONT_EnumLogFontExAToW( &penumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
    enumexW.elfDesignVector = penumexA->elfDesignVector;
    return CreateFontIndirectExW( &enumexW );
413 414 415
}

/***********************************************************************
416
 *           CreateFontIndirectExW   (GDI32.@)
417
 */
418
HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *penumex )
Alexandre Julliard's avatar
Alexandre Julliard committed
419
{
420 421
    HFONT hFont;
    FONTOBJ *fontPtr;
422
    const LOGFONTW *plf;
423

424 425 426 427 428 429 430 431 432 433 434
    if (!penumex) return 0;

    if (penumex->elfEnumLogfontEx.elfFullName[0] ||
        penumex->elfEnumLogfontEx.elfStyle[0] ||
        penumex->elfEnumLogfontEx.elfScript[0])
    {
        FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
            debugstr_w(penumex->elfEnumLogfontEx.elfFullName),
            debugstr_w(penumex->elfEnumLogfontEx.elfStyle),
            debugstr_w(penumex->elfEnumLogfontEx.elfScript));
    }
435

436
    plf = &penumex->elfEnumLogfontEx.elfLogFont;
437
    if (!(fontPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr) ))) return 0;
438

439
    fontPtr->logfont = *plf;
440 441 442 443 444 445 446

    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",
447
             plf->lfOrientation/10., plf->lfEscapement/10., fontPtr);
448 449
    }

450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
    if (!(hFont = alloc_gdi_handle( &fontPtr->header, OBJ_FONT, &font_funcs )))
    {
        HeapFree( GetProcessHeap(), 0, fontPtr );
        return 0;
    }

    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);

Alexandre Julliard's avatar
Alexandre Julliard committed
467 468
    return hFont;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
469

470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
/***********************************************************************
 *           CreateFontIndirectA   (GDI32.@)
 */
HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
{
    LOGFONTW lfW;

    if (!plfA) return 0;

    FONT_LogFontAToW( plfA, &lfW );
    return CreateFontIndirectW( &lfW );
}

/***********************************************************************
 *           CreateFontIndirectW   (GDI32.@)
 */
HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf )
{
    ENUMLOGFONTEXDVW exdv;

    if (!plf) return 0;

    exdv.elfEnumLogfontEx.elfLogFont = *plf;
    exdv.elfEnumLogfontEx.elfFullName[0] = 0;
    exdv.elfEnumLogfontEx.elfStyle[0] = 0;
    exdv.elfEnumLogfontEx.elfScript[0] = 0;
    return CreateFontIndirectExW( &exdv );
}

Alexandre Julliard's avatar
Alexandre Julliard committed
499
/*************************************************************************
500
 *           CreateFontA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
501
 */
502 503
HFONT WINAPI CreateFontA( INT height, INT width, INT esc,
                              INT orient, INT weight, DWORD italic,
Alexandre Julliard's avatar
Alexandre Julliard committed
504 505 506
                              DWORD underline, DWORD strikeout, DWORD charset,
                              DWORD outpres, DWORD clippres, DWORD quality,
                              DWORD pitch, LPCSTR name )
Alexandre Julliard's avatar
Alexandre Julliard committed
507
{
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
    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;
523 524

    if (name)
525
	lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
526
    else
527 528 529
	logfont.lfFaceName[0] = '\0';

    return CreateFontIndirectA( &logfont );
Alexandre Julliard's avatar
Alexandre Julliard committed
530 531 532
}

/*************************************************************************
533
 *           CreateFontW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
534
 */
535 536
HFONT WINAPI CreateFontW( INT height, INT width, INT esc,
                              INT orient, INT weight, DWORD italic,
Alexandre Julliard's avatar
Alexandre Julliard committed
537 538 539
                              DWORD underline, DWORD strikeout, DWORD charset,
                              DWORD outpres, DWORD clippres, DWORD quality,
                              DWORD pitch, LPCWSTR name )
Alexandre Julliard's avatar
Alexandre Julliard committed
540
{
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
    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;
556 557 558

    if (name)
	lstrcpynW(logfont.lfFaceName, name,
559
		  sizeof(logfont.lfFaceName) / sizeof(WCHAR));
560
    else
561 562 563
	logfont.lfFaceName[0] = '\0';

    return CreateFontIndirectW( &logfont );
Alexandre Julliard's avatar
Alexandre Julliard committed
564 565
}

566 567 568
static void update_font_code_page( DC *dc )
{
    CHARSETINFO csi;
569
    int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 );
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608

    /* Hmm, nicely designed api this one! */
    if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) )
        dc->font_code_page = csi.ciACP;
    else {
        switch(charset) {
        case OEM_CHARSET:
            dc->font_code_page = GetOEMCP();
            break;
        case DEFAULT_CHARSET:
            dc->font_code_page = 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...
            */
            dc->font_code_page = CP_ACP;
            break;

        default:
            FIXME("Can't find codepage for charset %d\n", charset);
            dc->font_code_page = CP_ACP;
            break;
        }
    }

    TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
609

610 611 612
/***********************************************************************
 *           FONT_SelectObject
 */
613
static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
614 615
{
    HGDIOBJ ret = 0;
616
    DC *dc = get_dc_ptr( hdc );
617
    PHYSDEV physdev;
618 619 620

    if (!dc) return 0;

621 622 623 624 625 626
    if (!GDI_inc_ref_count( handle ))
    {
        release_dc_ptr( dc );
        return 0;
    }

627
    physdev = GET_DC_PHYSDEV( dc, pSelectFont );
628
    if (physdev->funcs->pSelectFont( physdev, handle ))
629 630 631
    {
        ret = dc->hFont;
        dc->hFont = handle;
632
        update_font_code_page( dc );
633
        GDI_dec_ref_count( ret );
634
    }
635 636
    else GDI_dec_ref_count( handle );

637
    release_dc_ptr( dc );
638 639 640 641
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
642
/***********************************************************************
643
 *           FONT_GetObjectA
Alexandre Julliard's avatar
Alexandre Julliard committed
644
 */
645
static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
646
{
647
    FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
648
    LOGFONTA lfA;
Alexandre Julliard's avatar
Alexandre Julliard committed
649

650 651 652 653 654 655 656 657 658
    if (!font) return 0;
    if (buffer)
    {
        FONT_LogFontWToA( &font->logfont, &lfA );
        if (count > sizeof(lfA)) count = sizeof(lfA);
        memcpy( buffer, &lfA, count );
    }
    else count = sizeof(lfA);
    GDI_ReleaseObj( handle );
Alexandre Julliard's avatar
Alexandre Julliard committed
659 660
    return count;
}
661

662
/***********************************************************************
663
 *           FONT_GetObjectW
664
 */
665
static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
666
{
667
    FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
668 669 670 671 672 673 674 675 676

    if (!font) return 0;
    if (buffer)
    {
        if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
        memcpy( buffer, &font->logfont, count );
    }
    else count = sizeof(LOGFONTW);
    GDI_ReleaseObj( handle );
677 678
    return count;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
679 680


681 682 683
/***********************************************************************
 *           FONT_DeleteObject
 */
684
static BOOL FONT_DeleteObject( HGDIOBJ handle )
685
{
686 687
    FONTOBJ *obj;

688
    WineEngDestroyFontInstance( handle );
689 690 691

    if (!(obj = free_gdi_handle( handle ))) return FALSE;
    return HeapFree( GetProcessHeap(), 0, obj );
692 693 694
}


Alexandre Julliard's avatar
Alexandre Julliard committed
695
/***********************************************************************
696
 *              FONT_EnumInstance
697 698 699
 *
 * 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
700
 */
701 702
static INT CALLBACK FONT_EnumInstance( const LOGFONTW *plf, const TEXTMETRICW *ptm,
                                       DWORD fType, LPARAM lp )
Alexandre Julliard's avatar
Alexandre Julliard committed
703
{
704
    struct font_enum *pfe = (struct font_enum *)lp;
705
    INT ret = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
706

707
    /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
708 709
    if ((!pfe->lpLogFontParam ||
        pfe->lpLogFontParam->lfCharSet == DEFAULT_CHARSET ||
710 711
        pfe->lpLogFontParam->lfCharSet == plf->lfCharSet) &&
       (!(fType & RASTER_FONTTYPE) || GetDeviceCaps(pfe->hdc, TEXTCAPS) & TC_RA_ABLE) )
Alexandre Julliard's avatar
Alexandre Julliard committed
712 713
    {
	/* convert font metrics */
714 715
        ENUMLOGFONTEXA logfont;
        NEWTEXTMETRICEXA tmA;
Alexandre Julliard's avatar
Alexandre Julliard committed
716

717
        if (!pfe->unicode)
718
        {
719 720 721 722
            FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW *)plf, &logfont);
            FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW *)ptm, &tmA );
            plf = (LOGFONTW *)&logfont.elfLogFont;
            ptm = (TEXTMETRICW *)&tmA;
723
        }
724
        ret = pfe->lpEnumFunc( plf, ptm, fType, pfe->lpData );
725
        pfe->retval = ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
726
    }
727
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
728 729 730
}

/***********************************************************************
731
 *		FONT_EnumFontFamiliesEx
Alexandre Julliard's avatar
Alexandre Julliard committed
732
 */
733 734
static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
                                    LPARAM lParam, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
735
{
736
    INT ret = 0;
737
    DC *dc = get_dc_ptr( hDC );
738
    struct font_enum fe;
739

740
    if (dc)
741
    {
742
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pEnumFonts );
743 744 745 746 747 748 749

        if (plf) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
        fe.lpLogFontParam = plf;
        fe.lpEnumFunc = efproc;
        fe.lpData = lParam;
        fe.unicode = unicode;
        fe.hdc = hDC;
750 751
        fe.retval = 1;
        ret = physdev->funcs->pEnumFonts( physdev, plf, FONT_EnumInstance, (LPARAM)&fe );
752
        release_dc_ptr( dc );
Huw D M Davies's avatar
Huw D M Davies committed
753
    }
754
    return ret ? fe.retval : 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
755 756 757
}

/***********************************************************************
758
 *              EnumFontFamiliesExW	(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
759
 */
760
INT WINAPI EnumFontFamiliesExW( HDC hDC, LPLOGFONTW plf,
761
                                    FONTENUMPROCW efproc,
Alexandre Julliard's avatar
Alexandre Julliard committed
762
                                    LPARAM lParam, DWORD dwFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
763
{
764
    return FONT_EnumFontFamiliesEx( hDC, plf, efproc, lParam, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
765 766 767
}

/***********************************************************************
768
 *              EnumFontFamiliesExA	(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
769
 */
770
INT WINAPI EnumFontFamiliesExA( HDC hDC, LPLOGFONTA plf,
771
                                    FONTENUMPROCA efproc,
Alexandre Julliard's avatar
Alexandre Julliard committed
772
                                    LPARAM lParam, DWORD dwFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
773
{
774 775 776 777 778 779 780 781
    LOGFONTW lfW, *plfW;

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

783
    return FONT_EnumFontFamiliesEx( hDC, plfW, (FONTENUMPROCW)efproc, lParam, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
784 785 786
}

/***********************************************************************
787
 *              EnumFontFamiliesA	(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
788
 */
789 790
INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
                                  FONTENUMPROCA efproc, LPARAM lpData )
Alexandre Julliard's avatar
Alexandre Julliard committed
791
{
792
    LOGFONTA lf, *plf;
Alexandre Julliard's avatar
Alexandre Julliard committed
793

794 795 796 797
    if (lpFamily)
    {
        if (!*lpFamily) return 1;
        lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
798 799 800
        lf.lfCharSet = DEFAULT_CHARSET;
        lf.lfPitchAndFamily = 0;
        plf = &lf;
801
    }
802
    else plf = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
803

804
    return EnumFontFamiliesExA( hDC, plf, efproc, lpData, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
805 806 807
}

/***********************************************************************
808
 *              EnumFontFamiliesW	(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
809
 */
810 811
INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
                                  FONTENUMPROCW efproc, LPARAM lpData )
Alexandre Julliard's avatar
Alexandre Julliard committed
812
{
813
    LOGFONTW lf, *plf;
Alexandre Julliard's avatar
Alexandre Julliard committed
814

815 816 817 818
    if (lpFamily)
    {
        if (!*lpFamily) return 1;
        lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
819 820 821
        lf.lfCharSet = DEFAULT_CHARSET;
        lf.lfPitchAndFamily = 0;
        plf = &lf;
822
    }
823
    else plf = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
824

825
    return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
826 827 828
}

/***********************************************************************
829
 *              EnumFontsA		(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
830
 */
831
INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
Alexandre Julliard's avatar
Alexandre Julliard committed
832
                           LPARAM lpData )
Alexandre Julliard's avatar
Alexandre Julliard committed
833
{
834
    return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
Alexandre Julliard's avatar
Alexandre Julliard committed
835 836 837
}

/***********************************************************************
838
 *              EnumFontsW		(GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
839
 */
840
INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
Alexandre Julliard's avatar
Alexandre Julliard committed
841
                           LPARAM lpData )
Alexandre Julliard's avatar
Alexandre Julliard committed
842
{
843
    return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
Alexandre Julliard's avatar
Alexandre Julliard committed
844
}
Alexandre Julliard's avatar
Alexandre Julliard committed
845 846 847


/***********************************************************************
848
 *           GetTextCharacterExtra    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
849
 */
850
INT WINAPI GetTextCharacterExtra( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
851
{
852
    INT ret;
853
    DC *dc = get_dc_ptr( hdc );
854 855
    if (!dc) return 0x80000000;
    ret = dc->charExtra;
856
    release_dc_ptr( dc );
857
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
858 859 860 861
}


/***********************************************************************
862
 *           SetTextCharacterExtra    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
863
 */
864
INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
Alexandre Julliard's avatar
Alexandre Julliard committed
865
{
866
    INT ret = 0x80000000;
867
    DC * dc = get_dc_ptr( hdc );
868 869

    if (dc)
870
    {
871 872 873 874 875 876 877 878
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextCharacterExtra );
        extra = physdev->funcs->pSetTextCharacterExtra( physdev, extra );
        if (extra != 0x80000000)
        {
            ret = dc->charExtra;
            dc->charExtra = extra;
        }
        release_dc_ptr( dc );
879
    }
880
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
881 882 883
}


Alexandre Julliard's avatar
Alexandre Julliard committed
884
/***********************************************************************
885
 *           SetTextJustification    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
886
 */
887
BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
Alexandre Julliard's avatar
Alexandre Julliard committed
888
{
889 890
    BOOL ret;
    PHYSDEV physdev;
891
    DC * dc = get_dc_ptr( hdc );
892

893
    if (!dc) return FALSE;
894 895 896 897

    physdev = GET_DC_PHYSDEV( dc, pSetTextJustification );
    ret = physdev->funcs->pSetTextJustification( physdev, extra, breaks );
    if (ret)
Alexandre Julliard's avatar
Alexandre Julliard committed
898
    {
899 900 901 902
        extra = abs((extra * dc->vportExtX + dc->wndExtX / 2) / dc->wndExtX);
        if (!extra) breaks = 0;
        if (breaks)
        {
903
            dc->breakExtra = extra / breaks;
904
            dc->breakRem   = extra - (breaks * dc->breakExtra);
905 906 907
        }
        else
        {
908 909
            dc->breakExtra = 0;
            dc->breakRem   = 0;
910
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
911
    }
912
    release_dc_ptr( dc );
913
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
914 915
}

Alexandre Julliard's avatar
Alexandre Julliard committed
916

Alexandre Julliard's avatar
Alexandre Julliard committed
917
/***********************************************************************
918
 *           GetTextFaceA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
919
 */
920
INT WINAPI GetTextFaceA( HDC hdc, INT count, LPSTR name )
921 922 923 924
{
    INT res = GetTextFaceW(hdc, 0, NULL);
    LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
    GetTextFaceW( hdc, res, nameW );
925

926
    if (name)
927
    {
928 929 930 931 932
        if (count)
        {
            res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
            if (res == 0)
                res = count;
933
            name[count-1] = 0;
934 935 936 937 938
            /* GetTextFaceA does NOT include the nul byte in the return count.  */
            res--;
        }
        else
            res = 0;
939
    }
940 941 942 943 944 945 946 947 948 949
    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
950
{
951 952
    PHYSDEV dev;
    INT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
953

954
    DC * dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
955
    if (!dc) return 0;
956

957 958
    dev = GET_DC_PHYSDEV( dc, pGetTextFace );
    ret = dev->funcs->pGetTextFace( dev, count, name );
959
    release_dc_ptr( dc );
960
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
961 962 963
}


Alexandre Julliard's avatar
Alexandre Julliard committed
964
/***********************************************************************
965
 *           GetTextExtentPoint32A    (GDI32.@)
966 967
 *
 * See GetTextExtentPoint32W.
Alexandre Julliard's avatar
Alexandre Julliard committed
968
 */
969 970
BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
                                     LPSIZE size )
Alexandre Julliard's avatar
Alexandre Julliard committed
971
{
972
    BOOL ret = FALSE;
973
    INT wlen;
974
    LPWSTR p;
Hidenori Takeshima's avatar
Hidenori Takeshima committed
975

976 977 978 979 980 981
    if (count < 0) return FALSE;

    p = FONT_mbtowc(hdc, str, count, &wlen, NULL);

    if (p)
    {
982 983
	ret = GetTextExtentPoint32W( hdc, p, wlen, size );
	HeapFree( GetProcessHeap(), 0, p );
984
    }
985

986
    TRACE("(%p %s %d %p): returning %d x %d\n",
987
          hdc, debugstr_an (str, count), count, size, size->cx, size->cy );
988
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
989 990 991
}


Alexandre Julliard's avatar
Alexandre Julliard committed
992
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
993 994 995
 * GetTextExtentPoint32W [GDI32.@]
 *
 * Computes width/height for a string.
Alexandre Julliard's avatar
Alexandre Julliard committed
996 997 998 999 1000 1001
 *
 * Computes width and height of the specified string.
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1002
 */
1003 1004
BOOL WINAPI GetTextExtentPoint32W(
    HDC hdc,     /* [in]  Handle of device context */
Alexandre Julliard's avatar
Alexandre Julliard committed
1005
    LPCWSTR str,   /* [in]  Address of text string */
1006 1007
    INT count,   /* [in]  Number of characters in string */
    LPSIZE size) /* [out] Address of structure for string size */
Alexandre Julliard's avatar
Alexandre Julliard committed
1008
{
1009
    return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
Alexandre Julliard's avatar
Alexandre Julliard committed
1010 1011
}

1012
/***********************************************************************
1013
 * GetTextExtentExPointI [GDI32.@]
1014 1015 1016
 *
 * Computes width and height of the array of glyph indices.
 *
1017 1018 1019 1020 1021 1022 1023 1024 1025
 * 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.
 *
1026 1027 1028 1029
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
1030 1031
BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
                                   LPINT nfit, LPINT dxs, LPSIZE size )
1032
{
1033 1034
    PHYSDEV dev;
    BOOL ret;
1035 1036 1037 1038 1039
    DC *dc;

    if (count < 0) return FALSE;

    dc = get_dc_ptr( hdc );
1040 1041
    if (!dc) return FALSE;

1042 1043 1044 1045 1046
    dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI );
    ret = dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, nfit, dxs, size );
    size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
    size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
    size->cx += count * dc->charExtra;
1047
    release_dc_ptr( dc );
1048

1049
    TRACE("(%p %p %d %p): returning %d x %d\n",
1050 1051 1052 1053
          hdc, indices, count, size, size->cx, size->cy );
    return ret;
}

1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
/***********************************************************************
 * 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
1074

Alexandre Julliard's avatar
Alexandre Julliard committed
1075
/***********************************************************************
1076
 *           GetTextExtentPointA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1077
 */
1078 1079
BOOL WINAPI GetTextExtentPointA( HDC hdc, LPCSTR str, INT count,
                                          LPSIZE size )
Alexandre Julliard's avatar
Alexandre Julliard committed
1080
{
1081
    TRACE("not bug compatible.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1082 1083 1084 1085
    return GetTextExtentPoint32A( hdc, str, count, size );
}

/***********************************************************************
1086
 *           GetTextExtentPointW   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1087
 */
1088 1089
BOOL WINAPI GetTextExtentPointW( HDC hdc, LPCWSTR str, INT count,
                                          LPSIZE size )
Alexandre Julliard's avatar
Alexandre Julliard committed
1090
{
1091
    TRACE("not bug compatible.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1092 1093 1094
    return GetTextExtentPoint32W( hdc, str, count, size );
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1095

Alexandre Julliard's avatar
Alexandre Julliard committed
1096
/***********************************************************************
1097
 *           GetTextExtentExPointA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1098
 */
1099
BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count,
1100 1101 1102 1103
				   INT maxExt, LPINT lpnFit,
				   LPINT alpDx, LPSIZE size )
{
    BOOL ret;
1104
    INT wlen;
1105 1106
    INT *walpDx = NULL;
    LPWSTR p = NULL;
1107 1108 1109 1110 1111 1112 1113 1114 1115

    if (count < 0) return FALSE;

    if (alpDx)
    {
        walpDx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
        if (!walpDx) return FALSE;
    }

1116
    p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
    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];
        }
    }
1128
    if (lpnFit) *lpnFit = WideCharToMultiByte(CP_ACP,0,p,*lpnFit,NULL,0,NULL,NULL);
1129
    HeapFree( GetProcessHeap(), 0, p );
1130
    HeapFree( GetProcessHeap(), 0, walpDx );
1131 1132 1133 1134 1135
    return ret;
}


/***********************************************************************
1136
 *           GetTextExtentExPointW    (GDI32.@)
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
 *
 * 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
1147
 * be done by the driver.  However they don't support it yet.  Also I am not
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
 * 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.
1164 1165 1166 1167 1168
 */

BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
				   INT maxExt, LPINT lpnFit,
				   LPINT alpDx, LPSIZE size )
Alexandre Julliard's avatar
Alexandre Julliard committed
1169
{
1170 1171 1172
    INT nFit = 0;
    LPINT dxs = NULL;
    DC *dc;
1173
    BOOL ret = FALSE;
1174
    TEXTMETRICW tm;
1175
    PHYSDEV dev;
Alexandre Julliard's avatar
Alexandre Julliard committed
1176

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

1179 1180
    if (count < 0) return FALSE;

1181
    dc = get_dc_ptr(hdc);
1182
    if (!dc) return FALSE;
1183

1184 1185
    GetTextMetricsW(hdc, &tm);

1186 1187 1188
    /* 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
1189
    {
1190 1191 1192
	dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]);
	if (! dxs)
	{
1193
	    release_dc_ptr(dc);
1194 1195 1196
	    SetLastError(ERROR_OUTOFMEMORY);
	    return FALSE;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1197
    }
1198 1199
    else
	dxs = alpDx;
Alexandre Julliard's avatar
Alexandre Julliard committed
1200

1201 1202
    dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint );
    ret = dev->funcs->pGetTextExtentExPoint(dev, str, count, 0, NULL, dxs, size);
Gerald Pfeifer's avatar
Gerald Pfeifer committed
1203

1204 1205 1206
    /* Perform device size to world size transformations.  */
    if (ret)
    {
1207 1208 1209 1210
	INT extra      = dc->charExtra,
        breakExtra = dc->breakExtra,
        breakRem   = dc->breakRem,
        i;
1211 1212 1213 1214 1215 1216

	if (dxs)
	{
	    for (i = 0; i < count; ++i)
	    {
		dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
		dxs[i] += (i+1) * extra;
                if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
                {
                    dxs[i] += breakExtra;
                    if (breakRem > 0)
                    {
                        breakRem--;
                        dxs[i]++;
                    }
                }
1227 1228 1229
		if (dxs[i] <= maxExt)
		    ++nFit;
	    }
1230
            breakRem = dc->breakRem;
1231 1232 1233
	}
	size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
	size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249

        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)++;
                    }
                }
            }
        }
1250 1251 1252 1253 1254
    }

    if (lpnFit)
	*lpnFit = nFit;

1255
    if (! alpDx)
1256 1257
        HeapFree(GetProcessHeap(), 0, dxs);

1258
    release_dc_ptr( dc );
1259

1260
    TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy);
1261
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1262 1263
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1264
/***********************************************************************
1265
 *           GetTextMetricsA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1266
 */
1267
BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
{
    TEXTMETRICW tm32;

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

/***********************************************************************
 *           GetTextMetricsW    (GDI32.@)
 */
BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
{
1281
    PHYSDEV physdev;
1282
    BOOL ret = FALSE;
1283
    DC * dc = get_dc_ptr( hdc );
1284
    if (!dc) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1285

1286 1287
    physdev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
    ret = physdev->funcs->pGetTextMetrics( physdev, metrics );
1288 1289

    if (ret)
1290
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1291 1292 1293
    /* device layer returns values in device units
     * therefore we have to convert them to logical */

1294 1295 1296
        metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
        metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);

Alexandre Julliard's avatar
Alexandre Julliard committed
1297
#define WDPTOLP(x) ((x<0)?					\
1298 1299
		(-abs(INTERNAL_XDSTOWS(dc, (x)))):		\
		(abs(INTERNAL_XDSTOWS(dc, (x)))))
Alexandre Julliard's avatar
Alexandre Julliard committed
1300
#define HDPTOLP(y) ((y<0)?					\
1301 1302
		(-abs(INTERNAL_YDSTOWS(dc, (y)))):		\
		(abs(INTERNAL_YDSTOWS(dc, (y)))))
1303

1304 1305 1306 1307 1308 1309 1310 1311
        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);
1312
        ret = TRUE;
1313 1314
#undef WDPTOLP
#undef HDPTOLP
1315
    TRACE("text metrics:\n"
1316 1317 1318
          "    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"
1319
          "    StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1320 1321
          "    PitchAndFamily = %02x\n"
          "    --------------------\n"
1322 1323 1324 1325
          "    InternalLeading = %i\n"
          "    Ascent = %i\n"
          "    Descent = %i\n"
          "    Height = %i\n",
1326 1327 1328 1329 1330 1331 1332 1333 1334
          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 );
1335
    }
1336
    release_dc_ptr( dc );
1337
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1338 1339 1340
}


1341
/***********************************************************************
1342 1343
 *		GetOutlineTextMetricsA (GDI32.@)
 * Gets metrics for TrueType fonts.
1344
 *
1345 1346 1347
 * NOTES
 *    If the supplied buffer isn't big enough Windows partially fills it up to
 *    its given length and returns that length.
1348 1349 1350 1351 1352
 *
 * RETURNS
 *    Success: Non-zero or size of required buffer
 *    Failure: 0
 */
1353 1354 1355 1356
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 */
1357
{
1358 1359 1360
    char buf[512], *ptr;
    UINT ret, needed;
    OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1361
    OUTLINETEXTMETRICA *output = lpOTM;
1362
    INT left, len;
1363

1364 1365 1366
    if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
        return 0;
    if(ret > sizeof(buf))
1367
	lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1368
    GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1369

1370 1371 1372
    needed = sizeof(OUTLINETEXTMETRICA);
    if(lpOTMW->otmpFamilyName)
        needed += WideCharToMultiByte(CP_ACP, 0,
1373
	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1374 1375 1376
				      NULL, 0, NULL, NULL);
    if(lpOTMW->otmpFaceName)
        needed += WideCharToMultiByte(CP_ACP, 0,
1377
	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1378 1379 1380
				      NULL, 0, NULL, NULL);
    if(lpOTMW->otmpStyleName)
        needed += WideCharToMultiByte(CP_ACP, 0,
1381
	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1382 1383 1384
				      NULL, 0, NULL, NULL);
    if(lpOTMW->otmpFullName)
        needed += WideCharToMultiByte(CP_ACP, 0,
1385
	   (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1386 1387 1388 1389 1390 1391
				      NULL, 0, NULL, NULL);

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

1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
    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);
1432 1433

    if(lpOTMW->otmpFamilyName) {
1434
        output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1435
	len = WideCharToMultiByte(CP_ACP, 0,
1436
	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFamilyName), -1,
1437 1438 1439
				  ptr, left, NULL, NULL);
	left -= len;
	ptr += len;
1440
    } else
1441
        output->otmpFamilyName = 0;
1442 1443

    if(lpOTMW->otmpFaceName) {
1444
        output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1445
	len = WideCharToMultiByte(CP_ACP, 0,
1446
	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFaceName), -1,
1447 1448 1449
				  ptr, left, NULL, NULL);
	left -= len;
	ptr += len;
1450
    } else
1451
        output->otmpFaceName = 0;
1452 1453

    if(lpOTMW->otmpStyleName) {
1454
        output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1455
	len = WideCharToMultiByte(CP_ACP, 0,
1456
	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpStyleName), -1,
1457 1458 1459 1460
				  ptr, left, NULL, NULL);
	left -= len;
	ptr += len;
    } else
1461
        output->otmpStyleName = 0;
1462 1463

    if(lpOTMW->otmpFullName) {
1464
        output->otmpFullName = (LPSTR)(ptr - (char*)output);
1465
	len = WideCharToMultiByte(CP_ACP, 0,
1466
	     (WCHAR*)((char*)lpOTMW + (ptrdiff_t)lpOTMW->otmpFullName), -1,
1467 1468 1469
				  ptr, left, NULL, NULL);
	left -= len;
    } else
1470
        output->otmpFullName = 0;
1471

1472
    assert(left == 0);
1473

1474 1475 1476
    if(output != lpOTM) {
        memcpy(lpOTM, output, cbData);
        HeapFree(GetProcessHeap(), 0, output);
1477 1478 1479

        /* check if the string offsets really fit into the provided size */
        /* FIXME: should we check string length as well? */
1480 1481 1482 1483 1484 1485
        /* 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 */
        }
1486

1487 1488 1489 1490 1491 1492
        /* 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 */
        }
1493

1494 1495 1496 1497 1498 1499
            /* 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 */
        }
1500

1501 1502 1503 1504 1505 1506
        /* 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 */
        }
1507
    }
1508 1509 1510 1511 1512 1513

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

    return ret;
1514 1515
}

1516

1517
/***********************************************************************
1518
 *           GetOutlineTextMetricsW [GDI32.@]
1519
 */
1520 1521 1522 1523
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 */
1524
{
1525
    DC *dc = get_dc_ptr( hdc );
1526
    OUTLINETEXTMETRICW *output = lpOTM;
1527
    PHYSDEV dev;
1528 1529
    UINT ret;

1530
    TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
1531 1532
    if(!dc) return 0;

1533 1534
    dev = GET_DC_PHYSDEV( dc, pGetOutlineTextMetrics );
    ret = dev->funcs->pGetOutlineTextMetrics( dev, cbData, output );
1535

1536 1537 1538 1539 1540 1541 1542 1543
    if (lpOTM && ret > cbData)
    {
        output = HeapAlloc(GetProcessHeap(), 0, ret);
        ret = dev->funcs->pGetOutlineTextMetrics( dev, ret, output );
    }

    if (lpOTM && ret)
    {
1544 1545 1546
        output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
        output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);

1547 1548 1549 1550 1551 1552 1553
#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)))))

1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
        output->otmTextMetrics.tmHeight           = HDPTOLP(output->otmTextMetrics.tmHeight);
        output->otmTextMetrics.tmAscent           = HDPTOLP(output->otmTextMetrics.tmAscent);
        output->otmTextMetrics.tmDescent          = HDPTOLP(output->otmTextMetrics.tmDescent);
        output->otmTextMetrics.tmInternalLeading  = HDPTOLP(output->otmTextMetrics.tmInternalLeading);
        output->otmTextMetrics.tmExternalLeading  = HDPTOLP(output->otmTextMetrics.tmExternalLeading);
        output->otmTextMetrics.tmAveCharWidth     = WDPTOLP(output->otmTextMetrics.tmAveCharWidth);
        output->otmTextMetrics.tmMaxCharWidth     = WDPTOLP(output->otmTextMetrics.tmMaxCharWidth);
        output->otmTextMetrics.tmOverhang         = WDPTOLP(output->otmTextMetrics.tmOverhang);
        output->otmAscent = HDPTOLP(output->otmAscent);
        output->otmDescent = HDPTOLP(output->otmDescent);
        output->otmLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmLineGap));
        output->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsCapEmHeight));
        output->otmsXHeight = abs(INTERNAL_YDSTOWS(dc,output->otmsXHeight));
        output->otmrcFontBox.top = HDPTOLP(output->otmrcFontBox.top);
        output->otmrcFontBox.bottom = HDPTOLP(output->otmrcFontBox.bottom);
        output->otmrcFontBox.left = WDPTOLP(output->otmrcFontBox.left);
        output->otmrcFontBox.right = WDPTOLP(output->otmrcFontBox.right);
        output->otmMacAscent = HDPTOLP(output->otmMacAscent);
        output->otmMacDescent = HDPTOLP(output->otmMacDescent);
        output->otmMacLineGap = abs(INTERNAL_YDSTOWS(dc,output->otmMacLineGap));
        output->otmptSubscriptSize.x = WDPTOLP(output->otmptSubscriptSize.x);
        output->otmptSubscriptSize.y = HDPTOLP(output->otmptSubscriptSize.y);
        output->otmptSubscriptOffset.x = WDPTOLP(output->otmptSubscriptOffset.x);
        output->otmptSubscriptOffset.y = HDPTOLP(output->otmptSubscriptOffset.y);
        output->otmptSuperscriptSize.x = WDPTOLP(output->otmptSuperscriptSize.x);
        output->otmptSuperscriptSize.y = HDPTOLP(output->otmptSuperscriptSize.y);
        output->otmptSuperscriptOffset.x = WDPTOLP(output->otmptSuperscriptOffset.x);
        output->otmptSuperscriptOffset.y = HDPTOLP(output->otmptSuperscriptOffset.y);
        output->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(dc,output->otmsStrikeoutSize));
        output->otmsStrikeoutPosition = HDPTOLP(output->otmsStrikeoutPosition);
        output->otmsUnderscoreSize = HDPTOLP(output->otmsUnderscoreSize);
        output->otmsUnderscorePosition = HDPTOLP(output->otmsUnderscorePosition);
1586 1587
#undef WDPTOLP
#undef HDPTOLP
1588 1589 1590 1591 1592 1593
        if(output != lpOTM)
        {
            memcpy(lpOTM, output, cbData);
            HeapFree(GetProcessHeap(), 0, output);
            ret = cbData;
        }
1594
    }
1595
    release_dc_ptr(dc);
1596
    return ret;
1597
}
1598

1599
static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
1600 1601
{
    INT i, count = lastChar - firstChar + 1;
1602
    UINT mbcp;
1603 1604 1605 1606 1607 1608
    UINT c;
    LPSTR str;

    if (count <= 0)
        return NULL;

1609 1610
    mbcp = GdiGetCodePage(hdc);
    switch (mbcp)
1611 1612 1613 1614 1615 1616 1617 1618
    {
    case 932:
    case 936:
    case 949:
    case 950:
    case 1361:
        if (lastChar > 0xffff)
            return NULL;
1619 1620
        if ((firstChar ^ lastChar) > 0xff)
            return NULL;
1621 1622 1623 1624
        break;
    default:
        if (lastChar > 0xff)
            return NULL;
1625
        mbcp = 0;
1626 1627 1628
        break;
    }

1629 1630 1631 1632 1633 1634
    str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
    if (str == NULL)
        return NULL;

    for(i = 0, c = firstChar; c <= lastChar; i++, c++)
    {
1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
        if (mbcp) {
            if (c > 0xff)
                str[i++] = (BYTE)(c >> 8);
            if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
                str[i] = 0x1f; /* FIXME: use default character */
            else
                str[i] = (BYTE)c;
        }
        else
            str[i] = (BYTE)c;
1645 1646 1647 1648 1649 1650 1651
    }
    str[i] = '\0';

    *pByteLen = i;

    return str;
}
1652

Alexandre Julliard's avatar
Alexandre Julliard committed
1653
/***********************************************************************
1654 1655
 *           GetCharWidthW      (GDI32.@)
 *           GetCharWidth32W    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1656
 */
1657
BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
1658
                               LPINT buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
1659
{
1660
    UINT i;
1661
    BOOL ret;
1662
    PHYSDEV dev;
1663
    DC * dc = get_dc_ptr( hdc );
1664

1665
    if (!dc) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1666

1667 1668
    dev = GET_DC_PHYSDEV( dc, pGetCharWidth );
    ret = dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
1669 1670

    if (ret)
1671 1672 1673
    {
        /* convert device units to logical */
        for( i = firstChar; i <= lastChar; i++, buffer++ )
1674
            *buffer = INTERNAL_XDSTOWS(dc, *buffer);
1675
    }
1676
    release_dc_ptr( dc );
1677
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1678
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1679

Alexandre Julliard's avatar
Alexandre Julliard committed
1680

Alexandre Julliard's avatar
Alexandre Julliard committed
1681
/***********************************************************************
1682 1683
 *           GetCharWidthA      (GDI32.@)
 *           GetCharWidth32A    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1684
 */
1685
BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
1686
                               LPINT buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
1687
{
1688
    INT i, wlen;
1689 1690 1691 1692
    LPSTR str;
    LPWSTR wstr;
    BOOL ret = TRUE;

1693
    str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
1694 1695
    if(str == NULL)
        return FALSE;
1696

1697
    wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712

    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
1713 1714 1715
}


1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728
/* helper for nulldrv_ExtTextOut */
static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags,
                               GLYPHMETRICS *metrics, struct gdi_image_bits *image )
{
    UINT ggo_flags = aa_flags | GGO_GLYPH_INDEX;
    static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
    UINT indices[3] = {0, 0, 0x20};
    int i;
    DWORD ret, size;
    int stride;

    indices[0] = index;

1729
    for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
1730
    {
1731
        index = indices[i];
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
        ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, 0, NULL, &identity );
        if (ret != GDI_ERROR) break;
    }

    if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
    if (!image) return ERROR_SUCCESS;

    image->ptr = NULL;
    image->free = NULL;
    if (!ret) return ERROR_SUCCESS; /* empty glyph */

    stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
    size = metrics->gmBlackBoxY * stride;

    if (!(image->ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
    image->is_copy = TRUE;
    image->free = free_heap_bits;

    ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, size, image->ptr, &identity );
    if (ret == GDI_ERROR)
    {
        HeapFree( GetProcessHeap(), 0, image->ptr );
        return ERROR_NOT_FOUND;
    }
    return ERROR_SUCCESS;
}

1759 1760 1761 1762 1763
/* helper for nulldrv_ExtTextOut */
static RECT get_total_extents( HDC hdc, INT x, INT y, UINT flags, UINT aa_flags,
                               LPCWSTR str, UINT count, const INT *dx )
{
    int i;
1764
    RECT rect, bounds;
1765

1766
    reset_bounds( &bounds );
1767 1768 1769 1770 1771 1772
    for (i = 0; i < count; i++)
    {
        GLYPHMETRICS metrics;

        if (get_glyph_bitmap( hdc, (UINT)str[i], aa_flags, &metrics, NULL )) continue;

1773 1774 1775 1776 1777
        rect.left   = x + metrics.gmptGlyphOrigin.x;
        rect.top    = y - metrics.gmptGlyphOrigin.y;
        rect.right  = rect.left + metrics.gmBlackBoxX;
        rect.bottom = rect.top  + metrics.gmBlackBoxY;
        add_bounds_rect( &bounds, &rect );
1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793

        if (dx)
        {
            if (flags & ETO_PDY)
            {
                x += dx[ i * 2 ];
                y += dx[ i * 2 + 1];
            }
            else x += dx[ i ];
        }
        else
        {
            x += metrics.gmCellIncX;
            y += metrics.gmCellIncY;
        }
    }
1794
    return bounds;
1795 1796
}

1797 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 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846
/* helper for nulldrv_ExtTextOut */
static void draw_glyph( HDC hdc, INT origin_x, INT origin_y, const GLYPHMETRICS *metrics,
                        const struct gdi_image_bits *image, const RECT *clip )
{
    static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
    UINT x, y, i, count;
    BYTE *ptr = image->ptr;
    int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
    POINT *pts;
    RECT rect, clipped_rect;

    rect.left   = origin_x  + metrics->gmptGlyphOrigin.x;
    rect.top    = origin_y  - metrics->gmptGlyphOrigin.y;
    rect.right  = rect.left + metrics->gmBlackBoxX;
    rect.bottom = rect.top  + metrics->gmBlackBoxY;
    if (!clip) clipped_rect = rect;
    else if (!intersect_rect( &clipped_rect, &rect, clip )) return;

    pts = HeapAlloc( GetProcessHeap(), 0,
                     max(2,metrics->gmBlackBoxX) * metrics->gmBlackBoxY * sizeof(*pts) );
    if (!pts) return;

    count = 0;
    ptr += (clipped_rect.top - rect.top) * stride;
    for (y = clipped_rect.top; y < clipped_rect.bottom; y++, ptr += stride)
    {
        for (x = clipped_rect.left - rect.left; x < clipped_rect.right - rect.left; x++)
        {
            while (x < clipped_rect.right - rect.left && !(ptr[x / 8] & masks[x % 8])) x++;
            pts[count].x = rect.left + x;
            while (x < clipped_rect.right - rect.left && (ptr[x / 8] & masks[x % 8])) x++;
            pts[count + 1].x = rect.left + x;
            if (pts[count + 1].x > pts[count].x)
            {
                pts[count].y = pts[count + 1].y = y;
                count += 2;
            }
        }
    }
    DPtoLP( hdc, pts, count );
    for (i = 0; i < count; i += 2) Polyline( hdc, pts + i, 2 );
    HeapFree( GetProcessHeap(), 0, pts );
}

/***********************************************************************
 *           nulldrv_ExtTextOut
 */
BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect,
                         LPCWSTR str, UINT count, const INT *dx )
{
1847 1848
    DC *dc = get_nulldrv_dc( dev );
    UINT aa_flags, i;
1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869
    DWORD err;
    HGDIOBJ orig;
    HPEN pen;

    if (flags & ETO_OPAQUE)
    {
        RECT rc = *rect;
        HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, GetBkColor(dev->hdc) ));

        if (brush)
        {
            orig = SelectObject( dev->hdc, brush );
            DPtoLP( dev->hdc, (POINT *)&rc, 2 );
            PatBlt( dev->hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY );
            SelectObject( dev->hdc, orig );
            DeleteObject( brush );
        }
    }

    if (!count) return TRUE;

1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
    aa_flags = get_font_aa_flags( dev->hdc );

    if (aa_flags != GGO_BITMAP)
    {
        char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
        BITMAPINFO *info = (BITMAPINFO *)buffer;
        struct gdi_image_bits bits;
        struct bitblt_coords src, dst;
        PHYSDEV dst_dev;

        dst_dev = GET_DC_PHYSDEV( dc, pPutImage );
        src.visrect = get_total_extents( dev->hdc, x, y, flags, aa_flags, str, count, dx );
        if (flags & ETO_CLIPPED) intersect_rect( &src.visrect, &src.visrect, rect );
1883
        if (!clip_visrect( dc, &src.visrect, &src.visrect )) return TRUE;
1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946

        /* FIXME: check for ETO_OPAQUE and avoid GetImage */
        src.x = src.visrect.left;
        src.y = src.visrect.top;
        src.width = src.visrect.right - src.visrect.left;
        src.height = src.visrect.bottom - src.visrect.top;
        dst = src;
        if ((flags & ETO_OPAQUE) && (src.visrect.left >= rect->left) && (src.visrect.top >= rect->top) &&
            (src.visrect.right <= rect->right) && (src.visrect.bottom <= rect->bottom))
        {
            /* we can avoid the GetImage, just query the needed format */
            memset( &info->bmiHeader, 0, sizeof(info->bmiHeader) );
            info->bmiHeader.biSize   = sizeof(info->bmiHeader);
            info->bmiHeader.biWidth  = src.width;
            info->bmiHeader.biHeight = -src.height;
            err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, info, NULL, NULL, NULL, 0 );
            if (!err || err == ERROR_BAD_FORMAT)
            {
                /* make the source rectangle relative to the source bits */
                src.x = src.y = 0;
                src.visrect.left = src.visrect.top = 0;
                src.visrect.right = src.width;
                src.visrect.bottom = src.height;

                bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
                if (!bits.ptr) return ERROR_OUTOFMEMORY;
                bits.is_copy = TRUE;
                bits.free = free_heap_bits;
                err = ERROR_SUCCESS;
            }
        }
        else
        {
            PHYSDEV src_dev = GET_DC_PHYSDEV( dc, pGetImage );
            err = src_dev->funcs->pGetImage( src_dev, 0, info, &bits, &src );
            if (!err && !bits.is_copy)
            {
                void *ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ));
                if (!ptr)
                {
                    if (bits.free) bits.free( &bits );
                    return ERROR_OUTOFMEMORY;
                }
                memcpy( ptr, bits.ptr, get_dib_image_size( info ));
                if (bits.free) bits.free( &bits );
                bits.ptr = ptr;
                bits.is_copy = TRUE;
                bits.free = free_heap_bits;
            }
        }
        if (!err)
        {
            /* make x,y relative to the image bits */
            x += src.visrect.left - dst.visrect.left;
            y += src.visrect.top - dst.visrect.top;
            render_aa_text_bitmapinfo( dev->hdc, info, &bits, &src, x, y, flags,
                                       aa_flags, str, count, dx );
            err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, info, &bits, &src, &dst, SRCCOPY );
            if (bits.free) bits.free( &bits );
            return !err;
        }
    }

1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982
    pen = CreatePen( PS_SOLID, 1, GetTextColor(dev->hdc) );
    orig = SelectObject( dev->hdc, pen );

    for (i = 0; i < count; i++)
    {
        GLYPHMETRICS metrics;
        struct gdi_image_bits image;

        err = get_glyph_bitmap( dev->hdc, (UINT)str[i], GGO_BITMAP, &metrics, &image );
        if (err) continue;

        if (image.ptr) draw_glyph( dev->hdc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
        if (image.free) image.free( &image );

        if (dx)
        {
            if (flags & ETO_PDY)
            {
                x += dx[ i * 2 ];
                y += dx[ i * 2 + 1];
            }
            else x += dx[ i ];
        }
        else
        {
            x += metrics.gmCellIncX;
            y += metrics.gmCellIncY;
        }
    }

    SelectObject( dev->hdc, orig );
    DeleteObject( pen );
    return TRUE;
}


1983 1984
/***********************************************************************
 *           ExtTextOutA    (GDI32.@)
1985 1986
 *
 * See ExtTextOutW.
1987 1988 1989 1990 1991
 */
BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
                         const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
{
    INT wlen;
1992
    UINT codepage;
1993
    LPWSTR p;
1994 1995 1996
    BOOL ret;
    LPINT lpDxW = NULL;

1997 1998 1999
    if (flags & ETO_GLYPH_INDEX)
        return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );

2000
    p = FONT_mbtowc(hdc, str, count, &wlen, &codepage);
2001

2002 2003 2004
    if (lpDx) {
        unsigned int i = 0, j = 0;

2005 2006
        /* allocate enough for a ETO_PDY */
        lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
2007
        while(i < count) {
2008 2009 2010 2011 2012 2013 2014 2015 2016
            if(IsDBCSLeadByteEx(codepage, str[i]))
            {
                if(flags & ETO_PDY)
                {
                    lpDxW[j++] = lpDx[i * 2]     + lpDx[(i + 1) * 2];
                    lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
                }
                else
                    lpDxW[j++] = lpDx[i] + lpDx[i + 1];
2017
                i = i + 2;
2018 2019 2020 2021 2022 2023 2024 2025 2026 2027
            }
            else
            {
                if(flags & ETO_PDY)
                {
                    lpDxW[j++] = lpDx[i * 2];
                    lpDxW[j++] = lpDx[i * 2 + 1];
                }
                else
                    lpDxW[j++] = lpDx[i];
2028 2029 2030 2031 2032 2033 2034 2035
                i = i + 1;
            }
        }
    }

    ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );

    HeapFree( GetProcessHeap(), 0, p );
2036
    HeapFree( GetProcessHeap(), 0, lpDxW );
2037 2038 2039 2040 2041 2042
    return ret;
}


/***********************************************************************
 *           ExtTextOutW    (GDI32.@)
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069
 *
 * 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
2070 2071 2072 2073 2074
 */
BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
                         const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
{
    BOOL ret = FALSE;
2075
    LPWSTR reordered_str = (LPWSTR)str;
2076
    WORD *glyphs = NULL;
2077
    UINT align = GetTextAlign( hdc );
2078
    DWORD layout = GetLayout( hdc );
2079 2080 2081 2082
    POINT pt;
    TEXTMETRICW tm;
    LOGFONTW lf;
    double cosEsc, sinEsc;
2083
    INT char_extra;
2084 2085 2086
    SIZE sz;
    RECT rc;
    BOOL done_extents = FALSE;
2087
    POINT *deltas = NULL, width = {0, 0};
2088
    DWORD type;
2089
    DC * dc = get_dc_ptr( hdc );
2090
    PHYSDEV physdev;
2091
    INT breakRem;
2092
    static int quietfixme = 0;
2093 2094 2095

    if (!dc) return FALSE;

2096 2097
    breakRem = dc->breakRem;

2098
    if (quietfixme == 0 && flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN))
2099
    {
2100
        FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2101 2102
        quietfixme = 1;
    }
2103

2104
    update_dc( dc );
2105
    physdev = GET_DC_PHYSDEV( dc, pExtTextOut );
2106 2107 2108
    type = GetObjectType(hdc);
    if(type == OBJ_METADC || type == OBJ_ENHMETADC)
    {
2109
        ret = physdev->funcs->pExtTextOut( physdev, x, y, flags, lprect, str, count, lpDx );
2110
        release_dc_ptr( dc );
2111 2112
        return ret;
    }
2113 2114 2115

    if (!lprect)
        flags &= ~ETO_CLIPPED;
2116 2117 2118 2119 2120 2121 2122 2123

    if (flags & ETO_RTLREADING) align |= TA_RTLREADING;
    if (layout & LAYOUT_RTL)
    {
        if ((align & TA_CENTER) != TA_CENTER) align ^= TA_RIGHT;
        align ^= TA_RTLREADING;
    }

2124
    if( !(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0 )
2125
    {
2126
        INT cGlyphs;
2127 2128
        reordered_str = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));

2129
        BIDI_Reorder( hdc, str, count, GCP_REORDER,
2130
                      (align & TA_RTLREADING) ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR,
2131
                      reordered_str, count, NULL, &glyphs, &cGlyphs);
2132

2133
        flags |= ETO_IGNORELANGUAGE;
2134
        if (glyphs)
2135
        {
2136
            flags |= ETO_GLYPH_INDEX;
2137 2138 2139
            if (cGlyphs != count)
                count = cGlyphs;
        }
2140
    }
2141 2142
    else if(flags & ETO_GLYPH_INDEX)
        glyphs = reordered_str;
2143

2144 2145
    TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc, x, y, flags,
          wine_dbgstr_rect(lprect), debugstr_wn(str, count), count, lpDx);
2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160
    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;

2161 2162 2163 2164 2165 2166
    if ((dc->GraphicsMode == GM_COMPATIBLE) &&
        (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0))
    {
        lf.lfEscapement = -lf.lfEscapement;
    }

2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203
    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;}
    }

2204
    if (lprect && (flags & ETO_OPAQUE))
2205
        physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
2206

2207
    if(count == 0)
2208 2209
    {
        ret = TRUE;
2210
        goto done;
2211
    }
2212 2213 2214 2215 2216 2217 2218 2219

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

    char_extra = GetTextCharacterExtra(hdc);
2220
    if(char_extra || dc->breakExtra || breakRem || lpDx || lf.lfEscapement != 0)
2221 2222 2223
    {
        UINT i;
        SIZE tmpsz;
2224 2225 2226
        POINT total = {0, 0}, desired[2];

        deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2227
        for(i = 0; i < count; i++)
2228
        {
2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242
            if(lpDx)
            {
                if(flags & ETO_PDY)
                {
                    deltas[i].x = lpDx[i * 2] + char_extra;
                    deltas[i].y = -lpDx[i * 2 + 1];
                }
                else
                {
                    deltas[i].x = lpDx[i] + char_extra;
                    deltas[i].y = 0;
                }

            }
2243
            else
2244
            {
2245 2246 2247 2248
                if(flags & ETO_GLYPH_INDEX)
                    GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
                else
                    GetTextExtentPointW(hdc, reordered_str + i, 1, &tmpsz);
2249

2250 2251
                deltas[i].x = tmpsz.cx;
                deltas[i].y = 0;
2252 2253
            }
            
2254
            if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
2255
            {
2256
                deltas[i].x = deltas[i].x + dc->breakExtra;
2257 2258 2259
                if (breakRem > 0)
                {
                    breakRem--;
2260
                    deltas[i].x++;
2261
                }
2262
            }
2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273
            total.x += deltas[i].x;
            total.y += deltas[i].y;

            desired[0].x = desired[0].y = 0;

            desired[1].x =  cosEsc * total.x + sinEsc * total.y;
            desired[1].y = -sinEsc * total.x + cosEsc * total.y;

            LPtoDP(hdc, desired, 2);
            desired[1].x -= desired[0].x;
            desired[1].y -= desired[0].y;
2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285

            if (dc->GraphicsMode == GM_COMPATIBLE)
            {
                if (dc->vport2WorldValid && dc->xformWorld2Vport.eM11 < 0)
                    desired[1].x = -desired[1].x;
                if (dc->vport2WorldValid && dc->xformWorld2Vport.eM22 < 0)
                    desired[1].y = -desired[1].y;
            }
            else
            {
                if (layout & LAYOUT_RTL) desired[1].x = -desired[1].x;
            }
2286 2287 2288 2289 2290

            deltas[i].x = desired[1].x - width.x;
            deltas[i].y = desired[1].y - width.y;

            width = desired[1];
2291
        }
2292
        flags |= ETO_PDY;
2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303
    }
    else
    {
        if(!done_extents)
        {
            if(flags & ETO_GLYPH_INDEX)
                GetTextExtentPointI(hdc, glyphs, count, &sz);
            else
                GetTextExtentPointW(hdc, reordered_str, count, &sz);
            done_extents = TRUE;
        }
2304
        width.x = abs(INTERNAL_XWSTODS(dc, sz.cx));
2305
        width.y = 0;
2306 2307 2308 2309 2310 2311 2312 2313 2314
    }

    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)
        {
2315
            pt.x = x + width.x;
2316
            pt.y = y + width.y;
2317 2318 2319 2320 2321 2322
            DPtoLP(hdc, &pt, 1);
            MoveToEx(hdc, pt.x, pt.y, NULL);
        }
        break;

    case TA_CENTER:
2323
        x -= width.x / 2;
2324
        y -= width.y / 2;
2325
        break;
2326

2327
    case TA_RIGHT:
2328
        x -= width.x;
2329
        y -= width.y;
2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355
        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;
    }

2356
    if (GetBkMode(hdc) != TRANSPARENT)
2357 2358 2359
    {
        if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE)))
        {
2360 2361
            if(!(flags & ETO_OPAQUE) || !lprect ||
               x < rc.left || x + width.x >= rc.right ||
2362 2363
               y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom)
            {
2364 2365 2366 2367 2368
                RECT text_box;
                text_box.left = x;
                text_box.right = x + width.x;
                text_box.top = y - tm.tmAscent;
                text_box.bottom = y + tm.tmDescent;
2369

2370 2371
                if (flags & ETO_CLIPPED) intersect_rect( &text_box, &text_box, &rc );
                if (!is_rect_empty( &text_box ))
2372
                    physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &text_box, NULL, 0, NULL );
2373
            }
2374 2375
        }
    }
2376

2377 2378 2379 2380
    if(FontIsLinked(hdc) && !(flags & ETO_GLYPH_INDEX))
    {
        HFONT orig_font = dc->hFont, cur_font;
        UINT glyph;
2381 2382
        INT span = 0;
        POINT *offsets = NULL;
2383
        unsigned int i;
2384

2385
        glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD));
2386 2387 2388 2389 2390 2391 2392
        for(i = 0; i < count; i++)
        {
            WineEngGetLinkedHFont(dc, reordered_str[i], &cur_font, &glyph);
            if(cur_font != dc->hFont)
            {
                if(!offsets)
                {
2393
                    unsigned int j;
2394
                    offsets = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
2395 2396
                    offsets[0].x = offsets[0].y = 0;

2397 2398 2399 2400 2401 2402
                    if(!deltas)
                    {
                        SIZE tmpsz;
                        for(j = 1; j < count; j++)
                        {
                            GetTextExtentPointW(hdc, reordered_str + j - 1, 1, &tmpsz);
2403
                            offsets[j].x = offsets[j - 1].x + abs(INTERNAL_XWSTODS(dc, tmpsz.cx));
2404
                            offsets[j].y = 0;
2405 2406 2407 2408 2409
                        }
                    }
                    else
                    {
                        for(j = 1; j < count; j++)
2410 2411 2412 2413
                        {
                            offsets[j].x = offsets[j - 1].x + deltas[j].x;
                            offsets[j].y = offsets[j - 1].y + deltas[j].y;
                        }
2414 2415 2416 2417
                    }
                }
                if(span)
                {
2418 2419 2420 2421
                    physdev->funcs->pExtTextOut( physdev, x + offsets[i - span].x,
                                                 y + offsets[i - span].y,
                                                 (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc, glyphs,
                                                 span, deltas ? (INT*)(deltas + (i - span)) : NULL);
2422 2423 2424 2425 2426 2427 2428 2429
                    span = 0;
                }
                SelectObject(hdc, cur_font);
            }
            glyphs[span++] = glyph;

            if(i == count - 1)
            {
2430 2431 2432 2433
                ret = physdev->funcs->pExtTextOut(physdev, x + (offsets ? offsets[count - span].x : 0),
                                                  y + (offsets ? offsets[count - span].y : 0),
                                                  (flags & ~ETO_OPAQUE) | ETO_GLYPH_INDEX, &rc, glyphs,
                                                  span, deltas ? (INT*)(deltas + (count - span)) : NULL);
2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446
                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;
        }
2447 2448
        ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc,
                                           glyphs ? glyphs : reordered_str, count, (INT*)deltas );
2449
    }
2450

2451 2452 2453 2454 2455 2456 2457
done:
    HeapFree(GetProcessHeap(), 0, deltas);
    if(glyphs != reordered_str)
        HeapFree(GetProcessHeap(), 0, glyphs);
    if(reordered_str != str)
        HeapFree(GetProcessHeap(), 0, reordered_str);

2458
    release_dc_ptr( dc );
2459 2460

    if (ret && (lf.lfUnderline || lf.lfStrikeOut))
2461 2462 2463
    {
        int underlinePos, strikeoutPos;
        int underlineWidth, strikeoutWidth;
2464
        UINT size = GetOutlineTextMetricsW(hdc, 0, NULL);
2465
        OUTLINETEXTMETRICW* otm = NULL;
2466 2467 2468 2469 2470
        POINT pts[5];
        HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
        HBRUSH hbrush = CreateSolidBrush(GetTextColor(hdc));

        hbrush = SelectObject(hdc, hbrush);
2471

2472
        if(!size)
2473 2474 2475 2476 2477 2478 2479 2480
        {
            underlinePos = 0;
            underlineWidth = tm.tmAscent / 20 + 1;
            strikeoutPos = tm.tmAscent / 2;
            strikeoutWidth = underlineWidth;
        }
        else
        {
2481 2482
            otm = HeapAlloc(GetProcessHeap(), 0, size);
            GetOutlineTextMetricsW(hdc, size, otm);
2483 2484 2485 2486 2487 2488 2489
            underlinePos = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscorePosition ));
            if (otm->otmsUnderscorePosition < 0) underlinePos = -underlinePos;
            underlineWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsUnderscoreSize ));
            if (otm->otmsUnderscoreSize < 0) underlineWidth = -underlineWidth;
            strikeoutPos = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutPosition ));
            if (otm->otmsStrikeoutPosition < 0) strikeoutPos = -strikeoutPos;
            strikeoutWidth = abs( INTERNAL_YWSTODS( dc, otm->otmsStrikeoutSize ));
2490
            HeapFree(GetProcessHeap(), 0, otm);
2491 2492 2493
        }


2494
        if (lf.lfUnderline)
2495
        {
2496 2497 2498 2499
            pts[0].x = x - (underlinePos + underlineWidth / 2) * sinEsc;
            pts[0].y = y - (underlinePos + underlineWidth / 2) * cosEsc;
            pts[1].x = x + width.x - (underlinePos + underlineWidth / 2) * sinEsc;
            pts[1].y = y + width.y - (underlinePos + underlineWidth / 2) * cosEsc;
2500 2501 2502 2503 2504 2505 2506 2507 2508
            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);
        }
2509

2510 2511
        if (lf.lfStrikeOut)
        {
2512 2513 2514 2515
            pts[0].x = x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
            pts[0].y = y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
            pts[1].x = x + width.x - (strikeoutPos + strikeoutWidth / 2) * sinEsc;
            pts[1].y = y + width.y - (strikeoutPos + strikeoutWidth / 2) * cosEsc;
2516 2517 2518 2519 2520 2521 2522 2523
            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);
2524
        }
2525 2526 2527 2528

        SelectObject(hdc, hpen);
        hbrush = SelectObject(hdc, hbrush);
        DeleteObject(hbrush);
2529
    }
2530

2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555
    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.@)
 *
2556
 * See PolyTextOutW.
2557
 */
2558
BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pptxt, INT cStrings )
2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571
{
    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
2572 2573 2574 2575
 *
 * RETURNS
 *  TRUE:  Success.
 *  FALSE: Failure.
2576
 */
2577
BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pptxt, INT cStrings )
2578 2579 2580 2581 2582 2583 2584 2585
{
    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;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2586
/***********************************************************************
2587
 *           SetMapperFlags    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2588
 */
2589
DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
2590
{
2591 2592 2593 2594
    DC *dc = get_dc_ptr( hdc );
    DWORD ret = GDI_ERROR;

    if (dc)
2595
    {
2596 2597 2598 2599 2600 2601 2602 2603
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapperFlags );
        flags = physdev->funcs->pSetMapperFlags( physdev, flags );
        if (flags != GDI_ERROR)
        {
            ret = dc->mapperFlags;
            dc->mapperFlags = flags;
        }
        release_dc_ptr( dc );
2604
    }
2605
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2606 2607
}

2608
/***********************************************************************
2609
 *          GetAspectRatioFilterEx  (GDI32.@)
2610
 */
2611
BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
2612
{
2613
  FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
2614 2615
  return FALSE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2616

Alexandre Julliard's avatar
Alexandre Julliard committed
2617 2618

/***********************************************************************
2619
 *           GetCharABCWidthsA   (GDI32.@)
2620 2621
 *
 * See GetCharABCWidthsW.
Alexandre Julliard's avatar
Alexandre Julliard committed
2622
 */
2623 2624
BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
                                  LPABC abc )
Alexandre Julliard's avatar
Alexandre Julliard committed
2625
{
2626
    INT i, wlen;
2627 2628 2629 2630
    LPSTR str;
    LPWSTR wstr;
    BOOL ret = TRUE;

2631
    str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2632 2633
    if (str == NULL)
        return FALSE;
2634

2635
    wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
2636 2637 2638 2639 2640
    if (wstr == NULL)
    {
        HeapFree(GetProcessHeap(), 0, str);
        return FALSE;
    }
2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655

    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
2656 2657 2658
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2659
/******************************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
2660 2661 2662
 * GetCharABCWidthsW [GDI32.@]
 *
 * Retrieves widths of characters in range.
Alexandre Julliard's avatar
Alexandre Julliard committed
2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675
 *
 * 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
2676
 */
2677 2678
BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
                                   LPABC abc )
Alexandre Julliard's avatar
Alexandre Julliard committed
2679
{
2680
    DC *dc = get_dc_ptr(hdc);
2681
    PHYSDEV dev;
2682
    unsigned int i;
2683
    BOOL ret;
2684
    TEXTMETRICW tm;
2685

2686 2687
    if (!dc) return FALSE;

2688 2689
    if (!abc)
    {
2690
        release_dc_ptr( dc );
2691 2692 2693
        return FALSE;
    }

2694 2695 2696 2697 2698 2699 2700 2701
    /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-TrueType fonts */
    dev = GET_DC_PHYSDEV( dc, pGetTextMetrics );
    if (!dev->funcs->pGetTextMetrics( dev, &tm ) || !(tm.tmPitchAndFamily & TMPF_TRUETYPE))
    {
        release_dc_ptr( dc );
        return FALSE;
    }

2702 2703
    dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
    ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
2704 2705 2706 2707 2708
    if (ret)
    {
        /* convert device units to logical */
        for( i = firstChar; i <= lastChar; i++, abc++ ) {
            abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2709 2710 2711 2712 2713
            abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
            abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
	}
    }

2714
    release_dc_ptr( dc );
2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740
    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)
{
2741
    DC *dc = get_dc_ptr(hdc);
2742
    PHYSDEV dev;
2743
    unsigned int i;
2744
    BOOL ret;
2745 2746 2747

    if (!dc) return FALSE;

2748 2749
    if (!abc)
    {
2750
        release_dc_ptr( dc );
2751 2752 2753
        return FALSE;
    }

2754 2755
    dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
    ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
2756 2757 2758
    if (ret)
    {
        /* convert device units to logical */
2759
        for( i = 0; i < count; i++, abc++ ) {
2760
            abc->abcA = INTERNAL_XDSTOWS(dc, abc->abcA);
2761 2762
            abc->abcB = INTERNAL_XDSTOWS(dc, abc->abcB);
            abc->abcC = INTERNAL_XDSTOWS(dc, abc->abcC);
2763
	}
2764
    }
2765

2766
    release_dc_ptr( dc );
2767
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2768 2769
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2770

Alexandre Julliard's avatar
Alexandre Julliard committed
2771
/***********************************************************************
2772
 *           GetGlyphOutlineA    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2773
 */
2774 2775
DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat,
                                 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
Alexandre Julliard's avatar
Alexandre Julliard committed
2776
                                 LPVOID lpBuffer, const MAT2 *lpmat2 )
Alexandre Julliard's avatar
Alexandre Julliard committed
2777
{
2778 2779
    if (!lpmat2) return GDI_ERROR;

2780
    if(!(fuFormat & GGO_GLYPH_INDEX)) {
2781
        UINT cp;
2782 2783
        int len;
        char mbchs[2];
2784 2785 2786

        cp = GdiGetCodePage(hdc);
        if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
2787 2788 2789 2790 2791 2792 2793
            len = 2;
            mbchs[0] = (uChar & 0xff00) >> 8;
            mbchs[1] = (uChar & 0xff);
        } else {
            len = 1;
            mbchs[0] = (uChar & 0xff);
        }
2794
        uChar = 0;
2795 2796 2797 2798 2799
        MultiByteToWideChar(cp, 0, mbchs, len, (LPWSTR)&uChar, 1);
    }

    return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
                            lpmat2);
Alexandre Julliard's avatar
Alexandre Julliard committed
2800 2801
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2802
/***********************************************************************
2803
 *           GetGlyphOutlineW    (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2804
 */
2805 2806
DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat,
                                 LPGLYPHMETRICS lpgm, DWORD cbBuffer,
Alexandre Julliard's avatar
Alexandre Julliard committed
2807
                                 LPVOID lpBuffer, const MAT2 *lpmat2 )
Alexandre Julliard's avatar
Alexandre Julliard committed
2808
{
2809
    DC *dc;
2810
    DWORD ret;
2811
    PHYSDEV dev;
2812

2813
    TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2814
	  hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2815

2816 2817 2818
    if (!lpmat2) return GDI_ERROR;

    dc = get_dc_ptr(hdc);
2819 2820
    if(!dc) return GDI_ERROR;

2821 2822
    dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
    ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
2823
    release_dc_ptr( dc );
2824
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2825
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2826

Alexandre Julliard's avatar
Alexandre Julliard committed
2827

Alexandre Julliard's avatar
Alexandre Julliard committed
2828
/***********************************************************************
2829
 *           CreateScalableFontResourceA   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2830
 */
2831
BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
Alexandre Julliard's avatar
Alexandre Julliard committed
2832 2833 2834
                                             LPCSTR lpszResourceFile,
                                             LPCSTR lpszFontFile,
                                             LPCSTR lpszCurrentPath )
Alexandre Julliard's avatar
Alexandre Julliard committed
2835
{
2836 2837 2838 2839 2840
    LPWSTR lpszResourceFileW = NULL;
    LPWSTR lpszFontFileW = NULL;
    LPWSTR lpszCurrentPathW = NULL;
    int len;
    BOOL ret;
2841

2842 2843 2844 2845 2846 2847
    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);
    }
2848

2849 2850 2851 2852 2853
    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);
2854
    }
2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870

    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
2871 2872
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2873
/***********************************************************************
2874
 *           CreateScalableFontResourceW   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2875
 */
2876 2877 2878 2879 2880 2881 2882 2883
BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
                                         LPCWSTR font_file, LPCWSTR font_path )
{
    TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
          debugstr_w(font_file), debugstr_w(font_path) );

    return WineEngCreateScalableFontResource( hidden, resource_file,
                                              font_file, font_path );
Alexandre Julliard's avatar
Alexandre Julliard committed
2884 2885
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2886
/*************************************************************************
2887
 *             GetKerningPairsA   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2888
 */
2889
DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
2890
                               LPKERNINGPAIR kern_pairA )
Alexandre Julliard's avatar
Alexandre Julliard committed
2891
{
2892
    UINT cp;
2893 2894 2895 2896 2897 2898 2899 2900 2901 2902
    CPINFO cpi;
    DWORD i, total_kern_pairs, kern_pairs_copied = 0;
    KERNINGPAIR *kern_pairW;

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

2903 2904
    cp = GdiGetCodePage(hDC);

2905 2906 2907 2908
    /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
     * to fail on an invalid character for CP_SYMBOL.
     */
    cpi.DefaultChar[0] = 0;
2909
    if (cp != CP_SYMBOL && !GetCPInfo(cp, &cpi))
2910
    {
2911
        FIXME("Can't find codepage %u info\n", cp);
2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924
        return 0;
    }

    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;

2925
        if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
2926 2927
            continue;

2928
        if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
2929
            continue;
Alexandre Julliard's avatar
Alexandre Julliard committed
2930

2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949
        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
2950 2951

/*************************************************************************
2952
 *             GetKerningPairsW   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2953
 */
2954 2955
DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
                                 LPKERNINGPAIR lpKerningPairs )
Alexandre Julliard's avatar
Alexandre Julliard committed
2956
{
2957
    DC *dc;
2958 2959
    DWORD ret;
    PHYSDEV dev;
2960

2961
    TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
2962

2963 2964 2965 2966 2967 2968
    if (!cPairs && lpKerningPairs)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }

2969
    dc = get_dc_ptr(hDC);
2970 2971
    if (!dc) return 0;

2972 2973
    dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
    ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
2974
    release_dc_ptr( dc );
2975
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2976
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2977

Alexandre Julliard's avatar
Alexandre Julliard committed
2978
/*************************************************************************
2979
 * TranslateCharsetInfo [GDI32.@]
2980 2981
 *
 * Fills a CHARSETINFO structure for a character set, code page, or
2982
 * font. This allows making the correspondence between different labels
2983
 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2984 2985 2986 2987 2988 2989 2990 2991 2992
 * 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.
 *
 */
2993
BOOL WINAPI TranslateCharsetInfo(
2994
  LPDWORD lpSrc, /* [in]
2995 2996 2997 2998
       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
		 */
2999
  LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
Jon Griffiths's avatar
Jon Griffiths committed
3000 3001
  DWORD flags /* [in] determines interpretation of lpSrc */)
{
3002 3003 3004
    int index = 0;
    switch (flags) {
    case TCI_SRCFONTSIG:
3005
      while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
3006 3007
      break;
    case TCI_SRCCODEPAGE:
3008
      while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
3009 3010
      break;
    case TCI_SRCCHARSET:
3011
      while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
3012 3013 3014 3015 3016
      break;
    default:
      return FALSE;
    }
    if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
3017
    *lpCs = FONT_tci[index];
Alexandre Julliard's avatar
Alexandre Julliard committed
3018 3019 3020
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3021
/*************************************************************************
3022
 *             GetFontLanguageInfo   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3023
 */
3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034
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;
3035

3036
	DWORD result=0;
3037

3038 3039 3040 3041 3042
	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;
3043

3044 3045
	if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
		result|=GCP_DIACRITIC;
3046

3047 3048
	if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
		result|=FLI_GLYPHS;
3049

3050 3051
	if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
		result|=GCP_GLYPHSHAPE;
3052

3053 3054
	if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
		result|=GCP_KASHIDA;
3055

3056 3057 3058 3059 3060
	if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
		result|=GCP_LIGATE;

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

3062 3063 3064 3065
        /* 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;
3066

3067
	return result;
Alexandre Julliard's avatar
Alexandre Julliard committed
3068 3069
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3070

Alexandre Julliard's avatar
Alexandre Julliard committed
3071
/*************************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
3072 3073 3074
 * GetFontData [GDI32.@]
 *
 * Retrieve data for TrueType font.
Alexandre Julliard's avatar
Alexandre Julliard committed
3075 3076 3077
 *
 * RETURNS
 *
3078
 * success: Number of bytes returned
Alexandre Julliard's avatar
Alexandre Julliard committed
3079 3080 3081 3082
 * failure: GDI_ERROR
 *
 * NOTES
 *
3083
 * Calls SetLastError()
Alexandre Julliard's avatar
Alexandre Julliard committed
3084 3085
 *
 */
3086
DWORD WINAPI GetFontData(HDC hdc, DWORD table, DWORD offset,
Alexandre Julliard's avatar
Alexandre Julliard committed
3087 3088
    LPVOID buffer, DWORD length)
{
3089
    DC *dc = get_dc_ptr(hdc);
3090 3091
    PHYSDEV dev;
    DWORD ret;
Huw D M Davies's avatar
Huw D M Davies committed
3092 3093 3094

    if(!dc) return GDI_ERROR;

3095 3096
    dev = GET_DC_PHYSDEV( dc, pGetFontData );
    ret = dev->funcs->pGetFontData( dev, table, offset, buffer, length );
3097
    release_dc_ptr( dc );
Huw D M Davies's avatar
Huw D M Davies committed
3098
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3099
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3100

3101 3102 3103 3104 3105 3106 3107 3108 3109 3110
/*************************************************************************
 * GetGlyphIndicesA [GDI32.@]
 */
DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
			      LPWORD pgi, DWORD flags)
{
    DWORD ret;
    WCHAR *lpstrW;
    INT countW;

3111
    TRACE("(%p, %s, %d, %p, 0x%x)\n",
3112
          hdc, debugstr_an(lpstr, count), count, pgi, flags);
3113

3114
    lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126
    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)
{
3127
    DC *dc = get_dc_ptr(hdc);
3128 3129
    PHYSDEV dev;
    DWORD ret;
3130

3131
    TRACE("(%p, %s, %d, %p, 0x%x)\n",
3132
          hdc, debugstr_wn(lpstr, count), count, pgi, flags);
3133 3134 3135

    if(!dc) return GDI_ERROR;

3136 3137
    dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices );
    ret = dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
3138
    release_dc_ptr( dc );
3139 3140 3141
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3142
/*************************************************************************
3143
 * GetCharacterPlacementA [GDI32.@]
3144
 *
3145 3146
 * See GetCharacterPlacementW.
 *
3147 3148
 * NOTES:
 *  the web browser control of ie4 calls this with dwFlags=0
Alexandre Julliard's avatar
Alexandre Julliard committed
3149 3150
 */
DWORD WINAPI
3151 3152
GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
			 INT nMaxExtent, GCP_RESULTSA *lpResults,
Alexandre Julliard's avatar
Alexandre Julliard committed
3153 3154
			 DWORD dwFlags)
{
3155
    WCHAR *lpStringW;
3156
    INT uCountW;
3157 3158
    GCP_RESULTSW resultsW;
    DWORD ret;
3159
    UINT font_cp;
3160

3161
    TRACE("%s, %d, %d, 0x%08x\n",
3162
          debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
3163

3164 3165
    /* both structs are equal in size */
    memcpy(&resultsW, lpResults, sizeof(resultsW));
3166

3167
    lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
3168 3169
    if(lpResults->lpOutString)
        resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
3170

3171 3172
    ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);

3173 3174 3175
    lpResults->nGlyphs = resultsW.nGlyphs;
    lpResults->nMaxFit = resultsW.nMaxFit;

3176
    if(lpResults->lpOutString) {
3177
        WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
3178
                            lpResults->lpOutString, uCount, NULL, NULL );
3179
    }
3180

3181 3182
    HeapFree(GetProcessHeap(), 0, lpStringW);
    HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
3183 3184

    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3185 3186 3187
}

/*************************************************************************
3188
 * GetCharacterPlacementW [GDI32.@]
3189 3190 3191 3192 3193 3194
 *
 *   Retrieve information about a string. This includes the width, reordering,
 *   Glyphing and so on.
 *
 * RETURNS
 *
Francois Gouget's avatar
Francois Gouget committed
3195
 *   The width and height of the string if successful, 0 if failed.
3196 3197 3198 3199
 *
 * BUGS
 *
 *   All flags except GCP_REORDER are not yet implemented.
Austin English's avatar
Austin English committed
3200
 *   Reordering is not 100% compliant to the Windows BiDi method.
3201
 *   Caret positioning is not yet implemented for BiDi.
3202 3203
 *   Classes are not yet implemented.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
3204 3205
 */
DWORD WINAPI
3206
GetCharacterPlacementW(
3207 3208 3209 3210 3211 3212
		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 */
3213
		)
Alexandre Julliard's avatar
Alexandre Julliard committed
3214
{
3215 3216
    DWORD ret=0;
    SIZE size;
3217
    UINT i, nSet;
3218

3219
    TRACE("%s, %d, %d, 0x%08x\n",
3220
          debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
3221

3222 3223
    TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
          "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3224 3225 3226
	    lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
	    lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
	    lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
3227

3228
    if(dwFlags&(~GCP_REORDER))			FIXME("flags 0x%08x ignored\n", dwFlags);
3229
    if(lpResults->lpClass)	FIXME("classes not implemented\n");
3230 3231
    if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
        FIXME("Caret positions for complex scripts not implemented\n");
3232

3233 3234 3235
	nSet = (UINT)uCount;
	if(nSet > lpResults->nGlyphs)
		nSet = lpResults->nGlyphs;
3236

3237 3238
	/* return number of initialized fields */
	lpResults->nGlyphs = nSet;
3239

3240
	if((dwFlags&GCP_REORDER)==0 )
3241 3242 3243 3244
	{
		/* 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)
3245
                    memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
3246 3247 3248 3249 3250 3251

		if(lpResults->lpOrder)
		{
			for(i = 0; i < nSet; i++)
				lpResults->lpOrder[i] = i;
		}
3252
	} else
3253
	{
3254
            BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
3255
                          nSet, lpResults->lpOrder, NULL, NULL );
3256
	}
3257

3258 3259 3260 3261 3262 3263 3264 3265 3266 3267
	/* 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;
		}
	}
3268

3269 3270 3271 3272 3273 3274 3275 3276 3277 3278
    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);
    }
   
3279 3280 3281
    if(lpResults->lpGlyphs)
	GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);

3282 3283 3284 3285
    if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
      ret = MAKELONG(size.cx, size.cy);

    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3286
}
3287 3288

/*************************************************************************
3289
 *      GetCharABCWidthsFloatA [GDI32.@]
3290 3291
 *
 * See GetCharABCWidthsFloatW.
3292
 */
3293
BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3294
{
3295
    INT i, wlen;
3296 3297 3298 3299
    LPSTR str;
    LPWSTR wstr;
    BOOL ret = TRUE;

3300
    str = FONT_GetCharsByRangeA(hdc, first, last, &i);
3301 3302
    if (str == NULL)
        return FALSE;
3303

3304
    wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319

    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;
3320 3321 3322
}

/*************************************************************************
3323
 *      GetCharABCWidthsFloatW [GDI32.@]
3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335
 *
 * 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
3336
 */
3337
BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
3338
{
3339
    UINT i;
3340 3341
    ABC *abc;
    PHYSDEV dev;
3342 3343 3344 3345 3346 3347
    BOOL ret = FALSE;
    DC *dc = get_dc_ptr( hdc );

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

    if (!dc) return FALSE;
3348

3349 3350
    if (!abcf) goto done;
    if (!(abc = HeapAlloc( GetProcessHeap(), 0, (last - first + 1) * sizeof(*abc) ))) goto done;
3351

3352 3353
    dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
    ret = dev->funcs->pGetCharABCWidths( dev, first, last, abc );
3354
    if (ret)
3355
    {
3356 3357
        /* convert device units to logical */
        for (i = first; i <= last; i++, abcf++)
3358
        {
3359 3360 3361
            abcf->abcfA = abc[i - first].abcA * dc->xformVport2World.eM11;
            abcf->abcfB = abc[i - first].abcB * dc->xformVport2World.eM11;
            abcf->abcfC = abc[i - first].abcC * dc->xformVport2World.eM11;
3362 3363
        }
    }
3364
    HeapFree( GetProcessHeap(), 0, abc );
3365

3366
done:
3367
    release_dc_ptr( dc );
3368
    return ret;
3369 3370 3371
}

/*************************************************************************
3372
 *      GetCharWidthFloatA [GDI32.@]
3373
 */
3374 3375
BOOL WINAPI GetCharWidthFloatA(HDC hdc, UINT iFirstChar,
		                    UINT iLastChar, PFLOAT pxBuffer)
3376
{
3377 3378
    FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
    return 0;
3379 3380 3381
}

/*************************************************************************
3382
 *      GetCharWidthFloatW [GDI32.@]
3383
 */
3384 3385
BOOL WINAPI GetCharWidthFloatW(HDC hdc, UINT iFirstChar,
		                    UINT iLastChar, PFLOAT pxBuffer)
3386
{
3387 3388
    FIXME("%p, %u, %u, %p: stub!\n", hdc, iFirstChar, iLastChar, pxBuffer);
    return 0;
3389
}
3390

3391 3392 3393 3394 3395 3396 3397 3398

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

/***********************************************************************
3399
 *           AddFontResourceA    (GDI32.@)
3400 3401 3402
 */
INT WINAPI AddFontResourceA( LPCSTR str )
{
3403
    return AddFontResourceExA( str, 0, NULL);
3404 3405 3406
}

/***********************************************************************
3407
 *           AddFontResourceW    (GDI32.@)
3408 3409 3410
 */
INT WINAPI AddFontResourceW( LPCWSTR str )
{
3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429
    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;
}

3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448
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;
}

3449 3450 3451 3452 3453 3454 3455 3456
static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
{
    HANDLE file, mapping;
    void *ptr;

    file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
    if (file == INVALID_HANDLE_VALUE) return NULL;

3457 3458 3459 3460 3461 3462
    if (!GetFileSizeEx( file, size ) || size->u.HighPart)
    {
        CloseHandle( file );
        return NULL;
    }

3463 3464
    mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
    CloseHandle( file );
3465
    if (!mapping) return NULL;
3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523

    ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
    CloseHandle( mapping );

    return ptr;
}

static WCHAR *get_scalable_filename( const WCHAR *res )
{
    LARGE_INTEGER size;
    BYTE *ptr = map_file( res, &size );
    const IMAGE_DOS_HEADER *dos;
    const IMAGE_OS2_HEADER *ne;
    WCHAR *name = NULL;
    WORD rsrc_off, align, type_id, count;
    DWORD res_off, res_len, i;
    int len;

    if (!ptr) return NULL;

    if (size.u.LowPart < sizeof( *dos )) goto fail;
    dos = (const IMAGE_DOS_HEADER *)ptr;
    if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto fail;
    if (size.u.LowPart < dos->e_lfanew + sizeof( *ne )) goto fail;
    ne = (const IMAGE_OS2_HEADER *)(ptr + dos->e_lfanew);
    rsrc_off = dos->e_lfanew + ne->ne_rsrctab;
    if (size.u.LowPart < rsrc_off + 10) goto fail;
    align = *(WORD *)(ptr + rsrc_off);
    rsrc_off += 2;
    type_id = *(WORD *)(ptr + rsrc_off);
    while (type_id && type_id != 0x80cc)
    {
        count = *(WORD *)(ptr + rsrc_off + 2);
        rsrc_off += 8 + count * 12;
        if (size.u.LowPart < rsrc_off + 8) goto fail;
        type_id = *(WORD *)(ptr + rsrc_off);
    }
    if (!type_id) goto fail;
    count = *(WORD *)(ptr + rsrc_off + 2);
    if (size.u.LowPart < rsrc_off + 8 + count * 12) goto fail;

    res_off = *(WORD *)(ptr + rsrc_off + 8) << align;
    res_len = *(WORD *)(ptr + rsrc_off + 10) << align;
    if (size.u.LowPart < res_off + res_len) goto fail;

    for (i = 0; i < res_len; i++)
        if (ptr[ res_off + i ] == 0) break;
    if (i == res_len) goto fail;

    len = MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, NULL, 0 );
    name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
    if (name) MultiByteToWideChar( CP_ACP, 0, (char *)ptr + res_off, -1, name, len );

fail:
    UnmapViewOfFile( ptr );
    return name;
}

3524 3525 3526 3527 3528
/***********************************************************************
 *           AddFontResourceExW    (GDI32.@)
 */
INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
{
3529
    int ret = WineEngAddFontResourceEx(str, fl, pdv);
3530 3531
    WCHAR *filename;

3532 3533
    if (ret == 0)
    {
3534
        /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3535 3536 3537 3538 3539 3540
        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 */

3541
            TRACE("WineEndAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3542 3543 3544 3545 3546
                wine_dbgstr_w(str));
            if (EnumResourceNamesW(hModule, rt_font, load_enumed_resource, (LONG_PTR)&num_resources))
                ret = num_resources;
            FreeLibrary(hModule);
        }
3547 3548 3549 3550 3551
        else if ((filename = get_scalable_filename( str )) != NULL)
        {
            ret = WineEngAddFontResourceEx( filename, fl, pdv );
            HeapFree( GetProcessHeap(), 0, filename );
        }
3552 3553
    }
    return ret;
3554 3555 3556
}

/***********************************************************************
3557
 *           RemoveFontResourceA    (GDI32.@)
3558 3559 3560
 */
BOOL WINAPI RemoveFontResourceA( LPCSTR str )
{
3561
    return RemoveFontResourceExA(str, 0, 0);
3562 3563 3564
}

/***********************************************************************
3565
 *           RemoveFontResourceW    (GDI32.@)
3566 3567 3568
 */
BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
{
3569 3570 3571
    return RemoveFontResourceExW(str, 0, 0);
}

3572 3573 3574 3575 3576
/***********************************************************************
 *           AddFontMemResourceEx    (GDI32.@)
 */
HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
{
3577 3578 3579
    HANDLE ret;
    DWORD num_fonts;

3580 3581 3582 3583 3584 3585
    if (!pbFont || !cbFont || !pcFonts)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }

3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601
    ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts);
    if (ret)
    {
        __TRY
        {
            *pcFonts = num_fonts;
        }
        __EXCEPT_PAGE_FAULT
        {
            WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
            RemoveFontMemResourceEx(ret);
            ret = 0;
        }
        __ENDTRY
    }
    return ret;
3602 3603
}

3604 3605 3606 3607 3608 3609 3610 3611 3612
/***********************************************************************
 *           RemoveFontMemResourceEx    (GDI32.@)
 */
BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
{
    FIXME("(%p) stub\n", fh);
    return TRUE;
}

3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633
/***********************************************************************
 *           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);
3634
}
3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650

/***********************************************************************
 *           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;
3651
    DC *dc = get_dc_ptr(hdc);
3652
    PHYSDEV dev;
3653

3654 3655
    if (dc)
    {
3656 3657
        dev = GET_DC_PHYSDEV( dc, pGetTextCharsetInfo );
        ret = dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
3658
        release_dc_ptr( dc );
3659
    }
3660 3661 3662 3663 3664

    if (ret == DEFAULT_CHARSET && fs)
        memset(fs, 0, sizeof(FONTSIGNATURE));
    return ret;
}
3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704

/***********************************************************************
 *           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;
}
3705 3706 3707 3708 3709 3710

BOOL WINAPI EnableEUDC(BOOL fEnableEUDC)
{
    FIXME("(%d): stub\n", fEnableEUDC);
    return FALSE;
}
3711 3712 3713

/***********************************************************************
 *           GetCharWidthI    (GDI32.@)
3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729
 *
 * 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
3730
 */
3731
BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
3732
{
3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751
    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;
3752 3753 3754 3755
}

/***********************************************************************
 *           GetFontUnicodeRanges    (GDI32.@)
3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766
 *
 *  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
 *
3767 3768 3769
 */
DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
{
3770 3771
    DWORD ret;
    PHYSDEV dev;
3772
    DC *dc = get_dc_ptr(hdc);
3773 3774 3775 3776 3777

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

    if (!dc) return 0;

3778 3779
    dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
    ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
3780
    release_dc_ptr(dc);
3781
    return ret;
3782
}
3783 3784 3785 3786 3787 3788 3789


/*************************************************************
 *           FontIsLinked    (GDI32.@)
 */
BOOL WINAPI FontIsLinked(HDC hdc)
{
3790
    DC *dc = get_dc_ptr(hdc);
3791 3792
    PHYSDEV dev;
    BOOL ret;
3793 3794

    if (!dc) return FALSE;
3795 3796
    dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
    ret = dev->funcs->pFontIsLinked( dev );
3797
    release_dc_ptr(dc);
3798 3799 3800
    TRACE("returning %d\n", ret);
    return ret;
}
3801

3802 3803 3804 3805 3806
/*************************************************************
 *           GdiRealizationInfo    (GDI32.@)
 *
 * Returns a structure that contains some font information.
 */
3807 3808
BOOL WINAPI GdiRealizationInfo(HDC hdc, realization_info_t *info)
{
3809
    DC *dc = get_dc_ptr(hdc);
3810 3811
    PHYSDEV dev;
    BOOL ret;
3812

3813
    if (!dc) return FALSE;
3814 3815
    dev = GET_DC_PHYSDEV( dc, pGdiRealizationInfo );
    ret = dev->funcs->pGdiRealizationInfo( dev, info );
3816 3817
    release_dc_ptr(dc);
    return ret;
3818
}