freetype.c 169 KB
Newer Older
1 2 3 4
/*
 * FreeType font engine interface
 *
 * Copyright 2001 Huw D M Davies for CodeWeavers.
5
 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
6 7
 *
 * This file contains the WineEng* functions.
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * 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
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 23 24
 */

#include "config.h"
25
#include "wine/port.h"
26

27 28
#include <stdarg.h>
#include <stdlib.h>
29 30 31
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
32 33 34
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
35 36 37 38 39
#include <string.h>
#include <dirent.h>
#include <stdio.h>
#include <assert.h>

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
#ifdef HAVE_CARBON_CARBON_H
#define LoadResource __carbon_LoadResource
#define CompareString __carbon_CompareString
#define GetCurrentThread __carbon_GetCurrentThread
#define GetCurrentProcess __carbon_GetCurrentProcess
#define AnimatePalette __carbon_AnimatePalette
#define EqualRgn __carbon_EqualRgn
#define FillRgn __carbon_FillRgn
#define FrameRgn __carbon_FrameRgn
#define GetPixel __carbon_GetPixel
#define InvertRgn __carbon_InvertRgn
#define LineTo __carbon_LineTo
#define OffsetRgn __carbon_OffsetRgn
#define PaintRgn __carbon_PaintRgn
#define Polygon __carbon_Polygon
#define ResizePalette __carbon_ResizePalette
#define SetRectRgn __carbon_SetRectRgn
#include <Carbon/Carbon.h>
#undef LoadResource
#undef CompareString
#undef GetCurrentThread
#undef _CDECL
#undef DPRINTF
#undef GetCurrentProcess
#undef AnimatePalette
#undef EqualRgn
#undef FillRgn
#undef FrameRgn
#undef GetPixel
#undef InvertRgn
#undef LineTo
#undef OffsetRgn
#undef PaintRgn
#undef Polygon
#undef ResizePalette
#undef SetRectRgn
#endif /* HAVE_CARBON_CARBON_H */

78
#include "windef.h"
79
#include "winbase.h"
80
#include "winternl.h"
81 82 83
#include "winerror.h"
#include "winreg.h"
#include "wingdi.h"
84
#include "gdi_private.h"
85
#include "wine/unicode.h"
86
#include "wine/debug.h"
87
#include "wine/list.h"
88

89
WINE_DEFAULT_DEBUG_CHANNEL(font);
90 91 92

#ifdef HAVE_FREETYPE

93 94 95
#ifdef HAVE_FT2BUILD_H
#include <ft2build.h>
#endif
96 97 98 99 100 101 102 103 104
#ifdef HAVE_FREETYPE_FREETYPE_H
#include <freetype/freetype.h>
#endif
#ifdef HAVE_FREETYPE_FTGLYPH_H
#include <freetype/ftglyph.h>
#endif
#ifdef HAVE_FREETYPE_TTTABLES_H
#include <freetype/tttables.h>
#endif
105 106 107
#ifdef HAVE_FREETYPE_FTTYPES_H
#include <freetype/fttypes.h>
#endif
108 109
#ifdef HAVE_FREETYPE_FTSNAMES_H
#include <freetype/ftsnames.h>
110 111 112 113
#else
# ifdef HAVE_FREETYPE_FTNAMES_H
# include <freetype/ftnames.h>
# endif
114 115 116 117 118 119 120
#endif
#ifdef HAVE_FREETYPE_TTNAMEID_H
#include <freetype/ttnameid.h>
#endif
#ifdef HAVE_FREETYPE_FTOUTLN_H
#include <freetype/ftoutln.h>
#endif
Huw D M Davies's avatar
Huw D M Davies committed
121 122 123
#ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
#include <freetype/internal/sfnt.h>
#endif
124 125 126
#ifdef HAVE_FREETYPE_FTTRIGON_H
#include <freetype/fttrigon.h>
#endif
127 128 129
#ifdef HAVE_FREETYPE_FTWINFNT_H
#include <freetype/ftwinfnt.h>
#endif
130 131 132
#ifdef HAVE_FREETYPE_FTMODAPI_H
#include <freetype/ftmodapi.h>
#endif
133

134 135 136 137 138 139 140
#ifndef HAVE_FT_TRUETYPEENGINETYPE
typedef enum
{
    FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
    FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
    FT_TRUETYPE_ENGINE_TYPE_PATENTED
} FT_TrueTypeEngineType;
141 142
#endif

143
static FT_Library library = 0;
144 145 146 147 148 149 150
typedef struct
{
    FT_Int major;
    FT_Int minor;
    FT_Int patch;
} FT_Version_t;
static FT_Version_t FT_Version;
151
static DWORD FT_SimpleVersion;
152

153 154
static void *ft_handle = NULL;

155
#define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156
MAKE_FUNCPTR(FT_Vector_Unit);
157 158
MAKE_FUNCPTR(FT_Done_Face);
MAKE_FUNCPTR(FT_Get_Char_Index);
159
MAKE_FUNCPTR(FT_Get_Module);
160 161
MAKE_FUNCPTR(FT_Get_Sfnt_Name);
MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 163 164
MAKE_FUNCPTR(FT_Get_Sfnt_Table);
MAKE_FUNCPTR(FT_Init_FreeType);
MAKE_FUNCPTR(FT_Load_Glyph);
165
MAKE_FUNCPTR(FT_Matrix_Multiply);
166 167
MAKE_FUNCPTR(FT_MulFix);
MAKE_FUNCPTR(FT_New_Face);
168
MAKE_FUNCPTR(FT_New_Memory_Face);
169 170 171 172
MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
MAKE_FUNCPTR(FT_Outline_Transform);
MAKE_FUNCPTR(FT_Outline_Translate);
MAKE_FUNCPTR(FT_Select_Charmap);
173
MAKE_FUNCPTR(FT_Set_Charmap);
174
MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175
MAKE_FUNCPTR(FT_Vector_Transform);
176
static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177
static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178
static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179
static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180
static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 182 183
#ifdef HAVE_FREETYPE_FTWINFNT_H
MAKE_FUNCPTR(FT_Get_WinFNT_Header);
#endif
184

185
#ifdef SONAME_LIBFONTCONFIG
186 187 188 189 190 191 192 193 194 195
#include <fontconfig/fontconfig.h>
MAKE_FUNCPTR(FcConfigGetCurrent);
MAKE_FUNCPTR(FcFontList);
MAKE_FUNCPTR(FcFontSetDestroy);
MAKE_FUNCPTR(FcInit);
MAKE_FUNCPTR(FcObjectSetAdd);
MAKE_FUNCPTR(FcObjectSetCreate);
MAKE_FUNCPTR(FcObjectSetDestroy);
MAKE_FUNCPTR(FcPatternCreate);
MAKE_FUNCPTR(FcPatternDestroy);
196
MAKE_FUNCPTR(FcPatternGetBool);
197
MAKE_FUNCPTR(FcPatternGetString);
198 199 200 201
#endif

#undef MAKE_FUNCPTR

202 203 204 205 206 207
#ifndef FT_MAKE_TAG
#define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
	( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
	  ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
#endif

208
#ifndef ft_encoding_none
209 210
#define FT_ENCODING_NONE ft_encoding_none
#endif
211
#ifndef ft_encoding_ms_symbol
212 213
#define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
#endif
214
#ifndef ft_encoding_unicode
215 216
#define FT_ENCODING_UNICODE ft_encoding_unicode
#endif
217
#ifndef ft_encoding_apple_roman
218 219
#define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
#endif
220

221 222 223 224 225
#ifdef WORDS_BIGENDIAN
#define GET_BE_WORD(x) (x)
#else
#define GET_BE_WORD(x) RtlUshortByteSwap(x)
#endif
226

227 228 229 230
/* This is bascially a copy of FT_Bitmap_Size with an extra element added */
typedef struct {
    FT_Short height;
    FT_Short width;
231
    FT_Pos size;
232 233 234 235 236
    FT_Pos x_ppem;
    FT_Pos y_ppem;
    FT_Short internal_leading;
} Bitmap_Size;

237 238 239 240 241 242 243 244
/* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
   So to let this compile on older versions of FreeType we'll define the
   new structure here. */
typedef struct {
    FT_Short height, width;
    FT_Pos size, x_ppem, y_ppem;
} My_FT_Bitmap_Size;

245
typedef struct tagFace {
246
    struct list entry;
247 248
    WCHAR *StyleName;
    char *file;
249 250
    void *font_data_ptr;
    DWORD font_data_size;
251
    FT_Long face_index;
252 253
    BOOL Italic;
    BOOL Bold;
254
    FONTSIGNATURE fs;
255
    FONTSIGNATURE fs_links;
256
    DWORD ntmFlags;  /* Only some bits stored here. Others are computed on the fly */
257
    FT_Fixed font_version;
258 259
    BOOL scalable;
    Bitmap_Size size;     /* set if face is a bitmap */
260
    BOOL external; /* TRUE if we should manually add this font to the registry */
261
    struct tagFamily *family;
262 263 264
} Face;

typedef struct tagFamily {
265
    struct list entry;
266
    const WCHAR *FamilyName;
267
    struct list faces;
268 269
} Family;

270 271 272 273 274 275 276 277
typedef struct {
    GLYPHMETRICS gm;
    INT adv; /* These three hold to widths of the unrotated chars */
    INT lsb;
    INT bbx;
    BOOL init;
} GM;

278 279 280 281 282 283 284 285 286
typedef struct {
    FLOAT eM11, eM12;
    FLOAT eM21, eM22;
} FMAT2;

typedef struct {
    DWORD hash;
    LOGFONTW lf;
    FMAT2 matrix;
287
    BOOL can_use_bitmap;
288 289 290 291 292 293 294
} FONT_DESC;

typedef struct tagHFONTLIST {
    struct list entry;
    HFONT hfont;
} HFONTLIST;

295 296
typedef struct {
    struct list entry;
297
    Face *face;
298
    GdiFont *font;
299 300
} CHILD_FONT;

301
struct tagGdiFont {
302
    struct list entry;
303
    FT_Face ft_face;
304
    struct font_mapping *mapping;
305
    LPWSTR name;
306
    int charset;
307
    int codepage;
308 309
    BOOL fake_italic;
    BOOL fake_bold;
310 311
    BYTE underline;
    BYTE strikeout;
312
    INT orientation;
313
    GM **gm;
314
    DWORD gmsize;
315 316
    struct list hfontlist;
    FONT_DESC font_desc;
317
    LONG aveWidth;
318 319
    SHORT yMax;
    SHORT yMin;
320
    OUTLINETEXTMETRICW *potm;
321
    DWORD ntmFlags;
322 323
    DWORD total_kern_pairs;
    KERNINGPAIR *kern_pairs;
324
    FONTSIGNATURE fs;
325
    GdiFont *base_font;
326
    struct list child_fonts;
327
    LONG ppem;
328 329
};

330 331
typedef struct {
    struct list entry;
332
    const WCHAR *font_name;
333 334 335
    struct list links;
} SYSTEM_LINKS;

336 337
#define GM_BLOCK_SIZE 128
#define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
338

339
static struct list gdi_font_list = LIST_INIT(gdi_font_list);
340 341
static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
#define UNUSED_CACHE_SIZE 10
342
static struct list child_font_list = LIST_INIT(child_font_list);
343
static struct list system_links = LIST_INIT(system_links);
344

345 346
static struct list font_subst_list = LIST_INIT(font_subst_list);

347
static struct list font_list = LIST_INIT(font_list);
348

349
static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
350
static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
351
static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
352

353 354
static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};

355
static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
356 357 358 359 360 361 362 363 364 365
static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
                                           'W','i','n','d','o','w','s','\\',
                                           'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
                                           'F','o','n','t','s','\0'};

static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
                                           'W','i','n','d','o','w','s',' ','N','T','\\',
                                           'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
                                           'F','o','n','t','s','\0'};

366 367 368 369 370
static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};

371
static const WCHAR * const SystemFontValues[4] = {
372 373
    System_Value,
    OEMFont_Value,
374
    FixedSys_Value,
375 376 377
    NULL
};

378
static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
379
                                               'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
380

Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
381 382 383 384 385
static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
386
				    'E','u','r','o','p','e','a','n','\0'};
Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
387 388 389 390 391 392 393 394 395 396 397
static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
398
static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
399

400
static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
401 402 403 404 405 406 407 408 409 410 411
    WesternW, /*00*/
    Central_EuropeanW,
    CyrillicW,
    GreekW,
    TurkishW,
    HebrewW,
    ArabicW,
    BalticW,
    VietnameseW, /*08*/
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
    ThaiW,
412 413 414 415 416 417
    JapaneseW,
    CHINESE_GB2312W,
    HangulW,
    CHINESE_BIG5W,
    Hangul_Johab_W,
    NULL, NULL, /*23*/
418 419 420 421
    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    SymbolW /*31*/
};

422
typedef struct {
423 424
    WCHAR *name;
    INT charset;
425 426 427
} NameCs;

typedef struct tagFontSubst {
428 429 430
    struct list entry;
    NameCs from;
    NameCs to;
431 432
} FontSubst;

433 434 435 436 437 438 439 440 441 442 443 444
struct font_mapping
{
    struct list entry;
    int         refcount;
    dev_t       dev;
    ino_t       ino;
    void       *data;
    size_t      size;
};

static struct list mappings_list = LIST_INIT( mappings_list );

445
static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
446

447 448
static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};

449
static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
450 451 452 453 454 455 456 457 458 459

/****************************************
 *   Notes on .fon files
 *
 * The fonts System, FixedSys and Terminal are special.  There are typically multiple
 * versions installed for different resolutions and codepages.  Windows stores which one to use
 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
 *    Key            Meaning
 *  FIXEDFON.FON    FixedSys
 *  FONTS.FON       System
Vitaly Lipatov's avatar
Vitaly Lipatov committed
460
 *  OEMFONT.FON     Terminal
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
 *  LogPixels       Current dpi set by the display control panel applet
 *                  (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
 *                  also has a LogPixels value that appears to mirror this)
 *
 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
 * so that makes sense.
 *
 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
 * to be mapped into the registry on Windows 2000 at least).
 * I have
 * woafont=app850.fon
 * ega80woa.fon=ega80850.fon
 * ega40woa.fon=ega40850.fon
 * cga80woa.fon=cga80850.fon
 * cga40woa.fon=cga40850.fon
 */

481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 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
#ifdef HAVE_CARBON_CARBON_H
static char *find_cache_dir(void)
{
    FSRef ref;
    OSErr err;
    static char cached_path[MAX_PATH];
    static const char *wine = "/Wine", *fonts = "/Fonts";

    if(*cached_path) return cached_path;

    err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
    if(err != noErr)
    {
        WARN("can't create cached data folder\n");
        return NULL;
    }
    err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
    if(err != noErr)
    {
        WARN("can't create cached data path\n");
        *cached_path = '\0';
        return NULL;
    }
    if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
    {
        ERR("Could not create full path\n");
        *cached_path = '\0';
        return NULL;
    }
    strcat(cached_path, wine);

    if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
    {
        WARN("Couldn't mkdir %s\n", cached_path);
        *cached_path = '\0';
        return NULL;
    }
    strcat(cached_path, fonts);
    if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
    {
        WARN("Couldn't mkdir %s\n", cached_path);
        *cached_path = '\0';
        return NULL;
    }
    return cached_path;
}

/******************************************************************
 *            expand_mac_font
 *
 * Extracts individual TrueType font files from a Mac suitcase font
 * and saves them into the user's caches directory (see
 * find_cache_dir()).
 * Returns a NULL terminated array of filenames.
 *
 * We do this because they are apps that try to read ttf files
 * themselves and they don't like Mac suitcase files.
 */
static char **expand_mac_font(const char *path)
{
    FSRef ref;
    SInt16 res_ref;
    OSStatus s;
    unsigned int idx;
    const char *out_dir;
    const char *filename;
    int output_len;
    struct {
        char **array;
        unsigned int size, max_size;
    } ret;

    TRACE("path %s\n", path);

    s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
    if(s != noErr)
    {
        WARN("failed to get ref\n");
        return NULL;
    }

    s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
    if(s != noErr)
    {
        TRACE("no data fork, so trying resource fork\n");
        res_ref = FSOpenResFile(&ref, fsRdPerm);
        if(res_ref == -1)
        {
            TRACE("unable to open resource fork\n");
            return NULL;
        }
    }

    ret.size = 0;
    ret.max_size = 10;
    ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
    if(!ret.array)
    {
        CloseResFile(res_ref);
        return NULL;
    }

    out_dir = find_cache_dir();

    filename = strrchr(path, '/');
    if(!filename) filename = path;
    else filename++;

    /* output filename has the form out_dir/filename_%04x.ttf */
    output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;

    UseResFile(res_ref);
    idx = 1;
    while(1)
    {
        FamRec *fam_rec;
        unsigned short *num_faces_ptr, num_faces, face;
        AsscEntry *assoc;
        Handle fond;
600
        ResType fond_res = FT_MAKE_TAG('F','O','N','D');
601

602
        fond = Get1IndResource(fond_res, idx);
603 604 605 606 607 608 609 610 611 612 613 614 615
        if(!fond) break;
        TRACE("got fond resource %d\n", idx);
        HLock(fond);

        fam_rec = *(FamRec**)fond;
        num_faces_ptr = (unsigned short *)(fam_rec + 1);
        num_faces = GET_BE_WORD(*num_faces_ptr);
        num_faces++;
        assoc = (AsscEntry*)(num_faces_ptr + 1);
        TRACE("num faces %04x\n", num_faces);
        for(face = 0; face < num_faces; face++, assoc++)
        {
            Handle sfnt;
616
            ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
617 618 619 620 621 622 623 624 625 626 627 628
            unsigned short size, font_id;
            char *output;

            size = GET_BE_WORD(assoc->fontSize);
            font_id = GET_BE_WORD(assoc->fontID);
            if(size != 0)
            {
                TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
                continue;
            }

            TRACE("trying to load sfnt id %04x\n", font_id);
629
            sfnt = GetResource(sfnt_res, font_id);
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
            if(!sfnt)
            {
                TRACE("can't get sfnt resource %04x\n", font_id);
                continue;
            }

            output = HeapAlloc(GetProcessHeap(), 0, output_len);
            if(output)
            {
                int fd;

                sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);

                fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
                if(fd != -1 || errno == EEXIST)
                {
                    if(fd != -1)
                    {
                        unsigned char *sfnt_data;

                        HLock(sfnt);
                        sfnt_data = *(unsigned char**)sfnt;
                        write(fd, sfnt_data, GetHandleSize(sfnt));
                        HUnlock(sfnt);
                        close(fd);
                    }
                    if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
                    {
                        ret.max_size *= 2;
                        ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
                    }
                    ret.array[ret.size++] = output;
                }
                else
                {
                    WARN("unable to create %s\n", output);
                    HeapFree(GetProcessHeap(), 0, output);
                }
            }
            ReleaseResource(sfnt);
        }
        HUnlock(fond);
        ReleaseResource(fond);
        idx++;
    }
    CloseResFile(res_ref);

    return ret.array;
}

