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