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