+static BYTE
+ItalicFromStyle(const char *style_name)
+{
+ if (style_name == NULL || style_name[0] == 0)
+ return FALSE;
+ if (strstr(style_name, "Italic") != NULL)
+ return TRUE;
+ if (strstr(style_name, "Oblique") != NULL)
+ return TRUE;
+ return FALSE;
+}
+
+static LONG
+WeightFromStyle(const char *style_name)
+{
+ if (style_name == NULL || style_name[0] == 0)
+ return FW_NORMAL;
+ if (strstr(style_name, "Regular") != NULL)
+ return FW_REGULAR;
+ if (strstr(style_name, "Normal") != NULL)
+ return FW_NORMAL;
+ if (strstr(style_name, "SemiBold") != NULL)
+ return FW_SEMIBOLD;
+ if (strstr(style_name, "UltraBold") != NULL)
+ return FW_ULTRABOLD;
+ if (strstr(style_name, "DemiBold") != NULL)
+ return FW_DEMIBOLD;
+ if (strstr(style_name, "ExtraBold") != NULL)
+ return FW_EXTRABOLD;
+ if (strstr(style_name, "Bold") != NULL)
+ return FW_BOLD;
+ if (strstr(style_name, "UltraLight") != NULL)
+ return FW_ULTRALIGHT;
+ if (strstr(style_name, "ExtraLight") != NULL)
+ return FW_EXTRALIGHT;
+ if (strstr(style_name, "Light") != NULL)
+ return FW_LIGHT;
+ if (strstr(style_name, "Hairline") != NULL)
+ return 50;
+ if (strstr(style_name, "Book") != NULL)
+ return 350;
+ if (strstr(style_name, "ExtraBlack") != NULL)
+ return 950;
+ if (strstr(style_name, "UltraBlack") != NULL)
+ return 1000;
+ if (strstr(style_name, "Black") != NULL)
+ return FW_BLACK;
+ if (strstr(style_name, "Medium") != NULL)
+ return FW_MEDIUM;
+ if (strstr(style_name, "Thin") != NULL)
+ return FW_THIN;
+ if (strstr(style_name, "Heavy") != NULL)
+ return FW_HEAVY;
+ return FW_NORMAL;
+}
+
+static FT_Error
+IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight);
+
+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 AnsiFaceName;
+ 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(&AnsiFaceName, Face->family_name);
+ Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
+ 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();
+ }
+
+ /* FIXME: CharSet is invalid on Marlett */
+ if (RtlEqualUnicodeString(&Entry->FaceName, &g_MarlettW, TRUE))
+ {
+ FontGDI->CharSet = SYMBOL_CHARSET;
+ }
+
+ ++FaceCount;
+ DPRINT("Font loaded: %s (%s)\n",
+ Face->family_name ? Face->family_name : "<NULL>",
+ Face->style_name ? Face->style_name : "<NULL>");
+ 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;
+
+ if (pLoadFont->RegValueName.Length == 0)
+ {
+ RtlCreateUnicodeString(pValueName, Entry->FaceName.Buffer);
+ }
+ else
+ {
+ UNICODE_STRING NewString;
+ USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.Length;
+ 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;
+ }
+
+ for (i = 1; i < CharSetCount; ++i)
+ {
+ /* Do not count charsets towards 'faces' loaded */
+ IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
+ }
+ }
+
+ return FaceCount; /* number of loaded faces */
+}