#endif /* HAVE_CARBON_CARBON_H */
681

682 683 684 685
static inline BOOL is_win9x(void)
{
    return GetVersion() & 0x80000000;
}
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
/* 
   This function builds an FT_Fixed from a float. It puts the integer part
   in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
   It fails if the integer part of the float number is greater than SHORT_MAX.
*/
static inline FT_Fixed FT_FixedFromFloat(float f)
{
	short value = f;
	unsigned short fract = (f - value) * 0xFFFF;
	return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
}

/* 
   This function builds an FT_Fixed from a FIXED. It simply put f.value 
   in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
*/
static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
{
	return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
}

707

708
static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
709 710 711
{
    Family *family;
    Face *face;
712
    const char *file;
713 714
    DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
    char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
715

716 717
    WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
    TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
718 719 720

    LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
    {
721 722
        if(face_name && strcmpiW(face_name, family->FamilyName))
            continue;
723 724
        LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
        {
725 726
            if (!face->file)
                continue;
727 728 729 730 731
            file = strrchr(face->file, '/');
            if(!file)
                file = face->file;
            else
                file++;
732 733 734 735 736
            if(!strcasecmp(file, file_nameA))
            {
                HeapFree(GetProcessHeap(), 0, file_nameA);
                return face;
            }
737 738
	}
    }
739
    HeapFree(GetProcessHeap(), 0, file_nameA);
740
    return NULL;
741 742 743 744 745 746 747 748 749 750 751 752 753 754
}

static Family *find_family_from_name(const WCHAR *name)
{
    Family *family;

    LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
    {
        if(!strcmpiW(family->FamilyName, name))
            return family;
    }

    return NULL;
}
755

756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
static void DumpSubstList(void)
{
    FontSubst *psub;

    LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
    {
        if(psub->from.charset != -1 || psub->to.charset != -1)
	    TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
	      psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
	else
	    TRACE("%s -> %s\n", debugstr_w(psub->from.name),
		  debugstr_w(psub->to.name));
    }
    return;
}

static LPWSTR strdupW(LPCWSTR p)
{
    LPWSTR ret;
    DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
    ret = HeapAlloc(GetProcessHeap(), 0, len);
    memcpy(ret, p, len);
    return ret;
}

static LPSTR strdupA(LPCSTR p)
{
    LPSTR ret;
    DWORD len = (strlen(p) + 1);
    ret = HeapAlloc(GetProcessHeap(), 0, len);
    memcpy(ret, p, len);
    return ret;
}

static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
                                 INT from_charset)
{
    FontSubst *element;

    LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
    {
        if(!strcmpiW(element->from.name, from_name) &&
           (element->from.charset == from_charset ||
            element->from.charset == -1))
            return element;
    }

    return NULL;
}

#define ADD_FONT_SUBST_FORCE  1

static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
{
    FontSubst *from_exist, *to_exist;

    from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);

    if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
    {
        list_remove(&from_exist->entry);
        HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
        HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
        HeapFree(GetProcessHeap(), 0, from_exist);
        from_exist = NULL;
    }

    if(!from_exist)
    {
        to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);

        if(to_exist)
        {
            HeapFree(GetProcessHeap(), 0, subst->to.name);
            subst->to.name = strdupW(to_exist->to.name);
        }
            
        list_add_tail(subst_list, &subst->entry);

        return TRUE;
    }

838 839 840
    HeapFree(GetProcessHeap(), 0, subst->from.name);
    HeapFree(GetProcessHeap(), 0, subst->to.name);
    HeapFree(GetProcessHeap(), 0, subst);
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
    return FALSE;
}

static void split_subst_info(NameCs *nc, LPSTR str)
{
    CHAR *p = strrchr(str, ',');
    DWORD len;

    nc->charset = -1;
    if(p && *(p+1)) {
        nc->charset = strtol(p+1, NULL, 10);
	*p = '\0';
    }
    len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
    nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
    MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
}

static void LoadSubstList(void)
{
    FontSubst *psub;
    HKEY hkey;
    DWORD valuelen, datalen, i = 0, type, dlen, vlen;
    LPSTR value;
    LPVOID data;

    if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
		   "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
		   &hkey) == ERROR_SUCCESS) {

        RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
			 &valuelen, &datalen, NULL, NULL);

	valuelen++; /* returned value doesn't include room for '\0' */
	value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
	data = HeapAlloc(GetProcessHeap(), 0, datalen);

	dlen = datalen;
	vlen = valuelen;
	while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
			    &dlen) == ERROR_SUCCESS) {
	    TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));

	    psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
	    split_subst_info(&psub->from, value);
	    split_subst_info(&psub->to, data);

	    /* Win 2000 doesn't allow mapping between different charsets
	       or mapping of DEFAULT_CHARSET */
	    if((psub->to.charset != psub->from.charset) ||
	       psub->to.charset == DEFAULT_CHARSET) {
	        HeapFree(GetProcessHeap(), 0, psub->to.name);
		HeapFree(GetProcessHeap(), 0, psub->from.name);
		HeapFree(GetProcessHeap(), 0, psub);
	    } else {
	        add_font_subst(&font_subst_list, psub, 0);
	    }
	    /* reset dlen and vlen */
	    dlen = datalen;
	    vlen = valuelen;
	}
	HeapFree(GetProcessHeap(), 0, data);
	HeapFree(GetProcessHeap(), 0, value);
	RegCloseKey(hkey);
    }
}

908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
static WCHAR *get_familyname(FT_Face ft_face)
{
    WCHAR *family = NULL;
    FT_SfntName name;
    FT_UInt num_names, name_index, i;

    if(FT_IS_SFNT(ft_face))
    {
        num_names = pFT_Get_Sfnt_Name_Count(ft_face);

        for(name_index = 0; name_index < num_names; name_index++)
        {
            if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
            {
                if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
                   (name.language_id == GetUserDefaultLCID()) &&
                   (name.platform_id == TT_PLATFORM_MICROSOFT) &&
                   (name.encoding_id == TT_MS_ID_UNICODE_CS))
                {
                    /* String is not nul terminated and string_len is a byte length. */
                    family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
                    for(i = 0; i < name.string_len / 2; i++)
                    {
                        WORD *tmp = (WORD *)&name.string[i * 2];
                        family[i] = GET_BE_WORD(*tmp);
                    }
                    family[i] = 0;

                    TRACE("Got localised name %s\n", debugstr_w(family));
                    return family;
                }
            }
        }
    }

    return NULL;
}


947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
/*****************************************************************
 *  load_sfnt_table
 *
 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
 * of FreeType that don't export this function.
 *
 */
static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
{

    FT_Error err;

    /* If the FT_Load_Sfnt_Table function is there we'll use it */
    if(pFT_Load_Sfnt_Table)
    {
        err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
    }
#ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
    else  /* Do it the hard way */
    {
        TT_Face tt_face = (TT_Face) ft_face;
        SFNT_Interface *sfnt;
        if (FT_Version.major==2 && FT_Version.minor==0)
        {
            /* 2.0.x */
            sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
        }
        else
        {
            /* A field was added in the middle of the structure in 2.1.x */
            sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
        }
        err = sfnt->load_any(tt_face, table, offset, buf, len);
    }
#else
    else
    {
        static int msg;
        if(!msg)
        {
            MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
                    "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
                    "Please upgrade your freetype library.\n");
            msg++;
        }
        err = FT_Err_Unimplemented_Feature;
    }
#endif
    return err;
}


999 1000
#define ADDFONT_EXTERNAL_FONT 0x01
#define ADDFONT_FORCE_BITMAP  0x02
1001
static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1002 1003
{
    FT_Face ft_face;
1004
    TT_OS2 *pOS2;
1005
    TT_Header *pHeader = NULL;
1006
    WCHAR *english_family, *localised_family, *StyleW;
1007
    DWORD len;
1008 1009 1010
    Family *family;
    Face *face;
    struct list *family_elem_ptr, *face_elem_ptr;
1011
    FT_Error err;
1012
    FT_Long face_index = 0, num_faces;
1013 1014 1015
#ifdef HAVE_FREETYPE_FTWINFNT_H
    FT_WinFNT_HeaderRec winfnt_header;
#endif
1016 1017
    int i, bitmap_num, internal_leading;
    FONTSIGNATURE fs;
1018

1019 1020 1021
    /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
    assert(file || !(flags & ADDFONT_EXTERNAL_FONT));

1022
#ifdef HAVE_CARBON_CARBON_H
1023
    if(file && !fake_family)
1024 1025 1026 1027 1028 1029 1030 1031 1032
    {
        char **mac_list = expand_mac_font(file);
        if(mac_list)
        {
            BOOL had_one = FALSE;
            char **cursor;
            for(cursor = mac_list; *cursor; cursor++)
            {
                had_one = TRUE;
1033
                AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1034 1035 1036 1037
                HeapFree(GetProcessHeap(), 0, *cursor);
            }
            HeapFree(GetProcessHeap(), 0, mac_list);
            if(had_one)
1038
                return 1;
1039 1040 1041 1042
        }
    }
#endif /* HAVE_CARBON_CARBON_H */

1043
    do {
1044 1045
        char *family_name = fake_family;

1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
        if (file)
        {
            TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
            err = pFT_New_Face(library, file, face_index, &ft_face);
        } else
        {
            TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
            err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
        }

	if(err != 0) {
	    WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1058
	    return 0;
1059
	}
1060

1061
	if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1062
	    WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1063
	    pFT_Done_Face(ft_face);
1064
	    return 0;
1065 1066 1067 1068
	}

        /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
        if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1069
	    WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1070
	    pFT_Done_Face(ft_face);
1071
	    return 0;
1072
	}
1073

1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
        if(FT_IS_SFNT(ft_face))
        {
            if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
               !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
               !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
            {
                TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
                      "Skipping this font.\n", debugstr_a(file), font_data_ptr);
                pFT_Done_Face(ft_face);
                return 0;
            }

            /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
               we don't want to load these. */
            if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
            {
                FT_ULong len = 0;

                if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
                {
                    TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
                    pFT_Done_Face(ft_face);
                    return 0;
                }
            }
        }
1100

1101
        if(!ft_face->family_name || !ft_face->style_name) {
1102
            TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1103
            pFT_Done_Face(ft_face);
1104
            return 0;
1105 1106
        }

1107 1108 1109
        if (target_family)
        {
            localised_family = get_familyname(ft_face);
1110
            if (localised_family && strcmpiW(localised_family,target_family)!=0)
1111 1112 1113 1114
            {
                TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
                HeapFree(GetProcessHeap(), 0, localised_family);
                num_faces = ft_face->num_faces;
1115
                pFT_Done_Face(ft_face);
1116 1117 1118 1119 1120
                continue;
            }
            HeapFree(GetProcessHeap(), 0, localised_family);
        }

1121 1122 1123
        if(!family_name)
            family_name = ft_face->family_name;

1124 1125
        bitmap_num = 0;
        do {
1126
            My_FT_Bitmap_Size *size = NULL;
1127
            FT_ULong tmp_size;
1128 1129 1130 1131

            if(!FT_IS_SCALABLE(ft_face))
                size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;

1132
            len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
            english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
            MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);

            localised_family = NULL;
            if(!fake_family) {
                localised_family = get_familyname(ft_face);
                if(localised_family && !strcmpW(localised_family, english_family)) {
                    HeapFree(GetProcessHeap(), 0, localised_family);
                    localised_family = NULL;
                }
            }
1144

1145 1146 1147
            family = NULL;
            LIST_FOR_EACH(family_elem_ptr, &font_list) {
                family = LIST_ENTRY(family_elem_ptr, Family, entry);
1148
                if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1149
                    break;
1150
                family = NULL;
1151
            }
1152 1153
            if(!family) {
                family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1154
                family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1155 1156
                list_init(&family->faces);
                list_add_tail(&font_list, &family->entry);
1157 1158 1159 1160 1161 1162 1163 1164 1165

                if(localised_family) {
                    FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
                    subst->from.name = strdupW(english_family);
                    subst->from.charset = -1;
                    subst->to.name = strdupW(localised_family);
                    subst->to.charset = -1;
                    add_font_subst(&font_subst_list, subst, 0);
                }
1166
            }
1167 1168
            HeapFree(GetProcessHeap(), 0, localised_family);
            HeapFree(GetProcessHeap(), 0, english_family);
1169

1170 1171 1172 1173
            len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
            StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
            MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);

1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
            internal_leading = 0;
            memset(&fs, 0, sizeof(fs));

            pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
            if(pOS2) {
                fs.fsCsb[0] = pOS2->ulCodePageRange1;
                fs.fsCsb[1] = pOS2->ulCodePageRange2;
                fs.fsUsb[0] = pOS2->ulUnicodeRange1;
                fs.fsUsb[1] = pOS2->ulUnicodeRange2;
                fs.fsUsb[2] = pOS2->ulUnicodeRange3;
                fs.fsUsb[3] = pOS2->ulUnicodeRange4;
                if(pOS2->version == 0) {
                    FT_UInt dummy;

                    if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
                        fs.fsCsb[0] |= 1;
                    else
                        fs.fsCsb[0] |= 1L << 31;
                }
            }
#ifdef HAVE_FREETYPE_FTWINFNT_H
            else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
                CHARSETINFO csi;
                TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
                      winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1199
                if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1200 1201 1202 1203 1204
                    memcpy(&fs, &csi.fs, sizeof(csi.fs));
                internal_leading = winfnt_header.internal_leading;
            }
#endif

1205 1206 1207 1208 1209
            face_elem_ptr = list_head(&family->faces);
            while(face_elem_ptr) {
                face = LIST_ENTRY(face_elem_ptr, Face, entry);
                face_elem_ptr = list_next(&family->faces, face_elem_ptr);
                if(!strcmpW(face->StyleName, StyleW) &&
1210
                   (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1211
                    TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1212 1213
                          debugstr_w(family->FamilyName), debugstr_w(StyleW),
                          face->font_version,  pHeader ? pHeader->Font_Revision : 0);
1214 1215 1216 1217 1218

                    if(fake_family) {
                        TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
                        HeapFree(GetProcessHeap(), 0, StyleW);
                        pFT_Done_Face(ft_face);
1219
                        return 1;
1220
                    }
1221
                    if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1222 1223 1224
                        TRACE("Original font is newer so skipping this one\n");
                        HeapFree(GetProcessHeap(), 0, StyleW);
                        pFT_Done_Face(ft_face);
1225
                        return 1;
1226 1227
                    } else {
                        TRACE("Replacing original with this one\n");
1228 1229 1230 1231
                        list_remove(&face->entry);
                        HeapFree(GetProcessHeap(), 0, face->file);
                        HeapFree(GetProcessHeap(), 0, face->StyleName);
                        HeapFree(GetProcessHeap(), 0, face);
1232 1233
                        break;
                    }
1234
                }
1235
            }
1236 1237 1238
            face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
            list_add_tail(&family->faces, &face->entry);
            face->StyleName = StyleW;
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
            if (file)
            {
                face->file = strdupA(file);
                face->font_data_ptr = NULL;
                face->font_data_size = 0;
            }
            else
            {
                face->file = NULL;
                face->font_data_ptr = font_data_ptr;
                face->font_data_size = font_data_size;
            }
1251 1252 1253 1254 1255 1256
            face->face_index = face_index;
            face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
            face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
            face->font_version = pHeader ? pHeader->Font_Revision : 0;
            face->family = family;
            face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1257
            memcpy(&face->fs, &fs, sizeof(face->fs));
1258
            memset(&face->fs_links, 0, sizeof(face->fs_links));
1259 1260

            if(FT_IS_SCALABLE(ft_face)) {
1261 1262
                memset(&face->size, 0, sizeof(face->size));
                face->scalable = TRUE;
1263 1264 1265 1266
            } else {
                TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
                      size->height, size->width, size->size >> 6,
                      size->x_ppem >> 6, size->y_ppem >> 6);
1267 1268 1269 1270 1271
                face->size.height = size->height;
                face->size.width = size->width;
                face->size.size = size->size;
                face->size.x_ppem = size->x_ppem;
                face->size.y_ppem = size->y_ppem;
1272
                face->size.internal_leading = internal_leading;
1273
                face->scalable = FALSE;
1274 1275
            }

1276 1277
            /* check for the presence of the 'CFF ' table to check if the font is Type1 */
            tmp_size = 0;
1278
            if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1279 1280 1281 1282 1283 1284 1285
            {
                TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
                face->ntmFlags = NTM_PS_OPENTYPE;
            }
            else
                face->ntmFlags = 0;

1286
            TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1287 1288 1289
                  face->fs.fsCsb[0], face->fs.fsCsb[1],
                  face->fs.fsUsb[0], face->fs.fsUsb[1],
                  face->fs.fsUsb[2], face->fs.fsUsb[3]);
1290

1291

1292
            if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1293 1294
                for(i = 0; i < ft_face->num_charmaps; i++) {
                    switch(ft_face->charmaps[i]->encoding) {
1295 1296
                    case FT_ENCODING_UNICODE:
                    case FT_ENCODING_APPLE_ROMAN:
1297
			face->fs.fsCsb[0] |= 1;
1298
                        break;
1299
                    case FT_ENCODING_MS_SYMBOL:
1300
                        face->fs.fsCsb[0] |= 1L << 31;
1301 1302 1303 1304 1305 1306
                        break;
                    default:
                        break;
                    }
                }
            }
1307

1308
            if(face->fs.fsCsb[0] & ~(1L << 31))
1309 1310
                have_installed_roman_font = TRUE;
        } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1311

1312 1313
	num_faces = ft_face->num_faces;
	pFT_Done_Face(ft_face);
1314
	TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1315 1316
	      debugstr_w(StyleW));
    } while(num_faces > ++face_index);
1317
    return num_faces;
1318 1319
}

1320 1321 1322 1323 1324
static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
{
    return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
}

1325 1326 1327 1328
static void DumpFontList(void)
{
    Family *family;
    Face *face;
1329
    struct list *family_elem_ptr, *face_elem_ptr;
1330

1331 1332
    LIST_FOR_EACH(family_elem_ptr, &font_list) {
        family = LIST_ENTRY(family_elem_ptr, Family, entry); 
1333
        TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1334 1335
        LIST_FOR_EACH(face_elem_ptr, &family->faces) {
            face = LIST_ENTRY(face_elem_ptr, Face, entry);
1336
            TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1337
            if(!face->scalable)
1338
                TRACE(" %d", face->size.height);
1339
            TRACE("\n");
1340 1341 1342 1343 1344
	}
    }
    return;
}

