static INT FASTCALL IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont, PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex) { FT_Error Error; PFONT_ENTRY Entry; FONT_ENTRY_MEM* PrivateEntry = NULL; FONTGDI * FontGDI; NTSTATUS Status; FT_Face Face; ANSI_STRING AnsiString; FT_WinFNT_HeaderRec WinFNT; INT FaceCount = 0, CharSetCount = 0; PUNICODE_STRING pFileName = pLoadFont->pFileName; DWORD Characteristics = pLoadFont->Characteristics; PUNICODE_STRING pValueName = &pLoadFont->RegValueName; TT_OS2 * pOS2; INT BitIndex; FT_UShort os2_version; FT_ULong os2_ulCodePageRange1; FT_UShort os2_usWeightClass; if (SharedFace == NULL && CharSetIndex == -1) { /* load a face from memory */ IntLockFreeType(); Error = FT_New_Memory_Face( g_FreeTypeLibrary, pLoadFont->Memory->Buffer, pLoadFont->Memory->BufferSize, ((FontIndex != -1) ? FontIndex : 0), &Face); if (!Error) SharedFace = SharedFace_Create(Face, pLoadFont->Memory); IntUnLockFreeType(); if (!Error && FT_IS_SFNT(Face)) pLoadFont->IsTrueType = TRUE; if (Error || SharedFace == NULL) { if (SharedFace) SharedFace_Release(SharedFace); if (Error == FT_Err_Unknown_File_Format) DPRINT1("Unknown font file format\n"); else DPRINT1("Error reading font (error code: %d)\n", Error); return 0; /* failure */ } } else { Face = SharedFace->Face; IntLockFreeType(); SharedFace_AddRef(SharedFace); IntUnLockFreeType(); } /* allocate a FONT_ENTRY */ Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT); if (!Entry) { SharedFace_Release(SharedFace); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; /* failure */ } /* allocate a FONTGDI */ FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT); if (!FontGDI) { SharedFace_Release(SharedFace); ExFreePoolWithTag(Entry, TAG_FONT); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; /* failure */ } /* set file name */ if (pFileName) { FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, pFileName->Length + sizeof(UNICODE_NULL), GDITAG_PFF); if (FontGDI->Filename == NULL) { EngFreeMem(FontGDI); SharedFace_Release(SharedFace); ExFreePoolWithTag(Entry, TAG_FONT); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; /* failure */ } RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length); FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL; } else { FontGDI->Filename = NULL; PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT); if (!PrivateEntry) { if (FontGDI->Filename) ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); EngFreeMem(FontGDI); SharedFace_Release(SharedFace); ExFreePoolWithTag(Entry, TAG_FONT); return 0; } PrivateEntry->Entry = Entry; if (pLoadFont->PrivateEntry) { InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry); } else { InitializeListHead(&PrivateEntry->ListEntry); pLoadFont->PrivateEntry = PrivateEntry; } } /* set face */ FontGDI->SharedFace = SharedFace; FontGDI->CharSet = ANSI_CHARSET; FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name); FontGDI->RequestItalic = FALSE; FontGDI->OriginalWeight = WeightFromStyle(Face->style_name); FontGDI->RequestWeight = FW_NORMAL; RtlInitAnsiString(&AnsiString, Face->family_name); Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiString, TRUE); if (NT_SUCCESS(Status)) { if (Face->style_name && Face->style_name[0] && strcmp(Face->style_name, "Regular") != 0) { RtlInitAnsiString(&AnsiString, Face->style_name); Status = RtlAnsiStringToUnicodeString(&Entry->StyleName, &AnsiString, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&Entry->FaceName); } } else { RtlInitUnicodeString(&Entry->StyleName, NULL); } } if (!NT_SUCCESS(Status)) { if (PrivateEntry) { if (pLoadFont->PrivateEntry == PrivateEntry) { pLoadFont->PrivateEntry = NULL; } else { RemoveEntryList(&PrivateEntry->ListEntry); } ExFreePoolWithTag(PrivateEntry, TAG_FONT); } if (FontGDI->Filename) ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); EngFreeMem(FontGDI); SharedFace_Release(SharedFace); ExFreePoolWithTag(Entry, TAG_FONT); return 0; } os2_version = 0; IntLockFreeType(); pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2); if (pOS2) { os2_version = pOS2->version; os2_ulCodePageRange1 = pOS2->ulCodePageRange1; os2_usWeightClass = pOS2->usWeightClass; } IntUnLockFreeType(); if (pOS2 && os2_version >= 1) { /* get charset and weight from OS/2 header */ /* Make sure we do not use this pointer anymore */ pOS2 = NULL; for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex) { if (os2_ulCodePageRange1 & (1 << BitIndex)) { if (g_FontTci[BitIndex].ciCharset == DEFAULT_CHARSET) continue; if ((CharSetIndex == -1 && CharSetCount == 0) || CharSetIndex == CharSetCount) { FontGDI->CharSet = g_FontTci[BitIndex].ciCharset; } ++CharSetCount; } } /* set actual weight */ FontGDI->OriginalWeight = os2_usWeightClass; } else { /* get charset from WinFNT header */ IntLockFreeType(); Error = FT_Get_WinFNT_Header(Face, &WinFNT); if (!Error) { FontGDI->CharSet = WinFNT.charset; } IntUnLockFreeType(); } ++FaceCount; DPRINT("Font loaded: %s (%s)\n", Face->family_name ? Face->family_name : "", Face->style_name ? Face->style_name : ""); DPRINT("Num glyphs: %d\n", Face->num_glyphs); DPRINT("CharSet: %d\n", FontGDI->CharSet); IntLockFreeType(); IntRequestFontSize(NULL, FontGDI, 0, 0); IntUnLockFreeType(); /* Add this font resource to the font table */ Entry->Font = FontGDI; Entry->NotEnum = (Characteristics & FR_NOT_ENUM); if (Characteristics & FR_PRIVATE) { /* private font */ PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); IntLockProcessPrivateFonts(Win32Process); InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry); IntUnLockProcessPrivateFonts(Win32Process); } else { /* global font */ IntLockGlobalFonts(); InsertTailList(&g_FontListHead, &Entry->ListEntry); IntUnLockGlobalFonts(); } if (FontIndex == -1) { if (FT_IS_SFNT(Face)) { TT_Face TrueType = (TT_Face)Face; if (TrueType->ttc_header.count > 1) { FT_Long i; for (i = 1; i < TrueType->ttc_header.count; ++i) { FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1); } } } FontIndex = 0; } if (CharSetIndex == -1) { INT i; USHORT NameLength = Entry->FaceName.Length; if (Entry->StyleName.Length) NameLength += Entry->StyleName.Length + sizeof(WCHAR); if (pLoadFont->RegValueName.Length == 0) { pValueName->Length = 0; pValueName->MaximumLength = NameLength + sizeof(WCHAR); pValueName->Buffer = ExAllocatePoolWithTag(PagedPool, pValueName->MaximumLength, TAG_USTR); pValueName->Buffer[0] = UNICODE_NULL; RtlAppendUnicodeStringToString(pValueName, &Entry->FaceName); } else { UNICODE_STRING NewString; USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + NameLength; NewString.Length = 0; NewString.MaximumLength = Length + sizeof(WCHAR); NewString.Buffer = ExAllocatePoolWithTag(PagedPool, NewString.MaximumLength, TAG_USTR); NewString.Buffer[0] = UNICODE_NULL; RtlAppendUnicodeStringToString(&NewString, pValueName); RtlAppendUnicodeToString(&NewString, L" & "); RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName); RtlFreeUnicodeString(pValueName); *pValueName = NewString; } if (Entry->StyleName.Length) { RtlAppendUnicodeToString(pValueName, L" "); RtlAppendUnicodeStringToString(pValueName, &Entry->StyleName); } for (i = 1; i < CharSetCount; ++i) { /* Do not count charsets towards 'faces' loaded */ IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i); } } return FaceCount; /* number of loaded faces */ }