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 SIZE_T 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 SIZE_T 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 = ULongToHandle(++Win32Process->PrivateMemFontHandleCount); 1229 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry); 1230 IntUnLockProcessPrivateFonts(Win32Process); 1231 Ret = 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 == 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 FT_Error Error; 2095 NTSTATUS Status = STATUS_NOT_FOUND; 2096 ANSI_STRING AnsiName; 2097 PSHARED_FACE_CACHE Cache; 2098 FT_Face Face = SharedFace->Face; 2099 2100 RtlFreeUnicodeString(pNameW); 2101 2102 /* select cache */ 2103 if (PRIMARYLANGID(LangID) == LANG_ENGLISH) 2104 { 2105 Cache = &SharedFace->EnglishUS; 2106 } 2107 else 2108 { 2109 Cache = &SharedFace->UserLanguage; 2110 } 2111 2112 /* use cache if available */ 2113 if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer) 2114 { 2115 return DuplicateUnicodeString(&Cache->FontFamily, pNameW); 2116 } 2117 if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer) 2118 { 2119 return DuplicateUnicodeString(&Cache->FullName, pNameW); 2120 } 2121 2122 BestIndex = -1; 2123 BestScore = 0; 2124 2125 Count = FT_Get_Sfnt_Name_Count(Face); 2126 for (i = 0; i < Count; ++i) 2127 { 2128 Error = FT_Get_Sfnt_Name(Face, i, &Name); 2129 if (Error) 2130 { 2131 continue; /* failure */ 2132 } 2133 2134 if (Name.name_id != NameID) 2135 { 2136 continue; /* mismatched */ 2137 } 2138 2139 if (Name.platform_id != TT_PLATFORM_MICROSOFT || 2140 (Name.encoding_id != TT_MS_ID_UNICODE_CS && 2141 Name.encoding_id != TT_MS_ID_SYMBOL_CS)) 2142 { 2143 continue; /* not Microsoft Unicode name */ 2144 } 2145 2146 if (Name.string == NULL || Name.string_len == 0 || 2147 (Name.string[0] == 0 && Name.string[1] == 0)) 2148 { 2149 continue; /* invalid string */ 2150 } 2151 2152 if (Name.language_id == LangID) 2153 { 2154 Score = 30; 2155 BestIndex = i; 2156 break; /* best match */ 2157 } 2158 else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID)) 2159 { 2160 Score = 20; 2161 } 2162 else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH) 2163 { 2164 Score = 10; 2165 } 2166 else 2167 { 2168 Score = 0; 2169 } 2170 2171 if (Score > BestScore) 2172 { 2173 BestScore = Score; 2174 BestIndex = i; 2175 } 2176 } 2177 2178 if (BestIndex >= 0) 2179 { 2180 /* store the best name */ 2181 Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name); 2182 if (!Error) 2183 { 2184 /* NOTE: Name.string is not null-terminated */ 2185 UNICODE_STRING Tmp; 2186 Tmp.Buffer = (PWCH)Name.string; 2187 Tmp.Length = Tmp.MaximumLength = Name.string_len; 2188 2189 pNameW->Length = 0; 2190 pNameW->MaximumLength = Name.string_len + sizeof(WCHAR); 2191 pNameW->Buffer = ExAllocatePoolWithTag(PagedPool, pNameW->MaximumLength, TAG_USTR); 2192 2193 if (pNameW->Buffer) 2194 { 2195 Status = RtlAppendUnicodeStringToString(pNameW, &Tmp); 2196 if (Status == STATUS_SUCCESS) 2197 { 2198 /* Convert UTF-16 big endian to little endian */ 2199 SwapEndian(pNameW->Buffer, pNameW->Length); 2200 } 2201 } 2202 else 2203 { 2204 Status = STATUS_INSUFFICIENT_RESOURCES; 2205 } 2206 } 2207 } 2208 2209 if (!NT_SUCCESS(Status)) 2210 { 2211 /* defaulted */ 2212 if (NameID == TT_NAME_ID_FONT_SUBFAMILY) 2213 { 2214 RtlInitAnsiString(&AnsiName, Face->style_name); 2215 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE); 2216 } 2217 else 2218 { 2219 RtlInitAnsiString(&AnsiName, Face->family_name); 2220 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE); 2221 } 2222 } 2223 2224 if (NT_SUCCESS(Status)) 2225 { 2226 /* make cache */ 2227 if (NameID == TT_NAME_ID_FONT_FAMILY) 2228 { 2229 ASSERT_FREETYPE_LOCK_NOT_HELD(); 2230 IntLockFreeType; 2231 if (!Cache->FontFamily.Buffer) 2232 DuplicateUnicodeString(pNameW, &Cache->FontFamily); 2233 IntUnLockFreeType; 2234 } 2235 else if (NameID == TT_NAME_ID_FULL_NAME) 2236 { 2237 ASSERT_FREETYPE_LOCK_NOT_HELD(); 2238 IntLockFreeType; 2239 if (!Cache->FullName.Buffer) 2240 DuplicateUnicodeString(pNameW, &Cache->FullName); 2241 IntUnLockFreeType; 2242 } 2243 } 2244 2245 return Status; 2246 } 2247 2248 static void FASTCALL 2249 FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName, 2250 LPCWSTR FullName, PFONTGDI FontGDI) 2251 { 2252 ANSI_STRING StyleA; 2253 UNICODE_STRING StyleW; 2254 TT_OS2 *pOS2; 2255 FONTSIGNATURE fs; 2256 CHARSETINFO CharSetInfo; 2257 unsigned i, Size; 2258 OUTLINETEXTMETRICW *Otm; 2259 LOGFONTW *Lf; 2260 TEXTMETRICW *TM; 2261 NEWTEXTMETRICW *Ntm; 2262 DWORD fs0; 2263 NTSTATUS status; 2264 PSHARED_FACE SharedFace = FontGDI->SharedFace; 2265 FT_Face Face = SharedFace->Face; 2266 UNICODE_STRING NameW; 2267 2268 RtlInitUnicodeString(&NameW, NULL); 2269 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO)); 2270 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 2271 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 2272 if (!Otm) 2273 { 2274 return; 2275 } 2276 Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm); 2277 if (!Size) 2278 { 2279 ExFreePoolWithTag(Otm, GDITAG_TEXT); 2280 return; 2281 } 2282 2283 Lf = &Info->EnumLogFontEx.elfLogFont; 2284 TM = &Otm->otmTextMetrics; 2285 2286 Lf->lfHeight = TM->tmHeight; 2287 Lf->lfWidth = TM->tmAveCharWidth; 2288 Lf->lfWeight = TM->tmWeight; 2289 Lf->lfItalic = TM->tmItalic; 2290 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1; 2291 Lf->lfCharSet = TM->tmCharSet; 2292 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS; 2293 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; 2294 Lf->lfQuality = PROOF_QUALITY; 2295 2296 Ntm = &Info->NewTextMetricEx.ntmTm; 2297 Ntm->tmHeight = TM->tmHeight; 2298 Ntm->tmAscent = TM->tmAscent; 2299 Ntm->tmDescent = TM->tmDescent; 2300 Ntm->tmInternalLeading = TM->tmInternalLeading; 2301 Ntm->tmExternalLeading = TM->tmExternalLeading; 2302 Ntm->tmAveCharWidth = TM->tmAveCharWidth; 2303 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth; 2304 Ntm->tmWeight = TM->tmWeight; 2305 Ntm->tmOverhang = TM->tmOverhang; 2306 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX; 2307 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY; 2308 Ntm->tmFirstChar = TM->tmFirstChar; 2309 Ntm->tmLastChar = TM->tmLastChar; 2310 Ntm->tmDefaultChar = TM->tmDefaultChar; 2311 Ntm->tmBreakChar = TM->tmBreakChar; 2312 Ntm->tmItalic = TM->tmItalic; 2313 Ntm->tmUnderlined = TM->tmUnderlined; 2314 Ntm->tmStruckOut = TM->tmStruckOut; 2315 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily; 2316 Ntm->tmCharSet = TM->tmCharSet; 2317 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0; 2318 2319 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD; 2320 2321 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR; 2322 2323 Ntm->ntmSizeEM = Otm->otmEMSquare; 2324 Ntm->ntmCellHeight = Otm->otmEMSquare; 2325 Ntm->ntmAvgWidth = 0; 2326 2327 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE) 2328 ? TRUETYPE_FONTTYPE : 0); 2329 2330 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR)) 2331 Info->FontType |= RASTER_FONTTYPE; 2332 2333 2334 /* face name */ 2335 if (!FaceName) 2336 FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName); 2337 2338 RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName); 2339 2340 /* full name */ 2341 if (!FullName) 2342 FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName); 2343 2344 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName, 2345 sizeof(Info->EnumLogFontEx.elfFullName), 2346 FullName); 2347 2348 ExFreePoolWithTag(Otm, GDITAG_TEXT); 2349 2350 RtlInitAnsiString(&StyleA, Face->style_name); 2351 StyleW.Buffer = Info->EnumLogFontEx.elfStyle; 2352 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle); 2353 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE); 2354 if (!NT_SUCCESS(status)) 2355 { 2356 return; 2357 } 2358 Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL; 2359 2360 IntLockFreeType; 2361 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); 2362 2363 if (!pOS2) 2364 { 2365 IntUnLockFreeType; 2366 return; 2367 } 2368 2369 fs.fsCsb[0] = pOS2->ulCodePageRange1; 2370 fs.fsCsb[1] = pOS2->ulCodePageRange2; 2371 fs.fsUsb[0] = pOS2->ulUnicodeRange1; 2372 fs.fsUsb[1] = pOS2->ulUnicodeRange2; 2373 fs.fsUsb[2] = pOS2->ulUnicodeRange3; 2374 fs.fsUsb[3] = pOS2->ulUnicodeRange4; 2375 2376 if (0 == pOS2->version) 2377 { 2378 FT_UInt Dummy; 2379 2380 if (FT_Get_First_Char(Face, &Dummy) < 0x100) 2381 fs.fsCsb[0] |= FS_LATIN1; 2382 else 2383 fs.fsCsb[0] |= FS_SYMBOL; 2384 } 2385 IntUnLockFreeType; 2386 2387 if (fs.fsCsb[0] == 0) 2388 { 2389 /* Let's see if we can find any interesting cmaps */ 2390 for (i = 0; i < (UINT)Face->num_charmaps; i++) 2391 { 2392 switch (Face->charmaps[i]->encoding) 2393 { 2394 case FT_ENCODING_UNICODE: 2395 case FT_ENCODING_APPLE_ROMAN: 2396 fs.fsCsb[0] |= FS_LATIN1; 2397 break; 2398 case FT_ENCODING_MS_SYMBOL: 2399 fs.fsCsb[0] |= FS_SYMBOL; 2400 break; 2401 default: 2402 break; 2403 } 2404 } 2405 } 2406 2407 for (i = 0; i < MAXTCIINDEX; i++) 2408 { 2409 fs0 = 1L << i; 2410 if (fs.fsCsb[0] & fs0) 2411 { 2412 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG)) 2413 { 2414 CharSetInfo.ciCharset = DEFAULT_CHARSET; 2415 } 2416 if (DEFAULT_CHARSET != CharSetInfo.ciCharset) 2417 { 2418 if (ElfScripts[i]) 2419 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]); 2420 else 2421 { 2422 DPRINT1("Unknown elfscript for bit %u\n", i); 2423 } 2424 } 2425 } 2426 } 2427 Info->NewTextMetricEx.ntmFontSig = fs; 2428 } 2429 2430 static int FASTCALL 2431 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries) 2432 { 2433 DWORD i; 2434 UNICODE_STRING InfoFaceName; 2435 2436 for (i = 0; i < InfoEntries; i++) 2437 { 2438 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName); 2439 if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE)) 2440 { 2441 return i; 2442 } 2443 } 2444 2445 return -1; 2446 } 2447 2448 static BOOLEAN FASTCALL 2449 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName, 2450 PFONTFAMILYINFO Info, DWORD InfoEntries) 2451 { 2452 UNICODE_STRING LogFontFaceName; 2453 2454 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName); 2455 if (0 != LogFontFaceName.Length && 2456 !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE)) 2457 { 2458 return FALSE; 2459 } 2460 2461 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0; 2462 } 2463 2464 static BOOL FASTCALL 2465 FontFamilyFound(PFONTFAMILYINFO InfoEntry, 2466 PFONTFAMILYINFO Info, DWORD InfoCount) 2467 { 2468 LPLOGFONTW plf1 = &InfoEntry->EnumLogFontEx.elfLogFont; 2469 LPWSTR pFullName1 = InfoEntry->EnumLogFontEx.elfFullName; 2470 LPWSTR pFullName2; 2471 DWORD i; 2472 2473 for (i = 0; i < InfoCount; ++i) 2474 { 2475 LPLOGFONTW plf2 = &Info[i].EnumLogFontEx.elfLogFont; 2476 if (plf1->lfCharSet != plf2->lfCharSet) 2477 continue; 2478 2479 pFullName2 = Info[i].EnumLogFontEx.elfFullName; 2480 if (_wcsicmp(pFullName1, pFullName2) != 0) 2481 continue; 2482 2483 return TRUE; 2484 } 2485 return FALSE; 2486 } 2487 2488 static BOOLEAN FASTCALL 2489 GetFontFamilyInfoForList(LPLOGFONTW LogFont, 2490 PFONTFAMILYINFO Info, 2491 DWORD *pCount, 2492 DWORD MaxCount, 2493 PLIST_ENTRY Head) 2494 { 2495 PLIST_ENTRY Entry; 2496 PFONT_ENTRY CurrentEntry; 2497 FONTGDI *FontGDI; 2498 FONTFAMILYINFO InfoEntry; 2499 DWORD Count = *pCount; 2500 2501 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) 2502 { 2503 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); 2504 FontGDI = CurrentEntry->Font; 2505 ASSERT(FontGDI); 2506 2507 if (LogFont->lfCharSet != DEFAULT_CHARSET && 2508 LogFont->lfCharSet != FontGDI->CharSet) 2509 { 2510 continue; 2511 } 2512 2513 if (LogFont->lfFaceName[0] == UNICODE_NULL) 2514 { 2515 if (Count < MaxCount) 2516 { 2517 FontFamilyFillInfo(&Info[Count], NULL, NULL, FontGDI); 2518 } 2519 Count++; 2520 continue; 2521 } 2522 2523 FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI); 2524 2525 if (_wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0 && 2526 _wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfFullName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0) 2527 { 2528 continue; 2529 } 2530 2531 if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount))) 2532 { 2533 if (Count < MaxCount) 2534 { 2535 RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry)); 2536 } 2537 Count++; 2538 } 2539 } 2540 2541 *pCount = Count; 2542 2543 return TRUE; 2544 } 2545 2546 static BOOLEAN FASTCALL 2547 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont, 2548 PFONTFAMILYINFO Info, 2549 DWORD *pCount, 2550 DWORD MaxCount) 2551 { 2552 PLIST_ENTRY pEntry, pHead = &FontSubstListHead; 2553 PFONTSUBST_ENTRY pCurrentEntry; 2554 PUNICODE_STRING pFromW; 2555 FONTGDI *FontGDI; 2556 LOGFONTW lf = *LogFont; 2557 UNICODE_STRING NameW; 2558 2559 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) 2560 { 2561 pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry); 2562 2563 pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM]; 2564 if (LogFont->lfFaceName[0] != UNICODE_NULL) 2565 { 2566 if (!FontFamilyInclude(LogFont, pFromW, Info, min(*pCount, MaxCount))) 2567 continue; /* mismatch */ 2568 } 2569 2570 RtlStringCchCopyW(lf.lfFaceName, LF_FACESIZE, pFromW->Buffer); 2571 SubstituteFontRecurse(&lf); 2572 2573 RtlInitUnicodeString(&NameW, lf.lfFaceName); 2574 FontGDI = FindFaceNameInLists(&NameW); 2575 if (FontGDI == NULL) 2576 { 2577 continue; /* no real font */ 2578 } 2579 2580 if (*pCount < MaxCount) 2581 { 2582 FontFamilyFillInfo(&Info[*pCount], pFromW->Buffer, NULL, FontGDI); 2583 } 2584 (*pCount)++; 2585 } 2586 2587 return TRUE; 2588 } 2589 2590 BOOL 2591 FASTCALL 2592 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs) 2593 { 2594 if ( lprs ) 2595 { 2596 lprs->nSize = sizeof(RASTERIZER_STATUS); 2597 lprs->wFlags = TT_AVAILABLE | TT_ENABLED; 2598 lprs->nLanguageID = gusLanguageID; 2599 return TRUE; 2600 } 2601 EngSetLastError(ERROR_INVALID_PARAMETER); 2602 return FALSE; 2603 } 2604 2605 static 2606 BOOL 2607 SameScaleMatrix( 2608 PMATRIX pmx1, 2609 PMATRIX pmx2) 2610 { 2611 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) && 2612 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) && 2613 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) && 2614 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22)); 2615 } 2616 2617 FT_BitmapGlyph APIENTRY 2618 ftGdiGlyphCacheGet( 2619 FT_Face Face, 2620 INT GlyphIndex, 2621 INT Height, 2622 FT_Render_Mode RenderMode, 2623 PMATRIX pmx) 2624 { 2625 PLIST_ENTRY CurrentEntry; 2626 PFONT_CACHE_ENTRY FontEntry; 2627 2628 ASSERT_FREETYPE_LOCK_HELD(); 2629 2630 CurrentEntry = FontCacheListHead.Flink; 2631 while (CurrentEntry != &FontCacheListHead) 2632 { 2633 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry); 2634 if ((FontEntry->Face == Face) && 2635 (FontEntry->GlyphIndex == GlyphIndex) && 2636 (FontEntry->Height == Height) && 2637 (FontEntry->RenderMode == RenderMode) && 2638 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx))) 2639 break; 2640 CurrentEntry = CurrentEntry->Flink; 2641 } 2642 2643 if (CurrentEntry == &FontCacheListHead) 2644 { 2645 return NULL; 2646 } 2647 2648 RemoveEntryList(CurrentEntry); 2649 InsertHeadList(&FontCacheListHead, CurrentEntry); 2650 return FontEntry->BitmapGlyph; 2651 } 2652 2653 /* no cache */ 2654 FT_BitmapGlyph APIENTRY 2655 ftGdiGlyphSet( 2656 FT_Face Face, 2657 FT_GlyphSlot GlyphSlot, 2658 FT_Render_Mode RenderMode) 2659 { 2660 FT_Glyph Glyph; 2661 INT error; 2662 FT_Bitmap AlignedBitmap; 2663 FT_BitmapGlyph BitmapGlyph; 2664 2665 error = FT_Get_Glyph(GlyphSlot, &Glyph); 2666 if (error) 2667 { 2668 DPRINT1("Failure getting glyph.\n"); 2669 return NULL; 2670 } 2671 2672 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1); 2673 if (error) 2674 { 2675 FT_Done_Glyph(Glyph); 2676 DPRINT1("Failure rendering glyph.\n"); 2677 return NULL; 2678 } 2679 2680 BitmapGlyph = (FT_BitmapGlyph)Glyph; 2681 FT_Bitmap_New(&AlignedBitmap); 2682 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4)) 2683 { 2684 DPRINT1("Conversion failed\n"); 2685 FT_Done_Glyph((FT_Glyph)BitmapGlyph); 2686 return NULL; 2687 } 2688 2689 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap); 2690 BitmapGlyph->bitmap = AlignedBitmap; 2691 2692 return BitmapGlyph; 2693 } 2694 2695 FT_BitmapGlyph APIENTRY 2696 ftGdiGlyphCacheSet( 2697 FT_Face Face, 2698 INT GlyphIndex, 2699 INT Height, 2700 PMATRIX pmx, 2701 FT_GlyphSlot GlyphSlot, 2702 FT_Render_Mode RenderMode) 2703 { 2704 FT_Glyph GlyphCopy; 2705 INT error; 2706 PFONT_CACHE_ENTRY NewEntry; 2707 FT_Bitmap AlignedBitmap; 2708 FT_BitmapGlyph BitmapGlyph; 2709 2710 ASSERT_FREETYPE_LOCK_HELD(); 2711 2712 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy); 2713 if (error) 2714 { 2715 DPRINT1("Failure caching glyph.\n"); 2716 return NULL; 2717 }; 2718 2719 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1); 2720 if (error) 2721 { 2722 FT_Done_Glyph(GlyphCopy); 2723 DPRINT1("Failure rendering glyph.\n"); 2724 return NULL; 2725 }; 2726 2727 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT); 2728 if (!NewEntry) 2729 { 2730 DPRINT1("Alloc failure caching glyph.\n"); 2731 FT_Done_Glyph(GlyphCopy); 2732 return NULL; 2733 } 2734 2735 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy; 2736 FT_Bitmap_New(&AlignedBitmap); 2737 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4)) 2738 { 2739 DPRINT1("Conversion failed\n"); 2740 ExFreePoolWithTag(NewEntry, TAG_FONT); 2741 FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap); 2742 FT_Done_Glyph((FT_Glyph)BitmapGlyph); 2743 return NULL; 2744 } 2745 2746 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap); 2747 BitmapGlyph->bitmap = AlignedBitmap; 2748 2749 NewEntry->GlyphIndex = GlyphIndex; 2750 NewEntry->Face = Face; 2751 NewEntry->BitmapGlyph = BitmapGlyph; 2752 NewEntry->Height = Height; 2753 NewEntry->RenderMode = RenderMode; 2754 NewEntry->mxWorldToDevice = *pmx; 2755 2756 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry); 2757 if (++FontCacheNumEntries > MAX_FONT_CACHE) 2758 { 2759 NewEntry = CONTAINING_RECORD(FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry); 2760 RemoveCachedEntry(NewEntry); 2761 } 2762 2763 return BitmapGlyph; 2764 } 2765 2766 2767 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt) 2768 { 2769 pt->x.value = vec->x >> 6; 2770 pt->x.fract = (vec->x & 0x3f) << 10; 2771 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12)); 2772 pt->y.value = vec->y >> 6; 2773 pt->y.fract = (vec->y & 0x3f) << 10; 2774 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12)); 2775 } 2776 2777 /* 2778 This function builds an FT_Fixed from a float. It puts the integer part 2779 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed. 2780 It fails if the integer part of the float number is greater than SHORT_MAX. 2781 */ 2782 static __inline FT_Fixed FT_FixedFromFloat(float f) 2783 { 2784 short value = f; 2785 unsigned short fract = (f - value) * 0xFFFF; 2786 return (FT_Fixed)((long)value << 16 | (unsigned long)fract); 2787 } 2788 2789 /* 2790 This function builds an FT_Fixed from a FIXED. It simply put f.value 2791 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed. 2792 */ 2793 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f) 2794 { 2795 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract); 2796 } 2797 2798 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) 2799 { 2800 TTPOLYGONHEADER *pph; 2801 TTPOLYCURVE *ppc; 2802 int needed = 0, point = 0, contour, first_pt; 2803 unsigned int pph_start, cpfx; 2804 DWORD type; 2805 2806 for (contour = 0; contour < outline->n_contours; contour++) 2807 { 2808 /* Ignore contours containing one point */ 2809 if (point == outline->contours[contour]) 2810 { 2811 point++; 2812 continue; 2813 } 2814 2815 pph_start = needed; 2816 pph = (TTPOLYGONHEADER *)(buf + needed); 2817 first_pt = point; 2818 if (buf) 2819 { 2820 pph->dwType = TT_POLYGON_TYPE; 2821 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); 2822 } 2823 needed += sizeof(*pph); 2824 point++; 2825 while (point <= outline->contours[contour]) 2826 { 2827 ppc = (TTPOLYCURVE *)(buf + needed); 2828 type = outline->tags[point] & FT_Curve_Tag_On ? 2829 TT_PRIM_LINE : TT_PRIM_QSPLINE; 2830 cpfx = 0; 2831 do 2832 { 2833 if (buf) 2834 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); 2835 cpfx++; 2836 point++; 2837 } while (point <= outline->contours[contour] && 2838 (outline->tags[point] & FT_Curve_Tag_On) == 2839 (outline->tags[point-1] & FT_Curve_Tag_On)); 2840 /* At the end of a contour Windows adds the start point, but 2841 only for Beziers */ 2842 if (point > outline->contours[contour] && 2843 !(outline->tags[point-1] & FT_Curve_Tag_On)) 2844 { 2845 if (buf) 2846 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]); 2847 cpfx++; 2848 } 2849 else if (point <= outline->contours[contour] && 2850 outline->tags[point] & FT_Curve_Tag_On) 2851 { 2852 /* add closing pt for bezier */ 2853 if (buf) 2854 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); 2855 cpfx++; 2856 point++; 2857 } 2858 if (buf) 2859 { 2860 ppc->wType = type; 2861 ppc->cpfx = cpfx; 2862 } 2863 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); 2864 } 2865 if (buf) 2866 pph->cb = needed - pph_start; 2867 } 2868 return needed; 2869 } 2870 2871 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) 2872 { 2873 /* Convert the quadratic Beziers to cubic Beziers. 2874 The parametric eqn for a cubic Bezier is, from PLRM: 2875 r(t) = at^3 + bt^2 + ct + r0 2876 with the control points: 2877 r1 = r0 + c/3 2878 r2 = r1 + (c + b)/3 2879 r3 = r0 + c + b + a 2880 2881 A quadratic Bezier has the form: 2882 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2 2883 2884 So equating powers of t leads to: 2885 r1 = 2/3 p1 + 1/3 p0 2886 r2 = 2/3 p1 + 1/3 p2 2887 and of course r0 = p0, r3 = p2 2888 */ 2889 int contour, point = 0, first_pt; 2890 TTPOLYGONHEADER *pph; 2891 TTPOLYCURVE *ppc; 2892 DWORD pph_start, cpfx, type; 2893 FT_Vector cubic_control[4]; 2894 unsigned int needed = 0; 2895 2896 for (contour = 0; contour < outline->n_contours; contour++) 2897 { 2898 pph_start = needed; 2899 pph = (TTPOLYGONHEADER *)(buf + needed); 2900 first_pt = point; 2901 if (buf) 2902 { 2903 pph->dwType = TT_POLYGON_TYPE; 2904 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); 2905 } 2906 needed += sizeof(*pph); 2907 point++; 2908 while (point <= outline->contours[contour]) 2909 { 2910 ppc = (TTPOLYCURVE *)(buf + needed); 2911 type = outline->tags[point] & FT_Curve_Tag_On ? 2912 TT_PRIM_LINE : TT_PRIM_CSPLINE; 2913 cpfx = 0; 2914 do 2915 { 2916 if (type == TT_PRIM_LINE) 2917 { 2918 if (buf) 2919 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); 2920 cpfx++; 2921 point++; 2922 } 2923 else 2924 { 2925 /* Unlike QSPLINEs, CSPLINEs always have their endpoint 2926 so cpfx = 3n */ 2927 2928 /* FIXME: Possible optimization in endpoint calculation 2929 if there are two consecutive curves */ 2930 cubic_control[0] = outline->points[point-1]; 2931 if (!(outline->tags[point-1] & FT_Curve_Tag_On)) 2932 { 2933 cubic_control[0].x += outline->points[point].x + 1; 2934 cubic_control[0].y += outline->points[point].y + 1; 2935 cubic_control[0].x >>= 1; 2936 cubic_control[0].y >>= 1; 2937 } 2938 if (point+1 > outline->contours[contour]) 2939 cubic_control[3] = outline->points[first_pt]; 2940 else 2941 { 2942 cubic_control[3] = outline->points[point+1]; 2943 if (!(outline->tags[point+1] & FT_Curve_Tag_On)) 2944 { 2945 cubic_control[3].x += outline->points[point].x + 1; 2946 cubic_control[3].y += outline->points[point].y + 1; 2947 cubic_control[3].x >>= 1; 2948 cubic_control[3].y >>= 1; 2949 } 2950 } 2951 /* r1 = 1/3 p0 + 2/3 p1 2952 r2 = 1/3 p2 + 2/3 p1 */ 2953 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3; 2954 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3; 2955 cubic_control[2] = cubic_control[1]; 2956 cubic_control[1].x += (cubic_control[0].x + 1) / 3; 2957 cubic_control[1].y += (cubic_control[0].y + 1) / 3; 2958 cubic_control[2].x += (cubic_control[3].x + 1) / 3; 2959 cubic_control[2].y += (cubic_control[3].y + 1) / 3; 2960 if (buf) 2961 { 2962 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]); 2963 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]); 2964 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]); 2965 } 2966 cpfx += 3; 2967 point++; 2968 } 2969 } while (point <= outline->contours[contour] && 2970 (outline->tags[point] & FT_Curve_Tag_On) == 2971 (outline->tags[point-1] & FT_Curve_Tag_On)); 2972 /* At the end of a contour Windows adds the start point, 2973 but only for Beziers and we've already done that. 2974 */ 2975 if (point <= outline->contours[contour] && 2976 outline->tags[point] & FT_Curve_Tag_On) 2977 { 2978 /* This is the closing pt of a bezier, but we've already 2979 added it, so just inc point and carry on */ 2980 point++; 2981 } 2982 if (buf) 2983 { 2984 ppc->wType = type; 2985 ppc->cpfx = cpfx; 2986 } 2987 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); 2988 } 2989 if (buf) 2990 pph->cb = needed - pph_start; 2991 } 2992 return needed; 2993 } 2994 2995 static INT 2996 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height) 2997 { 2998 FT_Size_RequestRec req; 2999 3000 if (Width < 0) 3001 Width = -Width; 3002 3003 if (Height < 0) 3004 { 3005 Height = -Height; 3006 } 3007 if (Height == 0) 3008 { 3009 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight; 3010 } 3011 if (Height == 0) 3012 { 3013 Height = Width; 3014 } 3015 3016 if (Height < 1) 3017 Height = 1; 3018 3019 if (Width > 0xFFFFU) 3020 Width = 0xFFFFU; 3021 if (Height > 0xFFFFU) 3022 Height = 0xFFFFU; 3023 3024 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; 3025 req.width = (FT_Long)(Width << 6); 3026 req.height = (FT_Long)(Height << 6); 3027 req.horiResolution = 0; 3028 req.vertResolution = 0; 3029 return FT_Request_Size(face, &req); 3030 } 3031 3032 BOOL 3033 FASTCALL 3034 TextIntUpdateSize(PDC dc, 3035 PTEXTOBJ TextObj, 3036 PFONTGDI FontGDI, 3037 BOOL bDoLock) 3038 { 3039 FT_Face face; 3040 INT error, n; 3041 FT_CharMap charmap, found; 3042 LOGFONTW *plf; 3043 3044 if (bDoLock) 3045 IntLockFreeType; 3046 3047 face = FontGDI->SharedFace->Face; 3048 if (face->charmap == NULL) 3049 { 3050 DPRINT("WARNING: No charmap selected!\n"); 3051 DPRINT("This font face has %d charmaps\n", face->num_charmaps); 3052 3053 found = NULL; 3054 for (n = 0; n < face->num_charmaps; n++) 3055 { 3056 charmap = face->charmaps[n]; 3057 DPRINT("Found charmap encoding: %i\n", charmap->encoding); 3058 if (charmap->encoding != 0) 3059 { 3060 found = charmap; 3061 break; 3062 } 3063 } 3064 if (!found) 3065 { 3066 DPRINT1("WARNING: Could not find desired charmap!\n"); 3067 } 3068 else 3069 { 3070 error = FT_Set_Charmap(face, found); 3071 if (error) 3072 { 3073 DPRINT1("WARNING: Could not set the charmap!\n"); 3074 } 3075 } 3076 } 3077 3078 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 3079 3080 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight); 3081 3082 if (bDoLock) 3083 IntUnLockFreeType; 3084 3085 if (error) 3086 { 3087 DPRINT1("Error in setting pixel sizes: %d\n", error); 3088 return FALSE; 3089 } 3090 3091 return TRUE; 3092 } 3093 3094 3095 /* 3096 * Based on WineEngGetGlyphOutline 3097 * 3098 */ 3099 ULONG 3100 FASTCALL 3101 ftGdiGetGlyphOutline( 3102 PDC dc, 3103 WCHAR wch, 3104 UINT iFormat, 3105 LPGLYPHMETRICS pgm, 3106 ULONG cjBuf, 3107 PVOID pvBuf, 3108 LPMAT2 pmat2, 3109 BOOL bIgnoreRotation) 3110 { 3111 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)}; 3112 PDC_ATTR pdcattr; 3113 PTEXTOBJ TextObj; 3114 PFONTGDI FontGDI; 3115 HFONT hFont = 0; 3116 GLYPHMETRICS gm; 3117 ULONG Size; 3118 FT_Face ft_face; 3119 FT_UInt glyph_index; 3120 DWORD width, height, pitch, needed = 0; 3121 FT_Bitmap ft_bitmap; 3122 FT_Error error; 3123 INT left, right, top = 0, bottom = 0; 3124 FT_Angle angle = 0; 3125 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; 3126 FLOAT eM11, widthRatio = 1.0; 3127 FT_Matrix transMat = identityMat; 3128 BOOL needsTransform = FALSE; 3129 INT orientation; 3130 LONG aveWidth; 3131 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */ 3132 OUTLINETEXTMETRICW *potm; 3133 XFORM xForm; 3134 LOGFONTW *plf; 3135 3136 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm, 3137 cjBuf, pvBuf, pmat2); 3138 3139 pdcattr = dc->pdcattr; 3140 3141 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice); 3142 eM11 = xForm.eM11; 3143 3144 hFont = pdcattr->hlfntNew; 3145 TextObj = RealizeFontInit(hFont); 3146 3147 if (!TextObj) 3148 { 3149 EngSetLastError(ERROR_INVALID_HANDLE); 3150 return GDI_ERROR; 3151 } 3152 FontGDI = ObjToGDI(TextObj->Font, FONT); 3153 ft_face = FontGDI->SharedFace->Face; 3154 3155 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 3156 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0; 3157 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0; 3158 3159 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 3160 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 3161 if (!potm) 3162 { 3163 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 3164 TEXTOBJ_UnlockText(TextObj); 3165 return GDI_ERROR; 3166 } 3167 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm); 3168 if (!Size) 3169 { 3170 /* FIXME: last error? */ 3171 ExFreePoolWithTag(potm, GDITAG_TEXT); 3172 TEXTOBJ_UnlockText(TextObj); 3173 return GDI_ERROR; 3174 } 3175 3176 IntLockFreeType; 3177 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE); 3178 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc)); 3179 3180 TEXTOBJ_UnlockText(TextObj); 3181 3182 if (iFormat & GGO_GLYPH_INDEX) 3183 { 3184 glyph_index = wch; 3185 iFormat &= ~GGO_GLYPH_INDEX; 3186 } 3187 else glyph_index = FT_Get_Char_Index(ft_face, wch); 3188 3189 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2) 3190 load_flags |= FT_LOAD_NO_BITMAP; 3191 3192 if (iFormat & GGO_UNHINTED) 3193 { 3194 load_flags |= FT_LOAD_NO_HINTING; 3195 iFormat &= ~GGO_UNHINTED; 3196 } 3197 3198 error = FT_Load_Glyph(ft_face, glyph_index, load_flags); 3199 if (error) 3200 { 3201 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index); 3202 IntUnLockFreeType; 3203 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); 3204 return GDI_ERROR; 3205 } 3206 IntUnLockFreeType; 3207 3208 if (aveWidth && potm) 3209 { 3210 widthRatio = (FLOAT)aveWidth * eM11 / 3211 (FLOAT) potm->otmTextMetrics.tmAveCharWidth; 3212 } 3213 3214 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64; 3215 right = (INT)((ft_face->glyph->metrics.horiBearingX + 3216 ft_face->glyph->metrics.width) * widthRatio + 63) & -64; 3217 3218 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6; 3219 lsb = left >> 6; 3220 bbx = (right - left) >> 6; 3221 3222 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx); 3223 3224 IntLockFreeType; 3225 3226 /* Scaling transform */ 3227 /*if (aveWidth)*/ 3228 { 3229 3230 FT_Matrix ftmatrix; 3231 FLOATOBJ efTemp; 3232 3233 PMATRIX pmx = DC_pmxWorldToDevice(dc); 3234 3235 /* Create a freetype matrix, by converting to 16.16 fixpoint format */ 3236 efTemp = pmx->efM11; 3237 FLOATOBJ_MulLong(&efTemp, 0x00010000); 3238 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp); 3239 3240 efTemp = pmx->efM12; 3241 FLOATOBJ_MulLong(&efTemp, 0x00010000); 3242 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp); 3243 3244 efTemp = pmx->efM21; 3245 FLOATOBJ_MulLong(&efTemp, 0x00010000); 3246 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp); 3247 3248 efTemp = pmx->efM22; 3249 FLOATOBJ_MulLong(&efTemp, 0x00010000); 3250 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp); 3251 3252 FT_Matrix_Multiply(&ftmatrix, &transMat); 3253 needsTransform = TRUE; 3254 } 3255 3256 /* Rotation transform */ 3257 if (orientation) 3258 { 3259 FT_Matrix rotationMat; 3260 FT_Vector vecAngle; 3261 DPRINT("Rotation Trans!\n"); 3262 angle = FT_FixedFromFloat((float)orientation / 10.0); 3263 FT_Vector_Unit(&vecAngle, angle); 3264 rotationMat.xx = vecAngle.x; 3265 rotationMat.xy = -vecAngle.y; 3266 rotationMat.yx = -rotationMat.xy; 3267 rotationMat.yy = rotationMat.xx; 3268 FT_Matrix_Multiply(&rotationMat, &transMat); 3269 needsTransform = TRUE; 3270 } 3271 3272 /* Extra transformation specified by caller */ 3273 if (pmat2) 3274 { 3275 FT_Matrix extraMat; 3276 DPRINT("MAT2 Matrix Trans!\n"); 3277 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11); 3278 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21); 3279 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12); 3280 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22); 3281 FT_Matrix_Multiply(&extraMat, &transMat); 3282 needsTransform = TRUE; 3283 } 3284 3285 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */ 3286 3287 if (!needsTransform) 3288 { 3289 DPRINT("No Need to be Transformed!\n"); 3290 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64; 3291 bottom = (ft_face->glyph->metrics.horiBearingY - 3292 ft_face->glyph->metrics.height) & -64; 3293 gm.gmCellIncX = adv; 3294 gm.gmCellIncY = 0; 3295 } 3296 else 3297 { 3298 INT xc, yc; 3299 FT_Vector vec; 3300 for (xc = 0; xc < 2; xc++) 3301 { 3302 for (yc = 0; yc < 2; yc++) 3303 { 3304 vec.x = (ft_face->glyph->metrics.horiBearingX + 3305 xc * ft_face->glyph->metrics.width); 3306 vec.y = ft_face->glyph->metrics.horiBearingY - 3307 yc * ft_face->glyph->metrics.height; 3308 DPRINT("Vec %ld,%ld\n", vec.x, vec.y); 3309 FT_Vector_Transform(&vec, &transMat); 3310 if (xc == 0 && yc == 0) 3311 { 3312 left = right = vec.x; 3313 top = bottom = vec.y; 3314 } 3315 else 3316 { 3317 if (vec.x < left) left = vec.x; 3318 else if (vec.x > right) right = vec.x; 3319 if (vec.y < bottom) bottom = vec.y; 3320 else if (vec.y > top) top = vec.y; 3321 } 3322 } 3323 } 3324 left = left & -64; 3325 right = (right + 63) & -64; 3326 bottom = bottom & -64; 3327 top = (top + 63) & -64; 3328 3329 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom); 3330 vec.x = ft_face->glyph->metrics.horiAdvance; 3331 vec.y = 0; 3332 FT_Vector_Transform(&vec, &transMat); 3333 gm.gmCellIncX = (vec.x+63) >> 6; 3334 gm.gmCellIncY = -((vec.y+63) >> 6); 3335 } 3336 gm.gmBlackBoxX = (right - left) >> 6; 3337 gm.gmBlackBoxY = (top - bottom) >> 6; 3338 gm.gmptGlyphOrigin.x = left >> 6; 3339 gm.gmptGlyphOrigin.y = top >> 6; 3340 3341 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n", 3342 gm.gmCellIncX, gm.gmCellIncY, 3343 gm.gmBlackBoxX, gm.gmBlackBoxY, 3344 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y); 3345 3346 IntUnLockFreeType; 3347 3348 3349 if (iFormat == GGO_METRICS) 3350 { 3351 DPRINT("GGO_METRICS Exit!\n"); 3352 *pgm = gm; 3353 return 1; /* FIXME */ 3354 } 3355 3356 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP) 3357 { 3358 DPRINT1("Loaded a bitmap\n"); 3359 return GDI_ERROR; 3360 } 3361 3362 switch (iFormat) 3363 { 3364 case GGO_BITMAP: 3365 width = gm.gmBlackBoxX; 3366 height = gm.gmBlackBoxY; 3367 pitch = ((width + 31) >> 5) << 2; 3368 needed = pitch * height; 3369 3370 if (!pvBuf || !cjBuf) break; 3371 if (!needed) return GDI_ERROR; /* empty glyph */ 3372 if (needed > cjBuf) 3373 return GDI_ERROR; 3374 3375 switch (ft_face->glyph->format) 3376 { 3377 case ft_glyph_format_bitmap: 3378 { 3379 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf; 3380 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 ); 3381 INT h = min( height, ft_face->glyph->bitmap.rows ); 3382 while (h--) 3383 { 3384 RtlCopyMemory(dst, src, w); 3385 src += ft_face->glyph->bitmap.pitch; 3386 dst += pitch; 3387 } 3388 break; 3389 } 3390 3391 case ft_glyph_format_outline: 3392 ft_bitmap.width = width; 3393 ft_bitmap.rows = height; 3394 ft_bitmap.pitch = pitch; 3395 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO; 3396 ft_bitmap.buffer = pvBuf; 3397 3398 IntLockFreeType; 3399 if (needsTransform) 3400 { 3401 FT_Outline_Transform(&ft_face->glyph->outline, &transMat); 3402 } 3403 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); 3404 /* Note: FreeType will only set 'black' bits for us. */ 3405 RtlZeroMemory(pvBuf, needed); 3406 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); 3407 IntUnLockFreeType; 3408 break; 3409 3410 default: 3411 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format); 3412 return GDI_ERROR; 3413 } 3414 break; 3415 3416 case GGO_GRAY2_BITMAP: 3417 case GGO_GRAY4_BITMAP: 3418 case GGO_GRAY8_BITMAP: 3419 { 3420 unsigned int mult, row, col; 3421 BYTE *start, *ptr; 3422 3423 width = gm.gmBlackBoxX; 3424 height = gm.gmBlackBoxY; 3425 pitch = (width + 3) / 4 * 4; 3426 needed = pitch * height; 3427 3428 if (!pvBuf || !cjBuf) break; 3429 if (!needed) return GDI_ERROR; /* empty glyph */ 3430 if (needed > cjBuf) 3431 return GDI_ERROR; 3432 3433 switch (ft_face->glyph->format) 3434 { 3435 case ft_glyph_format_bitmap: 3436 { 3437 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf; 3438 INT h = min( height, ft_face->glyph->bitmap.rows ); 3439 INT x; 3440 while (h--) 3441 { 3442 for (x = 0; (UINT)x < pitch; x++) 3443 { 3444 if (x < ft_face->glyph->bitmap.width) 3445 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0; 3446 else 3447 dst[x] = 0; 3448 } 3449 src += ft_face->glyph->bitmap.pitch; 3450 dst += pitch; 3451 } 3452 break; 3453 } 3454 case ft_glyph_format_outline: 3455 { 3456 ft_bitmap.width = width; 3457 ft_bitmap.rows = height; 3458 ft_bitmap.pitch = pitch; 3459 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; 3460 ft_bitmap.buffer = pvBuf; 3461 3462 IntLockFreeType; 3463 if (needsTransform) 3464 { 3465 FT_Outline_Transform(&ft_face->glyph->outline, &transMat); 3466 } 3467 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); 3468 RtlZeroMemory(ft_bitmap.buffer, cjBuf); 3469 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); 3470 IntUnLockFreeType; 3471 3472 if (iFormat == GGO_GRAY2_BITMAP) 3473 mult = 4; 3474 else if (iFormat == GGO_GRAY4_BITMAP) 3475 mult = 16; 3476 else if (iFormat == GGO_GRAY8_BITMAP) 3477 mult = 64; 3478 else 3479 { 3480 return GDI_ERROR; 3481 } 3482 3483 start = pvBuf; 3484 for (row = 0; row < height; row++) 3485 { 3486 ptr = start; 3487 for (col = 0; col < width; col++, ptr++) 3488 { 3489 *ptr = (((int)*ptr) * mult + 128) / 256; 3490 } 3491 start += pitch; 3492 } 3493 3494 break; 3495 } 3496 default: 3497 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format); 3498 return GDI_ERROR; 3499 } 3500 } 3501 3502 case GGO_NATIVE: 3503 { 3504 FT_Outline *outline = &ft_face->glyph->outline; 3505 3506 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */ 3507 3508 IntLockFreeType; 3509 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat); 3510 3511 needed = get_native_glyph_outline(outline, cjBuf, NULL); 3512 3513 if (!pvBuf || !cjBuf) 3514 { 3515 IntUnLockFreeType; 3516 break; 3517 } 3518 if (needed > cjBuf) 3519 { 3520 IntUnLockFreeType; 3521 return GDI_ERROR; 3522 } 3523 get_native_glyph_outline(outline, cjBuf, pvBuf); 3524 IntUnLockFreeType; 3525 break; 3526 } 3527 case GGO_BEZIER: 3528 { 3529 FT_Outline *outline = &ft_face->glyph->outline; 3530 if (cjBuf == 0) pvBuf = NULL; 3531 3532 if (needsTransform && pvBuf) 3533 { 3534 IntLockFreeType; 3535 FT_Outline_Transform(outline, &transMat); 3536 IntUnLockFreeType; 3537 } 3538 needed = get_bezier_glyph_outline(outline, cjBuf, NULL); 3539 3540 if (!pvBuf || !cjBuf) 3541 break; 3542 if (needed > cjBuf) 3543 return GDI_ERROR; 3544 3545 get_bezier_glyph_outline(outline, cjBuf, pvBuf); 3546 break; 3547 } 3548 3549 default: 3550 DPRINT1("Unsupported format %u\n", iFormat); 3551 return GDI_ERROR; 3552 } 3553 3554 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed); 3555 *pgm = gm; 3556 return needed; 3557 } 3558 3559 BOOL 3560 FASTCALL 3561 TextIntGetTextExtentPoint(PDC dc, 3562 PTEXTOBJ TextObj, 3563 LPCWSTR String, 3564 INT Count, 3565 ULONG MaxExtent, 3566 LPINT Fit, 3567 LPINT Dx, 3568 LPSIZE Size, 3569 FLONG fl) 3570 { 3571 PFONTGDI FontGDI; 3572 FT_Face face; 3573 FT_GlyphSlot glyph; 3574 FT_BitmapGlyph realglyph; 3575 INT error, glyph_index, i, previous; 3576 ULONGLONG TotalWidth = 0; 3577 BOOL use_kerning; 3578 FT_Render_Mode RenderMode; 3579 BOOLEAN Render; 3580 PMATRIX pmxWorldToDevice; 3581 LOGFONTW *plf; 3582 BOOL EmuBold, EmuItalic; 3583 LONG ascender, descender; 3584 3585 FontGDI = ObjToGDI(TextObj->Font, FONT); 3586 3587 face = FontGDI->SharedFace->Face; 3588 if (NULL != Fit) 3589 { 3590 *Fit = 0; 3591 } 3592 3593 IntLockFreeType; 3594 3595 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE); 3596 3597 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 3598 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL); 3599 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic); 3600 3601 Render = IntIsFontRenderingEnabled(); 3602 if (Render) 3603 RenderMode = IntGetFontRenderMode(plf); 3604 else 3605 RenderMode = FT_RENDER_MODE_MONO; 3606 3607 /* Get the DC's world-to-device transformation matrix */ 3608 pmxWorldToDevice = DC_pmxWorldToDevice(dc); 3609 FtSetCoordinateTransform(face, pmxWorldToDevice); 3610 3611 use_kerning = FT_HAS_KERNING(face); 3612 previous = 0; 3613 3614 for (i = 0; i < Count; i++) 3615 { 3616 if (fl & GTEF_INDICES) 3617 glyph_index = *String; 3618 else 3619 glyph_index = FT_Get_Char_Index(face, *String); 3620 3621 if (EmuBold || EmuItalic) 3622 realglyph = NULL; 3623 else 3624 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight, 3625 RenderMode, pmxWorldToDevice); 3626 3627 if (EmuBold || EmuItalic || !realglyph) 3628 { 3629 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 3630 if (error) 3631 { 3632 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index); 3633 break; 3634 } 3635 3636 glyph = face->glyph; 3637 if (EmuBold || EmuItalic) 3638 { 3639 if (EmuBold) 3640 FT_GlyphSlot_Embolden(glyph); 3641 if (EmuItalic) 3642 FT_GlyphSlot_Oblique(glyph); 3643 realglyph = ftGdiGlyphSet(face, glyph, RenderMode); 3644 } 3645 else 3646 { 3647 realglyph = ftGdiGlyphCacheSet(face, 3648 glyph_index, 3649 plf->lfHeight, 3650 pmxWorldToDevice, 3651 glyph, 3652 RenderMode); 3653 } 3654 3655 if (!realglyph) 3656 { 3657 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index); 3658 break; 3659 } 3660 } 3661 3662 /* Retrieve kerning distance */ 3663 if (use_kerning && previous && glyph_index) 3664 { 3665 FT_Vector delta; 3666 FT_Get_Kerning(face, previous, glyph_index, 0, &delta); 3667 TotalWidth += delta.x; 3668 } 3669 3670 TotalWidth += realglyph->root.advance.x >> 10; 3671 3672 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit) 3673 { 3674 *Fit = i + 1; 3675 } 3676 if (NULL != Dx) 3677 { 3678 Dx[i] = (TotalWidth + 32) >> 6; 3679 } 3680 3681 if (EmuBold || EmuItalic) 3682 { 3683 FT_Done_Glyph((FT_Glyph)realglyph); 3684 realglyph = NULL; 3685 } 3686 3687 previous = glyph_index; 3688 String++; 3689 } 3690 ascender = (face->size->metrics.ascender + 32) >> 6; /* Units above baseline */ 3691 descender = (32 - face->size->metrics.descender) >> 6; /* Units below baseline */ 3692 IntUnLockFreeType; 3693 3694 Size->cx = (TotalWidth + 32) >> 6; 3695 Size->cy = ascender + descender; 3696 3697 return TRUE; 3698 } 3699 3700 3701 INT 3702 FASTCALL 3703 ftGdiGetTextCharsetInfo( 3704 PDC Dc, 3705 LPFONTSIGNATURE lpSig, 3706 DWORD dwFlags) 3707 { 3708 PDC_ATTR pdcattr; 3709 UINT Ret = DEFAULT_CHARSET; 3710 INT i; 3711 HFONT hFont; 3712 PTEXTOBJ TextObj; 3713 PFONTGDI FontGdi; 3714 FONTSIGNATURE fs; 3715 TT_OS2 *pOS2; 3716 FT_Face Face; 3717 CHARSETINFO csi; 3718 DWORD cp, fs0; 3719 USHORT usACP, usOEM; 3720 3721 pdcattr = Dc->pdcattr; 3722 hFont = pdcattr->hlfntNew; 3723 TextObj = RealizeFontInit(hFont); 3724 3725 if (!TextObj) 3726 { 3727 EngSetLastError(ERROR_INVALID_HANDLE); 3728 return Ret; 3729 } 3730 FontGdi = ObjToGDI(TextObj->Font, FONT); 3731 Face = FontGdi->SharedFace->Face; 3732 TEXTOBJ_UnlockText(TextObj); 3733 3734 IntLockFreeType; 3735 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); 3736 IntUnLockFreeType; 3737 memset(&fs, 0, sizeof(FONTSIGNATURE)); 3738 if (NULL != pOS2) 3739 { 3740 fs.fsCsb[0] = pOS2->ulCodePageRange1; 3741 fs.fsCsb[1] = pOS2->ulCodePageRange2; 3742 fs.fsUsb[0] = pOS2->ulUnicodeRange1; 3743 fs.fsUsb[1] = pOS2->ulUnicodeRange2; 3744 fs.fsUsb[2] = pOS2->ulUnicodeRange3; 3745 fs.fsUsb[3] = pOS2->ulUnicodeRange4; 3746 if (pOS2->version == 0) 3747 { 3748 FT_UInt dummy; 3749 3750 if (FT_Get_First_Char( Face, &dummy ) < 0x100) 3751 fs.fsCsb[0] |= FS_LATIN1; 3752 else 3753 fs.fsCsb[0] |= FS_SYMBOL; 3754 } 3755 } 3756 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]); 3757 if (fs.fsCsb[0] == 0) 3758 { /* Let's see if we can find any interesting cmaps */ 3759 for (i = 0; i < Face->num_charmaps; i++) 3760 { 3761 switch (Face->charmaps[i]->encoding) 3762 { 3763 case FT_ENCODING_UNICODE: 3764 case FT_ENCODING_APPLE_ROMAN: 3765 fs.fsCsb[0] |= FS_LATIN1; 3766 break; 3767 case FT_ENCODING_MS_SYMBOL: 3768 fs.fsCsb[0] |= FS_SYMBOL; 3769 break; 3770 default: 3771 break; 3772 } 3773 } 3774 } 3775 if (lpSig) 3776 { 3777 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE)); 3778 } 3779 3780 RtlGetDefaultCodePage(&usACP, &usOEM); 3781 cp = usACP; 3782 3783 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE)) 3784 if (csi.fs.fsCsb[0] & fs.fsCsb[0]) 3785 { 3786 DPRINT("Hit 1\n"); 3787 Ret = csi.ciCharset; 3788 goto Exit; 3789 } 3790 3791 for (i = 0; i < MAXTCIINDEX; i++) 3792 { 3793 fs0 = 1L << i; 3794 if (fs.fsCsb[0] & fs0) 3795 { 3796 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) 3797 { 3798 // *cp = csi.ciACP; 3799 DPRINT("Hit 2\n"); 3800 Ret = csi.ciCharset; 3801 goto Exit; 3802 } 3803 else 3804 DPRINT1("TCI failing on %x\n", fs0); 3805 } 3806 } 3807 Exit: 3808 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP); 3809 return (MAKELONG(csi.ciACP, csi.ciCharset)); 3810 } 3811 3812 3813 DWORD 3814 FASTCALL 3815 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset) 3816 { 3817 DWORD size = 0; 3818 DWORD num_ranges = 0; 3819 FT_Face face = Font->SharedFace->Face; 3820 3821 if (face->charmap->encoding == FT_ENCODING_UNICODE) 3822 { 3823 FT_UInt glyph_code = 0; 3824 FT_ULong char_code, char_code_prev; 3825 3826 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code); 3827 3828 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n", 3829 face->num_glyphs, glyph_code, char_code); 3830 3831 if (!glyph_code) return 0; 3832 3833 if (glyphset) 3834 { 3835 glyphset->ranges[0].wcLow = (USHORT)char_code; 3836 glyphset->ranges[0].cGlyphs = 0; 3837 glyphset->cGlyphsSupported = 0; 3838 } 3839 3840 num_ranges = 1; 3841 while (glyph_code) 3842 { 3843 if (char_code < char_code_prev) 3844 { 3845 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n"); 3846 return 0; 3847 } 3848 if (char_code - char_code_prev > 1) 3849 { 3850 num_ranges++; 3851 if (glyphset) 3852 { 3853 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code; 3854 glyphset->ranges[num_ranges - 1].cGlyphs = 1; 3855 glyphset->cGlyphsSupported++; 3856 } 3857 } 3858 else if (glyphset) 3859 { 3860 glyphset->ranges[num_ranges - 1].cGlyphs++; 3861 glyphset->cGlyphsSupported++; 3862 } 3863 char_code_prev = char_code; 3864 char_code = FT_Get_Next_Char(face, char_code, &glyph_code); 3865 } 3866 } 3867 else 3868 DPRINT1("Encoding %i not supported\n", face->charmap->encoding); 3869 3870 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1); 3871 if (glyphset) 3872 { 3873 glyphset->cbThis = size; 3874 glyphset->cRanges = num_ranges; 3875 glyphset->flAccel = 0; 3876 } 3877 return size; 3878 } 3879 3880 3881 BOOL 3882 FASTCALL 3883 ftGdiGetTextMetricsW( 3884 HDC hDC, 3885 PTMW_INTERNAL ptmwi) 3886 { 3887 PDC dc; 3888 PDC_ATTR pdcattr; 3889 PTEXTOBJ TextObj; 3890 PFONTGDI FontGDI; 3891 FT_Face Face; 3892 TT_OS2 *pOS2; 3893 TT_HoriHeader *pHori; 3894 FT_WinFNT_HeaderRec Win; 3895 ULONG Error; 3896 NTSTATUS Status = STATUS_SUCCESS; 3897 LOGFONTW *plf; 3898 3899 if (!ptmwi) 3900 { 3901 EngSetLastError(STATUS_INVALID_PARAMETER); 3902 return FALSE; 3903 } 3904 3905 if (!(dc = DC_LockDc(hDC))) 3906 { 3907 EngSetLastError(ERROR_INVALID_HANDLE); 3908 return FALSE; 3909 } 3910 pdcattr = dc->pdcattr; 3911 TextObj = RealizeFontInit(pdcattr->hlfntNew); 3912 if (NULL != TextObj) 3913 { 3914 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 3915 FontGDI = ObjToGDI(TextObj->Font, FONT); 3916 3917 Face = FontGDI->SharedFace->Face; 3918 IntLockFreeType; 3919 Error = IntRequestFontSize(dc, Face, plf->lfWidth, plf->lfHeight); 3920 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc)); 3921 IntUnLockFreeType; 3922 if (0 != Error) 3923 { 3924 DPRINT1("Error in setting pixel sizes: %u\n", Error); 3925 Status = STATUS_UNSUCCESSFUL; 3926 } 3927 else 3928 { 3929 FT_Face Face = FontGDI->SharedFace->Face; 3930 Status = STATUS_SUCCESS; 3931 3932 IntLockFreeType; 3933 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); 3934 if (NULL == pOS2) 3935 { 3936 DPRINT1("Can't find OS/2 table - not TT font?\n"); 3937 Status = STATUS_INTERNAL_ERROR; 3938 } 3939 3940 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea); 3941 if (NULL == pHori) 3942 { 3943 DPRINT1("Can't find HHEA table - not TT font?\n"); 3944 Status = STATUS_INTERNAL_ERROR; 3945 } 3946 3947 Error = FT_Get_WinFNT_Header(Face, &Win); 3948 3949 IntUnLockFreeType; 3950 3951 if (NT_SUCCESS(Status)) 3952 { 3953 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0); 3954 3955 /* FIXME: Fill Diff member */ 3956 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff)); 3957 } 3958 } 3959 TEXTOBJ_UnlockText(TextObj); 3960 } 3961 else 3962 { 3963 Status = STATUS_INVALID_HANDLE; 3964 } 3965 DC_UnlockDc(dc); 3966 3967 if (!NT_SUCCESS(Status)) 3968 { 3969 SetLastNtError(Status); 3970 return FALSE; 3971 } 3972 return TRUE; 3973 } 3974 3975 DWORD 3976 FASTCALL 3977 ftGdiGetFontData( 3978 PFONTGDI FontGdi, 3979 DWORD Table, 3980 DWORD Offset, 3981 PVOID Buffer, 3982 DWORD Size) 3983 { 3984 DWORD Result = GDI_ERROR; 3985 FT_Face Face = FontGdi->SharedFace->Face; 3986 3987 IntLockFreeType; 3988 3989 if (FT_IS_SFNT(Face)) 3990 { 3991 if (Table) 3992 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) | 3993 (Table << 8 & 0xFF0000); 3994 3995 if (!Buffer) Size = 0; 3996 3997 if (Buffer && Size) 3998 { 3999 FT_Error Error; 4000 FT_ULong Needed = 0; 4001 4002 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed); 4003 4004 if ( !Error && Needed < Size) Size = Needed; 4005 } 4006 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size)) 4007 Result = Size; 4008 } 4009 4010 IntUnLockFreeType; 4011 4012 return Result; 4013 } 4014 4015 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx 4016 static UINT 4017 GetFontPenalty(const LOGFONTW * LogFont, 4018 const OUTLINETEXTMETRICW * Otm, 4019 const char * style_name) 4020 { 4021 ULONG Penalty = 0; 4022 BYTE Byte; 4023 LONG Long; 4024 BOOL fNeedScaling = FALSE; 4025 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID); 4026 const TEXTMETRICW * TM = &Otm->otmTextMetrics; 4027 WCHAR* ActualNameW; 4028 4029 ASSERT(Otm); 4030 ASSERT(LogFont); 4031 ASSERT(style_name); 4032 4033 /* FIXME: Aspect Penalty 30 */ 4034 /* FIXME: IntSizeSynth Penalty 20 */ 4035 /* FIXME: SmallPenalty Penalty 1 */ 4036 /* FIXME: FaceNameSubst Penalty 500 */ 4037 4038 Byte = LogFont->lfCharSet; 4039 if (Byte == DEFAULT_CHARSET) 4040 { 4041 if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0) 4042 { 4043 if (Byte == ANSI_CHARSET) 4044 { 4045 DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n"); 4046 } 4047 /* We assume SYMBOL_CHARSET for "Marlett" font */ 4048 Byte = SYMBOL_CHARSET; 4049 } 4050 } 4051 4052 if (Byte != TM->tmCharSet) 4053 { 4054 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET) 4055 { 4056 /* CharSet Penalty 65000 */ 4057 /* Requested charset does not match the candidate's. */ 4058 Penalty += 65000; 4059 } 4060 else 4061 { 4062 if (UserCharSet != TM->tmCharSet) 4063 { 4064 /* UNDOCUMENTED */ 4065 Penalty += 100; 4066 if (ANSI_CHARSET != TM->tmCharSet) 4067 { 4068 /* UNDOCUMENTED */ 4069 Penalty += 100; 4070 } 4071 } 4072 } 4073 } 4074 4075 Byte = LogFont->lfOutPrecision; 4076 if (Byte == OUT_DEFAULT_PRECIS) 4077 Byte = OUT_OUTLINE_PRECIS; /* Is it OK? */ 4078 switch (Byte) 4079 { 4080 case OUT_DEVICE_PRECIS: 4081 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) || 4082 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))) 4083 { 4084 /* OutputPrecision Penalty 19000 */ 4085 /* Requested OUT_STROKE_PRECIS, but the device can't do it 4086 or the candidate is not a vector font. */ 4087 Penalty += 19000; 4088 } 4089 break; 4090 default: 4091 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)) 4092 { 4093 /* OutputPrecision Penalty 19000 */ 4094 /* Or OUT_STROKE_PRECIS not requested, and the candidate 4095 is a vector font that requires GDI support. */ 4096 Penalty += 19000; 4097 } 4098 break; 4099 } 4100 4101 Byte = (LogFont->lfPitchAndFamily & 0x0F); 4102 if (Byte == DEFAULT_PITCH) 4103 Byte = VARIABLE_PITCH; 4104 if (Byte == FIXED_PITCH) 4105 { 4106 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH) 4107 { 4108 /* FixedPitch Penalty 15000 */ 4109 /* Requested a fixed pitch font, but the candidate is a 4110 variable pitch font. */ 4111 Penalty += 15000; 4112 } 4113 } 4114 if (Byte == VARIABLE_PITCH) 4115 { 4116 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) 4117 { 4118 /* PitchVariable Penalty 350 */ 4119 /* Requested a variable pitch font, but the candidate is not a 4120 variable pitch font. */ 4121 Penalty += 350; 4122 } 4123 } 4124 4125 Byte = (LogFont->lfPitchAndFamily & 0x0F); 4126 if (Byte == DEFAULT_PITCH) 4127 { 4128 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) 4129 { 4130 /* DefaultPitchFixed Penalty 1 */ 4131 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */ 4132 Penalty += 1; 4133 } 4134 } 4135 4136 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName); 4137 4138 if (LogFont->lfFaceName[0]) 4139 { 4140 BOOL Found = FALSE; 4141 4142 /* localized family name */ 4143 if (!Found) 4144 { 4145 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0); 4146 } 4147 /* localized full name */ 4148 if (!Found) 4149 { 4150 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName); 4151 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0); 4152 } 4153 if (!Found) 4154 { 4155 /* FaceName Penalty 10000 */ 4156 /* Requested a face name, but the candidate's face name 4157 does not match. */ 4158 Penalty += 10000; 4159 } 4160 } 4161 4162 Byte = (LogFont->lfPitchAndFamily & 0xF0); 4163 if (Byte != FF_DONTCARE) 4164 { 4165 if (Byte != (TM->tmPitchAndFamily & 0xF0)) 4166 { 4167 /* Family Penalty 9000 */ 4168 /* Requested a family, but the candidate's family is different. */ 4169 Penalty += 9000; 4170 } 4171 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE) 4172 { 4173 /* FamilyUnknown Penalty 8000 */ 4174 /* Requested a family, but the candidate has no family. */ 4175 Penalty += 8000; 4176 } 4177 } 4178 4179 /* Is the candidate a non-vector font? */ 4180 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) 4181 { 4182 /* Is lfHeight specified? */ 4183 if (LogFont->lfHeight != 0) 4184 { 4185 if (labs(LogFont->lfHeight) < TM->tmHeight) 4186 { 4187 /* HeightBigger Penalty 600 */ 4188 /* The candidate is a nonvector font and is bigger than the 4189 requested height. */ 4190 Penalty += 600; 4191 /* HeightBiggerDifference Penalty 150 */ 4192 /* The candidate is a raster font and is larger than the 4193 requested height. Penalty * height difference */ 4194 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)); 4195 4196 fNeedScaling = TRUE; 4197 } 4198 if (TM->tmHeight < labs(LogFont->lfHeight)) 4199 { 4200 /* HeightSmaller Penalty 150 */ 4201 /* The candidate is a raster font and is smaller than the 4202 requested height. Penalty * height difference */ 4203 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)); 4204 4205 fNeedScaling = TRUE; 4206 } 4207 } 4208 } 4209 4210 switch (LogFont->lfPitchAndFamily & 0xF0) 4211 { 4212 case FF_ROMAN: case FF_MODERN: case FF_SWISS: 4213 switch (TM->tmPitchAndFamily & 0xF0) 4214 { 4215 case FF_DECORATIVE: case FF_SCRIPT: 4216 /* FamilyUnlikely Penalty 50 */ 4217 /* Requested a roman/modern/swiss family, but the 4218 candidate is decorative/script. */ 4219 Penalty += 50; 4220 break; 4221 default: 4222 break; 4223 } 4224 break; 4225 case FF_DECORATIVE: case FF_SCRIPT: 4226 switch (TM->tmPitchAndFamily & 0xF0) 4227 { 4228 case FF_ROMAN: case FF_MODERN: case FF_SWISS: 4229 /* FamilyUnlikely Penalty 50 */ 4230 /* Or requested decorative/script, and the candidate is 4231 roman/modern/swiss. */ 4232 Penalty += 50; 4233 break; 4234 default: 4235 break; 4236 } 4237 default: 4238 break; 4239 } 4240 4241 if (LogFont->lfWidth != 0) 4242 { 4243 if (LogFont->lfWidth != TM->tmAveCharWidth) 4244 { 4245 /* Width Penalty 50 */ 4246 /* Requested a nonzero width, but the candidate's width 4247 doesn't match. Penalty * width difference */ 4248 Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth); 4249 4250 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) 4251 fNeedScaling = TRUE; 4252 } 4253 } 4254 4255 if (fNeedScaling) 4256 { 4257 /* SizeSynth Penalty 50 */ 4258 /* The candidate is a raster font that needs scaling by GDI. */ 4259 Penalty += 50; 4260 } 4261 4262 if (!!LogFont->lfItalic != !!TM->tmItalic) 4263 { 4264 if (!LogFont->lfItalic && ItalicFromStyle(style_name)) 4265 { 4266 /* Italic Penalty 4 */ 4267 /* Requested font and candidate font do not agree on italic status, 4268 and the desired result cannot be simulated. */ 4269 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */ 4270 Penalty += 40; 4271 } 4272 else if (LogFont->lfItalic && !ItalicFromStyle(style_name)) 4273 { 4274 /* ItalicSim Penalty 1 */ 4275 /* Requested italic font but the candidate is not italic, 4276 although italics can be simulated. */ 4277 Penalty += 1; 4278 } 4279 } 4280 4281 if (LogFont->lfOutPrecision == OUT_TT_PRECIS) 4282 { 4283 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE)) 4284 { 4285 /* NotTrueType Penalty 4 */ 4286 /* Requested OUT_TT_PRECIS, but the candidate is not a 4287 TrueType font. */ 4288 Penalty += 4; 4289 } 4290 } 4291 4292 Long = LogFont->lfWeight; 4293 if (LogFont->lfWeight == FW_DONTCARE) 4294 Long = FW_NORMAL; 4295 if (Long != TM->tmWeight) 4296 { 4297 /* Weight Penalty 3 */ 4298 /* The candidate's weight does not match the requested weight. 4299 Penalty * (weight difference/10) */ 4300 Penalty += 3 * (labs(Long - TM->tmWeight) / 10); 4301 } 4302 4303 if (!LogFont->lfUnderline && TM->tmUnderlined) 4304 { 4305 /* Underline Penalty 3 */ 4306 /* Requested font has no underline, but the candidate is 4307 underlined. */ 4308 Penalty += 3; 4309 } 4310 4311 if (!LogFont->lfStrikeOut && TM->tmStruckOut) 4312 { 4313 /* StrikeOut Penalty 3 */ 4314 /* Requested font has no strike-out, but the candidate is 4315 struck out. */ 4316 Penalty += 3; 4317 } 4318 4319 /* Is the candidate a non-vector font? */ 4320 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) 4321 { 4322 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight) 4323 { 4324 /* VectorHeightSmaller Penalty 2 */ 4325 /* Candidate is a vector font that is smaller than the 4326 requested height. Penalty * height difference */ 4327 Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight); 4328 } 4329 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight) 4330 { 4331 /* VectorHeightBigger Penalty 1 */ 4332 /* Candidate is a vector font that is bigger than the 4333 requested height. Penalty * height difference */ 4334 Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight); 4335 } 4336 } 4337 4338 if (!(TM->tmPitchAndFamily & TMPF_DEVICE)) 4339 { 4340 /* DeviceFavor Penalty 2 */ 4341 /* Extra penalty for all nondevice fonts. */ 4342 Penalty += 2; 4343 } 4344 4345 if (Penalty < 200) 4346 { 4347 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, " 4348 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, " 4349 "tmCharSet:%d, tmWeight:%ld\n", 4350 Penalty, LogFont->lfFaceName, ActualNameW, 4351 LogFont->lfCharSet, LogFont->lfWeight, 4352 TM->tmCharSet, TM->tmWeight); 4353 } 4354 4355 return Penalty; /* success */ 4356 } 4357 4358 static __inline VOID 4359 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, 4360 const LOGFONTW *LogFont, 4361 const PLIST_ENTRY Head) 4362 { 4363 ULONG Penalty; 4364 PLIST_ENTRY Entry; 4365 PFONT_ENTRY CurrentEntry; 4366 FONTGDI *FontGDI; 4367 OUTLINETEXTMETRICW *Otm = NULL; 4368 UINT OtmSize, OldOtmSize = 0; 4369 FT_Face Face; 4370 4371 ASSERT(FontObj); 4372 ASSERT(MatchPenalty); 4373 ASSERT(LogFont); 4374 ASSERT(Head); 4375 4376 /* Start with a pretty big buffer */ 4377 OldOtmSize = 0x200; 4378 Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT); 4379 4380 /* get the FontObj of lowest penalty */ 4381 Entry = Head->Flink; 4382 while (Entry != Head) 4383 { 4384 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); 4385 Entry = Entry->Flink; 4386 4387 FontGDI = CurrentEntry->Font; 4388 ASSERT(FontGDI); 4389 Face = FontGDI->SharedFace->Face; 4390 4391 /* get text metrics */ 4392 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 4393 if (OtmSize > OldOtmSize) 4394 { 4395 if (Otm) 4396 ExFreePoolWithTag(Otm, GDITAG_TEXT); 4397 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT); 4398 } 4399 4400 /* update FontObj if lowest penalty */ 4401 if (Otm) 4402 { 4403 OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm); 4404 if (!OtmSize) 4405 continue; 4406 4407 OldOtmSize = OtmSize; 4408 4409 Penalty = GetFontPenalty(LogFont, Otm, Face->style_name); 4410 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty) 4411 { 4412 *FontObj = GDIToObj(FontGDI, FONT); 4413 *MatchPenalty = Penalty; 4414 } 4415 } 4416 } 4417 4418 if (Otm) 4419 ExFreePoolWithTag(Otm, GDITAG_TEXT); 4420 } 4421 4422 static 4423 VOID 4424 FASTCALL 4425 IntFontType(PFONTGDI Font) 4426 { 4427 PS_FontInfoRec psfInfo; 4428 FT_ULong tmp_size = 0; 4429 FT_Face Face = Font->SharedFace->Face; 4430 4431 if (FT_HAS_MULTIPLE_MASTERS(Face)) 4432 Font->FontObj.flFontType |= FO_MULTIPLEMASTER; 4433 if (FT_HAS_VERTICAL(Face)) 4434 Font->FontObj.flFontType |= FO_VERT_FACE; 4435 if (!FT_IS_SCALABLE(Face)) 4436 Font->FontObj.flFontType |= FO_TYPE_RASTER; 4437 if (FT_IS_SFNT(Face)) 4438 { 4439 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE; 4440 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post)) 4441 Font->FontObj.flFontType |= FO_POSTSCRIPT; 4442 } 4443 if (!FT_Get_PS_Font_Info(Face, &psfInfo )) 4444 { 4445 Font->FontObj.flFontType |= FO_POSTSCRIPT; 4446 } 4447 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */ 4448 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size)) 4449 { 4450 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT); 4451 } 4452 } 4453 4454 NTSTATUS 4455 FASTCALL 4456 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj) 4457 { 4458 NTSTATUS Status = STATUS_SUCCESS; 4459 PTEXTOBJ TextObj; 4460 PPROCESSINFO Win32Process; 4461 ULONG MatchPenalty; 4462 LOGFONTW *pLogFont; 4463 LOGFONTW SubstitutedLogFont; 4464 FT_Face Face; 4465 4466 if (!pTextObj) 4467 { 4468 TextObj = TEXTOBJ_LockText(FontHandle); 4469 if (NULL == TextObj) 4470 { 4471 return STATUS_INVALID_HANDLE; 4472 } 4473 4474 if (TextObj->fl & TEXTOBJECT_INIT) 4475 { 4476 TEXTOBJ_UnlockText(TextObj); 4477 return STATUS_SUCCESS; 4478 } 4479 } 4480 else 4481 { 4482 TextObj = pTextObj; 4483 } 4484 4485 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 4486 4487 /* substitute */ 4488 SubstitutedLogFont = *pLogFont; 4489 DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet); 4490 SubstituteFontRecurse(&SubstitutedLogFont); 4491 DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet); 4492 4493 MatchPenalty = 0xFFFFFFFF; 4494 TextObj->Font = NULL; 4495 4496 Win32Process = PsGetCurrentProcessWin32Process(); 4497 4498 /* Search private fonts */ 4499 IntLockProcessPrivateFonts(Win32Process); 4500 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont, 4501 &Win32Process->PrivateFontListHead); 4502 IntUnLockProcessPrivateFonts(Win32Process); 4503 4504 /* Search system fonts */ 4505 IntLockGlobalFonts; 4506 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont, 4507 &FontListHead); 4508 IntUnLockGlobalFonts; 4509 4510 if (NULL == TextObj->Font) 4511 { 4512 DPRINT1("Request font %S not found, no fonts loaded at all\n", 4513 pLogFont->lfFaceName); 4514 Status = STATUS_NOT_FOUND; 4515 } 4516 else 4517 { 4518 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT); 4519 // Need hdev, when freetype is loaded need to create DEVOBJ for 4520 // Consumer and Producer. 4521 TextObj->Font->iUniq = 1; // Now it can be cached. 4522 IntFontType(FontGdi); 4523 FontGdi->flType = TextObj->Font->flFontType; 4524 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0; 4525 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0; 4526 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0; 4527 if (pLogFont->lfWeight != FW_DONTCARE) 4528 FontGdi->RequestWeight = pLogFont->lfWeight; 4529 else 4530 FontGdi->RequestWeight = FW_NORMAL; 4531 4532 Face = FontGdi->SharedFace->Face; 4533 4534 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name); 4535 4536 if (!FontGdi->OriginalItalic) 4537 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name); 4538 4539 TextObj->fl |= TEXTOBJECT_INIT; 4540 Status = STATUS_SUCCESS; 4541 } 4542 4543 if (!pTextObj) TEXTOBJ_UnlockText(TextObj); 4544 4545 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0); 4546 4547 return Status; 4548 } 4549 4550 4551 static 4552 BOOL 4553 FASTCALL 4554 IntGetFullFileName( 4555 POBJECT_NAME_INFORMATION NameInfo, 4556 ULONG Size, 4557 PUNICODE_STRING FileName) 4558 { 4559 NTSTATUS Status; 4560 OBJECT_ATTRIBUTES ObjectAttributes; 4561 HANDLE hFile; 4562 IO_STATUS_BLOCK IoStatusBlock; 4563 ULONG Desired; 4564 4565 InitializeObjectAttributes(&ObjectAttributes, 4566 FileName, 4567 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 4568 NULL, 4569 NULL); 4570 4571 Status = ZwOpenFile( 4572 &hFile, 4573 0, // FILE_READ_ATTRIBUTES, 4574 &ObjectAttributes, 4575 &IoStatusBlock, 4576 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 4577 0); 4578 4579 if (!NT_SUCCESS(Status)) 4580 { 4581 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status); 4582 return FALSE; 4583 } 4584 4585 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired); 4586 ZwClose(hFile); 4587 if (!NT_SUCCESS(Status)) 4588 { 4589 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status); 4590 return FALSE; 4591 } 4592 4593 return TRUE; 4594 } 4595 4596 static BOOL 4597 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2) 4598 { 4599 const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx; 4600 const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx; 4601 const LOGFONTW *plf1 = &pLog1->elfLogFont; 4602 const LOGFONTW *plf2 = &pLog2->elfLogFont; 4603 4604 if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0) 4605 { 4606 return FALSE; 4607 } 4608 4609 if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0) 4610 { 4611 return FALSE; 4612 } 4613 4614 return TRUE; 4615 } 4616 4617 static VOID 4618 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo) 4619 { 4620 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName); 4621 if (FamInfo->EnumLogFontEx.elfStyle[0] && 4622 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0) 4623 { 4624 wcscat(psz, L" "); 4625 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle); 4626 } 4627 } 4628 4629 BOOL 4630 FASTCALL 4631 IntGdiGetFontResourceInfo( 4632 PUNICODE_STRING FileName, 4633 PVOID pBuffer, 4634 DWORD *pdwBytes, 4635 DWORD dwType) 4636 { 4637 UNICODE_STRING EntryFileName; 4638 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2; 4639 PLIST_ENTRY ListEntry; 4640 PFONT_ENTRY FontEntry; 4641 ULONG Size, i, Count; 4642 LPBYTE pbBuffer; 4643 BOOL IsEqual; 4644 FONTFAMILYINFO *FamInfo; 4645 const ULONG MaxFamInfo = 64; 4646 BOOL bSuccess; 4647 4648 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType); 4649 4650 /* Create buffer for full path name */ 4651 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR); 4652 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF); 4653 if (!NameInfo1) 4654 { 4655 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 4656 return FALSE; 4657 } 4658 4659 /* Get the full path name */ 4660 if (!IntGetFullFileName(NameInfo1, Size, FileName)) 4661 { 4662 ExFreePoolWithTag(NameInfo1, TAG_FINF); 4663 return FALSE; 4664 } 4665 4666 /* Create a buffer for the entries' names */ 4667 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF); 4668 if (!NameInfo2) 4669 { 4670 ExFreePoolWithTag(NameInfo1, TAG_FINF); 4671 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 4672 return FALSE; 4673 } 4674 4675 FamInfo = ExAllocatePoolWithTag(PagedPool, 4676 sizeof(FONTFAMILYINFO) * MaxFamInfo, 4677 TAG_FINF); 4678 if (!FamInfo) 4679 { 4680 ExFreePoolWithTag(NameInfo2, TAG_FINF); 4681 ExFreePoolWithTag(NameInfo1, TAG_FINF); 4682 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 4683 return FALSE; 4684 } 4685 /* Try to find the pathname in the global font list */ 4686 Count = 0; 4687 IntLockGlobalFonts; 4688 for (ListEntry = FontListHead.Flink; ListEntry != &FontListHead; 4689 ListEntry = ListEntry->Flink) 4690 { 4691 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry); 4692 if (FontEntry->Font->Filename == NULL) 4693 continue; 4694 4695 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename); 4696 if (!IntGetFullFileName(NameInfo2, Size, &EntryFileName)) 4697 continue; 4698 4699 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE)) 4700 continue; 4701 4702 IsEqual = FALSE; 4703 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer, 4704 NULL, FontEntry->Font); 4705 for (i = 0; i < Count; ++i) 4706 { 4707 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count])) 4708 { 4709 IsEqual = TRUE; 4710 break; 4711 } 4712 } 4713 if (!IsEqual) 4714 { 4715 /* Found */ 4716 ++Count; 4717 if (Count >= MaxFamInfo) 4718 break; 4719 } 4720 } 4721 IntUnLockGlobalFonts; 4722 4723 /* Free the buffers */ 4724 ExFreePoolWithTag(NameInfo1, TAG_FINF); 4725 ExFreePool(NameInfo2); 4726 4727 if (Count == 0 && dwType != 5) 4728 { 4729 /* Font could not be found in system table 4730 dwType == 5 will still handle this */ 4731 ExFreePoolWithTag(FamInfo, TAG_FINF); 4732 return FALSE; 4733 } 4734 4735 bSuccess = FALSE; 4736 switch (dwType) 4737 { 4738 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */ 4739 Size = sizeof(DWORD); 4740 if (*pdwBytes == 0) 4741 { 4742 *pdwBytes = Size; 4743 bSuccess = TRUE; 4744 } 4745 else if (pBuffer) 4746 { 4747 if (*pdwBytes >= Size) 4748 { 4749 *(DWORD*)pBuffer = Count; 4750 } 4751 *pdwBytes = Size; 4752 bSuccess = TRUE; 4753 } 4754 break; 4755 4756 case 1: /* copy the font title */ 4757 /* calculate the required size */ 4758 Size = 0; 4759 Size += wcslen(FamInfo[0].EnumLogFontEx.elfLogFont.lfFaceName); 4760 if (FamInfo[0].EnumLogFontEx.elfStyle[0] && 4761 _wcsicmp(FamInfo[0].EnumLogFontEx.elfStyle, L"Regular") != 0) 4762 { 4763 Size += 1 + wcslen(FamInfo[0].EnumLogFontEx.elfStyle); 4764 } 4765 for (i = 1; i < Count; ++i) 4766 { 4767 Size += 3; /* " & " */ 4768 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName); 4769 if (FamInfo[i].EnumLogFontEx.elfStyle[0] && 4770 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0) 4771 { 4772 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle); 4773 } 4774 } 4775 Size += 2; /* "\0\0" */ 4776 Size *= sizeof(WCHAR); 4777 4778 if (*pdwBytes == 0) 4779 { 4780 *pdwBytes = Size; 4781 bSuccess = TRUE; 4782 } 4783 else if (pBuffer) 4784 { 4785 if (*pdwBytes >= Size) 4786 { 4787 /* store font title to buffer */ 4788 WCHAR *psz = pBuffer; 4789 *psz = 0; 4790 IntAddNameFromFamInfo(psz, &FamInfo[0]); 4791 for (i = 1; i < Count; ++i) 4792 { 4793 wcscat(psz, L" & "); 4794 IntAddNameFromFamInfo(psz, &FamInfo[i]); 4795 } 4796 psz[wcslen(psz) + 1] = UNICODE_NULL; 4797 *pdwBytes = Size; 4798 bSuccess = TRUE; 4799 } 4800 else 4801 { 4802 *pdwBytes = 1024; /* this is confirmed value */ 4803 } 4804 } 4805 break; 4806 4807 case 2: /* Copy an array of LOGFONTW */ 4808 Size = Count * sizeof(LOGFONTW); 4809 if (*pdwBytes == 0) 4810 { 4811 *pdwBytes = Size; 4812 bSuccess = TRUE; 4813 } 4814 else if (pBuffer) 4815 { 4816 if (*pdwBytes >= Size) 4817 { 4818 pbBuffer = (LPBYTE)pBuffer; 4819 for (i = 0; i < Count; ++i) 4820 { 4821 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0; 4822 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW)); 4823 pbBuffer += sizeof(LOGFONTW); 4824 } 4825 } 4826 *pdwBytes = Size; 4827 bSuccess = TRUE; 4828 } 4829 else 4830 { 4831 *pdwBytes = 1024; /* this is confirmed value */ 4832 } 4833 break; 4834 4835 case 3: 4836 Size = sizeof(DWORD); 4837 if (*pdwBytes == 0) 4838 { 4839 *pdwBytes = Size; 4840 bSuccess = TRUE; 4841 } 4842 else if (pBuffer) 4843 { 4844 if (*pdwBytes >= Size) 4845 { 4846 /* FIXME: What exactly is copied here? */ 4847 *(DWORD*)pBuffer = 1; 4848 } 4849 *pdwBytes = Size; 4850 bSuccess = TRUE; 4851 } 4852 break; 4853 4854 case 4: /* full file path */ 4855 if (FileName->Length >= 4 * sizeof(WCHAR)) 4856 { 4857 /* The beginning of FileName is \??\ */ 4858 LPWSTR pch = FileName->Buffer + 4; 4859 DWORD Length = FileName->Length - 4 * sizeof(WCHAR); 4860 4861 Size = Length + sizeof(WCHAR); 4862 if (*pdwBytes == 0) 4863 { 4864 *pdwBytes = Size; 4865 bSuccess = TRUE; 4866 } 4867 else if (pBuffer) 4868 { 4869 if (*pdwBytes >= Size) 4870 { 4871 RtlCopyMemory(pBuffer, pch, Size); 4872 } 4873 *pdwBytes = Size; 4874 bSuccess = TRUE; 4875 } 4876 } 4877 break; 4878 4879 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */ 4880 Size = sizeof(BOOL); 4881 if (*pdwBytes == 0) 4882 { 4883 *pdwBytes = Size; 4884 bSuccess = TRUE; 4885 } 4886 else if (pBuffer) 4887 { 4888 if (*pdwBytes >= Size) 4889 { 4890 *(BOOL*)pBuffer = Count == 0; 4891 } 4892 *pdwBytes = Size; 4893 bSuccess = TRUE; 4894 } 4895 break; 4896 } 4897 ExFreePoolWithTag(FamInfo, TAG_FINF); 4898 4899 return bSuccess; 4900 } 4901 4902 4903 BOOL 4904 FASTCALL 4905 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info) 4906 { 4907 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face)) 4908 Info->iTechnology = RI_TECH_BITMAP; 4909 else 4910 { 4911 if (FT_IS_SCALABLE(Font->SharedFace->Face)) 4912 Info->iTechnology = RI_TECH_SCALABLE; 4913 else 4914 Info->iTechnology = RI_TECH_FIXED; 4915 } 4916 Info->iUniq = Font->FontObj.iUniq; 4917 Info->dwUnknown = -1; 4918 return TRUE; 4919 } 4920 4921 4922 DWORD 4923 FASTCALL 4924 ftGdiGetKerningPairs( PFONTGDI Font, 4925 DWORD cPairs, 4926 LPKERNINGPAIR pKerningPair) 4927 { 4928 DWORD Count = 0; 4929 INT i = 0; 4930 FT_Face face = Font->SharedFace->Face; 4931 4932 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE) 4933 { 4934 FT_UInt previous_index = 0, glyph_index = 0; 4935 FT_ULong char_code, char_previous; 4936 FT_Vector delta; 4937 4938 char_previous = char_code = FT_Get_First_Char(face, &glyph_index); 4939 4940 IntLockFreeType; 4941 4942 while (glyph_index) 4943 { 4944 if (previous_index && glyph_index) 4945 { 4946 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta); 4947 4948 if (pKerningPair && cPairs) 4949 { 4950 pKerningPair[i].wFirst = char_previous; 4951 pKerningPair[i].wSecond = char_code; 4952 pKerningPair[i].iKernAmount = delta.x; 4953 i++; 4954 if (i == cPairs) break; 4955 } 4956 Count++; 4957 } 4958 previous_index = glyph_index; 4959 char_previous = char_code; 4960 char_code = FT_Get_Next_Char(face, char_code, &glyph_index); 4961 } 4962 IntUnLockFreeType; 4963 } 4964 return Count; 4965 } 4966 4967 4968 /////////////////////////////////////////////////////////////////////////// 4969 // 4970 // Functions needing sorting. 4971 // 4972 /////////////////////////////////////////////////////////////////////////// 4973 int APIENTRY 4974 NtGdiGetFontFamilyInfo(HDC Dc, 4975 LPLOGFONTW UnsafeLogFont, 4976 PFONTFAMILYINFO UnsafeInfo, 4977 DWORD Size) 4978 { 4979 NTSTATUS Status; 4980 LOGFONTW LogFont; 4981 PFONTFAMILYINFO Info; 4982 DWORD Count; 4983 PPROCESSINFO Win32Process; 4984 4985 /* Make a safe copy */ 4986 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW)); 4987 if (! NT_SUCCESS(Status)) 4988 { 4989 EngSetLastError(ERROR_INVALID_PARAMETER); 4990 return -1; 4991 } 4992 4993 /* Allocate space for a safe copy */ 4994 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT); 4995 if (NULL == Info) 4996 { 4997 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 4998 return -1; 4999 } 5000 5001 /* Enumerate font families in the global list */ 5002 IntLockGlobalFonts; 5003 Count = 0; 5004 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) ) 5005 { 5006 IntUnLockGlobalFonts; 5007 ExFreePoolWithTag(Info, GDITAG_TEXT); 5008 return -1; 5009 } 5010 IntUnLockGlobalFonts; 5011 5012 /* Enumerate font families in the process local list */ 5013 Win32Process = PsGetCurrentProcessWin32Process(); 5014 IntLockProcessPrivateFonts(Win32Process); 5015 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, 5016 &Win32Process->PrivateFontListHead)) 5017 { 5018 IntUnLockProcessPrivateFonts(Win32Process); 5019 ExFreePoolWithTag(Info, GDITAG_TEXT); 5020 return -1; 5021 } 5022 IntUnLockProcessPrivateFonts(Win32Process); 5023 5024 /* Enumerate font families in the registry */ 5025 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size)) 5026 { 5027 ExFreePoolWithTag(Info, GDITAG_TEXT); 5028 return -1; 5029 } 5030 5031 /* Return data to caller */ 5032 if (0 != Count) 5033 { 5034 Status = MmCopyToCaller(UnsafeInfo, Info, 5035 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO)); 5036 if (! NT_SUCCESS(Status)) 5037 { 5038 ExFreePoolWithTag(Info, GDITAG_TEXT); 5039 EngSetLastError(ERROR_INVALID_PARAMETER); 5040 return -1; 5041 } 5042 } 5043 5044 ExFreePoolWithTag(Info, GDITAG_TEXT); 5045 5046 return Count; 5047 } 5048 5049 FORCEINLINE 5050 LONG 5051 ScaleLong(LONG lValue, PFLOATOBJ pef) 5052 { 5053 FLOATOBJ efTemp; 5054 5055 /* Check if we have scaling different from 1 */ 5056 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1)) 5057 { 5058 /* Need to multiply */ 5059 FLOATOBJ_SetLong(&efTemp, lValue); 5060 FLOATOBJ_Mul(&efTemp, pef); 5061 lValue = FLOATOBJ_GetLong(&efTemp); 5062 } 5063 5064 return lValue; 5065 } 5066 5067 BOOL 5068 APIENTRY 5069 GreExtTextOutW( 5070 IN HDC hDC, 5071 IN INT XStart, 5072 IN INT YStart, 5073 IN UINT fuOptions, 5074 IN OPTIONAL PRECTL lprc, 5075 IN LPCWSTR String, 5076 IN INT Count, 5077 IN OPTIONAL LPINT Dx, 5078 IN DWORD dwCodePage) 5079 { 5080 /* 5081 * FIXME: 5082 * Call EngTextOut, which does the real work (calling DrvTextOut where 5083 * appropriate) 5084 */ 5085 5086 DC *dc; 5087 PDC_ATTR pdcattr; 5088 SURFOBJ *SurfObj; 5089 SURFACE *psurf = NULL; 5090 int error, glyph_index, i; 5091 FT_Face face; 5092 FT_GlyphSlot glyph; 5093 FT_BitmapGlyph realglyph; 5094 LONGLONG TextLeft, RealXStart; 5095 ULONG TextTop, previous, BackgroundLeft; 5096 FT_Bool use_kerning; 5097 RECTL DestRect, MaskRect; 5098 POINTL SourcePoint, BrushOrigin; 5099 HBITMAP HSourceGlyph; 5100 SURFOBJ *SourceGlyphSurf; 5101 SIZEL bitSize; 5102 INT yoff; 5103 FONTOBJ *FontObj; 5104 PFONTGDI FontGDI; 5105 PTEXTOBJ TextObj = NULL; 5106 EXLATEOBJ exloRGB2Dst, exloDst2RGB; 5107 FT_Render_Mode RenderMode; 5108 BOOLEAN Render; 5109 POINT Start; 5110 BOOL DoBreak = FALSE; 5111 USHORT DxShift; 5112 PMATRIX pmxWorldToDevice; 5113 LONG fixAscender, fixDescender; 5114 FLOATOBJ Scale; 5115 LOGFONTW *plf; 5116 BOOL EmuBold, EmuItalic; 5117 int thickness; 5118 BOOL bResult; 5119 5120 /* Check if String is valid */ 5121 if ((Count > 0xFFFF) || (Count > 0 && String == NULL)) 5122 { 5123 EngSetLastError(ERROR_INVALID_PARAMETER); 5124 return FALSE; 5125 } 5126 5127 /* NOTE: This function locks the screen DC, so it must never be called 5128 with a DC already locked */ 5129 Render = IntIsFontRenderingEnabled(); 5130 5131 // TODO: Write test-cases to exactly match real Windows in different 5132 // bad parameters (e.g. does Windows check the DC or the RECT first?). 5133 dc = DC_LockDc(hDC); 5134 if (!dc) 5135 { 5136 EngSetLastError(ERROR_INVALID_HANDLE); 5137 return FALSE; 5138 } 5139 5140 if (PATH_IsPathOpen(dc->dclevel)) 5141 { 5142 bResult = PATH_ExtTextOut(dc, 5143 XStart, 5144 YStart, 5145 fuOptions, 5146 (const RECTL *)lprc, 5147 String, 5148 Count, 5149 (const INT *)Dx); 5150 DC_UnlockDc(dc); 5151 return bResult; 5152 } 5153 5154 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL); 5155 5156 if (!dc->dclevel.pSurface) 5157 { 5158 /* Memory DC with no surface selected */ 5159 bResult = TRUE; 5160 goto Cleanup; 5161 } 5162 5163 pdcattr = dc->pdcattr; 5164 5165 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED))) 5166 { 5167 IntLPtoDP(dc, (POINT *)lprc, 2); 5168 } 5169 5170 if (pdcattr->lTextAlign & TA_UPDATECP) 5171 { 5172 Start.x = pdcattr->ptlCurrent.x; 5173 Start.y = pdcattr->ptlCurrent.y; 5174 } else { 5175 Start.x = XStart; 5176 Start.y = YStart; 5177 } 5178 5179 IntLPtoDP(dc, &Start, 1); 5180 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6; 5181 YStart = Start.y + dc->ptlDCOrig.y; 5182 5183 SourcePoint.x = 0; 5184 SourcePoint.y = 0; 5185 MaskRect.left = 0; 5186 MaskRect.top = 0; 5187 BrushOrigin.x = 0; 5188 BrushOrigin.y = 0; 5189 5190 if ((fuOptions & ETO_OPAQUE) && lprc) 5191 { 5192 DestRect.left = lprc->left; 5193 DestRect.top = lprc->top; 5194 DestRect.right = lprc->right; 5195 DestRect.bottom = lprc->bottom; 5196 5197 DestRect.left += dc->ptlDCOrig.x; 5198 DestRect.top += dc->ptlDCOrig.y; 5199 DestRect.right += dc->ptlDCOrig.x; 5200 DestRect.bottom += dc->ptlDCOrig.y; 5201 5202 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 5203 { 5204 IntUpdateBoundsRect(dc, &DestRect); 5205 } 5206 5207 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND) 5208 DC_vUpdateBackgroundBrush(dc); 5209 if (dc->dctype == DCTYPE_DIRECT) 5210 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom); 5211 5212 psurf = dc->dclevel.pSurface; 5213 IntEngBitBlt( 5214 &psurf->SurfObj, 5215 NULL, 5216 NULL, 5217 (CLIPOBJ *)&dc->co, 5218 NULL, 5219 &DestRect, 5220 &SourcePoint, 5221 &SourcePoint, 5222 &dc->eboBackground.BrushObject, 5223 &BrushOrigin, 5224 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); 5225 5226 if (dc->dctype == DCTYPE_DIRECT) 5227 MouseSafetyOnDrawEnd(dc->ppdev); 5228 5229 fuOptions &= ~ETO_OPAQUE; 5230 } 5231 else 5232 { 5233 if (pdcattr->jBkMode == OPAQUE) 5234 { 5235 fuOptions |= ETO_OPAQUE; 5236 } 5237 } 5238 5239 TextObj = RealizeFontInit(pdcattr->hlfntNew); 5240 if (TextObj == NULL) 5241 { 5242 bResult = FALSE; 5243 goto Cleanup; 5244 } 5245 5246 FontObj = TextObj->Font; 5247 ASSERT(FontObj); 5248 FontGDI = ObjToGDI(FontObj, FONT); 5249 ASSERT(FontGDI); 5250 5251 IntLockFreeType; 5252 face = FontGDI->SharedFace->Face; 5253 5254 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 5255 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL); 5256 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic); 5257 5258 if (Render) 5259 RenderMode = IntGetFontRenderMode(plf); 5260 else 5261 RenderMode = FT_RENDER_MODE_MONO; 5262 5263 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE)) 5264 { 5265 IntUnLockFreeType; 5266 bResult = FALSE; 5267 goto Cleanup; 5268 } 5269 5270 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED) 5271 { 5272 pmxWorldToDevice = DC_pmxWorldToDevice(dc); 5273 FtSetCoordinateTransform(face, pmxWorldToDevice); 5274 5275 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22); 5276 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22); 5277 } 5278 else 5279 { 5280 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault; 5281 FtSetCoordinateTransform(face, pmxWorldToDevice); 5282 5283 fixAscender = face->size->metrics.ascender; 5284 fixDescender = face->size->metrics.descender; 5285 } 5286 5287 /* 5288 * Process the vertical alignment and determine the yoff. 5289 */ 5290 5291 if (pdcattr->lTextAlign & TA_BASELINE) 5292 yoff = 0; 5293 else if (pdcattr->lTextAlign & TA_BOTTOM) 5294 yoff = -fixDescender >> 6; 5295 else /* TA_TOP */ 5296 yoff = fixAscender >> 6; 5297 5298 use_kerning = FT_HAS_KERNING(face); 5299 previous = 0; 5300 5301 /* 5302 * Process the horizontal alignment and modify XStart accordingly. 5303 */ 5304 DxShift = fuOptions & ETO_PDY ? 1 : 0; 5305 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER)) 5306 { 5307 ULONGLONG TextWidth = 0; 5308 LPCWSTR TempText = String; 5309 int iStart; 5310 5311 /* 5312 * Calculate width of the text. 5313 */ 5314 5315 if (NULL != Dx) 5316 { 5317 iStart = Count < 2 ? 0 : Count - 2; 5318 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6); 5319 } 5320 else 5321 { 5322 iStart = 0; 5323 } 5324 TempText = String + iStart; 5325 5326 for (i = iStart; i < Count; i++) 5327 { 5328 if (fuOptions & ETO_GLYPH_INDEX) 5329 glyph_index = *TempText; 5330 else 5331 glyph_index = FT_Get_Char_Index(face, *TempText); 5332 5333 if (EmuBold || EmuItalic) 5334 realglyph = NULL; 5335 else 5336 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight, 5337 RenderMode, pmxWorldToDevice); 5338 if (!realglyph) 5339 { 5340 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 5341 if (error) 5342 { 5343 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index); 5344 } 5345 5346 glyph = face->glyph; 5347 if (EmuBold || EmuItalic) 5348 { 5349 if (EmuBold) 5350 FT_GlyphSlot_Embolden(glyph); 5351 if (EmuItalic) 5352 FT_GlyphSlot_Oblique(glyph); 5353 realglyph = ftGdiGlyphSet(face, glyph, RenderMode); 5354 } 5355 else 5356 { 5357 realglyph = ftGdiGlyphCacheSet(face, 5358 glyph_index, 5359 plf->lfHeight, 5360 pmxWorldToDevice, 5361 glyph, 5362 RenderMode); 5363 } 5364 if (!realglyph) 5365 { 5366 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index); 5367 IntUnLockFreeType; 5368 goto Cleanup; 5369 } 5370 5371 } 5372 /* Retrieve kerning distance */ 5373 if (use_kerning && previous && glyph_index) 5374 { 5375 FT_Vector delta; 5376 FT_Get_Kerning(face, previous, glyph_index, 0, &delta); 5377 TextWidth += delta.x; 5378 } 5379 5380 TextWidth += realglyph->root.advance.x >> 10; 5381 5382 if (EmuBold || EmuItalic) 5383 { 5384 FT_Done_Glyph((FT_Glyph)realglyph); 5385 realglyph = NULL; 5386 } 5387 5388 previous = glyph_index; 5389 TempText++; 5390 } 5391 5392 previous = 0; 5393 5394 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER) 5395 { 5396 RealXStart -= TextWidth / 2; 5397 } 5398 else 5399 { 5400 RealXStart -= TextWidth; 5401 } 5402 } 5403 5404 psurf = dc->dclevel.pSurface; 5405 SurfObj = &psurf->SurfObj ; 5406 5407 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND)) 5408 DC_vUpdateBackgroundBrush(dc) ; 5409 5410 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT) 5411 DC_vUpdateTextBrush(dc) ; 5412 5413 if (!face->units_per_EM) 5414 { 5415 thickness = 1; 5416 } 5417 else 5418 { 5419 thickness = face->underline_thickness * 5420 face->size->metrics.y_ppem / face->units_per_EM; 5421 if (thickness <= 0) 5422 thickness = 1; 5423 } 5424 5425 if ((fuOptions & ETO_OPAQUE) && plf->lfItalic) 5426 { 5427 /* Draw background */ 5428 TextLeft = RealXStart; 5429 TextTop = YStart; 5430 BackgroundLeft = (RealXStart + 32) >> 6; 5431 for (i = 0; i < Count; ++i) 5432 { 5433 if (fuOptions & ETO_GLYPH_INDEX) 5434 glyph_index = String[i]; 5435 else 5436 glyph_index = FT_Get_Char_Index(face, String[i]); 5437 5438 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 5439 if (error) 5440 { 5441 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index); 5442 IntUnLockFreeType; 5443 goto Cleanup; 5444 } 5445 5446 glyph = face->glyph; 5447 if (EmuBold) 5448 FT_GlyphSlot_Embolden(glyph); 5449 if (EmuItalic) 5450 FT_GlyphSlot_Oblique(glyph); 5451 realglyph = ftGdiGlyphSet(face, glyph, RenderMode); 5452 if (!realglyph) 5453 { 5454 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index); 5455 IntUnLockFreeType; 5456 goto Cleanup; 5457 } 5458 5459 /* retrieve kerning distance and move pen position */ 5460 if (use_kerning && previous && glyph_index && NULL == Dx) 5461 { 5462 FT_Vector delta; 5463 FT_Get_Kerning(face, previous, glyph_index, 0, &delta); 5464 TextLeft += delta.x; 5465 } 5466 DPRINT("TextLeft: %I64d\n", TextLeft); 5467 DPRINT("TextTop: %lu\n", TextTop); 5468 DPRINT("Advance: %d\n", realglyph->root.advance.x); 5469 5470 DestRect.left = BackgroundLeft; 5471 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6; 5472 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6); 5473 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6); 5474 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom); 5475 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 5476 { 5477 IntUpdateBoundsRect(dc, &DestRect); 5478 } 5479 IntEngBitBlt( 5480 &psurf->SurfObj, 5481 NULL, 5482 NULL, 5483 (CLIPOBJ *)&dc->co, 5484 NULL, 5485 &DestRect, 5486 &SourcePoint, 5487 &SourcePoint, 5488 &dc->eboBackground.BrushObject, 5489 &BrushOrigin, 5490 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); 5491 MouseSafetyOnDrawEnd(dc->ppdev); 5492 BackgroundLeft = DestRect.right; 5493 5494 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left; 5495 DestRect.right = DestRect.left + realglyph->bitmap.width; 5496 DestRect.top = TextTop + yoff - realglyph->top; 5497 DestRect.bottom = DestRect.top + realglyph->bitmap.rows; 5498 5499 bitSize.cx = realglyph->bitmap.width; 5500 bitSize.cy = realglyph->bitmap.rows; 5501 MaskRect.right = realglyph->bitmap.width; 5502 MaskRect.bottom = realglyph->bitmap.rows; 5503 5504 if (NULL == Dx) 5505 { 5506 TextLeft += realglyph->root.advance.x >> 10; 5507 DPRINT("New TextLeft: %I64d\n", TextLeft); 5508 } 5509 else 5510 { 5511 // FIXME this should probably be a matrix transform with TextTop as well. 5512 Scale = pdcattr->mxWorldToDevice.efM11; 5513 if (FLOATOBJ_Equal0(&Scale)) 5514 FLOATOBJ_Set1(&Scale); 5515 5516 /* do the shift before multiplying to preserve precision */ 5517 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6); 5518 TextLeft += FLOATOBJ_GetLong(&Scale); 5519 DPRINT("New TextLeft2: %I64d\n", TextLeft); 5520 } 5521 5522 if (DxShift) 5523 { 5524 TextTop -= Dx[2 * i + 1] << 6; 5525 } 5526 5527 previous = glyph_index; 5528 5529 if (EmuBold || EmuItalic) 5530 { 5531 FT_Done_Glyph((FT_Glyph)realglyph); 5532 realglyph = NULL; 5533 } 5534 } 5535 } 5536 5537 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0); 5538 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0); 5539 5540 /* Assume success */ 5541 bResult = TRUE; 5542 5543 /* 5544 * The main rendering loop. 5545 */ 5546 TextLeft = RealXStart; 5547 TextTop = YStart; 5548 BackgroundLeft = (RealXStart + 32) >> 6; 5549 for (i = 0; i < Count; ++i) 5550 { 5551 if (fuOptions & ETO_GLYPH_INDEX) 5552 glyph_index = String[i]; 5553 else 5554 glyph_index = FT_Get_Char_Index(face, String[i]); 5555 5556 if (EmuBold || EmuItalic) 5557 realglyph = NULL; 5558 else 5559 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight, 5560 RenderMode, pmxWorldToDevice); 5561 if (!realglyph) 5562 { 5563 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 5564 if (error) 5565 { 5566 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index); 5567 bResult = FALSE; 5568 break; 5569 } 5570 5571 glyph = face->glyph; 5572 if (EmuBold || EmuItalic) 5573 { 5574 if (EmuBold) 5575 FT_GlyphSlot_Embolden(glyph); 5576 if (EmuItalic) 5577 FT_GlyphSlot_Oblique(glyph); 5578 realglyph = ftGdiGlyphSet(face, glyph, RenderMode); 5579 } 5580 else 5581 { 5582 realglyph = ftGdiGlyphCacheSet(face, 5583 glyph_index, 5584 plf->lfHeight, 5585 pmxWorldToDevice, 5586 glyph, 5587 RenderMode); 5588 } 5589 if (!realglyph) 5590 { 5591 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index); 5592 bResult = FALSE; 5593 break; 5594 } 5595 } 5596 5597 /* retrieve kerning distance and move pen position */ 5598 if (use_kerning && previous && glyph_index && NULL == Dx) 5599 { 5600 FT_Vector delta; 5601 FT_Get_Kerning(face, previous, glyph_index, 0, &delta); 5602 TextLeft += delta.x; 5603 } 5604 DPRINT("TextLeft: %I64d\n", TextLeft); 5605 DPRINT("TextTop: %lu\n", TextTop); 5606 DPRINT("Advance: %d\n", realglyph->root.advance.x); 5607 5608 if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic) 5609 { 5610 DestRect.left = BackgroundLeft; 5611 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6; 5612 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6); 5613 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6); 5614 5615 if (dc->dctype == DCTYPE_DIRECT) 5616 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom); 5617 5618 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 5619 { 5620 IntUpdateBoundsRect(dc, &DestRect); 5621 } 5622 IntEngBitBlt( 5623 &psurf->SurfObj, 5624 NULL, 5625 NULL, 5626 (CLIPOBJ *)&dc->co, 5627 NULL, 5628 &DestRect, 5629 &SourcePoint, 5630 &SourcePoint, 5631 &dc->eboBackground.BrushObject, 5632 &BrushOrigin, 5633 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); 5634 5635 if (dc->dctype == DCTYPE_DIRECT) 5636 MouseSafetyOnDrawEnd(dc->ppdev); 5637 5638 BackgroundLeft = DestRect.right; 5639 } 5640 5641 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left; 5642 DestRect.right = DestRect.left + realglyph->bitmap.width; 5643 DestRect.top = TextTop + yoff - realglyph->top; 5644 DestRect.bottom = DestRect.top + realglyph->bitmap.rows; 5645 5646 bitSize.cx = realglyph->bitmap.width; 5647 bitSize.cy = realglyph->bitmap.rows; 5648 MaskRect.right = realglyph->bitmap.width; 5649 MaskRect.bottom = realglyph->bitmap.rows; 5650 5651 /* Check if the bitmap has any pixels */ 5652 if ((bitSize.cx != 0) && (bitSize.cy != 0)) 5653 { 5654 /* 5655 * We should create the bitmap out of the loop at the biggest possible 5656 * glyph size. Then use memset with 0 to clear it and sourcerect to 5657 * limit the work of the transbitblt. 5658 */ 5659 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch, 5660 BMF_8BPP, BMF_TOPDOWN, 5661 realglyph->bitmap.buffer); 5662 if ( !HSourceGlyph ) 5663 { 5664 DPRINT1("WARNING: EngCreateBitmap() failed!\n"); 5665 // FT_Done_Glyph(realglyph); 5666 bResult = FALSE; 5667 break; 5668 } 5669 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph); 5670 if ( !SourceGlyphSurf ) 5671 { 5672 EngDeleteSurface((HSURF)HSourceGlyph); 5673 DPRINT1("WARNING: EngLockSurface() failed!\n"); 5674 bResult = FALSE; 5675 break; 5676 } 5677 5678 /* 5679 * Use the font data as a mask to paint onto the DCs surface using a 5680 * brush. 5681 */ 5682 if (lprc && (fuOptions & ETO_CLIPPED) && 5683 DestRect.right >= lprc->right + dc->ptlDCOrig.x) 5684 { 5685 // We do the check '>=' instead of '>' to possibly save an iteration 5686 // through this loop, since it's breaking after the drawing is done, 5687 // and x is always incremented. 5688 DestRect.right = lprc->right + dc->ptlDCOrig.x; 5689 DoBreak = TRUE; 5690 } 5691 if (lprc && (fuOptions & ETO_CLIPPED) && 5692 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y) 5693 { 5694 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y; 5695 } 5696 5697 if (dc->dctype == DCTYPE_DIRECT) 5698 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom); 5699 5700 if (!IntEngMaskBlt( 5701 SurfObj, 5702 SourceGlyphSurf, 5703 (CLIPOBJ *)&dc->co, 5704 &exloRGB2Dst.xlo, 5705 &exloDst2RGB.xlo, 5706 &DestRect, 5707 (PPOINTL)&MaskRect, 5708 &dc->eboText.BrushObject, 5709 &BrushOrigin)) 5710 { 5711 DPRINT1("Failed to MaskBlt a glyph!\n"); 5712 } 5713 5714 if (dc->dctype == DCTYPE_DIRECT) 5715 MouseSafetyOnDrawEnd(dc->ppdev) ; 5716 5717 EngUnlockSurface(SourceGlyphSurf); 5718 EngDeleteSurface((HSURF)HSourceGlyph); 5719 } 5720 5721 if (DoBreak) 5722 { 5723 break; 5724 } 5725 5726 if (plf->lfUnderline) 5727 { 5728 int i, position; 5729 if (!face->units_per_EM) 5730 { 5731 position = 0; 5732 } 5733 else 5734 { 5735 position = face->underline_position * 5736 face->size->metrics.y_ppem / face->units_per_EM; 5737 } 5738 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i) 5739 { 5740 EngLineTo(SurfObj, 5741 (CLIPOBJ *)&dc->co, 5742 &dc->eboText.BrushObject, 5743 (TextLeft >> 6), 5744 TextTop + yoff - position + i, 5745 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6), 5746 TextTop + yoff - position + i, 5747 NULL, 5748 ROP2_TO_MIX(R2_COPYPEN)); 5749 } 5750 } 5751 if (plf->lfStrikeOut) 5752 { 5753 int i; 5754 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i) 5755 { 5756 EngLineTo(SurfObj, 5757 (CLIPOBJ *)&dc->co, 5758 &dc->eboText.BrushObject, 5759 (TextLeft >> 6), 5760 TextTop + yoff - (fixAscender >> 6) / 3 + i, 5761 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6), 5762 TextTop + yoff - (fixAscender >> 6) / 3 + i, 5763 NULL, 5764 ROP2_TO_MIX(R2_COPYPEN)); 5765 } 5766 } 5767 5768 if (NULL == Dx) 5769 { 5770 TextLeft += realglyph->root.advance.x >> 10; 5771 DPRINT("New TextLeft: %I64d\n", TextLeft); 5772 } 5773 else 5774 { 5775 // FIXME this should probably be a matrix transform with TextTop as well. 5776 Scale = pdcattr->mxWorldToDevice.efM11; 5777 if (FLOATOBJ_Equal0(&Scale)) 5778 FLOATOBJ_Set1(&Scale); 5779 5780 /* do the shift before multiplying to preserve precision */ 5781 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6); 5782 TextLeft += FLOATOBJ_GetLong(&Scale); 5783 DPRINT("New TextLeft2: %I64d\n", TextLeft); 5784 } 5785 5786 if (DxShift) 5787 { 5788 TextTop -= Dx[2 * i + 1] << 6; 5789 } 5790 5791 previous = glyph_index; 5792 5793 if (EmuBold || EmuItalic) 5794 { 5795 FT_Done_Glyph((FT_Glyph)realglyph); 5796 realglyph = NULL; 5797 } 5798 } 5799 5800 if (pdcattr->lTextAlign & TA_UPDATECP) { 5801 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x; 5802 } 5803 5804 IntUnLockFreeType; 5805 5806 EXLATEOBJ_vCleanup(&exloRGB2Dst); 5807 EXLATEOBJ_vCleanup(&exloDst2RGB); 5808 5809 Cleanup: 5810 5811 DC_vFinishBlit(dc, NULL); 5812 5813 if (TextObj != NULL) 5814 TEXTOBJ_UnlockText(TextObj); 5815 5816 DC_UnlockDc(dc); 5817 5818 return bResult; 5819 } 5820 5821 #define STACK_TEXT_BUFFER_SIZE 100 5822 BOOL 5823 APIENTRY 5824 NtGdiExtTextOutW( 5825 IN HDC hDC, 5826 IN INT XStart, 5827 IN INT YStart, 5828 IN UINT fuOptions, 5829 IN OPTIONAL LPRECT UnsafeRect, 5830 IN LPWSTR UnsafeString, 5831 IN INT Count, 5832 IN OPTIONAL LPINT UnsafeDx, 5833 IN DWORD dwCodePage) 5834 { 5835 BOOL Result = FALSE; 5836 NTSTATUS Status = STATUS_SUCCESS; 5837 RECTL SafeRect; 5838 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE]; 5839 PVOID Buffer = LocalBuffer; 5840 LPCWSTR SafeString = NULL; 5841 LPINT SafeDx = NULL; 5842 ULONG BufSize, StringSize, DxSize = 0; 5843 5844 /* Check if String is valid */ 5845 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL)) 5846 { 5847 EngSetLastError(ERROR_INVALID_PARAMETER); 5848 return FALSE; 5849 } 5850 5851 if (Count > 0) 5852 { 5853 /* Calculate buffer size for string and Dx values */ 5854 BufSize = StringSize = Count * sizeof(WCHAR); 5855 if (UnsafeDx) 5856 { 5857 /* If ETO_PDY is specified, we have pairs of INTs */ 5858 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1); 5859 BufSize += DxSize; 5860 } 5861 5862 /* Check if our local buffer is large enough */ 5863 if (BufSize > STACK_TEXT_BUFFER_SIZE) 5864 { 5865 /* It's not, allocate a temp buffer */ 5866 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT); 5867 if (!Buffer) 5868 { 5869 return FALSE; 5870 } 5871 } 5872 5873 /* Probe and copy user mode data to the buffer */ 5874 _SEH2_TRY 5875 { 5876 /* Put the Dx before the String to assure alignment of 4 */ 5877 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize); 5878 5879 /* Probe and copy the string */ 5880 ProbeForRead(UnsafeString, StringSize, 1); 5881 memcpy((PVOID)SafeString, UnsafeString, StringSize); 5882 5883 /* If we have Dx values... */ 5884 if (UnsafeDx) 5885 { 5886 /* ... probe and copy them */ 5887 SafeDx = Buffer; 5888 ProbeForRead(UnsafeDx, DxSize, 1); 5889 memcpy(SafeDx, UnsafeDx, DxSize); 5890 } 5891 } 5892 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5893 { 5894 Status = _SEH2_GetExceptionCode(); 5895 } 5896 _SEH2_END 5897 if (!NT_SUCCESS(Status)) 5898 { 5899 goto cleanup; 5900 } 5901 } 5902 5903 /* If we have a rect, copy it */ 5904 if (UnsafeRect) 5905 { 5906 _SEH2_TRY 5907 { 5908 ProbeForRead(UnsafeRect, sizeof(RECT), 1); 5909 SafeRect = *UnsafeRect; 5910 } 5911 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5912 { 5913 Status = _SEH2_GetExceptionCode(); 5914 } 5915 _SEH2_END 5916 if (!NT_SUCCESS(Status)) 5917 { 5918 goto cleanup; 5919 } 5920 } 5921 5922 /* Finally call the internal routine */ 5923 Result = GreExtTextOutW(hDC, 5924 XStart, 5925 YStart, 5926 fuOptions, 5927 &SafeRect, 5928 SafeString, 5929 Count, 5930 SafeDx, 5931 dwCodePage); 5932 5933 cleanup: 5934 /* If we allocated a buffer, free it */ 5935 if (Buffer != LocalBuffer) 5936 { 5937 ExFreePoolWithTag(Buffer, GDITAG_TEXT); 5938 } 5939 5940 return Result; 5941 } 5942 5943 5944 /* 5945 * @implemented 5946 */ 5947 BOOL 5948 APIENTRY 5949 NtGdiGetCharABCWidthsW( 5950 IN HDC hDC, 5951 IN UINT FirstChar, 5952 IN ULONG Count, 5953 IN OPTIONAL PWCHAR UnSafepwch, 5954 IN FLONG fl, 5955 OUT PVOID Buffer) 5956 { 5957 LPABC SafeBuff; 5958 LPABCFLOAT SafeBuffF = NULL; 5959 PDC dc; 5960 PDC_ATTR pdcattr; 5961 PTEXTOBJ TextObj; 5962 PFONTGDI FontGDI; 5963 FT_Face face; 5964 FT_CharMap charmap, found = NULL; 5965 UINT i, glyph_index, BufferSize; 5966 HFONT hFont = 0; 5967 NTSTATUS Status = STATUS_SUCCESS; 5968 PMATRIX pmxWorldToDevice; 5969 PWCHAR Safepwch = NULL; 5970 LOGFONTW *plf; 5971 5972 if (!Buffer) 5973 { 5974 EngSetLastError(ERROR_INVALID_PARAMETER); 5975 return FALSE; 5976 } 5977 5978 if (UnSafepwch) 5979 { 5980 UINT pwchSize = Count * sizeof(WCHAR); 5981 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT); 5982 5983 if(!Safepwch) 5984 { 5985 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 5986 return FALSE; 5987 } 5988 5989 _SEH2_TRY 5990 { 5991 ProbeForRead(UnSafepwch, pwchSize, 1); 5992 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize); 5993 } 5994 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5995 { 5996 Status = _SEH2_GetExceptionCode(); 5997 } 5998 _SEH2_END; 5999 } 6000 6001 if (!NT_SUCCESS(Status)) 6002 { 6003 if(Safepwch) 6004 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6005 6006 EngSetLastError(Status); 6007 return FALSE; 6008 } 6009 6010 BufferSize = Count * sizeof(ABC); // Same size! 6011 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT); 6012 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff; 6013 if (SafeBuff == NULL) 6014 { 6015 6016 if(Safepwch) 6017 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6018 6019 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 6020 return FALSE; 6021 } 6022 6023 dc = DC_LockDc(hDC); 6024 if (dc == NULL) 6025 { 6026 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6027 6028 if(Safepwch) 6029 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6030 6031 EngSetLastError(ERROR_INVALID_HANDLE); 6032 return FALSE; 6033 } 6034 pdcattr = dc->pdcattr; 6035 hFont = pdcattr->hlfntNew; 6036 TextObj = RealizeFontInit(hFont); 6037 6038 /* Get the DC's world-to-device transformation matrix */ 6039 pmxWorldToDevice = DC_pmxWorldToDevice(dc); 6040 DC_UnlockDc(dc); 6041 6042 if (TextObj == NULL) 6043 { 6044 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6045 6046 if(Safepwch) 6047 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6048 6049 EngSetLastError(ERROR_INVALID_HANDLE); 6050 return FALSE; 6051 } 6052 6053 FontGDI = ObjToGDI(TextObj->Font, FONT); 6054 6055 face = FontGDI->SharedFace->Face; 6056 if (face->charmap == NULL) 6057 { 6058 for (i = 0; i < (UINT)face->num_charmaps; i++) 6059 { 6060 charmap = face->charmaps[i]; 6061 if (charmap->encoding != 0) 6062 { 6063 found = charmap; 6064 break; 6065 } 6066 } 6067 6068 if (!found) 6069 { 6070 DPRINT1("WARNING: Could not find desired charmap!\n"); 6071 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6072 6073 if(Safepwch) 6074 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6075 6076 EngSetLastError(ERROR_INVALID_HANDLE); 6077 return FALSE; 6078 } 6079 6080 IntLockFreeType; 6081 FT_Set_Charmap(face, found); 6082 IntUnLockFreeType; 6083 } 6084 6085 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 6086 IntLockFreeType; 6087 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight); 6088 FtSetCoordinateTransform(face, pmxWorldToDevice); 6089 6090 for (i = FirstChar; i < FirstChar+Count; i++) 6091 { 6092 int adv, lsb, bbx, left, right; 6093 6094 if (Safepwch) 6095 { 6096 if (fl & GCABCW_INDICES) 6097 glyph_index = Safepwch[i - FirstChar]; 6098 else 6099 glyph_index = FT_Get_Char_Index(face, Safepwch[i - FirstChar]); 6100 } 6101 else 6102 { 6103 if (fl & GCABCW_INDICES) 6104 glyph_index = i; 6105 else 6106 glyph_index = FT_Get_Char_Index(face, i); 6107 } 6108 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 6109 6110 left = (INT)face->glyph->metrics.horiBearingX & -64; 6111 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64; 6112 adv = (face->glyph->advance.x + 32) >> 6; 6113 6114 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6; 6115 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */ 6116 6117 lsb = left >> 6; 6118 bbx = (right - left) >> 6; 6119 /* 6120 DPRINT1("lsb %d and bbx %d\n", lsb, bbx ); 6121 */ 6122 if (!fl) 6123 { 6124 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb; 6125 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx; 6126 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx); 6127 } 6128 else 6129 { 6130 SafeBuff[i - FirstChar].abcA = lsb; 6131 SafeBuff[i - FirstChar].abcB = bbx; 6132 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx; 6133 } 6134 } 6135 IntUnLockFreeType; 6136 TEXTOBJ_UnlockText(TextObj); 6137 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize); 6138 6139 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6140 6141 if(Safepwch) 6142 ExFreePoolWithTag(Safepwch , GDITAG_TEXT); 6143 6144 if (! NT_SUCCESS(Status)) 6145 { 6146 SetLastNtError(Status); 6147 return FALSE; 6148 } 6149 6150 DPRINT("NtGdiGetCharABCWidths Worked!\n"); 6151 return TRUE; 6152 } 6153 6154 /* 6155 * @implemented 6156 */ 6157 BOOL 6158 APIENTRY 6159 NtGdiGetCharWidthW( 6160 IN HDC hDC, 6161 IN UINT FirstChar, 6162 IN UINT Count, 6163 IN OPTIONAL PWCHAR UnSafepwc, 6164 IN FLONG fl, 6165 OUT PVOID Buffer) 6166 { 6167 NTSTATUS Status = STATUS_SUCCESS; 6168 LPINT SafeBuff; 6169 PFLOAT SafeBuffF = NULL; 6170 PDC dc; 6171 PDC_ATTR pdcattr; 6172 PTEXTOBJ TextObj; 6173 PFONTGDI FontGDI; 6174 FT_Face face; 6175 FT_CharMap charmap, found = NULL; 6176 UINT i, glyph_index, BufferSize; 6177 HFONT hFont = 0; 6178 PMATRIX pmxWorldToDevice; 6179 PWCHAR Safepwc = NULL; 6180 LOGFONTW *plf; 6181 6182 if (UnSafepwc) 6183 { 6184 UINT pwcSize = Count * sizeof(WCHAR); 6185 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT); 6186 6187 if(!Safepwc) 6188 { 6189 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 6190 return FALSE; 6191 } 6192 _SEH2_TRY 6193 { 6194 ProbeForRead(UnSafepwc, pwcSize, 1); 6195 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize); 6196 } 6197 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6198 { 6199 Status = _SEH2_GetExceptionCode(); 6200 } 6201 _SEH2_END; 6202 } 6203 6204 if (!NT_SUCCESS(Status)) 6205 { 6206 EngSetLastError(Status); 6207 return FALSE; 6208 } 6209 6210 BufferSize = Count * sizeof(INT); // Same size! 6211 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT); 6212 if (!fl) SafeBuffF = (PFLOAT) SafeBuff; 6213 if (SafeBuff == NULL) 6214 { 6215 if(Safepwc) 6216 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6217 6218 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 6219 return FALSE; 6220 } 6221 6222 dc = DC_LockDc(hDC); 6223 if (dc == NULL) 6224 { 6225 if(Safepwc) 6226 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6227 6228 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6229 EngSetLastError(ERROR_INVALID_HANDLE); 6230 return FALSE; 6231 } 6232 pdcattr = dc->pdcattr; 6233 hFont = pdcattr->hlfntNew; 6234 TextObj = RealizeFontInit(hFont); 6235 /* Get the DC's world-to-device transformation matrix */ 6236 pmxWorldToDevice = DC_pmxWorldToDevice(dc); 6237 DC_UnlockDc(dc); 6238 6239 if (TextObj == NULL) 6240 { 6241 if(Safepwc) 6242 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6243 6244 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6245 EngSetLastError(ERROR_INVALID_HANDLE); 6246 return FALSE; 6247 } 6248 6249 FontGDI = ObjToGDI(TextObj->Font, FONT); 6250 6251 face = FontGDI->SharedFace->Face; 6252 if (face->charmap == NULL) 6253 { 6254 for (i = 0; i < (UINT)face->num_charmaps; i++) 6255 { 6256 charmap = face->charmaps[i]; 6257 if (charmap->encoding != 0) 6258 { 6259 found = charmap; 6260 break; 6261 } 6262 } 6263 6264 if (!found) 6265 { 6266 DPRINT1("WARNING: Could not find desired charmap!\n"); 6267 6268 if(Safepwc) 6269 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6270 6271 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6272 EngSetLastError(ERROR_INVALID_HANDLE); 6273 return FALSE; 6274 } 6275 6276 IntLockFreeType; 6277 FT_Set_Charmap(face, found); 6278 IntUnLockFreeType; 6279 } 6280 6281 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; 6282 IntLockFreeType; 6283 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight); 6284 FtSetCoordinateTransform(face, pmxWorldToDevice); 6285 6286 for (i = FirstChar; i < FirstChar+Count; i++) 6287 { 6288 if (Safepwc) 6289 { 6290 if (fl & GCW_INDICES) 6291 glyph_index = Safepwc[i - FirstChar]; 6292 else 6293 glyph_index = FT_Get_Char_Index(face, Safepwc[i - FirstChar]); 6294 } 6295 else 6296 { 6297 if (fl & GCW_INDICES) 6298 glyph_index = i; 6299 else 6300 glyph_index = FT_Get_Char_Index(face, i); 6301 } 6302 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 6303 if (!fl) 6304 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6); 6305 else 6306 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6; 6307 } 6308 IntUnLockFreeType; 6309 TEXTOBJ_UnlockText(TextObj); 6310 MmCopyToCaller(Buffer, SafeBuff, BufferSize); 6311 6312 if(Safepwc) 6313 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6314 6315 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); 6316 return TRUE; 6317 } 6318 6319 6320 /* 6321 * @implemented 6322 */ 6323 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap 6324 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead. 6325 // NOTE: See also GreGetGlyphIndicesW. 6326 __kernel_entry 6327 W32KAPI 6328 DWORD 6329 APIENTRY 6330 NtGdiGetGlyphIndicesW( 6331 _In_ HDC hdc, 6332 _In_reads_opt_(cwc) LPCWSTR pwc, 6333 _In_ INT cwc, 6334 _Out_writes_opt_(cwc) LPWORD pgi, 6335 _In_ DWORD iMode) 6336 { 6337 PDC dc; 6338 PDC_ATTR pdcattr; 6339 PTEXTOBJ TextObj; 6340 PFONTGDI FontGDI; 6341 HFONT hFont = NULL; 6342 NTSTATUS Status = STATUS_SUCCESS; 6343 OUTLINETEXTMETRICW *potm; 6344 INT i; 6345 WCHAR DefChar = 0xffff; 6346 PWSTR Buffer = NULL; 6347 ULONG Size, pwcSize; 6348 PWSTR Safepwc = NULL; 6349 LPCWSTR UnSafepwc = pwc; 6350 LPWORD UnSafepgi = pgi; 6351 6352 /* Check for integer overflow */ 6353 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN 6354 return GDI_ERROR; 6355 6356 if (!UnSafepwc && !UnSafepgi) 6357 return cwc; 6358 6359 if (!UnSafepwc || !UnSafepgi) 6360 { 6361 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi); 6362 return GDI_ERROR; 6363 } 6364 6365 // TODO: Special undocumented case! 6366 if (!pwc && !pgi && (cwc == 0)) 6367 { 6368 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n"); 6369 return 0; 6370 } 6371 6372 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825 6373 if (cwc == 0) 6374 { 6375 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n"); 6376 return GDI_ERROR; 6377 } 6378 6379 dc = DC_LockDc(hdc); 6380 if (!dc) 6381 { 6382 return GDI_ERROR; 6383 } 6384 pdcattr = dc->pdcattr; 6385 hFont = pdcattr->hlfntNew; 6386 TextObj = RealizeFontInit(hFont); 6387 DC_UnlockDc(dc); 6388 if (!TextObj) 6389 { 6390 return GDI_ERROR; 6391 } 6392 6393 FontGDI = ObjToGDI(TextObj->Font, FONT); 6394 TEXTOBJ_UnlockText(TextObj); 6395 6396 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT); 6397 if (!Buffer) 6398 { 6399 return GDI_ERROR; 6400 } 6401 6402 if (iMode & GGI_MARK_NONEXISTING_GLYPHS) 6403 { 6404 DefChar = 0xffff; 6405 } 6406 else 6407 { 6408 FT_Face Face = FontGDI->SharedFace->Face; 6409 if (FT_IS_SFNT(Face)) 6410 { 6411 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); 6412 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(Face, pOS2->usDefaultChar) : 0); 6413 } 6414 else 6415 { 6416 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 6417 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 6418 if (!potm) 6419 { 6420 cwc = GDI_ERROR; 6421 goto ErrorRet; 6422 } 6423 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm); 6424 if (Size) 6425 DefChar = potm->otmTextMetrics.tmDefaultChar; 6426 ExFreePoolWithTag(potm, GDITAG_TEXT); 6427 } 6428 } 6429 6430 pwcSize = cwc * sizeof(WCHAR); 6431 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT); 6432 6433 if (!Safepwc) 6434 { 6435 Status = STATUS_NO_MEMORY; 6436 goto ErrorRet; 6437 } 6438 6439 _SEH2_TRY 6440 { 6441 ProbeForRead(UnSafepwc, pwcSize, 1); 6442 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize); 6443 } 6444 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6445 { 6446 Status = _SEH2_GetExceptionCode(); 6447 } 6448 _SEH2_END; 6449 6450 if (!NT_SUCCESS(Status)) goto ErrorRet; 6451 6452 IntLockFreeType; 6453 6454 for (i = 0; i < cwc; i++) 6455 { 6456 Buffer[i] = FT_Get_Char_Index(FontGDI->SharedFace->Face, Safepwc[i]); 6457 if (Buffer[i] == 0) 6458 { 6459 Buffer[i] = DefChar; 6460 } 6461 } 6462 6463 IntUnLockFreeType; 6464 6465 _SEH2_TRY 6466 { 6467 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1); 6468 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD)); 6469 } 6470 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6471 { 6472 Status = _SEH2_GetExceptionCode(); 6473 } 6474 _SEH2_END; 6475 6476 ErrorRet: 6477 ExFreePoolWithTag(Buffer, GDITAG_TEXT); 6478 if (Safepwc != NULL) 6479 { 6480 ExFreePoolWithTag(Safepwc, GDITAG_TEXT); 6481 } 6482 if (NT_SUCCESS(Status)) return cwc; 6483 return GDI_ERROR; 6484 } 6485 6486 /* EOF */ 6487