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