mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
508 lines
13 KiB
508 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fontdata.c
|
|
|
|
Abstract:
|
|
|
|
Implementation of DDI entry points DrvQueryFontData
|
|
and DrvQueryAdvanceWidths.
|
|
|
|
[Environment:]
|
|
|
|
Win32 subsystem, PostScript driver
|
|
|
|
Revision History:
|
|
|
|
04/25/91 -kentse-
|
|
Created it.
|
|
|
|
08/08/95 -davidx-
|
|
Clean up.
|
|
|
|
mm/dd/yy -author-
|
|
description
|
|
|
|
--*/
|
|
|
|
#include "pscript.h"
|
|
|
|
#define WIDTH_DIVISOR 12
|
|
#define WIDTH_MULT (1<<WIDTH_DIVISOR)
|
|
|
|
|
|
|
|
LONG
|
|
DrvQueryFontData(
|
|
DHPDEV dhpdev,
|
|
FONTOBJ *pfo,
|
|
ULONG iMode,
|
|
HGLYPH hg,
|
|
GLYPHDATA *pgd,
|
|
PVOID pv,
|
|
ULONG cjSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implementation of DDI entry point DrvQueryFontData.
|
|
Please refer to DDK documentation for more details.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNTFM pntfm = NULL;
|
|
LONG lWidth;
|
|
PDEVDATA pdev;
|
|
XFORMOBJ *pxo;
|
|
ULONG ulComplex;
|
|
PIFIMETRICS pifi;
|
|
POINTL ptl1, ptl2;
|
|
POINTFIX ptfx1;
|
|
FD_DEVICEMETRICS *pdm = (FD_DEVICEMETRICS *) pv;
|
|
FIX fxLength, fxExtLeading, fxWidth;
|
|
LONG lfHeight, InternalLeading;
|
|
DWORD dwPointSize, dwLeadSuggest;
|
|
FLOATOBJ tmpfloat;
|
|
|
|
TRACEDDIENTRY("DrvQueryFontData");
|
|
|
|
// Get a pointer to our DEVDATA structure and validate it
|
|
|
|
pdev = (PDEVDATA) dhpdev;
|
|
|
|
if (! bValidatePDEV(pdev)) {
|
|
DBGERRMSG("bValidatePDEV");
|
|
SETLASTERROR(ERROR_INVALID_PARAMETER);
|
|
return -1;
|
|
}
|
|
|
|
// Make sure we have been given a valid font
|
|
|
|
if (! ValidPsFontIndex(pdev, pfo->iFace)) {
|
|
DBGERRMSG("ValidPsFontIndex");
|
|
SETLASTERROR(ERROR_INVALID_PARAMETER);
|
|
return -1;
|
|
}
|
|
|
|
// Get the metrics for the given font
|
|
|
|
pntfm = GetPsFontNtfm(pdev, pfo->iFace);
|
|
|
|
// Get the Notional to Device transform.
|
|
|
|
if((pxo = FONTOBJ_pxoGetXform(pfo)) == NULL)
|
|
{
|
|
DBGERRMSG("FONTOBJ_pxoGetXform");
|
|
return -1;
|
|
}
|
|
|
|
// Get the font transform information.
|
|
|
|
ulComplex = XFORMOBJ_iGetXform(pxo, &pdev->cgs.FontXform);
|
|
|
|
// Get local pointer to IFIMETRICS.
|
|
|
|
pifi = (PIFIMETRICS) ((PBYTE) pntfm + pntfm->ntfmsz.loIFIMETRICS);
|
|
|
|
// Fill in the appropriate data, depending on iMode.
|
|
|
|
switch(iMode) {
|
|
|
|
case QFD_GLYPHANDBITMAP:
|
|
|
|
// We don't actually return bitmaps, but we give them
|
|
// metrics via this call.
|
|
|
|
if (pgd) {
|
|
|
|
lWidth = (LONG) pntfm->ausCharWidths[hg];
|
|
|
|
// Currently, I am just putting the BBox for the font here, not
|
|
// for the character. Does anyone care?
|
|
|
|
// Now fill in the GLYPHDATA structure.
|
|
// Remember under NT 0,0 is top left, while under
|
|
// PostScript 0,0 is bottom left. Return device coords.
|
|
|
|
// fxInkBottom,Top are measured along pteSide vector:
|
|
|
|
ptl1.x = 0;
|
|
ptl1.y = pifi->rclFontBox.bottom;
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOFX, 1, &ptl1, &ptfx1);
|
|
pgd->fxInkBottom = iHipot(ptfx1.x, ptfx1.y);
|
|
if (pifi->rclFontBox.bottom < 0)
|
|
pgd->fxInkBottom = -pgd->fxInkBottom;
|
|
|
|
ptl1.x = 0;
|
|
ptl1.y = pifi->rclFontBox.top;
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOFX, 1, &ptl1, &ptfx1);
|
|
pgd->fxInkTop = iHipot(ptfx1.x, ptfx1.y);
|
|
if (pifi->rclFontBox.top < 0)
|
|
pgd->fxInkTop = -pgd->fxInkTop;
|
|
|
|
pgd->fxInkBottom = ROUNDFIX(pgd->fxInkBottom);
|
|
pgd->fxInkTop = ROUNDFIX(pgd->fxInkTop);
|
|
|
|
// aw info, ideally we would like more precission than 28.4
|
|
// in case of text at an angle. [bodind]
|
|
|
|
ptl1.x = WIDTH_MULT;
|
|
ptl1.y = 0;
|
|
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOFX, 1, &ptl1, &ptfx1);
|
|
|
|
fxWidth = iHipot(ptfx1.x, ptfx1.y);
|
|
|
|
// At this point fxWidth is just the length of the transformed
|
|
// vector [4K,0]. We will now multiply by the the fraction
|
|
// (transformed length)/(original length) or fxWidth/4K to get
|
|
// the transformed width of the glyph. We could be more direct
|
|
// but do it like this to be consistent with the math in the
|
|
// DrvQueryAdvanceWidths case where doing it this way allows us to
|
|
// remove a bApplyXform from an inner loop. [gerritv]
|
|
|
|
fxWidth = ( lWidth * fxWidth ) >> WIDTH_DIVISOR;
|
|
|
|
pgd->fxD = ROUNDFIX(fxWidth);
|
|
|
|
pgd->ptqD.x.HighPart = ( ptfx1.x * lWidth) >> WIDTH_DIVISOR;
|
|
pgd->ptqD.x.LowPart = 0;
|
|
pgd->ptqD.y.HighPart = ( ptfx1.y * lWidth) >> WIDTH_DIVISOR;
|
|
pgd->ptqD.y.LowPart = 0;
|
|
|
|
pgd->ptqD.x.HighPart = ROUNDFIX(pgd->ptqD.x.HighPart);
|
|
pgd->ptqD.y.HighPart = ROUNDFIX(pgd->ptqD.y.HighPart);
|
|
|
|
// Often wrong but it seems win31 is doing the same thing.
|
|
// This may cause char to stick outside the computed
|
|
// background box. Try ZapfChancery on NT and Win31.
|
|
|
|
pgd->fxA = 0;
|
|
pgd->fxAB = pgd->fxD;
|
|
|
|
pgd->hg = hg;
|
|
}
|
|
|
|
// Size is just the size of the (in this case non-existant) bitmap
|
|
|
|
return 0;
|
|
|
|
case QFD_MAXEXTENTS:
|
|
|
|
// If there is no output buffer, just return the size needed.
|
|
|
|
if (pv == NULL)
|
|
return sizeof(FD_DEVICEMETRICS);
|
|
|
|
ASSERT(cjSize >= sizeof(FD_DEVICEMETRICS));
|
|
|
|
// We have a large enough buffer, so fill it in.
|
|
|
|
pdm->flRealizedType = 0;
|
|
|
|
// Base and side, as used below, basically are vectors
|
|
// describing the orientation of the font. For example,
|
|
// for a left to right font, the base vector would be
|
|
// (1,0). The side vector should be in the direction of
|
|
// the ascender, so in the standard case the side vector
|
|
// would be (0,-1), since 0 is up in Windows.
|
|
|
|
ptl1.x = 1000;
|
|
ptl1.y = 0;
|
|
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOFX, 1, &ptl1, &ptfx1);
|
|
|
|
fxLength = iHipot(ptfx1.x, ptfx1.y);
|
|
|
|
// We are assuming FLOAT and LONG have the same size.
|
|
// Make sure that's indeed that case.
|
|
|
|
ASSERT(sizeof(FLOAT) == sizeof(LONG));
|
|
|
|
FLOATOBJ_SetLong(&tmpfloat, ptfx1.x);
|
|
FLOATOBJ_DivLong(&tmpfloat, fxLength);
|
|
*((LONG*) &pdm->pteBase.x) = FLOATOBJ_GetFloat(&tmpfloat);
|
|
|
|
FLOATOBJ_SetLong(&tmpfloat, ptfx1.y);
|
|
FLOATOBJ_DivLong(&tmpfloat, fxLength);
|
|
*((LONG*) &pdm->pteBase.y) = FLOATOBJ_GetFloat(&tmpfloat);
|
|
|
|
ptl1.x = 0;
|
|
ptl1.y = -1000;
|
|
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOFX, 1, &ptl1, &ptfx1);
|
|
|
|
fxLength = iHipot(ptfx1.x, ptfx1.y);
|
|
|
|
FLOATOBJ_SetLong(&tmpfloat, ptfx1.x);
|
|
FLOATOBJ_DivLong(&tmpfloat, fxLength);
|
|
*((LONG*) &pdm->pteSide.x) = FLOATOBJ_GetFloat(&tmpfloat);
|
|
|
|
FLOATOBJ_SetLong(&tmpfloat, ptfx1.y);
|
|
FLOATOBJ_DivLong(&tmpfloat, fxLength);
|
|
*((LONG*) &pdm->pteSide.y) = FLOATOBJ_GetFloat(&tmpfloat);
|
|
|
|
// Munge with the FD_REALIZEEXTRA external leading field for
|
|
// win31 compatability.
|
|
|
|
{
|
|
// -fxLength is the FIX 28.4 lfHeight in pels.
|
|
|
|
lfHeight = abs(FXTOL(fxLength));
|
|
|
|
// Get point size as win31 does.
|
|
|
|
dwPointSize = (DWORD)
|
|
MULDIV(lfHeight, PS_RESOLUTION,
|
|
pdev->dm.dmPublic.dmPrintQuality);
|
|
|
|
if (pifi->jWinPitchAndFamily & FF_ROMAN)
|
|
{
|
|
dwLeadSuggest = 2;
|
|
}
|
|
else if (pifi->jWinPitchAndFamily & FF_SWISS)
|
|
{
|
|
if (dwPointSize <= 12)
|
|
dwLeadSuggest = 2;
|
|
else if (dwPointSize < 14)
|
|
dwLeadSuggest = 3;
|
|
else
|
|
dwLeadSuggest = 4;
|
|
}
|
|
else
|
|
{
|
|
// Default to 19.6%.
|
|
|
|
dwLeadSuggest = (DWORD)
|
|
MULDIV(dwPointSize, 196, ADOBE_FONT_UNITS);
|
|
}
|
|
|
|
// Get notional internal leading.
|
|
|
|
InternalLeading =
|
|
(pifi->rclFontBox.top - pifi->rclFontBox.bottom) -
|
|
ADOBE_FONT_UNITS;
|
|
|
|
// Make it device coordinates.
|
|
|
|
InternalLeading =
|
|
MULDIV(InternalLeading, lfHeight, ADOBE_FONT_UNITS);
|
|
|
|
if (InternalLeading < 0)
|
|
InternalLeading = 0;
|
|
|
|
fxExtLeading = LTOFX(MULDIV(dwLeadSuggest,
|
|
pdev->dm.dmPublic.dmPrintQuality,
|
|
PS_RESOLUTION) - InternalLeading);
|
|
|
|
// If the external leading was calculated to be negative, or
|
|
// if this is a fixed pitch font, set external leading to
|
|
// zero.
|
|
|
|
if (fxExtLeading < 0 || (pifi->jWinPitchAndFamily & FIXED_PITCH))
|
|
fxExtLeading = 0;
|
|
|
|
// Fill in the leading field of the FD_REALIZEEXTRA struct.
|
|
|
|
pdm->lNonLinearExtLeading = (LONG) fxExtLeading;
|
|
|
|
if (pifi->jWinPitchAndFamily & FIXED_PITCH)
|
|
pdm->lNonLinearIntLeading = 0;
|
|
}
|
|
|
|
// cxMax the same as max char width for a and c's are zero:
|
|
|
|
ptl1.x = pifi->fwdMaxCharInc;
|
|
ptl1.y = 0;
|
|
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOL, 1, &ptl1, &ptl2);
|
|
|
|
// Now get the length of the vector
|
|
|
|
pdm->cxMax = iHipot(ptl2.x, ptl2.y);
|
|
|
|
// lD is the advance width if the font is fixed pitch,
|
|
// otherwise, set to zero.
|
|
|
|
if (pifi->jWinPitchAndFamily & FIXED_PITCH)
|
|
pdm->lD = (LONG)pdm->cxMax;
|
|
else
|
|
pdm->lD = 0;
|
|
|
|
// Calculate the max ascender
|
|
|
|
ptl1.x = 0;
|
|
ptl1.y = pifi->rclFontBox.top;
|
|
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOFX, 1, &ptl1, &ptfx1);
|
|
|
|
pdm->fxMaxAscender = iHipot(ptfx1.x, ptfx1.y);
|
|
|
|
// Calculate the max descender.
|
|
|
|
ptl1.x = 0;
|
|
ptl1.y = pifi->rclFontBox.bottom;
|
|
|
|
if (ptl1.y < 0)
|
|
ptl1.y = -ptl1.y;
|
|
|
|
// Do the ugly fixed pitch means zero internal leading hack
|
|
|
|
if (pifi->jWinPitchAndFamily & FIXED_PITCH)
|
|
{
|
|
// Get notional internal leading
|
|
|
|
InternalLeading =
|
|
(pifi->rclFontBox.top - pifi->rclFontBox.bottom) -
|
|
ADOBE_FONT_UNITS;
|
|
|
|
// WFW seems to make all the adjustment here in the
|
|
// MaxDescender, so we will too.
|
|
|
|
ptl1.y -= InternalLeading;
|
|
|
|
if (ptl1.y < 0)
|
|
ptl1.y = 0;
|
|
}
|
|
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOFX, 1, &ptl1, &ptfx1);
|
|
|
|
pdm->fxMaxDescender = iHipot(ptfx1.x, ptfx1.y);
|
|
|
|
pdm->fxMaxAscender = ROUNDFIX(pdm->fxMaxAscender);
|
|
pdm->fxMaxDescender = ROUNDFIX(pdm->fxMaxDescender);
|
|
|
|
// Calculate the underline position for this font instance
|
|
|
|
ptl1.x = 0;
|
|
ptl1.y = - pifi->fwdUnderscorePosition;
|
|
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOL, 1, &ptl1, &pdm->ptlUnderline1);
|
|
|
|
// Calculate the strikeout position for this font instance
|
|
|
|
ptl1.x = 0;
|
|
ptl1.y = - pifi->fwdStrikeoutPosition;
|
|
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOL, 1, &ptl1, &pdm->ptlStrikeOut);
|
|
|
|
// Calculate the line thickness
|
|
|
|
ptl1.x = 0;
|
|
ptl1.y = pifi->fwdUnderscoreSize;
|
|
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOL, 1, &ptl1, &pdm->ptlULThickness);
|
|
|
|
pdm->ptlSOThickness = pdm->ptlULThickness;
|
|
|
|
return(sizeof(FD_DEVICEMETRICS));
|
|
|
|
default:
|
|
|
|
DBGMSG1(DBG_LEVEL_ERROR, "Invalid iMode: %d\n", iMode);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DrvQueryAdvanceWidths(
|
|
DHPDEV dhpdev,
|
|
FONTOBJ *pfo,
|
|
ULONG iMode,
|
|
HGLYPH *phg,
|
|
PVOID plWidths,
|
|
ULONG cGlyphs
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implementation of DDI entry point DrvQueryAdvanceWidths.
|
|
Please refer to DDK documentation for more details.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVDATA pdev;
|
|
ULONG count;
|
|
PNTFM pntfm;
|
|
USHORT *pwidth;
|
|
XFORMOBJ *pxo;
|
|
POINTL ptl;
|
|
POINTFIX ptfx;
|
|
FIX fxWidth;
|
|
|
|
TRACEDDIENTRY("DrvQueryAdvanceWidths");
|
|
|
|
// Get a pointer to our DEVDATA structure and validate it
|
|
|
|
pdev = (PDEVDATA) dhpdev;
|
|
|
|
if (! bValidatePDEV(pdev))
|
|
{
|
|
DBGERRMSG("bValidatePDEV");
|
|
SETLASTERROR(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
// We treat GETWIDTHS and GETEASYWIDTHS the same way
|
|
|
|
if (iMode != QAW_GETWIDTHS && iMode != QAW_GETEASYWIDTHS)
|
|
{
|
|
DBGMSG1(DBG_LEVEL_ERROR, "Invalid iMode: %d\n", iMode);
|
|
SETLASTERROR(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
// See if there is anything to do
|
|
|
|
if (cGlyphs == 0)
|
|
return TRUE;
|
|
|
|
// Make sure we have been given a valid font
|
|
|
|
if (! ValidPsFontIndex(pdev, pfo->iFace)) {
|
|
DBGERRMSG("ValidPsFontIndex");
|
|
SETLASTERROR(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the metrics for the given font
|
|
|
|
pntfm = GetPsFontNtfm(pdev, pfo->iFace);
|
|
|
|
if((pxo = FONTOBJ_pxoGetXform(pfo)) == NULL)
|
|
{
|
|
DBGERRMSG("FONTOBJ_pxoGetXform");
|
|
return FALSE;
|
|
}
|
|
|
|
// Compute the character advance widths
|
|
|
|
pwidth = (USHORT *) plWidths;
|
|
|
|
ptl.x = WIDTH_MULT;
|
|
ptl.y = 0;
|
|
|
|
XFORMOBJ_bApplyXform(pxo, XF_LTOFX, 1, &ptl, &ptfx);
|
|
|
|
fxWidth = iHipot(ptfx.x, ptfx.y);
|
|
|
|
for (count = 0; count < cGlyphs; count++)
|
|
{
|
|
LONG lWidth = (LONG) pntfm->ausCharWidths[*phg++];
|
|
|
|
*pwidth++ = ROUNDFIX((lWidth * fxWidth) >> WIDTH_DIVISOR);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|