Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2540 lines
76 KiB

/******************************Module*Header*******************************\
* Module Name: fdfc.c *
* *
* Open,Close,Reset Font Context *
* *
* Created: 18-Nov-1991 11:55:38 *
* Author: Bodin Dresevic [BodinD] *
* *
* Copyright (c) 1993 Microsoft Corporation *
\**************************************************************************/
#include "fd.h"
#include "winfont.h"
#if DBG
// #define DBG_XFORM
extern ULONG gflTtfdDebug;
ULONG gflTtfdDebug = 0;
#endif
BOOL bSetXform
(
PFONTCONTEXT pfc // OUT
);
STATIC BOOL bNewXform
(
FONTOBJ *pfo, // IN
PFONTCONTEXT pfc // OUT
);
STATIC BOOL bComputeMaxGlyph(PFONTCONTEXT pfc);
#define CVT_TRUNCATE 0x00000001
#define CVT_TO_FIX 0X00000002
STATIC BOOL bFloatToL(FLOAT e, PLONG pl);
STATIC Fixed fxPtSize(PFONTCONTEXT pfc);
STATIC BOOL ttfdCloseFontContext(FONTCONTEXT *pfc);
STATIC VOID vFindHdmxTable(PFONTCONTEXT pfc);
STATIC ULONG iHipot(LONG x, LONG y);
LONG lFFF(LONG l);
#define FFF(e,l) *(LONG*)(&(e)) = lFFF(l)
/******************************Public*Routine******************************\
*
* BOOL bInitInAndOut
*
*
* History:
* 18-Nov-1992 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BOOL bInitInAndOut(FONTFILE *pff)
{
FS_ENTRY iRet;
fs_GlyphInputType *pgin;
fs_GlyphInfoType *pgout;
ASSERTDD(pff->pj034 != NULL, "pff->pj3 IS null\n");
pgin = (fs_GlyphInputType *)pff->pj034;
pgout = (fs_GlyphInfoType *)(pff->pj034 + CJ_IN);
if ((iRet = fs_OpenFonts(pgin, pgout)) != NO_ERR)
{
V_FSERROR(iRet);
return (FALSE);
}
pgin->memoryBases[0] = (char *)(pff->pj034 + CJ_IN + CJ_OUT);
pgin->memoryBases[1] = NULL;
pgin->memoryBases[2] = NULL;
// initialize the font scaler, notice no fields of pfc->gin are initialized [BodinD]
if ((iRet = fs_Initialize(pgin, pgout)) != NO_ERR)
{
// clean up and return:
V_FSERROR(iRet);
RET_FALSE("TTFD!_ttfdLoadFontFile(): fs_Initialize \n");
}
// initialize info needed by NewSfnt function
pgin->sfntDirectory = (int32 *)pff->pvView; // pointer to the top of the view of the ttf file
#ifdef FE_SB
pgin->clientID = (int32)pff; // pointer to FONTFILE.
#else
pgin->clientID = (int32)pff->pvView; // pointer to the top of the
// view of the ttf file
#endif // FE_SB
pgin->GetSfntFragmentPtr = pvGetPointerCallback;
pgin->ReleaseSfntFrag = vReleasePointerCallback;
pgin->param.newsfnt.platformID = BE_UINT16(&pff->ui16PlatformID);
pgin->param.newsfnt.specificID = BE_UINT16(&pff->ui16SpecificID);
if ((iRet = fs_NewSfnt(pgin, pgout)) != NO_ERR)
{
// clean up and exit
V_FSERROR(iRet);
RET_FALSE("TTFD!_ttfdLoadFontFile(): fs_NewSfnt \n");
}
// sizes 3 and 4 returned
ASSERTDD(pff->cj3 == (ULONG)NATURAL_ALIGN(pgout->memorySizes[3]), "cj3\n");
ASSERTDD(pff->cj4 == (ULONG)NATURAL_ALIGN(pgout->memorySizes[4]), "cj4\n");
// pj3 should be shareable, but unfortunately there are fonts that
// use it to store some info there which they expect to find there at
// later times, so we have to make pj3 private as well
pgin->memoryBases[3] = pff->pj034 + (CJ_IN + CJ_OUT + CJ_0);
// not shared, private
pgin->memoryBases[4] = pgin->memoryBases[3] + pff->cj3;
return TRUE;
}
/******************************Public*Routine******************************\
*
* Find minimal non-zero advance width
*
* Called by: ttfdOpenFontContext
*
* Routines called: bGetTablePointers
*
* History:
* 02-May-1996 [kirko]
* Added checking for table corruption.
* 22-Feb-1996 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
VOID vGetMinD(FONTFILE *pff)
{
#ifdef FE_SB
extern PBYTE pjTable(ULONG, PFONTFILE, ULONG*);
#else
extern PBYTE pjTable(ULONG, PVOID, ULONG, ULONG*);
#endif
extern BOOL bGetTablePointers(PVOID, ULONG, BYTE*, TABLE_POINTERS*);
sfnt_HorizontalHeader *phhea;
sfnt_HorizontalMetrics *phmtx;
ULONG cHMTX;
BYTE *pjView;
ULONG ig, igMin;
USHORT usMinWidth = 0xffff;
USHORT usWidth;
pjView = (BYTE *)pff->pvView;
ASSERTDD(pjView, "pjView is NULL 1\n");
ASSERTDD(pff->igMinD == USHRT_MAX, "igMinD is bogus \n");
#if DBG
{
// check for table trashing
BYTE *pj;
ULONG cj;
TABLE_ENTRY *pte;
#ifdef FE_SB
pj = pjTable('aehh', pff, &cj);
#else
pj = pjTable('aehh', pff->pvView, pff->cjView, &cj);
#endif
pte = pff->tp.ateReq + IT_REQ_HHEAD;
if ((ULONG) (pj - pjView) != pte->dp) {
RIP("FONTFILE contains bad offset to 'hhea' table\n");
} else if (cj != pte->cj) {
RIP("FONTFILE contains bad size of 'hhea' table\n");
}
#ifdef FE_SB
pj = pjTable('xtmh', pff, &cj);
#else
pj = pjTable('xtmh', pff->pvView, pff->cjView, &cj);
#endif
pte = pff->tp.ateReq + IT_REQ_HMTX;
if ((ULONG)(pj - pjView) != pte->dp) {
RIP("FONTFILE contains bad offset to 'hmtx' table\n");
} else if (cj != pte->cj) {
RIP("FONTFILE contains bad size of 'hmtx' table\n");
}
}
#endif
// There is a bug that causes the table of pointers to be randomly
// trashed upon entry to this routine. So, as a precaution I
// will regenerate the table at this point. This routine is called
// only upon a new realization, so the cost should not be prohibitive.
// Of course, the right thing to do is to understand and eliminate
// the source of the corruption, but this will have to do until
// that is done [kirko].
#ifndef FE_SB
if (!bGetTablePointers(pff->pvView,pff->cjView,0,&(pff->tp))) {
RIP("bGetTablePointers failed\n");
}
#endif
phhea = (sfnt_HorizontalHeader *)(pjView + pff->tp.ateReq[IT_REQ_HHEAD].dp);
phmtx = (sfnt_HorizontalMetrics *)(pjView + pff->tp.ateReq[IT_REQ_HMTX].dp);
cHMTX = (ULONG) BE_UINT16(&phhea->numberOf_LongHorMetrics);
for (ig = 0; ig < cHMTX; ig++)
{
usWidth = BE_UINT16(&phmtx[ig].advanceWidth);
if ((usWidth < usMinWidth) && (usWidth != 0))
{
usMinWidth = usWidth;
igMin = ig;
}
}
// store the results
pff->usMinD = usMinWidth;
pff->igMinD = (USHORT)igMin;
}
/******************************Public*Routine******************************\
* ttfdOpenFontContext *
* *
* History: *
* 11-Nov-1991 -by- Bodin Dresevic [BodinD] *
* Wrote it. *
\**************************************************************************/
#ifdef FE_SB
FONTCONTEXT *ttfdOpenFontContext(FONTOBJ *pfo)
{
PFONTCONTEXT pfc = PFC(NULL);
PTTC_FONTFILE pttc = (PTTC_FONTFILE)pfo->iFile;
ULONG iFace = pfo->iFace;
ULONG iFile;
PFONTFILE pff;
if (!pttc)
return((FONTCONTEXT *) NULL);
ASSERTDD(
iFace <= pttc->ulNumEntry,
"gdisrv!ttfdOpenFontContextTTC(): ulFont out of range\n"
);
iFile = PFF(pttc->ahffEntry[0].hff)->iFile;
if (pttc->cRef == 0)
{
// have to remap the file
if
(
!EngMapFontFile(
iFile,
(PULONG*)&pttc->pvView,
&pttc->cjView
)
)
{
RETURN("TTFD!_bMapTTF, somebody removed a ttf file\n",NULL);
}
}
// Get FONTFILE structure.
pff = PFF(pttc->ahffEntry[iFace-1].hff);
if (pff->cRef == 0)
{
// Update FILEVIEW structure in FONTFILE
pff->pvView = pttc->pvView;
pff->cjView = pttc->cjView;
// We have precomputed all sizes and we are allocating all memory at once:
ASSERTDD(pff->pj034 == NULL, "TTFD, pff->pj034 should be null\n");
if
(
!(pff->pj034 = (PBYTE)PV_ALLOC(
CJ_IN +
CJ_OUT +
CJ_0 +
pff->cj3 +
pff->cj4
))
)
{
if(pttc->cRef == 0)
EngUnmapFontFile(iFile);
RETURN("ttfd, MEM Alloc failed for pj034\n", NULL);
}
if (!bInitInAndOut(pff)) // could cause the exception
{
if(pttc->cRef == 0)
EngUnmapFontFile(iFile);
V_FREE(pff->pj034);
pff->pj034 = (BYTE *)NULL;
RETURN("ttfd, bInitInAndOut failed for \n", NULL);
}
// check if usMinD has been initialized, if not do it
if (!pff->usMinD)
vGetMinD(pff);
}
// allocate memory for the font context and get the pointer to font context
ASSERTDD(!pff->pfcToBeFreed, "TTFD!ttfdOpenFontContext, pfcToBeFreed NOT null\n");
if ((pff->pfcToBeFreed = pfc = pfcAlloc(sizeof(FONTCONTEXT))) ==
(FONTCONTEXT *) NULL )
{
WARNING("TTFD!_ttfdOpenFontContext, hfcAlloc failed\n");
if (pttc->cRef == 0)
EngUnmapFontFile(iFile);
if (pff->cRef == 0)
{
V_FREE(pff->pj034);
pff->pj034 = (BYTE *)NULL;
}
return((FONTCONTEXT *) NULL);
}
// state that the hff passed to this function is the FF selected in
// this font context
pfc->pfo = pfo;
pfc->pff = pff;
pfc->ptp = &pff->tp;
// parts of FONTOBJ that are important
pfc->flFontType = pfo->flFontType ;
pfc->sizLogResPpi = pfo->sizLogResPpi;
pfc->ulStyleSize = pfo->ulStyleSize ;
// tt strucs
pfc->pgin = (fs_GlyphInputType *) pfc->pff->pj034;
pfc->pgout = (fs_GlyphInfoType *) (pfc->pff->pj034 + CJ_IN);
// given the values in the context info store the transform matrix:
if (!bNewXform(pfo,pfc))
{
// clean up and exit
WARNING("TTFD!_ttfdOpenFontContext, bNewXform\n");
vFreeFC(pfc);
pff->pfcToBeFreed = NULL;
if (pttc->cRef == 0)
EngUnmapFontFile(iFile);
if (pff->cRef == 0)
{
V_FREE(pff->pj034);
pff->pj034 = (BYTE *)NULL;
}
return((FONTCONTEXT *) NULL);
}
pfc->ulControl = 0;
// 2,4,6... (n*2) is Vertical face.
pfc->bVertical = (pttc->ahffEntry[iFace-1].iFace & 0x1) ? FALSE : TRUE;
// increase the reference count of the font file, WE DO THIS ONLY WHEN
// WE ARE SURE that can not fail any more
// we have pfc, no exceptions any more
// now that we have pfc, we do not want to delete it
pff->pfcToBeFreed = NULL;
(pff->cRef)++;
(pttc->cRef)++;
return(pfc);
}
#else
FONTCONTEXT *ttfdOpenFontContext(FONTOBJ *pfo)
{
PFONTCONTEXT pfc = PFC(NULL);
PFONTFILE pff = (PFONTFILE)pfo->iFile;
ASSERTDD(pfo->iFace <= pff->ulNumFaces,
"gdisrv!ttfdOpenFontContext(): ulFont out of range\n");
if (!pff)
return((FONTCONTEXT *) NULL);
if (pff->cRef == 0)
{
// have to remap the file
if
(
!EngMapFontFile(
pff->iFile,
(PULONG*)&pff->pvView,
&pff->cjView
)
)
{
RETURN("TTFD!ttfdOpenFontContext: bMapFileUNICODE failed\n",NULL);
}
ASSERTDD(pff->pj034 == NULL, "pff->pj034 should be null\n");
// We have precomputed all sizes and we are allocating all memory at once:
if
(
!(pff->pj034 = (PBYTE)PV_ALLOC(
CJ_IN +
CJ_OUT +
CJ_0 +
pff->cj3 +
pff->cj4
))
)
{
EngUnmapFontFile(pff->iFile);
RETURN("ttfd, MEM Alloc failed for pj034\n", NULL);
}
if (!bInitInAndOut(pff)) // could cause the exception
{
EngUnmapFontFile(pff->iFile);
V_FREE(pff->pj034);
pff->pj034 = (BYTE *)NULL;
RETURN("ttfd, bInitInAndOut failed for \n", NULL);
}
// check if usMinD has been initialized, if not do it
if (!pff->usMinD)
vGetMinD(pff);
}
// allocate memory for the font context and get the pointer to font context
ASSERTDD(!pff->pfcToBeFreed, "ttfdOpenFontContext, pfcToBeFreed NOT null\n");
if ((pff->pfcToBeFreed = pfc = pfcAlloc(sizeof(FONTCONTEXT))) == (FONTCONTEXT *) NULL )
{
WARNING("TTFD!_ttfdOpenFontContext, hfcAlloc failed\n");
if (pff->cRef == 0)
{
EngUnmapFontFile(pff->iFile);
V_FREE(pff->pj034);
pff->pj034 = (BYTE *)NULL;
}
return((FONTCONTEXT *) NULL);
}
// state that the hff passed to this function is the FF selected in
// this font context
pfc->pfo = pfo;
pfc->pff = pff;
pfc->ptp = &pff->tp;
// parts of FONTOBJ that are important
pfc->flFontType = pfo->flFontType ;
pfc->sizLogResPpi = pfo->sizLogResPpi;
pfc->ulStyleSize = pfo->ulStyleSize ;
// tt strucs
pfc->pgin = (fs_GlyphInputType *) pfc->pff->pj034;
pfc->pgout = (fs_GlyphInfoType *) (pfc->pff->pj034 + CJ_IN);
// given the values in the context info store the transform matrix:
if (!bNewXform(pfo,pfc))
{
// clean up and exit
WARNING("TTFD!_ttfdOpenFontContext, bNewXform\n");
vFreeFC(pfc);
pff->pfcToBeFreed = NULL;
if (pff->cRef == 0)
{
EngUnmapFontFile(pff->iFile);
V_FREE(pff->pj034);
pff->pj034 = (BYTE *)NULL;
}
return((FONTCONTEXT *) NULL);
}
pfc->ulControl = 0;
pfc->bVertical = ((pfo->iFace == 2) ? TRUE : FALSE);
// increase the reference count of the font file, WE DO THIS ONLY WHEN
// WE ARE SURE that can not fail any more
// we have pfc, no exceptions any more
// now that we have pfc, we do not want to delete it
pff->pfcToBeFreed = NULL;
(pff->cRef)++;
return(pfc);
}
#endif
/******************************Public*Routine******************************\
*
* ttfdCloseFontContext
*
*
* Effects:
*
*
* History:
* 11-Nov-1991 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
#ifdef FE_SB
BOOL
ttfdCloseFontContext (
FONTCONTEXT *pfc
)
{
PTTC_FONTFILE pttc;
PFONTFILE pff;
if (pfc == (FONTCONTEXT *) NULL)
return(FALSE);
pff = pfc->pff;
pttc = pfc->pff->pttc;
// decrement the reference count for the corresponding FONTFILE
ASSERTDD(pff->cRef > 0L, "TTFD!_CloseFontContext: cRef <= 0 \n");
pff->cRef--;
pttc->cRef--;
// if this was the last fc that last used the buffer at pj3, invalidate
// the associated pfcLast
if (pff->pfcLast == pfc)
pff->pfcLast = PFC(NULL);
// in case that this is happening after the exception, make sure to release
// any memory that may have possibly been allocated to perform queries
// on per character basis:
if (pttc->fl & FF_EXCEPTION_IN_PAGE_ERROR)
{
// if exception this memory has already been freed
ASSERTDD(!pff->pj034, "\n TTFD! pff->pj3 is NOT null\n");
if (pfc->gstat.pv) // this may or may have not been allocated
{
V_FREE(pfc->gstat.pv);
pfc->gstat.pv = NULL;
}
}
else
{
ASSERTDD(pff->pj034, "\n TTFD! pff->pj3 is null\n");
}
if (pff->cRef == 0)
{
// there are no fc's around to use memory at pff->pj3, release it.
if (!(pttc->fl & FF_EXCEPTION_IN_PAGE_ERROR))
{
V_FREE(pff->pj034);
pff->pj034 = (BYTE *)NULL;
}
}
if (pttc->cRef == 0)
{
// file will not be used for a while,
EngUnmapFontFile(PFF(pttc->ahffEntry[0].hff)->iFile);
}
// free the memory associated with hfc
vFreeFC(pfc);
return(TRUE);
}
#else
BOOL
ttfdCloseFontContext (
FONTCONTEXT *pfc
)
{
PFONTFILE pff;
if (pfc == (FONTCONTEXT *) NULL)
return(FALSE);
pff = pfc->pff;
// decrement the reference count for the corresponding FONTFILE
ASSERTDD(pff->cRef > 0L, "CloseFontContext: cRef <= 0 \n");
pff->cRef--;
// if this was the last fc that last used the buffer at pj3, invalidate
// the associated pfcLast
if (pff->pfcLast == pfc)
pff->pfcLast = PFC(NULL);
// in case that this is happening after the exception, make sure to release
// any memory that may have possibly been allocated to perform queries
// on per character basis:
if (pff->fl & FF_EXCEPTION_IN_PAGE_ERROR)
{
// if exception this memory has already been freed
ASSERTDD(!pff->pj034, "\n pff->pj3 is NOT null\n");
if (pfc->gstat.pv) // this may or may have not been allocated
{
V_FREE(pfc->gstat.pv);
pfc->gstat.pv = NULL;
}
}
else
{
ASSERTDD(pff->pj034, "\n pff->pj3 is null\n");
}
if (pff->cRef == 0)
{
// there are no fc's around to use memory at pff->pj3, release it.
if (!(pff->fl & FF_EXCEPTION_IN_PAGE_ERROR))
{
V_FREE(pff->pj034);
pff->pj034 = (BYTE *)NULL;
}
// file will not be used for a while,
EngUnmapFontFile(pff->iFile);
}
// free the memory associated with hfc
vFreeFC(pfc);
return(TRUE);
}
#endif
/******************************Public*Routine******************************\
* ttfdDestroyFont
*
* Driver can release all resources associated with this font realization
* (embodied in the FONTOBJ).
*
* History:
* 27-Oct-1992 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
VOID
ttfdDestroyFont (
FONTOBJ *pfo
)
{
// For the ttfd, this is simply closing the font context.
// We cleverly store the font context handle in the FONTOBJ pvProducer
// field.
// pfo->pvProducer COULD BE null if exception occured while trying to create fc
if (pfo->pvProducer)
{
ttfdCloseFontContext((FONTCONTEXT *) pfo->pvProducer);
pfo->pvProducer = NULL;
}
}
/******************************Public*Routine******************************\
* ttfdFree
*
*
* Effects:
*
* Warnings:
*
* History:
* 27-Oct-1992 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
VOID
ttfdFree (
PVOID pv,
ULONG id
)
{
DYNAMICDATA *pdd;
//
// If id is NULL, then we can ignore.
//
if ( (pdd = (DYNAMICDATA *) id) == (DYNAMICDATA *) NULL )
return;
// What kind of data?
//
switch (pdd->ulDataType)
{
case ID_KERNPAIR:
// Invalidate the cached pointer to the data.
pdd->pff->pkp = NULL; // important to check at vUnloadFontFile time
// Free the kerning pair buffer and DYNAMICDATA structure.
pv; // we ignore pv because it is part of the mem allocated with DYNAMICDATA structure.
V_FREE(pdd); // this frees both the DYNAMICDATA struct and the FD_KERNINGPAIR buffer.
break;
default:
//
// Don't do anything.
//
break;
}
}
/******************************Public*Routine******************************\
*
* bSetXform
*
* the only reason this funcion can fail is if fs_NewTransformation has failed
* Needs to be called when the transform has changed relative to the
* transform stored in this fc
*
* History:
* 28-Mar-1992 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BOOL bSetXform (
PFONTCONTEXT pfc
)
{
FS_ENTRY iRet;
transMatrix mx = pfc->mx;
Fixed fxScale;
LONG ptSize;
// no previous glyph metric computation can be used
vInitGlyphState(&pfc->gstat);
// if an illegal junk is passed for style size replace by reasonable default
if (pfc->ulStyleSize > SHRT_MAX)
pfc->ulStyleSize = 0;
pfc->pgin->param.newtrans.xResolution = (int16)pfc->sizLogResPpi.cx;
pfc->pgin->param.newtrans.yResolution = (int16)pfc->sizLogResPpi.cy;
if (pfc->flXform & XFORM_SINGULAR)
{
// just put in some junk so that the preprogram does not explode
pfc->pgin->param.newtrans.pointSize = LTOF16_16(12);
mx.transform[0][0] = LTOF16_16(1);
mx.transform[1][0] = 0;
mx.transform[1][1] = LTOF16_16(1);
mx.transform[0][1] = 0;
}
else
{
if (pfc->flXform & XFORM_HORIZ)
{
if (pfc->ulStyleSize == 0)
{
// hinting is determined by ptSize that corresponds to the
// actual height in points of the font
pfc->pgin->param.newtrans.pointSize = pfc->fxPtSize;
// factor out pointSize from the xform:
if (pfc->mx.transform[1][1] > 0)
mx.transform[1][1] = LTOF16_16(1);
else
mx.transform[1][1] = LTOF16_16(-1);
if
(
(pfc->mx.transform[1][1] == pfc->mx.transform[0][0])
&&
(pfc->sizLogResPpi.cy == pfc->sizLogResPpi.cx)
)
{
// important special case, simplify computation
mx.transform[0][0] = mx.transform[1][1];
}
else // general case
{
fxScale = LongMulDiv(
LTOF16_16(pfc->pff->ui16EmHt),pfc->sizLogResPpi.cy,
pfc->lEmHtDev * pfc->sizLogResPpi.cx
);
mx.transform[0][0] = FixMul(mx.transform[0][0], fxScale);
}
}
else
{
// This is the support for new optical scaling feature.
// Hint the font as determined by the style point size from
// ExtLogFont, but possibly zoom the font to a different
// physical size
pfc->pgin->param.newtrans.pointSize =
(Fixed)LTOF16_16(pfc->ulStyleSize);
// factor out pointSize from the xform:
fxScale = LongMulDiv(LTOF16_16(pfc->pff->ui16EmHt),72,
pfc->ulStyleSize * pfc->sizLogResPpi.cx
);
mx.transform[0][0] = FixMul(mx.transform[0][0], fxScale);
if (pfc->sizLogResPpi.cy != pfc->sizLogResPpi.cx)
{
fxScale = LongMulDiv(LTOF16_16(pfc->pff->ui16EmHt),72,
pfc->ulStyleSize * pfc->sizLogResPpi.cy
);
}
mx.transform[1][1] = FixMul(mx.transform[1][1], fxScale);
}
}
else
{
if (pfc->ulStyleSize == 0)
{
// compute the physical point size
ptSize = F16_16TOLROUND(pfc->fxPtSize);
pfc->pgin->param.newtrans.pointSize = pfc->fxPtSize;
}
else // use style size from logfont, the support for optical scaling
{
ptSize = pfc->ulStyleSize;
pfc->pgin->param.newtrans.pointSize = LTOF16_16(pfc->ulStyleSize);
}
// factor out pointSize from the xform:
fxScale = LongMulDiv(LTOF16_16(pfc->pff->ui16EmHt),72,
ptSize * pfc->sizLogResPpi.cx
);
mx.transform[0][0] = FixMul(mx.transform[0][0], fxScale);
mx.transform[1][0] = FixMul(mx.transform[1][0], fxScale);
if (pfc->sizLogResPpi.cy != pfc->sizLogResPpi.cx)
{
fxScale = LongMulDiv(LTOF16_16(pfc->pff->ui16EmHt),72,
ptSize * pfc->sizLogResPpi.cy
);
}
mx.transform[1][1] = FixMul(mx.transform[1][1], fxScale);
mx.transform[0][1] = FixMul(mx.transform[0][1], fxScale);
}
}
// last minute modification to the matrix if italicization is present:
if (pfc->flFontType & FO_SIM_ITALIC)
{
// the result of multiplying arbitrary matrix with italicization matrix
// We are multiplying from the left because the italicization matrix
// acts first on the notional space vectors on the left
//
// |1 0| |m00 m01| |m00 m10 |
// | | * | | = | |
// |sin20 1| |m10 m11| |m10 + m00 * sin20 m11 + m01 * sin20|
//
mx.transform[1][0] += FixMul(mx.transform[0][0], FX_SIN20);
mx.transform[1][1] += FixMul(mx.transform[0][1], FX_SIN20);
}
pfc->pgin->param.newtrans.transformMatrix = &mx;
// FIXEDSQRT2 is good as pixel diameter for all practical purposes
// according to EliK, LenoxB and JeanP [bodind]
if ( pfc->bVertical )
{
//
// keep these values for later
//
pfc->mxn = mx;
pfc->pointSize = pfc->pgin->param.newtrans.pointSize;
//
// call the transformation matrix calculation function
// for vertical glyphs just before calling fs_NewTransformation.
//
vCalcXformVertical( pfc );
}
pfc->pgin->param.newtrans.pixelDiameter = FIXEDSQRT2;
pfc->pgin->param.newtrans.traceFunc = (FntTraceFunc)NULL;
// now call the rasterizer to acknowledge the new transform
if ((iRet = fs_NewTransformation(pfc->pgin, pfc->pgout)) != NO_ERR)
{
V_FSERROR(iRet);
return(FALSE);
}
return(TRUE);
}
VOID vQuantizeXform
(
PFONTCONTEXT pfc
);
/******************************Public*Routine******************************\
*
* STATIC bComputeMaxGlyph
*
*
* Effects:
*
* Warnings:
*
* History:
* 04-Dec-1991 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
STATIC BOOL
bComputeMaxGlyph (
PFONTCONTEXT pfc
)
{
VOID vSetGrayState__FONTCONTEXT(FONTCONTEXT *);
LONG cxMax,cyMax;
LONG yMinN, yMaxN;
LONG xMinN, xMaxN;
LONG lTmp;
Fixed fxMxx,fxMyy;
BYTE *pjView = (BYTE *)pfc->pff->pvView;
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 ;
ASSERTDD(pjView, "bComputeMaxGlyph, pjView\n");
// get the notional space values
if (pjOS2 && (pfc->flXform & (XFORM_HORIZ | XFORM_VERT)))
{
// 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:
yMinN = - BE_INT16(pjOS2 + OFF_OS2_usWinAscent);
yMaxN = BE_INT16(pjOS2 + OFF_OS2_usWinDescent);
}
else
{
yMinN = - BE_INT16(&phead->yMax);
yMaxN = - BE_INT16(&phead->yMin);
}
ASSERTDD(yMinN < yMaxN, "yMinN >= yMaxN\n");
xMinN = BE_INT16(&phead->xMin);
xMaxN = BE_INT16(&phead->xMax);
if (pfc->flFontType & FO_SIM_ITALIC)
{
// IF there is italic simulation
// xMin -> xMin - yMaxN * sin20
// xMax -> yMax - yMinN * sin20
xMinN -= FixMul(yMaxN, FX_SIN20);
xMaxN -= FixMul(yMinN, FX_SIN20);
}
ASSERTDD(xMinN < xMaxN, "xMinN >= xMaxN\n");
pfc->lEmHtDev = 0; // flag that it has not been computed
pfc->fxPtSize = 0; // flag that it has not been computed
pfc->lD = 0; // zero unless computed otherwise
pfc->phdmx = NULL; // NULL unless computed otherwise
if (pfc->flXform & XFORM_HORIZ) // XX AND YY Only
{
sfnt_HorizontalHeader *phhea;
ULONG cHMTX;
fxMxx = pfc->mx.transform[0][0];
fxMyy = pfc->mx.transform[1][1];
// ascender, round up
yMinN = FixMul(fxMyy, yMinN);
yMaxN = FixMul(fxMyy, yMaxN);
if (fxMyy > 0)
{
// vdmx table should be consulted if present and used to compute
// ascender and descender. If this computation can not be done
// based on vdmx table or if vdmx table is not present simple
// linear scaling will suffice [bodind].
vQuantizeXform(pfc);
if (!(pfc->flXform & XFORM_VDMXEXTENTS)) // COMPUTED FROM VDMX
{
pfc->yMin = yMinN;
pfc->yMax = yMaxN;
}
pfc->lAscDev = - pfc->yMin;
pfc->lDescDev = pfc->yMax;
}
else // fxMyy < 0
{
pfc->lAscDev = yMinN;
pfc->lDescDev = - yMaxN;
// swap yMin and yMax for when the xform flips y coord
lTmp = yMinN;
yMinN = yMaxN;
yMaxN = lTmp;
pfc->yMin = yMinN;
pfc->yMax = yMaxN;
}
if (pfc->lEmHtDev == 0)
{
// if this value has not been computed in vQuantizeXform routine
pfc->lEmHtDev = FixMul(fxMyy, pfc->pff->ifi.fwdUnitsPerEm);
if (pfc->lEmHtDev < 0)
pfc->lEmHtDev = - pfc->lEmHtDev;
}
ASSERTDD(pfc->lEmHtDev >= 0, "lEmHt negative\n");
// now that em height has been computed, we can compute the
// pt size on the rendering device. This value will be fed to
// fs_NewTransformation
pfc->fxPtSize = LongMulDiv(
LTOF16_16(pfc->lEmHtDev), 72,
pfc->sizLogResPpi.cy);
cyMax = pfc->yMax - pfc->yMin;
if
(
(pfc->flXform & XFORM_HORIZ) &&
(pfc->mx.transform[0][0] == pfc->mx.transform[1][1]) &&
(pfc->mx.transform[1][1] > 0)
)
{
// caution, do not move this line of code elsewhere for
// this check has to be made after vQuantizeXform since
// this function may change the transform, but it has to be
// made before bGetFastAdvanceWidth or bQueryAdvanceWidths
// are ever called for these functions check flXform agains
// XFORM_POSITIVE_SCALE
pfc->flXform |= XFORM_POSITIVE_SCALE;
// find the hdmx table, in case of the console fixed pitch font this
// table may be useful in determining if cxMax needs to be cut off
// to the advance width of this font
vFindHdmxTable(pfc); // this could cause an exception:
}
phhea = (sfnt_HorizontalHeader *)(
(BYTE *)pfc->pff->pvView + pfc->ptp->ateReq[IT_REQ_HHEAD].dp
);
cHMTX = (ULONG) BE_UINT16(&phhea->numberOf_LongHorMetrics);
// ig == cHMTX - 1; pick the last width from hmtx table.
// If we use ig == 0 as I originally intended, turns out this
// field is usually hacked and set to zero. ig == 0 corresponds to
// apple logo which is not allowed in msft fonts.
// We should only do this with new console fonts, not with the old style
// fixed pitch fonts that may have negative a and c spaces
if(
(!IS_ANY_DBCS_CHARSET(pfc->pff->ifi.jWinCharSet)) &&
(pfc->pff->ifi.flInfo & FM_INFO_OPTICALLY_FIXED_PITCH) &&
(pfc->flXform & XFORM_POSITIVE_SCALE) &&
!(pfc->flFontType & FO_SIM_ITALIC) &&
(pfc->pff->ifi.flInfo & FM_INFO_NONNEGATIVE_AC) &&
bGetFastAdvanceWidth(pfc,cHMTX - 1, &pfc->lD)
)
{
pfc->lD = FXTOLROUND(pfc->lD);
// do this before possibly adding 1 for emboldening, for
// these quantities refer to what rasterizer will return
pfc->xMin = 0;
pfc->xMax = pfc->lD;
// we want emboldened fonts in console:
if (pfc->flFontType & FO_SIM_BOLD)
pfc->lD += 1;
// for the console fonts we want to be sure that every glyph fits in
// in the box of the width lD and height equal to asc+desc.
pfc->cxMax = cxMax = (ULONG)pfc->lD;
}
else
{
// even though this may be a fixed pitch font we shall not optimize in this
// case, for this is not a frequently used type of transform.
pfc->lD = 0;
// scale xMin,xMax to device, 28.4 format
xMinN = FixMul(LTOFX(xMinN), fxMxx);
xMaxN = FixMul(LTOFX(xMaxN), fxMxx);
if (fxMxx < 0)
{
lTmp = xMinN;
xMinN = xMaxN;
xMaxN = lTmp;
}
// I run the experiment on 400 fonts at several sizes. I found
// that subtracting 2 from xMin and adding 1 to xMax suffices
// in all situations to prevent any columns from being shaved off.
// [bodind]
xMinN = FXTOLFLOOR(xMinN) - 2;
xMaxN = FXTOLCEILING(xMaxN) + 1;
pfc->xMin = xMinN;
pfc->xMax = xMaxN;
cxMax = xMaxN - xMinN;
}
// the direction unit vectors for scaling transforms are simple
// if the font is intended for horizontal left to right writing
//!!! here the check is due to verify that the font is not designed
//!!! for vertical writing in the notional space [bodind]
vLToE(&pfc->pteUnitBase.x, (fxMxx > 0) ? 1L : - 1L);
vLToE(&pfc->pteUnitBase.y, 0L);
vLToE(&pfc->pteUnitSide.x, 0L);
vLToE(&pfc->pteUnitSide.y, (fxMyy > 0) ? -1L : 1L); // y axis points down
// We need to adjust the the glyph origin of singular bitmaps for glyphs
// when MaxAscent or MaxDescent is negative or zero. The trick is to choose
// these values so that the "blank" glyph is always included in the
// rectangle of the text. What this means is that
// for m11 > 0 we must have: yT >= -lAsc && yB <= lDesc
// for m11 < 0 we must have: yT >= -lDesc && yB <= lAsc
// here yB == yT + 1, because blank glyphs has a cy == 1, and
// yT == ptlSingularOrigin.y
// This leads to
// for m11 > 0 we must have: - (lAsc + 1) < yT < lDesc
// for m11 < 0 we must have: - (lDesc + 1) < yT < lAsc
// One point that would satisfy both of these conditions is
// the midpoint between the endpoints. Thus, before any rouding:
// for m11 > 0 we have: yT = (lDesc- lAsc - 1)/2
// for m11 < 0 we have: yT = -(lDesc- lAsc - 1)/2
// where divide by 2 is not integer divide but ordinary real number divide.
// The proper rounding is done ala KirkO, that is, add 1/2 and take a
// flor:
// for m11 > 0 we have: yT = FLOOR((lDesc - lAsc - 1)/2 + 1/2)
// for m11 < 0 we have: yT = FLOOR((lAsc - lDesc - 1)/2 + 1/2)
// That is:
// for m11 > 0 we have: yT = FLOOR(lDesc - lAsc)/2)
// for m11 < 0 we have: yT = FLOOR(lAsc - lDesc)/2)
// Now floor is computed correctly (on signed nubmers) by implementing
// divide by 2 as >> 1 operation:
pfc->ptlSingularOrigin.x = 0;
if ((pfc->lAscDev <= 0) || (pfc->lDescDev <= 0))
{
if (pfc->mx.transform[1][1] > 0)
{
pfc->ptlSingularOrigin.y =
(pfc->lDescDev - pfc->lAscDev) >> 1;
}
else
{
pfc->ptlSingularOrigin.y =
(pfc->lAscDev - pfc->lDescDev) >> 1;
}
}
else
{
pfc->ptlSingularOrigin.y = 0;
}
}
else // nontrivial transformation
{
POINTL aptl[4];
POINTFIX aptfx[4];
BOOL bOk;
INT i;
FIX xMinD, xMaxD, yMinD, yMaxD; // device space values;
// add little extra space to be safe
i = (INT)(pfc->pff->ui16EmHt / 64);
yMaxN += i; // adds about 1.7% to ht
yMinN -= i; // adds about 1.7% to ht
// set up the input array, the four corners of the maximal bounding
// box in the notional coords
aptl[0].x = xMinN; // tl.x
aptl[0].y = yMinN; // tl.y
aptl[1].x = xMaxN; // tr.x
aptl[1].y = yMinN; // tr.y
aptl[2].x = xMinN; // bl.x
aptl[2].y = yMaxN; // bl.y
aptl[3].x = xMaxN; // br.x
aptl[3].y = yMaxN; // br.y
// xform to device coords with 28.4 precision:
// !!! [GilmanW] 27-Oct-1992
// !!! Should change over to engine user object helper functions
// !!! instead of the fontmath.cxx functions.
bOk = bFDXform(&pfc->xfm, aptfx, aptl, 4);
if (!bOk) { RETURN("TTFD!_:bFDXform\n", FALSE); }
xMaxD = xMinD = aptfx[0].x;
yMaxD = yMinD = aptfx[0].y;
for (i = 1; i < 4; i++)
{
if (aptfx[i].x < xMinD)
xMinD = aptfx[i].x;
if (aptfx[i].x > xMaxD)
xMaxD = aptfx[i].x;
if (aptfx[i].y < yMinD)
yMinD = aptfx[i].y;
if (aptfx[i].y > yMaxD)
yMaxD = aptfx[i].y;
}
yMinD = FXTOLFLOOR(yMinD) ;
yMaxD = FXTOLCEILING(yMaxD) ;
xMinD = FXTOLFLOOR(xMinD) ;
xMaxD = FXTOLCEILING(xMaxD) ;
cxMax = xMaxD - xMinD;
cyMax = yMaxD - yMinD;
// now re-use aptl to store e1 and -e2, base and side unit
// vectors in the notional space.
//!!! This may be wrong if have font for
//!!! right to left or vert writing [bodind]
aptl[0].x = 1; // base.x
aptl[0].y = 0; // base.y
aptl[1].x = 0; // side.x
aptl[1].y = -1; // side.y
// !!! [GilmanW] 27-Oct-1992
// !!! Should change over to engine user object helper functions
// !!! instead of the fontmath.cxx functions.
bOk = bXformUnitVector (
&aptl[0], // IN, incoming unit vector
&pfc->xfm, // IN, xform to use
&pfc->vtflBase, // OUT, xform of the incoming unit vector
&pfc->pteUnitBase, // OUT, *pptqXormed/|*pptqXormed|, POINTE
(pfc->flFontType & FO_SIM_BOLD) ? &pfc->ptqUnitBase : NULL, // OUT, *pptqXormed/|*pptqXormed|, POINTQF
&pfc->efBase // OUT, |*pptqXormed|
);
bOk &= bXformUnitVector (
&aptl[1], // IN, incoming unit vector
&pfc->xfm, // IN, xform to use
&pfc->vtflSide, // OUT, xform of the incoming unit vector
&pfc->pteUnitSide, // OUT, *pptqXormed/|*pptqXormed|, POINTE
NULL,
&pfc->efSide // OUT, |*pptqXormed|
);
if (!bOk) { RETURN("TTFD!_:bXformUnitVector\n", FALSE); }
pfc->lAscDev = -fxLTimesEf(&pfc->efSide,yMinN);
pfc->lDescDev = fxLTimesEf(&pfc->efSide,yMaxN);
pfc->lAscDev = FXTOLCEILING(pfc->lAscDev) ;
pfc->lDescDev = FXTOLCEILING(pfc->lDescDev);
pfc->ptfxTop.x = lExL(pfc->pteUnitSide.x, LTOFX(pfc->lAscDev));
pfc->ptfxTop.y = lExL(pfc->pteUnitSide.y, LTOFX(pfc->lAscDev));
pfc->ptfxBottom.x = lExL(pfc->pteUnitSide.x, -LTOFX(pfc->lDescDev));
pfc->ptfxBottom.y = lExL(pfc->pteUnitSide.y, -LTOFX(pfc->lDescDev));
if ((yMinN >= 0) || (yMaxN <= 0) || ((pfc->lAscDev + pfc->lDescDev) < 3))
{
// Either all the glyphs are above the base line or all the glyphs
// are below the baseline. In either case adjust the origin for
// the singular glyph bitmap.
// Compute the midpoint between asc and desc in notional space:
// lAverage = ROUND(-(yMaxN+yMinN)/2)
LONG lAverage = (-yMaxN -yMinN + 1) >> 1;
pfc->ptlSingularOrigin.x = fxLTimesEf(&pfc->vtflSide.x,lAverage);
pfc->ptlSingularOrigin.x = FXTOLROUND(pfc->ptlSingularOrigin.x);
pfc->ptlSingularOrigin.y = fxLTimesEf(&pfc->vtflSide.y,lAverage);
pfc->ptlSingularOrigin.y = FXTOLROUND(pfc->ptlSingularOrigin.y);
}
else
{
pfc->ptlSingularOrigin.x = 0;
pfc->ptlSingularOrigin.y = 0;
}
// finally store the results:
pfc->xMin = xMinD;
pfc->xMax = xMaxD;
pfc->yMin = yMinD;
pfc->yMax = yMaxD;
// compute em ht in pixels and points
pfc->lEmHtDev = FixMul(
iHipot(pfc->mx.transform[1][1],pfc->mx.transform[1][0]),
(Fixed)pfc->pff->ui16EmHt
);
pfc->fxPtSize = fxPtSize(pfc);
}
if (!pfc->lD)
{
// this is win31 hack for emboldening: they always offset the bitmap to the
// right by one pixel and or it with the original bitmap. This of course only
// makes sense when writtinng left to right, when writing at 90 degrees, say,
// the bitmaps should be offsetted by one pixel up. In general, depending on
// the direction of the baseline, bitmap should be offset right, up, left or down,
if (pfc->flFontType & FO_SIM_BOLD)
cxMax += 1;
// we can liberally extend cxMax to the byte boundary, this is not
// going to change memory requirements of the system.
cxMax = ((cxMax + 7) & ~7);
pfc->cxMax = cxMax;
}
// now we have to determine how big in memory is the biggest glyph.
// let us remember that the rasterizer needs little more storage than the
// the engine does, because rasterizer will want dword aligned rows rather
// than byte aligned rows
{
DWORDLONG lrg;
// why am I dword instead byte extending cxMax? because that is
// how much rasterizer will want for this bitmap
ULONG cjMaxScan = ((cxMax + 31) & ~31) / 8;
lrg = UInt32x32To64(cjMaxScan, cyMax);
if (lrg > ULONG_MAX)
{
// the result does not fit in 32 bits, alloc memory will fail
// this is too big to digest, we fail to open fc
RETURN("TTFD! huge pt size, must fail\n", FALSE);
}
}
// We now have all the informaiton to set the gray bit
// appropriately.
vSetGrayState__FONTCONTEXT(pfc);
ASSERTDD(pfc->flFontType & FO_CHOSE_DEPTH,
"We haven't decided about pixel depth\n"
);
pfc->cjGlyphMax = CJGD(cxMax,cyMax,pfc);
return TRUE;
}
//--------------------------------------------------------------------
// LONG iHipot(x, y)
//
// This routine returns the hypoteneous of a right triangle.
//
// FORMULA:
// use sq(x) + sq(y) = sq(hypo);
// start with MAX(x, y),
// use sq(x + 1) = sq(x) + 2x + 1 to incrementally get to the
// target hypotenouse.
//
// History:
// Mon 07-Feb-1994 -by- Bodin Dresevic [BodinD]
// update: update to use Fixed 16.16
// 10-Feb-1993 -by- Kent Settle (kentse)
// Stole from RASDD.
// 21-Aug-1991 -by- Lindsay Harris (lindsayh)
// Cleaned up UniDrive version, added comments etc.
//--------------------------------------------------------------------
STATIC ULONG iHipot(LONG x, LONG y)
{
ULONG hypo; /* Value to calculate */
ULONG delta; /* Used in the calculation loop */
ULONG target; /* Loop limit factor */
// quick exit for frequent trivial cases [bodind]
if (x < 0)
x = -x;
if (y < 0)
y = -y;
if (x == 0)
return y;
if (y == 0)
return x;
if (x > y)
{
hypo = x;
target = y * y;
}
else
{
hypo = y;
target = x * x;
}
for (delta = 0; delta < target; hypo++)
delta += ((hypo << 1) + 1);
return hypo;
}
/******************************Public*Routine******************************\
*
* bSingularXform
*
* Checks whether this is one of the xforms that the rasterizer is known
* to choke on. Those are the transforms that generate very
* narrow fonts (less than 0.5 pixels/em wide or tall). For fonts that
* allow only integer widths/em and heights/em this number will get rounded
* down to zero and generate divide by zero exception in the preprogram.
* We will flag such transforms as XFORM_SINGULAR and return empty bitmaps
* and outlines for them shortcircuiting the rasterizer which would die on
* us.
*
* Actually, for compatibility reasons we will have to change
* this plan a little bit. It turns out that
* win 31 does not allow for the rasterization of a font that is less
* than 2 pixels tall (ie. the Em Ht of the font in device space must be
* >= 2 pixels). If a request comes down to realize a font that is tall less
* than 2 pixels we will simply have to substitute the transform by a scaled
* transform that will produce a font of height two pixels. We will still keep
* our singular transform code in case a font is requested that is singular in
* X direction, that is, too narrow.
*
* History:
* 22-Sep-1992 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
// smallest ppem allowed under win31:
#define WIN31_PPEM_CUTOFF 2
STATIC VOID vCheckForSingularXform (PFONTCONTEXT pfc) // OUT
{
register LONG lEmHtDev;
Fixed fxEmHtDev;
Fixed fxEmHtNot = LTOF16_16(pfc->pff->ui16EmHt);
Fixed fxScale;
Fixed fxEmWidthDev;
// xforms are conforming left multiplication rule v' = v * M i.e.:
//
// (x,0) -> x(m00,m01)
// (0,y) -> y(m10,m11)
//
// compute length of (0,Em) after it gets transformed to device space:
// We need to have fxEmHtDev computed with high precission, for we
// shall be using it to divide the original transform by.
// We want to avoid division by zero when that is not neccessary.
fxEmHtDev = FixMul(
iHipot(pfc->mx.transform[1][1],pfc->mx.transform[1][0]),
fxEmHtNot
);
lEmHtDev = F16_16TOLROUND(fxEmHtDev);
if (lEmHtDev < WIN31_PPEM_CUTOFF) // too small a transform:
{
pfc->flXform |= XFORM_2PPEM;
// according to win31 algorithm, we must scale this xform so that the
// resulting xform will produce font that is 2 pels tall.
// That is, the new transform M' is going to be
//
// M' = (WIN31_PPEM_CUTOFF / lEmHtDev) * M
//
// so that the following equation is satisfied:
//
// |(0,EmNotional) * M'| == WIN31_PPEM_CUTOFF == 2;
if (pfc->flXform & XFORM_HORIZ)
{
// in this special case the above formula for M' becomes:
//
// | m00/|m11| 0 |
// M' = (WIN31_PPEM_CUTOFF / EmNotional) * | |
// | 0 sgn(m11) |
#define LABS(x) ((x)<0)?(-x):(x)
Fixed fxAbsM11 = LABS(pfc->mx.transform[1][1]);
Fixed fxAbsM00 = LABS(pfc->mx.transform[0][0]);
LONG lSgn11 = (pfc->mx.transform[1][1] >= 0) ? 1 : -1;
LONG lSgn00 = (pfc->mx.transform[0][0] >= 0) ? 1 : -1;
fxScale = FixDiv(WIN31_PPEM_CUTOFF,pfc->pff->ui16EmHt);
pfc->mx.transform[1][1] = fxScale;
if (fxAbsM00 != fxAbsM11)
{
pfc->mx.transform[0][0] = LongMulDiv(fxScale,fxAbsM00,fxAbsM11);
}
else
{
pfc->mx.transform[0][0] = fxScale;
}
// fix the signs if needed:
if (lSgn11 < 0)
pfc->mx.transform[1][1] = - pfc->mx.transform[1][1];
if (lSgn00 < 0)
pfc->mx.transform[0][0] = - pfc->mx.transform[0][0];
}
else
{
// general case, compute scale (which involves division) once,
// and use it for all four members of the matrix:
fxScale = FixDiv(LTOF16_16(WIN31_PPEM_CUTOFF),fxEmHtDev);
pfc->mx.transform[0][0] = FixMul(pfc->mx.transform[0][0],fxScale);
pfc->mx.transform[0][1] = FixMul(pfc->mx.transform[0][1],fxScale);
pfc->mx.transform[1][0] = FixMul(pfc->mx.transform[1][0],fxScale);
pfc->mx.transform[1][1] = FixMul(pfc->mx.transform[1][1],fxScale);
// In general case must also fix the original EFLOAT xform because
// it is going to be used for computation of extents, max glyphs etc.
FFF(pfc->xfm.eM11, +pfc->mx.transform[0][0]);
FFF(pfc->xfm.eM22, +pfc->mx.transform[1][1]);
FFF(pfc->xfm.eM12, -pfc->mx.transform[0][1]);
FFF(pfc->xfm.eM21, -pfc->mx.transform[1][0]);
}
}
// Now check if the transform is singular in x. To do this
// compute length of (Em,0) after it gets transformed to device space:
fxEmWidthDev = FixMul(
iHipot(pfc->mx.transform[0][0],pfc->mx.transform[0][1]),
fxEmHtNot
);
if (fxEmWidthDev <= ONEHALFFIX)
{
// We are in trouble, we shall have to lie to the engine:
pfc->flXform |= XFORM_SINGULAR;
}
}
/******************************Public*Routine******************************\
*
* bNewXform:
*
* converts the transform matrix to the form the rasterizer likes
* and computes the global (per font) sizes that are relevant for this
* transform.
*
* History:
* 28-Mar-1992 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
STATIC BOOL
bNewXform (
FONTOBJ *pfo,
PFONTCONTEXT pfc // OUT
)
{
// do not write immediately to pfc->mx until sure that all bFloatToL
// have succeeded. You do not want to leave this function and leave
// fc in a dirty state
BOOL bRet;
Fixed fx00, fx01, fx10, fx11;
// Get the transform elements.
XFORMOBJ_iGetXform(FONTOBJ_pxoGetXform(pfo), &pfc->xfm);
if (
!bFloatToL(pfc->xfm.eM11, &fx00) ||
!bFloatToL(pfc->xfm.eM22, &fx11) ||
!bFloatToL(pfc->xfm.eM12, &fx01) ||
!bFloatToL(pfc->xfm.eM21, &fx10)
)
RET_FALSE("TTFD!_bFloatToL failed\n");
// we are fine now, can not fail after this:
pfc->mx.transform[0][0] = fx00;
pfc->mx.transform[1][1] = fx11;
pfc->mx.transform[0][1] = -fx01;
pfc->mx.transform[1][0] = -fx10;
// components in the projective space are zero
pfc->mx.transform[2][2] = ONEFIX;
pfc->mx.transform[0][2] = (Fixed)0;
pfc->mx.transform[1][2] = (Fixed)0;
pfc->mx.transform[2][0] = (Fixed)0;
pfc->mx.transform[2][1] = (Fixed)0;
// set the flags for the transform:
pfc->flXform = 0;
if ((fx01 == 0) && (fx10 == 0))
pfc->flXform |= XFORM_HORIZ;
if ((fx00 == 0) && (fx11 == 0))
pfc->flXform |= XFORM_VERT;
// important to check for "singular transform"
// (ie. request for too small a font realization) after flags have been set
vCheckForSingularXform(pfc);
// no glyph metrics computation is valid yet
vInitGlyphState(&pfc->gstat);
// no memory to rasterize a glyph or produce glyph outline has been allocated
pfc->gstat.pv = NULL;
// now get the sizes for this transform
if (bRet = bComputeMaxGlyph(pfc))
{
// BEGIN Perpetua-Hack
if (pfc->pff->fl & FF_PERPETUA_REGULAR)
{
bRet = FALSE;
if (pfc->flXform & XFORM_POSITIVE_SCALE)
{
if (pfc->lEmHtDev <= PERPETUA_REGULAR_MAX_EM)
{
bRet = TRUE;
}
}
#if DBG
if (!bRet)
{
TTFD_PRINT(2,("Rejecting Perpetua Regular\n"));
}
#endif
}
// END Perpetua-Hack
}
return(bRet);
}
/******************************Public*Function*****************************\
* bFToL *
* *
* Convert an IEEE floating point number to a long integer. *
* *
* History: *
*
* Sun 17-Nov-1991 -by- Bodin Dresevic [BodinD]
* update:
*
* changed the line
* if (flType & CVT_TO_FIX) lExp += 4;
* to
* if (flType & CVT_TO_FIX) lExp += 16;
* to reflect that we are converting to 16.16 format rather than to 28.4
*
*
* 03-Jan-1991 -by- Wendy Wu [wendywu] *
* Wrote it. *
\**************************************************************************/
STATIC BOOL bFloatToL(FLOAT e, PLONG pl)
{
LONG lEf, lExp;
lEf = (*((LONG *) &e)); // convert type EFLOAT to LONG
// if exponent < 0 then convert to 0 and return true
lExp = ((lEf >> 23) & 0xff) -127;
lExp += 16; // this is the only line I changed [bodind]
if (lExp < 0)
{
*pl = 0;
return(TRUE);
}
// if exponent <= 23 then
// lMantissa = (lEf & 0x7fffff) | 0x800000;
// if we are to truncate the fractions
// l = lMantissa >> (23 - lExponent);
// else
// l = ((lMantissa >> (23 - lExponent -1)) + 1) >> 1;
if (lExp <= 23)
{
*pl = (lEf & 0x80000000) ?
-(((((lEf & 0x7fffff) | 0x800000) >> (23 - lExp -1)) + 1) >> 1) :
((((lEf & 0x7fffff) | 0x800000) >> (23 - lExp -1)) + 1) >> 1;
return(TRUE);
}
// if exponent <= 30 then
// lMantissa = (lEf & 0x7fffff) | 0x800000;
// l = lMantissa << (lExponent - 23);
if (lExp <= 30)
{
*pl = (lEf & 0x80000000) ?
-(((lEf & 0x7fffff) | 0x800000) << (lExp - 23)) :
((lEf & 0x7fffff) | 0x800000) << (lExp - 23);
return(TRUE);
}
return(FALSE);
}
/******************************Public*Routine******************************\
* lFFF = long-float-from-fixed
*
* input: 16.16 representation
* output: LONG that is bit equivalent of the 32-bit ieee float
* equal to the fix point number. To recover the float
* the FLOAT representation you simply cast the bits as a float
* that is
*
* FLOAT e;
*
* *(LONG*)&e = lFFF(n16Dot16)
*
* History:
* Tue 03-Jan-1995 14:33:35 by Kirk Olynyk [kirko]
* Wrote it.
\**************************************************************************/
LONG lFFF(LONG l)
{
#if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
FLOAT e = ((FLOAT) l)/((FLOAT) 65536);
return(*(LONG*)&e);
#elif defined(_X86_)
int i; // shift count
unsigned k; // significand
if (k = (unsigned) l)
{
if (l < 0)
k = (unsigned) -l; // significand is positive, sign
// bit accounted for later
i = 0;
if (k < (1 << 16)) { // put the number in the
k <<= 16; // range 2^31 <= k < 2^32
i += 16; // by shifting to left, put
} // shift count in i
if (k < (1 << 24)) {
k <<= 8;
i += 8;
}
if (k < (1 << 28)) {
k <<= 4;
i += 4;
}
if (k < (1 << 30)) {
k <<= 2;
i += 2;
}
if (k < (1 << 31)) {
k <<= 1;
i += 1;
}
// at this point
// i = 31-floor(log2(abs(l)))
k += (1 << 7); // about to shift out
// the lowest 8-bits
// account for their effect by
// rounding. This has the effect
// that numbers are rounded away
// from zero as opposed to rounding
// stricktly up
k >>= 8; // shift out the lowest 8 bits
k &= ((1<<23) - 1); // 2^23 bit is implicit so mask it out
k |= (0xff & (142 - i)) << 23; // set exponent at correct place
if (l < 0) // if original number was negative
k |= (1<<31); // then set the sign bit
}
return((LONG) k);
#endif
}
#if DBG
/******************************Public*Routine******************************\
*
* VOID vFSError(FS_ENTRY iRet);
*
*
* Effects:
*
* Warnings:
*
* History:
* 25-Nov-1991 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
VOID vFSError(FS_ENTRY iRet)
{
PCHAR psz;
switch (iRet)
{
case BAD_CALL_ERR:
psz = "BAD_CALL_ERR";
break;
case BAD_CLIENT_ID_ERR:
psz = "BAD_CLIENT_ID_ERR";
break;
case BAD_MAGIC_ERR:
psz = "BAD_MAGIC_ERR";
break;
case BAD_START_POINT_ERR:
psz = "BAD_START_POINT_ERR";
break;
case CLIENT_RETURNED_NULL:
psz = "CLIENT_RETURNED_NULL";
break;
case CONTOUR_DATA_ERR:
psz = "CONTOUR_DATA_ERR";
break;
case GLYPH_INDEX_ERR:
psz = "GLYPH_INDEX_ERR";
break;
case INSTRUCTION_SIZE_ERR:
psz = "INSTRUCTION_SIZE_ERR";
break;
case INVALID_GLYPH_INDEX:
psz = "INVALID_GLYPH_INDEX";
break;
case MISSING_SFNT_TABLE:
psz = "MISSING_SFNT_TABLE";
break;
case NULL_INPUT_PTR_ERR:
psz = "NULL_INPUT_PTR_ERR";
break;
case NULL_KEY_ERR:
psz = "NULL_KEY_ERR";
break;
case NULL_MEMORY_BASES_ERR:
psz = "NULL_MEMORY_BASES_ERR";
break;
case NULL_OUTPUT_PTR_ERR:
psz = "NULL_OUTPUT_PTR_ERR";
break;
case NULL_SFNT_DIR_ERR:
psz = "NULL_SFNT_DIR_ERR";
break;
case NULL_SFNT_FRAG_PTR_ERR:
psz = "NULL_SFNT_FRAG_PTR_ERR";
break;
case OUT_OFF_SEQUENCE_CALL_ERR:
psz = "OUT_OFF_SEQUENCE_CALL_ERR";
break;
case OUT_OF_RANGE_SUBTABLE:
psz = "OUT_OF_RANGE_SUBTABLE";
break;
case POINTS_DATA_ERR:
psz = "POINTS_DATA_ERR";
break;
case POINT_MIGRATION_ERR:
psz = "POINT_MIGRATION_ERR";
break;
case SCAN_ERR:
psz = "SCAN_ERR";
break;
case SFNT_DATA_ERR:
psz = "SFNT_DATA_ERR";
break;
case TRASHED_MEM_ERR:
psz = "TRASHED_MEM_ERR";
break;
case TRASHED_OUTLINE_CACHE:
psz = "TRASHED_OUTLINE_CACHE";
break;
case UNDEFINED_INSTRUCTION_ERR:
psz = "UNDEFINED_INSTRUCTION_ERR";
break;
case UNKNOWN_CMAP_FORMAT:
psz = "UNKNOWN_CMAP_FORMAT";
break;
case UNKNOWN_COMPOSITE_VERSION:
psz = "UNKNOWN_COMPOSITE_VERSION";
break;
case VOID_FUNC_PTR_BASE_ERR:
psz = "VOID_FUNC_PTR_BASE_ERR";
break;
case SBIT_COMPONENT_MISSING_ERR:
psz = "SBIT_COMPONENT_MISSING_ERR";
break;
default:
psz = "UNKNOWN FONT SCALER ERROR";
break;
}
TtfdDbgPrint ("\n Rasterizer Error: 0x%lx, %s \n", iRet, psz);
}
#endif
/******************************Public*Routine******************************\
*
* fxPtSize
*
* Effects: computes the size in points for this font realization
*
* History:
* 06-Aug-1992 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
STATIC LONG fxPtSize(PFONTCONTEXT pfc)
{
// This is done as follows:
//
// Transform
// (0, ui16EmHt) to device (pixel) space.
// Let us say that the vector obtained is (xEm, yEm).
// Then, ptSize should be computed as
// ptSize = 72 * sqrt((xEm/xRes)^2 + (yEm/yRes)^2);
// expanding here a bit we get:
// ptSize = 72 * ui16EmHt * sqrt((mx10/xRes)^2 + (mx11/yRes)^2);
Fixed x,y;
LONG lEmHtX72 = (LONG)(72 * pfc->pff->ui16EmHt);
// fxEmHtDev = FixMul(
// iHipot(pfc->mx.transform[1][1],pfc->mx.transform[1][0]),
// fxEmHtNot
// );
if (pfc->sizLogResPpi.cx == pfc->sizLogResPpi.cy)
{
return FixDiv(lEmHtX72, pfc->sizLogResPpi.cy);
}
else
{
x = LongMulDiv(lEmHtX72,pfc->mx.transform[1][0],pfc->sizLogResPpi.cx);
y = LongMulDiv(lEmHtX72,pfc->mx.transform[1][1],pfc->sizLogResPpi.cy);
return iHipot(x,y);
}
}
//
// this is win31 code intended as a comment for our code:
//
#ifdef THIS_IS_WIN31_CODE_INTENDED_AS_COMMENT
// Find out if a width Table is available
if (pfnt->ulHdmxPos && !(pfc->fStatus & FD_MORE_THAN_STRETCH) && pfc->Mx11 == pfc->Mx00)
{
unsigned i;
HDMXHEADER FAR *pHdmx;
HDMXTABLE FAR *pHdmxTable;
if (pHdmx = (HDMXHEADER FAR *) SfntReadFragment (pfc->fgi.clientID, pfnt->ulHdmxPos, pfnt->uHdmxSize))
{
if (pHdmx->Version == 0)
{
pHdmxTable = pHdmx->HdmxTable;
// Init the the glyph count
pfc->cHdmxRecord = (unsigned) SWAPL (pHdmx->cbSizeRecord);
// look through the table if the size is available
for (i = 0; i < (unsigned) SWAPW (pHdmx->cbRecord); i++, pHdmxTable = (HDMXTABLE FAR *)((char FAR *) pHdmxTable + pfc->cHdmxRecord))
if (pfc->Mx11 == (int) pHdmxTable->ucEmY)
{
pfc->ulHdmxPosTable = pfnt->ulHdmxPos + (i * pfc->cHdmxRecord + sizeof (HDMXHEADER));
break;
}
}
ReleaseSFNT (pHdmx);
}
}
#endif // THIS_IS_WIN31_CODE_INTENDED_AS_COMMENT
STATIC VOID vFindHdmxTable(PFONTCONTEXT pfc)
{
HDMXHEADER *phdr = (HDMXHEADER *)(
(pfc->ptp->ateOpt[IT_OPT_HDMX].dp) ?
((BYTE *)pfc->pff->pvView + pfc->ptp->ateOpt[IT_OPT_HDMX].dp) :
NULL
);
UINT cRecords;
ULONG cjRecord;
HDMXTABLE *phdmx, *phdmxEnd;
LONG yEmHt = pfc->lEmHtDev;
// assume failure, no hdmx table can be used:
pfc->phdmx = NULL;
// first see if hdmx table is there at all:
if (!phdr || !pfc->ptp->ateOpt[IT_OPT_HDMX].cj)
return;
// if table is there but not necessary since the whole font scales
// linearly at all sizes, we will ignore it:
//(phead->flags & SWAP(2))
// return;
// if transform is not such as to allow the use of hdmx table, return;
ASSERTDD(pfc->flXform & XFORM_POSITIVE_SCALE,
"vFindHdmxTable, bogus xform\n");
// if this is the version that we do not understand, return
if (phdr->Version != 0)
return;
cRecords = BE_UINT16(&phdr->cRecords);
cjRecord = (ULONG)SWAPL(phdr->cjRecord);
ASSERTDD((cjRecord & 3) == 0, "cjRecord\n");
// if yEmHt > 255, can not fit in the byte, so there is no need to
// to search for the hdmx entry:
if (yEmHt > 255)
return;
// Finally, find out if there is something useful there. Note that the
// table is sorted by size, so we can take an early out.
phdmx = (HDMXTABLE *)(phdr + 1);
phdmxEnd = (HDMXTABLE *)((PBYTE)phdmx + cRecords * cjRecord);
for
(
;
phdmx < phdmxEnd;
phdmx = (HDMXTABLE *)((PBYTE)phdmx + cjRecord)
)
{
if (((BYTE) yEmHt) <= phdmx->ucEmY)
{
if (((BYTE) yEmHt) == phdmx->ucEmY)
pfc->phdmx = phdmx; // We found it.
break;
}
}
}
/******************************Public*Routine******************************\
*
* bGrabXform
*
* updates buffers 0 and 4, those that save the state of the transform.
* also for "buggy" fonts (URW FONTS) some of the transform dependent
* info (twightlight points) may be stored in the buffer 3, which otherwise would be shareable
* this is unfortunate, more memory is required
*
*
* History:
* 24-Mar-1993 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BOOL
bGrabXform (
PFONTCONTEXT pfc
)
{
BOOL bOk = TRUE;
if (pfc->pff->pfcLast != pfc)
{
// have to refresh the transform, somebody has changed it on us
if (bOk = bSetXform(pfc))
{
// affirm that we are the ones who have set the transform last
pfc->pff->pfcLast = pfc;
}
else // make sure to restore the old current transform
{
#if DBG
BOOL bOkXform =
#endif
bSetXform(pfc->pff->pfcLast);
ASSERTDD(bOkXform, "bOkXform\n");
}
}
return (bOk);
}
/******************************Public*Routine******************************\
* vSetGrayState__FONTCONTEXT *
* *
* This routine set the FO_GRAY16 bit in pfc->flFontType and *
* pfc->pfo->flFontType as is appropriate. If the bit is set *
* then, later on, we shall make calls to the fs_FindGraySize and *
* fs_ContourGrayScan pair instead of the usual monochrome pair of *
* calls, fs_FindBitmapSize and fs_ContourScan. *
* *
* The only effect that this routine could have is to clear *
* the FO_GRAY16 flags in pfc->flFontType and pfc->pfo->flFontType. *
* *
* The only way in which this clearing could occur is if all of the *
* following conditions are met: 1) the caller has not set the *
* FO_NO_CHOICE bit; 2) the font has a 'gasp' table; 3) the 'gasp' *
* table indicates that for the requested number of pixels per em *
* the 'gasp' table indicates that the font should not be grayed; 4) *
* the glyphs of the font are not acted upon by a simple scaling *
* transformation. *
* *
* On Entry *
* *
* pfc->flFontType & FO_GRAY16 != 0 *
* pfc->pfo->flFontType & FO_GRAY16 != 0 *
* *
* Procedure *
* *
* 1. if the force bit is on then go to 6. *
* 2. if the transformation is not axial then go to 6. *
* 3. if the font does not gave a 'gasp' table then go to 6. *
* 4. if the gasp table says that this size is ok for graying then *
* go to 6. *
* 5. clear the FO_GRAY16 flags in both places *
* 6. return *
* *
* History: *
* Fri 10-Feb-1995 14:02:51 by Kirk Olynyk [kirko] *
* Wrote it. *
\**************************************************************************/
VOID vSetGrayState__FONTCONTEXT(FONTCONTEXT *this)
{
#if DBG
void vPrintGASPTABLE(GASPTABLE*);
#endif
ptrdiff_t dp; // offset from the beginning of the font to the
// 'gasp' table
GASPTABLE *pgasp; // pointer to the 'gasp' table
USHORT usEmHt; // requested pixels per em
GASPRANGE *pgr, *pgrOut;
ASSERTDD(
this->flFontType == this->pfo->flFontType
,"flFontType value should be identical here\n"
);
ASSERTDD(
!(this->flFontType & FO_CHOSE_DEPTH)
,"We should not have chosen a level at this time\n"
);
this->flFontType |= FO_CHOSE_DEPTH;
if (this->flFontType & FO_GRAY16)
{
this->flFontType &= ~(FO_GRAY16);
if (this->flFontType & FO_NO_CHOICE)
{
this->flFontType |= FO_GRAY16;
}
else
{
if (!(dp = (ptrdiff_t) (this->ptp->ateOpt[IT_OPT_GASP].dp)))
{
USHORT fs;
// Win95 lifts the default GASP tables from the registry
// We should have the same behavior. Bug #11755
#define US2BE(x) ((((x) >> 8) | ((x) << 8)) & 0xFFFF)
static CONST USHORT gaspDefaultRegular[] = {
US2BE(0) // version
, US2BE(3) // numRanges
, US2BE(8) , US2BE(GASP_DOGRAY)
, US2BE(17) , US2BE(GASP_GRIDFIT)
, US2BE(USHRT_MAX) , US2BE(GASP_GRIDFIT + GASP_DOGRAY)
};
static CONST USHORT gaspDefaultBold[] = {
US2BE(0) // version
, US2BE(2) // numRanges
, US2BE(8) , US2BE(GASP_DOGRAY)
, US2BE(USHRT_MAX) , US2BE(GASP_GRIDFIT + GASP_DOGRAY)
};
static CONST USHORT *gaspDefaultItalic = gaspDefaultRegular;
#if DBG
if (gflTtfdDebug & DEBUG_GRAY)
{
TtfdDbgPrint("Supplying default GASPTABLE\n");
}
#endif // DBG
fs = this->pff->ifi.fsSelection;
if (fs & FM_SEL_ITALIC)
{
pgasp = (GASPTABLE*) gaspDefaultItalic;
}
else if (fs & FM_SEL_BOLD)
{
pgasp = (GASPTABLE*) gaspDefaultBold;
}
else
{
pgasp = (GASPTABLE*) gaspDefaultRegular;
}
}
else
{
pgasp = (GASPTABLE*) (((BYTE *)(this->pff->pvView)) + dp);
}
#if DBG
if (gflTtfdDebug & DEBUG_GRAY)
{
vPrintGASPTABLE(pgasp);
EngDebugBreak();
}
#endif
if (this->lEmHtDev > USHRT_MAX)
{
WARNING("vSetGrayScale: lEmHtDev > USHRT_MAX\n");
}
else
{
size_t cRanges;
int iLow, iHt, iHigh;
// Search the gasp table for the instructions
// for this particular em height. I have assumed that there
// are not too many GASP tables (typically 3 or less) so
// I use a linear search.
pgr = pgasp->gaspRange;
cRanges = BE_UINT16(&(pgasp->numRanges));
if (cRanges > 8)
{
WARNING("Unusual GASPTABLE : cRanges > 8\n");
cRanges = 8;
}
pgrOut = pgr + cRanges;
iLow = -1;
iHt = this->lEmHtDev;
for ( ; pgr < pgrOut; pgr++)
{
iHigh = (int) BE_UINT16(&(pgr->rangeMaxPPEM));
if (iLow < iHt && iHt <= iHigh)
{
if (GASP_DOGRAY & BE_UINT16(&(pgr->rangeGaspBehavior)))
{
this->flFontType |= FO_GRAY16;
}
break;
}
iLow = iHigh;
}
}
}
if (this->flFontType & FO_GRAY16)
{
#if DBG
if (gflTtfdDebug & DEBUG_GRAY)
{
TtfdDbgPrint("Choosing 16-Level Glyphs\n");
}
#endif
}
else
{
#if DBG
if (gflTtfdDebug & DEBUG_GRAY)
{
TtfdDbgPrint(
"\n"
"We came into the routine with the FO_GRAY16 bit set.\n"
"However, for some reason it is not possible to has\n"
"anti-aliased the text. Therefore we must adjust the\n"
"font context and inform it that that antialiasing \n"
"is out of the picture. We will continue and create\n"
"a monochrome font.\n"
);
}
#endif
this->flFontType |= FO_NOGRAY16;
this->pfo->flFontType = this->flFontType;
}
}
}
#if DBG
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* vPrintGASPTABLE *
* *
* Routine Description: *
* *
* Dumps a GASPTABLE to the debug screen *
* *
* Arguments: *
* *
* pgasp -- pointer to a big endian GASPTABLE *
* *
* Return Value: *
* *
* none *
* *
\**************************************************************************/
void vPrintGASPTABLE(GASPTABLE *pgasp)
{
GASPRANGE *pgr, *pgrOut;
TtfdDbgPrint(
"\n"
"-------------------------------------\n"
"GASPTABLE HEADER\n"
"-------------------------------------\n"
"pgasp = %-#x\n"
"version = %d\n"
"numRanges = %d\n"
"-------------------------------------\n"
" rangeMaxPPEM rangeGaspBehavior\n"
"-------------------------------------\n"
, pgasp
, BE_UINT16(&(pgasp->version))
, BE_UINT16(&(pgasp->numRanges))
);
pgr = pgasp->gaspRange;
pgrOut = pgr + BE_UINT16(&(pgasp->numRanges));
for (pgr = pgasp->gaspRange; pgr < pgrOut; pgr++)
{
char *psz;
USHORT us = BE_UINT16(&(pgr->rangeGaspBehavior));
us &= (GASP_GRIDFIT | GASP_DOGRAY);
switch (us)
{
case 0:
psz = "";
break;
case GASP_GRIDFIT:
psz = "GASP_GRIDFIT";
break;
case GASP_DOGRAY:
psz = "GASP_DOGRAY";
break;
case GASP_GRIDFIT | GASP_DOGRAY:
psz = "GASP_GRIDFIT | GASP_DOGRAY";
break;
}
TtfdDbgPrint(
" %12d %s\n"
, BE_UINT16(&(pgr->rangeMaxPPEM))
, psz
);
}
TtfdDbgPrint(
"-------------------------------------\n\n\n"
);
}
#endif