1345 1346 1347 1348
/***********************************************************
 * The replacement list is a way to map an entire font
 * family onto another family.  For example adding
 *
1349
 * [HKCU\Software\Wine\Fonts\Replacements]
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
 * "Wingdings"="Winedings"
 *
 * would enumerate the Winedings font both as Winedings and
 * Wingdings.  However if a real Wingdings font is present the
 * replacement does not take place.
 * 
 */
static void LoadReplaceList(void)
{
    HKEY hkey;
    DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1361
    LPWSTR value;
1362 1363 1364
    LPVOID data;
    Family *family;
    Face *face;
1365
    struct list *family_elem_ptr, *face_elem_ptr;
1366
    CHAR familyA[400];
1367

1368 1369 1370
    /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
    if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
    {
1371
        RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1372 1373 1374
			 &valuelen, &datalen, NULL, NULL);

	valuelen++; /* returned value doesn't include room for '\0' */
1375
	value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1376 1377 1378 1379
	data = HeapAlloc(GetProcessHeap(), 0, datalen);

	dlen = datalen;
	vlen = valuelen;
1380
	while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1381
			    &dlen) == ERROR_SUCCESS) {
1382
	    TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1383
            /* "NewName"="Oldname" */
1384
            WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1385 1386 1387

            /* Find the old family and hence all of the font files
               in that family */
1388
            LIST_FOR_EACH(family_elem_ptr, &font_list) {
1389 1390
                family = LIST_ENTRY(family_elem_ptr, Family, entry);
                if(!strcmpiW(family->FamilyName, data)) {
1391 1392
                    LIST_FOR_EACH(face_elem_ptr, &family->faces) {
                        face = LIST_ENTRY(face_elem_ptr, Face, entry);
1393
                        TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1394
                              debugstr_w(face->StyleName), familyA);
1395
                        /* Now add a new entry with the new family name */
1396
                        AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
                    }
                    break;
                }
            }
	    /* reset dlen and vlen */
	    dlen = datalen;
	    vlen = valuelen;
	}
	HeapFree(GetProcessHeap(), 0, data);
	HeapFree(GetProcessHeap(), 0, value);
	RegCloseKey(hkey);
    }
}

1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427
/*************************************************************
 * init_system_links
 */
static BOOL init_system_links(void)
{
    static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
                                        'W','i','n','d','o','w','s',' ','N','T','\\',
                                        'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
                                        'S','y','s','t','e','m','L','i','n','k',0};
    HKEY hkey;
    BOOL ret = FALSE;
    DWORD type, max_val, max_data, val_len, data_len, index;
    WCHAR *value, *data;
    WCHAR *entry, *next;
    SYSTEM_LINKS *font_link, *system_font_link;
    CHILD_FONT *child_font;
    static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1428
    static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1429 1430 1431 1432
    static const WCHAR System[] = {'S','y','s','t','e','m',0};
    FONTSIGNATURE fs;
    Family *family;
    Face *face;
1433
    FontSubst *psub;
1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448

    if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
    {
        RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
        value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
        data = HeapAlloc(GetProcessHeap(), 0, max_data);
        val_len = max_val + 1;
        data_len = max_data;
        index = 0;
        while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
        {
            TRACE("%s:\n", debugstr_w(value));

            memset(&fs, 0, sizeof(fs));
            font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1449 1450
            psub = get_font_subst(&font_subst_list, value, -1);
            font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
            list_init(&font_link->links);
            for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
            {
                WCHAR *face_name;
                CHILD_FONT *child_font;

                TRACE("\t%s\n", debugstr_w(entry));

                next = entry + strlenW(entry) + 1;
                
                face_name = strchrW(entry, ',');
1462
                if(face_name)
1463 1464 1465 1466
                {
                    *face_name++ = 0;
                    while(isspaceW(*face_name))
                        face_name++;
1467 1468 1469 1470

                    psub = get_font_subst(&font_subst_list, face_name, -1);
                    if(psub)
                        face_name = psub->to.name;
1471
                }
1472
                face = find_face_from_filename(entry, face_name);
1473 1474
                if(!face)
                {
1475
                    TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1476 1477 1478 1479
                    continue;
                }

                child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1480
                child_font->face = face;
1481 1482 1483
                child_font->font = NULL;
                fs.fsCsb[0] |= face->fs.fsCsb[0];
                fs.fsCsb[1] |= face->fs.fsCsb[1];
1484
                TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506
                list_add_tail(&font_link->links, &child_font->entry);
            }
            family = find_family_from_name(font_link->font_name);
            if(family)
            {
                LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
                {
                    memcpy(&face->fs_links, &fs, sizeof(fs));
                }
            }
            list_add_tail(&system_links, &font_link->entry);
            val_len = max_val + 1;
            data_len = max_data;
        }

        HeapFree(GetProcessHeap(), 0, value);
        HeapFree(GetProcessHeap(), 0, data);
        RegCloseKey(hkey);
    }

    /* Explicitly add an entry for the system font, this links to Tahoma and any links
       that Tahoma has */
1507

1508 1509 1510
    system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
    system_font_link->font_name = strdupW(System);
    list_init(&system_font_link->links);    
1511

1512
    face = find_face_from_filename(tahoma_ttf, Tahoma);
1513 1514 1515
    if(face)
    {
        child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1516
        child_font->face = face;
1517
        child_font->font = NULL;
1518
        TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1519 1520
        list_add_tail(&system_font_link->links, &child_font->entry);
    }
1521 1522
    LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
    {
1523
        if(!strcmpiW(font_link->font_name, Tahoma))
1524 1525 1526 1527 1528 1529
        {
            CHILD_FONT *font_link_entry;
            LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
            {
                CHILD_FONT *new_child;
                new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1530
                new_child->face = font_link_entry->face;
1531 1532 1533 1534 1535 1536 1537 1538 1539
                new_child->font = NULL;
                list_add_tail(&system_font_link->links, &new_child->entry);
            }
            break;
        }
    }
    list_add_tail(&system_links, &system_font_link->entry);
    return ret;
}
1540

1541
static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1542 1543 1544 1545 1546
{
    DIR *dir;
    struct dirent *dent;
    char path[MAX_PATH];

1547 1548
    TRACE("Loading fonts from %s\n", debugstr_a(dirname));

1549 1550
    dir = opendir(dirname);
    if(!dir) {
1551
        WARN("Can't open directory %s\n", debugstr_a(dirname));
1552 1553 1554
	return FALSE;
    }
    while((dent = readdir(dir)) != NULL) {
1555 1556
	struct stat statbuf;

1557 1558
        if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
	    continue;
1559 1560 1561

	TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));

1562
	sprintf(path, "%s/%s", dirname, dent->d_name);
1563 1564 1565 1566 1567 1568 1569

	if(stat(path, &statbuf) == -1)
	{
	    WARN("Can't stat %s\n", debugstr_a(path));
	    continue;
	}
	if(S_ISDIR(statbuf.st_mode))
1570
	    ReadFontDir(path, external_fonts);
1571
	else
1572
	    AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1573
    }
1574
    closedir(dir);
1575 1576 1577
    return TRUE;
}

1578 1579
static void load_fontconfig_fonts(void)
{
1580
#ifdef SONAME_LIBFONTCONFIG
1581 1582 1583 1584 1585 1586
    void *fc_handle = NULL;
    FcConfig *config;
    FcPattern *pat;
    FcObjectSet *os;
    FcFontSet *fontset;
    int i, len;
1587 1588
    char *file;
    const char *ext;
1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605

    fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
    if(!fc_handle) {
        TRACE("Wine cannot find the fontconfig library (%s).\n",
              SONAME_LIBFONTCONFIG);
	return;
    }
#define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
LOAD_FUNCPTR(FcConfigGetCurrent);
LOAD_FUNCPTR(FcFontList);
LOAD_FUNCPTR(FcFontSetDestroy);
LOAD_FUNCPTR(FcInit);
LOAD_FUNCPTR(FcObjectSetAdd);
LOAD_FUNCPTR(FcObjectSetCreate);
LOAD_FUNCPTR(FcObjectSetDestroy);
LOAD_FUNCPTR(FcPatternCreate);
LOAD_FUNCPTR(FcPatternDestroy);
1606
LOAD_FUNCPTR(FcPatternGetBool);
1607
LOAD_FUNCPTR(FcPatternGetString);
1608 1609 1610 1611 1612 1613 1614 1615
#undef LOAD_FUNCPTR

    if(!pFcInit()) return;
    
    config = pFcConfigGetCurrent();
    pat = pFcPatternCreate();
    os = pFcObjectSetCreate();
    pFcObjectSetAdd(os, FC_FILE);
1616
    pFcObjectSetAdd(os, FC_SCALABLE);
1617 1618 1619
    fontset = pFcFontList(config, pat, os);
    if(!fontset) return;
    for(i = 0; i < fontset->nfont; i++) {
1620 1621
        FcBool scalable;

1622
        if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1623
            continue;
1624
        TRACE("fontconfig: %s\n", file);
1625 1626

        /* We're just interested in OT/TT fonts for now, so this hack just
1627 1628 1629 1630 1631 1632 1633 1634 1635
           picks up the scalable fonts without extensions .pf[ab] to save time
           loading every other font */

        if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
        {
            TRACE("not scalable\n");
            continue;
        }

1636
        len = strlen( file );
1637
        if(len < 4) continue;
1638
        ext = &file[ len - 3 ];
1639
        if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1640
            AddFontFileToList(file, NULL, NULL,  ADDFONT_EXTERNAL_FONT);
1641 1642 1643 1644 1645 1646 1647 1648
    }
    pFcFontSetDestroy(fontset);
    pFcObjectSetDestroy(os);
    pFcPatternDestroy(pat);
 sym_not_found:
#endif
    return;
}
1649

1650 1651 1652 1653 1654
static BOOL load_font_from_data_dir(LPCWSTR file)
{
    BOOL ret = FALSE;
    const char *data_dir = wine_get_data_dir();

1655 1656
    if (!data_dir) data_dir = wine_get_build_dir();

1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670
    if (data_dir)
    {
        INT len;
        char *unix_name;

        len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);

        unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));

        strcpy(unix_name, data_dir);
        strcat(unix_name, "/fonts/");

        WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);

1671
        ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1672 1673 1674 1675
        HeapFree(GetProcessHeap(), 0, unix_name);
    }
    return ret;
}
1676

1677
static void load_system_fonts(void)
1678 1679 1680
{
    HKEY hkey;
    WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1681
    const WCHAR * const *value;
1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692
    DWORD dlen, type;
    static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
    char *unixname;

    if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
        GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
        strcatW(windowsdir, fontsW);
        for(value = SystemFontValues; *value; value++) { 
            dlen = sizeof(data);
            if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
               type == REG_SZ) {
1693 1694
                BOOL added = FALSE;

1695 1696
                sprintfW(pathW, fmtW, windowsdir, data);
                if((unixname = wine_get_unix_file_name(pathW))) {
1697
                    added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1698 1699
                    HeapFree(GetProcessHeap(), 0, unixname);
                }
1700 1701
                if (!added)
                    load_font_from_data_dir(data);
1702 1703 1704 1705 1706 1707
            }
        }
        RegCloseKey(hkey);
    }
}

1708 1709 1710 1711 1712 1713 1714
/*************************************************************
 *
 * This adds registry entries for any externally loaded fonts
 * (fonts from fontconfig or FontDirs).  It also deletes entries
 * of no longer existing fonts.
 *
 */
1715
static void update_reg_entries(void)
1716 1717 1718 1719 1720 1721 1722
{
    HKEY winkey = 0, externalkey = 0;
    LPWSTR valueW;
    LPVOID data;
    DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
    Family *family;
    Face *face;
1723
    struct list *family_elem_ptr, *face_elem_ptr;
1724
    WCHAR *file;
1725 1726
    static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
    static const WCHAR spaceW[] = {' ', '\0'};
1727 1728 1729 1730 1731 1732 1733
    char *path;

    if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
                       0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
        ERR("Can't create Windows font reg key\n");
        goto end;
    }
1734 1735
    /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
    if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
        ERR("Can't create external font reg key\n");
        goto end;
    }

    /* Delete all external fonts added last time */

    RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                     &valuelen, &datalen, NULL, NULL);
    valuelen++; /* returned value doesn't include room for '\0' */
    valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
    data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));

    dlen = datalen * sizeof(WCHAR);
    vlen = valuelen;
    i = 0;
    while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
                        &dlen) == ERROR_SUCCESS) {

        RegDeleteValueW(winkey, valueW);
        /* reset dlen and vlen */
        dlen = datalen;
        vlen = valuelen;
    }
    HeapFree(GetProcessHeap(), 0, data);
    HeapFree(GetProcessHeap(), 0, valueW);

    /* Delete the old external fonts key */
    RegCloseKey(externalkey);
    externalkey = 0;
1765
    RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1766

1767
    /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1768
    if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1769 1770 1771 1772 1773 1774 1775
                       0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
        ERR("Can't create external font reg key\n");
        goto end;
    }

    /* enumerate the fonts and add external ones to the two keys */

1776 1777
    LIST_FOR_EACH(family_elem_ptr, &font_list) {
        family = LIST_ENTRY(family_elem_ptr, Family, entry); 
1778
        len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1779 1780
        LIST_FOR_EACH(face_elem_ptr, &family->faces) {
            face = LIST_ENTRY(face_elem_ptr, Face, entry);
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815
            if(!face->external) continue;
            len = len_fam;
            if(strcmpiW(face->StyleName, RegularW))
                len = len_fam + strlenW(face->StyleName) + 1;
            valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
            strcpyW(valueW, family->FamilyName);
            if(len != len_fam) {
                strcatW(valueW, spaceW);
                strcatW(valueW, face->StyleName);
            }
            strcatW(valueW, TrueType);
            if((path = strrchr(face->file, '/')) == NULL)
                path = face->file;
            else
                path++;
            len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);

            file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
            MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
            RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
            RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));

            HeapFree(GetProcessHeap(), 0, file);
            HeapFree(GetProcessHeap(), 0, valueW);
        }
    }
 end:
    if(externalkey)
        RegCloseKey(externalkey);
    if(winkey)
        RegCloseKey(winkey);
    return;
}


1816 1817 1818 1819 1820 1821 1822 1823
/*************************************************************
 *    WineEngAddFontResourceEx
 *
 */
INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
{
    if (ft_handle)  /* do it only if we have freetype up and running */
    {
1824
        char *unixname;
1825 1826

        if(flags)
1827
            FIXME("Ignoring flags %x\n", flags);
1828

1829 1830
        if((unixname = wine_get_unix_file_name(file)))
        {
1831
            INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1832
            HeapFree(GetProcessHeap(), 0, unixname);
1833
            return ret;
1834
        }
1835
    }
1836
    return 0;
1837
}
1838

1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870
/*************************************************************
 *    WineEngAddFontMemResourceEx
 *
 */
HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
{
    if (ft_handle)  /* do it only if we have freetype up and running */
    {
        PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);

        TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
        memcpy(pFontCopy, pbFont, cbFont);

        *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);

        if (*pcFonts == 0)
        {
            TRACE("AddFontToList failed\n");
            HeapFree(GetProcessHeap(), 0, pFontCopy);
            return NULL;
        }
        /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
         * For now return something unique but quite random
         */
        TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
        return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
    }

    *pcFonts = 0;
    return 0;
}

1871 1872 1873 1874 1875 1876 1877 1878 1879
/*************************************************************
 *    WineEngRemoveFontResourceEx
 *
 */
BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
{
    FIXME(":stub\n");
    return TRUE;
}
1880

1881 1882 1883 1884 1885
static const struct nls_update_font_list
{
    UINT ansi_cp, oem_cp;
    const char *oem, *fixed, *system;
    const char *courier, *serif, *small, *sserif;
1886 1887
   /* these are for font substitute */
    const char *shelldlg, *tmsrmn;
1888 1889
} nls_update_font_list[] =
{
1890 1891
    /* Latin 1 (United States) */
    { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1892
      "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1893
      "Tahoma","Times New Roman",
1894
    },
1895 1896
    /* Latin 1 (Multilingual) */
    { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1897
      "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1898
      "Tahoma","Times New Roman",  /* FIXME unverified */
1899
    },
1900
    /* Eastern Europe */
1901 1902
    { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
      "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1903
      "Tahoma","Times New Roman", /* FIXME unverified */
1904 1905 1906 1907
    },
    /* Cyrillic */
    { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
      "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1908
      "Tahoma","Times New Roman", /* FIXME unverified */
1909 1910 1911 1912
    },
    /* Greek */
    { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
      "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1913
      "Tahoma","Times New Roman", /* FIXME unverified */
1914
    },
1915 1916 1917
    /* Turkish */
    { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
      "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1918
      "Tahoma","Times New Roman", /* FIXME unverified */
1919
    },
1920 1921 1922
    /* Hebrew */
    { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
      "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1923
      "Tahoma","Times New Roman", /* FIXME unverified */
1924
    },
1925 1926 1927
    /* Arabic */
    { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
      "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1928
      "Tahoma","Times New Roman", /* FIXME unverified */
1929
    },
1930 1931 1932
    /* Baltic */
    { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
      "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1933
      "Tahoma","Times New Roman", /* FIXME unverified */
1934 1935 1936
    },
    /* Vietnamese */
    { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1937
      "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1938
      "Tahoma","Times New Roman", /* FIXME unverified */
1939 1940 1941 1942
    },
    /* Thai */
    { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
      "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1943
      "Tahoma","Times New Roman", /* FIXME unverified */
1944
    },
1945 1946 1947
    /* Japanese */
    { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
      "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1948
      "MS UI Gothic","MS Serif",
1949
    },
1950 1951
    /* Chinese Simplified */
    { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1952
      "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1953
      "Tahoma", "Times New Roman", /* FIXME unverified */
1954
    },
1955 1956
    /* Korean */
    { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1957
      "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1958
      "Gulim",  "Batang",
1959
    },
1960 1961
    /* Chinese Traditional */
    { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1962
      "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1963
      "Tahoma",  "Times New Roman", /* FIXME unverified */
1964 1965 1966
    }
};

1967
static inline HKEY create_fonts_NT_registry_key(void)
1968 1969 1970 1971 1972 1973 1974 1975
{
    HKEY hkey = 0;

    RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
                    0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
    return hkey;
}

1976
static inline HKEY create_fonts_9x_registry_key(void)
1977 1978 1979 1980 1981 1982 1983 1984
{
    HKEY hkey = 0;

    RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
                    0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
    return hkey;
}

1985
static inline HKEY create_config_fonts_registry_key(void)
1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
{
    HKEY hkey = 0;

    RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
                    0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
    return hkey;
}

static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
{
    RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
    RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
    RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
    RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
}

