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.
612 lines
18 KiB
612 lines
18 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: vdmx.c
|
|
*
|
|
* Created: 03-Oct-1991 10:58:34
|
|
* Author: Jean-francois Peyroux [jeanp]
|
|
*
|
|
* Microsoft Confidential
|
|
*
|
|
* Copyright (c) Microsoft Corporation 1989, 1991
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* Copyright (c) 1991 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
|
|
#include "fd.h"
|
|
#include "winfont.h"
|
|
|
|
#define LINEAR_TRESHOLD 255
|
|
|
|
#pragma pack(1)
|
|
|
|
typedef struct
|
|
{
|
|
BYTE bCharSet; // Character set (0=all glyphs, 1=Windows ANSI subset
|
|
BYTE xRatio; // Value to use for x-Ratio
|
|
BYTE yStartRatio; // Starting y-Ratio value
|
|
BYTE yEndRatio; // Ending y-Ratio value
|
|
} RATIOS;
|
|
|
|
typedef struct
|
|
{
|
|
USHORT version; // Version number for table (starts at 0)
|
|
USHORT numRecs; // Number of VDMX groups present
|
|
USHORT numRatios; // Number of aspect ratio groupings
|
|
} VDMX_HDR;
|
|
|
|
typedef struct
|
|
{
|
|
USHORT yPelHeight; // yPelHeight (PPEM in Y) to which values apply
|
|
SHORT yMax; // yMax (in pels) for this yPelHeight
|
|
SHORT yMin; // yMin (in pels) for this yPelHeight
|
|
} VTABLE;
|
|
|
|
typedef struct
|
|
{
|
|
USHORT recs; // Number of height records in this group.
|
|
BYTE startsz; // Starting yPelHeight
|
|
BYTE endsz; // Ending yPelHeight
|
|
} VDMX;
|
|
|
|
#pragma pack()
|
|
|
|
/******************************Public Routine*******************************
|
|
*
|
|
* BOOL bSearchVdmxTable
|
|
*
|
|
* Description:
|
|
*
|
|
* if em > 0
|
|
* searches vdmx table for vA+vD == em. returns vA,vD (== em - vA), vEm
|
|
* else // em < 0
|
|
* searches vdmx table for vEm == em. returns vA,vD, vEm
|
|
*
|
|
* History:
|
|
*
|
|
* Tue 21-Jul-1992 -by- Bodin Dresevic [BodinD]
|
|
* update: ported to NT
|
|
* 15 Nov 1991 -by- Raymond E. Endres [rayen]
|
|
* Added aspect ratio option and optimized the function.
|
|
* 3 Oct 1991 -by- Jean-francois Peyroux [jeanp]
|
|
* Wrote it.
|
|
**************************************************************************/
|
|
|
|
BOOL
|
|
bSearchVdmxTable (
|
|
PBYTE pjVdmx,
|
|
ULONG ResX,
|
|
ULONG ResY,
|
|
INT EM, // NOT really EM, could be asc + desc wish in pixel units
|
|
VTABLE *pVTAB // out put structure
|
|
)
|
|
{
|
|
USHORT numRatios; // VDMX_HDR.numRatios
|
|
USHORT numVtable; // VDMX.recs, not VDMX_HDR.numRecs
|
|
|
|
RATIOS *pRatios;
|
|
VDMX *pVdmx;
|
|
VTABLE *pVtable;
|
|
LONG lRet, lRet2;
|
|
UINT i;
|
|
BYTE Abs_EM;
|
|
|
|
// do not call us if pjVdmx is null
|
|
|
|
ASSERTDD (pjVdmx != (PBYTE)NULL, "pjVdmx == NULL\n");
|
|
|
|
// The following line is silly, but we keep it here for win31 compatibility.
|
|
// It is possible to have EM = +256, which corresponds to |ppem| < 256
|
|
// such that there is an entry for this -|ppem| in the table but
|
|
// yMax-yMin for this entry may be equal to 256. This in fact is the case
|
|
// with symbol.ttf font [bodind]
|
|
|
|
if ((EM >= LINEAR_TRESHOLD) || (EM <= -LINEAR_TRESHOLD)) // assume EM > LINEAR_TRESHOLD scales linearly
|
|
return FALSE;
|
|
|
|
// need to proceed to search vdmx table
|
|
|
|
numRatios = SWAPW(((VDMX_HDR *) pjVdmx)->numRatios);
|
|
pRatios = (RATIOS *) &((VDMX_HDR *) pjVdmx)[1];
|
|
|
|
for(i = 0; i < numRatios; i++)
|
|
{
|
|
if (pRatios[i].bCharSet == 1)
|
|
{
|
|
// must be Windows ANSI subset
|
|
|
|
if (pRatios[i].xRatio == 0)
|
|
{
|
|
break;
|
|
} // auto match if 0
|
|
else
|
|
{ // is it within aspect ratios
|
|
lRet = ResY * pRatios[i].xRatio;
|
|
lRet2= ResX * pRatios[i].yStartRatio;
|
|
if (lRet >= lRet2)
|
|
{
|
|
lRet2 = ResX * pRatios[i].yEndRatio;
|
|
if (lRet <= lRet2)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i == numRatios) // did not find an aspect ratio match
|
|
return FALSE;
|
|
|
|
// found an aspect ratio match
|
|
|
|
pVdmx = (VDMX *) (pjVdmx + SWAPW(((USHORT *) &pRatios[numRatios])[i]));
|
|
Abs_EM = (BYTE) (EM >=0 ? EM : - EM);
|
|
|
|
if (EM > 0 || Abs_EM >= pVdmx->startsz && Abs_EM <= pVdmx->endsz)
|
|
{
|
|
// is there a Vtable for this EM
|
|
|
|
pVtable = (VTABLE *) &pVdmx[1];
|
|
numVtable = SWAPW(pVdmx->recs);
|
|
|
|
if (EM > 0)
|
|
{
|
|
// return the original yPelHeight
|
|
|
|
for (i = 0; i < numVtable; i++)
|
|
{
|
|
pVTAB->yPelHeight = SWAPW(pVtable[i].yPelHeight);
|
|
pVTAB->yMax = SWAPW(pVtable[i].yMax);
|
|
pVTAB->yMin = SWAPW(pVtable[i].yMin);
|
|
|
|
if ((pVTAB->yMax - pVTAB->yMin) == EM)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else if ((pVTAB->yMax - pVTAB->yMin) > EM)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else // return the actual em height in pixels
|
|
{
|
|
for (i = 0; i < numVtable; i++)
|
|
{
|
|
pVTAB->yPelHeight = SWAPW(pVtable[i].yPelHeight);
|
|
pVTAB->yMax = SWAPW(pVtable[i].yMax);
|
|
pVTAB->yMin = SWAPW(pVtable[i].yMin);
|
|
|
|
if ((INT)pVTAB->yPelHeight == -EM)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else if ((INT)pVTAB->yPelHeight > -EM)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef THIS_IS_COMMENTED_PSEUDOCODE
|
|
|
|
// BASED ON THE DISCUSSION OF KIRKO, BODIND AND GILMANW WITH GUNTERZ
|
|
|
|
|INPUT: hWish = wish height in pixel units
|
|
|
|
|
|OUTPUT: ascender, descender, ppem (all in pixel units) (dA,dD,dEm)
|
|
|
|
|
|
|
|
| NOTATION:
|
|
|
|
|
| dA = ascender in device/pixel space
|
|
| nA = ascender in notional space
|
|
| vA = ascender in vdmx table
|
|
|
|
|
| dD = descender in device/pixel space
|
|
| nD = descender in notional space
|
|
| vD = descender in vdmx table
|
|
|
|
|
| dEm = pixels per em in device space
|
|
| nEm = em height in notional space
|
|
| vEm = pixels per em in vdmx table
|
|
|
|
|
|
|
|
|LOCALS
|
|
|
|
|
| LONG hTrial
|
|
| LONG hEqualOrBelow
|
|
| BOOL wasAbove
|
|
| BOOL wasBelow
|
|
|
|
|
|PROCEDURE
|
|
|{
|
|
| if (hWish < 0) then
|
|
| {
|
|
| <look in the vdmx and look for a vEm that matches -hWish>;
|
|
| if (a match is found) then
|
|
| {
|
|
| dA = vA;
|
|
| dD = vD;
|
|
| }
|
|
| else
|
|
| {
|
|
| //
|
|
| // No Match is found in vdmx table, assume linear scaling
|
|
| //
|
|
| dA = round(nA * (-hWish) / nEm);
|
|
| dD = round(nD * (-hWish) / nEm);
|
|
| }
|
|
| ppEm = -hWish;
|
|
| return;
|
|
| }
|
|
|
|
|
|//
|
|
|// hWish > 0
|
|
|//
|
|
| <search the vdmx table for (vA + vD) that matches hWish>;
|
|
| if (a match is found)
|
|
| {
|
|
| dA = vA;
|
|
| dCs = vD;
|
|
| dEm = vEm;
|
|
| return;
|
|
| }
|
|
|
|
|
|//
|
|
|// Note, that from this point forward vA + vD never equals hWish
|
|
|// otherwise we would have found it in the step above
|
|
|//
|
|
| ppemTrial = round(nEm * hWish / (nA + nD));
|
|
|
|
|
| wasAbove = FALSE;
|
|
| wasBelow = FALSE;
|
|
|
|
|
| while (TRUE)
|
|
| {
|
|
| <search the vdmx table for vEm that matches ppemTrial>;
|
|
| if (a match is found)
|
|
| {
|
|
| hTrial = vA + vD;
|
|
| //
|
|
| // This can't equal hWish (see above) so don't bother
|
|
| // checking
|
|
| }
|
|
| else
|
|
| {
|
|
| hTrial = round(ppemTrial * (nA + nD) / nEm);
|
|
| if (hTrial == hWish)
|
|
| {
|
|
| hEqualOrBelow = hTrial;
|
|
| break;
|
|
| }
|
|
| }
|
|
|
|
|
| if (hTrial < hWish)
|
|
| {
|
|
| hEqualOrBelow = hTrial;
|
|
| if (wasAbove)
|
|
| break;
|
|
| ppemTrial = ppemTrial + 1;
|
|
| wasBelow = TRUE;
|
|
| }
|
|
| else
|
|
| {
|
|
| ppemTrial = ppemTrial - 1; // <==== NEW POSITION
|
|
| if (wasBelow)
|
|
| break;
|
|
| // <==== OLD POSITION
|
|
| wasAbove = TRUE
|
|
| }
|
|
| }
|
|
| dA = round(ppemTrial * nA / nEm);
|
|
| dD = hEqualOrBelow - dA;
|
|
| dEm = ppemTrial;
|
|
| return;
|
|
|}.
|
|
|
|
|
|
|
#endif // THIS_IS_COMMENTED_PSEUDOCODE
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* VOID vQuantizeXform
|
|
*
|
|
* Effects: quantize the xform according to win31 recipe. as side effects
|
|
* this routine may compute ascender and descener in device space
|
|
* from vdmx table as well as number of pixels per M in device space.
|
|
*
|
|
* History:
|
|
* 25-Jul-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vQuantizeXform (
|
|
PFONTCONTEXT pfc
|
|
)
|
|
{
|
|
BYTE *pjView = (BYTE *)pfc->pff->pvView;
|
|
Fixed fxMyy = pfc->mx.transform[1][1];
|
|
PBYTE pjVdmx = (pfc->ptp->ateOpt[IT_OPT_VDMX].dp) ?
|
|
(pjView + pfc->ptp->ateOpt[IT_OPT_VDMX].dp) :
|
|
NULL ;
|
|
|
|
LONG hWish;
|
|
VTABLE vtb, vtbPrev;
|
|
|
|
LONG ppemTrial, hTrial, yEmN, yHeightN;
|
|
|
|
BOOL bWasAbove, bWasBelow, bFound, bFoundPrev;
|
|
|
|
sfnt_FontHeader * phead =
|
|
(sfnt_FontHeader *)(pjView + pfc->ptp->ateReq[IT_REQ_HEAD].dp);
|
|
BYTE * pjOS2 = (pfc->ptp->ateOpt[IT_OPT_OS2].dp) ?
|
|
(pjView + pfc->ptp->ateOpt[IT_OPT_OS2].dp):
|
|
NULL ;
|
|
|
|
yEmN = pfc->pff->ifi.fwdUnitsPerEm;
|
|
|
|
if (!((pfc->flXform & XFORM_HORIZ) && (fxMyy > 0) && (pjVdmx != (PBYTE)NULL)))
|
|
{
|
|
// nothing to do, just return.
|
|
|
|
return;
|
|
}
|
|
|
|
// compute hWish in pixel coords. This is lfHeight from the logfont, except
|
|
// that it has been transformed to device pixel units and the sign is preserved
|
|
|
|
if (pfc->flFontType & FO_EM_HEIGHT)
|
|
{
|
|
hWish = FixMul(fxMyy, -yEmN);
|
|
}
|
|
else // use tmp variable
|
|
{
|
|
yHeightN = pfc->pff->ifi.fwdWinAscender + pfc->pff->ifi.fwdWinDescender;
|
|
hWish = FixMul(fxMyy, yHeightN);
|
|
}
|
|
|
|
// quick out, all bSearchVdmxTable routines will fail if hWish is too big:
|
|
|
|
|
|
|
|
if (bSearchVdmxTable(pjVdmx,
|
|
pfc->sizLogResPpi.cx,
|
|
pfc->sizLogResPpi.cy,
|
|
hWish,
|
|
&vtb)
|
|
)
|
|
{
|
|
pfc->yMax = - vtb.yMin;
|
|
pfc->yMin = - vtb.yMax;
|
|
pfc->lEmHtDev = vtb.yPelHeight;
|
|
|
|
// flag that dA and dD have been computed, do not scale linerly:
|
|
|
|
pfc->flXform |= XFORM_VDMXEXTENTS;
|
|
}
|
|
else
|
|
{
|
|
// dA and dD will have to be computed using linear scaling
|
|
// after the xform is quantized using win31 hacked recipe
|
|
// get the notional space values which are needed for scaling
|
|
|
|
// get the notional space values
|
|
|
|
if (pjOS2)
|
|
{
|
|
// win 31 compatibility: we only take the max over win 31 char set:
|
|
// all the glyphs outside this set, if they stand out will get chopped
|
|
// off to match the height of the win31 char subset:
|
|
|
|
yHeightN = BE_INT16(pjOS2 + OFF_OS2_usWinDescent) +
|
|
BE_INT16(pjOS2 + OFF_OS2_usWinAscent);
|
|
}
|
|
else
|
|
{
|
|
yHeightN = BE_INT16(&phead->yMax) - BE_INT16(&phead->yMin);
|
|
}
|
|
|
|
if (hWish < 0)
|
|
{
|
|
pfc->lEmHtDev = -hWish;
|
|
}
|
|
else // hWish > 0
|
|
{
|
|
// Note, that from this point forward vA + vD never equals hWish
|
|
// otherwise we would have found it in the step above. This claim
|
|
// is WRONG for only one reason. suppose hWish is 256. bSearchVdmxTable
|
|
// will return FALSE because of the early exit test |EM| <= LINEAR_TRESHOLD
|
|
// at the begininig of the routine. We have to keep this test in the
|
|
// code for compatibility reasons. Now it is possible to have
|
|
// ppemTrial <= LINEAR_TRESHOLD, so that bSearchVdmxTable will not hit the
|
|
// early exit, and such that there exists an entry in the vdmx table
|
|
// for this -ppemTrial, but with yMax-yMin == 256 == hWish.
|
|
|
|
// ppemTrial = F16_16TOLROUND(yEmN * fxMyy);
|
|
ppemTrial = FixMul(fxMyy, yEmN);
|
|
|
|
bWasAbove = FALSE;
|
|
bWasBelow = FALSE;
|
|
bFound = FALSE;
|
|
bFoundPrev = FALSE; // save the value from the prev. loop
|
|
|
|
// init the strucs
|
|
|
|
vtb.yMin = 0;
|
|
vtb.yMax = 0;
|
|
vtb.yPelHeight = 0;
|
|
vtbPrev = vtb;
|
|
|
|
for (;TRUE; bFoundPrev = bFound, vtbPrev = vtb)
|
|
{
|
|
// search the vdmx table for vEm that matches ppemTrial
|
|
|
|
if
|
|
(
|
|
bFound = bSearchVdmxTable(
|
|
pjVdmx,
|
|
pfc->sizLogResPpi.cx,
|
|
pfc->sizLogResPpi.cy,
|
|
-ppemTrial,
|
|
&vtb)
|
|
)
|
|
{
|
|
hTrial = vtb.yMax - vtb.yMin;
|
|
//
|
|
// This can't equal hWish (see above) so don't bother
|
|
// checking? WRONG!!! see teh comment above.
|
|
|
|
if (hTrial == hWish)
|
|
{
|
|
// This assert would be correct if it were not
|
|
// for occasional bugs in vdmx tables.
|
|
// In the case of Bell MT Regular, vA+vD = 0x13 for
|
|
// lEmHt = 0x0f which is STRICTLY bigger than
|
|
// vA+vD = 0x12 for lEmHt = 0x10 which is absurd.
|
|
// For this reason the first
|
|
// bSearchVdmxTable(EM = 0X12) fails to find an entry
|
|
// while the second bSearchVdmxTable(EM =- 0X10)
|
|
// DOES FIND an entry
|
|
// in vdmx table such that vA+vD=0x12, generating
|
|
// the commented assertion to bark. That is why we converted
|
|
// assertion to just print out a warning message.
|
|
|
|
|
|
#if DBG
|
|
|
|
// ASSERTGDI(hWish > LINEAR_TRESHOLD, "TTFD! hWish <= LINEAR_TRESHOLD\n");
|
|
|
|
if (hWish <= LINEAR_TRESHOLD)
|
|
TtfdDbgPrint("TTFD! hWish <= LINEAR_TRESHOLD\n");
|
|
|
|
#endif
|
|
|
|
/* Bell MT Table:
|
|
|
|
pVtable --> f800 ff08 // F8 entries = numVtable,
|
|
// startsz = 8, endsz = ff
|
|
0800 0800 feff
|
|
0900 0900 feff
|
|
0a00 0900 fdff
|
|
0b00 0a00 fdff
|
|
0c00 0c00 fdff
|
|
0d00 0c00 fdff
|
|
0e00 0d00 fcff
|
|
0f00 0e00 fbff <- yMax-yMin = 14-(-5) = 19 == 0X13
|
|
1000 0e00 fcff <- yMax-yMin = 14-(-4) = 18 // problem
|
|
1100 0f00 fbff
|
|
1200 1100 fbff
|
|
1300 1100 fbff
|
|
..............
|
|
|
|
*/
|
|
|
|
pfc->yMax = - vtb.yMin;
|
|
pfc->yMin = - vtb.yMax;
|
|
pfc->lEmHtDev = vtb.yPelHeight;
|
|
|
|
// flag that dA and dD have been computed, do not scale linerly:
|
|
|
|
pfc->flXform |= XFORM_VDMXEXTENTS;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hTrial = LongMulDiv(ppemTrial, yHeightN, yEmN);
|
|
|
|
if (hTrial == hWish)
|
|
{
|
|
// hEqualOrBelow = hTrial;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (hTrial < hWish)
|
|
{
|
|
// hEqualOrBelow = hTrial;
|
|
if (bWasAbove)
|
|
{
|
|
if (bFound) // just found this hTrial in the search above
|
|
{
|
|
pfc->yMax = - vtb.yMin;
|
|
pfc->yMin = - vtb.yMax;
|
|
|
|
// flag that dA and dD have been computed, do not scale linerly:
|
|
|
|
pfc->flXform |= XFORM_VDMXEXTENTS;
|
|
}
|
|
break;
|
|
}
|
|
ppemTrial = ppemTrial + 1;
|
|
bWasBelow = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ppemTrial = ppemTrial - 1; // <==== NEW POSITION
|
|
if (bWasBelow)
|
|
{
|
|
if (bFoundPrev) // just found this hTrial in the search above
|
|
{
|
|
ASSERTDD (ppemTrial == vtbPrev.yPelHeight,
|
|
"vdmx logic screwed up");
|
|
|
|
pfc->yMax = - vtbPrev.yMin;
|
|
pfc->yMin = - vtbPrev.yMax;
|
|
|
|
// flag that dA and dD have been computed, do not scale linerly:
|
|
|
|
pfc->flXform |= XFORM_VDMXEXTENTS;
|
|
}
|
|
break;
|
|
}
|
|
// <==== OLD POSITION
|
|
bWasAbove = TRUE;
|
|
}
|
|
}
|
|
pfc->lEmHtDev = ppemTrial;
|
|
}
|
|
}
|
|
|
|
// the following line means quantizing:
|
|
|
|
pfc->mx.transform[1][1] = FixDiv(pfc->lEmHtDev, yEmN);
|
|
|
|
// now fix xx component accordingly: xxNew = xxOld * (yyNew/yyOld)
|
|
|
|
// we do one final tweak with the transform here:
|
|
// If the difference between
|
|
// horizontal and vertical scaling is so small that the resulting
|
|
// avg font width is the same if we replace x scaling by y scaling
|
|
// than we will do it, which will result in diag transform and we will
|
|
// be able to use hdmx tables for this realization. By doing so
|
|
// we ensure that we get the same realization when we enumerate font
|
|
// and then use the logfont returned from enumeration to realize this font
|
|
// again.
|
|
|
|
if
|
|
(
|
|
(pfc->mx.transform[0][0] == fxMyy) ||
|
|
(FixMul(pfc->mx.transform[0][0] - pfc->mx.transform[1][1],
|
|
(Fixed)pfc->pff->ifi.fwdAveCharWidth) == 0)
|
|
)
|
|
{
|
|
pfc->mx.transform[0][0] = pfc->mx.transform[1][1];
|
|
}
|
|
else
|
|
{
|
|
pfc->mx.transform[0][0] = LongMulDiv(
|
|
pfc->mx.transform[0][0],
|
|
pfc->mx.transform[1][1],
|
|
fxMyy
|
|
);
|
|
}
|
|
return;
|
|
}
|