1 /* 2 * PROJECT: ReactOS win32 kernel mode subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/gdi/ntgdi/freetype.c 5 * PURPOSE: FreeType font engine interface 6 * PROGRAMMERS: Copyright 2001 Huw D M Davies for CodeWeavers. 7 * Copyright 2006 Dmitry Timoshkov for CodeWeavers. 8 * Copyright 2016-2018 Katayama Hirofumi MZ. 9 */ 10 11 /** Includes ******************************************************************/ 12 13 #include <win32k.h> 14 15 #include FT_GLYPH_H 16 #include FT_TYPE1_TABLES_H 17 #include FT_TRUETYPE_TABLES_H 18 #include FT_TRUETYPE_TAGS_H 19 #include FT_TRIGONOMETRY_H 20 #include FT_BITMAP_H 21 #include FT_OUTLINE_H 22 #include FT_WINFONTS_H 23 #include FT_SFNT_NAMES_H 24 #include FT_SYNTHESIS_H 25 #include FT_TRUETYPE_IDS_H 26 27 #ifndef FT_INTERNAL_INTERNAL_H 28 #define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h> 29 #include FT_INTERNAL_INTERNAL_H 30 #endif 31 #include FT_INTERNAL_TRUETYPE_TYPES_H 32 33 #include <gdi/eng/floatobj.h> 34 #include "font.h" 35 36 #define NDEBUG 37 #include <debug.h> 38 39 /* TPMF_FIXED_PITCH is confusing; brain-dead api */ 40 #ifndef _TMPF_VARIABLE_PITCH 41 #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH 42 #endif 43 44 extern const MATRIX gmxWorldToDeviceDefault; 45 extern const MATRIX gmxWorldToPageDefault; 46 47 /* HACK!! Fix XFORMOBJ then use 1:16 / 16:1 */ 48 #define gmxWorldToDeviceDefault gmxWorldToPageDefault 49 50 FT_Library g_FreeTypeLibrary; 51 52 /* special font names */ 53 static const UNICODE_STRING g_MarlettW = RTL_CONSTANT_STRING(L"Marlett"); 54 55 /* registry */ 56 static UNICODE_STRING g_FontRegPath = 57 RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"); 58 59 60 /* The FreeType library is not thread safe, so we have 61 to serialize access to it */ 62 static PFAST_MUTEX g_FreeTypeLock; 63 64 static LIST_ENTRY g_FontListHead; 65 static PFAST_MUTEX g_FontListLock; 66 static BOOL g_RenderingEnabled = TRUE; 67 68 #define IntLockGlobalFonts() \ 69 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FontListLock) 70 71 #define IntUnLockGlobalFonts() \ 72 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FontListLock) 73 74 #define ASSERT_GLOBALFONTS_LOCK_HELD() \ 75 ASSERT(g_FontListLock->Owner == KeGetCurrentThread()) 76 77 #define IntLockFreeType() \ 78 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FreeTypeLock) 79 80 #define IntUnLockFreeType() \ 81 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FreeTypeLock) 82 83 #define ASSERT_FREETYPE_LOCK_HELD() \ 84 ASSERT(g_FreeTypeLock->Owner == KeGetCurrentThread()) 85 86 #define ASSERT_FREETYPE_LOCK_NOT_HELD() \ 87 ASSERT(g_FreeTypeLock->Owner != KeGetCurrentThread()) 88 89 #define MAX_FONT_CACHE 256 90 91 static LIST_ENTRY g_FontCacheListHead; 92 static UINT g_FontCacheNumEntries; 93 94 static PWCHAR g_ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */ 95 { 96 L"Western", /* 00 */ 97 L"Central_European", 98 L"Cyrillic", 99 L"Greek", 100 L"Turkish", 101 L"Hebrew", 102 L"Arabic", 103 L"Baltic", 104 L"Vietnamese", /* 08 */ 105 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */ 106 L"Thai", 107 L"Japanese", 108 L"CHINESE_GB2312", 109 L"Hangul", 110 L"CHINESE_BIG5", 111 L"Hangul(Johab)", 112 NULL, NULL, /* 23 */ 113 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 114 L"Symbol" /* 31 */ 115 }; 116 117 /* 118 * For TranslateCharsetInfo 119 */ 120 #define CP_SYMBOL 42 121 #define MAXTCIINDEX 32 122 static const CHARSETINFO g_FontTci[MAXTCIINDEX] = 123 { 124 /* ANSI */ 125 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} }, 126 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} }, 127 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} }, 128 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} }, 129 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} }, 130 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} }, 131 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} }, 132 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} }, 133 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} }, 134 /* reserved by ANSI */ 135 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 136 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 137 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 138 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 141 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 142 /* ANSI and OEM */ 143 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} }, 144 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} }, 145 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} }, 146 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} }, 147 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} }, 148 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} }, 149 /* Reserved for alternate ANSI and OEM */ 150 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 151 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 152 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 153 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 156 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 158 /* Reserved for system */ 159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 160 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} } 161 }; 162 163 #ifndef CP_OEMCP 164 #define CP_OEMCP 1 165 #define CP_MACCP 2 166 #endif 167 168 /* Get charset from specified codepage. 169 g_FontTci is used also in TranslateCharsetInfo. */ 170 BYTE FASTCALL IntCharSetFromCodePage(UINT uCodePage) 171 { 172 UINT i; 173 174 if (uCodePage == CP_OEMCP) 175 return OEM_CHARSET; 176 177 if (uCodePage == CP_MACCP) 178 return MAC_CHARSET; 179 180 for (i = 0; i < MAXTCIINDEX; ++i) 181 { 182 if (g_FontTci[i].ciACP == 0) 183 continue; 184 185 if (g_FontTci[i].ciACP == uCodePage) 186 return g_FontTci[i].ciCharset; 187 } 188 189 return DEFAULT_CHARSET; 190 } 191 192 /* list head */ 193 static RTL_STATIC_LIST_HEAD(g_FontSubstListHead); 194 195 static void 196 SharedMem_AddRef(PSHARED_MEM Ptr) 197 { 198 ASSERT_FREETYPE_LOCK_HELD(); 199 200 ++Ptr->RefCount; 201 } 202 203 static void 204 SharedFaceCache_Init(PSHARED_FACE_CACHE Cache) 205 { 206 Cache->OutlineRequiredSize = 0; 207 RtlInitUnicodeString(&Cache->FontFamily, NULL); 208 RtlInitUnicodeString(&Cache->FullName, NULL); 209 } 210 211 static PSHARED_FACE 212 SharedFace_Create(FT_Face Face, PSHARED_MEM Memory) 213 { 214 PSHARED_FACE Ptr; 215 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT); 216 if (Ptr) 217 { 218 Ptr->Face = Face; 219 Ptr->RefCount = 1; 220 Ptr->Memory = Memory; 221 SharedFaceCache_Init(&Ptr->EnglishUS); 222 SharedFaceCache_Init(&Ptr->UserLanguage); 223 224 SharedMem_AddRef(Memory); 225 DPRINT("Creating SharedFace for %s\n", Face->family_name ? Face->family_name : "<NULL>"); 226 } 227 return Ptr; 228 } 229 230 static PSHARED_MEM 231 SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping) 232 { 233 PSHARED_MEM Ptr; 234 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT); 235 if (Ptr) 236 { 237 Ptr->Buffer = Buffer; 238 Ptr->BufferSize = BufferSize; 239 Ptr->RefCount = 1; 240 Ptr->IsMapping = IsMapping; 241 DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr); 242 } 243 return Ptr; 244 } 245 246 static void 247 SharedFace_AddRef(PSHARED_FACE Ptr) 248 { 249 ASSERT_FREETYPE_LOCK_HELD(); 250 251 ++Ptr->RefCount; 252 } 253 254 static void 255 RemoveCachedEntry(PFONT_CACHE_ENTRY Entry) 256 { 257 ASSERT_FREETYPE_LOCK_HELD(); 258 259 FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph); 260 RemoveEntryList(&Entry->ListEntry); 261 ExFreePoolWithTag(Entry, TAG_FONT); 262 g_FontCacheNumEntries--; 263 ASSERT(g_FontCacheNumEntries <= MAX_FONT_CACHE); 264 } 265 266 static void 267 RemoveCacheEntries(FT_Face Face) 268 { 269 PLIST_ENTRY CurrentEntry, NextEntry; 270 PFONT_CACHE_ENTRY FontEntry; 271 272 ASSERT_FREETYPE_LOCK_HELD(); 273 274 for (CurrentEntry = g_FontCacheListHead.Flink; 275 CurrentEntry != &g_FontCacheListHead; 276 CurrentEntry = NextEntry) 277 { 278 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry); 279 NextEntry = CurrentEntry->Flink; 280 281 if (FontEntry->Face == Face) 282 { 283 RemoveCachedEntry(FontEntry); 284 } 285 } 286 } 287 288 static void SharedMem_Release(PSHARED_MEM Ptr) 289 { 290 ASSERT_FREETYPE_LOCK_HELD(); 291 ASSERT(Ptr->RefCount > 0); 292 293 if (Ptr->RefCount <= 0) 294 return; 295 296 --Ptr->RefCount; 297 if (Ptr->RefCount == 0) 298 { 299 DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr); 300 if (Ptr->IsMapping) 301 MmUnmapViewInSystemSpace(Ptr->Buffer); 302 else 303 ExFreePoolWithTag(Ptr->Buffer, TAG_FONT); 304 ExFreePoolWithTag(Ptr, TAG_FONT); 305 } 306 } 307 308 static void 309 SharedFaceCache_Release(PSHARED_FACE_CACHE Cache) 310 { 311 RtlFreeUnicodeString(&Cache->FontFamily); 312 RtlFreeUnicodeString(&Cache->FullName); 313 } 314 315 static void 316 SharedFace_Release(PSHARED_FACE Ptr) 317 { 318 IntLockFreeType(); 319 ASSERT(Ptr->RefCount > 0); 320 321 if (Ptr->RefCount <= 0) 322 return; 323 324 --Ptr->RefCount; 325 if (Ptr->RefCount == 0) 326 { 327 DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name ? Ptr->Face->family_name : "<NULL>"); 328 RemoveCacheEntries(Ptr->Face); 329 FT_Done_Face(Ptr->Face); 330 SharedMem_Release(Ptr->Memory); 331 SharedFaceCache_Release(&Ptr->EnglishUS); 332 SharedFaceCache_Release(&Ptr->UserLanguage); 333 ExFreePoolWithTag(Ptr, TAG_FONT); 334 } 335 IntUnLockFreeType(); 336 } 337 338 #if DBG 339 VOID DumpFontGDI(PFONTGDI FontGDI) 340 { 341 const char *family_name; 342 const char *style_name; 343 FT_Face Face; 344 345 if (!FontGDI) 346 { 347 DPRINT("FontGDI NULL\n"); 348 return; 349 } 350 351 Face = (FontGDI->SharedFace ? FontGDI->SharedFace->Face : NULL); 352 if (Face) 353 { 354 family_name = Face->family_name; 355 if (!family_name) 356 family_name = "<NULL>"; 357 358 style_name = Face->style_name; 359 if (!style_name) 360 style_name = "<NULL>"; 361 } 362 else 363 { 364 family_name = "<invalid>"; 365 style_name = "<invalid>"; 366 } 367 368 DPRINT("family_name '%s', style_name '%s', FontGDI %p, FontObj %p, iUnique %lu, SharedFace %p, Face %p, CharSet %u, Filename '%S'\n", 369 family_name, 370 style_name, 371 FontGDI, 372 FontGDI->FontObj, 373 FontGDI->iUnique, 374 FontGDI->SharedFace, 375 Face, 376 FontGDI->CharSet, 377 FontGDI->Filename); 378 } 379 380 VOID DumpFontList(PLIST_ENTRY Head) 381 { 382 PLIST_ENTRY Entry; 383 PFONT_ENTRY CurrentEntry; 384 PFONTGDI FontGDI; 385 386 DPRINT("## DumpFontList(%p)\n", Head); 387 388 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) 389 { 390 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); 391 FontGDI = CurrentEntry->Font; 392 393 DumpFontGDI(FontGDI); 394 } 395 } 396 397 VOID DumpFontSubstEntry(PFONTSUBST_ENTRY pSubstEntry) 398 { 399 DPRINT("%wZ,%u -> %wZ,%u\n", 400 &pSubstEntry->FontNames[FONTSUBST_FROM], 401 pSubstEntry->CharSets[FONTSUBST_FROM], 402 &pSubstEntry->FontNames[FONTSUBST_TO], 403 pSubstEntry->CharSets[FONTSUBST_TO]); 404 } 405 406 VOID DumpFontSubstList(VOID) 407 { 408 PLIST_ENTRY pHead = &g_FontSubstListHead; 409 PLIST_ENTRY pListEntry; 410 PFONTSUBST_ENTRY pSubstEntry; 411 412 DPRINT("## DumpFontSubstList\n"); 413 414 for (pListEntry = pHead->Flink; 415 pListEntry != pHead; 416 pListEntry = pListEntry->Flink) 417 { 418 pSubstEntry = 419 (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry); 420 421 DumpFontSubstEntry(pSubstEntry); 422 } 423 } 424 425 VOID DumpPrivateFontList(BOOL bDoLock) 426 { 427 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); 428 429 if (!Win32Process) 430 return; 431 432 if (bDoLock) 433 IntLockProcessPrivateFonts(Win32Process); 434 435 DumpFontList(&Win32Process->PrivateFontListHead); 436 437 if (bDoLock) 438 IntUnLockProcessPrivateFonts(Win32Process); 439 } 440 441 VOID DumpGlobalFontList(BOOL bDoLock) 442 { 443 if (bDoLock) 444 IntLockGlobalFonts(); 445 446 DumpFontList(&g_FontListHead); 447 448 if (bDoLock) 449 IntUnLockGlobalFonts(); 450 } 451 452 VOID DumpFontInfo(BOOL bDoLock) 453 { 454 DumpGlobalFontList(bDoLock); 455 DumpPrivateFontList(bDoLock); 456 DumpFontSubstList(); 457 } 458 #endif 459 460 /* 461 * IntLoadFontSubstList --- loads the list of font substitutes 462 */ 463 BOOL FASTCALL 464 IntLoadFontSubstList(PLIST_ENTRY pHead) 465 { 466 NTSTATUS Status; 467 HANDLE KeyHandle; 468 OBJECT_ATTRIBUTES ObjectAttributes; 469 KEY_FULL_INFORMATION KeyFullInfo; 470 ULONG i, Length; 471 UNICODE_STRING FromW, ToW; 472 BYTE InfoBuffer[128]; 473 PKEY_VALUE_FULL_INFORMATION pInfo; 474 BYTE CharSets[FONTSUBST_FROM_AND_TO]; 475 LPWSTR pch; 476 PFONTSUBST_ENTRY pEntry; 477 BOOLEAN Success; 478 479 /* the FontSubstitutes registry key */ 480 static UNICODE_STRING FontSubstKey = 481 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\" 482 L"Microsoft\\Windows NT\\CurrentVersion\\" 483 L"FontSubstitutes"); 484 485 /* open registry key */ 486 InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey, 487 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 488 NULL, NULL); 489 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 490 if (!NT_SUCCESS(Status)) 491 { 492 DPRINT("ZwOpenKey failed: 0x%08X\n", Status); 493 return FALSE; /* failure */ 494 } 495 496 /* query count of values */ 497 Status = ZwQueryKey(KeyHandle, KeyFullInformation, 498 &KeyFullInfo, sizeof(KeyFullInfo), &Length); 499 if (!NT_SUCCESS(Status)) 500 { 501 DPRINT("ZwQueryKey failed: 0x%08X\n", Status); 502 ZwClose(KeyHandle); 503 return FALSE; /* failure */ 504 } 505 506 /* for each value */ 507 for (i = 0; i < KeyFullInfo.Values; ++i) 508 { 509 /* get value name */ 510 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation, 511 InfoBuffer, sizeof(InfoBuffer), &Length); 512 if (!NT_SUCCESS(Status)) 513 { 514 DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status); 515 break; /* failure */ 516 } 517 518 /* create FromW string */ 519 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer; 520 Length = pInfo->NameLength / sizeof(WCHAR); 521 pInfo->Name[Length] = UNICODE_NULL; /* truncate */ 522 Success = RtlCreateUnicodeString(&FromW, pInfo->Name); 523 if (!Success) 524 { 525 Status = STATUS_INSUFFICIENT_RESOURCES; 526 DPRINT("RtlCreateUnicodeString failed\n"); 527 break; /* failure */ 528 } 529 530 /* query value */ 531 Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation, 532 InfoBuffer, sizeof(InfoBuffer), &Length); 533 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer; 534 if (!NT_SUCCESS(Status) || !pInfo->DataLength) 535 { 536 DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status); 537 RtlFreeUnicodeString(&FromW); 538 break; /* failure */ 539 } 540 541 /* create ToW string */ 542 pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset); 543 Length = pInfo->DataLength / sizeof(WCHAR); 544 pch[Length] = UNICODE_NULL; /* truncate */ 545 Success = RtlCreateUnicodeString(&ToW, pch); 546 if (!Success) 547 { 548 Status = STATUS_INSUFFICIENT_RESOURCES; 549 DPRINT("RtlCreateUnicodeString failed\n"); 550 RtlFreeUnicodeString(&FromW); 551 break; /* failure */ 552 } 553 554 /* does charset exist? (from) */ 555 CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET; 556 pch = wcsrchr(FromW.Buffer, L','); 557 if (pch) 558 { 559 /* truncate */ 560 *pch = UNICODE_NULL; 561 FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR); 562 /* parse charset number */ 563 CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1); 564 } 565 566 /* does charset exist? (to) */ 567 CharSets[FONTSUBST_TO] = DEFAULT_CHARSET; 568 pch = wcsrchr(ToW.Buffer, L','); 569 if (pch) 570 { 571 /* truncate */ 572 *pch = UNICODE_NULL; 573 ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR); 574 /* parse charset number */ 575 CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1); 576 } 577 578 /* is it identical? */ 579 if (RtlEqualUnicodeString(&FromW, &ToW, TRUE) && 580 CharSets[FONTSUBST_FROM] == CharSets[FONTSUBST_TO]) 581 { 582 RtlFreeUnicodeString(&FromW); 583 RtlFreeUnicodeString(&ToW); 584 continue; 585 } 586 587 /* allocate an entry */ 588 pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTSUBST_ENTRY), TAG_FONT); 589 if (pEntry == NULL) 590 { 591 DPRINT("ExAllocatePoolWithTag failed\n"); 592 RtlFreeUnicodeString(&FromW); 593 RtlFreeUnicodeString(&ToW); 594 break; /* failure */ 595 } 596 597 /* store to *pEntry */ 598 pEntry->FontNames[FONTSUBST_FROM] = FromW; 599 pEntry->FontNames[FONTSUBST_TO] = ToW; 600 pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM]; 601 pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO]; 602 603 /* insert pEntry to *pHead */ 604 InsertTailList(pHead, &pEntry->ListEntry); 605 } 606 607 /* close now */ 608 ZwClose(KeyHandle); 609 610 return NT_SUCCESS(Status); 611 } 612 613 BOOL FASTCALL 614 InitFontSupport(VOID) 615 { 616 ULONG ulError; 617 618 InitializeListHead(&g_FontListHead); 619 InitializeListHead(&g_FontCacheListHead); 620 g_FontCacheNumEntries = 0; 621 /* Fast Mutexes must be allocated from non paged pool */ 622 g_FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC); 623 if (g_FontListLock == NULL) 624 { 625 return FALSE; 626 } 627 628 ExInitializeFastMutex(g_FontListLock); 629 g_FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC); 630 if (g_FreeTypeLock == NULL) 631 { 632 return FALSE; 633 } 634 ExInitializeFastMutex(g_FreeTypeLock); 635 636 ulError = FT_Init_FreeType(&g_FreeTypeLibrary); 637 if (ulError) 638 { 639 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError); 640 return FALSE; 641 } 642 643 IntLoadSystemFonts(); 644 IntLoadFontSubstList(&g_FontSubstListHead); 645 646 #if DBG 647 DumpFontInfo(TRUE); 648 #endif 649 650 return TRUE; 651 } 652 653 VOID 654 FtSetCoordinateTransform( 655 FT_Face face, 656 PMATRIX pmx) 657 { 658 FT_Matrix ftmatrix; 659 FLOATOBJ efTemp; 660 661 /* Create a freetype matrix, by converting to 16.16 fixpoint format */ 662 efTemp = pmx->efM11; 663 FLOATOBJ_MulLong(&efTemp, 0x00010000); 664 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp); 665 666 efTemp = pmx->efM12; 667 FLOATOBJ_MulLong(&efTemp, 0x00010000); 668 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp); 669 670 efTemp = pmx->efM21; 671 FLOATOBJ_MulLong(&efTemp, 0x00010000); 672 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp); 673 674 efTemp = pmx->efM22; 675 FLOATOBJ_MulLong(&efTemp, 0x00010000); 676 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp); 677 678 /* Set the transformation matrix */ 679 FT_Set_Transform(face, &ftmatrix, 0); 680 } 681 682 static BOOL 683 SubstituteFontByList(PLIST_ENTRY pHead, 684 PUNICODE_STRING pOutputName, 685 PUNICODE_STRING pInputName, 686 BYTE RequestedCharSet, 687 BYTE CharSetMap[FONTSUBST_FROM_AND_TO]) 688 { 689 PLIST_ENTRY pListEntry; 690 PFONTSUBST_ENTRY pSubstEntry; 691 BYTE CharSets[FONTSUBST_FROM_AND_TO]; 692 693 CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET; 694 CharSetMap[FONTSUBST_TO] = RequestedCharSet; 695 696 /* for each list entry */ 697 for (pListEntry = pHead->Flink; 698 pListEntry != pHead; 699 pListEntry = pListEntry->Flink) 700 { 701 pSubstEntry = 702 (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry); 703 704 CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM]; 705 706 if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET && 707 CharSets[FONTSUBST_FROM] != RequestedCharSet) 708 { 709 continue; /* not matched */ 710 } 711 712 /* does charset number exist? (to) */ 713 if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET) 714 { 715 CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO]; 716 } 717 else 718 { 719 CharSets[FONTSUBST_TO] = RequestedCharSet; 720 } 721 722 /* does font name match? */ 723 if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM], 724 pInputName, TRUE)) 725 { 726 continue; /* not matched */ 727 } 728 729 /* update *pOutputName */ 730 *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO]; 731 732 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET) 733 { 734 /* update CharSetMap */ 735 CharSetMap[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM]; 736 CharSetMap[FONTSUBST_TO] = CharSets[FONTSUBST_TO]; 737 } 738 return TRUE; /* success */ 739 } 740 741 return FALSE; 742 } 743 744 static VOID 745 IntUnicodeStringToBuffer(LPWSTR pszBuffer, USHORT cbBuffer, const UNICODE_STRING *pString) 746 { 747 USHORT cbLength = pString->Length; 748 749 if (cbBuffer < sizeof(UNICODE_NULL)) 750 return; 751 752 if (cbLength > cbBuffer - sizeof(UNICODE_NULL)) 753 cbLength = cbBuffer - sizeof(UNICODE_NULL); 754 755 RtlCopyMemory(pszBuffer, pString->Buffer, cbLength); 756 pszBuffer[cbLength / sizeof(WCHAR)] = UNICODE_NULL; 757 } 758 759 static BOOL 760 SubstituteFontRecurse(LOGFONTW* pLogFont) 761 { 762 UINT RecurseCount = 5; 763 UNICODE_STRING OutputNameW = { 0 }; 764 BYTE CharSetMap[FONTSUBST_FROM_AND_TO]; 765 BOOL Found; 766 UNICODE_STRING InputNameW; 767 768 if (pLogFont->lfFaceName[0] == UNICODE_NULL) 769 return FALSE; 770 771 RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName); 772 773 while (RecurseCount-- > 0) 774 { 775 Found = SubstituteFontByList(&g_FontSubstListHead, 776 &OutputNameW, &InputNameW, 777 pLogFont->lfCharSet, CharSetMap); 778 if (!Found) 779 break; 780 781 IntUnicodeStringToBuffer(pLogFont->lfFaceName, sizeof(pLogFont->lfFaceName), &OutputNameW); 782 783 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET || 784 CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet) 785 { 786 pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO]; 787 } 788 } 789 790 return TRUE; /* success */ 791 } 792 793 /* 794 * IntLoadSystemFonts 795 * 796 * Search the system font directory and adds each font found. 797 */ 798 VOID FASTCALL 799 IntLoadSystemFonts(VOID) 800 { 801 OBJECT_ATTRIBUTES ObjectAttributes; 802 UNICODE_STRING Directory, FileName, TempString; 803 IO_STATUS_BLOCK Iosb; 804 HANDLE hDirectory; 805 BYTE *DirInfoBuffer; 806 PFILE_DIRECTORY_INFORMATION DirInfo; 807 BOOLEAN bRestartScan = TRUE; 808 NTSTATUS Status; 809 INT i; 810 static UNICODE_STRING SearchPatterns[] = 811 { 812 RTL_CONSTANT_STRING(L"*.ttf"), 813 RTL_CONSTANT_STRING(L"*.ttc"), 814 RTL_CONSTANT_STRING(L"*.otf"), 815 RTL_CONSTANT_STRING(L"*.otc"), 816 RTL_CONSTANT_STRING(L"*.fon"), 817 RTL_CONSTANT_STRING(L"*.fnt") 818 }; 819 820 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\"); 821 822 InitializeObjectAttributes( 823 &ObjectAttributes, 824 &Directory, 825 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 826 NULL, 827 NULL); 828 829 Status = ZwOpenFile( 830 &hDirectory, 831 SYNCHRONIZE | FILE_LIST_DIRECTORY, 832 &ObjectAttributes, 833 &Iosb, 834 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 835 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE); 836 837 if (NT_SUCCESS(Status)) 838 { 839 for (i = 0; i < _countof(SearchPatterns); ++i) 840 { 841 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT); 842 if (DirInfoBuffer == NULL) 843 { 844 ZwClose(hDirectory); 845 return; 846 } 847 848 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT); 849 if (FileName.Buffer == NULL) 850 { 851 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); 852 ZwClose(hDirectory); 853 return; 854 } 855 FileName.Length = 0; 856 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR); 857 858 while (1) 859 { 860 Status = ZwQueryDirectoryFile( 861 hDirectory, 862 NULL, 863 NULL, 864 NULL, 865 &Iosb, 866 DirInfoBuffer, 867 0x4000, 868 FileDirectoryInformation, 869 FALSE, 870 &SearchPatterns[i], 871 bRestartScan); 872 873 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES) 874 { 875 break; 876 } 877 878 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer; 879 while (1) 880 { 881 TempString.Buffer = DirInfo->FileName; 882 TempString.Length = 883 TempString.MaximumLength = DirInfo->FileNameLength; 884 RtlCopyUnicodeString(&FileName, &Directory); 885 RtlAppendUnicodeStringToString(&FileName, &TempString); 886 IntGdiAddFontResource(&FileName, 0); 887 if (DirInfo->NextEntryOffset == 0) 888 break; 889 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset); 890 } 891 892 bRestartScan = FALSE; 893 } 894 895 ExFreePoolWithTag(FileName.Buffer, TAG_FONT); 896 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); 897 } 898 ZwClose(hDirectory); 899 } 900 } 901 902 static BYTE 903 ItalicFromStyle(const char *style_name) 904 { 905 if (style_name == NULL || style_name[0] == 0) 906 return FALSE; 907 if (strstr(style_name, "Italic") != NULL) 908 return TRUE; 909 if (strstr(style_name, "Oblique") != NULL) 910 return TRUE; 911 return FALSE; 912 } 913 914 static LONG 915 WeightFromStyle(const char *style_name) 916 { 917 if (style_name == NULL || style_name[0] == 0) 918 return FW_NORMAL; 919 if (strstr(style_name, "Regular") != NULL) 920 return FW_REGULAR; 921 if (strstr(style_name, "Normal") != NULL) 922 return FW_NORMAL; 923 if (strstr(style_name, "SemiBold") != NULL) 924 return FW_SEMIBOLD; 925 if (strstr(style_name, "UltraBold") != NULL) 926 return FW_ULTRABOLD; 927 if (strstr(style_name, "DemiBold") != NULL) 928 return FW_DEMIBOLD; 929 if (strstr(style_name, "ExtraBold") != NULL) 930 return FW_EXTRABOLD; 931 if (strstr(style_name, "Bold") != NULL) 932 return FW_BOLD; 933 if (strstr(style_name, "UltraLight") != NULL) 934 return FW_ULTRALIGHT; 935 if (strstr(style_name, "ExtraLight") != NULL) 936 return FW_EXTRALIGHT; 937 if (strstr(style_name, "Light") != NULL) 938 return FW_LIGHT; 939 if (strstr(style_name, "Hairline") != NULL) 940 return 50; 941 if (strstr(style_name, "Book") != NULL) 942 return 350; 943 if (strstr(style_name, "ExtraBlack") != NULL) 944 return 950; 945 if (strstr(style_name, "UltraBlack") != NULL) 946 return 1000; 947 if (strstr(style_name, "Black") != NULL) 948 return FW_BLACK; 949 if (strstr(style_name, "Medium") != NULL) 950 return FW_MEDIUM; 951 if (strstr(style_name, "Thin") != NULL) 952 return FW_THIN; 953 if (strstr(style_name, "Heavy") != NULL) 954 return FW_HEAVY; 955 return FW_NORMAL; 956 } 957 958 static FT_Error 959 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight); 960 961 static INT FASTCALL 962 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont, 963 PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex) 964 { 965 FT_Error Error; 966 PFONT_ENTRY Entry; 967 FONT_ENTRY_MEM* PrivateEntry = NULL; 968 FONTGDI * FontGDI; 969 NTSTATUS Status; 970 FT_Face Face; 971 ANSI_STRING AnsiString; 972 FT_WinFNT_HeaderRec WinFNT; 973 INT FaceCount = 0, CharSetCount = 0; 974 PUNICODE_STRING pFileName = pLoadFont->pFileName; 975 DWORD Characteristics = pLoadFont->Characteristics; 976 PUNICODE_STRING pValueName = &pLoadFont->RegValueName; 977 TT_OS2 * pOS2; 978 INT BitIndex; 979 FT_UShort os2_version; 980 FT_ULong os2_ulCodePageRange1; 981 FT_UShort os2_usWeightClass; 982 983 if (SharedFace == NULL && CharSetIndex == -1) 984 { 985 /* load a face from memory */ 986 IntLockFreeType(); 987 Error = FT_New_Memory_Face( 988 g_FreeTypeLibrary, 989 pLoadFont->Memory->Buffer, 990 pLoadFont->Memory->BufferSize, 991 ((FontIndex != -1) ? FontIndex : 0), 992 &Face); 993 994 if (!Error) 995 SharedFace = SharedFace_Create(Face, pLoadFont->Memory); 996 997 IntUnLockFreeType(); 998 999 if (!Error && FT_IS_SFNT(Face)) 1000 pLoadFont->IsTrueType = TRUE; 1001 1002 if (Error || SharedFace == NULL) 1003 { 1004 if (SharedFace) 1005 SharedFace_Release(SharedFace); 1006 1007 if (Error == FT_Err_Unknown_File_Format) 1008 DPRINT1("Unknown font file format\n"); 1009 else 1010 DPRINT1("Error reading font (error code: %d)\n", Error); 1011 return 0; /* failure */ 1012 } 1013 } 1014 else 1015 { 1016 Face = SharedFace->Face; 1017 IntLockFreeType(); 1018 SharedFace_AddRef(SharedFace); 1019 IntUnLockFreeType(); 1020 } 1021 1022 /* allocate a FONT_ENTRY */ 1023 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT); 1024 if (!Entry) 1025 { 1026 SharedFace_Release(SharedFace); 1027 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1028 return 0; /* failure */ 1029 } 1030 1031 /* allocate a FONTGDI */ 1032 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT); 1033 if (!FontGDI) 1034 { 1035 SharedFace_Release(SharedFace); 1036 ExFreePoolWithTag(Entry, TAG_FONT); 1037 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1038 return 0; /* failure */ 1039 } 1040 1041 /* set file name */ 1042 if (pFileName) 1043 { 1044 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, 1045 pFileName->Length + sizeof(UNICODE_NULL), 1046 GDITAG_PFF); 1047 if (FontGDI->Filename == NULL) 1048 { 1049 EngFreeMem(FontGDI); 1050 SharedFace_Release(SharedFace); 1051 ExFreePoolWithTag(Entry, TAG_FONT); 1052 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1053 return 0; /* failure */ 1054 } 1055 1056 RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length); 1057 FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL; 1058 } 1059 else 1060 { 1061 FontGDI->Filename = NULL; 1062 1063 PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT); 1064 if (!PrivateEntry) 1065 { 1066 if (FontGDI->Filename) 1067 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); 1068 EngFreeMem(FontGDI); 1069 SharedFace_Release(SharedFace); 1070 ExFreePoolWithTag(Entry, TAG_FONT); 1071 return 0; 1072 } 1073 1074 PrivateEntry->Entry = Entry; 1075 if (pLoadFont->PrivateEntry) 1076 { 1077 InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry); 1078 } 1079 else 1080 { 1081 InitializeListHead(&PrivateEntry->ListEntry); 1082 pLoadFont->PrivateEntry = PrivateEntry; 1083 } 1084 } 1085 1086 /* set face */ 1087 FontGDI->SharedFace = SharedFace; 1088 FontGDI->CharSet = ANSI_CHARSET; 1089 FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name); 1090 FontGDI->RequestItalic = FALSE; 1091 FontGDI->OriginalWeight = WeightFromStyle(Face->style_name); 1092 FontGDI->RequestWeight = FW_NORMAL; 1093 1094 RtlInitAnsiString(&AnsiString, Face->family_name); 1095 Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiString, TRUE); 1096 if (NT_SUCCESS(Status)) 1097 { 1098 if (Face->style_name && Face->style_name[0] && 1099 strcmp(Face->style_name, "Regular") != 0) 1100 { 1101 RtlInitAnsiString(&AnsiString, Face->style_name); 1102 Status = RtlAnsiStringToUnicodeString(&Entry->StyleName, &AnsiString, TRUE); 1103 if (!NT_SUCCESS(Status)) 1104 { 1105 RtlFreeUnicodeString(&Entry->FaceName); 1106 } 1107 } 1108 else 1109 { 1110 RtlInitUnicodeString(&Entry->StyleName, NULL); 1111 } 1112 } 1113 if (!NT_SUCCESS(Status)) 1114 { 1115 if (PrivateEntry) 1116 { 1117 if (pLoadFont->PrivateEntry == PrivateEntry) 1118 { 1119 pLoadFont->PrivateEntry = NULL; 1120 } 1121 else 1122 { 1123 RemoveEntryList(&PrivateEntry->ListEntry); 1124 } 1125 ExFreePoolWithTag(PrivateEntry, TAG_FONT); 1126 } 1127 if (FontGDI->Filename) 1128 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); 1129 EngFreeMem(FontGDI); 1130 SharedFace_Release(SharedFace); 1131 ExFreePoolWithTag(Entry, TAG_FONT); 1132 return 0; 1133 } 1134 1135 os2_version = 0; 1136 IntLockFreeType(); 1137 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2); 1138 if (pOS2) 1139 { 1140 os2_version = pOS2->version; 1141 os2_ulCodePageRange1 = pOS2->ulCodePageRange1; 1142 os2_usWeightClass = pOS2->usWeightClass; 1143 } 1144 IntUnLockFreeType(); 1145 1146 if (pOS2 && os2_version >= 1) 1147 { 1148 /* get charset and weight from OS/2 header */ 1149 1150 /* Make sure we do not use this pointer anymore */ 1151 pOS2 = NULL; 1152 1153 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex) 1154 { 1155 if (os2_ulCodePageRange1 & (1 << BitIndex)) 1156 { 1157 if (g_FontTci[BitIndex].ciCharset == DEFAULT_CHARSET) 1158 continue; 1159 1160 if ((CharSetIndex == -1 && CharSetCount == 0) || 1161 CharSetIndex == CharSetCount) 1162 { 1163 FontGDI->CharSet = g_FontTci[BitIndex].ciCharset; 1164 } 1165 1166 ++CharSetCount; 1167 } 1168 } 1169 1170 /* set actual weight */ 1171 FontGDI->OriginalWeight = os2_usWeightClass; 1172 } 1173 else 1174 { 1175 /* get charset from WinFNT header */ 1176 IntLockFreeType(); 1177 Error = FT_Get_WinFNT_Header(Face, &WinFNT); 1178 if (!Error) 1179 { 1180 FontGDI->CharSet = WinFNT.charset; 1181 } 1182 IntUnLockFreeType(); 1183 } 1184 1185 /* FIXME: CharSet is invalid on Marlett */ 1186 if (RtlEqualUnicodeString(&Entry->FaceName, &g_MarlettW, TRUE)) 1187 { 1188 FontGDI->CharSet = SYMBOL_CHARSET; 1189 } 1190 1191 ++FaceCount; 1192 DPRINT("Font loaded: %s (%s)\n", 1193 Face->family_name ? Face->family_name : "<NULL>", 1194 Face->style_name ? Face->style_name : "<NULL>"); 1195 DPRINT("Num glyphs: %d\n", Face->num_glyphs); 1196 DPRINT("CharSet: %d\n", FontGDI->CharSet); 1197 1198 IntLockFreeType(); 1199 IntRequestFontSize(NULL, FontGDI, 0, 0); 1200 IntUnLockFreeType(); 1201 1202 /* Add this font resource to the font table */ 1203 Entry->Font = FontGDI; 1204 Entry->NotEnum = (Characteristics & FR_NOT_ENUM); 1205 1206 if (Characteristics & FR_PRIVATE) 1207 { 1208 /* private font */ 1209 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); 1210 IntLockProcessPrivateFonts(Win32Process); 1211 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry); 1212 IntUnLockProcessPrivateFonts(Win32Process); 1213 } 1214 else 1215 { 1216 /* global font */ 1217 IntLockGlobalFonts(); 1218 InsertTailList(&g_FontListHead, &Entry->ListEntry); 1219 IntUnLockGlobalFonts(); 1220 } 1221 1222 if (FontIndex == -1) 1223 { 1224 if (FT_IS_SFNT(Face)) 1225 { 1226 TT_Face TrueType = (TT_Face)Face; 1227 if (TrueType->ttc_header.count > 1) 1228 { 1229 FT_Long i; 1230 for (i = 1; i < TrueType->ttc_header.count; ++i) 1231 { 1232 FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1); 1233 } 1234 } 1235 } 1236 FontIndex = 0; 1237 } 1238 1239 if (CharSetIndex == -1) 1240 { 1241 INT i; 1242 USHORT NameLength = Entry->FaceName.Length; 1243 1244 if (Entry->StyleName.Length) 1245 NameLength += Entry->StyleName.Length + sizeof(WCHAR); 1246 1247 if (pLoadFont->RegValueName.Length == 0) 1248 { 1249 pValueName->Length = 0; 1250 pValueName->MaximumLength = NameLength + sizeof(WCHAR); 1251 pValueName->Buffer = ExAllocatePoolWithTag(PagedPool, 1252 pValueName->MaximumLength, 1253 TAG_USTR); 1254 pValueName->Buffer[0] = UNICODE_NULL; 1255 RtlAppendUnicodeStringToString(pValueName, &Entry->FaceName); 1256 } 1257 else 1258 { 1259 UNICODE_STRING NewString; 1260 USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + NameLength; 1261 NewString.Length = 0; 1262 NewString.MaximumLength = Length + sizeof(WCHAR); 1263 NewString.Buffer = ExAllocatePoolWithTag(PagedPool, 1264 NewString.MaximumLength, 1265 TAG_USTR); 1266 NewString.Buffer[0] = UNICODE_NULL; 1267 1268 RtlAppendUnicodeStringToString(&NewString, pValueName); 1269 RtlAppendUnicodeToString(&NewString, L" & "); 1270 RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName); 1271 1272 RtlFreeUnicodeString(pValueName); 1273 *pValueName = NewString; 1274 } 1275 if (Entry->StyleName.Length) 1276 { 1277 RtlAppendUnicodeToString(pValueName, L" "); 1278 RtlAppendUnicodeStringToString(pValueName, &Entry->StyleName); 1279 } 1280 1281 for (i = 1; i < CharSetCount; ++i) 1282 { 1283 /* Do not count charsets towards 'faces' loaded */ 1284 IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i); 1285 } 1286 } 1287 1288 return FaceCount; /* number of loaded faces */ 1289 } 1290 1291 /* 1292 * IntGdiAddFontResource 1293 * 1294 * Adds the font resource from the specified file to the system. 1295 */ 1296 1297 INT FASTCALL 1298 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics) 1299 { 1300 NTSTATUS Status; 1301 HANDLE FileHandle; 1302 PVOID Buffer = NULL; 1303 IO_STATUS_BLOCK Iosb; 1304 PVOID SectionObject; 1305 SIZE_T ViewSize = 0; 1306 LARGE_INTEGER SectionSize; 1307 OBJECT_ATTRIBUTES ObjectAttributes; 1308 GDI_LOAD_FONT LoadFont; 1309 INT FontCount; 1310 HANDLE KeyHandle; 1311 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)"); 1312 1313 /* Open the font file */ 1314 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL); 1315 Status = ZwOpenFile( 1316 &FileHandle, 1317 FILE_GENERIC_READ | SYNCHRONIZE, 1318 &ObjectAttributes, 1319 &Iosb, 1320 FILE_SHARE_READ, 1321 FILE_SYNCHRONOUS_IO_NONALERT); 1322 if (!NT_SUCCESS(Status)) 1323 { 1324 DPRINT("Could not load font file: %wZ\n", FileName); 1325 return 0; 1326 } 1327 1328 SectionSize.QuadPart = 0LL; 1329 Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS, 1330 NULL, &SectionSize, PAGE_READONLY, 1331 SEC_COMMIT, FileHandle, NULL); 1332 if (!NT_SUCCESS(Status)) 1333 { 1334 DPRINT("Could not map file: %wZ\n", FileName); 1335 ZwClose(FileHandle); 1336 return 0; 1337 } 1338 ZwClose(FileHandle); 1339 1340 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize); 1341 if (!NT_SUCCESS(Status)) 1342 { 1343 DPRINT("Could not map file: %wZ\n", FileName); 1344 ObDereferenceObject(SectionObject); 1345 return 0; 1346 } 1347 1348 LoadFont.pFileName = FileName; 1349 LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE); 1350 LoadFont.Characteristics = Characteristics; 1351 RtlInitUnicodeString(&LoadFont.RegValueName, NULL); 1352 LoadFont.IsTrueType = FALSE; 1353 LoadFont.PrivateEntry = NULL; 1354 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1); 1355 1356 ObDereferenceObject(SectionObject); 1357 1358 /* Release our copy */ 1359 IntLockFreeType(); 1360 SharedMem_Release(LoadFont.Memory); 1361 IntUnLockFreeType(); 1362 1363 if (FontCount > 0) 1364 { 1365 if (LoadFont.IsTrueType) 1366 { 1367 /* append " (TrueType)" */ 1368 UNICODE_STRING NewString; 1369 USHORT Length; 1370 1371 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length; 1372 NewString.Length = 0; 1373 NewString.MaximumLength = Length + sizeof(WCHAR); 1374 NewString.Buffer = ExAllocatePoolWithTag(PagedPool, 1375 NewString.MaximumLength, 1376 TAG_USTR); 1377 NewString.Buffer[0] = UNICODE_NULL; 1378 1379 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName); 1380 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix); 1381 RtlFreeUnicodeString(&LoadFont.RegValueName); 1382 LoadFont.RegValueName = NewString; 1383 } 1384 1385 /* registry */ 1386 InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath, 1387 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 1388 NULL, NULL); 1389 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes); 1390 if (NT_SUCCESS(Status)) 1391 { 1392 SIZE_T DataSize; 1393 LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\'); 1394 if (pFileName) 1395 { 1396 pFileName++; 1397 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR); 1398 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ, 1399 pFileName, DataSize); 1400 } 1401 ZwClose(KeyHandle); 1402 } 1403 } 1404 RtlFreeUnicodeString(&LoadFont.RegValueName); 1405 1406 return FontCount; 1407 } 1408 1409 HANDLE FASTCALL 1410 IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded) 1411 { 1412 GDI_LOAD_FONT LoadFont; 1413 FONT_ENTRY_COLL_MEM* EntryCollection; 1414 INT FaceCount; 1415 HANDLE Ret = 0; 1416 1417 PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT); 1418 1419 if (!BufferCopy) 1420 { 1421 *pNumAdded = 0; 1422 return NULL; 1423 } 1424 memcpy(BufferCopy, Buffer, dwSize); 1425 1426 LoadFont.pFileName = NULL; 1427 LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE); 1428 LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM; 1429 RtlInitUnicodeString(&LoadFont.RegValueName, NULL); 1430 LoadFont.IsTrueType = FALSE; 1431 LoadFont.PrivateEntry = NULL; 1432 FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1); 1433 1434 RtlFreeUnicodeString(&LoadFont.RegValueName); 1435 1436 /* Release our copy */ 1437 IntLockFreeType(); 1438 SharedMem_Release(LoadFont.Memory); 1439 IntUnLockFreeType(); 1440 1441 if (FaceCount > 0) 1442 { 1443 EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT); 1444 if (EntryCollection) 1445 { 1446 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); 1447 EntryCollection->Entry = LoadFont.PrivateEntry; 1448 IntLockProcessPrivateFonts(Win32Process); 1449 EntryCollection->Handle = ULongToHandle(++Win32Process->PrivateMemFontHandleCount); 1450 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry); 1451 IntUnLockProcessPrivateFonts(Win32Process); 1452 Ret = EntryCollection->Handle; 1453 } 1454 } 1455 *pNumAdded = FaceCount; 1456 1457 return Ret; 1458 } 1459 1460 // FIXME: Add RemoveFontResource 1461 1462 static VOID FASTCALL 1463 CleanupFontEntry(PFONT_ENTRY FontEntry) 1464 { 1465 PFONTGDI FontGDI = FontEntry->Font; 1466 PSHARED_FACE SharedFace = FontGDI->SharedFace; 1467 1468 if (FontGDI->Filename) 1469 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); 1470 1471 EngFreeMem(FontGDI); 1472 SharedFace_Release(SharedFace); 1473 ExFreePoolWithTag(FontEntry, TAG_FONT); 1474 } 1475 1476 VOID FASTCALL 1477 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head) 1478 { 1479 PLIST_ENTRY Entry; 1480 PFONT_ENTRY_MEM FontEntry; 1481 1482 while (!IsListEmpty(&Head->ListEntry)) 1483 { 1484 Entry = RemoveHeadList(&Head->ListEntry); 1485 FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry); 1486 1487 CleanupFontEntry(FontEntry->Entry); 1488 ExFreePoolWithTag(FontEntry, TAG_FONT); 1489 } 1490 1491 CleanupFontEntry(Head->Entry); 1492 ExFreePoolWithTag(Head, TAG_FONT); 1493 } 1494 1495 static VOID FASTCALL 1496 UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection) 1497 { 1498 PFONT_ENTRY_MEM FontMemEntry = Collection->Entry; 1499 PLIST_ENTRY ListEntry; 1500 RemoveEntryList(&Collection->ListEntry); 1501 1502 do { 1503 /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */ 1504 RemoveEntryList(&FontMemEntry->Entry->ListEntry); 1505 1506 ListEntry = FontMemEntry->ListEntry.Flink; 1507 FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry); 1508 1509 } while (FontMemEntry != Collection->Entry); 1510 } 1511 1512 BOOL FASTCALL 1513 IntGdiRemoveFontMemResource(HANDLE hMMFont) 1514 { 1515 PLIST_ENTRY Entry; 1516 PFONT_ENTRY_COLL_MEM CurrentEntry; 1517 PFONT_ENTRY_COLL_MEM EntryCollection = NULL; 1518 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); 1519 1520 IntLockProcessPrivateFonts(Win32Process); 1521 for (Entry = Win32Process->PrivateMemFontListHead.Flink; 1522 Entry != &Win32Process->PrivateMemFontListHead; 1523 Entry = Entry->Flink) 1524 { 1525 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry); 1526 1527 if (CurrentEntry->Handle == hMMFont) 1528 { 1529 EntryCollection = CurrentEntry; 1530 UnlinkFontMemCollection(CurrentEntry); 1531 break; 1532 } 1533 } 1534 IntUnLockProcessPrivateFonts(Win32Process); 1535 1536 if (EntryCollection) 1537 { 1538 IntGdiCleanupMemEntry(EntryCollection->Entry); 1539 ExFreePoolWithTag(EntryCollection, TAG_FONT); 1540 return TRUE; 1541 } 1542 return FALSE; 1543 } 1544 1545 1546 VOID FASTCALL 1547 IntGdiCleanupPrivateFontsForProcess(VOID) 1548 { 1549 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); 1550 PLIST_ENTRY Entry; 1551 PFONT_ENTRY_COLL_MEM EntryCollection; 1552 1553 DPRINT("IntGdiCleanupPrivateFontsForProcess()\n"); 1554 do { 1555 Entry = NULL; 1556 EntryCollection = NULL; 1557 1558 IntLockProcessPrivateFonts(Win32Process); 1559 if (!IsListEmpty(&Win32Process->PrivateMemFontListHead)) 1560 { 1561 Entry = Win32Process->PrivateMemFontListHead.Flink; 1562 EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry); 1563 UnlinkFontMemCollection(EntryCollection); 1564 } 1565 IntUnLockProcessPrivateFonts(Win32Process); 1566 1567 if (EntryCollection) 1568 { 1569 IntGdiCleanupMemEntry(EntryCollection->Entry); 1570 ExFreePoolWithTag(EntryCollection, TAG_FONT); 1571 } 1572 else 1573 { 1574 /* No Mem fonts anymore, see if we have any other private fonts left */ 1575 Entry = NULL; 1576 IntLockProcessPrivateFonts(Win32Process); 1577 if (!IsListEmpty(&Win32Process->PrivateFontListHead)) 1578 { 1579 Entry = RemoveHeadList(&Win32Process->PrivateFontListHead); 1580 } 1581 IntUnLockProcessPrivateFonts(Win32Process); 1582 1583 if (Entry) 1584 { 1585 CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry)); 1586 } 1587 } 1588 1589 } while (Entry); 1590 } 1591 1592 BOOL FASTCALL 1593 IntIsFontRenderingEnabled(VOID) 1594 { 1595 BOOL Ret = g_RenderingEnabled; 1596 HDC hDC; 1597 1598 hDC = IntGetScreenDC(); 1599 if (hDC) 1600 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && g_RenderingEnabled; 1601 1602 return Ret; 1603 } 1604 1605 VOID FASTCALL 1606 IntEnableFontRendering(BOOL Enable) 1607 { 1608 g_RenderingEnabled = Enable; 1609 } 1610 1611 FT_Render_Mode FASTCALL 1612 IntGetFontRenderMode(LOGFONTW *logfont) 1613 { 1614 switch (logfont->lfQuality) 1615 { 1616 case ANTIALIASED_QUALITY: 1617 break; 1618 case NONANTIALIASED_QUALITY: 1619 return FT_RENDER_MODE_MONO; 1620 case DRAFT_QUALITY: 1621 return FT_RENDER_MODE_LIGHT; 1622 /* case CLEARTYPE_QUALITY: 1623 return FT_RENDER_MODE_LCD; */ 1624 } 1625 return FT_RENDER_MODE_NORMAL; 1626 } 1627 1628 1629 NTSTATUS FASTCALL 1630 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont) 1631 { 1632 PLFONT plfont; 1633 LOGFONTW *plf; 1634 1635 ASSERT(lf); 1636 plfont = LFONT_AllocFontWithHandle(); 1637 if (!plfont) 1638 { 1639 return STATUS_NO_MEMORY; 1640 } 1641 1642 ExInitializePushLock(&plfont->lock); 1643 *NewFont = plfont->BaseObject.hHmgr; 1644 plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont; 1645 RtlCopyMemory(plf, lf, sizeof(LOGFONTW)); 1646 if (lf->lfEscapement != lf->lfOrientation) 1647 { 1648 /* This should really depend on whether GM_ADVANCED is set */ 1649 plf->lfOrientation = plf->lfEscapement; 1650 } 1651 LFONT_UnlockFont(plfont); 1652 1653 return STATUS_SUCCESS; 1654 } 1655 1656 /************************************************************************* 1657 * TranslateCharsetInfo 1658 * 1659 * Fills a CHARSETINFO structure for a character set, code page, or 1660 * font. This allows making the correspondance between different labelings 1661 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges) 1662 * of the same encoding. 1663 * 1664 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used, 1665 * only one codepage should be set in *Src. 1666 * 1667 * RETURNS 1668 * TRUE on success, FALSE on failure. 1669 * 1670 */ 1671 static BOOLEAN APIENTRY 1672 IntTranslateCharsetInfo(PDWORD Src, /* [in] 1673 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE 1674 if flags == TCI_SRCCHARSET: a character set value 1675 if flags == TCI_SRCCODEPAGE: a code page value */ 1676 LPCHARSETINFO Cs, /* [out] structure to receive charset information */ 1677 DWORD Flags /* [in] determines interpretation of lpSrc */) 1678 { 1679 int Index = 0; 1680 1681 switch (Flags) 1682 { 1683 case TCI_SRCFONTSIG: 1684 while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001)) 1685 { 1686 Index++; 1687 } 1688 break; 1689 case TCI_SRCCODEPAGE: 1690 while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciACP) 1691 { 1692 Index++; 1693 } 1694 break; 1695 case TCI_SRCCHARSET: 1696 while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciCharset) 1697 { 1698 Index++; 1699 } 1700 break; 1701 case TCI_SRCLOCALE: 1702 UNIMPLEMENTED; 1703 return FALSE; 1704 default: 1705 return FALSE; 1706 } 1707 1708 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == g_FontTci[Index].ciCharset) 1709 { 1710 return FALSE; 1711 } 1712 1713 RtlCopyMemory(Cs, &g_FontTci[Index], sizeof(CHARSETINFO)); 1714 1715 return TRUE; 1716 } 1717 1718 1719 static BOOL face_has_symbol_charmap(FT_Face ft_face) 1720 { 1721 int i; 1722 1723 for(i = 0; i < ft_face->num_charmaps; i++) 1724 { 1725 if (ft_face->charmaps[i]->platform_id == TT_PLATFORM_MICROSOFT && 1726 ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL) 1727 { 1728 return TRUE; 1729 } 1730 } 1731 return FALSE; 1732 } 1733 1734 static void FASTCALL 1735 FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI, 1736 TT_OS2 *pOS2, TT_HoriHeader *pHori, 1737 FT_WinFNT_HeaderRec *pFNT, BOOL RealFont) 1738 { 1739 FT_Fixed XScale, YScale; 1740 int Ascent, Descent; 1741 FT_Face Face = FontGDI->SharedFace->Face; 1742 1743 ASSERT_FREETYPE_LOCK_HELD(); 1744 1745 XScale = Face->size->metrics.x_scale; 1746 YScale = Face->size->metrics.y_scale; 1747 1748 if (pFNT) 1749 { 1750 TM->tmHeight = pFNT->pixel_height; 1751 TM->tmAscent = pFNT->ascent; 1752 TM->tmDescent = TM->tmHeight - TM->tmAscent; 1753 TM->tmInternalLeading = pFNT->internal_leading; 1754 TM->tmExternalLeading = pFNT->external_leading; 1755 TM->tmAveCharWidth = pFNT->avg_width; 1756 TM->tmMaxCharWidth = pFNT->max_width; 1757 TM->tmOverhang = 0; 1758 TM->tmDigitizedAspectX = pFNT->horizontal_resolution; 1759 TM->tmDigitizedAspectY = pFNT->vertical_resolution; 1760 TM->tmFirstChar = pFNT->first_char; 1761 TM->tmLastChar = pFNT->last_char; 1762 TM->tmDefaultChar = pFNT->default_char + pFNT->first_char; 1763 TM->tmBreakChar = pFNT->break_char + pFNT->first_char; 1764 TM->tmPitchAndFamily = pFNT->pitch_and_family; 1765 if (RealFont) 1766 { 1767 TM->tmWeight = FontGDI->OriginalWeight; 1768 TM->tmItalic = FontGDI->OriginalItalic; 1769 TM->tmUnderlined = pFNT->underline; 1770 TM->tmStruckOut = pFNT->strike_out; 1771 TM->tmCharSet = pFNT->charset; 1772 } 1773 else 1774 { 1775 TM->tmWeight = FontGDI->RequestWeight; 1776 TM->tmItalic = FontGDI->RequestItalic; 1777 TM->tmUnderlined = FontGDI->RequestUnderline; 1778 TM->tmStruckOut = FontGDI->RequestStrikeOut; 1779 TM->tmCharSet = FontGDI->CharSet; 1780 } 1781 return; 1782 } 1783 1784 if (pOS2->usWinAscent + pOS2->usWinDescent == 0) 1785 { 1786 Ascent = pHori->Ascender; 1787 Descent = -pHori->Descender; 1788 } 1789 else 1790 { 1791 Ascent = pOS2->usWinAscent; 1792 Descent = pOS2->usWinDescent; 1793 } 1794 1795 if (FontGDI->Magic != FONTGDI_MAGIC) 1796 { 1797 IntRequestFontSize(NULL, FontGDI, 0, 0); 1798 } 1799 TM->tmAscent = FontGDI->tmAscent; 1800 TM->tmDescent = FontGDI->tmDescent; 1801 TM->tmHeight = TM->tmAscent + TM->tmDescent; 1802 TM->tmInternalLeading = FontGDI->tmInternalLeading; 1803 1804 /* MSDN says: 1805 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender))) 1806 */ 1807 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap 1808 - ((Ascent + Descent) 1809 - (pHori->Ascender - pHori->Descender)), 1810 YScale) + 32) >> 6); 1811 1812 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6; 1813 if (TM->tmAveCharWidth == 0) 1814 { 1815 TM->tmAveCharWidth = 1; 1816 } 1817 1818 /* Correct forumla to get the maxcharwidth from unicode and ansi font */ 1819 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6; 1820 1821 if (RealFont) 1822 { 1823 TM->tmWeight = FontGDI->OriginalWeight; 1824 } 1825 else 1826 { 1827 if (FontGDI->OriginalWeight != FW_DONTCARE && 1828 FontGDI->OriginalWeight != FW_NORMAL) 1829 { 1830 TM->tmWeight = FontGDI->OriginalWeight; 1831 } 1832 else 1833 { 1834 TM->tmWeight = FontGDI->RequestWeight; 1835 } 1836 } 1837 1838 TM->tmOverhang = 0; 1839 TM->tmDigitizedAspectX = 96; 1840 TM->tmDigitizedAspectY = 96; 1841 if (face_has_symbol_charmap(Face) || 1842 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100)) 1843 { 1844 USHORT cpOEM, cpAnsi; 1845 1846 EngGetCurrentCodePage(&cpOEM, &cpAnsi); 1847 TM->tmFirstChar = 0; 1848 switch(cpAnsi) 1849 { 1850 case 1257: /* Baltic */ 1851 TM->tmLastChar = 0xf8fd; 1852 break; 1853 default: 1854 TM->tmLastChar = 0xf0ff; 1855 } 1856 TM->tmBreakChar = 0x20; 1857 TM->tmDefaultChar = 0x1f; 1858 } 1859 else 1860 { 1861 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */ 1862 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */ 1863 1864 if(pOS2->usFirstCharIndex <= 1) 1865 TM->tmBreakChar = pOS2->usFirstCharIndex + 2; 1866 else if (pOS2->usFirstCharIndex > 0xff) 1867 TM->tmBreakChar = 0x20; 1868 else 1869 TM->tmBreakChar = pOS2->usFirstCharIndex; 1870 TM->tmDefaultChar = TM->tmBreakChar - 1; 1871 } 1872 1873 if (RealFont) 1874 { 1875 TM->tmItalic = FontGDI->OriginalItalic; 1876 TM->tmUnderlined = FALSE; 1877 TM->tmStruckOut = FALSE; 1878 } 1879 else 1880 { 1881 if (FontGDI->OriginalItalic || FontGDI->RequestItalic) 1882 { 1883 TM->tmItalic = 0xFF; 1884 } 1885 else 1886 { 1887 TM->tmItalic = 0; 1888 } 1889 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0); 1890 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0); 1891 } 1892 1893 if (!FT_IS_FIXED_WIDTH(Face)) 1894 { 1895 switch (pOS2->panose[PAN_PROPORTION_INDEX]) 1896 { 1897 case PAN_PROP_MONOSPACED: 1898 TM->tmPitchAndFamily = 0; 1899 break; 1900 default: 1901 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH; 1902 break; 1903 } 1904 } 1905 else 1906 { 1907 TM->tmPitchAndFamily = 0; 1908 } 1909 1910 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX]) 1911 { 1912 case PAN_FAMILY_SCRIPT: 1913 TM->tmPitchAndFamily |= FF_SCRIPT; 1914 break; 1915 case PAN_FAMILY_DECORATIVE: 1916 TM->tmPitchAndFamily |= FF_DECORATIVE; 1917 break; 1918 1919 case PAN_ANY: 1920 case PAN_NO_FIT: 1921 case PAN_FAMILY_TEXT_DISPLAY: 1922 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */ 1923 /* Which is clearly not what the panose spec says. */ 1924 if (TM->tmPitchAndFamily == 0) /* Fixed */ 1925 { 1926 TM->tmPitchAndFamily = FF_MODERN; 1927 } 1928 else 1929 { 1930 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX]) 1931 { 1932 case PAN_ANY: 1933 case PAN_NO_FIT: 1934 default: 1935 TM->tmPitchAndFamily |= FF_DONTCARE; 1936 break; 1937 1938 case PAN_SERIF_COVE: 1939 case PAN_SERIF_OBTUSE_COVE: 1940 case PAN_SERIF_SQUARE_COVE: 1941 case PAN_SERIF_OBTUSE_SQUARE_COVE: 1942 case PAN_SERIF_SQUARE: 1943 case PAN_SERIF_THIN: 1944 case PAN_SERIF_BONE: 1945 case PAN_SERIF_EXAGGERATED: 1946 case PAN_SERIF_TRIANGLE: 1947 TM->tmPitchAndFamily |= FF_ROMAN; 1948 break; 1949 1950 case PAN_SERIF_NORMAL_SANS: 1951 case PAN_SERIF_OBTUSE_SANS: 1952 case PAN_SERIF_PERP_SANS: 1953 case PAN_SERIF_FLARED: 1954 case PAN_SERIF_ROUNDED: 1955 TM->tmPitchAndFamily |= FF_SWISS; 1956 break; 1957 } 1958 } 1959 break; 1960 default: 1961 TM->tmPitchAndFamily |= FF_DONTCARE; 1962 } 1963 1964 if (FT_IS_SCALABLE(Face)) 1965 { 1966 TM->tmPitchAndFamily |= TMPF_VECTOR; 1967 } 1968 if (FT_IS_SFNT(Face)) 1969 { 1970 TM->tmPitchAndFamily |= TMPF_TRUETYPE; 1971 } 1972 1973 TM->tmCharSet = FontGDI->CharSet; 1974 } 1975 1976 static void FASTCALL 1977 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, 1978 TT_OS2 *pOS2, TT_HoriHeader *pHori, 1979 FT_WinFNT_HeaderRec *pFNT) 1980 { 1981 FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE); 1982 } 1983 1984 static NTSTATUS 1985 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace, 1986 FT_UShort NameID, FT_UShort LangID); 1987 1988 typedef struct FONT_NAMES 1989 { 1990 UNICODE_STRING FamilyNameW; /* family name (TT_NAME_ID_FONT_FAMILY) */ 1991 UNICODE_STRING FaceNameW; /* face name (TT_NAME_ID_FULL_NAME) */ 1992 UNICODE_STRING StyleNameW; /* style name (TT_NAME_ID_FONT_SUBFAMILY) */ 1993 UNICODE_STRING FullNameW; /* unique name (TT_NAME_ID_UNIQUE_ID) */ 1994 ULONG OtmSize; /* size of OUTLINETEXTMETRICW with extra data */ 1995 } FONT_NAMES, *LPFONT_NAMES; 1996 1997 static __inline void FASTCALL 1998 IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace) 1999 { 2000 ULONG OtmSize; 2001 2002 RtlInitUnicodeString(&Names->FamilyNameW, NULL); 2003 RtlInitUnicodeString(&Names->FaceNameW, NULL); 2004 RtlInitUnicodeString(&Names->StyleNameW, NULL); 2005 RtlInitUnicodeString(&Names->FullNameW, NULL); 2006 2007 /* family name */ 2008 IntGetFontLocalizedName(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID); 2009 /* face name */ 2010 IntGetFontLocalizedName(&Names->FaceNameW, SharedFace, TT_NAME_ID_FULL_NAME, gusLanguageID); 2011 /* style name */ 2012 IntGetFontLocalizedName(&Names->StyleNameW, SharedFace, TT_NAME_ID_FONT_SUBFAMILY, gusLanguageID); 2013 /* unique name (full name) */ 2014 IntGetFontLocalizedName(&Names->FullNameW, SharedFace, TT_NAME_ID_UNIQUE_ID, gusLanguageID); 2015 2016 /* Calculate the size of OUTLINETEXTMETRICW with extra data */ 2017 OtmSize = sizeof(OUTLINETEXTMETRICW) + 2018 Names->FamilyNameW.Length + sizeof(UNICODE_NULL) + 2019 Names->FaceNameW.Length + sizeof(UNICODE_NULL) + 2020 Names->StyleNameW.Length + sizeof(UNICODE_NULL) + 2021 Names->FullNameW.Length + sizeof(UNICODE_NULL); 2022 Names->OtmSize = OtmSize; 2023 } 2024 2025 static __inline SIZE_T FASTCALL 2026 IntStoreName(const UNICODE_STRING *pName, BYTE *pb) 2027 { 2028 RtlCopyMemory(pb, pName->Buffer, pName->Length); 2029 *(WCHAR *)&pb[pName->Length] = UNICODE_NULL; 2030 return pName->Length + sizeof(UNICODE_NULL); 2031 } 2032 2033 static __inline BYTE *FASTCALL 2034 IntStoreFontNames(const FONT_NAMES *Names, OUTLINETEXTMETRICW *Otm) 2035 { 2036 BYTE *pb = (BYTE *)Otm + sizeof(OUTLINETEXTMETRICW); 2037 2038 /* family name */ 2039 Otm->otmpFamilyName = (LPSTR)(pb - (BYTE*) Otm); 2040 pb += IntStoreName(&Names->FamilyNameW, pb); 2041 2042 /* face name */ 2043 Otm->otmpFaceName = (LPSTR)(pb - (BYTE*) Otm); 2044 pb += IntStoreName(&Names->FaceNameW, pb); 2045 2046 /* style name */ 2047 Otm->otmpStyleName = (LPSTR)(pb - (BYTE*) Otm); 2048 pb += IntStoreName(&Names->StyleNameW, pb); 2049 2050 /* unique name (full name) */ 2051 Otm->otmpFullName = (LPSTR)(pb - (BYTE*) Otm); 2052 pb += IntStoreName(&Names->FullNameW, pb); 2053 2054 return pb; 2055 } 2056 2057 static __inline void FASTCALL 2058 IntFreeFontNames(FONT_NAMES *Names) 2059 { 2060 RtlFreeUnicodeString(&Names->FamilyNameW); 2061 RtlFreeUnicodeString(&Names->FaceNameW); 2062 RtlFreeUnicodeString(&Names->StyleNameW); 2063 RtlFreeUnicodeString(&Names->FullNameW); 2064 } 2065 2066 /************************************************************* 2067 * IntGetOutlineTextMetrics 2068 * 2069 */ 2070 INT FASTCALL 2071 IntGetOutlineTextMetrics(PFONTGDI FontGDI, 2072 UINT Size, 2073 OUTLINETEXTMETRICW *Otm) 2074 { 2075 TT_OS2 *pOS2; 2076 TT_HoriHeader *pHori; 2077 TT_Postscript *pPost; 2078 FT_Fixed XScale, YScale; 2079 FT_WinFNT_HeaderRec WinFNT; 2080 FT_Error Error; 2081 BYTE *pb; 2082 FONT_NAMES FontNames; 2083 PSHARED_FACE SharedFace = FontGDI->SharedFace; 2084 PSHARED_FACE_CACHE Cache; 2085 FT_Face Face = SharedFace->Face; 2086 2087 if (PRIMARYLANGID(gusLanguageID) == LANG_ENGLISH) 2088 { 2089 Cache = &SharedFace->EnglishUS; 2090 } 2091 else 2092 { 2093 Cache = &SharedFace->UserLanguage; 2094 } 2095 2096 if (Cache->OutlineRequiredSize && Size < Cache->OutlineRequiredSize) 2097 { 2098 return Cache->OutlineRequiredSize; 2099 } 2100 2101 IntInitFontNames(&FontNames, SharedFace); 2102 2103 if (!Cache->OutlineRequiredSize) 2104 { 2105 Cache->OutlineRequiredSize = FontNames.OtmSize; 2106 } 2107 2108 if (Size < Cache->OutlineRequiredSize) 2109 { 2110 IntFreeFontNames(&FontNames); 2111 return Cache->OutlineRequiredSize; 2112 } 2113 2114 XScale = Face->size->metrics.x_scale; 2115 YScale = Face->size->metrics.y_scale; 2116 2117 IntLockFreeType(); 2118 2119 pOS2 = FT_Get_Sfnt_Table(Face, FT_SFNT_OS2); 2120 if (NULL == pOS2) 2121 { 2122 IntUnLockFreeType(); 2123 DPRINT1("Can't find OS/2 table - not TT font?\n"); 2124 IntFreeFontNames(&FontNames); 2125 return 0; 2126 } 2127 2128 pHori = FT_Get_Sfnt_Table(Face, FT_SFNT_HHEA); 2129 if (NULL == pHori) 2130 { 2131 IntUnLockFreeType(); 2132 DPRINT1("Can't find HHEA table - not TT font?\n"); 2133 IntFreeFontNames(&FontNames); 2134 return 0; 2135 } 2136 2137 pPost = FT_Get_Sfnt_Table(Face, FT_SFNT_POST); /* We can live with this failing */ 2138 2139 Error = FT_Get_WinFNT_Header(Face, &WinFNT); 2140 2141 Otm->otmSize = Cache->OutlineRequiredSize; 2142 2143 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &WinFNT : 0); 2144 2145 Otm->otmFiller = 0; 2146 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT); 2147 Otm->otmfsSelection = pOS2->fsSelection; 2148 Otm->otmfsType = pOS2->fsType; 2149 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise; 2150 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run; 2151 Otm->otmItalicAngle = 0; /* POST table */ 2152 Otm->otmEMSquare = Face->units_per_EM; 2153 2154 #define SCALE_X(value) ((FT_MulFix((value), XScale) + 32) >> 6) 2155 #define SCALE_Y(value) ((FT_MulFix((value), YScale) + 32) >> 6) 2156 2157 Otm->otmAscent = SCALE_Y(pOS2->sTypoAscender); 2158 Otm->otmDescent = SCALE_Y(pOS2->sTypoDescender); 2159 Otm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap); 2160 Otm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight); 2161 Otm->otmsXHeight = SCALE_Y(pOS2->sxHeight); 2162 Otm->otmrcFontBox.left = SCALE_X(Face->bbox.xMin); 2163 Otm->otmrcFontBox.right = SCALE_X(Face->bbox.xMax); 2164 Otm->otmrcFontBox.top = SCALE_Y(Face->bbox.yMax); 2165 Otm->otmrcFontBox.bottom = SCALE_Y(Face->bbox.yMin); 2166 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent; 2167 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent; 2168 Otm->otmMacLineGap = Otm->otmLineGap; 2169 Otm->otmusMinimumPPEM = 0; /* TT Header */ 2170 Otm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize); 2171 Otm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize); 2172 Otm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset); 2173 Otm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset); 2174 Otm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize); 2175 Otm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize); 2176 Otm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset); 2177 Otm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset); 2178 Otm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize); 2179 Otm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition); 2180 2181 if (!pPost) 2182 { 2183 Otm->otmsUnderscoreSize = 0; 2184 Otm->otmsUnderscorePosition = 0; 2185 } 2186 else 2187 { 2188 Otm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness); 2189 Otm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition); 2190 } 2191 2192 #undef SCALE_X 2193 #undef SCALE_Y 2194 2195 IntUnLockFreeType(); 2196 2197 pb = IntStoreFontNames(&FontNames, Otm); 2198 ASSERT(pb - (BYTE*)Otm == Cache->OutlineRequiredSize); 2199 2200 IntFreeFontNames(&FontNames); 2201 2202 return Cache->OutlineRequiredSize; 2203 } 2204 2205 static PFONTGDI FASTCALL 2206 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head) 2207 { 2208 PLIST_ENTRY Entry; 2209 PFONT_ENTRY CurrentEntry; 2210 ANSI_STRING EntryFaceNameA; 2211 UNICODE_STRING EntryFaceNameW; 2212 FONTGDI *FontGDI; 2213 NTSTATUS status; 2214 2215 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) 2216 { 2217 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); 2218 2219 FontGDI = CurrentEntry->Font; 2220 ASSERT(FontGDI); 2221 2222 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name); 2223 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); 2224 if (!NT_SUCCESS(status)) 2225 { 2226 break; 2227 } 2228 2229 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length) 2230 { 2231 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR); 2232 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; 2233 } 2234 2235 if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE)) 2236 { 2237 RtlFreeUnicodeString(&EntryFaceNameW); 2238 return FontGDI; 2239 } 2240 2241 RtlFreeUnicodeString(&EntryFaceNameW); 2242 } 2243 2244 return NULL; 2245 } 2246 2247 static PFONTGDI FASTCALL 2248 FindFaceNameInLists(PUNICODE_STRING FaceName) 2249 { 2250 PPROCESSINFO Win32Process; 2251 PFONTGDI Font; 2252 2253 /* Search the process local list. 2254 We do not have to search the 'Mem' list, since those fonts are linked in the PrivateFontListHead */ 2255 Win32Process = PsGetCurrentProcessWin32Process(); 2256 IntLockProcessPrivateFonts(Win32Process); 2257 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead); 2258 IntUnLockProcessPrivateFonts(Win32Process); 2259 if (NULL != Font) 2260 { 2261 return Font; 2262 } 2263 2264 /* Search the global list */ 2265 IntLockGlobalFonts(); 2266 Font = FindFaceNameInList(FaceName, &g_FontListHead); 2267 IntUnLockGlobalFonts(); 2268 2269 return Font; 2270 } 2271 2272 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */ 2273 static BYTE 2274 CharSetFromLangID(LANGID LangID) 2275 { 2276 /* FIXME: Add more and fix if wrong */ 2277 switch (PRIMARYLANGID(LangID)) 2278 { 2279 case LANG_CHINESE: 2280 switch (SUBLANGID(LangID)) 2281 { 2282 case SUBLANG_CHINESE_TRADITIONAL: 2283 return CHINESEBIG5_CHARSET; 2284 case SUBLANG_CHINESE_SIMPLIFIED: 2285 default: 2286 break; 2287 } 2288 return GB2312_CHARSET; 2289 2290 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH: 2291 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN: 2292 return EASTEUROPE_CHARSET; 2293 2294 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN: 2295 case LANG_SERBIAN: case LANG_UKRAINIAN: 2296 return RUSSIAN_CHARSET; 2297 2298 case LANG_ARABIC: return ARABIC_CHARSET; 2299 case LANG_GREEK: return GREEK_CHARSET; 2300 case LANG_HEBREW: return HEBREW_CHARSET; 2301 case LANG_JAPANESE: return SHIFTJIS_CHARSET; 2302 case LANG_KOREAN: return JOHAB_CHARSET; 2303 case LANG_TURKISH: return TURKISH_CHARSET; 2304 case LANG_THAI: return THAI_CHARSET; 2305 case LANG_LATVIAN: return BALTIC_CHARSET; 2306 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET; 2307 2308 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN: 2309 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH: 2310 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN: 2311 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH: 2312 case LANG_SWEDISH: default: 2313 return ANSI_CHARSET; 2314 } 2315 } 2316 2317 static void 2318 SwapEndian(LPVOID pvData, DWORD Size) 2319 { 2320 BYTE b, *pb = pvData; 2321 Size /= 2; 2322 while (Size-- > 0) 2323 { 2324 b = pb[0]; 2325 pb[0] = pb[1]; 2326 pb[1] = b; 2327 ++pb; ++pb; 2328 } 2329 } 2330 2331 static NTSTATUS 2332 DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination) 2333 { 2334 NTSTATUS Status = STATUS_NO_MEMORY; 2335 UNICODE_STRING Tmp; 2336 2337 Tmp.Buffer = ExAllocatePoolWithTag(PagedPool, Source->MaximumLength, TAG_USTR); 2338 if (Tmp.Buffer) 2339 { 2340 Tmp.MaximumLength = Source->MaximumLength; 2341 Tmp.Length = 0; 2342 RtlCopyUnicodeString(&Tmp, Source); 2343 2344 Destination->MaximumLength = Tmp.MaximumLength; 2345 Destination->Length = Tmp.Length; 2346 Destination->Buffer = Tmp.Buffer; 2347 2348 Status = STATUS_SUCCESS; 2349 } 2350 2351 return Status; 2352 } 2353 2354 static NTSTATUS 2355 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace, 2356 FT_UShort NameID, FT_UShort LangID) 2357 { 2358 FT_SfntName Name; 2359 INT i, Count, BestIndex, Score, BestScore; 2360 FT_Error Error; 2361 NTSTATUS Status = STATUS_NOT_FOUND; 2362 ANSI_STRING AnsiName; 2363 PSHARED_FACE_CACHE Cache; 2364 FT_Face Face = SharedFace->Face; 2365 2366 RtlFreeUnicodeString(pNameW); 2367 2368 /* select cache */ 2369 if (PRIMARYLANGID(LangID) == LANG_ENGLISH) 2370 { 2371 Cache = &SharedFace->EnglishUS; 2372 } 2373 else 2374 { 2375 Cache = &SharedFace->UserLanguage; 2376 } 2377 2378 /* use cache if available */ 2379 if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer) 2380 { 2381 return DuplicateUnicodeString(&Cache->FontFamily, pNameW); 2382 } 2383 if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer) 2384 { 2385 return DuplicateUnicodeString(&Cache->FullName, pNameW); 2386 } 2387 2388 BestIndex = -1; 2389 BestScore = 0; 2390 2391 Count = FT_Get_Sfnt_Name_Count(Face); 2392 for (i = 0; i < Count; ++i) 2393 { 2394 Error = FT_Get_Sfnt_Name(Face, i, &Name); 2395 if (Error) 2396 { 2397 continue; /* failure */ 2398 } 2399 2400 if (Name.name_id != NameID) 2401 { 2402 continue; /* mismatched */ 2403 } 2404 2405 if (Name.platform_id != TT_PLATFORM_MICROSOFT || 2406 (Name.encoding_id != TT_MS_ID_UNICODE_CS && 2407 Name.encoding_id != TT_MS_ID_SYMBOL_CS)) 2408 { 2409 continue; /* not Microsoft Unicode name */ 2410 } 2411 2412 if (Name.string == NULL || Name.string_len == 0 || 2413 (Name.string[0] == 0 && Name.string[1] == 0)) 2414 { 2415 continue; /* invalid string */ 2416 } 2417 2418 if (Name.language_id == LangID) 2419 { 2420 Score = 30; 2421 BestIndex = i; 2422 break; /* best match */ 2423 } 2424 else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID)) 2425 { 2426 Score = 20; 2427 } 2428 else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH) 2429 { 2430 Score = 10; 2431 } 2432 else 2433 { 2434 Score = 0; 2435 } 2436 2437 if (Score > BestScore) 2438 { 2439 BestScore = Score; 2440 BestIndex = i; 2441 } 2442 } 2443 2444 if (BestIndex >= 0) 2445 { 2446 /* store the best name */ 2447 Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name); 2448 if (!Error) 2449 { 2450 /* NOTE: Name.string is not null-terminated */ 2451 UNICODE_STRING Tmp; 2452 Tmp.Buffer = (PWCH)Name.string; 2453 Tmp.Length = Tmp.MaximumLength = Name.string_len; 2454 2455 pNameW->Length = 0; 2456 pNameW->MaximumLength = Name.string_len + sizeof(WCHAR); 2457 pNameW->Buffer = ExAllocatePoolWithTag(PagedPool, pNameW->MaximumLength, TAG_USTR); 2458 2459 if (pNameW->Buffer) 2460 { 2461 Status = RtlAppendUnicodeStringToString(pNameW, &Tmp); 2462 if (Status == STATUS_SUCCESS) 2463 { 2464 /* Convert UTF-16 big endian to little endian */ 2465 SwapEndian(pNameW->Buffer, pNameW->Length); 2466 } 2467 } 2468 else 2469 { 2470 Status = STATUS_INSUFFICIENT_RESOURCES; 2471 } 2472 } 2473 } 2474 2475 if (!NT_SUCCESS(Status)) 2476 { 2477 /* defaulted */ 2478 if (NameID == TT_NAME_ID_FONT_SUBFAMILY) 2479 { 2480 RtlInitAnsiString(&AnsiName, Face->style_name); 2481 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE); 2482 } 2483 else 2484 { 2485 RtlInitAnsiString(&AnsiName, Face->family_name); 2486 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE); 2487 } 2488 } 2489 2490 if (NT_SUCCESS(Status)) 2491 { 2492 /* make cache */ 2493 if (NameID == TT_NAME_ID_FONT_FAMILY) 2494 { 2495 ASSERT_FREETYPE_LOCK_NOT_HELD(); 2496 IntLockFreeType(); 2497 if (!Cache->FontFamily.Buffer) 2498 DuplicateUnicodeString(pNameW, &Cache->FontFamily); 2499 IntUnLockFreeType(); 2500 } 2501 else if (NameID == TT_NAME_ID_FULL_NAME) 2502 { 2503 ASSERT_FREETYPE_LOCK_NOT_HELD(); 2504 IntLockFreeType(); 2505 if (!Cache->FullName.Buffer) 2506 DuplicateUnicodeString(pNameW, &Cache->FullName); 2507 IntUnLockFreeType(); 2508 } 2509 } 2510 2511 return Status; 2512 } 2513 2514 static void FASTCALL 2515 FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName, 2516 LPCWSTR FullName, PFONTGDI FontGDI) 2517 { 2518 ANSI_STRING StyleA; 2519 UNICODE_STRING StyleW; 2520 TT_OS2 *pOS2; 2521 FONTSIGNATURE fs; 2522 CHARSETINFO CharSetInfo; 2523 unsigned i, Size; 2524 OUTLINETEXTMETRICW *Otm; 2525 LOGFONTW *Lf; 2526 TEXTMETRICW *TM; 2527 NEWTEXTMETRICW *Ntm; 2528 DWORD fs0; 2529 NTSTATUS status; 2530 PSHARED_FACE SharedFace = FontGDI->SharedFace; 2531 FT_Face Face = SharedFace->Face; 2532 UNICODE_STRING NameW; 2533 2534 RtlInitUnicodeString(&NameW, NULL); 2535 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO)); 2536 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 2537 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 2538 if (!Otm) 2539 { 2540 return; 2541 } 2542 Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm); 2543 if (!Size) 2544 { 2545 ExFreePoolWithTag(Otm, GDITAG_TEXT); 2546 return; 2547 } 2548 2549 Lf = &Info->EnumLogFontEx.elfLogFont; 2550 TM = &Otm->otmTextMetrics; 2551 2552 Lf->lfHeight = TM->tmHeight; 2553 Lf->lfWidth = TM->tmAveCharWidth; 2554 Lf->lfWeight = TM->tmWeight; 2555 Lf->lfItalic = TM->tmItalic; 2556 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1; 2557 Lf->lfCharSet = TM->tmCharSet; 2558 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS; 2559 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; 2560 Lf->lfQuality = PROOF_QUALITY; 2561 2562 Ntm = &Info->NewTextMetricEx.ntmTm; 2563 Ntm->tmHeight = TM->tmHeight; 2564 Ntm->tmAscent = TM->tmAscent; 2565 Ntm->tmDescent = TM->tmDescent; 2566 Ntm->tmInternalLeading = TM->tmInternalLeading; 2567 Ntm->tmExternalLeading = TM->tmExternalLeading; 2568 Ntm->tmAveCharWidth = TM->tmAveCharWidth; 2569 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth; 2570 Ntm->tmWeight = TM->tmWeight; 2571 Ntm->tmOverhang = TM->tmOverhang; 2572 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX; 2573 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY; 2574 Ntm->tmFirstChar = TM->tmFirstChar; 2575 Ntm->tmLastChar = TM->tmLastChar; 2576 Ntm->tmDefaultChar = TM->tmDefaultChar; 2577 Ntm->tmBreakChar = TM->tmBreakChar; 2578 Ntm->tmItalic = TM->tmItalic; 2579 Ntm->tmUnderlined = TM->tmUnderlined; 2580 Ntm->tmStruckOut = TM->tmStruckOut; 2581 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily; 2582 Ntm->tmCharSet = TM->tmCharSet; 2583 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0; 2584 2585 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD; 2586 2587 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR; 2588 2589 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE) 2590 ? TRUETYPE_FONTTYPE : 0); 2591 2592 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR)) 2593 Info->FontType |= RASTER_FONTTYPE; 2594 2595 2596 /* face name */ 2597 if (!FaceName) 2598 FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName); 2599 2600 RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName); 2601 2602 /* full name */ 2603 if (!FullName) 2604 FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName); 2605 2606 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName, 2607 sizeof(Info->EnumLogFontEx.elfFullName), 2608 FullName); 2609 2610 RtlInitAnsiString(&StyleA, Face->style_name); 2611 StyleW.Buffer = Info->EnumLogFontEx.elfStyle; 2612 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle); 2613 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE); 2614 if (!NT_SUCCESS(status)) 2615 { 2616 ExFreePoolWithTag(Otm, GDITAG_TEXT); 2617 return; 2618 } 2619 Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL; 2620 2621 IntLockFreeType(); 2622 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); 2623 2624 if (!pOS2) 2625 { 2626 IntUnLockFreeType(); 2627 ExFreePoolWithTag(Otm, GDITAG_TEXT); 2628 return; 2629 } 2630 2631 Ntm->ntmSizeEM = Otm->otmEMSquare; 2632 Ntm->ntmCellHeight = pOS2->usWinAscent + pOS2->usWinDescent; 2633 Ntm->ntmAvgWidth = 0; 2634 2635 ExFreePoolWithTag(Otm, GDITAG_TEXT); 2636 2637 fs.fsCsb[0] = pOS2->ulCodePageRange1; 2638 fs.fsCsb[1] = pOS2->ulCodePageRange2; 2639 fs.fsUsb[0] = pOS2->ulUnicodeRange1; 2640 fs.fsUsb[1] = pOS2->ulUnicodeRange2; 2641 fs.fsUsb[2] = pOS2->ulUnicodeRange3; 2642 fs.fsUsb[3] = pOS2->ulUnicodeRange4; 2643 2644 if (0 == pOS2->version) 2645 { 2646 FT_UInt Dummy; 2647 2648 if (FT_Get_First_Char(Face, &Dummy) < 0x100) 2649 fs.fsCsb[0] |= FS_LATIN1; 2650 else 2651 fs.fsCsb[0] |= FS_SYMBOL; 2652 } 2653 IntUnLockFreeType(); 2654 2655 if (fs.fsCsb[0] == 0) 2656 { 2657 /* Let's see if we can find any interesting cmaps */ 2658 for (i = 0; i < (UINT)Face->num_charmaps; i++) 2659 { 2660 switch (Face->charmaps[i]->encoding) 2661 { 2662 case FT_ENCODING_UNICODE: 2663 case FT_ENCODING_APPLE_ROMAN: 2664 fs.fsCsb[0] |= FS_LATIN1; 2665 break; 2666 case FT_ENCODING_MS_SYMBOL: 2667 fs.fsCsb[0] |= FS_SYMBOL; 2668 break; 2669 default: 2670 break; 2671 } 2672 } 2673 } 2674 2675 for (i = 0; i < MAXTCIINDEX; i++) 2676 { 2677 fs0 = 1L << i; 2678 if (fs.fsCsb[0] & fs0) 2679 { 2680 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG)) 2681 { 2682 CharSetInfo.ciCharset = DEFAULT_CHARSET; 2683 } 2684 if (DEFAULT_CHARSET != CharSetInfo.ciCharset) 2685 { 2686 if (g_ElfScripts[i]) 2687 wcscpy(Info->EnumLogFontEx.elfScript, g_ElfScripts[i]); 2688 else 2689 { 2690 DPRINT1("Unknown elfscript for bit %u\n", i); 2691 } 2692 } 2693 } 2694 } 2695 Info->NewTextMetricEx.ntmFontSig = fs; 2696 } 2697 2698 static int FASTCALL 2699 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries) 2700 { 2701 DWORD i; 2702 UNICODE_STRING InfoFaceName; 2703 2704 for (i = 0; i < InfoEntries; i++) 2705 { 2706 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName); 2707 if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE)) 2708 { 2709 return i; 2710 } 2711 } 2712 2713 return -1; 2714 } 2715 2716 static BOOLEAN FASTCALL 2717 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName, 2718 PFONTFAMILYINFO Info, DWORD InfoEntries) 2719 { 2720 UNICODE_STRING LogFontFaceName; 2721 2722 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName); 2723 if (0 != LogFontFaceName.Length && 2724 !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE)) 2725 { 2726 return FALSE; 2727 } 2728 2729 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0; 2730 } 2731 2732 static BOOL FASTCALL 2733 FontFamilyFound(PFONTFAMILYINFO InfoEntry, 2734 PFONTFAMILYINFO Info, DWORD InfoCount) 2735 { 2736 LPLOGFONTW plf1 = &InfoEntry->EnumLogFontEx.elfLogFont; 2737 LPWSTR pFullName1 = InfoEntry->EnumLogFontEx.elfFullName; 2738 LPWSTR pFullName2; 2739 DWORD i; 2740 2741 for (i = 0; i < InfoCount; ++i) 2742 { 2743 LPLOGFONTW plf2 = &Info[i].EnumLogFontEx.elfLogFont; 2744 if (plf1->lfCharSet != plf2->lfCharSet) 2745 continue; 2746 2747 pFullName2 = Info[i].EnumLogFontEx.elfFullName; 2748 if (_wcsicmp(pFullName1, pFullName2) != 0) 2749 continue; 2750 2751 return TRUE; 2752 } 2753 return FALSE; 2754 } 2755 2756 static BOOLEAN FASTCALL 2757 GetFontFamilyInfoForList(LPLOGFONTW LogFont, 2758 PFONTFAMILYINFO Info, 2759 DWORD *pCount, 2760 DWORD MaxCount, 2761 PLIST_ENTRY Head) 2762 { 2763 PLIST_ENTRY Entry; 2764 PFONT_ENTRY CurrentEntry; 2765 FONTGDI *FontGDI; 2766 FONTFAMILYINFO InfoEntry; 2767 DWORD Count = *pCount; 2768 2769 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) 2770 { 2771 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); 2772 FontGDI = CurrentEntry->Font; 2773 ASSERT(FontGDI); 2774 2775 if (LogFont->lfCharSet != DEFAULT_CHARSET && 2776 LogFont->lfCharSet != FontGDI->CharSet) 2777 { 2778 continue; 2779 } 2780 2781 if (LogFont->lfFaceName[0] == UNICODE_NULL) 2782 { 2783 if (Count < MaxCount) 2784 { 2785 FontFamilyFillInfo(&Info[Count], NULL, NULL, FontGDI); 2786 } 2787 Count++; 2788 continue; 2789 } 2790 2791 FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI); 2792 2793 if (_wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0 && 2794 _wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfFullName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0) 2795 { 2796 continue; 2797 } 2798 2799 if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount))) 2800 { 2801 if (Count < MaxCount) 2802 { 2803 RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry)); 2804 } 2805 Count++; 2806 } 2807 } 2808 2809 *pCount = Count; 2810 2811 return TRUE; 2812 } 2813 2814 static BOOLEAN FASTCALL 2815 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont, 2816 PFONTFAMILYINFO Info, 2817 DWORD *pCount, 2818 DWORD MaxCount) 2819 { 2820 PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead; 2821 PFONTSUBST_ENTRY pCurrentEntry; 2822 PUNICODE_STRING pFromW; 2823 FONTGDI *FontGDI; 2824 LOGFONTW lf = *LogFont; 2825 UNICODE_STRING NameW; 2826 2827 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) 2828 { 2829 pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry); 2830 2831 pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM]; 2832 if (LogFont->lfFaceName[0] != UNICODE_NULL) 2833 { 2834 if (!FontFamilyInclude(LogFont, pFromW, Info, min(*pCount, MaxCount))) 2835 continue; /* mismatch */ 2836 } 2837 2838 IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW); 2839 SubstituteFontRecurse(&lf); 2840 2841 RtlInitUnicodeString(&NameW, lf.lfFaceName); 2842 FontGDI = FindFaceNameInLists(&NameW); 2843 if (FontGDI == NULL) 2844 { 2845 continue; /* no real font */ 2846 } 2847 2848 if (*pCount < MaxCount) 2849 { 2850 FontFamilyFillInfo(&Info[*pCount], pFromW->Buffer, NULL, FontGDI); 2851 } 2852 (*pCount)++; 2853 } 2854 2855 return TRUE; 2856 } 2857 2858 BOOL 2859 FASTCALL 2860 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs) 2861 { 2862 if ( lprs ) 2863 { 2864 lprs->nSize = sizeof(RASTERIZER_STATUS); 2865 lprs->wFlags = TT_AVAILABLE | TT_ENABLED; 2866 lprs->nLanguageID = gusLanguageID; 2867 return TRUE; 2868 } 2869 EngSetLastError(ERROR_INVALID_PARAMETER); 2870 return FALSE; 2871 } 2872 2873 static 2874 BOOL 2875 SameScaleMatrix( 2876 PMATRIX pmx1, 2877 PMATRIX pmx2) 2878 { 2879 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) && 2880 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) && 2881 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) && 2882 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22)); 2883 } 2884 2885 FT_BitmapGlyph APIENTRY 2886 ftGdiGlyphCacheGet( 2887 FT_Face Face, 2888 INT GlyphIndex, 2889 INT Height, 2890 FT_Render_Mode RenderMode, 2891 PMATRIX pmx) 2892 { 2893 PLIST_ENTRY CurrentEntry; 2894 PFONT_CACHE_ENTRY FontEntry; 2895 2896 ASSERT_FREETYPE_LOCK_HELD(); 2897 2898 for (CurrentEntry = g_FontCacheListHead.Flink; 2899 CurrentEntry != &g_FontCacheListHead; 2900 CurrentEntry = CurrentEntry->Flink) 2901 { 2902 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry); 2903 if ((FontEntry->Face == Face) && 2904 (FontEntry->GlyphIndex == GlyphIndex) && 2905 (FontEntry->Height == Height) && 2906 (FontEntry->RenderMode == RenderMode) && 2907 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx))) 2908 break; 2909 } 2910 2911 if (CurrentEntry == &g_FontCacheListHead) 2912 { 2913 return NULL; 2914 } 2915 2916 RemoveEntryList(CurrentEntry); 2917 InsertHeadList(&g_FontCacheListHead, CurrentEntry); 2918 return FontEntry->BitmapGlyph; 2919 } 2920 2921 /* no cache */ 2922 FT_BitmapGlyph APIENTRY 2923 ftGdiGlyphSet( 2924 FT_Face Face, 2925 FT_GlyphSlot GlyphSlot, 2926 FT_Render_Mode RenderMode) 2927 { 2928 FT_Glyph Glyph; 2929 INT error; 2930 FT_Bitmap AlignedBitmap; 2931 FT_BitmapGlyph BitmapGlyph; 2932 2933 error = FT_Get_Glyph(GlyphSlot, &Glyph); 2934 if (error) 2935 { 2936 DPRINT1("Failure getting glyph.\n"); 2937 return NULL; 2938 } 2939 2940 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1); 2941 if (error) 2942 { 2943 FT_Done_Glyph(Glyph); 2944 DPRINT1("Failure rendering glyph.\n"); 2945 return NULL; 2946 } 2947 2948 BitmapGlyph = (FT_BitmapGlyph)Glyph; 2949 FT_Bitmap_New(&AlignedBitmap); 2950 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4)) 2951 { 2952 DPRINT1("Conversion failed\n"); 2953 FT_Done_Glyph((FT_Glyph)BitmapGlyph); 2954 return NULL; 2955 } 2956 2957 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap); 2958 BitmapGlyph->bitmap = AlignedBitmap; 2959 2960 return BitmapGlyph; 2961 } 2962 2963 FT_BitmapGlyph APIENTRY 2964 ftGdiGlyphCacheSet( 2965 FT_Face Face, 2966 INT GlyphIndex, 2967 INT Height, 2968 PMATRIX pmx, 2969 FT_GlyphSlot GlyphSlot, 2970 FT_Render_Mode RenderMode) 2971 { 2972 FT_Glyph GlyphCopy; 2973 INT error; 2974 PFONT_CACHE_ENTRY NewEntry; 2975 FT_Bitmap AlignedBitmap; 2976 FT_BitmapGlyph BitmapGlyph; 2977 2978 ASSERT_FREETYPE_LOCK_HELD(); 2979 2980 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy); 2981 if (error) 2982 { 2983 DPRINT1("Failure caching glyph.\n"); 2984 return NULL; 2985 }; 2986 2987 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1); 2988 if (error) 2989 { 2990 FT_Done_Glyph(GlyphCopy); 2991 DPRINT1("Failure rendering glyph.\n"); 2992 return NULL; 2993 }; 2994 2995 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT); 2996 if (!NewEntry) 2997 { 2998 DPRINT1("Alloc failure caching glyph.\n"); 2999 FT_Done_Glyph(GlyphCopy); 3000 return NULL; 3001 } 3002 3003 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy; 3004 FT_Bitmap_New(&AlignedBitmap); 3005 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4)) 3006 { 3007 DPRINT1("Conversion failed\n"); 3008 ExFreePoolWithTag(NewEntry, TAG_FONT); 3009 FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap); 3010 FT_Done_Glyph((FT_Glyph)BitmapGlyph); 3011 return NULL; 3012 } 3013 3014 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap); 3015 BitmapGlyph->bitmap = AlignedBitmap; 3016 3017 NewEntry->GlyphIndex = GlyphIndex; 3018 NewEntry->Face = Face; 3019 NewEntry->BitmapGlyph = BitmapGlyph; 3020 NewEntry->Height = Height; 3021 NewEntry->RenderMode = RenderMode; 3022 NewEntry->mxWorldToDevice = *pmx; 3023 3024 InsertHeadList(&g_FontCacheListHead, &NewEntry->ListEntry); 3025 if (++g_FontCacheNumEntries > MAX_FONT_CACHE) 3026 { 3027 NewEntry = CONTAINING_RECORD(g_FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry); 3028 RemoveCachedEntry(NewEntry); 3029 } 3030 3031 return BitmapGlyph; 3032 } 3033 3034 3035 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt) 3036 { 3037 pt->x.value = vec->x >> 6; 3038 pt->x.fract = (vec->x & 0x3f) << 10; 3039 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12)); 3040 pt->y.value = vec->y >> 6; 3041 pt->y.fract = (vec->y & 0x3f) << 10; 3042 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12)); 3043 } 3044 3045 /* 3046 This function builds an FT_Fixed from a float. It puts the integer part 3047 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed. 3048 It fails if the integer part of the float number is greater than SHORT_MAX. 3049 */ 3050 static __inline FT_Fixed FT_FixedFromFloat(float f) 3051 { 3052 short value = f; 3053 unsigned short fract = (f - value) * 0xFFFF; 3054 return (FT_Fixed)((long)value << 16 | (unsigned long)fract); 3055 } 3056 3057 /* 3058 This function builds an FT_Fixed from a FIXED. It simply put f.value 3059 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed. 3060 */ 3061 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f) 3062 { 3063 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract); 3064 } 3065 3066 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) 3067 { 3068 TTPOLYGONHEADER *pph; 3069 TTPOLYCURVE *ppc; 3070 int needed = 0, point = 0, contour, first_pt; 3071 unsigned int pph_start, cpfx; 3072 DWORD type; 3073 3074 for (contour = 0; contour < outline->n_contours; contour++) 3075 { 3076 /* Ignore contours containing one point */ 3077 if (point == outline->contours[contour]) 3078 { 3079 point++; 3080 continue; 3081 } 3082 3083 pph_start = needed; 3084 pph = (TTPOLYGONHEADER *)(buf + needed); 3085 first_pt = point; 3086 if (buf) 3087 { 3088 pph->dwType = TT_POLYGON_TYPE; 3089 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); 3090 } 3091 needed += sizeof(*pph); 3092 point++; 3093 while (point <= outline->contours[contour]) 3094 { 3095 ppc = (TTPOLYCURVE *)(buf + needed); 3096 type = outline->tags[point] & FT_Curve_Tag_On ? 3097 TT_PRIM_LINE : TT_PRIM_QSPLINE; 3098 cpfx = 0; 3099 do 3100 { 3101 if (buf) 3102 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); 3103 cpfx++; 3104 point++; 3105 } while (point <= outline->contours[contour] && 3106 (outline->tags[point] & FT_Curve_Tag_On) == 3107 (outline->tags[point-1] & FT_Curve_Tag_On)); 3108 /* At the end of a contour Windows adds the start point, but 3109 only for Beziers */ 3110 if (point > outline->contours[contour] && 3111 !(outline->tags[point-1] & FT_Curve_Tag_On)) 3112 { 3113 if (buf) 3114 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]); 3115 cpfx++; 3116 } 3117 else if (point <= outline->contours[contour] && 3118 outline->tags[point] & FT_Curve_Tag_On) 3119 { 3120 /* add closing pt for bezier */ 3121 if (buf) 3122 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); 3123 cpfx++; 3124 point++; 3125 } 3126 if (buf) 3127 { 3128 ppc->wType = type; 3129 ppc->cpfx = cpfx; 3130 } 3131 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); 3132 } 3133 if (buf) 3134 pph->cb = needed - pph_start; 3135 } 3136 return needed; 3137 } 3138 3139 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) 3140 { 3141 /* Convert the quadratic Beziers to cubic Beziers. 3142 The parametric eqn for a cubic Bezier is, from PLRM: 3143 r(t) = at^3 + bt^2 + ct + r0 3144 with the control points: 3145 r1 = r0 + c/3 3146 r2 = r1 + (c + b)/3 3147 r3 = r0 + c + b + a 3148 3149 A quadratic Bezier has the form: 3150 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2 3151 3152 So equating powers of t leads to: 3153 r1 = 2/3 p1 + 1/3 p0 3154 r2 = 2/3 p1 + 1/3 p2 3155 and of course r0 = p0, r3 = p2 3156 */ 3157 int contour, point = 0, first_pt; 3158 TTPOLYGONHEADER *pph; 3159 TTPOLYCURVE *ppc; 3160 DWORD pph_start, cpfx, type; 3161 FT_Vector cubic_control[4]; 3162 unsigned int needed = 0; 3163 3164 for (contour = 0; contour < outline->n_contours; contour++) 3165 { 3166 pph_start = needed; 3167 pph = (TTPOLYGONHEADER *)(buf + needed); 3168 first_pt = point; 3169 if (buf) 3170 { 3171 pph->dwType = TT_POLYGON_TYPE; 3172 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); 3173 } 3174 needed += sizeof(*pph); 3175 point++; 3176 while (point <= outline->contours[contour]) 3177 { 3178 ppc = (TTPOLYCURVE *)(buf + needed); 3179 type = outline->tags[point] & FT_Curve_Tag_On ? 3180 TT_PRIM_LINE : TT_PRIM_CSPLINE; 3181 cpfx = 0; 3182 do 3183 { 3184 if (type == TT_PRIM_LINE) 3185 { 3186 if (buf) 3187 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); 3188 cpfx++; 3189 point++; 3190 } 3191 else 3192 { 3193 /* Unlike QSPLINEs, CSPLINEs always have their endpoint 3194 so cpfx = 3n */ 3195 3196 /* FIXME: Possible optimization in endpoint calculation 3197 if there are two consecutive curves */ 3198 cubic_control[0] = outline->points[point-1]; 3199 if (!(outline->tags[point-1] & FT_Curve_Tag_On)) 3200 { 3201 cubic_control[0].x += outline->points[point].x + 1; 3202 cubic_control[0].y += outline->points[point].y + 1; 3203 cubic_control[0].x >>= 1; 3204 cubic_control[0].y >>= 1; 3205 } 3206 if (point+1 > outline->contours[contour]) 3207 cubic_control[3] = outline->points[first_pt]; 3208 else 3209 { 3210 cubic_control[3] = outline->points[point+1]; 3211 if (!(outline->tags[point+1] & FT_Curve_Tag_On)) 3212 { 3213 cubic_control[3].x += outline->points[point].x + 1; 3214 cubic_control[3].y += outline->points[point].y + 1; 3215 cubic_control[3].x >>= 1; 3216 cubic_control[3].y >>= 1; 3217 } 3218 } 3219 /* r1 = 1/3 p0 + 2/3 p1 3220 r2 = 1/3 p2 + 2/3 p1 */ 3221 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3; 3222 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3; 3223 cubic_control[2] = cubic_control[1]; 3224 cubic_control[1].x += (cubic_control[0].x + 1) / 3; 3225 cubic_control[1].y += (cubic_control[0].y + 1) / 3; 3226 cubic_control[2].x += (cubic_control[3].x + 1) / 3; 3227 cubic_control[2].y += (cubic_control[3].y + 1) / 3; 3228 if (buf) 3229 { 3230 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]); 3231 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]); 3232 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]); 3233 } 3234 cpfx += 3; 3235 point++; 3236 } 3237 } while (point <= outline->contours[contour] && 3238 (outline->tags[point] & FT_Curve_Tag_On) == 3239 (outline->tags[point-1] & FT_Curve_Tag_On)); 3240 /* At the end of a contour Windows adds the start point, 3241 but only for Beziers and we've already done that. 3242 */ 3243 if (point <= outline->contours[contour] && 3244 outline->tags[point] & FT_Curve_Tag_On) 3245 { 3246 /* This is the closing pt of a bezier, but we've already 3247 added it, so just inc point and carry on */ 3248 point++; 3249 } 3250 if (buf) 3251 { 3252 ppc->wType = type; 3253 ppc->cpfx = cpfx; 3254 } 3255 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); 3256 } 3257 if (buf) 3258 pph->cb = needed - pph_start; 3259 } 3260 return needed; 3261 } 3262 3263 static FT_Error 3264 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight) 3265 { 3266 FT_Error error; 3267 FT_Size_RequestRec req; 3268 FT_Face face = FontGDI->SharedFace->Face; 3269 TT_OS2 *pOS2; 3270 TT_HoriHeader *pHori; 3271 FT_WinFNT_HeaderRec WinFNT; 3272 LONG Ascent, Descent, Sum, EmHeight64; 3273 3274 lfWidth = abs(lfWidth); 3275 if (lfHeight == 0) 3276 { 3277 if (lfWidth == 0) 3278 { 3279 DPRINT("lfHeight and lfWidth are zero.\n"); 3280 lfHeight = -16; 3281 } 3282 else 3283 { 3284 lfHeight = lfWidth; 3285 } 3286 } 3287 3288 if (lfHeight == -1) 3289 lfHeight = -2; 3290 3291 ASSERT_FREETYPE_LOCK_HELD(); 3292 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2); 3293 pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA); 3294 3295 if (!pOS2 || !pHori) 3296 { 3297 error = FT_Get_WinFNT_Header(face, &WinFNT); 3298 if (error) 3299 { 3300 DPRINT1("%s: Failed to request font size.\n", face->family_name); 3301 ASSERT(FALSE); 3302 return error; 3303 } 3304 3305 FontGDI->tmHeight = WinFNT.pixel_height; 3306 FontGDI->tmAscent = WinFNT.ascent; 3307 FontGDI->tmDescent = FontGDI->tmHeight - FontGDI->tmAscent; 3308 FontGDI->tmInternalLeading = WinFNT.internal_leading; 3309 FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading; 3310 FontGDI->EmHeight = max(FontGDI->EmHeight, 1); 3311 FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX); 3312 FontGDI->Magic = FONTGDI_MAGIC; 3313 3314 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; 3315 req.width = 0; 3316 req.height = (FT_Long)(FontGDI->EmHeight << 6); 3317 req.horiResolution = 0; 3318 req.vertResolution = 0; 3319 return FT_Request_Size(face, &req); 3320 } 3321 3322 /* See also: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fsselection */ 3323 #define FM_SEL_USE_TYPO_METRICS 0x80 3324 if (lfHeight > 0) 3325 { 3326 /* case (A): lfHeight is positive */ 3327 Sum = pOS2->usWinAscent + pOS2->usWinDescent; 3328 if (Sum == 0 || (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS)) 3329 { 3330 Ascent = pHori->Ascender; 3331 Descent = -pHori->Descender; 3332 Sum = Ascent + Descent; 3333 } 3334 else 3335 { 3336 Ascent = pOS2->usWinAscent; 3337 Descent = pOS2->usWinDescent; 3338 } 3339 3340 FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum); 3341 FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum); 3342 FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent; 3343 FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum); 3344 } 3345 else if (lfHeight < 0) 3346 { 3347 /* case (B): lfHeight is negative */ 3348 if (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS) 3349 { 3350 FontGDI->tmAscent = FT_MulDiv(-lfHeight, pHori->Ascender, face->units_per_EM); 3351 FontGDI->tmDescent = FT_MulDiv(-lfHeight, -pHori->Descender, face->units_per_EM); 3352 } 3353 else 3354 { 3355 FontGDI->tmAscent = FT_MulDiv(-lfHeight, pOS2->usWinAscent, face->units_per_EM); 3356 FontGDI->tmDescent = FT_MulDiv(-lfHeight, pOS2->usWinDescent, face->units_per_EM); 3357 } 3358 FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent; 3359 FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight; 3360 } 3361 #undef FM_SEL_USE_TYPO_METRICS 3362 3363 FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading; 3364 FontGDI->EmHeight = max(FontGDI->EmHeight, 1); 3365 FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX); 3366 FontGDI->Magic = FONTGDI_MAGIC; 3367 3368 if (lfHeight > 0) 3369 EmHeight64 = (FontGDI->EmHeight << 6) + 31; 3370 else 3371 EmHeight64 = (FontGDI->EmHeight << 6); 3372 3373 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; 3374 req.width = 0; 3375 req.height = EmHeight64; 3376 req.horiResolution = 0; 3377 req.vertResolution = 0; 3378 return FT_Request_Size(face, &req); 3379 } 3380 3381 BOOL 3382 FASTCALL 3383 TextIntUpdateSize(PDC dc, 3384 PTEXTOBJ TextObj, 3385 PFONTGDI FontGDI, 3386 BOOL bDoLock) 3387 { 3388 FT_Face face; 3389 INT error, n; 3390 FT_CharMap charmap, found; 3391 LOGFONTW *plf; 3392 3393 if (bDoLock) 3394 IntLockFreeType(); 3395 3396 face = FontGDI->SharedFace->Face; 3397 if (face->charmap == NULL) 3398 { 3399 DPRINT("WARNING: No charmap selected!\n"); 3400 DPRINT("This font face has %d charmaps\n", face->num_charmaps); 3401 3402 found = NULL; 3403 for (n = 0; n < face->num_charmaps; n++) 3404 { 3405 charmap = face->charmaps[n]; 3406 if (charmap->encoding == FT_ENCODING_UNICODE) 3407 { 3408 found = charmap; 3409 break; 3410 } 3411 } 3412 if (!found) 3413 { 3414 for (n = 0; n < face->num_charmaps; n++) 3415 { 3416 charmap = face->charmaps[n]; 3417 if (charmap->encoding == FT_ENCODING_MS_SYMBOL) 3418 { 3419 found = charmap; 3420 break; 3421 } 3422 } 3423 } 3424 if (!found) 3425 { 3426 DPRINT1("WARNING: Could not find desired charmap!\n"); 3427 } 3428 else 3429 { 3430 DPRINT("Found charmap encoding: %i\n", found->encoding); 3431 error = FT_Set_Charmap(face, found); 3432 if (error) 3433 { 3434 DPRINT1("WARNING: Could not set the charmap!\n"); 3435 } 3436 } 3437 } 3438 3439 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 3440 3441 error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight); 3442 3443 if (bDoLock) 3444 IntUnLockFreeType(); 3445 3446 if (error) 3447 { 3448 DPRINT1("Error in setting pixel sizes: %d\n", error); 3449 return FALSE; 3450 } 3451 3452 return TRUE; 3453 } 3454 3455 static inline FT_UInt FASTCALL 3456 get_glyph_index_symbol(FT_Face ft_face, UINT glyph) 3457 { 3458 FT_UInt ret; 3459 3460 if (glyph < 0x100) glyph += 0xf000; 3461 /* there are a number of old pre-Unicode "broken" TTFs, which 3462 do have symbols at U+00XX instead of U+f0XX */ 3463 if (!(ret = FT_Get_Char_Index(ft_face, glyph))) 3464 ret = FT_Get_Char_Index(ft_face, glyph - 0xf000); 3465 3466 return ret; 3467 } 3468 3469 static inline FT_UInt FASTCALL 3470 get_glyph_index(FT_Face ft_face, UINT glyph) 3471 { 3472 FT_UInt ret; 3473 3474 if (face_has_symbol_charmap(ft_face)) 3475 { 3476 ret = get_glyph_index_symbol(ft_face, glyph); 3477 if (ret != 0) 3478 return ret; 3479 } 3480 3481 return FT_Get_Char_Index(ft_face, glyph); 3482 } 3483 3484 static inline FT_UInt FASTCALL 3485 get_glyph_index_flagged(FT_Face face, FT_ULong code, DWORD indexed_flag, DWORD flags) 3486 { 3487 FT_UInt glyph_index; 3488 if (flags & indexed_flag) 3489 { 3490 glyph_index = code; 3491 } 3492 else 3493 { 3494 glyph_index = get_glyph_index(face, code); 3495 } 3496 return glyph_index; 3497 } 3498 3499 /* 3500 * Based on WineEngGetGlyphOutline 3501 * 3502 */ 3503 ULONG 3504 FASTCALL 3505 ftGdiGetGlyphOutline( 3506 PDC dc, 3507 WCHAR wch, 3508 UINT iFormat, 3509 LPGLYPHMETRICS pgm, 3510 ULONG cjBuf, 3511 PVOID pvBuf, 3512 LPMAT2 pmat2, 3513 BOOL bIgnoreRotation) 3514 { 3515 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)}; 3516 PDC_ATTR pdcattr; 3517 PTEXTOBJ TextObj; 3518 PFONTGDI FontGDI; 3519 HFONT hFont = 0; 3520 GLYPHMETRICS gm; 3521 ULONG Size; 3522 FT_Face ft_face; 3523 FT_UInt glyph_index; 3524 DWORD width, height, pitch, needed = 0; 3525 FT_Bitmap ft_bitmap; 3526 FT_Error error; 3527 INT left, right, top = 0, bottom = 0; 3528 FT_Angle angle = 0; 3529 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; 3530 FLOAT eM11, widthRatio = 1.0; 3531 FT_Matrix transMat = identityMat; 3532 BOOL needsTransform = FALSE; 3533 INT orientation; 3534 LONG aveWidth; 3535 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */ 3536 OUTLINETEXTMETRICW *potm; 3537 XFORM xForm; 3538 LOGFONTW *plf; 3539 3540 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm, 3541 cjBuf, pvBuf, pmat2); 3542 3543 pdcattr = dc->pdcattr; 3544 3545 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice); 3546 eM11 = xForm.eM11; 3547 3548 hFont = pdcattr->hlfntNew; 3549 TextObj = RealizeFontInit(hFont); 3550 3551 if (!TextObj) 3552 { 3553 EngSetLastError(ERROR_INVALID_HANDLE); 3554 return GDI_ERROR; 3555 } 3556 FontGDI = ObjToGDI(TextObj->Font, FONT); 3557 ft_face = FontGDI->SharedFace->Face; 3558 3559 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 3560 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0; 3561 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0; 3562 3563 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 3564 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 3565 if (!potm) 3566 { 3567 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 3568 TEXTOBJ_UnlockText(TextObj); 3569 return GDI_ERROR; 3570 } 3571 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm); 3572 if (!Size) 3573 { 3574 /* FIXME: last error? */ 3575 ExFreePoolWithTag(potm, GDITAG_TEXT); 3576 TEXTOBJ_UnlockText(TextObj); 3577 return GDI_ERROR; 3578 } 3579 3580 IntLockFreeType(); 3581 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE); 3582 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc)); 3583 3584 TEXTOBJ_UnlockText(TextObj); 3585 3586 glyph_index = get_glyph_index_flagged(ft_face, wch, GGO_GLYPH_INDEX, iFormat); 3587 iFormat &= ~GGO_GLYPH_INDEX; 3588 3589 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2) 3590 load_flags |= FT_LOAD_NO_BITMAP; 3591 3592 if (iFormat & GGO_UNHINTED) 3593 { 3594 load_flags |= FT_LOAD_NO_HINTING; 3595 iFormat &= ~GGO_UNHINTED; 3596 } 3597 3598 error = FT_Load_Glyph(ft_face, glyph_index, load_flags); 3599 if (error) 3600 { 3601 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index); 3602 IntUnLockFreeType(); 3603 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); 3604 return GDI_ERROR; 3605 } 3606 IntUnLockFreeType(); 3607 3608 if (aveWidth && potm) 3609 { 3610 widthRatio = (FLOAT)aveWidth * eM11 / 3611 (FLOAT) potm->otmTextMetrics.tmAveCharWidth; 3612 } 3613 3614 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64; 3615 right = (INT)((ft_face->glyph->metrics.horiBearingX + 3616 ft_face->glyph->metrics.width) * widthRatio + 63) & -64; 3617 3618 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6; 3619 lsb = left >> 6; 3620 bbx = (right - left) >> 6; 3621 3622 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx); 3623 3624 IntLockFreeType(); 3625 3626 /* Width scaling transform */ 3627 if (widthRatio != 1.0) 3628 { 3629 FT_Matrix scaleMat; 3630 scaleMat.xx = FT_FixedFromFloat(widthRatio); 3631 scaleMat.xy = 0; 3632 scaleMat.yx = 0; 3633 scaleMat.yy = FT_FixedFromFloat(1.0); 3634 3635 FT_Matrix_Multiply(&scaleMat, &transMat); 3636 needsTransform = TRUE; 3637 } 3638 3639 /* World transform */ 3640 { 3641 FT_Matrix ftmatrix; 3642 FLOATOBJ efTemp; 3643 PMATRIX pmx = DC_pmxWorldToDevice(dc); 3644 3645 /* Create a freetype matrix, by converting to 16.16 fixpoint format */ 3646 efTemp = pmx->efM11; 3647 FLOATOBJ_MulLong(&efTemp, 0x00010000); 3648 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp); 3649 3650 efTemp = pmx->efM12; 3651 FLOATOBJ_MulLong(&efTemp, 0x00010000); 3652 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp); 3653 3654 efTemp = pmx->efM21; 3655 FLOATOBJ_MulLong(&efTemp, 0x00010000); 3656 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp); 3657 3658 efTemp = pmx->efM22; 3659 FLOATOBJ_MulLong(&efTemp, 0x00010000); 3660 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp); 3661 3662 if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0) 3663 { 3664 FT_Matrix_Multiply(&ftmatrix, &transMat); 3665 needsTransform = TRUE; 3666 } 3667 } 3668 3669 /* Rotation transform */ 3670 if (orientation) 3671 { 3672 FT_Matrix rotationMat; 3673 FT_Vector vecAngle; 3674 DPRINT("Rotation Trans!\n"); 3675 angle = FT_FixedFromFloat((float)orientation / 10.0); 3676 FT_Vector_Unit(&vecAngle, angle); 3677 rotationMat.xx = vecAngle.x; 3678 rotationMat.xy = -vecAngle.y; 3679 rotationMat.yx = -rotationMat.xy; 3680 rotationMat.yy = rotationMat.xx; 3681 FT_Matrix_Multiply(&rotationMat, &transMat); 3682 needsTransform = TRUE; 3683 } 3684 3685 /* Extra transformation specified by caller */ 3686 if (pmat2) 3687 { 3688 FT_Matrix extraMat; 3689 DPRINT("MAT2 Matrix Trans!\n"); 3690 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11); 3691 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21); 3692 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12); 3693 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22); 3694 FT_Matrix_Multiply(&extraMat, &transMat); 3695 needsTransform = TRUE; 3696 } 3697 3698 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */ 3699 3700 if (!needsTransform) 3701 { 3702 DPRINT("No Need to be Transformed!\n"); 3703 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64; 3704 bottom = (ft_face->glyph->metrics.horiBearingY - 3705 ft_face->glyph->metrics.height) & -64; 3706 gm.gmCellIncX = adv; 3707 gm.gmCellIncY = 0; 3708 } 3709 else 3710 { 3711 INT xc, yc; 3712 FT_Vector vec; 3713 for (xc = 0; xc < 2; xc++) 3714 { 3715 for (yc = 0; yc < 2; yc++) 3716 { 3717 vec.x = (ft_face->glyph->metrics.horiBearingX + 3718 xc * ft_face->glyph->metrics.width); 3719 vec.y = ft_face->glyph->metrics.horiBearingY - 3720 yc * ft_face->glyph->metrics.height; 3721 DPRINT("Vec %ld,%ld\n", vec.x, vec.y); 3722 FT_Vector_Transform(&vec, &transMat); 3723 if (xc == 0 && yc == 0) 3724 { 3725 left = right = vec.x; 3726 top = bottom = vec.y; 3727 } 3728 else 3729 { 3730 if (vec.x < left) left = vec.x; 3731 else if (vec.x > right) right = vec.x; 3732 if (vec.y < bottom) bottom = vec.y; 3733 else if (vec.y > top) top = vec.y; 3734 } 3735 } 3736 } 3737 left = left & -64; 3738 right = (right + 63) & -64; 3739 bottom = bottom & -64; 3740 top = (top + 63) & -64; 3741 3742 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom); 3743 vec.x = ft_face->glyph->metrics.horiAdvance; 3744 vec.y = 0; 3745 FT_Vector_Transform(&vec, &transMat); 3746 gm.gmCellIncX = (vec.x+63) >> 6; 3747 gm.gmCellIncY = -((vec.y+63) >> 6); 3748 } 3749 gm.gmBlackBoxX = (right - left) >> 6; 3750 gm.gmBlackBoxY = (top - bottom) >> 6; 3751 gm.gmptGlyphOrigin.x = left >> 6; 3752 gm.gmptGlyphOrigin.y = top >> 6; 3753 3754 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n", 3755 gm.gmCellIncX, gm.gmCellIncY, 3756 gm.gmBlackBoxX, gm.gmBlackBoxY, 3757 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y); 3758 3759 IntUnLockFreeType(); 3760 3761 3762 if (iFormat == GGO_METRICS) 3763 { 3764 DPRINT("GGO_METRICS Exit!\n"); 3765 *pgm = gm; 3766 return 1; /* FIXME */ 3767 } 3768 3769 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP) 3770 { 3771 DPRINT1("Loaded a bitmap\n"); 3772 return GDI_ERROR; 3773 } 3774 3775 switch (iFormat) 3776 { 3777 case GGO_BITMAP: 3778 width = gm.gmBlackBoxX; 3779 height = gm.gmBlackBoxY; 3780 pitch = ((width + 31) >> 5) << 2; 3781 needed = pitch * height; 3782 3783 if (!pvBuf || !cjBuf) break; 3784 if (!needed) return GDI_ERROR; /* empty glyph */ 3785 if (needed > cjBuf) 3786 return GDI_ERROR; 3787 3788 switch (ft_face->glyph->format) 3789 { 3790 case ft_glyph_format_bitmap: 3791 { 3792 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf; 3793 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 ); 3794 INT h = min( height, ft_face->glyph->bitmap.rows ); 3795 while (h--) 3796 { 3797 RtlCopyMemory(dst, src, w); 3798 src += ft_face->glyph->bitmap.pitch; 3799 dst += pitch; 3800 } 3801 break; 3802 } 3803 3804 case ft_glyph_format_outline: 3805 ft_bitmap.width = width; 3806 ft_bitmap.rows = height; 3807 ft_bitmap.pitch = pitch; 3808 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO; 3809 ft_bitmap.buffer = pvBuf; 3810 3811 IntLockFreeType(); 3812 if (needsTransform) 3813 { 3814 FT_Outline_Transform(&ft_face->glyph->outline, &transMat); 3815 } 3816 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); 3817 /* Note: FreeType will only set 'black' bits for us. */ 3818 RtlZeroMemory(pvBuf, needed); 3819 FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap); 3820 IntUnLockFreeType(); 3821 break; 3822 3823 default: 3824 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format); 3825 return GDI_ERROR; 3826 } 3827 break; 3828 3829 case GGO_GRAY2_BITMAP: 3830 case GGO_GRAY4_BITMAP: 3831 case GGO_GRAY8_BITMAP: 3832 { 3833 unsigned int mult, row, col; 3834 BYTE *start, *ptr; 3835 3836 width = gm.gmBlackBoxX; 3837 height = gm.gmBlackBoxY; 3838 pitch = (width + 3) / 4 * 4; 3839 needed = pitch * height; 3840 3841 if (!pvBuf || !cjBuf) break; 3842 if (!needed) return GDI_ERROR; /* empty glyph */ 3843 if (needed > cjBuf) 3844 return GDI_ERROR; 3845 3846 switch (ft_face->glyph->format) 3847 { 3848 case ft_glyph_format_bitmap: 3849 { 3850 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf; 3851 INT h = min( height, ft_face->glyph->bitmap.rows ); 3852 INT x; 3853 while (h--) 3854 { 3855 for (x = 0; (UINT)x < pitch; x++) 3856 { 3857 if (x < ft_face->glyph->bitmap.width) 3858 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0; 3859 else 3860 dst[x] = 0; 3861 } 3862 src += ft_face->glyph->bitmap.pitch; 3863 dst += pitch; 3864 } 3865 break; 3866 } 3867 case ft_glyph_format_outline: 3868 { 3869 ft_bitmap.width = width; 3870 ft_bitmap.rows = height; 3871 ft_bitmap.pitch = pitch; 3872 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; 3873 ft_bitmap.buffer = pvBuf; 3874 3875 IntLockFreeType(); 3876 if (needsTransform) 3877 { 3878 FT_Outline_Transform(&ft_face->glyph->outline, &transMat); 3879 } 3880 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); 3881 RtlZeroMemory(ft_bitmap.buffer, cjBuf); 3882 FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap); 3883 IntUnLockFreeType(); 3884 3885 if (iFormat == GGO_GRAY2_BITMAP) 3886 mult = 4; 3887 else if (iFormat == GGO_GRAY4_BITMAP) 3888 mult = 16; 3889 else if (iFormat == GGO_GRAY8_BITMAP) 3890 mult = 64; 3891 else 3892 { 3893 return GDI_ERROR; 3894 } 3895 3896 start = pvBuf; 3897 for (row = 0; row < height; row++) 3898 { 3899 ptr = start; 3900 for (col = 0; col < width; col++, ptr++) 3901 { 3902 *ptr = (((int)*ptr) * mult + 128) / 256; 3903 } 3904 start += pitch; 3905 } 3906 3907 break; 3908 } 3909 default: 3910 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format); 3911 return GDI_ERROR; 3912 } 3913 } 3914 3915 case GGO_NATIVE: 3916 { 3917 FT_Outline *outline = &ft_face->glyph->outline; 3918 3919 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */ 3920 3921 IntLockFreeType(); 3922 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat); 3923 3924 needed = get_native_glyph_outline(outline, cjBuf, NULL); 3925 3926 if (!pvBuf || !cjBuf) 3927 { 3928 IntUnLockFreeType(); 3929 break; 3930 } 3931 if (needed > cjBuf) 3932 { 3933 IntUnLockFreeType(); 3934 return GDI_ERROR; 3935 } 3936 get_native_glyph_outline(outline, cjBuf, pvBuf); 3937 IntUnLockFreeType(); 3938 break; 3939 } 3940 case GGO_BEZIER: 3941 { 3942 FT_Outline *outline = &ft_face->glyph->outline; 3943 if (cjBuf == 0) pvBuf = NULL; 3944 3945 if (needsTransform && pvBuf) 3946 { 3947 IntLockFreeType(); 3948 FT_Outline_Transform(outline, &transMat); 3949 IntUnLockFreeType(); 3950 } 3951 needed = get_bezier_glyph_outline(outline, cjBuf, NULL); 3952 3953 if (!pvBuf || !cjBuf) 3954 break; 3955 if (needed > cjBuf) 3956 return GDI_ERROR; 3957 3958 get_bezier_glyph_outline(outline, cjBuf, pvBuf); 3959 break; 3960 } 3961 3962 default: 3963 DPRINT1("Unsupported format %u\n", iFormat); 3964 return GDI_ERROR; 3965 } 3966 3967 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed); 3968 *pgm = gm; 3969 return needed; 3970 } 3971 3972 BOOL 3973 FASTCALL 3974 TextIntGetTextExtentPoint(PDC dc, 3975 PTEXTOBJ TextObj, 3976 LPCWSTR String, 3977 INT Count, 3978 ULONG MaxExtent, 3979 LPINT Fit, 3980 LPINT Dx, 3981 LPSIZE Size, 3982 FLONG fl) 3983 { 3984 PFONTGDI FontGDI; 3985 FT_Face face; 3986 FT_GlyphSlot glyph; 3987 FT_BitmapGlyph realglyph; 3988 INT error, glyph_index, i, previous; 3989 ULONGLONG TotalWidth = 0; 3990 BOOL use_kerning; 3991 FT_Render_Mode RenderMode; 3992 BOOLEAN Render; 3993 PMATRIX pmxWorldToDevice; 3994 LOGFONTW *plf; 3995 BOOL EmuBold, EmuItalic; 3996 LONG ascender, descender; 3997 3998 FontGDI = ObjToGDI(TextObj->Font, FONT); 3999 4000 face = FontGDI->SharedFace->Face; 4001 if (NULL != Fit) 4002 { 4003 *Fit = 0; 4004 } 4005 4006 IntLockFreeType(); 4007 4008 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE); 4009 4010 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 4011 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL); 4012 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic); 4013 4014 Render = IntIsFontRenderingEnabled(); 4015 if (Render) 4016 RenderMode = IntGetFontRenderMode(plf); 4017 else 4018 RenderMode = FT_RENDER_MODE_MONO; 4019 4020 /* Get the DC's world-to-device transformation matrix */ 4021 pmxWorldToDevice = DC_pmxWorldToDevice(dc); 4022 FtSetCoordinateTransform(face, pmxWorldToDevice); 4023 4024 use_kerning = FT_HAS_KERNING(face); 4025 previous = 0; 4026 4027 for (i = 0; i < Count; i++) 4028 { 4029 glyph_index = get_glyph_index_flagged(face, *String, GTEF_INDICES, fl); 4030 4031 if (EmuBold || EmuItalic) 4032 realglyph = NULL; 4033 else 4034 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight, 4035 RenderMode, pmxWorldToDevice); 4036 4037 if (EmuBold || EmuItalic || !realglyph) 4038 { 4039 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 4040 if (error) 4041 { 4042 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index); 4043 break; 4044 } 4045 4046 glyph = face->glyph; 4047 if (EmuBold || EmuItalic) 4048 { 4049 if (EmuBold) 4050 FT_GlyphSlot_Embolden(glyph); 4051 if (EmuItalic) 4052 FT_GlyphSlot_Oblique(glyph); 4053 realglyph = ftGdiGlyphSet(face, glyph, RenderMode); 4054 } 4055 else 4056 { 4057 realglyph = ftGdiGlyphCacheSet(face, 4058 glyph_index, 4059 plf->lfHeight, 4060 pmxWorldToDevice, 4061 glyph, 4062 RenderMode); 4063 } 4064 4065 if (!realglyph) 4066 { 4067 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index); 4068 break; 4069 } 4070 } 4071 4072 /* Retrieve kerning distance */ 4073 if (use_kerning && previous && glyph_index) 4074 { 4075 FT_Vector delta; 4076 FT_Get_Kerning(face, previous, glyph_index, 0, &delta); 4077 TotalWidth += delta.x; 4078 } 4079 4080 TotalWidth += realglyph->root.advance.x >> 10; 4081 4082 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit) 4083 { 4084 *Fit = i + 1; 4085 } 4086 if (NULL != Dx) 4087 { 4088 Dx[i] = (TotalWidth + 32) >> 6; 4089 } 4090 4091 if (EmuBold || EmuItalic) 4092 { 4093 FT_Done_Glyph((FT_Glyph)realglyph); 4094 realglyph = NULL; 4095 } 4096 4097 previous = glyph_index; 4098 String++; 4099 } 4100 ASSERT(FontGDI->Magic == FONTGDI_MAGIC); 4101 ascender = FontGDI->tmAscent; /* Units above baseline */ 4102 descender = FontGDI->tmDescent; /* Units below baseline */ 4103 IntUnLockFreeType(); 4104 4105 Size->cx = (TotalWidth + 32) >> 6; 4106 Size->cy = ascender + descender; 4107 4108 return TRUE; 4109 } 4110 4111 4112 INT 4113 FASTCALL 4114 ftGdiGetTextCharsetInfo( 4115 PDC Dc, 4116 LPFONTSIGNATURE lpSig, 4117 DWORD dwFlags) 4118 { 4119 PDC_ATTR pdcattr; 4120 UINT Ret = DEFAULT_CHARSET; 4121 INT i; 4122 HFONT hFont; 4123 PTEXTOBJ TextObj; 4124 PFONTGDI FontGdi; 4125 FONTSIGNATURE fs; 4126 TT_OS2 *pOS2; 4127 FT_Face Face; 4128 CHARSETINFO csi; 4129 DWORD cp, fs0; 4130 USHORT usACP, usOEM; 4131 4132 pdcattr = Dc->pdcattr; 4133 hFont = pdcattr->hlfntNew; 4134 TextObj = RealizeFontInit(hFont); 4135 4136 if (!TextObj) 4137 { 4138 EngSetLastError(ERROR_INVALID_HANDLE); 4139 return Ret; 4140 } 4141 FontGdi = ObjToGDI(TextObj->Font, FONT); 4142 Face = FontGdi->SharedFace->Face; 4143 TEXTOBJ_UnlockText(TextObj); 4144 4145 IntLockFreeType(); 4146 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); 4147 IntUnLockFreeType(); 4148 memset(&fs, 0, sizeof(FONTSIGNATURE)); 4149 if (NULL != pOS2) 4150 { 4151 fs.fsCsb[0] = pOS2->ulCodePageRange1; 4152 fs.fsCsb[1] = pOS2->ulCodePageRange2; 4153 fs.fsUsb[0] = pOS2->ulUnicodeRange1; 4154 fs.fsUsb[1] = pOS2->ulUnicodeRange2; 4155 fs.fsUsb[2] = pOS2->ulUnicodeRange3; 4156 fs.fsUsb[3] = pOS2->ulUnicodeRange4; 4157 if (pOS2->version == 0) 4158 { 4159 FT_UInt dummy; 4160 4161 if (FT_Get_First_Char( Face, &dummy ) < 0x100) 4162 fs.fsCsb[0] |= FS_LATIN1; 4163 else 4164 fs.fsCsb[0] |= FS_SYMBOL; 4165 } 4166 } 4167 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]); 4168 if (fs.fsCsb[0] == 0) 4169 { /* Let's see if we can find any interesting cmaps */ 4170 for (i = 0; i < Face->num_charmaps; i++) 4171 { 4172 switch (Face->charmaps[i]->encoding) 4173 { 4174 case FT_ENCODING_UNICODE: 4175 case FT_ENCODING_APPLE_ROMAN: 4176 fs.fsCsb[0] |= FS_LATIN1; 4177 break; 4178 case FT_ENCODING_MS_SYMBOL: 4179 fs.fsCsb[0] |= FS_SYMBOL; 4180 break; 4181 default: 4182 break; 4183 } 4184 } 4185 } 4186 if (lpSig) 4187 { 4188 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE)); 4189 } 4190 4191 RtlGetDefaultCodePage(&usACP, &usOEM); 4192 cp = usACP; 4193 4194 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE)) 4195 if (csi.fs.fsCsb[0] & fs.fsCsb[0]) 4196 { 4197 DPRINT("Hit 1\n"); 4198 Ret = csi.ciCharset; 4199 goto Exit; 4200 } 4201 4202 for (i = 0; i < MAXTCIINDEX; i++) 4203 { 4204 fs0 = 1L << i; 4205 if (fs.fsCsb[0] & fs0) 4206 { 4207 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) 4208 { 4209 // *cp = csi.ciACP; 4210 DPRINT("Hit 2\n"); 4211 Ret = csi.ciCharset; 4212 goto Exit; 4213 } 4214 else 4215 DPRINT1("TCI failing on %x\n", fs0); 4216 } 4217 } 4218 Exit: 4219 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP); 4220 return (MAKELONG(csi.ciACP, csi.ciCharset)); 4221 } 4222 4223 4224 DWORD 4225 FASTCALL 4226 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset) 4227 { 4228 DWORD size = 0; 4229 DWORD num_ranges = 0; 4230 FT_Face face = Font->SharedFace->Face; 4231 4232 if (face->charmap->encoding == FT_ENCODING_UNICODE) 4233 { 4234 FT_UInt glyph_code = 0; 4235 FT_ULong char_code, char_code_prev; 4236 4237 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code); 4238 4239 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n", 4240 face->num_glyphs, glyph_code, char_code); 4241 4242 if (!glyph_code) return 0; 4243 4244 if (glyphset) 4245 { 4246 glyphset->ranges[0].wcLow = (USHORT)char_code; 4247 glyphset->ranges[0].cGlyphs = 0; 4248 glyphset->cGlyphsSupported = 0; 4249 } 4250 4251 num_ranges = 1; 4252 while (glyph_code) 4253 { 4254 if (char_code < char_code_prev) 4255 { 4256 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n"); 4257 return 0; 4258 } 4259 if (char_code - char_code_prev > 1) 4260 { 4261 num_ranges++; 4262 if (glyphset) 4263 { 4264 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code; 4265 glyphset->ranges[num_ranges - 1].cGlyphs = 1; 4266 glyphset->cGlyphsSupported++; 4267 } 4268 } 4269 else if (glyphset) 4270 { 4271 glyphset->ranges[num_ranges - 1].cGlyphs++; 4272 glyphset->cGlyphsSupported++; 4273 } 4274 char_code_prev = char_code; 4275 char_code = FT_Get_Next_Char(face, char_code, &glyph_code); 4276 } 4277 } 4278 else 4279 DPRINT1("Encoding %i not supported\n", face->charmap->encoding); 4280 4281 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1); 4282 if (glyphset) 4283 { 4284 glyphset->cbThis = size; 4285 glyphset->cRanges = num_ranges; 4286 glyphset->flAccel = 0; 4287 } 4288 return size; 4289 } 4290 4291 4292 BOOL 4293 FASTCALL 4294 ftGdiGetTextMetricsW( 4295 HDC hDC, 4296 PTMW_INTERNAL ptmwi) 4297 { 4298 PDC dc; 4299 PDC_ATTR pdcattr; 4300 PTEXTOBJ TextObj; 4301 PFONTGDI FontGDI; 4302 FT_Face Face; 4303 TT_OS2 *pOS2; 4304 TT_HoriHeader *pHori; 4305 FT_WinFNT_HeaderRec Win; 4306 ULONG Error; 4307 NTSTATUS Status = STATUS_SUCCESS; 4308 LOGFONTW *plf; 4309 4310 if (!ptmwi) 4311 { 4312 EngSetLastError(STATUS_INVALID_PARAMETER); 4313 return FALSE; 4314 } 4315 4316 if (!(dc = DC_LockDc(hDC))) 4317 { 4318 EngSetLastError(ERROR_INVALID_HANDLE); 4319 return FALSE; 4320 } 4321 pdcattr = dc->pdcattr; 4322 TextObj = RealizeFontInit(pdcattr->hlfntNew); 4323 if (NULL != TextObj) 4324 { 4325 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 4326 FontGDI = ObjToGDI(TextObj->Font, FONT); 4327 4328 Face = FontGDI->SharedFace->Face; 4329 4330 IntLockFreeType(); 4331 Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight); 4332 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc)); 4333 IntUnLockFreeType(); 4334 4335 if (0 != Error) 4336 { 4337 DPRINT1("Error in setting pixel sizes: %u\n", Error); 4338 Status = STATUS_UNSUCCESSFUL; 4339 } 4340 else 4341 { 4342 FT_Face Face = FontGDI->SharedFace->Face; 4343 Status = STATUS_SUCCESS; 4344 4345 IntLockFreeType(); 4346 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); 4347 if (NULL == pOS2) 4348 { 4349 DPRINT1("Can't find OS/2 table - not TT font?\n"); 4350 Status = STATUS_INTERNAL_ERROR; 4351 } 4352 4353 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea); 4354 if (NULL == pHori) 4355 { 4356 DPRINT1("Can't find HHEA table - not TT font?\n"); 4357 Status = STATUS_INTERNAL_ERROR; 4358 } 4359 4360 Error = FT_Get_WinFNT_Header(Face, &Win); 4361 4362 if (NT_SUCCESS(Status)) 4363 { 4364 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0); 4365 4366 /* FIXME: Fill Diff member */ 4367 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff)); 4368 } 4369 4370 IntUnLockFreeType(); 4371 } 4372 TEXTOBJ_UnlockText(TextObj); 4373 } 4374 else 4375 { 4376 Status = STATUS_INVALID_HANDLE; 4377 } 4378 DC_UnlockDc(dc); 4379 4380 if (!NT_SUCCESS(Status)) 4381 { 4382 SetLastNtError(Status); 4383 return FALSE; 4384 } 4385 return TRUE; 4386 } 4387 4388 DWORD 4389 FASTCALL 4390 ftGdiGetFontData( 4391 PFONTGDI FontGdi, 4392 DWORD Table, 4393 DWORD Offset, 4394 PVOID Buffer, 4395 DWORD Size) 4396 { 4397 DWORD Result = GDI_ERROR; 4398 FT_Face Face = FontGdi->SharedFace->Face; 4399 4400 IntLockFreeType(); 4401 4402 if (FT_IS_SFNT(Face)) 4403 { 4404 if (Table) 4405 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) | 4406 (Table << 8 & 0xFF0000); 4407 4408 if (!Buffer) Size = 0; 4409 4410 if (Buffer && Size) 4411 { 4412 FT_Error Error; 4413 FT_ULong Needed = 0; 4414 4415 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed); 4416 4417 if ( !Error && Needed < Size) Size = Needed; 4418 } 4419 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size)) 4420 Result = Size; 4421 } 4422 4423 IntUnLockFreeType(); 4424 4425 return Result; 4426 } 4427 4428 #define GOT_PENALTY(name, value) Penalty += (value) 4429 4430 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx 4431 static UINT 4432 GetFontPenalty(const LOGFONTW * LogFont, 4433 const OUTLINETEXTMETRICW * Otm, 4434 const char * style_name) 4435 { 4436 ULONG Penalty = 0; 4437 BYTE Byte; 4438 LONG Long; 4439 BOOL fNeedScaling = FALSE; 4440 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID); 4441 const TEXTMETRICW * TM = &Otm->otmTextMetrics; 4442 WCHAR* ActualNameW; 4443 4444 ASSERT(Otm); 4445 ASSERT(LogFont); 4446 4447 /* FIXME: IntSizeSynth Penalty 20 */ 4448 /* FIXME: SmallPenalty Penalty 1 */ 4449 /* FIXME: FaceNameSubst Penalty 500 */ 4450 4451 Byte = LogFont->lfCharSet; 4452 if (Byte == DEFAULT_CHARSET) 4453 { 4454 if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0) 4455 { 4456 if (Byte == ANSI_CHARSET) 4457 { 4458 DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n"); 4459 } 4460 /* We assume SYMBOL_CHARSET for "Marlett" font */ 4461 Byte = SYMBOL_CHARSET; 4462 } 4463 } 4464 4465 if (Byte != TM->tmCharSet) 4466 { 4467 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET) 4468 { 4469 /* CharSet Penalty 65000 */ 4470 /* Requested charset does not match the candidate's. */ 4471 GOT_PENALTY("CharSet", 65000); 4472 } 4473 else 4474 { 4475 if (UserCharSet != TM->tmCharSet) 4476 { 4477 /* UNDOCUMENTED: Not user language */ 4478 GOT_PENALTY("UNDOCUMENTED:NotUserLanguage", 100); 4479 4480 if (ANSI_CHARSET != TM->tmCharSet) 4481 { 4482 /* UNDOCUMENTED: Not ANSI charset */ 4483 GOT_PENALTY("UNDOCUMENTED:NotAnsiCharSet", 100); 4484 } 4485 } 4486 } 4487 } 4488 4489 Byte = LogFont->lfOutPrecision; 4490 switch (Byte) 4491 { 4492 case OUT_DEFAULT_PRECIS: 4493 /* nothing to do */ 4494 break; 4495 case OUT_DEVICE_PRECIS: 4496 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) || 4497 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))) 4498 { 4499 /* OutputPrecision Penalty 19000 */ 4500 /* Requested OUT_STROKE_PRECIS, but the device can't do it 4501 or the candidate is not a vector font. */ 4502 GOT_PENALTY("OutputPrecision", 19000); 4503 } 4504 break; 4505 default: 4506 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)) 4507 { 4508 /* OutputPrecision Penalty 19000 */ 4509 /* Or OUT_STROKE_PRECIS not requested, and the candidate 4510 is a vector font that requires GDI support. */ 4511 GOT_PENALTY("OutputPrecision", 19000); 4512 } 4513 break; 4514 } 4515 4516 Byte = (LogFont->lfPitchAndFamily & 0x0F); 4517 if (Byte == DEFAULT_PITCH) 4518 Byte = VARIABLE_PITCH; 4519 if (Byte == FIXED_PITCH) 4520 { 4521 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH) 4522 { 4523 /* FixedPitch Penalty 15000 */ 4524 /* Requested a fixed pitch font, but the candidate is a 4525 variable pitch font. */ 4526 GOT_PENALTY("FixedPitch", 15000); 4527 } 4528 } 4529 if (Byte == VARIABLE_PITCH) 4530 { 4531 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) 4532 { 4533 /* PitchVariable Penalty 350 */ 4534 /* Requested a variable pitch font, but the candidate is not a 4535 variable pitch font. */ 4536 GOT_PENALTY("PitchVariable", 350); 4537 } 4538 } 4539 4540 Byte = (LogFont->lfPitchAndFamily & 0x0F); 4541 if (Byte == DEFAULT_PITCH) 4542 { 4543 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) 4544 { 4545 /* DefaultPitchFixed Penalty 1 */ 4546 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */ 4547 GOT_PENALTY("DefaultPitchFixed", 1); 4548 } 4549 } 4550 4551 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName); 4552 4553 if (LogFont->lfFaceName[0]) 4554 { 4555 BOOL Found = FALSE; 4556 4557 /* localized family name */ 4558 if (!Found) 4559 { 4560 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0); 4561 } 4562 /* localized full name */ 4563 if (!Found) 4564 { 4565 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName); 4566 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0); 4567 } 4568 if (!Found) 4569 { 4570 /* FaceName Penalty 10000 */ 4571 /* Requested a face name, but the candidate's face name 4572 does not match. */ 4573 GOT_PENALTY("FaceName", 10000); 4574 } 4575 } 4576 4577 Byte = (LogFont->lfPitchAndFamily & 0xF0); 4578 if (Byte != FF_DONTCARE) 4579 { 4580 if (Byte != (TM->tmPitchAndFamily & 0xF0)) 4581 { 4582 /* Family Penalty 9000 */ 4583 /* Requested a family, but the candidate's family is different. */ 4584 GOT_PENALTY("Family", 9000); 4585 } 4586 } 4587 4588 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE) 4589 { 4590 /* FamilyUnknown Penalty 8000 */ 4591 /* Requested a family, but the candidate has no family. */ 4592 GOT_PENALTY("FamilyUnknown", 8000); 4593 } 4594 4595 /* Is the candidate a non-vector font? */ 4596 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) 4597 { 4598 /* Is lfHeight specified? */ 4599 if (LogFont->lfHeight != 0) 4600 { 4601 if (labs(LogFont->lfHeight) < TM->tmHeight) 4602 { 4603 /* HeightBigger Penalty 600 */ 4604 /* The candidate is a nonvector font and is bigger than the 4605 requested height. */ 4606 GOT_PENALTY("HeightBigger", 600); 4607 /* HeightBiggerDifference Penalty 150 */ 4608 /* The candidate is a raster font and is larger than the 4609 requested height. Penalty * height difference */ 4610 GOT_PENALTY("HeightBiggerDifference", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight))); 4611 4612 fNeedScaling = TRUE; 4613 } 4614 if (TM->tmHeight < labs(LogFont->lfHeight)) 4615 { 4616 /* HeightSmaller Penalty 150 */ 4617 /* The candidate is a raster font and is smaller than the 4618 requested height. Penalty * height difference */ 4619 GOT_PENALTY("HeightSmaller", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight))); 4620 4621 fNeedScaling = TRUE; 4622 } 4623 } 4624 } 4625 4626 switch (LogFont->lfPitchAndFamily & 0xF0) 4627 { 4628 case FF_ROMAN: case FF_MODERN: case FF_SWISS: 4629 switch (TM->tmPitchAndFamily & 0xF0) 4630 { 4631 case FF_DECORATIVE: case FF_SCRIPT: 4632 /* FamilyUnlikely Penalty 50 */ 4633 /* Requested a roman/modern/swiss family, but the 4634 candidate is decorative/script. */ 4635 GOT_PENALTY("FamilyUnlikely", 50); 4636 break; 4637 default: 4638 break; 4639 } 4640 break; 4641 case FF_DECORATIVE: case FF_SCRIPT: 4642 switch (TM->tmPitchAndFamily & 0xF0) 4643 { 4644 case FF_ROMAN: case FF_MODERN: case FF_SWISS: 4645 /* FamilyUnlikely Penalty 50 */ 4646 /* Or requested decorative/script, and the candidate is 4647 roman/modern/swiss. */ 4648 GOT_PENALTY("FamilyUnlikely", 50); 4649 break; 4650 default: 4651 break; 4652 } 4653 default: 4654 break; 4655 } 4656 4657 if (LogFont->lfWidth != 0) 4658 { 4659 if (LogFont->lfWidth != TM->tmAveCharWidth) 4660 { 4661 /* Width Penalty 50 */ 4662 /* Requested a nonzero width, but the candidate's width 4663 doesn't match. Penalty * width difference */ 4664 GOT_PENALTY("Width", 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth)); 4665 4666 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) 4667 fNeedScaling = TRUE; 4668 } 4669 } 4670 4671 if (fNeedScaling) 4672 { 4673 /* SizeSynth Penalty 50 */ 4674 /* The candidate is a raster font that needs scaling by GDI. */ 4675 GOT_PENALTY("SizeSynth", 50); 4676 } 4677 4678 if (!!LogFont->lfItalic != !!TM->tmItalic) 4679 { 4680 if (!LogFont->lfItalic && ItalicFromStyle(style_name)) 4681 { 4682 /* Italic Penalty 4 */ 4683 /* Requested font and candidate font do not agree on italic status, 4684 and the desired result cannot be simulated. */ 4685 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */ 4686 GOT_PENALTY("Italic", 40); 4687 } 4688 else if (LogFont->lfItalic && !ItalicFromStyle(style_name)) 4689 { 4690 /* ItalicSim Penalty 1 */ 4691 /* Requested italic font but the candidate is not italic, 4692 although italics can be simulated. */ 4693 GOT_PENALTY("ItalicSim", 1); 4694 } 4695 } 4696 4697 if (LogFont->lfOutPrecision == OUT_TT_PRECIS) 4698 { 4699 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE)) 4700 { 4701 /* NotTrueType Penalty 4 */ 4702 /* Requested OUT_TT_PRECIS, but the candidate is not a 4703 TrueType font. */ 4704 GOT_PENALTY("NotTrueType", 4); 4705 } 4706 } 4707 4708 Long = LogFont->lfWeight; 4709 if (LogFont->lfWeight == FW_DONTCARE) 4710 Long = FW_NORMAL; 4711 if (Long != TM->tmWeight) 4712 { 4713 /* Weight Penalty 3 */ 4714 /* The candidate's weight does not match the requested weight. 4715 Penalty * (weight difference/10) */ 4716 GOT_PENALTY("Weight", 3 * (labs(Long - TM->tmWeight) / 10)); 4717 } 4718 4719 if (!LogFont->lfUnderline && TM->tmUnderlined) 4720 { 4721 /* Underline Penalty 3 */ 4722 /* Requested font has no underline, but the candidate is 4723 underlined. */ 4724 GOT_PENALTY("Underline", 3); 4725 } 4726 4727 if (!LogFont->lfStrikeOut && TM->tmStruckOut) 4728 { 4729 /* StrikeOut Penalty 3 */ 4730 /* Requested font has no strike-out, but the candidate is 4731 struck out. */ 4732 GOT_PENALTY("StrikeOut", 3); 4733 } 4734 4735 /* Is the candidate a non-vector font? */ 4736 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) 4737 { 4738 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight) 4739 { 4740 /* VectorHeightSmaller Penalty 2 */ 4741 /* Candidate is a vector font that is smaller than the 4742 requested height. Penalty * height difference */ 4743 GOT_PENALTY("VectorHeightSmaller", 2 * labs(TM->tmHeight - LogFont->lfHeight)); 4744 } 4745 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight) 4746 { 4747 /* VectorHeightBigger Penalty 1 */ 4748 /* Candidate is a vector font that is bigger than the 4749 requested height. Penalty * height difference */ 4750 GOT_PENALTY("VectorHeightBigger", 1 * labs(TM->tmHeight - LogFont->lfHeight)); 4751 } 4752 } 4753 4754 if (!(TM->tmPitchAndFamily & TMPF_DEVICE)) 4755 { 4756 /* DeviceFavor Penalty 2 */ 4757 /* Extra penalty for all nondevice fonts. */ 4758 GOT_PENALTY("DeviceFavor", 2); 4759 } 4760 4761 if (TM->tmAveCharWidth >= 5 && TM->tmHeight >= 5) 4762 { 4763 if (TM->tmAveCharWidth / TM->tmHeight >= 3) 4764 { 4765 /* Aspect Penalty 30 */ 4766 /* The aspect rate is >= 3. It seems like a bad font. */ 4767 GOT_PENALTY("Aspect", ((TM->tmAveCharWidth / TM->tmHeight) - 2) * 30); 4768 } 4769 else if (TM->tmHeight / TM->tmAveCharWidth >= 3) 4770 { 4771 /* Aspect Penalty 30 */ 4772 /* The aspect rate is >= 3. It seems like a bad font. */ 4773 GOT_PENALTY("Aspect", ((TM->tmHeight / TM->tmAveCharWidth) - 2) * 30); 4774 } 4775 } 4776 4777 if (Penalty < 200) 4778 { 4779 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, " 4780 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, " 4781 "tmCharSet:%d, tmWeight:%ld\n", 4782 Penalty, LogFont->lfFaceName, ActualNameW, 4783 LogFont->lfCharSet, LogFont->lfWeight, 4784 TM->tmCharSet, TM->tmWeight); 4785 } 4786 4787 return Penalty; /* success */ 4788 } 4789 4790 #undef GOT_PENALTY 4791 4792 static __inline VOID 4793 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, 4794 const LOGFONTW *LogFont, 4795 const PLIST_ENTRY Head) 4796 { 4797 ULONG Penalty; 4798 PLIST_ENTRY Entry; 4799 PFONT_ENTRY CurrentEntry; 4800 FONTGDI *FontGDI; 4801 OUTLINETEXTMETRICW *Otm = NULL; 4802 UINT OtmSize, OldOtmSize = 0; 4803 FT_Face Face; 4804 4805 ASSERT(FontObj); 4806 ASSERT(MatchPenalty); 4807 ASSERT(LogFont); 4808 ASSERT(Head); 4809 4810 /* Start with a pretty big buffer */ 4811 OldOtmSize = 0x200; 4812 Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT); 4813 4814 /* get the FontObj of lowest penalty */ 4815 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) 4816 { 4817 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); 4818 4819 FontGDI = CurrentEntry->Font; 4820 ASSERT(FontGDI); 4821 Face = FontGDI->SharedFace->Face; 4822 4823 /* get text metrics */ 4824 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 4825 if (OtmSize > OldOtmSize) 4826 { 4827 if (Otm) 4828 ExFreePoolWithTag(Otm, GDITAG_TEXT); 4829 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT); 4830 } 4831 4832 /* update FontObj if lowest penalty */ 4833 if (Otm) 4834 { 4835 IntLockFreeType(); 4836 IntRequestFontSize(NULL, FontGDI, LogFont->lfWidth, LogFont->lfHeight); 4837 IntUnLockFreeType(); 4838 4839 OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm); 4840 if (!OtmSize) 4841 continue; 4842 4843 OldOtmSize = OtmSize; 4844 4845 Penalty = GetFontPenalty(LogFont, Otm, Face->style_name); 4846 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty) 4847 { 4848 *FontObj = GDIToObj(FontGDI, FONT); 4849 *MatchPenalty = Penalty; 4850 } 4851 } 4852 } 4853 4854 if (Otm) 4855 ExFreePoolWithTag(Otm, GDITAG_TEXT); 4856 } 4857 4858 static 4859 VOID 4860 FASTCALL 4861 IntFontType(PFONTGDI Font) 4862 { 4863 PS_FontInfoRec psfInfo; 4864 FT_ULong tmp_size = 0; 4865 FT_Face Face = Font->SharedFace->Face; 4866 4867 if (FT_HAS_MULTIPLE_MASTERS(Face)) 4868 Font->FontObj.flFontType |= FO_MULTIPLEMASTER; 4869 if (FT_HAS_VERTICAL(Face)) 4870 Font->FontObj.flFontType |= FO_VERT_FACE; 4871 if (!FT_IS_SCALABLE(Face)) 4872 Font->FontObj.flFontType |= FO_TYPE_RASTER; 4873 if (FT_IS_SFNT(Face)) 4874 { 4875 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE; 4876 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post)) 4877 Font->FontObj.flFontType |= FO_POSTSCRIPT; 4878 } 4879 if (!FT_Get_PS_Font_Info(Face, &psfInfo )) 4880 { 4881 Font->FontObj.flFontType |= FO_POSTSCRIPT; 4882 } 4883 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */ 4884 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size)) 4885 { 4886 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT); 4887 } 4888 } 4889 4890 static BOOL 4891 MatchFontName(PSHARED_FACE SharedFace, LPCWSTR lfFaceName, FT_UShort NameID, FT_UShort LangID) 4892 { 4893 NTSTATUS Status; 4894 UNICODE_STRING Name1, Name2; 4895 4896 if (lfFaceName[0] == UNICODE_NULL) 4897 return FALSE; 4898 4899 RtlInitUnicodeString(&Name1, lfFaceName); 4900 4901 RtlInitUnicodeString(&Name2, NULL); 4902 Status = IntGetFontLocalizedName(&Name2, SharedFace, NameID, LangID); 4903 4904 if (NT_SUCCESS(Status)) 4905 { 4906 if (RtlCompareUnicodeString(&Name1, &Name2, TRUE) == 0) 4907 { 4908 RtlFreeUnicodeString(&Name2); 4909 return TRUE; 4910 } 4911 4912 RtlFreeUnicodeString(&Name2); 4913 } 4914 4915 return FALSE; 4916 } 4917 4918 static BOOL 4919 MatchFontNames(PSHARED_FACE SharedFace, LPCWSTR lfFaceName) 4920 { 4921 if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) || 4922 MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, LANG_ENGLISH)) 4923 { 4924 return TRUE; 4925 } 4926 if (PRIMARYLANGID(gusLanguageID) != LANG_ENGLISH) 4927 { 4928 if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, gusLanguageID) || 4929 MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, gusLanguageID)) 4930 { 4931 return TRUE; 4932 } 4933 } 4934 return FALSE; 4935 } 4936 4937 NTSTATUS 4938 FASTCALL 4939 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj) 4940 { 4941 NTSTATUS Status = STATUS_SUCCESS; 4942 PTEXTOBJ TextObj; 4943 PPROCESSINFO Win32Process; 4944 ULONG MatchPenalty; 4945 LOGFONTW *pLogFont; 4946 LOGFONTW SubstitutedLogFont; 4947 FT_Face Face; 4948 4949 if (!pTextObj) 4950 { 4951 TextObj = TEXTOBJ_LockText(FontHandle); 4952 if (NULL == TextObj) 4953 { 4954 return STATUS_INVALID_HANDLE; 4955 } 4956 4957 if (TextObj->fl & TEXTOBJECT_INIT) 4958 { 4959 TEXTOBJ_UnlockText(TextObj); 4960 return STATUS_SUCCESS; 4961 } 4962 } 4963 else 4964 { 4965 TextObj = pTextObj; 4966 } 4967 4968 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 4969 4970 /* substitute */ 4971 SubstitutedLogFont = *pLogFont; 4972 DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet); 4973 SubstituteFontRecurse(&SubstitutedLogFont); 4974 DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet); 4975 4976 MatchPenalty = 0xFFFFFFFF; 4977 TextObj->Font = NULL; 4978 4979 Win32Process = PsGetCurrentProcessWin32Process(); 4980 4981 /* Search private fonts */ 4982 IntLockProcessPrivateFonts(Win32Process); 4983 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont, 4984 &Win32Process->PrivateFontListHead); 4985 IntUnLockProcessPrivateFonts(Win32Process); 4986 4987 /* Search system fonts */ 4988 IntLockGlobalFonts(); 4989 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont, 4990 &g_FontListHead); 4991 IntUnLockGlobalFonts(); 4992 4993 if (NULL == TextObj->Font) 4994 { 4995 DPRINT1("Request font %S not found, no fonts loaded at all\n", 4996 pLogFont->lfFaceName); 4997 Status = STATUS_NOT_FOUND; 4998 } 4999 else 5000 { 5001 UNICODE_STRING Name; 5002 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT); 5003 PSHARED_FACE SharedFace = FontGdi->SharedFace; 5004 5005 IntLockFreeType(); 5006 IntRequestFontSize(NULL, FontGdi, pLogFont->lfWidth, pLogFont->lfHeight); 5007 IntUnLockFreeType(); 5008 5009 TextObj->TextFace[0] = UNICODE_NULL; 5010 if (MatchFontNames(SharedFace, SubstitutedLogFont.lfFaceName)) 5011 { 5012 RtlStringCchCopyW(TextObj->TextFace, _countof(TextObj->TextFace), pLogFont->lfFaceName); 5013 } 5014 else 5015 { 5016 RtlInitUnicodeString(&Name, NULL); 5017 Status = IntGetFontLocalizedName(&Name, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID); 5018 if (NT_SUCCESS(Status)) 5019 { 5020 /* truncated copy */ 5021 IntUnicodeStringToBuffer(TextObj->TextFace, sizeof(TextObj->TextFace), &Name); 5022 RtlFreeUnicodeString(&Name); 5023 } 5024 } 5025 5026 // Need hdev, when freetype is loaded need to create DEVOBJ for 5027 // Consumer and Producer. 5028 TextObj->Font->iUniq = 1; // Now it can be cached. 5029 IntFontType(FontGdi); 5030 FontGdi->flType = TextObj->Font->flFontType; 5031 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0; 5032 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0; 5033 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0; 5034 if (pLogFont->lfWeight != FW_DONTCARE) 5035 FontGdi->RequestWeight = pLogFont->lfWeight; 5036 else 5037 FontGdi->RequestWeight = FW_NORMAL; 5038 5039 Face = FontGdi->SharedFace->Face; 5040 5041 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name); 5042 5043 if (!FontGdi->OriginalItalic) 5044 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name); 5045 5046 TextObj->fl |= TEXTOBJECT_INIT; 5047 Status = STATUS_SUCCESS; 5048 } 5049 5050 if (!pTextObj) TEXTOBJ_UnlockText(TextObj); 5051 5052 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0); 5053 5054 return Status; 5055 } 5056 5057 5058 static 5059 BOOL 5060 FASTCALL 5061 IntGetFullFileName( 5062 POBJECT_NAME_INFORMATION NameInfo, 5063 ULONG Size, 5064 PUNICODE_STRING FileName) 5065 { 5066 NTSTATUS Status; 5067 OBJECT_ATTRIBUTES ObjectAttributes; 5068 HANDLE hFile; 5069 IO_STATUS_BLOCK IoStatusBlock; 5070 ULONG Desired; 5071 5072 InitializeObjectAttributes(&ObjectAttributes, 5073 FileName, 5074 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 5075 NULL, 5076 NULL); 5077 5078 Status = ZwOpenFile( 5079 &hFile, 5080 0, // FILE_READ_ATTRIBUTES, 5081 &ObjectAttributes, 5082 &IoStatusBlock, 5083 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 5084 0); 5085 5086 if (!NT_SUCCESS(Status)) 5087 { 5088 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status); 5089 return FALSE; 5090 } 5091 5092 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired); 5093 ZwClose(hFile); 5094 if (!NT_SUCCESS(Status)) 5095 { 5096 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status); 5097 return FALSE; 5098 } 5099 5100 return TRUE; 5101 } 5102 5103 static BOOL 5104 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2) 5105 { 5106 const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx; 5107 const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx; 5108 const LOGFONTW *plf1 = &pLog1->elfLogFont; 5109 const LOGFONTW *plf2 = &pLog2->elfLogFont; 5110 5111 if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0) 5112 { 5113 return FALSE; 5114 } 5115 5116 if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0) 5117 { 5118 return FALSE; 5119 } 5120 5121 return TRUE; 5122 } 5123 5124 static VOID 5125 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo) 5126 { 5127 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName); 5128 if (FamInfo->EnumLogFontEx.elfStyle[0] && 5129 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0) 5130 { 5131 wcscat(psz, L" "); 5132 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle); 5133 } 5134 } 5135 5136 BOOL 5137 FASTCALL 5138 IntGdiGetFontResourceInfo( 5139 PUNICODE_STRING FileName, 5140 PVOID pBuffer, 5141 DWORD *pdwBytes, 5142 DWORD dwType) 5143 { 5144 UNICODE_STRING EntryFileName; 5145 POBJECT_NAME_INFORMATION NameInfo1 = NULL, NameInfo2 = NULL; 5146 PLIST_ENTRY ListEntry; 5147 PFONT_ENTRY FontEntry; 5148 ULONG Size, i, Count; 5149 LPBYTE pbBuffer; 5150 BOOL IsEqual; 5151 FONTFAMILYINFO *FamInfo; 5152 const ULONG MaxFamInfo = 64; 5153 const ULONG MAX_FAM_INFO_BYTES = sizeof(FONTFAMILYINFO) * MaxFamInfo; 5154 BOOL bSuccess; 5155 const ULONG NAMEINFO_SIZE = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR); 5156 5157 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType); 5158 5159 do 5160 { 5161 /* Create buffer for full path name */ 5162 NameInfo1 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF); 5163 if (!NameInfo1) 5164 break; 5165 5166 /* Get the full path name */ 5167 if (!IntGetFullFileName(NameInfo1, NAMEINFO_SIZE, FileName)) 5168 break; 5169 5170 /* Create a buffer for the entries' names */ 5171 NameInfo2 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF); 5172 if (!NameInfo2) 5173 break; 5174 5175 FamInfo = ExAllocatePoolWithTag(PagedPool, MAX_FAM_INFO_BYTES, TAG_FINF); 5176 } while (0); 5177 5178 if (!NameInfo1 || !NameInfo2 || !FamInfo) 5179 { 5180 if (NameInfo2) 5181 ExFreePoolWithTag(NameInfo2, TAG_FINF); 5182 5183 if (NameInfo1) 5184 ExFreePoolWithTag(NameInfo1, TAG_FINF); 5185 5186 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 5187 return FALSE; 5188 } 5189 5190 Count = 0; 5191 5192 /* Try to find the pathname in the global font list */ 5193 IntLockGlobalFonts(); 5194 for (ListEntry = g_FontListHead.Flink; ListEntry != &g_FontListHead; 5195 ListEntry = ListEntry->Flink) 5196 { 5197 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry); 5198 if (FontEntry->Font->Filename == NULL) 5199 continue; 5200 5201 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename); 5202 if (!IntGetFullFileName(NameInfo2, NAMEINFO_SIZE, &EntryFileName)) 5203 continue; 5204 5205 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE)) 5206 continue; 5207 5208 IsEqual = FALSE; 5209 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer, 5210 NULL, FontEntry->Font); 5211 for (i = 0; i < Count; ++i) 5212 { 5213 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count])) 5214 { 5215 IsEqual = TRUE; 5216 break; 5217 } 5218 } 5219 if (!IsEqual) 5220 { 5221 /* Found */ 5222 ++Count; 5223 if (Count >= MaxFamInfo) 5224 break; 5225 } 5226 } 5227 IntUnLockGlobalFonts(); 5228 5229 /* Free the buffers */ 5230 ExFreePoolWithTag(NameInfo1, TAG_FINF); 5231 ExFreePoolWithTag(NameInfo2, TAG_FINF); 5232 5233 if (Count == 0 && dwType != 5) 5234 { 5235 /* Font could not be found in system table 5236 dwType == 5 will still handle this */ 5237 ExFreePoolWithTag(FamInfo, TAG_FINF); 5238 return FALSE; 5239 } 5240 5241 bSuccess = FALSE; 5242 switch (dwType) 5243 { 5244 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */ 5245 Size = sizeof(DWORD); 5246 if (*pdwBytes == 0) 5247 { 5248 *pdwBytes = Size; 5249 bSuccess = TRUE; 5250 } 5251 else if (pBuffer) 5252 { 5253 if (*pdwBytes >= Size) 5254 { 5255 *(DWORD*)pBuffer = Count; 5256 } 5257 *pdwBytes = Size; 5258 bSuccess = TRUE; 5259 } 5260 break; 5261 5262 case 1: /* copy the font title */ 5263 /* calculate the required size */ 5264 Size = 0; 5265 for (i = 0; i < Count; ++i) 5266 { 5267 if (i > 0) 5268 Size += 3; /* " & " */ 5269 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName); 5270 if (FamInfo[i].EnumLogFontEx.elfStyle[0] && 5271 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0) 5272 { 5273 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle); 5274 } 5275 } 5276 Size += 2; /* "\0\0" */ 5277 Size *= sizeof(WCHAR); 5278 5279 if (*pdwBytes == 0) 5280 { 5281 *pdwBytes = Size; 5282 bSuccess = TRUE; 5283 } 5284 else if (pBuffer) 5285 { 5286 if (*pdwBytes >= Size) 5287 { 5288 /* store font title to buffer */ 5289 WCHAR *psz = pBuffer; 5290 *psz = 0; 5291 for (i = 0; i < Count; ++i) 5292 { 5293 if (i > 0) 5294 wcscat(psz, L" & "); 5295 IntAddNameFromFamInfo(psz, &FamInfo[i]); 5296 } 5297 psz[wcslen(psz) + 1] = UNICODE_NULL; 5298 *pdwBytes = Size; 5299 bSuccess = TRUE; 5300 } 5301 else 5302 { 5303 *pdwBytes = 1024; /* this is confirmed value */ 5304 } 5305 } 5306 break; 5307 5308 case 2: /* Copy an array of LOGFONTW */ 5309 Size = Count * sizeof(LOGFONTW); 5310 if (*pdwBytes == 0) 5311 { 5312 *pdwBytes = Size; 5313 bSuccess = TRUE; 5314 } 5315 else if (pBuffer) 5316 { 5317 if (*pdwBytes >= Size) 5318 { 5319 pbBuffer = (LPBYTE)pBuffer; 5320 for (i = 0; i < Count; ++i) 5321 { 5322 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0; 5323 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW)); 5324 pbBuffer += sizeof(LOGFONTW); 5325 } 5326 } 5327 *pdwBytes = Size; 5328 bSuccess = TRUE; 5329 } 5330 else 5331 { 5332 *pdwBytes = 1024; /* this is confirmed value */ 5333 } 5334 break; 5335 5336 case 3: 5337 Size = sizeof(DWORD); 5338 if (*pdwBytes == 0) 5339 { 5340 *pdwBytes = Size; 5341 bSuccess = TRUE; 5342 } 5343 else if (pBuffer) 5344 { 5345 if (*pdwBytes >= Size) 5346 { 5347 /* FIXME: What exactly is copied here? */ 5348 *(DWORD*)pBuffer = 1; 5349 } 5350 *pdwBytes = Size; 5351 bSuccess = TRUE; 5352 } 5353 break; 5354 5355 case 4: /* full file path */ 5356 if (FileName->Length >= 4 * sizeof(WCHAR)) 5357 { 5358 /* The beginning of FileName is \??\ */ 5359 LPWSTR pch = FileName->Buffer + 4; 5360 DWORD Length = FileName->Length - 4 * sizeof(WCHAR); 5361 5362 Size = Length + sizeof(WCHAR); 5363 if (*pdwBytes == 0) 5364 { 5365 *pdwBytes = Size; 5366 bSuccess = TRUE; 5367 } 5368 else if (pBuffer) 5369 { 5370 if (*pdwBytes >= Size) 5371 { 5372 RtlCopyMemory(pBuffer, pch, Size); 5373 } 5374 *pdwBytes = Size; 5375 bSuccess = TRUE; 5376 } 5377 } 5378 break; 5379 5380 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */ 5381 Size = sizeof(BOOL); 5382 if (*pdwBytes == 0) 5383 { 5384 *pdwBytes = Size; 5385 bSuccess = TRUE; 5386 } 5387 else if (pBuffer) 5388 { 5389 if (*pdwBytes >= Size) 5390 { 5391 *(BOOL*)pBuffer = Count == 0; 5392 } 5393 *pdwBytes = Size; 5394 bSuccess = TRUE; 5395 } 5396 break; 5397 } 5398 ExFreePoolWithTag(FamInfo, TAG_FINF); 5399 5400 return bSuccess; 5401 } 5402 5403 5404 BOOL 5405 FASTCALL 5406 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info) 5407 { 5408 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face)) 5409 Info->iTechnology = RI_TECH_BITMAP; 5410 else 5411 { 5412 if (FT_IS_SCALABLE(Font->SharedFace->Face)) 5413 Info->iTechnology = RI_TECH_SCALABLE; 5414 else 5415 Info->iTechnology = RI_TECH_FIXED; 5416 } 5417 Info->iUniq = Font->FontObj.iUniq; 5418 Info->dwUnknown = -1; 5419 return TRUE; 5420 } 5421 5422 5423 DWORD 5424 FASTCALL 5425 ftGdiGetKerningPairs( PFONTGDI Font, 5426 DWORD cPairs, 5427 LPKERNINGPAIR pKerningPair) 5428 { 5429 DWORD Count = 0; 5430 INT i = 0; 5431 FT_Face face = Font->SharedFace->Face; 5432 5433 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE) 5434 { 5435 FT_UInt previous_index = 0, glyph_index = 0; 5436 FT_ULong char_code, char_previous; 5437 FT_Vector delta; 5438 5439 char_previous = char_code = FT_Get_First_Char(face, &glyph_index); 5440 5441 IntLockFreeType(); 5442 5443 while (glyph_index) 5444 { 5445 if (previous_index && glyph_index) 5446 { 5447 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta); 5448 5449 if (pKerningPair && cPairs) 5450 { 5451 pKerningPair[i].wFirst = char_previous; 5452 pKerningPair[i].wSecond = char_code; 5453 pKerningPair[i].iKernAmount = delta.x; 5454 i++; 5455 if (i == cPairs) break; 5456 } 5457 Count++; 5458 } 5459 previous_index = glyph_index; 5460 char_previous = char_code; 5461 char_code = FT_Get_Next_Char(face, char_code, &glyph_index); 5462 } 5463 IntUnLockFreeType(); 5464 } 5465 return Count; 5466 } 5467 5468 5469 /////////////////////////////////////////////////////////////////////////// 5470 // 5471 // Functions needing sorting. 5472 // 5473 /////////////////////////////////////////////////////////////////////////// 5474 int APIENTRY 5475 NtGdiGetFontFamilyInfo(HDC Dc, 5476 LPLOGFONTW UnsafeLogFont, 5477 PFONTFAMILYINFO UnsafeInfo, 5478 DWORD Size) 5479 { 5480 NTSTATUS Status; 5481 LOGFONTW LogFont; 5482 PFONTFAMILYINFO Info; 5483 DWORD Count; 5484 PPROCESSINFO Win32Process; 5485 5486 /* Make a safe copy */ 5487 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW)); 5488 if (! NT_SUCCESS(Status)) 5489 { 5490 EngSetLastError(ERROR_INVALID_PARAMETER); 5491 return -1; 5492 } 5493 5494 /* Allocate space for a safe copy */ 5495 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT); 5496 if (NULL == Info) 5497 { 5498 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 5499 return -1; 5500 } 5501 5502 /* Enumerate font families in the global list */ 5503 IntLockGlobalFonts(); 5504 Count = 0; 5505 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &g_FontListHead) ) 5506 { 5507 IntUnLockGlobalFonts(); 5508 ExFreePoolWithTag(Info, GDITAG_TEXT); 5509 return -1; 5510 } 5511 IntUnLockGlobalFonts(); 5512 5513 /* Enumerate font families in the process local list */ 5514 Win32Process = PsGetCurrentProcessWin32Process(); 5515 IntLockProcessPrivateFonts(Win32Process); 5516 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, 5517 &Win32Process->PrivateFontListHead)) 5518 { 5519 IntUnLockProcessPrivateFonts(Win32Process); 5520 ExFreePoolWithTag(Info, GDITAG_TEXT); 5521 return -1; 5522 } 5523 IntUnLockProcessPrivateFonts(Win32Process); 5524 5525 /* Enumerate font families in the registry */ 5526 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size)) 5527 { 5528 ExFreePoolWithTag(Info, GDITAG_TEXT); 5529 return -1; 5530 } 5531 5532 /* Return data to caller */ 5533 if (0 != Count) 5534 { 5535 Status = MmCopyToCaller(UnsafeInfo, Info, 5536 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO)); 5537 if (! NT_SUCCESS(Status)) 5538 { 5539 ExFreePoolWithTag(Info, GDITAG_TEXT); 5540 EngSetLastError(ERROR_INVALID_PARAMETER); 5541 return -1; 5542 } 5543 } 5544 5545 ExFreePoolWithTag(Info, GDITAG_TEXT); 5546 5547 return Count; 5548 } 5549 5550 FORCEINLINE 5551 LONG 5552 ScaleLong(LONG lValue, PFLOATOBJ pef) 5553 { 5554 FLOATOBJ efTemp; 5555 5556 /* Check if we have scaling different from 1 */ 5557 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1)) 5558 { 5559 /* Need to multiply */ 5560 FLOATOBJ_SetLong(&efTemp, lValue); 5561 FLOATOBJ_Mul(&efTemp, pef); 5562 lValue = FLOATOBJ_GetLong(&efTemp); 5563 } 5564 5565 return lValue; 5566 } 5567 5568 BOOL 5569 APIENTRY 5570 GreExtTextOutW( 5571 IN HDC hDC, 5572 IN INT XStart, 5573 IN INT YStart, 5574 IN UINT fuOptions, 5575 IN OPTIONAL PRECTL lprc, 5576 IN LPCWSTR String, 5577 IN INT Count, 5578 IN OPTIONAL LPINT Dx, 5579 IN DWORD dwCodePage) 5580 { 5581 /* 5582 * FIXME: 5583 * Call EngTextOut, which does the real work (calling DrvTextOut where 5584 * appropriate) 5585 */ 5586 5587 DC *dc; 5588 PDC_ATTR pdcattr; 5589 SURFOBJ *SurfObj; 5590 SURFACE *psurf = NULL; 5591 int error, glyph_index, i; 5592 FT_Face face; 5593 FT_GlyphSlot glyph; 5594 FT_BitmapGlyph realglyph; 5595 LONGLONG TextLeft, RealXStart; 5596 ULONG TextTop, previous; 5597 FT_Bool use_kerning; 5598 RECTL DestRect, MaskRect; 5599 POINTL SourcePoint, BrushOrigin; 5600 HBITMAP HSourceGlyph; 5601 SURFOBJ *SourceGlyphSurf; 5602 SIZEL bitSize; 5603 INT yoff; 5604 FONTOBJ *FontObj; 5605 PFONTGDI FontGDI; 5606 PTEXTOBJ TextObj = NULL; 5607 EXLATEOBJ exloRGB2Dst, exloDst2RGB; 5608 FT_Render_Mode RenderMode; 5609 BOOLEAN Render; 5610 POINT Start; 5611 BOOL DoBreak = FALSE; 5612 USHORT DxShift; 5613 PMATRIX pmxWorldToDevice; 5614 LONG fixAscender, fixDescender; 5615 FLOATOBJ Scale; 5616 LOGFONTW *plf; 5617 BOOL EmuBold, EmuItalic; 5618 int thickness; 5619 BOOL bResult; 5620 ULONGLONG TextWidth; 5621 5622 /* Check if String is valid */ 5623 if ((Count > 0xFFFF) || (Count > 0 && String == NULL)) 5624 { 5625 EngSetLastError(ERROR_INVALID_PARAMETER); 5626 return FALSE; 5627 } 5628 5629 /* NOTE: This function locks the screen DC, so it must never be called 5630 with a DC already locked */ 5631 Render = IntIsFontRenderingEnabled(); 5632 5633 // TODO: Write test-cases to exactly match real Windows in different 5634 // bad parameters (e.g. does Windows check the DC or the RECT first?). 5635 dc = DC_LockDc(hDC); 5636 if (!dc) 5637 { 5638 EngSetLastError(ERROR_INVALID_HANDLE); 5639 return FALSE; 5640 } 5641 5642 if (PATH_IsPathOpen(dc->dclevel)) 5643 { 5644 bResult = PATH_ExtTextOut(dc, 5645 XStart, 5646 YStart, 5647 fuOptions, 5648 (const RECTL *)lprc, 5649 String, 5650 Count, 5651 (const INT *)Dx); 5652 DC_UnlockDc(dc); 5653 return bResult; 5654 } 5655 5656 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL); 5657 5658 if (!dc->dclevel.pSurface) 5659 { 5660 /* Memory DC with no surface selected */ 5661 bResult = TRUE; 5662 goto Cleanup; 5663 } 5664 5665 pdcattr = dc->pdcattr; 5666 5667 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED))) 5668 { 5669 IntLPtoDP(dc, (POINT *)lprc, 2); 5670 } 5671 5672 if (pdcattr->lTextAlign & TA_UPDATECP) 5673 { 5674 Start.x = pdcattr->ptlCurrent.x; 5675 Start.y = pdcattr->ptlCurrent.y; 5676 } else { 5677 Start.x = XStart; 5678 Start.y = YStart; 5679 } 5680 5681 IntLPtoDP(dc, &Start, 1); 5682 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6; 5683 YStart = Start.y + dc->ptlDCOrig.y; 5684 5685 SourcePoint.x = 0; 5686 SourcePoint.y = 0; 5687 MaskRect.left = 0; 5688 MaskRect.top = 0; 5689 BrushOrigin.x = 0; 5690 BrushOrigin.y = 0; 5691 5692 if ((fuOptions & ETO_OPAQUE) && lprc) 5693 { 5694 DestRect.left = lprc->left; 5695 DestRect.top = lprc->top; 5696 DestRect.right = lprc->right; 5697 DestRect.bottom = lprc->bottom; 5698 5699 DestRect.left += dc->ptlDCOrig.x; 5700 DestRect.top += dc->ptlDCOrig.y; 5701 DestRect.right += dc->ptlDCOrig.x; 5702 DestRect.bottom += dc->ptlDCOrig.y; 5703 5704 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 5705 { 5706 IntUpdateBoundsRect(dc, &DestRect); 5707 } 5708 5709 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND) 5710 DC_vUpdateBackgroundBrush(dc); 5711 if (dc->dctype == DCTYPE_DIRECT) 5712 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom); 5713 5714 psurf = dc->dclevel.pSurface; 5715 IntEngBitBlt( 5716 &psurf->SurfObj, 5717 NULL, 5718 NULL, 5719 (CLIPOBJ *)&dc->co, 5720 NULL, 5721 &DestRect, 5722 &SourcePoint, 5723 &SourcePoint, 5724 &dc->eboBackground.BrushObject, 5725 &BrushOrigin, 5726 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); 5727 5728 if (dc->dctype == DCTYPE_DIRECT) 5729 MouseSafetyOnDrawEnd(dc->ppdev); 5730 5731 fuOptions &= ~ETO_OPAQUE; 5732 } 5733 else 5734 { 5735 if (pdcattr->jBkMode == OPAQUE) 5736 { 5737 fuOptions |= ETO_OPAQUE; 5738 } 5739 } 5740 5741 TextObj = RealizeFontInit(pdcattr->hlfntNew); 5742 if (TextObj == NULL) 5743 { 5744 bResult = FALSE; 5745 goto Cleanup; 5746 } 5747 5748 FontObj = TextObj->Font; 5749 ASSERT(FontObj); 5750 FontGDI = ObjToGDI(FontObj, FONT); 5751 ASSERT(FontGDI); 5752 5753 IntLockFreeType(); 5754 face = FontGDI->SharedFace->Face; 5755 5756 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 5757 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL); 5758 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic); 5759 5760 if (Render) 5761 RenderMode = IntGetFontRenderMode(plf); 5762 else 5763 RenderMode = FT_RENDER_MODE_MONO; 5764 5765 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE)) 5766 { 5767 IntUnLockFreeType(); 5768 bResult = FALSE; 5769 goto Cleanup; 5770 } 5771 5772 /* NOTE: Don't trust face->size->metrics.ascender and descender values. */ 5773 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED) 5774 { 5775 pmxWorldToDevice = DC_pmxWorldToDevice(dc); 5776 FtSetCoordinateTransform(face, pmxWorldToDevice); 5777 5778 fixAscender = ScaleLong(FontGDI->tmAscent, &pmxWorldToDevice->efM22) << 6; 5779 fixDescender = ScaleLong(FontGDI->tmDescent, &pmxWorldToDevice->efM22) << 6; 5780 } 5781 else 5782 { 5783 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault; 5784 FtSetCoordinateTransform(face, pmxWorldToDevice); 5785 5786 fixAscender = FontGDI->tmAscent << 6; 5787 fixDescender = FontGDI->tmDescent << 6; 5788 } 5789 5790 /* 5791 * Process the vertical alignment and determine the yoff. 5792 */ 5793 #define VALIGN_MASK (TA_TOP | TA_BASELINE | TA_BOTTOM) 5794 if ((pdcattr->lTextAlign & VALIGN_MASK) == TA_BASELINE) 5795 yoff = 0; 5796 else if ((pdcattr->lTextAlign & VALIGN_MASK) == TA_BOTTOM) 5797 yoff = -(fixDescender >> 6); 5798 else /* TA_TOP */ 5799 yoff = fixAscender >> 6; 5800 #undef VALIGN_MASK 5801 5802 /* 5803 * Calculate width of the text. 5804 */ 5805 TextWidth = 0; 5806 DxShift = fuOptions & ETO_PDY ? 1 : 0; 5807 use_kerning = FT_HAS_KERNING(face); 5808 previous = 0; 5809 if ((fuOptions & ETO_OPAQUE) || 5810 (pdcattr->lTextAlign & (TA_CENTER | TA_RIGHT))) 5811 { 5812 TextLeft = RealXStart; 5813 TextTop = YStart; 5814 for (i = 0; i < Count; ++i) 5815 { 5816 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions); 5817 5818 // FIXME: Use FT_LOAD_BITMAP_METRICS_ONLY or cache. 5819 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 5820 if (error) 5821 { 5822 DPRINT1("Failed to load glyph! [index: %d]\n", glyph_index); 5823 IntUnLockFreeType(); 5824 goto Cleanup; 5825 } 5826 5827 glyph = face->glyph; 5828 if (EmuBold) 5829 FT_GlyphSlot_Embolden(glyph); 5830 if (EmuItalic) 5831 FT_GlyphSlot_Oblique(glyph); 5832 realglyph = ftGdiGlyphSet(face, glyph, RenderMode); 5833 if (!realglyph) 5834 { 5835 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index); 5836 IntUnLockFreeType(); 5837 goto Cleanup; 5838 } 5839 5840 /* retrieve kerning distance and move pen position */ 5841 if (use_kerning && previous && glyph_index && Dx == NULL) 5842 { 5843 FT_Vector delta; 5844 FT_Get_Kerning(face, previous, glyph_index, 0, &delta); 5845 TextLeft += delta.x; 5846 } 5847 5848 if (Dx == NULL) 5849 { 5850 TextLeft += realglyph->root.advance.x >> 10; 5851 } 5852 else 5853 { 5854 // FIXME this should probably be a matrix transform with TextTop as well. 5855 Scale = pdcattr->mxWorldToDevice.efM11; 5856 if (FLOATOBJ_Equal0(&Scale)) 5857 FLOATOBJ_Set1(&Scale); 5858 5859 /* do the shift before multiplying to preserve precision */ 5860 FLOATOBJ_MulLong(&Scale, Dx[i << DxShift] << 6); 5861 TextLeft += FLOATOBJ_GetLong(&Scale); 5862 } 5863 5864 if (DxShift) 5865 { 5866 TextTop -= Dx[2 * i + 1] << 6; 5867 } 5868 5869 previous = glyph_index; 5870 5871 if (EmuBold || EmuItalic) 5872 { 5873 FT_Done_Glyph((FT_Glyph)realglyph); 5874 realglyph = NULL; 5875 } 5876 } 5877 5878 TextWidth = TextLeft - RealXStart; 5879 } 5880 5881 /* 5882 * Process the horizontal alignment and modify XStart accordingly. 5883 */ 5884 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER) 5885 { 5886 RealXStart -= TextWidth / 2; 5887 } 5888 else if ((pdcattr->lTextAlign & TA_RIGHT) == TA_RIGHT) 5889 { 5890 RealXStart -= TextWidth; 5891 if (((RealXStart + TextWidth + 32) >> 6) <= Start.x + dc->ptlDCOrig.x) 5892 RealXStart += 1 << 6; 5893 } 5894 5895 psurf = dc->dclevel.pSurface; 5896 SurfObj = &psurf->SurfObj ; 5897 5898 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND)) 5899 DC_vUpdateBackgroundBrush(dc) ; 5900 5901 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT) 5902 DC_vUpdateTextBrush(dc) ; 5903 5904 if (!face->units_per_EM) 5905 { 5906 thickness = 1; 5907 } 5908 else 5909 { 5910 thickness = face->underline_thickness * 5911 face->size->metrics.y_ppem / face->units_per_EM; 5912 if (thickness <= 0) 5913 thickness = 1; 5914 } 5915 5916 if (fuOptions & ETO_OPAQUE) 5917 { 5918 /* Draw background */ 5919 RECTL Rect; 5920 5921 Rect.left = (RealXStart + 32) >> 6; 5922 Rect.top = TextTop + yoff - ((fixAscender + 32) >> 6); 5923 Rect.right = (RealXStart + TextWidth + 32) >> 6; 5924 Rect.bottom = Rect.top + ((fixAscender + fixDescender) >> 6); 5925 5926 if (dc->fs & (DC_ACCUM_APP | DC_ACCUM_WMGR)) 5927 { 5928 IntUpdateBoundsRect(dc, &Rect); 5929 } 5930 5931 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND) 5932 DC_vUpdateBackgroundBrush(dc); 5933 if (dc->dctype == DCTYPE_DIRECT) 5934 MouseSafetyOnDrawStart(dc->ppdev, Rect.left, Rect.top, Rect.right, Rect.bottom); 5935 5936 SourcePoint.x = SourcePoint.y = 0; 5937 BrushOrigin.x = BrushOrigin.y = 0; 5938 5939 psurf = dc->dclevel.pSurface; 5940 IntEngBitBlt( 5941 &psurf->SurfObj, 5942 NULL, 5943 NULL, 5944 (CLIPOBJ *)&dc->co, 5945 NULL, 5946 &Rect, 5947 &SourcePoint, 5948 &SourcePoint, 5949 &dc->eboBackground.BrushObject, 5950 &BrushOrigin, 5951 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); 5952 5953 if (dc->dctype == DCTYPE_DIRECT) 5954 MouseSafetyOnDrawEnd(dc->ppdev); 5955 } 5956 5957 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0); 5958 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0); 5959 5960 /* Assume success */ 5961 bResult = TRUE; 5962 5963 /* 5964 * The main rendering loop. 5965 */ 5966 TextLeft = RealXStart; 5967 TextTop = YStart; 5968 previous = 0; 5969 for (i = 0; i < Count; ++i) 5970 { 5971 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions); 5972 5973 if (EmuBold || EmuItalic) 5974 realglyph = NULL; 5975 else 5976 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight, 5977 RenderMode, pmxWorldToDevice); 5978 if (!realglyph) 5979 { 5980 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 5981 if (error) 5982 { 5983 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index); 5984 bResult = FALSE; 5985 break; 5986 } 5987 5988 glyph = face->glyph; 5989 if (EmuBold || EmuItalic) 5990 { 5991 if (EmuBold) 5992 FT_GlyphSlot_Embolden(glyph); 5993 if (EmuItalic) 5994 FT_GlyphSlot_Oblique(glyph); 5995 realglyph = ftGdiGlyphSet(face, glyph, RenderMode); 5996 } 5997 else 5998 { 5999 realglyph = ftGdiGlyphCacheSet(face, 6000 glyph_index, 6001 plf->lfHeight, 6002 pmxWorldToDevice, 6003 glyph, 6004 RenderMode); 6005 } 6006 if (!realglyph) 6007 { 6008 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index); 6009 bResult = FALSE; 6010 break; 6011 } 6012 } 6013 6014 /* retrieve kerning distance and move pen position */ 6015 if (use_kerning && previous && glyph_index && NULL == Dx) 6016 { 6017 FT_Vector delta; 6018 FT_Get_Kerning(face, previous, glyph_index, 0, &delta); 6019 TextLeft += delta.x; 6020 } 6021 DPRINT("TextLeft: %I64d\n", TextLeft); 6022 DPRINT("TextTop: %lu\n", TextTop); 6023 DPRINT("Advance: %d\n", realglyph->root.advance.x); 6024 6025 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left; 6026 DestRect.right = DestRect.left + realglyph->bitmap.width; 6027 DestRect.top = TextTop + yoff - realglyph->top; 6028 DestRect.bottom = DestRect.top + realglyph->bitmap.rows; 6029 6030 bitSize.cx = realglyph->bitmap.width; 6031 bitSize.cy = realglyph->bitmap.rows; 6032 MaskRect.right = realglyph->bitmap.width; 6033 MaskRect.bottom = realglyph->bitmap.rows; 6034 6035 /* Check if the bitmap has any pixels */ 6036 if ((bitSize.cx != 0) && (bitSize.cy != 0)) 6037 { 6038 /* 6039 * We should create the bitmap out of the loop at the biggest possible 6040 * glyph size. Then use memset with 0 to clear it and sourcerect to 6041 * limit the work of the transbitblt. 6042 */ 6043 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch, 6044 BMF_8BPP, BMF_TOPDOWN, 6045 realglyph->bitmap.buffer); 6046 if ( !HSourceGlyph ) 6047 { 6048 DPRINT1("WARNING: EngCreateBitmap() failed!\n"); 6049 // FT_Done_Glyph(realglyph); 6050 bResult = FALSE; 6051 break; 6052 } 6053 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph); 6054 if ( !SourceGlyphSurf ) 6055 { 6056 EngDeleteSurface((HSURF)HSourceGlyph); 6057 DPRINT1("WARNING: EngLockSurface() failed!\n"); 6058 bResult = FALSE; 6059 break; 6060 } 6061 6062 /* 6063 * Use the font data as a mask to paint onto the DCs surface using a 6064 * brush. 6065 */ 6066 if (lprc && (fuOptions & ETO_CLIPPED) && 6067 DestRect.right >= lprc->right + dc->ptlDCOrig.x) 6068 { 6069 // We do the check '>=' instead of '>' to possibly save an iteration 6070 // through this loop, since it's breaking after the drawing is done, 6071 // and x is always incremented. 6072 DestRect.right = lprc->right + dc->ptlDCOrig.x; 6073 DoBreak = TRUE; 6074 } 6075 if (lprc && (fuOptions & ETO_CLIPPED) && 6076 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y) 6077 { 6078 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y; 6079 } 6080 6081 if (dc->dctype == DCTYPE_DIRECT) 6082 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom); 6083 6084 if (!IntEngMaskBlt( 6085 SurfObj, 6086 SourceGlyphSurf, 6087 (CLIPOBJ *)&dc->co, 6088 &exloRGB2Dst.xlo, 6089 &exloDst2RGB.xlo, 6090 &DestRect, 6091 (PPOINTL)&MaskRect, 6092 &dc->eboText.BrushObject, 6093 &BrushOrigin)) 6094 { 6095 DPRINT1("Failed to MaskBlt a glyph!\n"); 6096 } 6097 6098 if (dc->dctype == DCTYPE_DIRECT) 6099 MouseSafetyOnDrawEnd(dc->ppdev) ; 6100 6101 EngUnlockSurface(SourceGlyphSurf); 6102 EngDeleteSurface((HSURF)HSourceGlyph); 6103 } 6104 6105 if (DoBreak) 6106 { 6107 break; 6108 } 6109 6110 if (plf->lfUnderline) 6111 { 6112 int i, position; 6113 if (!face->units_per_EM) 6114 { 6115 position = 0; 6116 } 6117 else 6118 { 6119 position = face->underline_position * 6120 face->size->metrics.y_ppem / face->units_per_EM; 6121 } 6122 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i) 6123 { 6124 EngLineTo(SurfObj, 6125 (CLIPOBJ *)&dc->co, 6126 &dc->eboText.BrushObject, 6127 (TextLeft >> 6), 6128 TextTop + yoff - position + i, 6129 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6), 6130 TextTop + yoff - position + i, 6131 NULL, 6132 ROP2_TO_MIX(R2_COPYPEN)); 6133 } 6134 } 6135 if (plf->lfStrikeOut) 6136 { 6137 int i; 6138 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i) 6139 { 6140 EngLineTo(SurfObj, 6141 (CLIPOBJ *)&dc->co, 6142 &dc->eboText.BrushObject, 6143 (TextLeft >> 6), 6144 TextTop + yoff - (fixAscender >> 6) / 3 + i, 6145 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6), 6146 TextTop + yoff - (fixAscender >> 6) / 3 + i, 6147 NULL, 6148 ROP2_TO_MIX(R2_COPYPEN)); 6149 } 6150 } 6151 6152 if (NULL == Dx) 6153 { 6154 TextLeft += realglyph->root.advance.x >> 10; 6155 DPRINT("New TextLeft: %I64d\n", TextLeft); 6156 } 6157 else 6158 { 6159 // FIXME this should probably be a matrix transform with TextTop as well. 6160 Scale = pdcattr->mxWorldToDevice.efM11; 6161 if (FLOATOBJ_Equal0(&Scale)) 6162 FLOATOBJ_Set1(&Scale); 6163 6164 /* do the shift before multiplying to preserve precision */ 6165 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6); 6166 TextLeft += FLOATOBJ_GetLong(&Scale); 6167 DPRINT("New TextLeft2: %I64d\n", TextLeft); 6168 } 6169 6170 if (DxShift) 6171 { 6172 TextTop -= Dx[2 * i + 1] << 6; 6173 } 6174 6175 previous = glyph_index; 6176 6177 if (EmuBold || EmuItalic) 6178 { 6179 FT_Done_Glyph((FT_Glyph)realglyph); 6180 realglyph = NULL; 6181 } 6182 } 6183 6184 if (pdcattr->lTextAlign & TA_UPDATECP) { 6185 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x; 6186 } 6187 6188 IntUnLockFreeType(); 6189 6190 EXLATEOBJ_vCleanup(&exloRGB2Dst); 6191 EXLATEOBJ_vCleanup(&exloDst2RGB); 6192 6193 Cleanup: 6194 6195 DC_vFinishBlit(dc, NULL); 6196 6197 if (TextObj != NULL) 6198 TEXTOBJ_UnlockText(TextObj); 6199 6200 DC_UnlockDc(dc); 6201 6202 return bResult; 6203 } 6204 6205 #define STACK_TEXT_BUFFER_SIZE 100 6206 BOOL 6207 APIENTRY 6208 NtGdiExtTextOutW( 6209 IN HDC hDC, 6210 IN INT XStart, 6211 IN INT YStart, 6212 IN UINT fuOptions, 6213 IN OPTIONAL LPRECT UnsafeRect, 6214 IN LPWSTR UnsafeString, 6215 IN INT Count, 6216 IN OPTIONAL LPINT UnsafeDx, 6217 IN DWORD dwCodePage) 6218 { 6219 BOOL Result = FALSE; 6220 NTSTATUS Status = STATUS_SUCCESS; 6221 RECTL SafeRect; 6222 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE]; 6223 PVOID Buffer = LocalBuffer; 6224 LPCWSTR SafeString = NULL; 6225 LPINT SafeDx = NULL; 6226 ULONG BufSize, StringSize, DxSize = 0; 6227 6228 /* Check if String is valid */ 6229 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL)) 6230 { 6231 EngSetLastError(ERROR_INVALID_PARAMETER); 6232 return FALSE; 6233 } 6234 6235 if (Count > 0) 6236 { 6237 /* Calculate buffer size for string and Dx values */ 6238 BufSize = StringSize = Count * sizeof(WCHAR); 6239 if (UnsafeDx) 6240 { 6241 /* If ETO_PDY is specified, we have pairs of INTs */ 6242 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1); 6243 BufSize += DxSize; 6244 } 6245 6246 /* Check if our local buffer is large enough */ 6247 if (BufSize > STACK_TEXT_BUFFER_SIZE) 6248 { 6249 /* It's not, allocate a temp buffer */ 6250 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT); 6251 if (!Buffer) 6252 { 6253 return FALSE; 6254 } 6255 } 6256 6257 /* Probe and copy user mode data to the buffer */ 6258 _SEH2_TRY 6259 { 6260 /* Put the Dx before the String to assure alignment of 4 */ 6261 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize); 6262 6263 /* Probe and copy the string */ 6264 ProbeForRead(UnsafeString, StringSize, 1); 6265 memcpy((PVOID)SafeString, UnsafeString, StringSize); 6266 6267 /* If we have Dx values... */ 6268 if (UnsafeDx) 6269 { 6270 /* ... probe and copy them */ 6271 SafeDx = Buffer; 6272 ProbeForRead(UnsafeDx, DxSize, 1); 6273 memcpy(SafeDx, UnsafeDx, DxSize); 6274 } 6275 } 6276 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6277 { 6278 Status = _SEH2_GetExceptionCode(); 6279 } 6280 _SEH2_END 6281 if (!NT_SUCCESS(Status)) 6282 { 6283 goto cleanup; 6284 } 6285 } 6286 6287 /* If we have a rect, copy it */ 6288 if (UnsafeRect) 6289 { 6290 _SEH2_TRY 6291 { 6292 ProbeForRead(UnsafeRect, sizeof(RECT), 1); 6293 SafeRect = *UnsafeRect; 6294 } 6295 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6296 { 6297 Status = _SEH2_GetExceptionCode(); 6298 } 6299 _SEH2_END 6300 if (!NT_SUCCESS(Status)) 6301 { 6302 goto cleanup; 6303 } 6304 } 6305 6306 /* Finally call the internal routine */ 6307 Result = GreExtTextOutW(hDC, 6308 XStart, 6309 YStart, 6310 fuOptions, 6311 &SafeRect, 6312 SafeString, 6313 Count, 6314 SafeDx, 6315 dwCodePage); 6316 6317 cleanup: 6318 /* If we allocated a buffer, free it */ 6319 if (Buffer != LocalBuffer) 6320 { 6321 ExFreePoolWithTag(Buffer, GDITAG_TEXT); 6322 } 6323 6324 return Result; 6325 } 6326 6327 6328 /* 6329 * @implemented 6330 */ 6331 BOOL 6332 APIENTRY 6333 NtGdiGetCharABCWidthsW( 6334 IN HDC hDC, 6335 IN UINT FirstChar, 6336 IN ULONG Count, 6337 IN OPTIONAL PWCHAR UnSafepwch, 6338 IN FLONG fl, 6339 OUT PVOID Buffer) 6340 { 6341 LPABC SafeBuff; 6342 LPABCFLOAT SafeBuffF = NULL; 6343 PDC dc; 6344 PDC_ATTR pdcattr; 6345 PTEXTOBJ TextObj; 6346 PFONTGDI FontGDI; 6347 FT_Face face; 6348 FT_CharMap charmap, found = NULL; 6349 UINT i, glyph_index, BufferSize; 6350 HFONT hFont = 0; 6351 NTSTATUS Status = STATUS_SUCCESS; 6352 PMATRIX pmxWorldToDevice; 6353 PWCHAR Safepwch = NULL; 6354 LOGFONTW *plf; 6355 6356 if (!Buffer) 6357 { 6358 EngSetLastError(ERROR_INVALID_PARAMETER); 6359 return FALSE; 6360 } 6361 6362 if (UnSafepwch) 6363 { 6364 UINT pwchSize = Count * sizeof(WCHAR); 6365 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT); 6366 6367 if(!Safepwch) 6368 { 6369 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 6370 return FALSE; 6371 } 6372 6373 _SEH2_TRY 6374 { 6375 ProbeForRead(UnSafepwch, pwchSize, 1); 6376 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize); 6377 } 6378 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6379 { 6380 Status = _SEH2_GetExceptionCode(); 6381 } 6382 _SEH2_END; 6383 } 6384 6385 if (!NT_SUCCESS(Status)) 6386 { 6387 if(Safepwch) 6388 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6389 6390 EngSetLastError(Status); 6391 return FALSE; 6392 } 6393 6394 BufferSize = Count * sizeof(ABC); // Same size! 6395 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT); 6396 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff; 6397 if (SafeBuff == NULL) 6398 { 6399 6400 if(Safepwch) 6401 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6402 6403 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 6404 return FALSE; 6405 } 6406 6407 dc = DC_LockDc(hDC); 6408 if (dc == NULL) 6409 { 6410 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6411 6412 if(Safepwch) 6413 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6414 6415 EngSetLastError(ERROR_INVALID_HANDLE); 6416 return FALSE; 6417 } 6418 pdcattr = dc->pdcattr; 6419 hFont = pdcattr->hlfntNew; 6420 TextObj = RealizeFontInit(hFont); 6421 6422 /* Get the DC's world-to-device transformation matrix */ 6423 pmxWorldToDevice = DC_pmxWorldToDevice(dc); 6424 DC_UnlockDc(dc); 6425 6426 if (TextObj == NULL) 6427 { 6428 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6429 6430 if(Safepwch) 6431 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6432 6433 EngSetLastError(ERROR_INVALID_HANDLE); 6434 return FALSE; 6435 } 6436 6437 FontGDI = ObjToGDI(TextObj->Font, FONT); 6438 6439 face = FontGDI->SharedFace->Face; 6440 if (face->charmap == NULL) 6441 { 6442 for (i = 0; i < (UINT)face->num_charmaps; i++) 6443 { 6444 charmap = face->charmaps[i]; 6445 if (charmap->encoding != 0) 6446 { 6447 found = charmap; 6448 break; 6449 } 6450 } 6451 6452 if (!found) 6453 { 6454 DPRINT1("WARNING: Could not find desired charmap!\n"); 6455 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6456 6457 if(Safepwch) 6458 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6459 6460 EngSetLastError(ERROR_INVALID_HANDLE); 6461 return FALSE; 6462 } 6463 6464 IntLockFreeType(); 6465 FT_Set_Charmap(face, found); 6466 IntUnLockFreeType(); 6467 } 6468 6469 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 6470 IntLockFreeType(); 6471 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight); 6472 FtSetCoordinateTransform(face, pmxWorldToDevice); 6473 6474 for (i = FirstChar; i < FirstChar+Count; i++) 6475 { 6476 int adv, lsb, bbx, left, right; 6477 6478 if (Safepwch) 6479 { 6480 glyph_index = get_glyph_index_flagged(face, Safepwch[i - FirstChar], GCABCW_INDICES, fl); 6481 } 6482 else 6483 { 6484 glyph_index = get_glyph_index_flagged(face, i, GCABCW_INDICES, fl); 6485 } 6486 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 6487 6488 left = (INT)face->glyph->metrics.horiBearingX & -64; 6489 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64; 6490 adv = (face->glyph->advance.x + 32) >> 6; 6491 6492 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6; 6493 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */ 6494 6495 lsb = left >> 6; 6496 bbx = (right - left) >> 6; 6497 /* 6498 DPRINT1("lsb %d and bbx %d\n", lsb, bbx ); 6499 */ 6500 if (!fl) 6501 { 6502 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb; 6503 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx; 6504 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx); 6505 } 6506 else 6507 { 6508 SafeBuff[i - FirstChar].abcA = lsb; 6509 SafeBuff[i - FirstChar].abcB = bbx; 6510 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx; 6511 } 6512 } 6513 IntUnLockFreeType(); 6514 TEXTOBJ_UnlockText(TextObj); 6515 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize); 6516 6517 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6518 6519 if(Safepwch) 6520 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6521 6522 if (! NT_SUCCESS(Status)) 6523 { 6524 SetLastNtError(Status); 6525 return FALSE; 6526 } 6527 6528 DPRINT("NtGdiGetCharABCWidths Worked!\n"); 6529 return TRUE; 6530 } 6531 6532 /* 6533 * @implemented 6534 */ 6535 BOOL 6536 APIENTRY 6537 NtGdiGetCharWidthW( 6538 IN HDC hDC, 6539 IN UINT FirstChar, 6540 IN UINT Count, 6541 IN OPTIONAL PWCHAR UnSafepwc, 6542 IN FLONG fl, 6543 OUT PVOID Buffer) 6544 { 6545 NTSTATUS Status = STATUS_SUCCESS; 6546 LPINT SafeBuff; 6547 PFLOAT SafeBuffF = NULL; 6548 PDC dc; 6549 PDC_ATTR pdcattr; 6550 PTEXTOBJ TextObj; 6551 PFONTGDI FontGDI; 6552 FT_Face face; 6553 FT_CharMap charmap, found = NULL; 6554 UINT i, glyph_index, BufferSize; 6555 HFONT hFont = 0; 6556 PMATRIX pmxWorldToDevice; 6557 PWCHAR Safepwc = NULL; 6558 LOGFONTW *plf; 6559 6560 if (UnSafepwc) 6561 { 6562 UINT pwcSize = Count * sizeof(WCHAR); 6563 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT); 6564 6565 if(!Safepwc) 6566 { 6567 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 6568 return FALSE; 6569 } 6570 _SEH2_TRY 6571 { 6572 ProbeForRead(UnSafepwc, pwcSize, 1); 6573 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize); 6574 } 6575 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6576 { 6577 Status = _SEH2_GetExceptionCode(); 6578 } 6579 _SEH2_END; 6580 } 6581 6582 if (!NT_SUCCESS(Status)) 6583 { 6584 EngSetLastError(Status); 6585 return FALSE; 6586 } 6587 6588 BufferSize = Count * sizeof(INT); // Same size! 6589 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT); 6590 if (!fl) SafeBuffF = (PFLOAT) SafeBuff; 6591 if (SafeBuff == NULL) 6592 { 6593 if(Safepwc) 6594 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6595 6596 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 6597 return FALSE; 6598 } 6599 6600 dc = DC_LockDc(hDC); 6601 if (dc == NULL) 6602 { 6603 if(Safepwc) 6604 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6605 6606 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6607 EngSetLastError(ERROR_INVALID_HANDLE); 6608 return FALSE; 6609 } 6610 pdcattr = dc->pdcattr; 6611 hFont = pdcattr->hlfntNew; 6612 TextObj = RealizeFontInit(hFont); 6613 /* Get the DC's world-to-device transformation matrix */ 6614 pmxWorldToDevice = DC_pmxWorldToDevice(dc); 6615 DC_UnlockDc(dc); 6616 6617 if (TextObj == NULL) 6618 { 6619 if(Safepwc) 6620 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6621 6622 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6623 EngSetLastError(ERROR_INVALID_HANDLE); 6624 return FALSE; 6625 } 6626 6627 FontGDI = ObjToGDI(TextObj->Font, FONT); 6628 6629 face = FontGDI->SharedFace->Face; 6630 if (face->charmap == NULL) 6631 { 6632 for (i = 0; i < (UINT)face->num_charmaps; i++) 6633 { 6634 charmap = face->charmaps[i]; 6635 if (charmap->encoding != 0) 6636 { 6637 found = charmap; 6638 break; 6639 } 6640 } 6641 6642 if (!found) 6643 { 6644 DPRINT1("WARNING: Could not find desired charmap!\n"); 6645 6646 if(Safepwc) 6647 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6648 6649 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6650 EngSetLastError(ERROR_INVALID_HANDLE); 6651 return FALSE; 6652 } 6653 6654 IntLockFreeType(); 6655 FT_Set_Charmap(face, found); 6656 IntUnLockFreeType(); 6657 } 6658 6659 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 6660 IntLockFreeType(); 6661 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight); 6662 FtSetCoordinateTransform(face, pmxWorldToDevice); 6663 6664 for (i = FirstChar; i < FirstChar+Count; i++) 6665 { 6666 if (Safepwc) 6667 { 6668 glyph_index = get_glyph_index_flagged(face, Safepwc[i - FirstChar], GCW_INDICES, fl); 6669 } 6670 else 6671 { 6672 glyph_index = get_glyph_index_flagged(face, i, GCW_INDICES, fl); 6673 } 6674 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 6675 if (!fl) 6676 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6); 6677 else 6678 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6; 6679 } 6680 IntUnLockFreeType(); 6681 TEXTOBJ_UnlockText(TextObj); 6682 MmCopyToCaller(Buffer, SafeBuff, BufferSize); 6683 6684 if(Safepwc) 6685 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6686 6687 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6688 return TRUE; 6689 } 6690 6691 6692 /* 6693 * @implemented 6694 */ 6695 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap 6696 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead. 6697 // NOTE: See also GreGetGlyphIndicesW. 6698 __kernel_entry 6699 W32KAPI 6700 DWORD 6701 APIENTRY 6702 NtGdiGetGlyphIndicesW( 6703 _In_ HDC hdc, 6704 _In_reads_opt_(cwc) LPCWSTR pwc, 6705 _In_ INT cwc, 6706 _Out_writes_opt_(cwc) LPWORD pgi, 6707 _In_ DWORD iMode) 6708 { 6709 PDC dc; 6710 PDC_ATTR pdcattr; 6711 PTEXTOBJ TextObj; 6712 PFONTGDI FontGDI; 6713 HFONT hFont = NULL; 6714 NTSTATUS Status = STATUS_SUCCESS; 6715 OUTLINETEXTMETRICW *potm; 6716 INT i; 6717 WCHAR DefChar = 0xffff; 6718 PWSTR Buffer = NULL; 6719 ULONG Size, pwcSize; 6720 PWSTR Safepwc = NULL; 6721 LPCWSTR UnSafepwc = pwc; 6722 LPWORD UnSafepgi = pgi; 6723 6724 /* Check for integer overflow */ 6725 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN 6726 return GDI_ERROR; 6727 6728 if (!UnSafepwc && !UnSafepgi) 6729 return cwc; 6730 6731 if (!UnSafepwc || !UnSafepgi) 6732 { 6733 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi); 6734 return GDI_ERROR; 6735 } 6736 6737 // TODO: Special undocumented case! 6738 if (!pwc && !pgi && (cwc == 0)) 6739 { 6740 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n"); 6741 return 0; 6742 } 6743 6744 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825 6745 if (cwc == 0) 6746 { 6747 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n"); 6748 return GDI_ERROR; 6749 } 6750 6751 dc = DC_LockDc(hdc); 6752 if (!dc) 6753 { 6754 return GDI_ERROR; 6755 } 6756 pdcattr = dc->pdcattr; 6757 hFont = pdcattr->hlfntNew; 6758 TextObj = RealizeFontInit(hFont); 6759 DC_UnlockDc(dc); 6760 if (!TextObj) 6761 { 6762 return GDI_ERROR; 6763 } 6764 6765 FontGDI = ObjToGDI(TextObj->Font, FONT); 6766 TEXTOBJ_UnlockText(TextObj); 6767 6768 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT); 6769 if (!Buffer) 6770 { 6771 return GDI_ERROR; 6772 } 6773 6774 if (iMode & GGI_MARK_NONEXISTING_GLYPHS) 6775 { 6776 DefChar = 0xffff; 6777 } 6778 else 6779 { 6780 FT_Face Face = FontGDI->SharedFace->Face; 6781 if (FT_IS_SFNT(Face)) 6782 { 6783 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); 6784 DefChar = (pOS2->usDefaultChar ? get_glyph_index(Face, pOS2->usDefaultChar) : 0); 6785 } 6786 else 6787 { 6788 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 6789 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 6790 if (!potm) 6791 { 6792 cwc = GDI_ERROR; 6793 goto ErrorRet; 6794 } 6795 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm); 6796 if (Size) 6797 DefChar = potm->otmTextMetrics.tmDefaultChar; 6798 ExFreePoolWithTag(potm, GDITAG_TEXT); 6799 } 6800 } 6801 6802 pwcSize = cwc * sizeof(WCHAR); 6803 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT); 6804 6805 if (!Safepwc) 6806 { 6807 Status = STATUS_NO_MEMORY; 6808 goto ErrorRet; 6809 } 6810 6811 _SEH2_TRY 6812 { 6813 ProbeForRead(UnSafepwc, pwcSize, 1); 6814 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize); 6815 } 6816 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6817 { 6818 Status = _SEH2_GetExceptionCode(); 6819 } 6820 _SEH2_END; 6821 6822 if (!NT_SUCCESS(Status)) goto ErrorRet; 6823 6824 IntLockFreeType(); 6825 6826 for (i = 0; i < cwc; i++) 6827 { 6828 Buffer[i] = get_glyph_index(FontGDI->SharedFace->Face, Safepwc[i]); 6829 if (Buffer[i] == 0) 6830 { 6831 Buffer[i] = DefChar; 6832 } 6833 } 6834 6835 IntUnLockFreeType(); 6836 6837 _SEH2_TRY 6838 { 6839 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1); 6840 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD)); 6841 } 6842 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6843 { 6844 Status = _SEH2_GetExceptionCode(); 6845 } 6846 _SEH2_END; 6847 6848 ErrorRet: 6849 ExFreePoolWithTag(Buffer, GDITAG_TEXT); 6850 if (Safepwc != NULL) 6851 { 6852 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6853 } 6854 if (NT_SUCCESS(Status)) return cwc; 6855 return GDI_ERROR; 6856 } 6857 6858 /* EOF */ 6859