static void update_font_info(void)
{
2004
    char buf[40], cpbuf[40];
2005 2006 2007 2008
    DWORD len, type;
    HKEY hkey = 0;
    UINT i, ansi_cp = 0, oem_cp = 0;

2009
    if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2010 2011
        return;

2012 2013 2014 2015 2016 2017
    GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
                   (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
    GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
                   (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
    sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );

2018
    len = sizeof(buf);
2019
    if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2020
    {
2021
        if (!strcmp( buf, cpbuf ))  /* already set correctly */
2022 2023 2024 2025
        {
            RegCloseKey(hkey);
            return;
        }
2026
        TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2027
    }
2028
    else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2029

2030
    RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
    RegCloseKey(hkey);

    for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
    {
        if (nls_update_font_list[i].ansi_cp == ansi_cp &&
            nls_update_font_list[i].oem_cp == oem_cp)
        {
            HKEY hkey;

            hkey = create_config_fonts_registry_key();
            RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2042
            RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053
            RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
            RegCloseKey(hkey);

            hkey = create_fonts_NT_registry_key();
            add_font_list(hkey, &nls_update_font_list[i]);
            RegCloseKey(hkey);

            hkey = create_fonts_9x_registry_key();
            add_font_list(hkey, &nls_update_font_list[i]);
            RegCloseKey(hkey);

2054 2055 2056 2057 2058 2059 2060 2061
            if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
            {
                RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
                               strlen(nls_update_font_list[i].shelldlg)+1);
                RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
                               strlen(nls_update_font_list[i].tmsrmn)+1);
                RegCloseKey(hkey);
            }
2062 2063 2064
            return;
        }
    }
2065
    FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2066 2067
}

2068 2069 2070 2071 2072 2073 2074
/*************************************************************
 *    WineEngInit
 *
 * Initialize FreeType library and create a list of available faces
 */
BOOL WineEngInit(void)
{
2075
    static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2076
    static const WCHAR pathW[] = {'P','a','t','h',0};
2077 2078 2079
    HKEY hkey;
    DWORD valuelen, datalen, i = 0, type, dlen, vlen;
    LPVOID data;
2080
    WCHAR windowsdir[MAX_PATH];
2081
    char *unixname;
2082
    HANDLE font_mutex;
2083
    const char *data_dir;
2084 2085

    TRACE("\n");
2086

2087 2088 2089
    /* update locale dependent font info in registry */
    update_font_info();

2090
    ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101
    if(!ft_handle) {
        WINE_MESSAGE(
      "Wine cannot find the FreeType font library.  To enable Wine to\n"
      "use TrueType fonts please install a version of FreeType greater than\n"
      "or equal to 2.0.5.\n"
      "http://www.freetype.org\n");
	return FALSE;
    }

#define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}

2102
    LOAD_FUNCPTR(FT_Vector_Unit)
2103 2104
    LOAD_FUNCPTR(FT_Done_Face)
    LOAD_FUNCPTR(FT_Get_Char_Index)
2105
    LOAD_FUNCPTR(FT_Get_Module)
2106 2107
    LOAD_FUNCPTR(FT_Get_Sfnt_Name)
    LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2108 2109 2110
    LOAD_FUNCPTR(FT_Get_Sfnt_Table)
    LOAD_FUNCPTR(FT_Init_FreeType)
    LOAD_FUNCPTR(FT_Load_Glyph)
2111
    LOAD_FUNCPTR(FT_Matrix_Multiply)
2112 2113
    LOAD_FUNCPTR(FT_MulFix)
    LOAD_FUNCPTR(FT_New_Face)
2114
    LOAD_FUNCPTR(FT_New_Memory_Face)
2115 2116 2117 2118
    LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
    LOAD_FUNCPTR(FT_Outline_Transform)
    LOAD_FUNCPTR(FT_Outline_Translate)
    LOAD_FUNCPTR(FT_Select_Charmap)
2119
    LOAD_FUNCPTR(FT_Set_Charmap)
2120
    LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2121
    LOAD_FUNCPTR(FT_Vector_Transform)
2122 2123

#undef LOAD_FUNCPTR
2124 2125
    /* Don't warn if this one is missing */
    pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2126
    pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2127
    pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2128
    pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2129
    pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2130 2131 2132
#ifdef HAVE_FREETYPE_FTWINFNT_H
    pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
#endif
2133 2134 2135 2136 2137 2138
      if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
	 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
	/* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
	   <= 2.0.3 has FT_Sqrt64 */
	  goto sym_not_found;
      }
2139

2140
    if(pFT_Init_FreeType(&library) != 0) {
2141
        ERR("Can't init FreeType library\n");
2142
	wine_dlclose(ft_handle, NULL, 0);
2143
        ft_handle = NULL;
2144 2145
	return FALSE;
    }
2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157
    FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
    if (pFT_Library_Version)
    {
        pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
    }
    if (FT_Version.major<=0)
    {
        FT_Version.major=2;
        FT_Version.minor=0;
        FT_Version.patch=5;
    }
    TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2158 2159 2160
    FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
                       ((FT_Version.minor <<  8) & 0x00ff00) |
                       ((FT_Version.patch      ) & 0x0000ff);
2161

2162 2163 2164 2165 2166 2167
    if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
        ERR("Failed to create font mutex\n");
        return FALSE;
    }
    WaitForSingleObject(font_mutex, INFINITE);

2168
    /* load the system bitmap fonts */
2169 2170
    load_system_fonts();

2171
    /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2172 2173
    GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
    strcatW(windowsdir, fontsW);
2174 2175
    if((unixname = wine_get_unix_file_name(windowsdir)))
    {
2176
        ReadFontDir(unixname, FALSE);
2177 2178
        HeapFree(GetProcessHeap(), 0, unixname);
    }
2179

2180 2181
    /* load the system truetype fonts */
    data_dir = wine_get_data_dir();
2182
    if (!data_dir) data_dir = wine_get_build_dir();
2183 2184 2185
    if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
        strcpy(unixname, data_dir);
        strcat(unixname, "/fonts/");
2186
        ReadFontDir(unixname, TRUE);
2187 2188 2189
        HeapFree(GetProcessHeap(), 0, unixname);
    }

2190
    /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2191
       for any fonts not installed in %WINDOWSDIR%\Fonts.  They will have their
2192 2193
       full path as the entry.  Also look for any .fon fonts, since ReadFontDir
       will skip these. */
2194 2195
    if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
                   is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2196
		   &hkey) == ERROR_SUCCESS) {
2197 2198
        LPWSTR valueW;
        RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2199 2200 2201
			 &valuelen, &datalen, NULL, NULL);

	valuelen++; /* returned value doesn't include room for '\0' */
2202 2203
	valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
	data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2204 2205 2206 2207 2208 2209 2210
        if (valueW && data)
        {
            dlen = datalen * sizeof(WCHAR);
            vlen = valuelen;
            while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
                                &dlen) == ERROR_SUCCESS) {
                if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2211
                {
2212 2213
                    if((unixname = wine_get_unix_file_name((LPWSTR)data)))
                    {
2214
                        AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2215 2216 2217 2218 2219 2220 2221
                        HeapFree(GetProcessHeap(), 0, unixname);
                    }
                }
                else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
                {
                    WCHAR pathW[MAX_PATH];
                    static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2222 2223
                    BOOL added = FALSE;

2224 2225 2226
                    sprintfW(pathW, fmtW, windowsdir, data);
                    if((unixname = wine_get_unix_file_name(pathW)))
                    {
2227
                        added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2228 2229
                        HeapFree(GetProcessHeap(), 0, unixname);
                    }
2230 2231
                    if (!added)
                        load_font_from_data_dir(data);
2232
                }
2233 2234 2235 2236 2237
                /* reset dlen and vlen */
                dlen = datalen;
                vlen = valuelen;
            }
        }
2238 2239
        HeapFree(GetProcessHeap(), 0, data);
        HeapFree(GetProcessHeap(), 0, valueW);
2240 2241 2242
	RegCloseKey(hkey);
    }

2243
    load_fontconfig_fonts();
2244 2245

    /* then look in any directories that we've specified in the config file */
2246 2247 2248 2249 2250 2251
    /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
    if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
    {
        DWORD len;
        LPWSTR valueW;
        LPSTR valueA, ptr;
2252

2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275
        if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
        {
            len += sizeof(WCHAR);
            valueW = HeapAlloc( GetProcessHeap(), 0, len );
            if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
            {
                len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
                valueA = HeapAlloc( GetProcessHeap(), 0, len );
                WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
                TRACE( "got font path %s\n", debugstr_a(valueA) );
                ptr = valueA;
                while (ptr)
                {
                    LPSTR next = strchr( ptr, ':' );
                    if (next) *next++ = 0;
                    ReadFontDir( ptr, TRUE );
                    ptr = next;
                }
                HeapFree( GetProcessHeap(), 0, valueA );
            }
            HeapFree( GetProcessHeap(), 0, valueW );
        }
        RegCloseKey(hkey);
2276
    }
2277

2278
    DumpFontList();
2279 2280
    LoadSubstList();
    DumpSubstList();
2281
    LoadReplaceList();
2282 2283
    update_reg_entries();

2284 2285
    init_system_links();
    
2286
    ReleaseMutex(font_mutex);
2287
    return TRUE;
2288 2289 2290 2291 2292 2293 2294
sym_not_found:
    WINE_MESSAGE(
      "Wine cannot find certain functions that it needs inside the FreeType\n"
      "font library.  To enable Wine to use TrueType fonts please upgrade\n"
      "FreeType to at least version 2.0.5.\n"
      "http://www.freetype.org\n");
    wine_dlclose(ft_handle, NULL, 0);
2295
    ft_handle = NULL;
2296
    return FALSE;
2297 2298 2299
}


2300
static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2301 2302
{
    TT_OS2 *pOS2;
2303 2304
    TT_HoriHeader *pHori;

2305 2306
    LONG ppem;

2307
    pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2308
    pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325

    if(height == 0) height = 16;

    /* Calc. height of EM square:
     *
     * For +ve lfHeight we have
     * lfHeight = (winAscent + winDescent) * ppem / units_per_em
     * Re-arranging gives:
     * ppem = units_per_em * lfheight / (winAscent + winDescent)
     *
     * For -ve lfHeight we have
     * |lfHeight| = ppem
     * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
     * with il = winAscent + winDescent - units_per_em]
     *
     */

2326 2327 2328 2329 2330 2331 2332 2333
    if(height > 0) {
        if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
            ppem = ft_face->units_per_EM * height /
                (pHori->Ascender - pHori->Descender);
        else
            ppem = ft_face->units_per_EM * height /
                (pOS2->usWinAscent + pOS2->usWinDescent);
    }
2334 2335 2336
    else
        ppem = -height;

2337 2338 2339
    return ppem;
}

2340
static struct font_mapping *map_font_file( const char *name )
2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380
{
    struct font_mapping *mapping;
    struct stat st;
    int fd;

    if ((fd = open( name, O_RDONLY )) == -1) return NULL;
    if (fstat( fd, &st ) == -1) goto error;

    LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
    {
        if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
        {
            mapping->refcount++;
            close( fd );
            return mapping;
        }
    }
    if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
        goto error;

    mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
    close( fd );

    if (mapping->data == MAP_FAILED)
    {
        HeapFree( GetProcessHeap(), 0, mapping );
        return NULL;
    }
    mapping->refcount = 1;
    mapping->dev = st.st_dev;
    mapping->ino = st.st_ino;
    mapping->size = st.st_size;
    list_add_tail( &mappings_list, &mapping->entry );
    return mapping;

error:
    close( fd );
    return NULL;
}

2381
static void unmap_font_file( struct font_mapping *mapping )
2382 2383 2384 2385 2386 2387 2388 2389 2390
{
    if (!--mapping->refcount)
    {
        list_remove( &mapping->entry );
        munmap( mapping->data, mapping->size );
        HeapFree( GetProcessHeap(), 0, mapping );
    }
}

2391
static LONG load_VDMX(GdiFont*, LONG);
2392

2393
static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2394 2395 2396
{
    FT_Error err;
    FT_Face ft_face;
2397 2398
    void *data_ptr;
    DWORD data_size;
2399

2400
    TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2401

2402
    if (face->file)
2403
    {
2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415
        if (!(font->mapping = map_font_file( face->file )))
        {
            WARN("failed to map %s\n", debugstr_a(face->file));
            return 0;
        }
        data_ptr = font->mapping->data;
        data_size = font->mapping->size;
    }
    else
    {
        data_ptr = face->font_data_ptr;
        data_size = face->font_data_size;
2416
    }
2417

2418
    err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2419 2420 2421 2422 2423 2424 2425 2426
    if(err) {
        ERR("FT_New_Face rets %d\n", err);
	return 0;
    }

    /* set it here, as load_VDMX needs it */
    font->ft_face = ft_face;

2427 2428
    if(FT_IS_SCALABLE(ft_face)) {
        /* load the VDMX table if we have one */
2429 2430 2431
        font->ppem = load_VDMX(font, height);
        if(font->ppem == 0)
            font->ppem = calc_ppem_for_height(ft_face, height);
2432

2433
        if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2434
            WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2435
    } else {
2436
        font->ppem = height;
2437
        if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2438
            WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2439
    }
2440 2441 2442
    return ft_face;
}

2443

2444
static int get_nearest_charset(Face *face, int *cp)
2445 2446 2447 2448 2449
{
  /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
     a single face with the requested charset.  The idea is to check if
     the selected font supports the current ANSI codepage, if it does
     return the corresponding charset, else return the first charset */
2450

2451 2452 2453 2454
    CHARSETINFO csi;
    int acp = GetACP(), i;
    DWORD fs0;

2455
    *cp = acp;
2456
    if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2457
        if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2458 2459 2460 2461
	    return csi.ciCharset;

    for(i = 0; i < 32; i++) {
        fs0 = 1L << i;
2462
        if(face->fs.fsCsb[0] & fs0) {
2463 2464
	    if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
                *cp = csi.ciACP;
2465
	        return csi.ciCharset;
2466
            }
2467
	    else
2468
                FIXME("TCI failing on %x\n", fs0);
2469 2470
	}
    }
2471

2472
    FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2473
	  face->fs.fsCsb[0], face->file);
2474
    *cp = acp;
2475 2476 2477
    return DEFAULT_CHARSET;
}

2478
static GdiFont *alloc_font(void)
2479
{
2480
    GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2481 2482 2483
    ret->gmsize = 1;
    ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
    ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2484
    ret->potm = NULL;
2485
    ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2486 2487
    ret->total_kern_pairs = (DWORD)-1;
    ret->kern_pairs = NULL;
2488
    list_init(&ret->hfontlist);
2489
    list_init(&ret->child_fonts);
2490 2491 2492
    return ret;
}

2493
static void free_font(GdiFont *font)
2494
{
2495
    struct list *cursor, *cursor2;
2496
    int i;
2497 2498 2499 2500 2501 2502 2503

    LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
    {
        CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
        struct list *first_hfont;
        HFONTLIST *hfontlist;
        list_remove(cursor);
2504 2505 2506 2507 2508 2509 2510 2511
        if(child->font)
        {
            first_hfont = list_head(&child->font->hfontlist);
            hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
            DeleteObject(hfontlist->hfont);
            HeapFree(GetProcessHeap(), 0, hfontlist);
            free_font(child->font);
        }
2512 2513 2514
        HeapFree(GetProcessHeap(), 0, child);
    }

2515
    if (font->ft_face) pFT_Done_Face(font->ft_face);
2516
    if (font->mapping) unmap_font_file( font->mapping );
2517
    HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2518 2519
    HeapFree(GetProcessHeap(), 0, font->potm);
    HeapFree(GetProcessHeap(), 0, font->name);
2520 2521
    for (i = 0; i < font->gmsize; i++)
        HeapFree(GetProcessHeap(),0,font->gm[i]);
2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547
    HeapFree(GetProcessHeap(), 0, font->gm);
    HeapFree(GetProcessHeap(), 0, font);
}


/*************************************************************
 * load_VDMX
 *
 * load the vdmx entry for the specified height
 */

#define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
          ( ( (FT_ULong)_x4 << 24 ) |     \
            ( (FT_ULong)_x3 << 16 ) |     \
            ( (FT_ULong)_x2 <<  8 ) |     \
              (FT_ULong)_x1         )

#define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')

typedef struct {
    BYTE bCharSet;
    BYTE xRatio;
    BYTE yStartRatio;
    BYTE yEndRatio;
} Ratios;

2548 2549 2550 2551 2552
typedef struct {
    WORD recs;
    BYTE startsz;
    BYTE endsz;
} VDMX_group;
2553

2554
static LONG load_VDMX(GdiFont *font, LONG height)
2555
{
2556 2557
    WORD hdr[3], tmp;
    VDMX_group group;
2558 2559
    BYTE devXRatio, devYRatio;
    USHORT numRecs, numRatios;
2560
    DWORD result, offset = -1;
2561
    LONG ppem = 0;
2562
    int i;
2563

2564 2565 2566 2567
    /* For documentation on VDMX records, see
     * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
     */

2568 2569 2570 2571 2572 2573 2574 2575 2576
    result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);

    if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
	return ppem;

    /* FIXME: need the real device aspect ratio */
    devXRatio = 1;
    devYRatio = 1;

2577 2578
    numRecs = GET_BE_WORD(hdr[1]);
    numRatios = GET_BE_WORD(hdr[2]);
2579

2580
    TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2581 2582
    for(i = 0; i < numRatios; i++) {
	Ratios ratio;
2583

2584 2585 2586 2587 2588 2589
	offset = (3 * 2) + (i * sizeof(Ratios));
	WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
	offset = -1;

	TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);

2590
	if((ratio.xRatio == 0 &&
2591 2592
	    ratio.yStartRatio == 0 &&
	    ratio.yEndRatio == 0) ||
2593
	   (devXRatio == ratio.xRatio &&
2594
	    devYRatio >= ratio.yStartRatio &&
2595
	    devYRatio <= ratio.yEndRatio))
2596 2597
	    {
		offset = (3 * 2) + (numRatios * 4) + (i * 2);
2598
		WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2599 2600 2601 2602 2603
		offset = GET_BE_WORD(tmp);
		break;
	    }
    }

2604
    if(offset == -1) {
2605
	FIXME("No suitable ratio found\n");
2606 2607 2608
	return ppem;
    }

2609
    if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2610 2611
	USHORT recs;
	BYTE startsz, endsz;
2612
	WORD *vTable;
2613

2614 2615 2616
	recs = GET_BE_WORD(group.recs);
	startsz = group.startsz;
	endsz = group.endsz;
