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