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