2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628

	TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);

	vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
	result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
	if(result == GDI_ERROR) {
	    FIXME("Failed to retrieve vTable\n");
	    goto end;
	}

	if(height > 0) {
	    for(i = 0; i < recs; i++) {
2629 2630 2631
                SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
                SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
                ppem = GET_BE_WORD(vTable[i * 3]);
2632 2633 2634 2635

		if(yMax + -yMin == height) {
		    font->yMax = yMax;
		    font->yMin = yMin;
2636
                    TRACE("ppem %d found; height=%d  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
2637 2638 2639 2640 2641 2642 2643
		    break;
		}
		if(yMax + -yMin > height) {
		    if(--i < 0) {
			ppem = 0;
			goto end; /* failed */
		    }
2644 2645
		    font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
		    font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2646
                    ppem = GET_BE_WORD(vTable[i * 3]);
2647
                    TRACE("ppem %d found; height=%d  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
2648 2649 2650 2651 2652
		    break;
		}
	    }
	    if(!font->yMax) {
		ppem = 0;
2653
		TRACE("ppem not found for height %d\n", height);
2654 2655 2656 2657 2658 2659 2660 2661
	    }
	} else {
	    ppem = -height;
	    if(ppem < startsz || ppem > endsz)
		goto end;

	    for(i = 0; i < recs; i++) {
		USHORT yPelHeight;
2662
		yPelHeight = GET_BE_WORD(vTable[i * 3]);
2663

2664 2665
		if(yPelHeight > ppem)
		    break; /* failed */
2666

2667
		if(yPelHeight == ppem) {
2668 2669
		    font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
		    font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2670
                    TRACE("ppem %d found; yMax=%d  yMin=%d\n", ppem, font->yMax, font->yMin);
2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681
		    break;
		}
	    }
	}
	end:
	HeapFree(GetProcessHeap(), 0, vTable);
    }

    return ppem;
}

2682
static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2683 2684 2685 2686
{
    if(font->font_desc.hash != fd->hash) return TRUE;
    if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
    if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2687
    if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2688 2689 2690 2691 2692 2693 2694
    return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
}

static void calc_hash(FONT_DESC *pfd)
{
    DWORD hash = 0, *ptr, two_chars;
    WORD *pwc;
2695
    unsigned int i;
2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710

    for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
        hash ^= *ptr;
    for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
        hash ^= *ptr;
    for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
        two_chars = *ptr;
        pwc = (WCHAR *)&two_chars;
        if(!*pwc) break;
        *pwc = toupperW(*pwc);
        pwc++;
        *pwc = toupperW(*pwc);
        hash ^= two_chars;
        if(!*pwc) break;
    }
2711
    hash ^= !pfd->can_use_bitmap;
2712 2713 2714 2715
    pfd->hash = hash;
    return;
}

2716
static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2717
{
2718
    GdiFont *ret;
2719 2720 2721 2722 2723 2724
    FONT_DESC fd;
    HFONTLIST *hflist;
    struct list *font_elem_ptr, *hfontlist_elem_ptr;

    memcpy(&fd.lf, plf, sizeof(LOGFONTW));
    memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2725
    fd.can_use_bitmap = can_use_bitmap;
2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763
    calc_hash(&fd);

    /* try the in-use list */
    LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
        ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
        if(!fontcmp(ret, &fd)) {
            if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
            LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
                hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
                if(hflist->hfont == hfont)
                    return ret;
            }
            hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
            hflist->hfont = hfont;
            list_add_head(&ret->hfontlist, &hflist->entry);
            return ret;
        }
    }
 
    /* then the unused list */
    font_elem_ptr = list_head(&unused_gdi_font_list);
    while(font_elem_ptr) {
        ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
        font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
        if(!fontcmp(ret, &fd)) {
            if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
            assert(list_empty(&ret->hfontlist));
            TRACE("Found %p in unused list\n", ret);
            list_remove(&ret->entry);
            list_add_head(&gdi_font_list, &ret->entry);
            hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
            hflist->hfont = hfont;
            list_add_head(&ret->hfontlist, &hflist->entry);
            return ret;
        }
    }
    return NULL;
}
2764

2765 2766 2767 2768
    
/*************************************************************
 * create_child_font_list
 */
2769
static BOOL create_child_font_list(GdiFont *font)
2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782
{
    BOOL ret = FALSE;
    SYSTEM_LINKS *font_link;
    CHILD_FONT *font_link_entry, *new_child;

    LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
    {
        if(!strcmpW(font_link->font_name, font->name))
        {
            TRACE("found entry in system list\n");
            LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
            {
                new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2783
                new_child->face = font_link_entry->face;
2784 2785
                new_child->font = NULL;
                list_add_tail(&font->child_fonts, &new_child->entry);
2786
                TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2787 2788 2789 2790 2791 2792 2793 2794 2795
            }
            ret = TRUE;
            break;
        }
    }

    return ret;
}

2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850
static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
{
    FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;

    if (pFT_Set_Charmap)
    {
        FT_Int i;
        FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;

        cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;

        for (i = 0; i < ft_face->num_charmaps; i++)
        {
            if (ft_face->charmaps[i]->encoding == encoding)
            {
                TRACE("found cmap with platform_id %u, encoding_id %u\n",
                       ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);

                switch (ft_face->charmaps[i]->platform_id)
                {
                    default:
                        cmap_def = ft_face->charmaps[i];
                        break;
                    case 0: /* Apple Unicode */
                        cmap0 = ft_face->charmaps[i];
                        break;
                    case 1: /* Macintosh */
                        cmap1 = ft_face->charmaps[i];
                        break;
                    case 2: /* ISO */
                        cmap2 = ft_face->charmaps[i];
                        break;
                    case 3: /* Microsoft */
                        cmap3 = ft_face->charmaps[i];
                        break;
                }
            }

            if (cmap3) /* prefer Microsoft cmap table */
                ft_err = pFT_Set_Charmap(ft_face, cmap3);
            else if (cmap1)
                ft_err = pFT_Set_Charmap(ft_face, cmap1);
            else if (cmap2)
                ft_err = pFT_Set_Charmap(ft_face, cmap2);
            else if (cmap0)
                ft_err = pFT_Set_Charmap(ft_face, cmap0);
            else if (cmap_def)
                ft_err = pFT_Set_Charmap(ft_face, cmap_def);
        }
        return ft_err == FT_Err_Ok;
    }

    return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
}

2851 2852 2853 2854
/*************************************************************
 * WineEngCreateFontInstance
 *
 */
2855
GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2856
{
2857
    GdiFont *ret;
2858
    Face *face, *best, *best_bitmap;
2859
    Family *family, *last_resort_family;
2860
    struct list *family_elem_ptr, *face_elem_ptr;
2861
    INT height, width = 0;
2862
    unsigned int score = 0, new_score;
2863 2864
    signed int diff = 0, newdiff;
    BOOL bd, it, can_use_bitmap;
2865
    LOGFONTW lf;
2866
    CHARSETINFO csi;
2867
    HFONTLIST *hflist;
2868

2869 2870 2871 2872 2873 2874 2875 2876
    LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
    {
        struct list *first_hfont = list_head(&ret->hfontlist);
        hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
        if(hflist->hfont == hfont)
            return ret;
    }

2877
    if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2878
    can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2879

2880
    TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2881 2882 2883
	  debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
	  lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
	  lf.lfEscapement);
2884 2885

    /* check the cache first */
2886 2887 2888
    if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
        TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
        return ret;
2889 2890
    }

2891
    TRACE("not in cache\n");
2892
    if(list_empty(&font_list)) /* No fonts installed */
2893 2894 2895 2896
    {
	TRACE("No fonts installed\n");
	return NULL;
    }
2897 2898 2899 2900 2901
    if(!have_installed_roman_font)
    {
	TRACE("No roman font installed\n");
	return NULL;
    }
2902

2903
    ret = alloc_font();
2904 2905 2906

     memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
     memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2907
     ret->font_desc.can_use_bitmap = can_use_bitmap;
2908 2909 2910 2911 2912
     calc_hash(&ret->font_desc);
     hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
     hflist->hfont = hfont;
     list_add_head(&ret->hfontlist, &hflist->entry);

2913

2914 2915 2916 2917 2918 2919 2920 2921
    /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
       SYMBOL_CHARSET so that Symbol gets picked irrespective of the
       original value lfCharSet.  Note this is a special case for
       Symbol and doesn't happen at least for "Wingdings*" */

    if(!strcmpiW(lf.lfFaceName, SymbolW))
        lf.lfCharSet = SYMBOL_CHARSET;

2922
    if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933
        switch(lf.lfCharSet) {
	case DEFAULT_CHARSET:
	    csi.fs.fsCsb[0] = 0;
	    break;
	default:
	    FIXME("Untranslated charset %d\n", lf.lfCharSet);
	    csi.fs.fsCsb[0] = 0;
	    break;
	}
    }

2934
    family = NULL;
2935
    if(lf.lfFaceName[0] != '\0') {
2936
        FontSubst *psub;
2937 2938 2939
        SYSTEM_LINKS *font_link;
        CHILD_FONT *font_link_entry;

2940 2941
        psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);

2942
	if(psub) {
2943
	    TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2944
		  debugstr_w(psub->to.name));
2945
	    strcpyW(lf.lfFaceName, psub->to.name);
2946 2947
	}

2948 2949 2950 2951 2952 2953
	/* We want a match on name and charset or just name if
	   charset was DEFAULT_CHARSET.  If the latter then
	   we fixup the returned charset later in get_nearest_charset
	   where we'll either use the charset of the current ansi codepage
	   or if that's unavailable the first charset that the font supports.
	*/
2954 2955 2956
        LIST_FOR_EACH(family_elem_ptr, &font_list) {
            family = LIST_ENTRY(family_elem_ptr, Family, entry);
	    if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2957 2958
                LIST_FOR_EACH(face_elem_ptr, &family->faces) { 
                    face = LIST_ENTRY(face_elem_ptr, Face, entry);
2959
                    if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2960 2961 2962
                        if(face->scalable || can_use_bitmap)
                            goto found;
                }
2963
            }
2964
	}
2965 2966 2967 2968 2969 2970 2971

        /*
	 * Try check the SystemLink list first for a replacement font.
	 * We may find good replacements there.
         */
        LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
        {
2972
            if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2973 2974 2975 2976
            {
                TRACE("found entry in system list\n");
                LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
                {
2977 2978 2979 2980
                    face = font_link_entry->face;
                    family = face->family;
                    if(csi.fs.fsCsb[0] &
                        (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2981
                    {
2982 2983
                        if(face->scalable || can_use_bitmap)
                            goto found;
2984 2985 2986 2987
                    }
                }
            }
        }
2988 2989
    }

2990 2991 2992 2993
    /* If requested charset was DEFAULT_CHARSET then try using charset
       corresponding to the current ansi codepage */
    if(!csi.fs.fsCsb[0]) {
        INT acp = GetACP();
2994
        if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2995 2996 2997 2998 2999
            FIXME("TCI failed on codepage %d\n", acp);
            csi.fs.fsCsb[0] = 0;
        } else
            lf.lfCharSet = csi.ciCharset;
    }
3000

3001 3002
    /* Face families are in the top 4 bits of lfPitchAndFamily,
       so mask with 0xF0 before testing */
3003

3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016
    if((lf.lfPitchAndFamily & FIXED_PITCH) ||
       (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
        strcpyW(lf.lfFaceName, defFixed);
    else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
        strcpyW(lf.lfFaceName, defSerif);
    else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
        strcpyW(lf.lfFaceName, defSans);
    else
        strcpyW(lf.lfFaceName, defSans);
    LIST_FOR_EACH(family_elem_ptr, &font_list) {
        family = LIST_ENTRY(family_elem_ptr, Family, entry);
        if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
            LIST_FOR_EACH(face_elem_ptr, &family->faces) { 
3017
                face = LIST_ENTRY(face_elem_ptr, Face, entry);
3018
                if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3019
                    if(face->scalable || can_use_bitmap)
3020
                        goto found;
3021
            }
3022
        }
3023 3024
    }

3025
    last_resort_family = NULL;
3026 3027 3028
    LIST_FOR_EACH(family_elem_ptr, &font_list) {
        family = LIST_ENTRY(family_elem_ptr, Family, entry);
        LIST_FOR_EACH(face_elem_ptr, &family->faces) { 
3029
            face = LIST_ENTRY(face_elem_ptr, Face, entry);
3030 3031
            if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
                if(face->scalable)
3032
                    goto found;
3033 3034 3035
                if(can_use_bitmap && !last_resort_family)
                    last_resort_family = family;
            }            
3036
        }
3037 3038
    }

3039 3040 3041 3042 3043 3044
    if(last_resort_family) {
        family = last_resort_family;
        csi.fs.fsCsb[0] = 0;
        goto found;
    }

3045 3046 3047
    LIST_FOR_EACH(family_elem_ptr, &font_list) {
        family = LIST_ENTRY(family_elem_ptr, Family, entry);
        LIST_FOR_EACH(face_elem_ptr, &family->faces) { 
3048
            face = LIST_ENTRY(face_elem_ptr, Face, entry);
3049
            if(face->scalable) {
3050
                csi.fs.fsCsb[0] = 0;
3051
                WARN("just using first face for now\n");
3052
                goto found;
3053
            }
3054 3055
            if(can_use_bitmap && !last_resort_family)
                last_resort_family = family;
3056
        }
3057
    }
3058 3059 3060 3061 3062 3063 3064 3065 3066
    if(!last_resort_family) {
        FIXME("can't find a single appropriate font - bailing\n");
        free_font(ret);
        return NULL;
    }

    WARN("could only find a bitmap font - this will probably look awful!\n");
    family = last_resort_family;
    csi.fs.fsCsb[0] = 0;
3067

3068
found:
3069 3070
    it = lf.lfItalic ? 1 : 0;
    bd = lf.lfWeight > 550 ? 1 : 0;
3071

3072 3073 3074
    height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
    height = lf.lfHeight < 0 ? -abs(height) : abs(height);

3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085
    face = best = best_bitmap = NULL;
    LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
    {
        if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
        {
            new_score = (face->Italic ^ it) + (face->Bold ^ bd);
            if(!best || new_score <= score)
            {
                TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
                      face->Italic, face->Bold, it, bd);
                score = new_score;
3086
                best = face;
3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101
                if(best->scalable  && score == 0) break;
                if(!best->scalable)
                {
                    if(height > 0)
                        newdiff = height - (signed int)(best->size.height);
                    else
                        newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
                    if(!best_bitmap || new_score < score ||
                       (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
                    {
                        TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
                        diff = newdiff;
                        best_bitmap = best;
                        if(score == 0 && diff == 0) break;
                    }
3102
                }
3103 3104
            }
        }
3105
    }
3106 3107 3108 3109
    if(best)
        face = best->scalable ? best : best_bitmap;
    ret->fake_italic = (it && !face->Italic);
    ret->fake_bold = (bd && !face->Bold);
3110

3111 3112
    memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));

3113
    if(csi.fs.fsCsb[0]) {
3114
        ret->charset = lf.lfCharSet;
3115 3116
        ret->codepage = csi.ciACP;
    }
3117
    else
3118
        ret->charset = get_nearest_charset(face, &ret->codepage);
3119

3120 3121
    TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
	  debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3122

3123 3124 3125 3126
    if(!face->scalable) {
        width = face->size.x_ppem >> 6;
        height = face->size.y_ppem >> 6;
    }
3127
    ret->ft_face = OpenFontFace(ret, face, width, height);
3128

3129 3130 3131 3132 3133
    if (!ret->ft_face)
    {
        free_font( ret );
        return 0;
    }
3134

3135 3136
    ret->ntmFlags = face->ntmFlags;

3137
    if (ret->charset == SYMBOL_CHARSET && 
3138
        select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3139 3140
        /* No ops */
    }
3141
    else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3142 3143 3144
        /* No ops */
    }
    else {
3145
        select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3146
    }
3147

3148
    ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3149
    ret->name = strdupW(family->FamilyName);
3150 3151
    ret->underline = lf.lfUnderline ? 0xff : 0;
    ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3152
    create_child_font_list(ret);
3153

3154
    TRACE("caching: gdiFont=%p  hfont=%p\n", ret, hfont);
3155

3156
    ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
3157
    list_add_head(&gdi_font_list, &ret->entry);
3158 3159 3160
    return ret;
}

3161
static void dump_gdi_font_list(void)
3162
{
3163
    GdiFont *gdiFont;
3164
    struct list *elem_ptr;
3165 3166

    TRACE("---------- gdiFont Cache ----------\n");
3167 3168
    LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
        gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3169
        TRACE("gdiFont=%p %s %d\n",
3170 3171 3172 3173 3174 3175
              gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
    }

    TRACE("---------- Unused gdiFont Cache ----------\n");
    LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
        gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3176
        TRACE("gdiFont=%p %s %d\n",
3177
              gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3178
    }
3179 3180 3181
}

/*************************************************************
3182 3183 3184
 * WineEngDestroyFontInstance
 *
 * free the gdiFont associated with this handle
3185 3186
 *
 */
3187
BOOL WineEngDestroyFontInstance(HFONT handle)
3188
{
3189
    GdiFont *gdiFont;
3190
    HFONTLIST *hflist;
3191
    BOOL ret = FALSE;
3192 3193
    struct list *font_elem_ptr, *hfontlist_elem_ptr;
    int i = 0;
3194

3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206
    LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
    {
        struct list *first_hfont = list_head(&gdiFont->hfontlist);
        hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
        if(hflist->hfont == handle)
        {
            TRACE("removing child font %p from child list\n", gdiFont);
            list_remove(&gdiFont->entry);
            return TRUE;
        }
    }

3207
    TRACE("destroying hfont=%p\n", handle);
3208
    if(TRACE_ON(font))
3209 3210
	dump_gdi_font_list();

3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227
    font_elem_ptr = list_head(&gdi_font_list);
    while(font_elem_ptr) {
        gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
        font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);

        hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
        while(hfontlist_elem_ptr) {
            hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
            hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
            if(hflist->hfont == handle) {
                list_remove(&hflist->entry);
                HeapFree(GetProcessHeap(), 0, hflist);
                ret = TRUE;
            }
        }
        if(list_empty(&gdiFont->hfontlist)) {
            TRACE("Moving to Unused list\n");
3228
            list_remove(&gdiFont->entry);
3229
            list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3230
        }
3231
    }
3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243


    font_elem_ptr = list_head(&unused_gdi_font_list);
    while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
        font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
    while(font_elem_ptr) {
        gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
        font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
        TRACE("freeing %p\n", gdiFont);
        list_remove(&gdiFont->entry);
        free_font(gdiFont);
    }
3244
    return ret;
3245 3246 3247
}

