/* * PROJECT: ReactOS win32 subsystem * LICENSE: GPL - See COPYING in the top level directory * PURPOSE: GDI font driver for bitmap fonts * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) */ #include "bmfd.h" static BOOLEAN IsValidPtr( PVOID p, ULONG cjSize, PVOID pStart, PVOID pEnd, ULONG cjAlign) { if ((ULONG_PTR)p < (ULONG_PTR)pStart || (ULONG_PTR)p + cjSize >= (ULONG_PTR)pEnd || (ULONG_PTR)p & (cjAlign -1)) { return FALSE; } return TRUE; } static BOOL FillFaceInfo( PBMFD_FACE pface, PFONTINFO16 pFontInfo) { CHAR ansi[4]; WCHAR unicode[4]; ULONG written; DWORD dfFlags; pface->pFontInfo = pFontInfo; pface->ulVersion = GETVAL(pFontInfo->dfVersion); pface->cGlyphs = pFontInfo->dfLastChar - pFontInfo->dfFirstChar + 1; /* Convert chars to unicode */ ansi[0] = pFontInfo->dfFirstChar; ansi[1] = pFontInfo->dfLastChar; ansi[2] = pFontInfo->dfFirstChar + pFontInfo->dfDefaultChar; ansi[3] = pFontInfo->dfFirstChar + pFontInfo->dfBreakChar; EngMultiByteToUnicodeN(unicode, 4 * sizeof(WCHAR), &written, ansi, 4); pface->wcFirstChar = unicode[0]; pface->wcLastChar = unicode[1]; pface->wcDefaultChar = unicode[2]; pface->wcBreakChar = unicode[3]; /* Copy some values */ pface->wPixHeight = GETVAL(pFontInfo->dfPixHeight); pface->wPixWidth = GETVAL(pFontInfo->dfPixWidth); pface->wWidthBytes = GETVAL(pFontInfo->dfWidthBytes); pface->wAscent = GETVAL(pFontInfo->dfAscent); pface->wDescent = pface->wPixHeight - pface->wAscent; /* Some version specific members */ if (pface->ulVersion >= 0x300) { dfFlags = GETVAL(pFontInfo->dfFlags); pface->wA = GETVAL(pFontInfo->dfAspace); pface->wB = GETVAL(pFontInfo->dfBspace); pface->wC = GETVAL(pFontInfo->dfCspace); pface->pCharTable = pFontInfo->dfCharTable; pface->cjEntrySize = sizeof(GLYPHENTRY30); } else { dfFlags = DFF_1COLOR; pface->wA = 0; pface->wB = 0; pface->wC = 0; pface->pCharTable = &pFontInfo->dfReserved + 1; pface->cjEntrySize = sizeof(GLYPHENTRY20); } pface->flInfo = FM_INFO_MASK; /* If dfWidth is non-null, we have a fixed width font */ if (dfFlags & DFF_FIXED || pface->wPixWidth) pface->flInfo |= FM_INFO_CONSTANT_WIDTH; /* Initialize color depth flags */ if (dfFlags & DFF_1COLOR) pface->flInfo |= FM_INFO_1BPP; else if (dfFlags & DFF_16COLOR) pface->flInfo |= FM_INFO_4BPP; else if (dfFlags & DFF_256COLOR) pface->flInfo |= FM_INFO_8BPP; else if (dfFlags & DFF_RGBCOLOR) pface->flInfo |= FM_INFO_24BPP; // TODO: walk through all glyphs and veryfy them and calculate max values // FIXME: After this point, the whole font data should be verified! return TRUE; } static PVOID ParseFntFile( PVOID pvView, ULONG cjView) { /* unimplemented */ return NULL; } static PVOID ParseFonFile( PVOID pvView, ULONG cjView) { PIMAGE_DOS_HEADER pDosHeader = pvView; PIMAGE_OS2_HEADER pOs2Header; PNE_RESTABLE pResTable; PNE_TYPEINFO pTInfo; PFONTINFO16 pFontInfo; PCHAR pStart, pEnd; PBMFD_FILE pfile = NULL; WORD wShift; ULONG i, cjOffset, cjLength; ULONG type_id, count; /* Initial margins for valid pointers */ pStart = pvView; pEnd = pStart + cjView; /* Check for image dos header */ if (GETVAL(pDosHeader->e_magic) != IMAGE_DOS_MAGIC) { return NULL; } /* Get pointer to OS2 header and veryfy it is valid */ pOs2Header = (PVOID)((PCHAR)pDosHeader + GETVAL(pDosHeader->e_lfanew)); pStart += sizeof(IMAGE_DOS_HEADER); if (!IsValidPtr(pOs2Header, sizeof(IMAGE_OS2_HEADER), pStart, pEnd, 4)) { DbgPrint("e_lfanew is invalid: 0x%lx\n", pDosHeader->e_lfanew); return NULL; } /* Get pointer to resource table and verify it is valid */ pResTable = (PVOID)((PCHAR)pOs2Header + GETVAL(pOs2Header->ne_rsrctab)); pStart = (PCHAR)pOs2Header; if (!IsValidPtr(pResTable, sizeof(NE_RESTABLE), pStart, pEnd, 1)) { DbgPrint("pTInfo is invalid: 0x%p\n", pResTable); return NULL; } wShift = GETVAL(pResTable->size_shift); pTInfo = pResTable->typeinfo; type_id = GETVAL(pTInfo->type_id); /* Loop the resource table to find a font resource */ while (type_id) { /* Get number of nameinfo entries */ count = GETVAL(pTInfo->count); /* Look for a font resource */ if (type_id == NE_RSCTYPE_FONT && count > 0) { DbgPrint("Found NE_RSCTYPE_FONT\n"); /* Allocate an info structure for this font and all faces */ cjLength = sizeof(BMFD_FILE) + (count-1) * sizeof(BMFD_FACE); pfile = EngAllocMem(0, cjLength, TAG_FONTINFO); if (!pfile) { DbgPrint("Not enough memory: %ld\n", cjLength); return NULL; } pfile->cNumFaces = count; /* Fill all face info structures */ for (i = 0; i < count; i++) { cjOffset = GETVAL(pTInfo->nameinfo[i].offset) << wShift; cjLength = GETVAL(pTInfo->nameinfo[i].length) << wShift; pFontInfo = (PVOID)((PCHAR)pDosHeader + cjOffset); if (!IsValidPtr(pFontInfo, cjLength, pStart, pEnd, 1)) { DbgPrint("pFontInfo is invalid: 0x%p\n", pFontInfo); EngFreeMem(pfile); return NULL; } /* Validate FONTINFO and fill face info */ if (!FillFaceInfo(&pfile->aface[i], pFontInfo)) { DbgPrint("pFontInfo is invalid: 0x%p\n", pFontInfo); EngFreeMem(pfile); return NULL; } } /* Break out of the loop */ break; } /* Following pointers must be bigger than this */ pStart = (PCHAR)pTInfo; /* Goto next entry in resource table */ pTInfo = (PVOID)&pTInfo->nameinfo[count]; /* Verify that the new pTInfo pointer is valid */ if (!IsValidPtr(pTInfo, sizeof(NE_TYPEINFO), pStart, pEnd, 1)) { DbgPrint("pTInfo is invalid: 0x%p\n", pTInfo); return NULL; } type_id = GETVAL(pTInfo->type_id); } return pfile; } /** Public Interface **********************************************************/ ULONG_PTR APIENTRY BmfdLoadFontFile( ULONG cFiles, ULONG_PTR *piFile, PVOID *ppvView, ULONG *pcjView, DESIGNVECTOR *pdv, ULONG ulLangID, ULONG ulFastCheckSum) { PBMFD_FILE pfile = NULL; PVOID pvView; ULONG cjView; DbgPrint("BmfdLoadFontFile()\n"); __debugbreak(); /* Check parameters */ if (cFiles != 1) { DbgPrint("Only 1 File is allowed, got %ld!\n", cFiles); return HFF_INVALID; } /* Map the font file */ if (!EngMapFontFileFD(*piFile, (PULONG*)&pvView, &cjView)) { DbgPrint("Could not map font file!\n", cFiles); return HFF_INVALID; } DbgPrint("mapped font file to %p, site if %ld\n", pvView, cjView); /* Try to parse a .fon file */ pfile = ParseFonFile(pvView, cjView); if (!pfile) { /* Could be a .fnt file */ pfile = ParseFntFile(pvView, cjView); } /* Check whether we succeeded finding a font */ if (!pfile) { DbgPrint("No font data found\n"); /* Unmap the file */ EngUnmapFontFileFD(*piFile); /* Failure! */ return HFF_INVALID; } pfile->iFile = *piFile; pfile->pvView = pvView; /* Success, return the pointer to font info structure */ return (ULONG_PTR)pfile; } BOOL APIENTRY BmfdUnloadFontFile( IN ULONG_PTR iFile) { PBMFD_FILE pfile = (PBMFD_FILE)iFile; DbgPrint("BmfdUnloadFontFile()\n"); /* Unmap the font file */ EngUnmapFontFileFD(pfile->iFile); /* Free the memory that was allocated for the font */ EngFreeMem(pfile); return TRUE; } LONG APIENTRY BmfdQueryFontFile( ULONG_PTR iFile, ULONG ulMode, ULONG cjBuf, ULONG *pulBuf) { PBMFD_FILE pfile = (PBMFD_FILE)iFile; DbgPrint("BmfdQueryFontFile()\n"); // __debugbreak(); switch (ulMode) { case QFF_DESCRIPTION: { /* We copy the face name of the 1st face */ PCHAR pDesc = pfile->aface[0].pszFaceName; ULONG cOutSize; if (pulBuf) { EngMultiByteToUnicodeN((LPWSTR)pulBuf, cjBuf, &cOutSize, pDesc, strnlen(pDesc, LF_FACESIZE)); } else { cOutSize = (strnlen(pDesc, LF_FACESIZE) + 1) * sizeof(WCHAR); } return cOutSize; } case QFF_NUMFACES: /* return the number of faces in the file */ return pfile->cNumFaces; default: return FD_ERROR; } } LONG APIENTRY BmfdQueryFontCaps( ULONG culCaps, ULONG *pulCaps) { DbgPrint("BmfdQueryFontCaps()\n"); /* We need room for 2 ULONGs */ if (culCaps < 2) { return FD_ERROR; } /* We only support 1 bpp */ pulCaps[0] = 2; pulCaps[1] = QC_1BIT; return 2; } PVOID APIENTRY BmfdQueryFontTree( DHPDEV dhpdev, ULONG_PTR iFile, ULONG iFace, ULONG iMode, ULONG_PTR *pid) { PBMFD_FILE pfile = (PBMFD_FILE)iFile; PBMFD_FACE pface; ULONG i, j, cjSize, cGlyphs, cRuns; CHAR ch, chFirst, ach[256]; WCHAR wc, awc[256]; PFD_GLYPHSET pGlyphSet; WCRUN *pwcrun; HGLYPH * phglyphs; DbgPrint("DrvQueryFontTree(iMode=%ld)\n", iMode); // __debugbreak(); /* Check parameters, we only support QFT_GLYPHSET */ if (!iFace || iFace > pfile->cNumFaces || iMode != QFT_GLYPHSET) { DbgPrint("iFace = %ld, cNumFaces = %ld\n", iFace, pfile->cNumFaces); return NULL; } /* Get a pointer to the face data */ pface = &pfile->aface[iFace - 1]; /* Get the number of characters in the face */ cGlyphs = pface->cGlyphs; chFirst = pface->pFontInfo->dfFirstChar; /* Build array of supported chars */ for (i = 0; i < cGlyphs; i++) { ach[i] = chFirst + i; } /* Convert the chars to unicode */ EngMultiByteToUnicodeN(awc, sizeof(awc), NULL, ach, cGlyphs); /* Sort both arrays in wchar order */ for (i = 0; i < cGlyphs - 1; i++) { wc = awc[i]; for (j = i + 1; j < cGlyphs; j++) { if (awc[j] < wc) { awc[i] = awc[j]; awc[j] = wc; wc = awc[i]; ch = ach[i]; ach[i] = ach[j]; ach[j] = ch; } } } /* Find number of WCRUNs */ cRuns = 1; for (i = 1; i < cGlyphs; i++) { if (awc[i] != awc[i - 1] + 1) { cRuns++; } } /* Calculate FD_GLYPHSET size */ cjSize = sizeof(FD_GLYPHSET) + (cRuns - 1) * sizeof(WCRUN) + cGlyphs * sizeof(HGLYPH); /* Allocate the FD_GLYPHSET structure */ pGlyphSet = EngAllocMem(0, cjSize, TAG_GLYPHSET); if (!pGlyphSet) { return NULL; } /* Initialize FD_GLYPHSET */ pGlyphSet->cjThis = cjSize; pGlyphSet->flAccel = 0; pGlyphSet->cGlyphsSupported = cGlyphs; pGlyphSet->cRuns = cRuns; /* Initialize 1st WCRUN */ pwcrun = pGlyphSet->awcrun; phglyphs = (PHGLYPH)&pGlyphSet->awcrun[cRuns]; pwcrun[0].wcLow = awc[0]; pwcrun[0].cGlyphs = 1; pwcrun[0].phg = phglyphs; phglyphs[0] = 0; /* Walk through all supported chars */ for (i = 1, j = 0; i < cGlyphs; i++) { /* Use offset to glyph entry as hglyph */ phglyphs[i] = (ach[i] - chFirst) * pface->cjEntrySize; /* Check whether we can append the wchar to a run */ if (awc[i] == awc[i - 1] + 1) { /* Append to current WCRUN */ pwcrun[j].cGlyphs++; } else { /* Add a new WCRUN */ j++; pwcrun[j].wcLow = awc[i]; pwcrun[j].cGlyphs = 1; pwcrun[j].phg = &phglyphs[i]; } } /* Set *pid to the allocated structure for use in BmfdFree */ *pid = (ULONG_PTR)pGlyphSet; return pGlyphSet; } PIFIMETRICS APIENTRY BmfdQueryFont( IN DHPDEV dhpdev, IN ULONG_PTR iFile, IN ULONG iFace, IN ULONG_PTR *pid) { PBMFD_FILE pfile = (PBMFD_FILE)iFile; PBMFD_FACE pface; PFONTINFO16 pFontInfo; PIFIMETRICS pifi; PBMFD_IFIMETRICS pifiX; PANOSE panose = {0}; DbgPrint("BmfdQueryFont()\n"); // __debugbreak(); /* Validate parameters */ if (iFace > pfile->cNumFaces || !pid) { return NULL; } pface = &pfile->aface[iFace - 1]; pFontInfo = pface->pFontInfo; /* Allocate the structure */ pifiX = EngAllocMem(FL_ZERO_MEMORY, sizeof(BMFD_IFIMETRICS), TAG_IFIMETRICS); if (!pifiX) { return NULL; } /* Return a pointer to free it later */ *pid = (ULONG_PTR)pifiX; /* Fill IFIMETRICS */ pifi = &pifiX->ifim; pifi->cjThis = sizeof(BMFD_IFIMETRICS); pifi->cjIfiExtra = 0; pifi->dpwszFamilyName = FIELD_OFFSET(BMFD_IFIMETRICS, wszFamilyName); pifi->dpwszStyleName = FIELD_OFFSET(BMFD_IFIMETRICS, wszFamilyName); pifi->dpwszFaceName = FIELD_OFFSET(BMFD_IFIMETRICS, wszFaceName); pifi->dpwszUniqueName = FIELD_OFFSET(BMFD_IFIMETRICS, wszFaceName); pifi->dpFontSim = 0; pifi->lEmbedId = 0; pifi->lItalicAngle = 0; pifi->lCharBias = 0; pifi->dpCharSets = 0; pifi->jWinCharSet = pFontInfo->dfCharSet; pifi->jWinPitchAndFamily = pFontInfo->dfPitchAndFamily; pifi->usWinWeight = GETVAL(pFontInfo->dfWeight); pifi->flInfo = pface->flInfo; pifi->fsSelection = 0; pifi->fsType = 0; pifi->fwdUnitsPerEm = GETVAL(pFontInfo->dfPixHeight); pifi->fwdLowestPPEm = 0; pifi->fwdWinAscender = GETVAL(pFontInfo->dfAscent); pifi->fwdWinDescender = pifi->fwdUnitsPerEm - pifi->fwdWinAscender; pifi->fwdMacAscender = pifi->fwdWinAscender; pifi->fwdMacDescender = - pifi->fwdWinDescender; pifi->fwdMacLineGap = 0; pifi->fwdTypoAscender = pifi->fwdWinAscender; pifi->fwdTypoDescender = - pifi->fwdWinDescender; pifi->fwdTypoLineGap = 0; pifi->fwdAveCharWidth = GETVAL(pFontInfo->dfAvgWidth); pifi->fwdMaxCharInc = GETVAL(pFontInfo->dfMaxWidth); pifi->fwdCapHeight = pifi->fwdUnitsPerEm / 2; pifi->fwdXHeight = pifi->fwdUnitsPerEm / 4; pifi->fwdSubscriptXSize = 0; pifi->fwdSubscriptYSize = 0; pifi->fwdSubscriptXOffset = 0; pifi->fwdSubscriptYOffset = 0; pifi->fwdSuperscriptXSize = 0; pifi->fwdSuperscriptYSize = 0; pifi->fwdSuperscriptXOffset = 0; pifi->fwdSuperscriptYOffset = 0; pifi->fwdUnderscoreSize = 01; pifi->fwdUnderscorePosition = -1; pifi->fwdStrikeoutSize = 1; pifi->fwdStrikeoutPosition = pifi->fwdXHeight + 1; pifi->chFirstChar = pFontInfo->dfFirstChar; pifi->chLastChar = pFontInfo->dfLastChar; pifi->chDefaultChar = pFontInfo->dfFirstChar + pFontInfo->dfDefaultChar; pifi->chBreakChar = pFontInfo->dfFirstChar + pFontInfo->dfBreakChar; pifi->wcFirstChar = pface->wcFirstChar; pifi->wcLastChar = pface->wcLastChar; pifi->wcDefaultChar = pface->wcDefaultChar; pifi->wcBreakChar = pface->wcBreakChar; pifi->ptlBaseline.x = 1; pifi->ptlBaseline.y = 0; pifi->ptlAspect.x = pFontInfo->dfVertRes; // CHECKME pifi->ptlAspect.y = pFontInfo->dfHorizRes; pifi->ptlCaret.x = 0; pifi->ptlCaret.y = 1; pifi->rclFontBox.left = 0; pifi->rclFontBox.right = pifi->fwdAveCharWidth; pifi->rclFontBox.top = pifi->fwdWinAscender; pifi->rclFontBox.bottom = - pifi->fwdWinDescender; *(DWORD*)&pifi->achVendId = 0x30303030; // FIXME pifi->cKerningPairs = 0; pifi->ulPanoseCulture = FM_PANOSE_CULTURE_LATIN; pifi->panose = panose; /* Set char sets */ pifiX->ajCharSet[0] = pifi->jWinCharSet; pifiX->ajCharSet[1] = DEFAULT_CHARSET; if (pface->flInfo & FM_INFO_CONSTANT_WIDTH) pifi->jWinPitchAndFamily |= FIXED_PITCH; #if 0 EngMultiByteToUnicodeN(pifiX->wszFaceName, LF_FACESIZE * sizeof(WCHAR), NULL, pFontInfo->, strnlen(pDesc, LF_FACESIZE)); #endif wcscpy(pifiX->wszFaceName, L"Courier-X"); wcscpy(pifiX->wszFamilyName, L"Courier-X"); /* Initialize font weight style flags and string */ if (pifi->usWinWeight == FW_REGULAR) { // pifi->fsSelection |= FM_SEL_REGULAR; } else if (pifi->usWinWeight > FW_SEMIBOLD) { pifi->fsSelection |= FM_SEL_BOLD; wcscat(pifiX->wszStyleName, L"Bold "); } else if (pifi->usWinWeight <= FW_LIGHT) { wcscat(pifiX->wszStyleName, L"Light "); } if (pFontInfo->dfItalic) { pifi->fsSelection |= FM_SEL_ITALIC; wcscat(pifiX->wszStyleName, L"Italic "); } if (pFontInfo->dfUnderline) { pifi->fsSelection |= FM_SEL_UNDERSCORE; wcscat(pifiX->wszStyleName, L"Underscore "); } if (pFontInfo->dfStrikeOut) { pifi->fsSelection |= FM_SEL_STRIKEOUT; wcscat(pifiX->wszStyleName, L"Strikeout "); } return pifi; } VOID APIENTRY BmfdFree( PVOID pv, ULONG_PTR id) { DbgPrint("BmfdFree()\n"); if (id) { EngFreeMem((PVOID)id); } } VOID APIENTRY BmfdDestroyFont( IN FONTOBJ *pfo) { /* Free the font realization info */ EngFreeMem(pfo->pvProducer); pfo->pvProducer = NULL; }