static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3248
			   NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3249
{
3250
    OUTLINETEXTMETRICW *potm = NULL;
3251
    UINT size;
3252
    TEXTMETRICW tm, *ptm;
3253
    GdiFont *font = alloc_font();
3254
    LONG width, height;
3255

3256 3257 3258 3259 3260 3261 3262 3263
    if(face->scalable) {
        height = 100;
        width = 0;
    } else {
        height = face->size.y_ppem >> 6;
        width = face->size.x_ppem >> 6;
    }
    
3264
    if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3265 3266 3267 3268
    {
        free_font(font);
        return;
    }
3269

3270
    font->name = strdupW(face->family->FamilyName);
3271
    font->ntmFlags = face->ntmFlags;
3272

3273 3274 3275
    memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));

    size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305
    if(size) {
        potm = HeapAlloc(GetProcessHeap(), 0, size);
        WineEngGetOutlineTextMetrics(font, size, potm);
        ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
    } else {
        WineEngGetTextMetrics(font, &tm);
        ptm = &tm;
    }
        
    pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
    pntm->ntmTm.tmAscent = ptm->tmAscent;
    pntm->ntmTm.tmDescent = ptm->tmDescent;
    pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
    pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
    pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
    pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
    pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
    pntm->ntmTm.tmOverhang = ptm->tmOverhang;
    pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
    pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
    pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
    pntm->ntmTm.tmLastChar = ptm->tmLastChar;
    pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
    pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
    pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
    pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
    pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
    pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
    pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
    pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3306 3307 3308
    pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
    pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
    pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3309

3310 3311 3312 3313 3314
    *ptype = 0;
    if (ptm->tmPitchAndFamily & TMPF_TRUETYPE)
        *ptype |= TRUETYPE_FONTTYPE;
    if (ptm->tmPitchAndFamily & TMPF_DEVICE)
        *ptype |= DEVICE_FONTTYPE;
3315 3316
    if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
        *ptype |= RASTER_FONTTYPE;
3317

3318 3319 3320
    pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
    if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
    if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3321
    pntm->ntmTm.ntmFlags |= face->ntmFlags;
3322

3323 3324 3325
    pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
    pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
    memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3326

3327 3328
    if(potm) {
        pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3329

3330
        lstrcpynW(pelf->elfLogFont.lfFaceName,
3331 3332
                 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
                 LF_FACESIZE);
3333
        lstrcpynW(pelf->elfFullName,
3334 3335
                 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
                 LF_FULLFACESIZE);
3336
        lstrcpynW(pelf->elfStyle,
3337 3338 3339
                 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
                 LF_FACESIZE);

3340
        HeapFree(GetProcessHeap(), 0, potm);
3341
    } else {
3342 3343
        pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;

3344 3345
        lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
        lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3346 3347
        pelf->elfStyle[0] = '\0';
    }
3348

3349
    pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3350

3351
    free_font(font);
3352 3353 3354 3355 3356 3357
}

/*************************************************************
 * WineEngEnumFonts
 *
 */
3358
DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3359 3360 3361
{
    Family *family;
    Face *face;
3362
    struct list *family_elem_ptr, *face_elem_ptr;
3363 3364 3365
    ENUMLOGFONTEXW elf;
    NEWTEXTMETRICEXW ntm;
    DWORD type, ret = 1;
3366 3367
    FONTSIGNATURE fs;
    CHARSETINFO csi;
3368
    LOGFONTW lf;
3369
    int i;
3370

3371
    TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3372

3373
    if(plf->lfFaceName[0]) {
3374
        FontSubst *psub;
3375 3376
        psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);

3377 3378 3379 3380 3381 3382 3383
        if(psub) {
            TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
                  debugstr_w(psub->to.name));
            memcpy(&lf, plf, sizeof(lf));
            strcpyW(lf.lfFaceName, psub->to.name);
            plf = &lf;
        }
3384 3385 3386 3387 3388 3389 3390 3391

        LIST_FOR_EACH(family_elem_ptr, &font_list) {
            family = LIST_ENTRY(family_elem_ptr, Family, entry);
            if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
                LIST_FOR_EACH(face_elem_ptr, &family->faces) {
                    face = LIST_ENTRY(face_elem_ptr, Face, entry);
                    GetEnumStructs(face, &elf, &ntm, &type);
                    for(i = 0; i < 32; i++) {
3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413
                        if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
                            elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
                            strcpyW(elf.elfScript, OEM_DOSW);
                            i = 32; /* break out of loop */
                        } else if(!(face->fs.fsCsb[0] & (1L << i)))
                            continue;
                        else {
                            fs.fsCsb[0] = 1L << i;
                            fs.fsCsb[1] = 0;
                            if(!TranslateCharsetInfo(fs.fsCsb, &csi,
                                                     TCI_SRCFONTSIG))
                                csi.ciCharset = DEFAULT_CHARSET;
                            if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
                            if(csi.ciCharset != DEFAULT_CHARSET) {
                                elf.elfLogFont.lfCharSet =
                                    ntm.ntmTm.tmCharSet = csi.ciCharset;
                                if(ElfScriptsW[i])
                                    strcpyW(elf.elfScript, ElfScriptsW[i]);
                                else
                                    FIXME("Unknown elfscript for bit %d\n", i);
                            }
                        }
3414
                        TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3415 3416 3417 3418 3419 3420 3421
                              debugstr_w(elf.elfLogFont.lfFaceName),
                              debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
                              csi.ciCharset, type, debugstr_w(elf.elfScript),
                              elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
                              ntm.ntmTm.ntmFlags);
                        ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
                        if(!ret) goto end;
3422
		    }
3423 3424 3425 3426
		}
	    }
	}
    } else {
3427 3428 3429 3430 3431 3432 3433
        LIST_FOR_EACH(family_elem_ptr, &font_list) {
            family = LIST_ENTRY(family_elem_ptr, Family, entry);
            face_elem_ptr = list_head(&family->faces);
            face = LIST_ENTRY(face_elem_ptr, Face, entry);
            GetEnumStructs(face, &elf, &ntm, &type);
            for(i = 0; i < 32; i++) {
                if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3434 3435 3436
                    elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
                    strcpyW(elf.elfScript, OEM_DOSW);
                    i = 32; /* break out of loop */
3437
	        } else if(!(face->fs.fsCsb[0] & (1L << i)))
3438 3439
                    continue;
                else {
3440 3441 3442 3443 3444 3445 3446
		    fs.fsCsb[0] = 1L << i;
		    fs.fsCsb[1] = 0;
		    if(!TranslateCharsetInfo(fs.fsCsb, &csi,
					     TCI_SRCFONTSIG))
		        csi.ciCharset = DEFAULT_CHARSET;
		    if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
		    if(csi.ciCharset != DEFAULT_CHARSET) {
3447
		        elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3448 3449 3450 3451 3452
			  csi.ciCharset;
			  if(ElfScriptsW[i])
			      strcpyW(elf.elfScript, ElfScriptsW[i]);
			  else
			      FIXME("Unknown elfscript for bit %d\n", i);
3453 3454
                    }
                }
3455
                TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3456 3457 3458 3459 3460 3461 3462
                      debugstr_w(elf.elfLogFont.lfFaceName),
                      debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
                      csi.ciCharset, type, debugstr_w(elf.elfScript),
                      elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
                      ntm.ntmTm.ntmFlags);
                ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
                if(!ret) goto end;
3463
	    }
3464 3465
	}
    }
3466
end:
3467 3468 3469
    return ret;
}

3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480
static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
{
    pt->x.value = vec->x >> 6;
    pt->x.fract = (vec->x & 0x3f) << 10;
    pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
    pt->y.value = vec->y >> 6;
    pt->y.fract = (vec->y & 0x3f) << 10;
    pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
    return;
}

3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499
/***************************************************
 * According to the MSDN documentation on WideCharToMultiByte,
 * certain codepages cannot set the default_used parameter.
 * This returns TRUE if the codepage can set that parameter, false else
 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
 */
static BOOL codepage_sets_default_used(UINT codepage)
{
   switch (codepage)
   {
       case CP_UTF7:
       case CP_UTF8:
       case CP_SYMBOL:
           return FALSE;
       default:
           return TRUE;
   }
}

3500
static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3501
{
3502 3503
    if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
        WCHAR wc = (WCHAR)glyph;
3504
        BOOL default_used;
3505
        BOOL *default_used_pointer;
3506
        FT_UInt ret;
3507
        char buf;
3508 3509 3510 3511 3512
        default_used_pointer = NULL;
        default_used = FALSE;
        if (codepage_sets_default_used(font->codepage))
            default_used_pointer = &default_used;
        if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3513 3514 3515 3516 3517
            ret = 0;
        else
            ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
        TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
        return ret;
3518 3519
    }

3520 3521
    if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
        glyph = glyph + 0xf000;
3522
    return pFT_Get_Char_Index(font->ft_face, glyph);
3523 3524
}

3525 3526 3527 3528 3529
/*************************************************************
 * WineEngGetGlyphIndices
 *
 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
 */
3530
DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3531 3532
				LPWORD pgi, DWORD flags)
{
3533 3534 3535 3536 3537
    int i;
    WCHAR default_char = 0;
    TEXTMETRICW textm;

    if  (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f;  /* Indicate non existence */
3538 3539

    for(i = 0; i < count; i++)
3540
    {
3541
        pgi[i] = get_glyph_index(font, lpstr[i]);
3542 3543 3544 3545 3546 3547 3548 3549 3550 3551
        if  (pgi[i] == 0)
        {
            if (!default_char)
            {
                WineEngGetTextMetrics(font, &textm);
                default_char = textm.tmDefaultChar;
            }
            pgi[i] = default_char;
        }
    }
3552 3553 3554
    return count;
}

3555 3556 3557 3558 3559 3560 3561 3562
/*************************************************************
 * WineEngGetGlyphOutline
 *
 * Behaves in exactly the same way as the win32 api GetGlyphOutline
 * except that the first parameter is the HWINEENGFONT of the font in
 * question rather than an HDC.
 *
 */
3563
DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3564 3565 3566
			     LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
			     const MAT2* lpmat)
{
3567
    static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3568 3569
    FT_Face ft_face = incoming_font->ft_face;
    GdiFont *font = incoming_font;
3570
    FT_UInt glyph_index;
3571
    DWORD width, height, pitch, needed = 0;
3572
    FT_Bitmap ft_bitmap;
3573
    FT_Error err;
3574
    INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
3575
    FT_Angle angle = 0;
3576 3577
    FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
    float widthRatio = 1.0;
3578 3579 3580
    FT_Matrix transMat = identityMat;
    BOOL needsTransform = FALSE;

3581

3582
    TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3583 3584
	  buflen, buf, lpmat);

3585
    if(format & GGO_GLYPH_INDEX) {
3586
        glyph_index = glyph;
3587
	format &= ~GGO_GLYPH_INDEX;
3588 3589 3590 3591
    } else {
        get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
        ft_face = font->ft_face;
    }
3592

3593 3594
    if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
	font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3595
	font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3596
			       font->gmsize * sizeof(GM*));
3597
    } else {
3598 3599
        if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
            *lpgm = FONT_GM(font,glyph_index)->gm;
3600 3601 3602
	    return 1; /* FIXME */
	}
    }
3603

3604 3605 3606
    if (!font->gm[glyph_index / GM_BLOCK_SIZE])
        font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);

3607
    if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || font->aveWidth || lpmat)
3608 3609 3610
        load_flags |= FT_LOAD_NO_BITMAP;

    err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3611

3612
    if(err) {
3613
        WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3614 3615
	return GDI_ERROR;
    }
3616 3617 3618
	
    /* Scaling factor */
    if (font->aveWidth && font->potm) {
3619
        widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3620
    }
3621

3622 3623
    left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
    right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3624

3625 3626 3627
    adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
    lsb = left >> 6;
    bbx = (right - left) >> 6;
3628

3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640
    /* Scaling transform */
    if(font->aveWidth) {
        FT_Matrix scaleMat;
        scaleMat.xx = FT_FixedFromFloat(widthRatio);
        scaleMat.xy = 0;
        scaleMat.yx = 0;
        scaleMat.yy = (1 << 16);

        pFT_Matrix_Multiply(&scaleMat, &transMat);
        needsTransform = TRUE;
    }

3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652
    /* Slant transform */
    if (font->fake_italic) {
        FT_Matrix slantMat;
        
        slantMat.xx = (1 << 16);
        slantMat.xy = ((1 << 16) >> 2);
        slantMat.yx = 0;
        slantMat.yy = (1 << 16);
        pFT_Matrix_Multiply(&slantMat, &transMat);
        needsTransform = TRUE;
    }

3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679
    /* Rotation transform */
    if(font->orientation) {
        FT_Matrix rotationMat;
        FT_Vector vecAngle;
        angle = FT_FixedFromFloat((float)font->orientation / 10.0);
        pFT_Vector_Unit(&vecAngle, angle);
        rotationMat.xx = vecAngle.x;
        rotationMat.xy = -vecAngle.y;
        rotationMat.yx = -rotationMat.xy;
        rotationMat.yy = rotationMat.xx;
        
        pFT_Matrix_Multiply(&rotationMat, &transMat);
        needsTransform = TRUE;
    }

    /* Extra transformation specified by caller */
    if (lpmat) {
        FT_Matrix extraMat;
        extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
        extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
        extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
        extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
        pFT_Matrix_Multiply(&extraMat, &transMat);
        needsTransform = TRUE;
    }

    if(!needsTransform) {
3680
	top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3681 3682
	bottom = (ft_face->glyph->metrics.horiBearingY -
		  ft_face->glyph->metrics.height) & -64;
3683
	lpgm->gmCellIncX = adv;
3684 3685 3686 3687 3688 3689
	lpgm->gmCellIncY = 0;
    } else {
        INT xc, yc;
	FT_Vector vec;
	for(xc = 0; xc < 2; xc++) {
	    for(yc = 0; yc < 2; yc++) {
3690 3691
	        vec.x = (ft_face->glyph->metrics.horiBearingX +
		  xc * ft_face->glyph->metrics.width);
3692 3693 3694
		vec.y = ft_face->glyph->metrics.horiBearingY -
		  yc * ft_face->glyph->metrics.height;
		TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3695
		pFT_Vector_Transform(&vec, &transMat);
3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714
		if(xc == 0 && yc == 0) {
		    left = right = vec.x;
		    top = bottom = vec.y;
		} else {
		    if(vec.x < left) left = vec.x;
		    else if(vec.x > right) right = vec.x;
		    if(vec.y < bottom) bottom = vec.y;
		    else if(vec.y > top) top = vec.y;
		}
	    }
	}
	left = left & -64;
	right = (right + 63) & -64;
	bottom = bottom & -64;
	top = (top + 63) & -64;

	TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
	vec.x = ft_face->glyph->metrics.horiAdvance;
	vec.y = 0;
3715
	pFT_Vector_Transform(&vec, &transMat);
3716
	lpgm->gmCellIncX = (vec.x+63) >> 6;
3717
	lpgm->gmCellIncY = -((vec.y+63) >> 6);
3718 3719 3720 3721 3722 3723
    }
    lpgm->gmBlackBoxX = (right - left) >> 6;
    lpgm->gmBlackBoxY = (top - bottom) >> 6;
    lpgm->gmptGlyphOrigin.x = left >> 6;
    lpgm->gmptGlyphOrigin.y = top >> 6;

3724
    if(format == GGO_METRICS || format == GGO_BITMAP || format ==  WINE_GGO_GRAY16_BITMAP)
3725 3726 3727 3728 3729 3730 3731
    {
        FONT_GM(font,glyph_index)->gm = *lpgm;
        FONT_GM(font,glyph_index)->adv = adv;
        FONT_GM(font,glyph_index)->lsb = lsb;
        FONT_GM(font,glyph_index)->bbx = bbx;
        FONT_GM(font,glyph_index)->init = TRUE;
    }
3732 3733

    if(format == GGO_METRICS)
3734
        return 1; /* FIXME */
3735

3736
    if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
3737
        TRACE("loaded a bitmap\n");
3738 3739 3740
	return GDI_ERROR;
    }

3741 3742
    switch(format) {
    case GGO_BITMAP:
3743 3744
        width = lpgm->gmBlackBoxX;
	height = lpgm->gmBlackBoxY;
3745
	pitch = ((width + 31) >> 5) << 2;
3746 3747
        needed = pitch * height;

3748
	if(!buf || !buflen) break;
3749

3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770
	switch(ft_face->glyph->format) {
	case ft_glyph_format_bitmap:
	  {
	    BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
	    INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
	    INT h = ft_face->glyph->bitmap.rows;
	    while(h--) {
	        memcpy(dst, src, w);
		src += ft_face->glyph->bitmap.pitch;
		dst += pitch;
	    }
	    break;
	  }

	case ft_glyph_format_outline:
	    ft_bitmap.width = width;
	    ft_bitmap.rows = height;
	    ft_bitmap.pitch = pitch;
	    ft_bitmap.pixel_mode = ft_pixel_mode_mono;
	    ft_bitmap.buffer = buf;

3771 3772
		if(needsTransform) {
			pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3773
	    }
3774

3775
	    pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3776

3777 3778 3779 3780
	    /* Note: FreeType will only set 'black' bits for us. */
	    memset(buf, 0, needed);
	    pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
	    break;
3781

3782 3783 3784 3785
	default:
	    FIXME("loaded glyph format %x\n", ft_face->glyph->format);
	    return GDI_ERROR;
	}
3786 3787 3788 3789 3790 3791 3792
	break;

    case GGO_GRAY2_BITMAP:
    case GGO_GRAY4_BITMAP:
    case GGO_GRAY8_BITMAP:
    case WINE_GGO_GRAY16_BITMAP:
      {
3793
	unsigned int mult, row, col;
3794 3795 3796 3797 3798 3799 3800 3801 3802
	BYTE *start, *ptr;

        width = lpgm->gmBlackBoxX;
	height = lpgm->gmBlackBoxY;
	pitch = (width + 3) / 4 * 4;
	needed = pitch * height;

	if(!buf || !buflen) break;

3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839
	switch(ft_face->glyph->format) {
	case ft_glyph_format_bitmap:
	  {
            BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
            INT h = ft_face->glyph->bitmap.rows;
            INT x;
            while(h--) {
                for(x = 0; x < pitch; x++)
                    dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
                src += ft_face->glyph->bitmap.pitch;
                dst += pitch;
            }
            return needed;
	  }
        case ft_glyph_format_outline:
          {
            ft_bitmap.width = width;
            ft_bitmap.rows = height;
            ft_bitmap.pitch = pitch;
            ft_bitmap.pixel_mode = ft_pixel_mode_grays;
            ft_bitmap.buffer = buf;

            if(needsTransform)
                pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);

            pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );

            memset(ft_bitmap.buffer, 0, buflen);

            pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);

            if(format == GGO_GRAY2_BITMAP)
                mult = 4;
            else if(format == GGO_GRAY4_BITMAP)
                mult = 16;
            else if(format == GGO_GRAY8_BITMAP)
                mult = 64;
3840
            else /* format == WINE_GGO_GRAY16_BITMAP */
3841
                return needed;
3842

3843
            break;
3844 3845 3846 3847 3848
          }
        default:
            FIXME("loaded glyph format %x\n", ft_face->glyph->format);
            return GDI_ERROR;
        }
3849 3850 3851 3852 3853

	start = buf;
	for(row = 0; row < height; row++) {
	    ptr = start;
	    for(col = 0; col < width; col++, ptr++) {
3854
	        *ptr = (((int)*ptr) * mult + 128) / 256;
3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870
	    }
	    start += pitch;
	}
	break;
      }

    case GGO_NATIVE:
      {
	int contour, point = 0, first_pt;
	FT_Outline *outline = &ft_face->glyph->outline;
	TTPOLYGONHEADER *pph;
	TTPOLYCURVE *ppc;
	DWORD pph_start, cpfx, type;

	if(buflen == 0) buf = NULL;

3871 3872 3873
	if (needsTransform && buf) {
		pFT_Outline_Transform(outline, &transMat);
	}
3874

3875 3876
        for(contour = 0; contour < outline->n_contours; contour++) {
	    pph_start = needed;
3877
	    pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3878 3879 3880 3881 3882 3883 3884 3885
	    first_pt = point;
	    if(buf) {
	        pph->dwType = TT_POLYGON_TYPE;
		FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
	    }
	    needed += sizeof(*pph);
	    point++;
	    while(point <= outline->contours[contour]) {
3886
	        ppc = (TTPOLYCURVE *)((char *)buf + needed);
3887
		type = (outline->tags[point] & FT_Curve_Tag_On) ?
3888 3889 3890 3891 3892 3893 3894 3895
		  TT_PRIM_LINE : TT_PRIM_QSPLINE;
		cpfx = 0;
		do {
		    if(buf)
		        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
		    cpfx++;
		    point++;
		} while(point <= outline->contours[contour] &&
3896 3897 3898 3899 3900 3901
			(outline->tags[point] & FT_Curve_Tag_On) ==
			(outline->tags[point-1] & FT_Curve_Tag_On));
		/* At the end of a contour Windows adds the start point, but
		   only for Beziers */
		if(point > outline->contours[contour] &&
		   !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3902 3903 3904
		    if(buf)
		        FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
		    cpfx++;
3905 3906
		} else if(point <= outline->contours[contour] &&
			  outline->tags[point] & FT_Curve_Tag_On) {
3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923
		  /* add closing pt for bezier */
		    if(buf)
		        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
		    cpfx++;
		    point++;
		}
		if(buf) {
		    ppc->wType = type;
		    ppc->cpfx = cpfx;
		}
		needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
	    }
	    if(buf)
	        pph->cb = needed - pph_start;
	}
	break;
      }
3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950
    case GGO_BEZIER:
      {
	/* Convert the quadratic Beziers to cubic Beziers.
	   The parametric eqn for a cubic Bezier is, from PLRM:
	   r(t) = at^3 + bt^2 + ct + r0
	   with the control points:
	   r1 = r0 + c/3
	   r2 = r1 + (c + b)/3
	   r3 = r0 + c + b + a

	   A quadratic Beizer has the form:
	   p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2

	   So equating powers of t leads to:
	   r1 = 2/3 p1 + 1/3 p0
	   r2 = 2/3 p1 + 1/3 p2
	   and of course r0 = p0, r3 = p2
	*/

	int contour, point = 0, first_pt;
	FT_Outline *outline = &ft_face->glyph->outline;
	TTPOLYGONHEADER *pph;
	TTPOLYCURVE *ppc;
	DWORD pph_start, cpfx, type;
	FT_Vector cubic_control[4];
	if(buflen == 0) buf = NULL;

3951 3952 3953
	if (needsTransform && buf) {
		pFT_Outline_Transform(outline, &transMat);
	}
3954

3955 3956
        for(contour = 0; contour < outline->n_contours; contour++) {
	    pph_start = needed;
3957
	    pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3958 3959 3960 3961 3962 3963 3964 3965
	    first_pt = point;
	    if(buf) {
	        pph->dwType = TT_POLYGON_TYPE;
		FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
	    }
	    needed += sizeof(*pph);
	    point++;
	    while(point <= outline->contours[contour]) {
3966
	        ppc = (TTPOLYCURVE *)((char *)buf + needed);
3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040
		type = (outline->tags[point] & FT_Curve_Tag_On) ?
		  TT_PRIM_LINE : TT_PRIM_CSPLINE;
		cpfx = 0;
		do {
		    if(type == TT_PRIM_LINE) {
		        if(buf)
			    FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
			cpfx++;
			point++;
		    } else {
		      /* Unlike QSPLINEs, CSPLINEs always have their endpoint
			 so cpfx = 3n */

		      /* FIXME: Possible optimization in endpoint calculation
			 if there are two consecutive curves */
		        cubic_control[0] = outline->points[point-1];
		        if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
			    cubic_control[0].x += outline->points[point].x + 1;
			    cubic_control[0].y += outline->points[point].y + 1;
			    cubic_control[0].x >>= 1;
			    cubic_control[0].y >>= 1;
			}
			if(point+1 > outline->contours[contour])
 			    cubic_control[3] = outline->points[first_pt];
			else {
			    cubic_control[3] = outline->points[point+1];
			    if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
			        cubic_control[3].x += outline->points[point].x + 1;
				cubic_control[3].y += outline->points[point].y + 1;
				cubic_control[3].x >>= 1;
				cubic_control[3].y >>= 1;
			    }
			}
			/* r1 = 1/3 p0 + 2/3 p1
			   r2 = 1/3 p2 + 2/3 p1 */
		        cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
			cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
			cubic_control[2] = cubic_control[1];
			cubic_control[1].x += (cubic_control[0].x + 1) / 3;
			cubic_control[1].y += (cubic_control[0].y + 1) / 3;
			cubic_control[2].x += (cubic_control[3].x + 1) / 3;
			cubic_control[2].y += (cubic_control[3].y + 1) / 3;
		        if(buf) {
			    FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
			    FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
			    FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
			}
			cpfx += 3;
			point++;
		    }
		} while(point <= outline->contours[contour] &&
			(outline->tags[point] & FT_Curve_Tag_On) ==
			(outline->tags[point-1] & FT_Curve_Tag_On));
		/* At the end of a contour Windows adds the start point,
		   but only for Beziers and we've already done that.
		*/
		if(point <= outline->contours[contour] &&
		   outline->tags[point] & FT_Curve_Tag_On) {
		  /* This is the closing pt of a bezier, but we've already
		     added it, so just inc point and carry on */
		    point++;
		}
		if(buf) {
		    ppc->wType = type;
		    ppc->cpfx = cpfx;
		}
		needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
	    }
	    if(buf)
	        pph->cb = needed - pph_start;
	}
	break;
      }

4041
    default:
4042 4043 4044
        FIXME("Unsupported format %d\n", format);
	return GDI_ERROR;
    }
4045
    return needed;
4046 4047
}

4048
static BOOL get_bitmap_text_metrics(GdiFont *font)
4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074
{
    FT_Face ft_face = font->ft_face;
#ifdef HAVE_FREETYPE_FTWINFNT_H
    FT_WinFNT_HeaderRec winfnt_header;
#endif
    const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller); 
    font->potm = HeapAlloc(GetProcessHeap(), 0, size);
    font->potm->otmSize = size;

#define TM font->potm->otmTextMetrics
#ifdef HAVE_FREETYPE_FTWINFNT_H
    if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
    {
        TM.tmHeight = winfnt_header.pixel_height;
        TM.tmAscent = winfnt_header.ascent;
        TM.tmDescent = TM.tmHeight - TM.tmAscent;
        TM.tmInternalLeading = winfnt_header.internal_leading;
        TM.tmExternalLeading = winfnt_header.external_leading;
        TM.tmAveCharWidth = winfnt_header.avg_width;
        TM.tmMaxCharWidth = winfnt_header.max_width;
        TM.tmWeight = winfnt_header.weight;
        TM.tmOverhang = 0;
        TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
        TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
        TM.tmFirstChar = winfnt_header.first_char;
        TM.tmLastChar = winfnt_header.last_char;
4075 4076
        TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
        TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4077
        TM.tmItalic = winfnt_header.italic;
4078 4079
        TM.tmUnderlined = font->underline;
        TM.tmStruckOut = font->strikeout;
4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101
        TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
        TM.tmCharSet = winfnt_header.charset;
    }
    else
#endif
    {
        TM.tmAscent = ft_face->size->metrics.ascender >> 6;
        TM.tmDescent = -ft_face->size->metrics.descender >> 6;
        TM.tmHeight = TM.tmAscent + TM.tmDescent;
        TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
        TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
        TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
        TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
        TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
        TM.tmOverhang = 0;
        TM.tmDigitizedAspectX = 96; /* FIXME */
        TM.tmDigitizedAspectY = 96; /* FIXME */
        TM.tmFirstChar = 1;
        TM.tmLastChar = 255;
        TM.tmDefaultChar = 32;
        TM.tmBreakChar = 32;
        TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4102 4103
        TM.tmUnderlined = font->underline;
        TM.tmStruckOut = font->strikeout;
4104 4105 4106 4107 4108 4109 4110 4111 4112
        /* NB inverted meaning of TMPF_FIXED_PITCH */
        TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
        TM.tmCharSet = font->charset;
    }
#undef TM

    return TRUE;
}

4113 4114 4115 4116
/*************************************************************
 * WineEngGetTextMetrics
 *
 */
4117
BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4118
{
4119 4120
    if(!font->potm) {
        if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4121 4122
            if(!get_bitmap_text_metrics(font))
                return FALSE;
4123
    }
4124 4125
    if(!font->potm) return FALSE;
    memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4126 4127

    if (font->aveWidth) {
4128
        ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
4129
    }
4130 4131
    return TRUE;
}
4132 4133


4134 4135 4136 4137
/*************************************************************
 * WineEngGetOutlineTextMetrics
 *
 */
4138
UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4139 4140 4141 4142 4143 4144
				  OUTLINETEXTMETRICW *potm)
{
    FT_Face ft_face = font->ft_face;
    UINT needed, lenfam, lensty, ret;
    TT_OS2 *pOS2;
    TT_HoriHeader *pHori;
4145
    TT_Postscript *pPost;
4146 4147
    FT_Fixed x_scale, y_scale;
    WCHAR *family_nameW, *style_nameW;
4148
    static const WCHAR spaceW[] = {' ', '\0'};
4149
    char *cp;
4150
    INT ascent, descent;
4151

4152 4153
    TRACE("font=%p\n", font);

4154 4155 4156
    if(!FT_IS_SCALABLE(ft_face))
        return 0;

4157 4158 4159 4160 4161 4162
    if(font->potm) {
        if(cbSize >= font->potm->otmSize)
	    memcpy(potm, font->potm, font->potm->otmSize);
	return font->potm->otmSize;
    }

4163

4164
    needed = sizeof(*potm);
4165

4166 4167
    lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
    family_nameW = strdupW(font->name);
4168 4169 4170 4171 4172

    lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
      * sizeof(WCHAR);
    style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
    MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4173
			style_nameW, lensty/sizeof(WCHAR));
4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196

    /* These names should be read from the TT name table */

    /* length of otmpFamilyName */
    needed += lenfam;

    /* length of otmpFaceName */
    if(!strcasecmp(ft_face->style_name, "regular")) {
      needed += lenfam; /* just the family name */
    } else {
      needed += lenfam + lensty; /* family + " " + style */
    }

    /* length of otmpStyleName */
    needed += lensty;

    /* length of otmpFullName */
    needed += lenfam + lensty;


    x_scale = ft_face->size->metrics.x_scale;
    y_scale = ft_face->size->metrics.y_scale;

4197
    pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4198 4199 4200 4201 4202 4203
    if(!pOS2) {
        FIXME("Can't find OS/2 table - not TT font?\n");
	ret = 0;
	goto end;
    }

4204
    pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4205 4206 4207 4208 4209 4210
    if(!pHori) {
        FIXME("Can't find HHEA table - not TT font?\n");
	ret = 0;
	goto end;
    }

4211 4212
    pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */

4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224
    TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
	  pOS2->usWinAscent, pOS2->usWinDescent,
	  pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
	  ft_face->ascender, ft_face->descender, ft_face->height,
	  pHori->Ascender, pHori->Descender, pHori->Line_Gap,
	  ft_face->bbox.yMax, ft_face->bbox.yMin);

    font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
    font->potm->otmSize = needed;

#define TM font->potm->otmTextMetrics

4225 4226 4227 4228 4229 4230 4231 4232
    if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
        ascent = pHori->Ascender;
        descent = -pHori->Descender;
    } else {
        ascent = pOS2->usWinAscent;
        descent = pOS2->usWinDescent;
    }

4233 4234 4235 4236 4237
    if(font->yMax) {
	TM.tmAscent = font->yMax;
	TM.tmDescent = -font->yMin;
	TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
    } else {
4238 4239 4240
	TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
	TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
	TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4241 4242 4243 4244 4245 4246 4247 4248 4249
					    - ft_face->units_per_EM, y_scale) + 32) >> 6;
    }

    TM.tmHeight = TM.tmAscent + TM.tmDescent;

    /* MSDN says:
     el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
    */
    TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4250
       		 ((ascent + descent) -
4251 4252 4253
		  (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);

    TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4254 4255 4256
    if (TM.tmAveCharWidth == 0) {
        TM.tmAveCharWidth = 1; 
    }
4257 4258 4259 4260 4261
    TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
    TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
    TM.tmOverhang = 0;
    TM.tmDigitizedAspectX = 300;
    TM.tmDigitizedAspectY = 300;
4262 4263 4264 4265 4266 4267 4268
    /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
     * symbol range to 0 - f0ff
     */
    if (font->charset == SYMBOL_CHARSET)
        TM.tmFirstChar = 0;
    else
        TM.tmFirstChar = pOS2->usFirstCharIndex;
4269
    TM.tmLastChar = pOS2->usLastCharIndex;
4270
    TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4271 4272
    TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
    TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4273 4274
    TM.tmUnderlined = font->underline;
    TM.tmStruckOut = font->strikeout;
4275 4276

    /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4277 4278 4279
    if(!FT_IS_FIXED_WIDTH(ft_face) &&
       (pOS2->version == 0xFFFFU || 
        pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312
        TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
    else
        TM.tmPitchAndFamily = 0;

    switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
    case PAN_FAMILY_SCRIPT:
        TM.tmPitchAndFamily |= FF_SCRIPT;
	break;
    case PAN_FAMILY_DECORATIVE:
    case PAN_FAMILY_PICTORIAL:
        TM.tmPitchAndFamily |= FF_DECORATIVE;
	break;
    case PAN_FAMILY_TEXT_DISPLAY:
        if(TM.tmPitchAndFamily == 0) /* fixed */
	    TM.tmPitchAndFamily = FF_MODERN;
	else {
	    switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
	    case PAN_SERIF_NORMAL_SANS:
	    case PAN_SERIF_OBTUSE_SANS:
	    case PAN_SERIF_PERP_SANS:
	        TM.tmPitchAndFamily |= FF_SWISS;
		break;
	    default:
	        TM.tmPitchAndFamily |= FF_ROMAN;
	    }
	}
	break;
    default:
        TM.tmPitchAndFamily |= FF_DONTCARE;
    }

    if(FT_IS_SCALABLE(ft_face))
        TM.tmPitchAndFamily |= TMPF_VECTOR;
4313

4314
    if(FT_IS_SFNT(ft_face))
4315 4316 4317 4318 4319 4320
    {
        if (font->ntmFlags & NTM_PS_OPENTYPE)
            TM.tmPitchAndFamily |= TMPF_DEVICE;
        else
            TM.tmPitchAndFamily |= TMPF_TRUETYPE;
    }
4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337

    TM.tmCharSet = font->charset;
#undef TM

    font->potm->otmFiller = 0;
    memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
    font->potm->otmfsSelection = pOS2->fsSelection;
    font->potm->otmfsType = pOS2->fsType;
    font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
    font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
    font->potm->otmItalicAngle = 0; /* POST table */
    font->potm->otmEMSquare = ft_face->units_per_EM;
    font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
    font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
    font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
    font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
    font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4338 4339 4340 4341
    font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
    font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
    font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
    font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355
    font->potm->otmMacAscent = 0; /* where do these come from ? */
    font->potm->otmMacDescent = 0;
    font->potm->otmMacLineGap = 0;
    font->potm->otmusMinimumPPEM = 0; /* TT Header */
    font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
    font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
    font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
    font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
    font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
    font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
    font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
    font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
    font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
    font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4356 4357 4358 4359 4360 4361 4362
    if(!pPost) {
        font->potm->otmsUnderscoreSize = 0;
	font->potm->otmsUnderscorePosition = 0;
    } else {
        font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
	font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
    }
4363

4364
    /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4365 4366
    cp = (char*)font->potm + sizeof(*font->potm);
    font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4367 4368
    strcpyW((WCHAR*)cp, family_nameW);
    cp += lenfam;
4369
    font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4370 4371
    strcpyW((WCHAR*)cp, style_nameW);
    cp += lensty;
4372
    font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4373 4374 4375 4376 4377
    strcpyW((WCHAR*)cp, family_nameW);
    if(strcasecmp(ft_face->style_name, "regular")) {
        strcatW((WCHAR*)cp, spaceW);
	strcatW((WCHAR*)cp, style_nameW);
	cp += lenfam + lensty;
4378
    } else
4379
        cp += lenfam;
4380
    font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4381 4382 4383 4384 4385
    strcpyW((WCHAR*)cp, family_nameW);
    strcatW((WCHAR*)cp, spaceW);
    strcatW((WCHAR*)cp, style_nameW);
    ret = needed;

4386
    if(potm && needed <= cbSize)
4387 4388 4389
        memcpy(potm, font->potm, font->potm->otmSize);

end:
4390 4391 4392 4393 4394 4395
    HeapFree(GetProcessHeap(), 0, style_nameW);
    HeapFree(GetProcessHeap(), 0, family_nameW);

    return ret;
}

4396
static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4397 4398 4399
{
    HFONTLIST *hfontlist;
    child->font = alloc_font();
4400
    child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4401
    if(!child->font->ft_face)
4402 4403 4404
    {
        free_font(child->font);
        child->font = NULL;
4405
        return FALSE;
4406
    }
4407

4408
    child->font->ntmFlags = child->face->ntmFlags;
4409 4410 4411 4412 4413 4414 4415 4416 4417 4418
    child->font->orientation = font->orientation;
    hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
    hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
    list_add_head(&child->font->hfontlist, &hfontlist->entry);
    child->font->base_font = font;
    list_add_head(&child_font_list, &child->font->entry);
    TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
    return TRUE;
}

4419
static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449
{
    FT_UInt g;
    CHILD_FONT *child_font;

    if(font->base_font)
        font = font->base_font;

    *linked_font = font;

    if((*glyph = get_glyph_index(font, c)))
        return TRUE;

    LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
    {
        if(!child_font->font)
            if(!load_child_font(font, child_font))
                continue;

        if(!child_font->font->ft_face)
            continue;
        g = get_glyph_index(child_font->font, c);
        if(g)
        {
            *glyph = g;
            *linked_font = child_font->font;
            return TRUE;
        }
    }
    return FALSE;
}
4450 4451 4452 4453 4454

/*************************************************************
 * WineEngGetCharWidth
 *
 */
4455
BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4456 4457 4458 4459
			 LPINT buffer)
{
    UINT c;
    GLYPHMETRICS gm;
4460
    FT_UInt glyph_index;
4461
    GdiFont *linked_font;
4462

4463 4464 4465
    TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);

    for(c = firstChar; c <= lastChar; c++) {
4466 4467
        get_glyph_index_linked(font, c, &linked_font, &glyph_index);
        WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4468
                               &gm, 0, NULL, NULL);
4469
	buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4470 4471 4472 4473
    }
    return TRUE;
}

4474 4475 4476 4477
/*************************************************************
 * WineEngGetCharABCWidths
 *
 */
4478
BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4479 4480 4481 4482 4483
			     LPABC buffer)
{
    UINT c;
    GLYPHMETRICS gm;
    FT_UInt glyph_index;
4484
    GdiFont *linked_font;
4485 4486 4487

    TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);

4488 4489 4490
    if(!FT_IS_SCALABLE(font->ft_face))
        return FALSE;

4491
    for(c = firstChar; c <= lastChar; c++) {
4492 4493
        get_glyph_index_linked(font, c, &linked_font, &glyph_index);
        WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4494
                               &gm, 0, NULL, NULL);
4495 4496 4497 4498
	buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
	buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
	buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
            FONT_GM(linked_font,glyph_index)->bbx;
4499 4500 4501 4502
    }
    return TRUE;
}

4503 4504 4505 4506
/*************************************************************
 * WineEngGetCharABCWidthsI
 *
 */
4507
BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4508 4509 4510 4511 4512
			      LPABC buffer)
{
    UINT c;
    GLYPHMETRICS gm;
    FT_UInt glyph_index;
4513
    GdiFont *linked_font;
4514 4515 4516 4517 4518 4519 4520 4521 4522

    if(!FT_IS_SCALABLE(font->ft_face))
        return FALSE;

    get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
    if (!pgi)
        for(c = firstChar; c < firstChar+count; c++) {
            WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
                                   &gm, 0, NULL, NULL);
4523 4524 4525 4526
            buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
            buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
            buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
                - FONT_GM(linked_font,c)->bbx;
4527 4528 4529 4530 4531
        }
    else
        for(c = 0; c < count; c++) {
            WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
                                   &gm, 0, NULL, NULL);
4532 4533 4534 4535
            buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
            buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
            buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
                - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4536 4537 4538 4539 4540
        }

    return TRUE;
}

4541
/*************************************************************
4542
 * WineEngGetTextExtentExPoint
4543 4544
 *
 */
4545
BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4546
                                 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4547
{
4548
    INT idx;
4549
    INT nfit = 0, ext;
4550 4551
    GLYPHMETRICS gm;
    TEXTMETRICW tm;
4552
    FT_UInt glyph_index;
4553
    GdiFont *linked_font;
4554

4555 4556
    TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
	  max_ext, size);
4557 4558 4559 4560

    size->cx = 0;
    WineEngGetTextMetrics(font, &tm);
    size->cy = tm.tmHeight;
4561

4562
    for(idx = 0; idx < count; idx++) {
4563 4564
        get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
        WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4565
                               &gm, 0, NULL, NULL);
4566
	size->cx += FONT_GM(linked_font,glyph_index)->adv;
4567 4568 4569 4570 4571 4572
        ext = size->cx;
        if (! pnfit || ext <= max_ext) {
            ++nfit;
            if (dxs)
                dxs[idx] = ext;
        }
4573
    }
4574 4575 4576 4577

    if (pnfit)
        *pnfit = nfit;

4578
    TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4579 4580 4581
    return TRUE;
}

4582 4583 4584 4585
/*************************************************************
 * WineEngGetTextExtentPointI
 *
 */
4586
BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4587 4588
				LPSIZE size)
{
4589
    INT idx;
4590 4591 4592 4593 4594 4595 4596 4597
    GLYPHMETRICS gm;
    TEXTMETRICW tm;

    TRACE("%p, %p, %d, %p\n", font, indices, count, size);

    size->cx = 0;
    WineEngGetTextMetrics(font, &tm);
    size->cy = tm.tmHeight;
4598

4599
    for(idx = 0; idx < count; idx++) {
4600 4601 4602
        WineEngGetGlyphOutline(font, indices[idx],
			       GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
			       NULL);
4603
	size->cx += FONT_GM(font,indices[idx])->adv;
4604
    }
4605
    TRACE("return %d,%d\n", size->cx, size->cy);
4606 4607 4608
    return TRUE;
}

Huw D M Davies's avatar
Huw D M Davies committed
4609 4610 4611 4612
/*************************************************************
 * WineEngGetFontData
 *
 */
4613
DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
Huw D M Davies's avatar
Huw D M Davies committed
4614 4615 4616
			 DWORD cbData)
{
    FT_Face ft_face = font->ft_face;
4617
    FT_ULong len;
Huw D M Davies's avatar
Huw D M Davies committed
4618 4619
    FT_Error err;

4620 4621 4622
    TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
	font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
        LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4623

Huw D M Davies's avatar
Huw D M Davies committed
4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636
    if(!FT_IS_SFNT(ft_face))
        return GDI_ERROR;

    if(!buf || !cbData)
        len = 0;
    else
        len = cbData;

    if(table) { /* MS tags differ in endidness from FT ones */
        table = table >> 24 | table << 24 |
	  (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
    }

4637 4638 4639 4640 4641 4642
    /* make sure value of len is the value freetype says it needs */
    if(buf && len)
    {
        FT_ULong needed = 0;
        err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
        if( !err && needed < len) len = needed;
4643
    }
4644 4645
    err = load_sfnt_table(ft_face, table, offset, buf, &len);

Huw D M Davies's avatar
Huw D M Davies committed
4646
    if(err) {
4647 4648 4649 4650
        TRACE("Can't find table %c%c%c%c\n",
              /* bytes were reversed */
              HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
              HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
Huw D M Davies's avatar
Huw D M Davies committed
4651 4652 4653 4654 4655
	return GDI_ERROR;
    }
    return len;
}

4656 4657 4658 4659
/*************************************************************
 * WineEngGetTextFace
 *
 */
4660
INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4661 4662 4663 4664 4665 4666 4667 4668
{
    if(str) {
        lstrcpynW(str, font->name, count);
	return strlenW(font->name);
    } else
        return strlenW(font->name) + 1;
}

4669
UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4670 4671 4672 4673
{
    if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
    return font->charset;
}
4674

4675 4676
BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
{
4677
    GdiFont *font = dc->gdiFont, *linked_font;
4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692
    struct list *first_hfont;
    BOOL ret;

    ret = get_glyph_index_linked(font, c, &linked_font, glyph);
    TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
    if(font == linked_font)
        *new_hfont = dc->hFont;
    else
    {
        first_hfont = list_head(&linked_font->hfontlist);
        *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
    }

    return ret;
}
Huw Davies's avatar
Huw Davies committed
4693
    
4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754
/* Retrieve a list of supported Unicode ranges for a given font.
 * Can be called with NULL gs to calculate the buffer size. Returns
 * the number of ranges found.
 */
static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
{
    DWORD num_ranges = 0;

    if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
    {
        FT_UInt glyph_code;
        FT_ULong char_code, char_code_prev;

        glyph_code = 0;
        char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);

        TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
               face->num_glyphs, glyph_code, char_code);

        if (!glyph_code) return 0;

        if (gs)
        {
            gs->ranges[0].wcLow = (USHORT)char_code;
            gs->ranges[0].cGlyphs = 0;
            gs->cGlyphsSupported = 0;
        }

        num_ranges = 1;
        while (glyph_code)
        {
            if (char_code < char_code_prev)
            {
                ERR("expected increasing char code from FT_Get_Next_Char\n");
                return 0;
            }
            if (char_code - char_code_prev > 1)
            {
                num_ranges++;
                if (gs)
                {
                    gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
                    gs->ranges[num_ranges - 1].cGlyphs = 1;
                    gs->cGlyphsSupported++;
                }
            }
            else if (gs)
            {
                gs->ranges[num_ranges - 1].cGlyphs++;
                gs->cGlyphsSupported++;
            }
            char_code_prev = char_code;
            char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
        }
    }
    else
        FIXME("encoding %u not supported\n", face->charmap->encoding);

    return num_ranges;
}

4755
DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
4756 4757
{
    DWORD size = 0;
4758
    DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
4759

4760 4761
    size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
    if (glyphset)
4762
    {
4763 4764
        glyphset->cbThis = size;
        glyphset->cRanges = num_ranges;
4765 4766 4767
    }
    return size;
}
Huw Davies's avatar
Huw Davies committed
4768 4769 4770 4771

/*************************************************************
 *     FontIsLinked
 */
4772
BOOL WineEngFontIsLinked(GdiFont *font)
Huw Davies's avatar
Huw Davies committed
4773
{
4774
    return !list_empty(&font->child_fonts);
Huw Davies's avatar
Huw Davies committed
4775
}
4776

4777 4778
static BOOL is_hinting_enabled(void)
{
4779
    /* Use the >= 2.2.0 function if available */
4780
    if(pFT_Get_TrueType_Engine_Type)
4781
    {
4782 4783
        FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
        return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4784 4785
    }
#ifdef FT_DRIVER_HAS_HINTER
4786 4787 4788 4789 4790 4791 4792 4793 4794 4795
    else
    {
        FT_Module mod;

        /* otherwise if we've been compiled with < 2.2.0 headers 
           use the internal macro */
        mod = pFT_Get_Module(library, "truetype");
        if(mod && FT_DRIVER_HAS_HINTER(mod))
            return TRUE;
    }
4796
#endif
4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808

    return FALSE;
}

/*************************************************************************
 *             GetRasterizerCaps   (GDI32.@)
 */
BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
{
    static int hinting = -1;

    if(hinting == -1)
4809
    {
4810
        hinting = is_hinting_enabled();
4811 4812
        TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
    }
4813 4814 4815 4816 4817 4818 4819

    lprs->nSize = sizeof(RASTERIZER_STATUS);
    lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
    lprs->nLanguageID = 0;
    return TRUE;
}

4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864
/*************************************************************************
 * Kerning support for TrueType fonts
 */
#define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')

struct TT_kern_table
{
    USHORT version;
    USHORT nTables;
};

struct TT_kern_subtable
{
    USHORT version;
    USHORT length;
    union
    {
        USHORT word;
        struct
        {
            USHORT horizontal : 1;
            USHORT minimum : 1;
            USHORT cross_stream: 1;
            USHORT override : 1;
            USHORT reserved1 : 4;
            USHORT format : 8;
        } bits;
    } coverage;
};

struct TT_format0_kern_subtable
{
    USHORT nPairs;
    USHORT searchRange;
    USHORT entrySelector;
    USHORT rangeShift;
};

struct TT_kern_pair
{
    USHORT left;
    USHORT right;
    short  value;
};

4865
static DWORD parse_format0_kern_subtable(GdiFont *font,
4866 4867 4868 4869 4870 4871 4872
                                         const struct TT_format0_kern_subtable *tt_f0_ks,
                                         const USHORT *glyph_to_char,
                                         KERNINGPAIR *kern_pair, DWORD cPairs)
{
    USHORT i, nPairs;
    const struct TT_kern_pair *tt_kern_pair;

4873
    TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891

    nPairs = GET_BE_WORD(tt_f0_ks->nPairs);

    TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
           nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
           GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));

    if (!kern_pair || !cPairs)
        return nPairs;

    tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);

    nPairs = min(nPairs, cPairs);

    for (i = 0; i < nPairs; i++)
    {
        kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
        kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904
        /* this algorithm appears to better match what Windows does */
        kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
        if (kern_pair->iKernAmount < 0)
        {
            kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
            kern_pair->iKernAmount -= font->ppem;
        }
        else if (kern_pair->iKernAmount > 0)
        {
            kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
            kern_pair->iKernAmount += font->ppem;
        }
        kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4905 4906 4907 4908 4909 4910 4911 4912 4913 4914

        TRACE("left %u right %u value %d\n",
               kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);

        kern_pair++;
    }
    TRACE("copied %u entries\n", nPairs);
    return nPairs;
}

4915
DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053
{
    DWORD length;
    void *buf;
    const struct TT_kern_table *tt_kern_table;
    const struct TT_kern_subtable *tt_kern_subtable;
    USHORT i, nTables;
    USHORT *glyph_to_char;

    if (font->total_kern_pairs != (DWORD)-1)
    {
        if (cPairs && kern_pair)
        {
            cPairs = min(cPairs, font->total_kern_pairs);
            memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
            return cPairs;
        }
        return font->total_kern_pairs;
    }

    font->total_kern_pairs = 0;

    length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);

    if (length == GDI_ERROR)
    {
        TRACE("no kerning data in the font\n");
        return 0;
    }

    buf = HeapAlloc(GetProcessHeap(), 0, length);
    if (!buf)
    {
        WARN("Out of memory\n");
        return 0;
    }

    WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);

    /* build a glyph index to char code map */
    glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
    if (!glyph_to_char)
    {
        WARN("Out of memory allocating a glyph index to char code map\n");
        HeapFree(GetProcessHeap(), 0, buf);
        return 0;
    }

    if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
    {
        FT_UInt glyph_code;
        FT_ULong char_code;

        glyph_code = 0;
        char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);

        TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
               font->ft_face->num_glyphs, glyph_code, char_code);

        while (glyph_code)
        {
            /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? "  !" : "" );*/

            /* FIXME: This doesn't match what Windows does: it does some fancy
             * things with duplicate glyph index to char code mappings, while
             * we just avoid overriding existing entries.
             */
            if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
                glyph_to_char[glyph_code] = (USHORT)char_code;

            char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
        }
    }
    else
    {
        ULONG n;

        FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
        for (n = 0; n <= 65535; n++)
            glyph_to_char[n] = (USHORT)n;
    }

    tt_kern_table = buf;
    nTables = GET_BE_WORD(tt_kern_table->nTables);
    TRACE("version %u, nTables %u\n",
           GET_BE_WORD(tt_kern_table->version), nTables);

    tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);

    for (i = 0; i < nTables; i++)
    {
        struct TT_kern_subtable tt_kern_subtable_copy;

        tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
        tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
        tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);

        TRACE("version %u, length %u, coverage %u, subtable format %u\n",
               tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
               tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);

        /* According to the TrueType specification this is the only format
         * that will be properly interpreted by Windows and OS/2
         */
        if (tt_kern_subtable_copy.coverage.bits.format == 0)
        {
            DWORD new_chunk, old_total = font->total_kern_pairs;

            new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
                                                    glyph_to_char, NULL, 0);
            font->total_kern_pairs += new_chunk;

            if (!font->kern_pairs)
                font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
                                             font->total_kern_pairs * sizeof(*font->kern_pairs));
            else
                font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
                                               font->total_kern_pairs * sizeof(*font->kern_pairs));

            parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
                        glyph_to_char, font->kern_pairs + old_total, new_chunk);
        }
        else
            TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);

        tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
    }

    HeapFree(GetProcessHeap(), 0, glyph_to_char);
    HeapFree(GetProcessHeap(), 0, buf);

    if (cPairs && kern_pair)
    {
        cPairs = min(cPairs, font->total_kern_pairs);
        memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
        return cPairs;
    }
    return font->total_kern_pairs;
}
5054

5055 5056
#else /* HAVE_FREETYPE */

5057 5058
/*************************************************************************/

5059 5060 5061 5062
BOOL WineEngInit(void)
{
    return FALSE;
}
5063
GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5064 5065 5066
{
    return NULL;
}
5067
BOOL WineEngDestroyFontInstance(HFONT hfont)
5068
{
5069
    return FALSE;
5070 5071
}

5072
DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5073 5074 5075 5076
{
    return 1;
}

5077
DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5078 5079 5080 5081 5082
				LPWORD pgi, DWORD flags)
{
    return GDI_ERROR;
}

5083
DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5084 5085 5086 5087 5088 5089 5090
			     LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
			     const MAT2* lpmat)
{
    ERR("called but we don't have FreeType\n");
    return GDI_ERROR;
}

5091
BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5092 5093 5094 5095 5096
{
    ERR("called but we don't have FreeType\n");
    return FALSE;
}

5097
UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5098 5099 5100 5101 5102 5103
				  OUTLINETEXTMETRICW *potm)
{
    ERR("called but we don't have FreeType\n");
    return 0;
}

5104
BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5105 5106 5107 5108
			 LPINT buffer)
{
    ERR("called but we don't have FreeType\n");
    return FALSE;
5109 5110
}

5111
BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5112 5113 5114 5115
			     LPABC buffer)
{
    ERR("called but we don't have FreeType\n");
    return FALSE;
5116 5117
}

5118
BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5119 5120 5121 5122 5123 5124
			      LPABC buffer)
{
    ERR("called but we don't have FreeType\n");
    return FALSE;
}

5125
BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5126
                                 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5127 5128 5129 5130 5131
{
    ERR("called but we don't have FreeType\n");
    return FALSE;
}

5132
BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
5133 5134 5135 5136 5137 5138
				LPSIZE size)
{
    ERR("called but we don't have FreeType\n");
    return FALSE;
}

5139
DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
Huw D M Davies's avatar
Huw D M Davies committed
5140 5141 5142 5143 5144
			 DWORD cbData)
{
    ERR("called but we don't have FreeType\n");
    return GDI_ERROR;
}
5145

5146
INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162
{
    ERR("called but we don't have FreeType\n");
    return 0;
}

INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
{
    FIXME(":stub\n");
    return 1;
}

INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
{
    FIXME(":stub\n");
    return TRUE;
}
5163

5164 5165 5166 5167 5168 5169
HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
{
    FIXME(":stub\n");
    return NULL;
}

5170
UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5171 5172 5173 5174 5175
{
    FIXME(":stub\n");
    return DEFAULT_CHARSET;
}

5176 5177 5178 5179
BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
{
    return FALSE;
}
Huw Davies's avatar
Huw Davies committed
5180

5181
DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5182
{
5183
    FIXME("(%p, %p): stub\n", font, glyphset);
5184 5185 5186
    return 0;
}

5187
BOOL WineEngFontIsLinked(GdiFont *font)
Huw Davies's avatar
Huw Davies committed
5188 5189 5190
{
    return FALSE;
}
5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202

/*************************************************************************
 *             GetRasterizerCaps   (GDI32.@)
 */
BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
{
    lprs->nSize = sizeof(RASTERIZER_STATUS);
    lprs->wFlags = 0;
    lprs->nLanguageID = 0;
    return TRUE;
}

5203
DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5204 5205 5206 5207 5208
{
    ERR("called but we don't have FreeType\n");
    return 0;
}

5209
#endif /* HAVE_FREETYPE */