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.
5571 lines
168 KiB
5571 lines
168 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: fd_query.c *
|
|
* *
|
|
* QUERY functions. *
|
|
* *
|
|
* Created: 18-Nov-1991 14:37:56 *
|
|
* Author: Bodin Dresevic [BodinD] *
|
|
* *
|
|
* Copyright (c) 1993 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include "fd.h"
|
|
#include "winfont.h"
|
|
#include "fdsem.h"
|
|
#include "winerror.h"
|
|
|
|
#if DBG
|
|
extern ULONG gflTtfdDebug;
|
|
#endif
|
|
|
|
//
|
|
// Monochrome: 1 bit per pixel
|
|
// Gray: 8 bits per pixel
|
|
//
|
|
// CJ_TT_SCAN rounds up to a 32-bit boundary
|
|
//
|
|
#define CJ_TT_SCAN(cx,p) \
|
|
(4*((((((p)->flFontType & FO_GRAY16)?(8):(1))*(cx))+31)/32))
|
|
|
|
// Each scan of a glyph bitmap is BYTE aligned (except for the
|
|
// top (first) scan which is DWORD aligned. The last scan is
|
|
// padded out with zeros to the nearest DWORD boundary. These
|
|
// statements apply to monochrome and 4-bpp gray glyphs images.
|
|
// The number of bytes per scan will depend upon the number of
|
|
// pixels in a scan and the depth of the image. For monochrome
|
|
// glyphs the number of bytes per scan is ceil(cx/8) = floor((cx+7)/8)
|
|
// For the case of 4-bpp bitmaps the count of bytes in a scan
|
|
// is ceil( 4*cx/8 ) = ceil(cx/2)
|
|
|
|
#define CJ_MONOCHROME_SCAN(cx) (((cx)+7)/8)
|
|
#define CJ_GRAY_SCAN(cx) (((cx)+1)/2)
|
|
|
|
#if DBG
|
|
#define IS_GRAY(p) ((((p)->flFontType & FO_CHOSE_DEPTH) ? \
|
|
0 : TtfdDbgPrint("Level Not chosen yet\n")) ,(p)->flFontType & FO_GRAY16)
|
|
#else
|
|
#define IS_GRAY(p) (p)->flFontType & FO_GRAY16
|
|
#endif
|
|
|
|
#if DBG
|
|
// #define DEBUG_OUTLINE
|
|
// #define DBG_CHARINC
|
|
#endif
|
|
|
|
|
|
// notional space metric data for an individual glyph
|
|
|
|
typedef struct _NOT_GM // ngm, notional glyph metrics
|
|
{
|
|
SHORT xMin;
|
|
SHORT xMax;
|
|
SHORT yMin; // char box in notional
|
|
SHORT yMax;
|
|
SHORT sA; // a space in notional
|
|
SHORT sD; // char inc in notional
|
|
|
|
} NOT_GM, *PNOT_GM;
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vCharacterCode
|
|
*
|
|
* History:
|
|
* 07-Dec-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vCharacterCode (
|
|
FONTFILE *pff,
|
|
HGLYPH hg,
|
|
fs_GlyphInputType *pgin
|
|
)
|
|
{
|
|
ASSERTDD((hg & 0xffff0000) == 0, "hg not unicode\n");
|
|
|
|
if (pff->iGlyphSet == GSET_TYPE_GENERAL ||
|
|
pff->iGlyphSet == GSET_TYPE_GENERAL_NOT_UNICODE ||
|
|
pff->iGlyphSet == GSET_TYPE_HIGH_BYTE)
|
|
{
|
|
pgin->param.newglyph.characterCode = NONVALID;
|
|
pgin->param.newglyph.glyphIndex = (uint16)hg;
|
|
return;
|
|
}
|
|
|
|
switch (pff->iGlyphSet)
|
|
{
|
|
case GSET_TYPE_MAC_ROMAN:
|
|
|
|
//!!! this is piece of ... stolen from JeanP. This routine should
|
|
//!!! be replaced by a proper NLS routine that takes into acount
|
|
//!!! mac lang id. [bodind]
|
|
|
|
hg = ui16UnicodeToMac((WCHAR)hg);
|
|
break;
|
|
|
|
case GSET_TYPE_PSEUDO_WIN:
|
|
case GSET_TYPE_SYMBOL:
|
|
|
|
// hg on the entry is an "ansi" code point for the glyph
|
|
|
|
if (pff->iGlyphSet == GSET_TYPE_SYMBOL)
|
|
hg += pff->wcBiasFirst; // offset by high byte of chfirst
|
|
|
|
break;
|
|
|
|
default:
|
|
RIP("TTFD!_ulGsetType\n");
|
|
break;
|
|
}
|
|
|
|
pgin->param.newglyph.characterCode = (uint16)hg;
|
|
pgin->param.newglyph.glyphIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* LONG ttfdQueryCaps
|
|
*
|
|
*
|
|
* Effects: returns the capabilities of this driver.
|
|
* Only mono bitmaps are supported.
|
|
*
|
|
*
|
|
* History:
|
|
* 27-Nov-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG ttfdQueryFontCaps (
|
|
ULONG culCaps,
|
|
ULONG *pulCaps
|
|
)
|
|
{
|
|
ULONG culCopied = min(culCaps,2);
|
|
ULONG aulCaps[2];
|
|
|
|
aulCaps[0] = 2L; // number of ULONG's in a complete array
|
|
|
|
//!!! make sure that outlines are really supported in the end, when this driver
|
|
//!!! is completed, if not, get rid of FD_OUTLINES flag [bodind]
|
|
|
|
aulCaps[1] = (QC_1BIT | QC_OUTLINES); // 1 bit per pel bitmaps only are supported
|
|
|
|
RtlCopyMemory((PVOID)pulCaps,(PVOID)aulCaps, culCopied * 4);
|
|
return( culCopied );
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PIFIMETRICS ttfdQueryFont
|
|
*
|
|
* Return a pointer to the IFIMETRICS for the specified face of the font
|
|
* file. Also returns an id (via the pid parameter) that is later used
|
|
* by ttfdFree.
|
|
*
|
|
* History:
|
|
* 21-Oct-1992 Gilman Wong [gilmanw]
|
|
* IFI/DDI merge
|
|
*
|
|
* 18-Nov-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
IFIMETRICS *ttfdQueryFont (
|
|
DHPDEV dhpdev,
|
|
HFF hff,
|
|
ULONG iFace,
|
|
ULONG *pid
|
|
)
|
|
{
|
|
|
|
#ifdef FE_SB
|
|
HFF httc = hff;
|
|
|
|
// Validate handle.
|
|
|
|
ASSERTDD(hff, "ttfdQueryFaces(): invalid iFile (hff)\n");
|
|
ASSERTDD(iFace <= PTTC(hff)->ulNumEntry,
|
|
"gdisrv!ttfdQueryFaces(): iFace out of range\n");
|
|
|
|
// get real hff from ttc array.
|
|
|
|
hff = PTTC(httc)->ahffEntry[iFace-1].hff;
|
|
iFace = PTTC(httc)->ahffEntry[iFace-1].iFace;
|
|
#endif
|
|
|
|
dhpdev;
|
|
|
|
//
|
|
// Validate handle.
|
|
//
|
|
ASSERTDD(hff, "ttfdQueryFaces(): invalid iFile (hff)\n");
|
|
ASSERTDD(iFace <= PFF(hff)->ulNumFaces,
|
|
"ttfdQueryFaces(): iFace out of range\n");
|
|
|
|
//
|
|
// ttfdFree can ignore this. IFIMETRICS will be deleted with the FONTFILE
|
|
// structure.
|
|
//
|
|
*pid = (ULONG) NULL;
|
|
|
|
//
|
|
// Return the pointer to the precomputed IFIMETRICS in the PFF.
|
|
//
|
|
|
|
if ( iFace == 1L )
|
|
return ( &(PFF(hff)->ifi) ); // Normal face
|
|
else
|
|
return ( PFF(hff)->pifi_vertical ); // Vertical face
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vFillSingularGLYPHDATA
|
|
*
|
|
* History:
|
|
* 22-Sep-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vFillSingularGLYPHDATA (
|
|
HGLYPH hg,
|
|
ULONG ig,
|
|
FONTCONTEXT *pfc,
|
|
GLYPHDATA *pgldt // OUT
|
|
)
|
|
{
|
|
extern VOID vGetNotionalGlyphMetrics(FONTCONTEXT*, ULONG, NOT_GM*);
|
|
NOT_GM ngm; // notional glyph data
|
|
|
|
// may get changed by the calling routine if bits requested too
|
|
pgldt->gdf.pgb = NULL;
|
|
pgldt->hg = hg;
|
|
|
|
// this is a fake 1x1 bitmap
|
|
|
|
pgldt->rclInk.left = 0;
|
|
pgldt->rclInk.top = 0;
|
|
pgldt->rclInk.right = 0;
|
|
pgldt->rclInk.bottom = 0;
|
|
|
|
// go on to compute the positioning info:
|
|
|
|
// here we will just xform the notional space data:
|
|
|
|
vGetNotionalGlyphMetrics(pfc,ig,&ngm);
|
|
|
|
// xforms are computed by simple multiplication
|
|
|
|
pgldt->fxD = fxLTimesEf(&pfc->efBase, (LONG)ngm.sD);
|
|
pgldt->fxA = fxLTimesEf(&pfc->efBase, (LONG)ngm.sA);
|
|
pgldt->fxAB = fxLTimesEf(&pfc->efBase, (LONG)ngm.xMax);
|
|
|
|
pgldt->fxInkTop = - fxLTimesEf(&pfc->efSide, (LONG)ngm.yMin);
|
|
pgldt->fxInkBottom = - fxLTimesEf(&pfc->efSide, (LONG)ngm.yMax);
|
|
|
|
vLTimesVtfl((LONG)ngm.sD, &pfc->vtflBase, &pgldt->ptqD);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* lGetSingularGlyphBitmap
|
|
*
|
|
* History:
|
|
* 22-Sep-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG lGetSingularGlyphBitmap (
|
|
FONTCONTEXT *pfc,
|
|
HGLYPH hglyph,
|
|
GLYPHDATA *pgd,
|
|
VOID *pv
|
|
)
|
|
{
|
|
LONG cjGlyphData;
|
|
ULONG ig;
|
|
FS_ENTRY iRet;
|
|
|
|
|
|
vCharacterCode(pfc->pff,hglyph,pfc->pgin);
|
|
|
|
// Compute the glyph index from the character code:
|
|
|
|
if ((iRet = fs_NewGlyph(pfc->pgin, pfc->pgout)) != NO_ERR)
|
|
{
|
|
V_FSERROR(iRet);
|
|
|
|
WARNING("gdisrv!lGetSingularGlyphBitmap(): fs_NewGlyph failed\n");
|
|
return FD_ERROR;
|
|
}
|
|
|
|
// Return the glyph index corresponding to this hglyph.
|
|
|
|
ig = pfc->pgout->glyphIndex;
|
|
|
|
ASSERTDD(pfc->flFontType & FO_CHOSE_DEPTH,"Depth Not Chosen Yet!\n");
|
|
cjGlyphData = CJGD(1,1,pfc);
|
|
|
|
// If prg is NULL, caller is requesting just the size.
|
|
|
|
// At this time we know that the caller wants the whole GLYPHDATA with
|
|
// bitmap bits, or maybe just the glypdata without the bits.
|
|
// In either case we shall reject the caller if he did not
|
|
// provide sufficiently big buffer
|
|
|
|
// fill all of GLYPHDATA structure except for bitmap bits
|
|
|
|
if ( pgd != (GLYPHDATA *)NULL )
|
|
{
|
|
vFillSingularGLYPHDATA( hglyph, ig, pfc, pgd );
|
|
}
|
|
|
|
if ( pv != NULL )
|
|
{
|
|
GLYPHBITS *pgb = (GLYPHBITS *)pv;
|
|
|
|
// By returning a small 1x1 bitmap, we save device drivers from having
|
|
// to special case this.
|
|
|
|
// The corresponding GLYPHDATA structure has been modified
|
|
// by vFillGlyphData. See the statement "pgldt->fxA = 0"
|
|
// in vFillGlyphData.
|
|
|
|
pgb->ptlOrigin.x = pfc->ptlSingularOrigin.x;
|
|
pgb->ptlOrigin.y = pfc->ptlSingularOrigin.y;
|
|
|
|
pgb->sizlBitmap.cx = 1; // cheating
|
|
pgb->sizlBitmap.cy = 1; // cheating
|
|
|
|
// This is where we fill in the blank 1x1 dib
|
|
// it turns out that a single zero'ed byte
|
|
// covers both the 1-bpp and 4-bpp cases
|
|
|
|
*((ULONG *)pgb->aj) = 0; // fill in a blank 1x1 dib
|
|
}
|
|
|
|
if ( pgd != (GLYPHDATA *)NULL )
|
|
{
|
|
pgd->gdf.pgb = (GLYPHBITS *)pv;
|
|
}
|
|
|
|
|
|
// Return the size.
|
|
|
|
return(cjGlyphData);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* lGetGlyphBitmap
|
|
*
|
|
* History:
|
|
* 20-Nov-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG lGetGlyphBitmap (
|
|
FONTCONTEXT *pfc,
|
|
HGLYPH hglyph,
|
|
GLYPHDATA *pgd,
|
|
VOID *pv,
|
|
BOOL bMinBmp,
|
|
FS_ENTRY *piRet
|
|
)
|
|
{
|
|
PVOID pvSetMemoryBases(fs_GlyphInfoType*, fs_GlyphInputType*, int);
|
|
VOID vCopyAndZeroOutPaddingBits(FONTCONTEXT*, GLYPHBITS*, BYTE*, GMC*);
|
|
VOID vCopyGrayBits(FONTCONTEXT*, GLYPHBITS*, BYTE*, GMC*);
|
|
STATIC VOID vMakeAFixedPitchBitmap(FONTCONTEXT*, GLYPHBITS*, BYTE*, GLYPHDATA*,
|
|
GMC*);
|
|
VOID vTtfdEmboldenBitmapInPlace(FONTCONTEXT*,GLYPHBITS*);
|
|
VOID vEmboldenGrayBitmap(FONTCONTEXT*, GLYPHBITS*);
|
|
VOID vMakeAFixedPitchGrayBitmap(FONTCONTEXT*,GLYPHBITS*,BYTE*,GLYPHDATA*,GMC*);
|
|
VOID vFillGLYPHDATA(HGLYPH, ULONG, FONTCONTEXT*, fs_GlyphInfoType*, GLYPHDATA*, GMC*, POINTL*, BOOL);
|
|
BOOL bGetGlyphMetrics(FONTCONTEXT*, HGLYPH, FLONG, FS_ENTRY*);
|
|
LONG lGetGlyphBitmapVertical(FONTCONTEXT*,HGLYPH,GLYPHDATA*,PVOID,BOOL,FS_ENTRY*);
|
|
|
|
LONG cjGlyphData;
|
|
ULONG cx,cy;
|
|
GMC gmc;
|
|
GLYPHDATA gd;
|
|
POINTL ptlOrg;
|
|
BOOL bBlankGlyph = FALSE; // initialization essential;
|
|
|
|
ASSERTDD(hglyph != HGLYPH_INVALID, "lGetGlyphBitmap, hglyph == -1\n");
|
|
ASSERTDD(pfc == pfc->pff->pfcLast, "pfc! = pfcLast\n");
|
|
|
|
*piRet = NO_ERR;
|
|
|
|
// check the last glyph processed to determine
|
|
// whether we have to register the glyph as new and compute its size
|
|
|
|
if (pfc->gstat.hgLast != hglyph)
|
|
{
|
|
// DO skip grid fitting if embedded bitmpas are found,
|
|
// for we will NOT be interested in outlines
|
|
|
|
if (!bGetGlyphMetrics(pfc,hglyph,FL_SKIP_IF_BITMAP,piRet))
|
|
{
|
|
return(FD_ERROR);
|
|
}
|
|
}
|
|
|
|
cx = pfc->pgout->bitMapInfo.bounds.right
|
|
- pfc->pgout->bitMapInfo.bounds.left;
|
|
cy = pfc->pgout->bitMapInfo.bounds.bottom
|
|
- pfc->pgout->bitMapInfo.bounds.top;
|
|
|
|
// here we shall endulge in cheating. If cx or cy is zero
|
|
// (ususally space character - no bits to set, but there is a nontrivial
|
|
// positioning information) we shall cheat and instead of retrning no bits
|
|
// for bimtap we shall
|
|
// return a small 1x1 bitmap, which will be blank, i.e. all bits will be off
|
|
// this prevents having to insert an if(cx && cy) check to a time critical
|
|
// loop in all device drivers before calling DrawGlyph routine.
|
|
|
|
if ((cx == 0) || (cy == 0)) // cheat here
|
|
{
|
|
bBlankGlyph = TRUE;
|
|
}
|
|
|
|
if (!bMinBmp)
|
|
{
|
|
// pfc->lD != 0, fixed pitch console font, all bitmaps are of the same size
|
|
|
|
cjGlyphData = (LONG)pfc->cjGlyphMax;
|
|
}
|
|
else // usual case, not a console font or minimal bitmaps are wanted
|
|
{
|
|
if (bBlankGlyph)
|
|
{
|
|
ASSERTDD(
|
|
pfc->flFontType & FO_CHOSE_DEPTH,"Depth Not Chosen Yet!\n");
|
|
cjGlyphData = CJGD(1,1,pfc);
|
|
}
|
|
else
|
|
{
|
|
// this is quick and dirty computation, the acutal culGlyphData
|
|
// written to the buffer may be little smaller if we had to shave
|
|
// off a few scans off the glyph bitmap that extended over
|
|
// the pfc->yMin or pfc->yMax bounds. Notice that culGlyphData
|
|
// computed this way may be somewhat bigger than pfc->culGlyphMax,
|
|
// but the actual glyph written to the buffer will be smaller than
|
|
// pfc->culGlyphMax
|
|
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
cx += 1;
|
|
// really win31 hack, shold not always be shifting right [bodind]
|
|
|
|
ASSERTDD(
|
|
pfc->flFontType & FO_CHOSE_DEPTH,
|
|
"Depth Not Chosen Yet!\n"
|
|
);
|
|
cjGlyphData = CJGD(cx,cy,pfc);
|
|
|
|
// since we will shave off any extra rows if there are any,
|
|
// we can fix culGlyphData so as not extend over the max value
|
|
|
|
if ((ULONG)cjGlyphData > pfc->cjGlyphMax)
|
|
cjGlyphData = (LONG)pfc->cjGlyphMax;
|
|
}
|
|
}
|
|
|
|
if ( (pgd == NULL) && (pv == NULL))
|
|
return cjGlyphData;
|
|
|
|
// at this time we know that the caller wants the whole GLYPHDATA with
|
|
// bitmap bits, or maybe just the glypdata without the bits.
|
|
|
|
// fill all of GLYPHDATA structure except for bitmap bits
|
|
// !!! Scummy hack - there appears to be no way to get just the
|
|
// !!! bitmap, without getting the metrics, since the origin for the
|
|
// !!! bitmap is computed from the rclink field in the glyphdata.
|
|
// !!! this is surely fixable but I have neither the time nor the
|
|
// !!! inclination to pursue it.
|
|
// !!!
|
|
// !!! We should fix this when we have time.
|
|
|
|
if ( pgd == NULL )
|
|
{
|
|
pgd = &gd;
|
|
}
|
|
|
|
if ( pfc->bVertical && ( pfc->ulControl & VERTICAL_MODE ) )
|
|
{
|
|
// Vertical case
|
|
fs_GlyphInfoType my_gout;
|
|
|
|
vShiftBitmapInfo( pfc, &my_gout, pfc->pgout );
|
|
vFillGLYPHDATA(
|
|
pfc->hgSave, // this is a little bit tricky. we wouldn't like to
|
|
pfc->gstat.igLast, // tell GDI about vertical glyph index.
|
|
pfc,
|
|
&my_gout,
|
|
pgd,
|
|
&gmc,
|
|
&ptlOrg,
|
|
bMinBmp
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// Normal case
|
|
vFillGLYPHDATA(
|
|
hglyph,
|
|
pfc->gstat.igLast,
|
|
pfc,
|
|
pfc->pgout,
|
|
pgd,
|
|
&gmc,
|
|
&ptlOrg,
|
|
bMinBmp
|
|
);
|
|
}
|
|
|
|
// the caller wants the bits too
|
|
|
|
if ( pv != NULL )
|
|
{
|
|
GLYPHBITS *pgb = (GLYPHBITS *)pv;
|
|
|
|
// allocate mem for the glyph, 5-7 are magic #s required by the spec
|
|
// remember the pointer so that the memory can be freed later in case
|
|
// of exception
|
|
|
|
pfc->gstat.pv = pvSetMemoryBases(pfc->pgout, pfc->pgin, IS_GRAY(pfc));
|
|
if (!pfc->gstat.pv)
|
|
RETURN("TTFD!_ttfdQGB, mem allocation failed\n",FD_ERROR);
|
|
|
|
// initialize the fields needed by fs_ContourScan,
|
|
// the routine that fills the outline, do the whole
|
|
// bitmap at once, do not want banding
|
|
|
|
pfc->pgin->param.scan.bottomClip = pfc->pgout->bitMapInfo.bounds.top;
|
|
pfc->pgin->param.scan.topClip = pfc->pgout->bitMapInfo.bounds.bottom;
|
|
pfc->pgin->param.scan.outlineCache = (int32 *)NULL;
|
|
|
|
|
|
// make sure that our state is ok: the ouline data in the shared buffer 3
|
|
// must correspond to the glyph we are processing, and the last
|
|
// font context that used the shared buffer pj3 to store glyph outlines
|
|
// has to be the pfc passed to this function:
|
|
|
|
ASSERTDD(hglyph == pfc->gstat.hgLast, "hgLast trashed \n");
|
|
|
|
if (IS_GRAY(pfc))
|
|
{
|
|
*piRet = fs_ContourGrayScan(pfc->pgin,pfc->pgout);
|
|
}
|
|
else
|
|
{
|
|
*piRet = fs_ContourScan(pfc->pgin,pfc->pgout);
|
|
}
|
|
pfc->gstat.hgLast = HGLYPH_INVALID;
|
|
|
|
|
|
if (*piRet != NO_ERR)
|
|
{
|
|
// just to be safe for the next time around, reset pfcLast to NULL
|
|
|
|
V_FSERROR(*piRet);
|
|
V_FREE(pfc->gstat.pv);
|
|
pfc->gstat.pv = NULL;
|
|
|
|
return(FD_ERROR);
|
|
}
|
|
|
|
if (!bMinBmp)
|
|
{
|
|
pgb->sizlBitmap.cx = pfc->lD;
|
|
pgb->sizlBitmap.cy = pfc->yMax - pfc->yMin;
|
|
|
|
pgb->ptlOrigin.x = 0;
|
|
pgb->ptlOrigin.y = pfc->yMin;
|
|
|
|
// clear the whole destination first
|
|
|
|
RtlZeroMemory(pgb->aj, pfc->cjGlyphMax - offsetof(GLYPHBITS,aj));
|
|
|
|
if (!bBlankGlyph && gmc.cxCor && gmc.cyCor)
|
|
{
|
|
if (IS_GRAY(pfc))
|
|
{
|
|
vMakeAFixedPitchGrayBitmap(
|
|
pfc,
|
|
pgb,
|
|
(PBYTE)pfc->pgout->bitMapInfo.baseAddr, // pjSrc
|
|
pgd,
|
|
&gmc
|
|
);
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
vEmboldenGrayBitmap(pfc, pgb);
|
|
}
|
|
else
|
|
{
|
|
vMakeAFixedPitchBitmap(
|
|
pfc,
|
|
pgb,
|
|
(PBYTE)pfc->pgout->bitMapInfo.baseAddr, // pjSrc
|
|
pgd,
|
|
&gmc
|
|
);
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
vTtfdEmboldenBitmapInPlace(pfc, pgb);
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// The usual case is where bMinBmp is true. This is the case
|
|
// where the client is requesting minimal bitmaps from the
|
|
// the font driver. A 'minimal' is a 'trimmed' bitmap.
|
|
|
|
if (!bBlankGlyph && gmc.cxCor && gmc.cyCor)
|
|
{
|
|
// copy to the engine's buffer and zero out the bits
|
|
// outside of the black box
|
|
|
|
#if DBG
|
|
if ((pfc->flXform & XFORM_POSITIVE_SCALE) && !(pfc->flFontType & FO_SIM_BOLD))
|
|
{
|
|
ASSERTDD(gmc.cxCor == (ULONG)((pgd->fxAB - pgd->fxA) >> 4),
|
|
"TTFD!vCopyAndZeroOutPaddingBits, SUM RULE\n");
|
|
}
|
|
#endif
|
|
/***************************************************************
|
|
* Call either the monochrome or the gray level function *
|
|
* depending upon the gray bit in the font context *
|
|
***************************************************************/
|
|
(*(IS_GRAY(pfc) ? vCopyGrayBits : vCopyAndZeroOutPaddingBits))(
|
|
pfc
|
|
, pgb
|
|
, (BYTE*) pfc->pgout->bitMapInfo.baseAddr
|
|
, &gmc
|
|
);
|
|
/****************************************************************
|
|
* If the bold simulation bit is set then call either the *
|
|
* monochrome or gray level emboldening function on the *
|
|
* bitmap *
|
|
****************************************************************/
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
(*(IS_GRAY(pfc) ?
|
|
vEmboldenGrayBitmap :
|
|
vTtfdEmboldenBitmapInPlace))(pfc, pgb);
|
|
|
|
// bitmap origin, i.e. the upper left corner of the bitmap, bitmap
|
|
// is as big as its black box
|
|
|
|
if (!(pfc->flXform & (XFORM_HORIZ | XFORM_VERT)))
|
|
{
|
|
pgb->ptlOrigin = ptlOrg;
|
|
}
|
|
else
|
|
{
|
|
pgb->ptlOrigin.x = pgd->rclInk.left;
|
|
pgb->ptlOrigin.y = pgd->rclInk.top;
|
|
}
|
|
}
|
|
else // blank glyph, cheat and return a blank 1x1 bitmap
|
|
{
|
|
if (bBlankGlyph)
|
|
{
|
|
ASSERTDD(cjGlyphData == CJ_GLYPHDATA(1,1),
|
|
"bBlankGlyph, cjGlyphData\n");
|
|
|
|
ASSERTDD(
|
|
pfc->flFontType & FO_CHOSE_DEPTH
|
|
,"Depth Not Chosen Yet!\n");
|
|
if (bBlankGlyph)
|
|
{
|
|
ASSERTDD(
|
|
cjGlyphData == (LONG) CJGD(1,1,pfc),
|
|
"TTFD!_bBlankGlyph, cjGlyphData\n"
|
|
);
|
|
}
|
|
else
|
|
{
|
|
ASSERTDD(
|
|
cjGlyphData >= (LONG) CJGD(1,1,pfc),
|
|
"TTFD!_corrected blank glyph, cjGlyphData\n"
|
|
);
|
|
}
|
|
}
|
|
|
|
pgb->ptlOrigin.x = pfc->ptlSingularOrigin.x;
|
|
pgb->ptlOrigin.y = pfc->ptlSingularOrigin.y;
|
|
|
|
pgb->sizlBitmap.cx = 1; // cheating
|
|
pgb->sizlBitmap.cy = 1; // cheating
|
|
|
|
pgb->aj[0] = (BYTE)0; // fill in a blank 1x1 bmp
|
|
|
|
}
|
|
}
|
|
pgd->gdf.pgb = pgb;
|
|
|
|
// free memory and return
|
|
|
|
V_FREE(pfc->gstat.pv);
|
|
pfc->gstat.pv = NULL;
|
|
}
|
|
|
|
if (!bMinBmp)
|
|
{
|
|
// need to fix glyph data cause we may have shaved some columns
|
|
|
|
ASSERTDD((pfc->lD << 4) == pgd->fxD, "fxD is bogus\n");
|
|
if (pgd->fxA < 0)
|
|
{
|
|
pgd->fxA = 0;
|
|
pgd->rclInk.left = 0;
|
|
}
|
|
if (pgd->fxAB > pgd->fxD)
|
|
{
|
|
pgd->fxAB = pgd->fxD;
|
|
pgd->rclInk.right = pfc->lD;
|
|
}
|
|
}
|
|
return(cjGlyphData);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bIndexToWchar
|
|
*
|
|
* Effects:
|
|
*
|
|
* Converts glyph index to the wchar that corresponds to that glyph
|
|
* index. returns true if succeeds, the function will fail only if
|
|
* there happens to be a bug in the font file, otherwise it should
|
|
* always succeed.
|
|
*
|
|
* Comments:
|
|
*
|
|
* The Win 3.1 algorithm generates a table for glyph index to Unicode
|
|
* translation. The table consists of an array of Unicode codepoints
|
|
* indexed by the corresponding glyph index. The table is built by
|
|
* scanning the ENTIRE cmap table. As each glyph index is encountered,
|
|
* its corresponding Unicode codepoint is put into the table EVEN IF
|
|
* THIS MEANS OVERWRITING A PREVIOUS VALUE. The effect of this is that
|
|
* Win 3.1, in the situation where there is a one-to-many mapping of
|
|
* glyph index to Unicode codepoint, always picks the last Unicode
|
|
* character encountered in the cmap table. We emulate this behavior
|
|
* by scanning the cmap table BACKWARDS and terminating the search at
|
|
* the first match encountered. [GilmanW]
|
|
*
|
|
* Returns:
|
|
* TRUE if conversion succeeded, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 16-May-1993 Gilman Wong [gilmanw]
|
|
* Re-wrote. Changed translation to be Win 3.1 compatible. Win 3.1 does
|
|
* not terminate the search as soon as the first Unicode character is found
|
|
* with the proper glyph index. Instead, its algorithm finds the LAST
|
|
* Unicode character with the proper glyph index.
|
|
*
|
|
* 06-Mar-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bIndexToWchar(FONTFILE *pff, WCHAR *pwc, uint16 usIndex)
|
|
{
|
|
uint16 *pstartCount, *pendCount, // Arrays that define the
|
|
*pidDelta, *pidRangeOffset; // Unicode runs supported
|
|
// by the CMAP table.
|
|
uint16 *pendCountStart; // Beginning of arrays.
|
|
uint16 cRuns; // Number of Unicode runs.
|
|
uint16 usLo, usHi, idDelta, idRangeOffset; // Current Unicode run.
|
|
uint16 *pidStart, *pid; // To parse glyph index array.
|
|
uint16 usIndexBE; // Big endian ver of usIndex.
|
|
sfnt_mappingTable *pmap = (sfnt_mappingTable *)(
|
|
(BYTE *)pff->pvView + pff->dpMappingTable
|
|
);
|
|
|
|
uint16 *pusEnd = (uint16 *)((BYTE *)pmap + (uint16)SWAPW(pmap->length));
|
|
|
|
// First must check if this is an MSFT style tt file or a Mac style file.
|
|
// Each case is handled separately.
|
|
|
|
if (pff->ui16PlatformID == BE_PLAT_ID_MAC)
|
|
{
|
|
PBYTE pjGlyphIdArray;
|
|
PBYTE pjGlyph;
|
|
BYTE jIndex;
|
|
|
|
// This is an easy case, GlyphIdArray is indexed into by mac code point,
|
|
// all we have to do is to convert it to UNICODE:
|
|
//
|
|
// Scan backwards for Win 3.1 compatibility.
|
|
|
|
ASSERTDD(pmap->format == BE_FORMAT_MAC_STANDARD,
|
|
"bIndexToWchar cmap format for mac\n");
|
|
ASSERTDD(usIndex < 256, "bIndexToWchar mac usIndex > 255\n");
|
|
|
|
jIndex = (BYTE) usIndex;
|
|
|
|
pjGlyphIdArray = (PBYTE)pmap + SIZEOF_CMAPTABLE;
|
|
pjGlyph = &pjGlyphIdArray[255];
|
|
|
|
for ( ; pjGlyph >= pjGlyphIdArray; pjGlyph--)
|
|
{
|
|
if (*pjGlyph == jIndex)
|
|
{
|
|
// Must convert the Mac code point to Unicode. The Mac code
|
|
// point is a BYTE; indeed, it is the index of the glyph id in
|
|
// the table and may be computed as the current offset from
|
|
// the beginning of the table.
|
|
|
|
jIndex = (BYTE) (pjGlyph - pjGlyphIdArray);
|
|
vCvtMacToUnicode((ULONG)pff->ui16LanguageID,pwc,&jIndex,1);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// If we are here, this is an indication of a bug in the font file
|
|
// (well, or possibly in my code [bodind])
|
|
|
|
WARNING("TTFD!_bIndexToWchar invalid kerning index\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// !!!
|
|
// !!! This code is NOT good, We have to get more performance
|
|
// !!!
|
|
|
|
if( pff->ui16PlatformID == BE_PLAT_ID_MS &&
|
|
(pff->iGlyphSet == GSET_TYPE_GENERAL_NOT_UNICODE ||
|
|
pff->iGlyphSet == GSET_TYPE_HIGH_BYTE )
|
|
)
|
|
{
|
|
WcharToIndex *pWCharToIndex = pff->pWCharToIndex;
|
|
UINT ii;
|
|
|
|
for( ii = 0 ; ii < 0xFFFF ; ii++ , pWCharToIndex++ )
|
|
{
|
|
if( (uint16)(pWCharToIndex->hGlyph) == usIndex )
|
|
{
|
|
*pwc = pWCharToIndex->wChar;
|
|
return( TRUE );
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
// !!! 17-May-1993 [GilmanW]
|
|
// !!! Why doesn't this code handle Format 6 (Trimmed table mapping)? The
|
|
// !!! code below only handles Format 4. Format 0 would be the Mac TT file
|
|
// !!! specific code above.
|
|
|
|
// If we get to this point, we know that this is an MSFT style TT file.
|
|
|
|
ASSERTDD(pff->ui16PlatformID == BE_PLAT_ID_MS,
|
|
"bIndexToWchar plat ID messed up\n");
|
|
ASSERTDD(pmap->format == BE_FORMAT_MSFT_UNICODE,
|
|
"bIndexToWchar cmap format for unicode table\n");
|
|
|
|
cRuns = BE_UINT16((PBYTE)pmap + OFF_segCountX2) >> 1;
|
|
|
|
// Get the pointer to the beginning of the array of endCount code points
|
|
|
|
pendCountStart = (uint16 *)((PBYTE)pmap + OFF_endCount);
|
|
|
|
// The final endCode has to be 0xffff; if this is not the case, there
|
|
// is a bug in the TT file or in our code:
|
|
|
|
ASSERTDD(pendCountStart[cRuns - 1] == 0xFFFF,
|
|
"bIndexToWchar pendCount[cRuns - 1] != 0xFFFF\n");
|
|
|
|
// Loop through the four paralel arrays (startCount, endCount, idDelta, and
|
|
// idRangeOffset) and find wc that usIndex corresponds to. Each iteration
|
|
// scans a continuous range of Unicode characters supported by the TT font.
|
|
//
|
|
// To be Win3.1 compatible, we are looking for the LAST Unicode character
|
|
// that corresponds to usIndex. So we scan all the arrays backwards,
|
|
// starting at the end of each of the arrays.
|
|
//
|
|
// Please note the following:
|
|
// For resons known only to the TT designers, startCount array does not
|
|
// begin immediately after the end of endCount array, i.e. at
|
|
// &pendCount[cRuns]. Instead, they insert an uint16 padding which has to
|
|
// set to zero and the startCount array begins after the padding. This
|
|
// padding in no way helps alignment of the structure.
|
|
//
|
|
// Here is the format of the arrays:
|
|
// ________________________________________________________________________________________
|
|
// | endCount[cRuns] | skip 1 | startCount[cRuns] | idDelta[cRuns] | idRangeOffset[cRuns] |
|
|
// |_________________|________|___________________|________________|______________________|
|
|
|
|
// ASSERTDD(pendCountStart[cRuns] == 0, "TTFD!_bIndexToWchar, padding != 0\n");
|
|
|
|
pendCount = &pendCountStart[cRuns - 1];
|
|
pstartCount = &pendCount[cRuns + 1]; // add 1 because of padding
|
|
pidDelta = &pstartCount[cRuns];
|
|
pidRangeOffset = &pidDelta[cRuns];
|
|
|
|
for ( ;
|
|
pendCount >= pendCountStart;
|
|
pstartCount--, pendCount--,pidDelta--,pidRangeOffset--
|
|
)
|
|
{
|
|
usLo = BE_UINT16(pstartCount); // current Unicode run
|
|
usHi = BE_UINT16(pendCount); // [usLo, usHi], inclusive
|
|
idDelta = BE_UINT16(pidDelta);
|
|
idRangeOffset = BE_UINT16(pidRangeOffset);
|
|
|
|
ASSERTDD(usLo <= usHi, "bIndexToWChar: usLo > usHi\n");
|
|
|
|
// Depending on idRangeOffset for the run, indexes are computed
|
|
// differently.
|
|
//
|
|
// If idRangeOffset is zero, then index is the Unicode codepoint
|
|
// plus the delta value.
|
|
//
|
|
// Otherwise, idRangeOffset specifies the BYTE offset of an array of
|
|
// glyph indices (elements of which correspond to the Unicode range
|
|
// [usLo, usHi], inclusive). Actually, each element of the array is
|
|
// the glyph index minus idDelta, so idDelta must be added in order
|
|
// to derive the actual glyph indices from the array values.
|
|
//
|
|
// Notice that the delta arithmetic is always mod 65536.
|
|
|
|
if (idRangeOffset == 0)
|
|
{
|
|
// Glyph index == Unicode codepoint + delta.
|
|
//
|
|
// If (usIndex-idDelta) is within the range [usLo, usHi], inclusive,
|
|
// we have found the glyph index. We'll overload usIndexBE
|
|
// to be usIndex-idDelta == Unicode codepoint.
|
|
|
|
usIndexBE = usIndex - idDelta;
|
|
|
|
if ( (usIndexBE >= usLo) && (usIndexBE <= usHi) )
|
|
{
|
|
*pwc = (WCHAR) usIndexBE;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We are looking for usIndex in an array in which each element
|
|
// is stored in big endian format. Rather than convert each
|
|
// element in the array to little endian, lets turn usIndex into
|
|
// a big endian number.
|
|
//
|
|
// The idDelta is subtracted from usIndex before the conversion
|
|
// because the values in the table we are searching are actually
|
|
// the glyph indices minus idDelta.
|
|
|
|
usIndexBE = usIndex - idDelta;
|
|
usIndexBE = (uint16) ( (usIndexBE << 8) | (usIndexBE >> 8) );
|
|
|
|
// Find the address of the glyph index array. Since we're doing
|
|
// pointer arithmetic with a uint16 ptr and idRangeOffset is a
|
|
// BYTE offset, we need to divide idRangeOffset by sizeof(uint16).
|
|
|
|
pidStart = pidRangeOffset + (idRangeOffset/sizeof(uint16));
|
|
|
|
if (pidStart <= pusEnd) // this will always be the case except for buggy files
|
|
{
|
|
// Search the glyph index array backwards. The range of the search
|
|
// is [usLo, usHi], inclusive, which corresponds to pidStart[0]
|
|
// through pidStart[usHi-usLo].
|
|
|
|
for (pid = &pidStart[usHi - usLo]; pid >= pidStart; pid--)
|
|
{
|
|
if ( usIndexBE == *pid )
|
|
{
|
|
// (pid-pidStart) == current offset into the glyph index
|
|
// array. Glyph index array[0] corresponds to Unicode
|
|
// codepoint usLo.
|
|
// Therefore, (pid-pidStart)+usLo == current
|
|
// Unicode codepoint.
|
|
|
|
*pwc = (WCHAR) ((pid - pidStart) + usLo);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
WARNING("TTFD!_bIndexToWchar: wonky TT file, index not found\n");
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL bIndexToWcharKern(FONTFILE *pff, WCHAR *pwc, uint16 usIndex)
|
|
{
|
|
BOOL bRet = bIndexToWchar(pff, pwc, usIndex);
|
|
|
|
if (bRet && (pff->fl & (FF_SPACE_EQUAL_NBSPACE|FF_HYPHEN_EQUAL_SFTHYPHEN)))
|
|
{
|
|
if ((*pwc == NBSPACE) && (pff->fl & FF_SPACE_EQUAL_NBSPACE))
|
|
{
|
|
*pwc = SPACE;
|
|
}
|
|
|
|
if ((*pwc == SFTHYPHEN) && (pff->fl & FF_HYPHEN_EQUAL_SFTHYPHEN))
|
|
{
|
|
*pwc = HYPHEN;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* cQueryKerningPairs *
|
|
* *
|
|
* Low level routine that pokes around inside the truetype font file *
|
|
* an gets the kerning pair data. *
|
|
* *
|
|
* Returns: *
|
|
* *
|
|
* If pkp is NULL then return the number of kerning pairs in *
|
|
* the table If pkp is not NULL then return the number of *
|
|
* kerning pairs copied to the buffer. In case of error, *
|
|
* the return value is FD_ERROR. *
|
|
* *
|
|
* Called by: *
|
|
* *
|
|
* ttfdQueryFaceAttr *
|
|
* *
|
|
* History: *
|
|
* Mon 17-Feb-1992 15:39:21 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
ULONG cQueryKerningPairs(FONTFILE *pff, ULONG cPairsInBuffer, FD_KERNINGPAIR *pkp)
|
|
{
|
|
FD_KERNINGPAIR *pkpTooFar;
|
|
ULONG cTables, cPairsInTable, cPairsRet;
|
|
BYTE *pj =
|
|
pff->tp.ateOpt[IT_OPT_KERN].dp ?
|
|
((BYTE *)pff->pvView + pff->tp.ateOpt[IT_OPT_KERN].dp):
|
|
NULL ;
|
|
|
|
if (pj == (BYTE*) NULL)
|
|
{
|
|
return(0);
|
|
}
|
|
cTables = BE_UINT16(pj+KERN_OFFSETOF_TABLE_NTABLES);
|
|
pj += KERN_SIZEOF_TABLE_HEADER;
|
|
while (cTables)
|
|
{
|
|
//
|
|
// if the subtable is of format KERN_WINDOWS_FORMAT then we can use it
|
|
//
|
|
if ((*(pj+KERN_OFFSETOF_SUBTABLE_FORMAT)) == KERN_WINDOWS_FORMAT)
|
|
{
|
|
break;
|
|
}
|
|
pj += BE_UINT16(pj+KERN_OFFSETOF_SUBTABLE_LENGTH);
|
|
cTables -= 1;
|
|
}
|
|
|
|
//
|
|
// If you have gone through all the tables and haven't
|
|
// found one of the format we like ... KERN_WINDOWS_FORMAT,
|
|
// then return no kerning info.
|
|
//
|
|
if (cTables == 0)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
cPairsInTable = BE_UINT16(pj+KERN_OFFSETOF_SUBTABLE_NPAIRS);
|
|
|
|
if (pkp == (FD_KERNINGPAIR*) NULL)
|
|
{
|
|
//
|
|
// If the pointer to the buffer was null, then the caller
|
|
// is asking for the number of pairs in the table. In this
|
|
// case the size of the buffer must be zero. This assures
|
|
// consistency
|
|
//
|
|
return (cPairsInBuffer ? FD_ERROR : cPairsInTable);
|
|
}
|
|
|
|
cPairsRet = min(cPairsInTable,cPairsInBuffer);
|
|
|
|
pj += KERN_SIZEOF_SUBTABLE_HEADER;
|
|
pkpTooFar = pkp + cPairsRet;
|
|
|
|
while (pkp < pkpTooFar)
|
|
{
|
|
// the routines that convert tt glyph index into a WCHAR only can fail
|
|
// if there is a bug in the tt font file. but we check for this anyway
|
|
|
|
if (!bIndexToWcharKern(
|
|
pff,
|
|
&pkp->wcFirst ,
|
|
(uint16)BE_UINT16(pj+KERN_OFFSETOF_ENTRY_LEFT)
|
|
)
|
|
||
|
|
!bIndexToWcharKern(
|
|
pff,
|
|
&pkp->wcSecond,
|
|
(uint16)BE_UINT16(pj+KERN_OFFSETOF_ENTRY_RIGHT)
|
|
)
|
|
)
|
|
{
|
|
WARNING("TTFD!_bIndexToWchar failed\n");
|
|
return (FD_ERROR);
|
|
}
|
|
|
|
pkp->fwdKern = (FWORD)BE_UINT16(pj+KERN_OFFSETOF_ENTRY_VALUE);
|
|
|
|
// update pointers
|
|
|
|
pkp += 1;
|
|
pj += KERN_SIZEOF_ENTRY;
|
|
}
|
|
|
|
return (cPairsRet);
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* pvHandleKerningPairs *
|
|
* *
|
|
* This routine sets up a DYNAMIC data structure to hold the kerning pair *
|
|
* data and then calls cQueryKerning pairs to fill it up. It also points *
|
|
* *pid to the dynamic data structure. *
|
|
* *
|
|
* Returns: *
|
|
* *
|
|
* If succesful this returns a pointer to the kerning pair data. If not *
|
|
* it returns NULL. *
|
|
* *
|
|
* Called by: *
|
|
* *
|
|
* ttfdQueryFontTree *
|
|
* *
|
|
* History: *
|
|
* Tue 1-Mar-1994 10:39:21 by Gerrit van Wingerden [gerritv] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
VOID *pvHandleKerningPairs(HFF hff, ULONG *pid)
|
|
{
|
|
DYNAMICDATA *pdd;
|
|
|
|
// set *pid to NULL right now that way if we except the exception handler
|
|
// in the calling routine will know not to deallocate any memory
|
|
|
|
*pid = (ULONG) NULL;
|
|
|
|
|
|
// ttfdFree must deal with the memory allocated for kerning pairs.
|
|
// We will pass a pointer to the DYNAMICDATA structure as the id.
|
|
|
|
ASSERTDD (
|
|
sizeof(ULONG) == sizeof(DYNAMICDATA *),
|
|
"gdisrv!ttfdQueryFontTree(): "
|
|
"BIG TROUBLE--pointers are not ULONG size\n"
|
|
);
|
|
|
|
//
|
|
// Does the kerning pair array already exist?
|
|
//
|
|
if ( PFF(hff)->pkp == (FD_KERNINGPAIR *) NULL )
|
|
{
|
|
ULONG cKernPairs; // number of kerning pairs in font
|
|
FD_KERNINGPAIR *pkpEnd;
|
|
|
|
// see if the file is mapped already, if not we will have to
|
|
// map it in temporarily:
|
|
|
|
if (PFF(hff)->cRef == 0)
|
|
{
|
|
//
|
|
// have to remap the file.
|
|
//
|
|
|
|
if (!EngMapFontFile(PFF(hff)->iFile, (PULONG*)&PFF(hff)->pvView,&PFF(hff)->cjView ))
|
|
{
|
|
RETURN("pvHandleKerningPairs, bMapFileUNICODE failed\n",NULL);
|
|
}
|
|
}
|
|
|
|
// Construct the kerning pairs array.
|
|
// Determine number of kerning pairs in the font.
|
|
|
|
if ( (cKernPairs = cQueryKerningPairs(PFF(hff), 0, (FD_KERNINGPAIR *) NULL))
|
|
== FD_ERROR )
|
|
{
|
|
if (PFF(hff)->cRef == 0)
|
|
{
|
|
EngUnmapFontFile(PFF(hff)->iFile);
|
|
}
|
|
return ((PVOID) NULL);
|
|
}
|
|
|
|
// make sure to mark the situation where SPACE and NBSPACE map to the same
|
|
// glyph and also when HYPHEN and SFTHYPHEN map to the same glyph.
|
|
|
|
if (cKernPairs &&
|
|
(PFF(hff)->ui16PlatformID == BE_PLAT_ID_MS) &&
|
|
(PFF(hff)->ui16SpecificID == BE_SPEC_ID_UGL) )
|
|
{
|
|
uint8 *pCmap = (BYTE *)PFF(hff)->pvView +
|
|
PFF(hff)->dpMappingTable +
|
|
sizeof(sfnt_mappingTable);
|
|
|
|
if (PFF(hff)->pComputeIndexProc(pCmap, SPACE, NULL) ==
|
|
PFF(hff)->pComputeIndexProc(pCmap, NBSPACE, NULL))
|
|
{
|
|
PFF(hff)->fl |= FF_SPACE_EQUAL_NBSPACE;
|
|
}
|
|
|
|
if (PFF(hff)->pComputeIndexProc(pCmap, HYPHEN, NULL) ==
|
|
PFF(hff)->pComputeIndexProc(pCmap, SFTHYPHEN, NULL))
|
|
{
|
|
PFF(hff)->fl |= FF_HYPHEN_EQUAL_SFTHYPHEN;
|
|
}
|
|
}
|
|
|
|
// Allocate memory for the kerning pair array. Leave room to terminate
|
|
// array with a zeroed FD_KERNINGPAIR structure. Also, make room at
|
|
// the beginning of the buffer for the DYNAMICDATA structure.
|
|
//
|
|
// Buffer:
|
|
//
|
|
// __________________________________________________________
|
|
// | | | |
|
|
// | DYNAMICDATA | FD_KERNINPAIR array ... | Terminator |
|
|
// |_________________|_________________________|____________|
|
|
//
|
|
|
|
pdd =
|
|
(DYNAMICDATA *)
|
|
PV_ALLOC((cKernPairs + 1) * sizeof(FD_KERNINGPAIR) + sizeof(DYNAMICDATA));
|
|
if (pdd == (DYNAMICDATA *) NULL)
|
|
{
|
|
if (PFF(hff)->cRef == 0)
|
|
{
|
|
EngUnmapFontFile(PFF(hff)->iFile);
|
|
}
|
|
return ((PVOID) NULL);
|
|
}
|
|
|
|
// Adjust kerning pair array pointer to point at the actual array.
|
|
|
|
PFF(hff)->pkp = (FD_KERNINGPAIR *) (pdd + 1);
|
|
|
|
// record to which font this data refers to:
|
|
|
|
pdd->pff = PFF(hff); // important for consistency checking
|
|
|
|
// set the data type
|
|
|
|
pdd->ulDataType = ID_KERNPAIR;
|
|
|
|
// set this here so that if we except the exception handler will know to
|
|
// deallocate the data just allocated.
|
|
|
|
*pid = (ULONG) pdd;
|
|
|
|
// Fill in the array.
|
|
|
|
if ( (cKernPairs = cQueryKerningPairs(PFF(hff), cKernPairs, PFF(hff)->pkp))
|
|
== FD_ERROR )
|
|
{
|
|
// Free kerning pair array.
|
|
|
|
V_FREE(pdd);
|
|
PFF(hff)->pkp = (FD_KERNINGPAIR *) NULL;
|
|
if (PFF(hff)->cRef == 0)
|
|
{
|
|
EngUnmapFontFile(PFF(hff)->iFile);
|
|
}
|
|
return ((PVOID) NULL);
|
|
}
|
|
|
|
// Terminate the array. (Terminating entry defined as an
|
|
// FD_KERNINGPAIR with all fields set to zero).
|
|
|
|
pkpEnd = PFF(hff)->pkp + cKernPairs; // point to end of array
|
|
pkpEnd->wcFirst = 0;
|
|
pkpEnd->wcSecond = 0;
|
|
pkpEnd->fwdKern = 0;
|
|
|
|
if (PFF(hff)->cRef == 0)
|
|
{
|
|
EngUnmapFontFile(PFF(hff)->iFile);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pid = (ULONG) (((DYNAMICDATA*) PFF(hff)->pkp) - 1);
|
|
}
|
|
|
|
//
|
|
// Return pointer to the kerning pair array.
|
|
//
|
|
return ((PVOID) PFF(hff)->pkp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ttfdQueryFontTree
|
|
*
|
|
* This function returns pointers to per-face information.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* dhpdev Not used.
|
|
*
|
|
* hff Handle to a font file.
|
|
*
|
|
* iFace Index of a face in the font file.
|
|
*
|
|
* iMode This is a 32-bit number that must be one of the following
|
|
* values:
|
|
*
|
|
* Allowed ulMode values:
|
|
* ----------------------
|
|
*
|
|
* QFT_LIGATURES -- returns a pointer to the ligature map.
|
|
*
|
|
* QFT_KERNPAIRS -- return a pointer to the kerning pair table.
|
|
*
|
|
* QFT_GLYPHSET -- return a pointer to the WC->HGLYPH mapping table.
|
|
*
|
|
* pid Used to identify data that ttfdFree will know how to deal
|
|
* with it.
|
|
*
|
|
* Returns:
|
|
* Returns a pointer to the requested data. This data will not change
|
|
* until BmfdFree is called on the pointer. Caller must not attempt to
|
|
* modify the data. NULL is returned if an error occurs.
|
|
*
|
|
* History:
|
|
* 21-Oct-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
PVOID ttfdQueryFontTree (
|
|
DHPDEV dhpdev,
|
|
HFF hff,
|
|
ULONG iFace,
|
|
ULONG iMode,
|
|
ULONG *pid
|
|
)
|
|
{
|
|
#ifdef FE_SB
|
|
VOID vMarkFontGone(TTC_FONTFILE*, DWORD);
|
|
#else
|
|
VOID vMarkFontGone(FONTFILE*, DWORD);
|
|
#endif
|
|
|
|
#ifdef FE_SB
|
|
HFF hffTTC = hff;
|
|
|
|
ASSERTDD(hff,"ttfdQueryFontTree(): invalid iFile (hff)\n");
|
|
|
|
ASSERTDD(
|
|
iFace <= PTTC(hff)->ulNumEntry,
|
|
"gdisrv!ttfdQueryFontTree(): iFace out of range\n"
|
|
);
|
|
//
|
|
// get real hff from ttc array.
|
|
//
|
|
hff = PTTC(hffTTC)->ahffEntry[iFace-1].hff;
|
|
iFace = PTTC(hffTTC)->ahffEntry[iFace-1].iFace;
|
|
#endif
|
|
|
|
dhpdev;
|
|
|
|
ASSERTDD(hff,"ttfdQueryFontTree(): invalid iFile (hff)\n");
|
|
ASSERTDD(iFace <= PFF(hff)->ulNumFaces ,
|
|
"ttfdQueryFaces(): iFace out of range\n");
|
|
|
|
//
|
|
// Which mode?
|
|
//
|
|
switch (iMode)
|
|
{
|
|
case QFT_LIGATURES:
|
|
//
|
|
// !!! Ligatures not currently supported.
|
|
//
|
|
// There are no ligatures currently not supported,
|
|
// therefore we return NULL.
|
|
//
|
|
*pid = (ULONG) NULL;
|
|
|
|
return ((PVOID) NULL);
|
|
|
|
case QFT_GLYPHSET:
|
|
//
|
|
// ttfdFree can ignore this because the glyph set will be deleted with
|
|
// the FONTFILE structure.
|
|
//
|
|
*pid = (ULONG) NULL;
|
|
|
|
return ((PVOID) PFF(hff)->pgset);
|
|
|
|
case QFT_KERNPAIRS:
|
|
|
|
try
|
|
{
|
|
// make sure the file is still around
|
|
#ifdef FE_SB
|
|
if ((PTTC(hffTTC))->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
{
|
|
WARNING("ttfd, pvHandleKerningPairs(): file is gone\n");
|
|
return NULL;
|
|
}
|
|
#else
|
|
if ((PFF(hff))->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
{
|
|
WARNING("ttfd, pvHandleKerningPairs(): file is gone\n");
|
|
return NULL;
|
|
}
|
|
#endif
|
|
return pvHandleKerningPairs (hff, pid);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("TTFD!_ exception in ttfdQueryFontTree\n");
|
|
|
|
#ifdef FE_SB
|
|
vMarkFontGone((TTC_FONTFILE *)PTTC(hffTTC), GetExceptionCode());
|
|
#else
|
|
vMarkFontGone((FONTFILE *)PFF(hff), GetExceptionCode());
|
|
#endif // FE_SB
|
|
|
|
// possibly free memory that was allocated and reset the pkp pointer
|
|
// to NULL
|
|
|
|
ttfdFree( NULL, *pid );
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
default:
|
|
|
|
//
|
|
// Should never get here.
|
|
//
|
|
RIP("gdisrv!ttfdQueryFontTree(): unknown iMode\n");
|
|
return ((PVOID) NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bGetGlyphOutline
|
|
*
|
|
* valid outline points are in pfc->gout after this call
|
|
*
|
|
* History:
|
|
* 19-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bGetGlyphOutline (
|
|
FONTCONTEXT *pfc,
|
|
HGLYPH hg,
|
|
ULONG *pig,
|
|
FLONG fl,
|
|
FS_ENTRY *piRet
|
|
)
|
|
{
|
|
// new glyph coming in or the metric has to be recomputed
|
|
// because the contents of the gin,gout strucs have been destroyed
|
|
|
|
vInitGlyphState(&pfc->gstat);
|
|
|
|
ASSERTDD((hg != HGLYPH_INVALID) && ((hg & (HGLYPH)0xFFFF0000) == 0),
|
|
"ttfdQueryGlyphBitmap: hg\n");
|
|
|
|
vCharacterCode(pfc->pff,hg,pfc->pgin);
|
|
|
|
// compute the glyph index from the character code:
|
|
|
|
if ((*piRet = fs_NewGlyph(pfc->pgin, pfc->pgout)) != NO_ERR)
|
|
{
|
|
V_FSERROR(*piRet);
|
|
RET_FALSE("TTFD!_bGetGlyphOutline, fs_NewGlyph\n");
|
|
}
|
|
|
|
// return the glyph index corresponding to this hglyph:
|
|
|
|
*pig = pfc->pgout->glyphIndex;
|
|
|
|
// these two field must be initialized before calling fs_ContourGridFit
|
|
|
|
pfc->pgin->param.gridfit.styleFunc = 0; //!!! do some casts here
|
|
pfc->pgin->param.gridfit.traceFunc = (FntTraceFunc)NULL;
|
|
|
|
// if bitmap is found for this glyph and if we are ultimately interested
|
|
// in bitmaps only and do not care about intermedieate outline, then set the
|
|
// bit in the "in" structure to hint the rasterizer that grid fitting
|
|
// will not be necessary:
|
|
|
|
if (pfc->pgout->usBitmapFound && (fl & FL_SKIP_IF_BITMAP))
|
|
pfc->pgin->param.gridfit.bSkipIfBitmap = 1;
|
|
else
|
|
pfc->pgin->param.gridfit.bSkipIfBitmap = 0; // must do hinting
|
|
|
|
// fs_ContourGridFit hints the glyph (executes the instructions for the glyph)
|
|
// and converts the glyph data from the tt file into an outline for this glyph
|
|
|
|
if ((*piRet = fs_ContourGridFit(pfc->pgin, pfc->pgout)) != NO_ERR)
|
|
{
|
|
V_FSERROR(*piRet);
|
|
RET_FALSE("TTFD!_bGetGlyphOutline, fs_Contour(No)GridFit\n");
|
|
}
|
|
|
|
#ifdef DEBUG_OUTLINE
|
|
vDbgGridFit(pfc->pgout);
|
|
#endif // DEBUG_OUTLINE
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* b_fxA_and_fxAB_are_Ok:
|
|
* This function checks if the fxA and fxAB
|
|
* that are computed by linear scaling are big enough in the following sense:
|
|
*
|
|
* The bounding box of the background parallelogram for the glyph which
|
|
* is spanned by ptfxLeft, Right, Top, Bottom (as defined by the code below)
|
|
* must fully contain the glyph bitmap.
|
|
*
|
|
* Warnings: slow function, not executed often
|
|
*
|
|
* History:
|
|
* 13-Mar-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#if defined(_X86_)
|
|
|
|
VOID ftoef_c(FLOAT, EFLOAT *);
|
|
#define vEToEF(e, pef) ftoef_c((e), (pef))
|
|
|
|
#else // not X86
|
|
|
|
#define vEToEF(e, pef) ( *(pef) = (e) )
|
|
|
|
#endif
|
|
|
|
// lExL is same as (LONG)(e*l), but do not want to use floating point
|
|
// math on pentium machines
|
|
|
|
LONG lExL(FLOAT e, LONG l)
|
|
{
|
|
EFLOAT ef;
|
|
vEToEF(e, &ef);
|
|
return lCvt(ef, l);
|
|
}
|
|
|
|
BOOL b_fxA_and_fxAB_are_Ok(
|
|
FONTCONTEXT *pfc,
|
|
GLYPHDATA *pgldt,
|
|
POINTL *pptlOrigin,
|
|
LONG cx,
|
|
LONG cy
|
|
)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
POINTFIX ptfxLeft,ptfxRight, aptfx[4];
|
|
LONG xLeft, yTop, xRight, yBottom;
|
|
INT i;
|
|
|
|
ptfxLeft.x = lExL(pfc->pteUnitBase.x, pgldt->fxA);
|
|
ptfxLeft.y = lExL(pfc->pteUnitBase.y, pgldt->fxA);
|
|
ptfxRight.x = lExL(pfc->pteUnitBase.x, pgldt->fxAB);
|
|
ptfxRight.y = lExL(pfc->pteUnitBase.y, pgldt->fxAB);
|
|
|
|
// note that here we do not use fxInkTop and fxInkBottom
|
|
// for the individual glyph, instead we use global asc and desc,
|
|
// in parallel with G2 and G3 layout routines in the engine.
|
|
// We are adjusting fxA and fxAB so that the code for G2 and G3
|
|
// cases together with bOpaqueArea computes the bounding box of the text
|
|
|
|
aptfx[0].x = ptfxLeft.x + pfc->ptfxTop.x;
|
|
aptfx[0].y = ptfxLeft.y + pfc->ptfxTop.y;
|
|
aptfx[1].x = ptfxRight.x + pfc->ptfxTop.x;
|
|
aptfx[1].y = ptfxRight.y + pfc->ptfxTop.y;
|
|
aptfx[2].x = ptfxRight.x + pfc->ptfxBottom.x;
|
|
aptfx[2].y = ptfxRight.y + pfc->ptfxBottom.y;
|
|
aptfx[3].x = ptfxLeft.x + pfc->ptfxBottom.x;
|
|
aptfx[3].y = ptfxLeft.y + pfc->ptfxBottom.y;
|
|
|
|
// bound the paralelogram
|
|
|
|
xLeft = xRight = aptfx[0].x;
|
|
yTop = yBottom = aptfx[0].y;
|
|
|
|
for (i = 1; i < 4; i++)
|
|
{
|
|
if (aptfx[i].x < xLeft)
|
|
xLeft = aptfx[i].x;
|
|
if (aptfx[i].x > xRight)
|
|
xRight = aptfx[i].x;
|
|
if (aptfx[i].y < yTop)
|
|
yTop = aptfx[i].y;
|
|
if (aptfx[i].y > yBottom)
|
|
yBottom = aptfx[i].y;
|
|
}
|
|
|
|
// Here we are following the prescription of the bOpaqueArea in textobj.cxx.
|
|
// We add a fudge factor of 1, 1/2 of the fuge factor in bOpaqueArea,
|
|
// and than check if glyph fits in the bounding rectangle.
|
|
// We add fudge factor in order to execute this function
|
|
// as few times as possible, but for glyph to still fit in the background
|
|
// rectangle computed by bOpaqueArea
|
|
|
|
#define FUDGE 1
|
|
|
|
xLeft = FXTOLFLOOR(xLeft) - FUDGE;
|
|
yTop = FXTOLFLOOR(yTop) - FUDGE;
|
|
xRight = FXTOLCEILING(xRight) + FUDGE;
|
|
yBottom = FXTOLCEILING(yBottom) + FUDGE;
|
|
|
|
// now check if glyph bitmap fits in the bounding rectangle, if not
|
|
// we need to augment fxA and fxAB and try again.
|
|
|
|
if
|
|
(
|
|
(xLeft > pptlOrigin->x) ||
|
|
(xRight < (pptlOrigin->x + cx)) ||
|
|
(yTop > pptlOrigin->y) ||
|
|
(yBottom < (pptlOrigin->y + cy))
|
|
)
|
|
{
|
|
// this code path is executed very rarely, that is only
|
|
// in case of really wierd transforms. Yet, because such
|
|
// transforms exist and used to crash machines, we needed to add
|
|
// this routine. That is, in most cases this routine will be called
|
|
// only once in the loop to confirm that fxA and fxAB as computed
|
|
// by linear scaling are fine. When they are not fine the routine
|
|
// will be called again with new augmented values of fxA and fxAB.
|
|
|
|
#ifdef DEBUG_FXA_FXAB
|
|
DbgPrint("need to fix rcfxInkBox: %ld, %ld, %ld, %ld\n",
|
|
xLeft,
|
|
yTop,
|
|
xRight,
|
|
yBottom);
|
|
DbgPrint("glyph cell : %ld, %ld, %ld, %ld\n\n",
|
|
pptlOrigin->x,
|
|
pptlOrigin->y,
|
|
pptlOrigin->x + cx,
|
|
pptlOrigin->y + cy);
|
|
#endif
|
|
bRet = FALSE; // not big enough.
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bGetGlyphMetrics
|
|
*
|
|
* History:
|
|
* 22-Nov-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bGetGlyphMetrics (
|
|
PFONTCONTEXT pfc,
|
|
HGLYPH hg,
|
|
FLONG fl,
|
|
FS_ENTRY *piRet
|
|
)
|
|
{
|
|
ULONG ig;
|
|
FS_ENTRY i;
|
|
|
|
if (!bGetGlyphOutline(pfc,hg,&ig,fl,piRet))
|
|
{
|
|
V_FSERROR(*piRet);
|
|
RET_FALSE("TTFD!_bGetGlyphMetrics, bGetGlyphOutline failed \n");
|
|
}
|
|
|
|
// get the metric info for this glyph,
|
|
|
|
if (IS_GRAY(pfc))
|
|
{
|
|
pfc->pgin->param.gray.usOverScale = 4;
|
|
pfc->pgin->param.gray.bMatchBBox = FALSE;
|
|
i = fs_FindGraySize(pfc->pgin, pfc->pgout);
|
|
}
|
|
else
|
|
{
|
|
i = fs_FindBitMapSize(pfc->pgin, pfc->pgout);
|
|
}
|
|
if (i != NO_ERR)
|
|
{
|
|
V_FSERROR(*piRet);
|
|
RET_FALSE("TTFD!_bGetGlyphMetrics, fs_FindBitMapSize \n");
|
|
}
|
|
|
|
|
|
// now that everything is computed sucessfully, we can update
|
|
// glyphstate (hg data stored in pj3) and return
|
|
|
|
pfc->gstat.hgLast = hg;
|
|
pfc->gstat.igLast = ig;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vFillGLYPHDATA
|
|
*
|
|
* History:
|
|
* 22-Nov-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vFillGLYPHDATA(
|
|
HGLYPH hg,
|
|
ULONG ig,
|
|
FONTCONTEXT *pfc,
|
|
fs_GlyphInfoType *pgout, // outputed from fsFind bitmap size
|
|
GLYPHDATA *pgldt, // OUT
|
|
GMC *pgmc, // optional, not used if doing outline only
|
|
POINTL *pptlOrigin,
|
|
BOOL bMinBmp
|
|
)
|
|
{
|
|
extern VOID vGetNotionalGlyphMetrics(FONTCONTEXT*, ULONG, NOT_GM*);
|
|
extern VOID vEmbolden_GLYPHDATA(FONTCONTEXT*, GLYPHDATA*);
|
|
|
|
BOOL bOutOfBounds = FALSE;
|
|
|
|
vectorType * pvtD; // 16.16 point
|
|
LONG lA,lAB; // *pvtA rounded to the closest integer value
|
|
|
|
ULONG cx = (ULONG)(pgout->bitMapInfo.bounds.right - pgout->bitMapInfo.bounds.left);
|
|
ULONG cy = (ULONG)(pgout->bitMapInfo.bounds.bottom - pgout->bitMapInfo.bounds.top);
|
|
|
|
pgldt->gdf.pgb = NULL; // may get changed by the calling routine if bits requested too
|
|
pgldt->hg = hg;
|
|
|
|
// fs_FindBitMapSize returned the the following information in gout:
|
|
//
|
|
// 1) gout.metricInfo // left side bearing and advance width
|
|
//
|
|
// 2) gout.bitMapInfo // black box info
|
|
//
|
|
// 3) memory requirement for the bitmap,
|
|
// returned in gout.memorySizes[5] and gout.memorySizes[6]
|
|
//
|
|
// Notice that fs_FindBitMapSize is exceptional scaler interface routine
|
|
// in that it returns info in several rather than in a single
|
|
// substructures of gout
|
|
|
|
// Check if hinting produced totally unreasonable result:
|
|
|
|
bOutOfBounds = ( (pgout->bitMapInfo.bounds.left > pfc->xMax) ||
|
|
(pgout->bitMapInfo.bounds.right < pfc->xMin) ||
|
|
(-pgout->bitMapInfo.bounds.bottom > pfc->yMax) ||
|
|
(-pgout->bitMapInfo.bounds.top < pfc->yMin) );
|
|
|
|
#if DBG
|
|
if (bOutOfBounds)
|
|
TtfdDbgPrint("TTFD! Glyph out of bounds: ppem = %ld, gi = %ld\n",
|
|
pfc->lEmHtDev, hg);
|
|
#endif
|
|
|
|
out_of_bounds:
|
|
|
|
if ((cx == 0) || (cy == 0) || bOutOfBounds)
|
|
{
|
|
// will be replaced by a a fake 1x1 bitmap
|
|
|
|
pgldt->rclInk.left = pfc->ptlSingularOrigin.x;
|
|
pgldt->rclInk.top = pfc->ptlSingularOrigin.y;
|
|
pgldt->rclInk.right = pgldt->rclInk.left + 1; // ink white for this glyph!
|
|
pgldt->rclInk.bottom = pgldt->rclInk.top + 1; // ink white for this glyph!
|
|
|
|
// more of hackorama forced upon me by DaveC so that suppossedly
|
|
// video drivers do not have to do a check on cx and cy.
|
|
// By setting right = bottom = 1 for blank glyph we are slightly
|
|
// incompatible with win31 in that they would return zero cx and cy
|
|
// when calling GGO, as well as B space equal to 0 in GetCharABCWidths.
|
|
// NT will return 1 for all of these quantities. I think we want to fix
|
|
// our drivers for Cairo to be able to accept cx = cy = 0.
|
|
|
|
if (pgmc != (PGMC)NULL)
|
|
{
|
|
pgmc->cxCor = 0; // forces blank glyph case when filling the bits
|
|
pgmc->cyCor = 0; // forces blank glyph case when filling the bits
|
|
}
|
|
}
|
|
else // non empty bitmap
|
|
{
|
|
lA = F16_16TOLROUND(pgout->metricInfo.devLeftSideBearing.x); // this is ok, always succeeds:
|
|
lAB = lA + (LONG)cx;
|
|
|
|
// black box info, we have to transform y coords to ifi specifications
|
|
|
|
pgldt->rclInk.bottom = - pgout->bitMapInfo.bounds.top;
|
|
pgldt->rclInk.top = - pgout->bitMapInfo.bounds.bottom;
|
|
|
|
if (pgmc != (PGMC)NULL)
|
|
{
|
|
LONG dyTop, dyBottom, dxLeft, dxRight;
|
|
LONG dxError, dyError;
|
|
|
|
#define MAXERROR 10
|
|
|
|
dyTop = (pgldt->rclInk.top < pfc->yMin) ?
|
|
(pfc->yMin - pgldt->rclInk.top) :
|
|
0;
|
|
|
|
dyBottom = (pgldt->rclInk.bottom > pfc->yMax) ?
|
|
(pgldt->rclInk.bottom - pfc->yMax) :
|
|
0;
|
|
|
|
if (dyTop || dyBottom)
|
|
{
|
|
// will have to chop off a few scans, infrequent
|
|
|
|
#if DBG
|
|
if ((LONG)cy < (dyTop + dyBottom))
|
|
{
|
|
TtfdDbgPrint("TTFD!_dcy: ppem = %ld, gi = %ld, cy: %ld, dyTop: %ld, dyBottom: %ld\n",
|
|
pfc->lEmHtDev, hg, cy, dyTop,dyBottom);
|
|
EngDebugBreak();
|
|
}
|
|
#endif
|
|
|
|
cy -= (dyTop + dyBottom);
|
|
pgldt->rclInk.top += dyTop;
|
|
pgldt->rclInk.bottom -= dyBottom;
|
|
|
|
dyError = max(pfc->lEmHtDev, MAXERROR);
|
|
if ((dyTop > dyError) || (dyBottom > dyError))
|
|
{
|
|
// something is really bogus, let us bail out:
|
|
|
|
bOutOfBounds = TRUE;
|
|
goto out_of_bounds;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
|
|
// this piece of debug code is put here to detect buggy glyphs
|
|
// with negative A or C spaces in console fonts [bodind]
|
|
|
|
if (pfc->lD)
|
|
{
|
|
LONG lAW;
|
|
|
|
lAW = pfc->lD;
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
lAW -= 1;
|
|
|
|
if (lA != pgout->bitMapInfo.bounds.left)
|
|
TtfdDbgPrint("ttfd: lA = %ld, bounds.left = %ld\n",
|
|
lA, pgout->bitMapInfo.bounds.left);
|
|
|
|
if ((lA < 0) || (lAB > lAW))
|
|
{
|
|
TtfdDbgPrint(
|
|
"ttfd! sz = %ld ppem, gi = %ld is buggy:"
|
|
" A+B = %ld, A = %ld, C = %ld, AW = %ld\n",
|
|
pfc->lEmHtDev, hg, lAB, lA, lAW - lAB,lAW
|
|
);
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
// let us see how good is scaling with appropriate rounding
|
|
// to determine xMin and xMax:
|
|
|
|
dxLeft = dxRight = 0;
|
|
if (lA < pfc->xMin)
|
|
dxLeft = pfc->xMin - lA;
|
|
if (lAB > pfc->xMax)
|
|
dxRight = lAB - pfc->xMax;
|
|
|
|
if (dxLeft || dxRight)
|
|
{
|
|
#if DBG
|
|
TtfdDbgPrint("TTFD! ppem = %ld"
|
|
", gi = %ld, dxLeft: %ld, dxRight: %ld\n"
|
|
, pfc->lEmHtDev, hg, dxLeft,dxRight
|
|
);
|
|
if ((LONG)cx < (dxLeft + dxRight))
|
|
{
|
|
TtfdDbgPrint(
|
|
"TTFD!_dcx: ppem = %ld, gi = %ld, cx: %ld"
|
|
", dxLeft: %ld, dxRight: %ld\n",
|
|
pfc->lEmHtDev, hg, cx, dxLeft, dxRight);
|
|
EngDebugBreak();
|
|
}
|
|
#endif // DBG
|
|
|
|
cx -= (dxLeft + dxRight);
|
|
lA += dxLeft;
|
|
lAB -= dxRight;
|
|
|
|
dxError = (LONG)max((pfc->cxMax/4),MAXERROR);
|
|
if ((dxLeft > dxError) || (dxRight > dxError))
|
|
{
|
|
// something is really bogus, let us bail out:
|
|
|
|
bOutOfBounds = TRUE;
|
|
goto out_of_bounds;
|
|
}
|
|
}
|
|
ASSERTDD(cx <= pfc->cxMax, "cx > cxMax\n");
|
|
|
|
pgmc->dyTop = (ULONG)dyTop ;
|
|
pgmc->dyBottom = (ULONG)dyBottom;
|
|
pgmc->dxLeft = (ULONG)dxLeft ;
|
|
pgmc->dxRight = (ULONG)dxRight ;
|
|
pgmc->cxCor = cx;
|
|
pgmc->cyCor = cy;
|
|
|
|
// only corrected values have to obey this condition:
|
|
|
|
ASSERTDD(
|
|
pfc->flFontType & FO_CHOSE_DEPTH,"Depth Not Chosen Yet!\n");
|
|
ASSERTDD(
|
|
CJGD(pgmc->cxCor,pgmc->cyCor,pfc) <= pfc->cjGlyphMax,
|
|
"ttfdQueryGlyphBitmap, cjGlyphMax \n"
|
|
);
|
|
}
|
|
|
|
// x coords do not transform, just shift them
|
|
|
|
pgldt->rclInk.left = lA;
|
|
pgldt->rclInk.right = lAB;
|
|
|
|
} // end of the non empty bitmap clause
|
|
|
|
// go on to compute the positioning info:
|
|
|
|
if (pfc->flXform & XFORM_HORIZ) // scaling only
|
|
{
|
|
FIX fxTmp;
|
|
|
|
// We shall lie to the engine and store integer
|
|
// pre and post bearings and char inc vectors because
|
|
// win31 also rounds, but we should not round for nondiag xforms
|
|
|
|
pvtD = & pgout->metricInfo.devAdvanceWidth;
|
|
|
|
// bGetFastAdvanceWidth returns the same aw that would get
|
|
// computed by bQueryAdvanceWidths and propagated to an api
|
|
// level through GetTextExtent and GetCharWidths. We have to
|
|
// fill in the same aw for consistency reasons.
|
|
// This also has to be done for win31 compatibility.
|
|
|
|
if (pfc->lD)
|
|
{
|
|
pgldt->fxD = LTOFX(pfc->lD);
|
|
}
|
|
else
|
|
{
|
|
if (!bGetFastAdvanceWidth(pfc,ig, &pgldt->fxD))
|
|
{
|
|
// not possible to get the fast value, use the "slow" value
|
|
// supplied by the rasterizer.
|
|
|
|
pgldt->fxD = F16_16TOLROUND(pvtD->x);
|
|
pgldt->fxD = LTOFX(pgldt->fxD);
|
|
}
|
|
#ifdef DEBUG_AW
|
|
|
|
// this should alsmost never happen, one example when it does
|
|
// is Lucida Sans Unicode at 14 pt, glyph 'a', try from winword
|
|
// the possible source of discrepancy is a bug in hdmx or ltsh
|
|
// tables or a loss of precission in some of mult. math routines
|
|
|
|
else
|
|
{
|
|
fxTmp = F16_16TOLROUND(pvtD->x);
|
|
fxTmp = LTOFX(fxTmp);
|
|
if (fxTmp != pgldt->fxD)
|
|
{
|
|
// print out a warning
|
|
|
|
fxTmp -= pgldt->fxD;
|
|
if (fxTmp < 0)
|
|
fxTmp = - fxTmp;
|
|
|
|
if (fxTmp > 16)
|
|
{
|
|
TtfdDbgPrint("ttfd! fxDSlow = 0x%lx\n", pgldt->fxD);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // DEBUG_AW
|
|
|
|
}
|
|
pgldt->ptqD.x.HighPart = (LONG)pgldt->fxD;
|
|
pgldt->ptqD.x.LowPart = 0;
|
|
|
|
if (pfc->mx.transform[0][0] < 0)
|
|
pgldt->fxD = - pgldt->fxD; // this is an absolute value
|
|
|
|
// make CharInc.y zero even if the rasterizer messed up
|
|
|
|
pgldt->ptqD.y.HighPart = 0;
|
|
pgldt->ptqD.y.LowPart = 0;
|
|
|
|
#if DBG
|
|
// if (pvtD->y) {TtfdDbgPrint("TTFD!_ pvtD->y = 0x%lx\n", pvtD->y);}
|
|
#endif
|
|
|
|
pgldt->fxA = LTOFX(pgldt->rclInk.left);
|
|
pgldt->fxAB = LTOFX(pgldt->rclInk.right);
|
|
|
|
// - is used here since ascender points in the negative y direction
|
|
|
|
pgldt->fxInkTop = -LTOFX(pgldt->rclInk.top);
|
|
pgldt->fxInkBottom = -LTOFX(pgldt->rclInk.bottom);
|
|
|
|
if (pfc->mx.transform[0][0] < 0)
|
|
{
|
|
fxTmp = pgldt->fxA;
|
|
pgldt->fxA = -pgldt->fxAB;
|
|
pgldt->fxAB = -fxTmp;
|
|
}
|
|
|
|
if (pfc->mx.transform[1][1] < 0)
|
|
{
|
|
fxTmp = pgldt->fxInkTop;
|
|
pgldt->fxInkTop = -pgldt->fxInkBottom;
|
|
pgldt->fxInkBottom = -fxTmp;
|
|
}
|
|
}
|
|
else // non trivial information
|
|
{
|
|
// here we will just xform the notional space data:
|
|
|
|
NOT_GM ngm; // notional glyph data
|
|
|
|
vGetNotionalGlyphMetrics(pfc,ig,&ngm);
|
|
|
|
// xforms are computed by simple multiplication
|
|
|
|
pgldt->fxD = fxLTimesEf(&pfc->efBase, (LONG)ngm.sD);
|
|
|
|
if (pfc->flXform & XFORM_VERT)
|
|
{
|
|
pgldt->fxD = FXTOLROUND(pgldt->fxD);
|
|
pgldt->fxD = LTOFX(pgldt->fxD);
|
|
|
|
pgldt->ptqD.x.LowPart = 0;
|
|
pgldt->ptqD.x.HighPart = 0;
|
|
pgldt->ptqD.y.LowPart = 0;
|
|
|
|
if (pfc->pteUnitBase.y < 0) // base.y < 0
|
|
{
|
|
pgldt->fxA = -LTOFX(pgldt->rclInk.bottom);
|
|
pgldt->fxAB = -LTOFX(pgldt->rclInk.top);
|
|
pgldt->ptqD.y.HighPart = -(LONG)pgldt->fxD;
|
|
}
|
|
else
|
|
{
|
|
pgldt->fxA = LTOFX(pgldt->rclInk.top);
|
|
pgldt->fxAB = LTOFX(pgldt->rclInk.bottom);
|
|
pgldt->ptqD.y.HighPart = (LONG)pgldt->fxD;
|
|
}
|
|
|
|
if (pfc->pteUnitSide.x < 0) // asc.x < 0
|
|
{
|
|
pgldt->fxInkTop = -LTOFX(pgldt->rclInk.left);
|
|
pgldt->fxInkBottom = -LTOFX(pgldt->rclInk.right);
|
|
}
|
|
else
|
|
{
|
|
pgldt->fxInkTop = LTOFX(pgldt->rclInk.right);
|
|
pgldt->fxInkBottom = LTOFX(pgldt->rclInk.left);
|
|
}
|
|
}
|
|
else // most general case, totally arb. xform.
|
|
{
|
|
POINTL ptlOrigin;
|
|
|
|
vLTimesVtfl((LONG)ngm.sD, &pfc->vtflBase, &pgldt->ptqD);
|
|
|
|
ptlOrigin.x = F16_16TOLROUND(pgout->metricInfo.devLeftSideBearing.x);
|
|
ptlOrigin.y = -F16_16TOLROUND(pgout->metricInfo.devLeftSideBearing.y);
|
|
|
|
if (pptlOrigin)
|
|
*pptlOrigin = ptlOrigin;
|
|
|
|
pgldt->fxA = fxLTimesEf(&pfc->efBase, (LONG)ngm.sA);
|
|
pgldt->fxAB = fxLTimesEf(&pfc->efBase, (LONG)ngm.xMax);
|
|
|
|
pgldt->fxInkTop = - fxLTimesEf(&pfc->efSide, (LONG)ngm.yMin);
|
|
pgldt->fxInkBottom = - fxLTimesEf(&pfc->efSide, (LONG)ngm.yMax);
|
|
|
|
// just to be safe let us round these up and down appropriately
|
|
|
|
#define ROUND_DOWN(X) ((X) & ~0xf)
|
|
#define ROUND_UP(X) (((X) + 15) & ~0xf)
|
|
|
|
pgldt->fxA = ROUND_DOWN(pgldt->fxA);
|
|
pgldt->fxAB = ROUND_UP(pgldt->fxAB);
|
|
|
|
pgldt->fxInkTop = ROUND_UP(pgldt->fxInkTop);
|
|
pgldt->fxInkBottom = ROUND_DOWN(pgldt->fxInkBottom);
|
|
|
|
if (pgmc && pgmc->cxCor && pgmc->cyCor)
|
|
{
|
|
int iCutoff = 0;
|
|
while (!b_fxA_and_fxAB_are_Ok(
|
|
pfc,
|
|
pgldt,
|
|
&ptlOrigin,
|
|
(LONG)pgmc->cxCor,
|
|
(LONG)pgmc->cyCor) && (iCutoff++ < 1000))
|
|
{
|
|
pgldt->fxA -= 16;
|
|
pgldt->fxAB += 16;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
//!!! These comments are crap I do not know why they are here [bodind]
|
|
//
|
|
// Disable this codepath, because Italicalized vertical
|
|
// font fxAB is not eqaul fxD, I just want original
|
|
// (= non rotated) metrics. [hideyukn]
|
|
//
|
|
// fxA and fxAB caluculated above are ones of non rotated glyph.
|
|
// Who knows the real fxA and fxAB of rotated glyph?
|
|
// Truetype font data doesn't contain such information.
|
|
// Replace them with reasonable value. [takaok]
|
|
//
|
|
// if ( pfc->bVertical && pfc->ulControl & VERTICAL_MODE )
|
|
// {
|
|
// pgldt->fxA = LTOFX(0);
|
|
// pgldt->fxAB = pgldt->fxD;
|
|
// }
|
|
//
|
|
|
|
// finally check if the glyphdata will need to get modified because of the
|
|
// emboldening simulation:
|
|
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
vEmbolden_GLYPHDATA(pfc, pgldt);
|
|
|
|
// If the caller requests a minimal bitmap and the bitmap or the
|
|
// corrected bimap has a zero extent in any dimension then
|
|
// the font driver will replace the original bitmap by a
|
|
// phony 1 x 1 blank bitmap. See lGetGlyphBitmap near
|
|
// the code "pgb->sizlBitmap.cx = 1".
|
|
|
|
if ( bMinBmp )
|
|
{
|
|
if ( cx == 0 || pgmc->cxCor == 0 || cy == 0 || pgmc->cyCor == 0)
|
|
{
|
|
pgldt->fxA = 0;
|
|
pgldt->fxAB = 16;
|
|
pgldt->fxInkTop = 0;
|
|
pgldt->fxInkBottom = 16;
|
|
pgldt->rclInk.left = 0;
|
|
pgldt->rclInk.top = 0;
|
|
pgldt->rclInk.right = 16;
|
|
pgldt->rclInk.bottom = 16;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ttfdQueryTrueTypeTable
|
|
*
|
|
* copies cjBytes starting at dpStart from the beginning of the table
|
|
* into the buffer
|
|
*
|
|
* if pjBuf == NULL or cjBuf == 0, the caller is asking how big a buffer
|
|
* is needed to store the info from the offset dpStart to the table
|
|
* specified by ulTag to the end of the table
|
|
*
|
|
* if pjBuf != 0 the caller wants no more than cjBuf bytes from
|
|
* the offset dpStart into the table copied into the
|
|
* buffer.
|
|
*
|
|
* if table is not present or if dpScart >= cjTable 0 is returned
|
|
*
|
|
* tag 0 means that the data has to be retrieved from the offset dpStart
|
|
* from the beginning of the file. The lenght of the whole file
|
|
* is returned if pBuf == nULL
|
|
*
|
|
* History:
|
|
* 09-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#ifdef FE_SB
|
|
PBYTE pjTable(ULONG ulTag, PFONTFILE pff, ULONG *pcjTable);
|
|
#else
|
|
PBYTE pjTable(ULONG ulTag, PVOID pvView, ULONG cjView, ULONG *pcjTable);
|
|
#endif
|
|
|
|
|
|
LONG ttfdQueryTrueTypeTable2 (
|
|
HFF hff,
|
|
ULONG ulFont, // always 1 for version 1.0 of tt
|
|
ULONG ulTag, // tag identifying the tt table
|
|
PTRDIFF dpStart, // offset into the table
|
|
ULONG cjBuf, // size of the buffer to retrieve the table into
|
|
BYTE *pjBuf // ptr to buffer into which to return the data
|
|
)
|
|
{
|
|
PBYTE pjBegin; // ptr to the beginning of the table
|
|
LONG cjTable;
|
|
#ifdef FE_SB
|
|
HFF hffTTC = hff;
|
|
#endif
|
|
|
|
ASSERTDD(hff, "ttfdQueryTrueTypeTable\n");
|
|
|
|
if (dpStart < 0)
|
|
return (FD_ERROR);
|
|
|
|
// if this font file is gone we are not gonna be able to answer any questions
|
|
// about it
|
|
|
|
|
|
#ifdef FE_SB
|
|
if (PTTC(hffTTC)->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
#else
|
|
if (PFF(hff)->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
#endif // FE_SB
|
|
{
|
|
WARNING("ttfd, ttfdQueryTrueTypeTable: file is gone\n");
|
|
return FD_ERROR;
|
|
}
|
|
|
|
#ifdef FE_SB
|
|
ASSERTDD(ulFont <= PTTC(hffTTC)->ulNumEntry,
|
|
"gdisrv!ttfdQueryFaces(): iFace out of range\n"
|
|
);
|
|
|
|
// get real hff from ttc array.
|
|
|
|
hff = PTTC(hffTTC)->ahffEntry[ulFont-1].hff;
|
|
ulFont = PTTC(hffTTC)->ahffEntry[ulFont-1].iFace;
|
|
#endif // FE_SB
|
|
|
|
ASSERTDD(ulFont <= PFF(hff)->ulNumFaces,
|
|
"TTFD!_ttfdQueryTrueTypeTable: ulFont != 1\n");
|
|
|
|
// verify the tag, determine whether this is a required or an optional
|
|
// table:
|
|
|
|
if (ulTag == 0) // requesting the whole file
|
|
{
|
|
pjBegin = (PBYTE)PFF(hff)->pvView;
|
|
cjTable = PFF(hff)->cjView; // cjView == cjFile
|
|
}
|
|
else // some specific table is requested
|
|
{
|
|
#ifdef FE_SB
|
|
pjBegin = pjTable(ulTag, PFF(hff), &cjTable);
|
|
#else
|
|
pjBegin = pjTable(ulTag, PFF(hff)->pvView,PFF(hff)->cjView, &cjTable);
|
|
#endif
|
|
if (pjBegin == (PBYTE)NULL) // table not present
|
|
return (FD_ERROR);
|
|
}
|
|
|
|
// adjust pjBegin to point to location from where the data is to be copied
|
|
|
|
pjBegin += dpStart;
|
|
cjTable -= (LONG)dpStart;
|
|
|
|
if (cjTable <= 0) // dpStart offsets into mem after the end of table
|
|
return (FD_ERROR);
|
|
|
|
if ( (pjBuf == (PBYTE)NULL) || (cjBuf == 0) )
|
|
{
|
|
// the caller is asking how big a buffer it needs to allocate to
|
|
// store the bytes from the offset dpStart into the table to
|
|
// the end of the table (or file if tag is zero)
|
|
|
|
return (cjTable);
|
|
}
|
|
|
|
// at this point we know that pjBuf != 0, the caller wants cjBuf bytes copied
|
|
// into his buffer:
|
|
|
|
if ((ULONG)cjTable > cjBuf)
|
|
cjTable = (LONG)cjBuf;
|
|
|
|
RtlCopyMemory((PVOID)pjBuf, (PVOID)pjBegin, cjTable);
|
|
|
|
return (cjTable);
|
|
}
|
|
|
|
|
|
|
|
LONG
|
|
ttfdQueryTrueTypeTable (
|
|
HFF hff,
|
|
ULONG ulFont, // always 1 for version 1.0 of tt
|
|
ULONG ulTag, // tag identifying the tt table
|
|
PTRDIFF dpStart, // offset into the table
|
|
ULONG cjBuf, // size of the buffer to retrieve the table into
|
|
BYTE *pjBuf // ptr to buffer into which to return the data
|
|
)
|
|
{
|
|
LONG lRet;
|
|
#ifdef FE_SB
|
|
ULONG iFile;
|
|
#endif
|
|
|
|
// see if the file is mapped already, if not we will have to
|
|
// map it in temporarily:
|
|
|
|
#ifdef FE_SB
|
|
if (PTTC(hff)->cRef == 0)
|
|
#else
|
|
if (PFF(hff)->cRef == 0)
|
|
#endif
|
|
{
|
|
// have to remap the file
|
|
|
|
#ifdef FE_SB
|
|
HFF hffTTF;
|
|
iFile = PFF(PTTC(hff)->ahffEntry[0].hff)->iFile;
|
|
|
|
if (!EngMapFontFile(iFile,
|
|
(PULONG*)&PTTC(hff)->pvView,
|
|
&PTTC(hff)->cjView ))
|
|
#else
|
|
if (!EngMapFontFile(PFF(hff)->iFile,
|
|
(PULONG*)&PFF(hff)->pvView,
|
|
&PFF(hff)->cjView ))
|
|
#endif
|
|
{
|
|
RETURN("ttfdQueryTrueTypeTable, bMapFileUNICODE failed\n", FD_ERROR);
|
|
}
|
|
|
|
#ifdef FE_SB
|
|
// update the HFF with the remapped view
|
|
|
|
hffTTF = PTTC(hff)->ahffEntry[ulFont-1].hff;
|
|
PFF(hffTTF)->pvView = PTTC(hff)->pvView;
|
|
PFF(hffTTF)->cjView = PTTC(hff)->cjView;
|
|
#endif
|
|
}
|
|
|
|
|
|
lRet = ttfdQueryTrueTypeTable2(hff, ulFont, ulTag, dpStart, cjBuf, pjBuf);
|
|
|
|
#ifdef FE_SB
|
|
if (PTTC(hff)->cRef==0)
|
|
#else
|
|
if (PFF(hff)->cRef == 0)
|
|
#endif
|
|
{
|
|
#ifdef FE_SB
|
|
EngUnmapFontFile(iFile);
|
|
#else
|
|
EngUnmapFontFile(PFF(hff)->iFile);
|
|
#endif
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ttfdGetTrueTypeFile
|
|
*
|
|
* private entry point for the engine, supported only off of ttfd to expose
|
|
* the pointer to the memory mapped file to the device drivers
|
|
*
|
|
* History:
|
|
* 04-Mar-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID *ttfdGetTrueTypeFile( HFF hff, ULONG *pcj )
|
|
{
|
|
PVOID pvView = NULL; // essential to initialize
|
|
*pcj = 0;
|
|
|
|
ASSERTDD(hff, "ttfdGetTrueTypeFile, hff\n");
|
|
|
|
#ifdef FE_SB
|
|
if (PTTC(hff)->cRef)
|
|
{
|
|
pvView = PTTC(hff)->pvView;
|
|
*pcj = PTTC(hff)->cjView;
|
|
}
|
|
#else
|
|
if (PFF(hff)->cRef)
|
|
{
|
|
pvView = PFF(hff)->pvView;
|
|
*pcj = PFF(hff)->cjView; // cjView == cjFile
|
|
}
|
|
#endif // FE_SB
|
|
|
|
return (pvView);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ttfdQueryFontFile
|
|
*
|
|
* A function to query per font file information.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* hff Handle to a font file.
|
|
*
|
|
* ulMode This is a 32-bit number that must be one of the following
|
|
* values:
|
|
*
|
|
* Allowed ulMode values:
|
|
* ----------------------
|
|
*
|
|
* QFF_DESCRIPTION -- copies a UNICODE string in the buffer
|
|
* that describes the contents of the font file.
|
|
*
|
|
* QFF_NUMFACES -- returns number of faces in the font file.
|
|
*
|
|
* cjBuf Maximum number of BYTEs to copy into the buffer. The
|
|
* driver will not copy more than this many BYTEs.
|
|
*
|
|
* This should be zero if pulBuf is NULL.
|
|
*
|
|
* This parameter is not used in QFF_NUMFACES mode.
|
|
*
|
|
* pulBuf Pointer to the buffer to receive the data
|
|
* If this is NULL, then the required buffer size
|
|
* is returned as a count of BYTEs. Notice that this
|
|
* is a PULONG, to enforce 32-bit data alignment.
|
|
*
|
|
* This parameter is not used in QFF_NUMFACES mode.
|
|
*
|
|
* Returns:
|
|
*
|
|
* If mode is QFF_DESCRIPTION, then the number of BYTEs copied into
|
|
* the buffer is returned by the function. If pulBuf is NULL,
|
|
* then the required buffer size (as a count of BYTEs) is returned.
|
|
*
|
|
* If mode is QFF_NUMFACES, then number of faces in font file is returned.
|
|
*
|
|
* FD_ERROR is returned if an error occurs.
|
|
*
|
|
* History:
|
|
* 22-Oct-1992 -by- Gilman Wong [gilmanw]
|
|
* Added QFF_NUMFACES mode (IFI/DDI merge).
|
|
*
|
|
* 09-Mar-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG ttfdQueryFontFile (
|
|
HFF hff, // handle to font file
|
|
ULONG ulMode, // type of query
|
|
ULONG cjBuf, // size of buffer (in BYTEs)
|
|
ULONG *pulBuf // return buffer (NULL if requesting size of data)
|
|
)
|
|
{
|
|
PIFIMETRICS pifi;
|
|
|
|
ASSERTDD(hff != HFF_INVALID, "ttfdQueryFontFile(): invalid HFF\n");
|
|
|
|
switch (ulMode)
|
|
{
|
|
case QFF_DESCRIPTION:
|
|
|
|
#ifdef FE_SB
|
|
{
|
|
ULONG ulIndex;
|
|
LPWSTR pwszDesc = (LPWSTR)pulBuf;
|
|
LONG lBuffer = 0;
|
|
|
|
for( ulIndex = 0;
|
|
ulIndex < PTTC(hff)->ulNumEntry;
|
|
ulIndex++
|
|
)
|
|
{
|
|
LONG wchlen;
|
|
|
|
// if this is a entry for vertical face font, just skip it...
|
|
|
|
if( !((PTTC(hff)->ahffEntry[ulIndex].iFace) & 0x1) )
|
|
continue;
|
|
|
|
pifi = &((PFF(PTTC(hff)->ahffEntry[ulIndex].hff))->ifi);
|
|
|
|
wchlen = (pifi->dpwszStyleName - pifi->dpwszFaceName) / sizeof(WCHAR);
|
|
|
|
if (ulIndex != 0)
|
|
{
|
|
if (pwszDesc != (LPWSTR) NULL)
|
|
{
|
|
wcscpy((LPWSTR)pwszDesc, (LPWSTR) L" & ");
|
|
pwszDesc += 3;
|
|
}
|
|
lBuffer += (3 * sizeof(WCHAR));
|
|
}
|
|
|
|
if (pwszDesc != (LPWSTR) NULL)
|
|
{
|
|
wcscpy((LPWSTR)pwszDesc, (LPWSTR)((PBYTE)pifi + pifi->dpwszFaceName));
|
|
pwszDesc += (wchlen-2); // -2 for overwrite NULL at next time.
|
|
}
|
|
lBuffer += (wchlen * sizeof(WCHAR));
|
|
}
|
|
|
|
return( lBuffer );
|
|
}
|
|
#else
|
|
|
|
// FullName in tt terms <--> FaceName in ifi terms)
|
|
// If there is a buffer, copy the string into the return buffer.
|
|
|
|
pifi = &PFF(hff)->ifi;
|
|
if (pulBuf != (PULONG)NULL)
|
|
{
|
|
// BUGBUG cast a byte pointer to a WCHAR pointer ???
|
|
|
|
wcscpy((LPWSTR)pulBuf, (LPWSTR)((PBYTE)pifi + pifi->dpwszFaceName));
|
|
}
|
|
|
|
#if DBG
|
|
{
|
|
// this code works if the structure of the ifimetrics does not change
|
|
// with respect to how strings are stored at the end of the structure.
|
|
// The following assert immediately will catch such a problem.
|
|
// we will only do this for non-DBCS fonts because there are some
|
|
// wierd hacks to handle buggy fonts which may cause us to allocate
|
|
// slightly more memory for a facename than there actually is
|
|
|
|
if(!IS_ANY_DBCS_CHARSET( pifi->jWinCharSet ))
|
|
{
|
|
LONG l1,l2;
|
|
l1 = (LONG)(pifi->dpwszStyleName - pifi->dpwszFaceName);
|
|
l2 = (wcslen((LPWSTR)((PBYTE)pifi + pifi->dpwszFaceName)) + 2) * 2;
|
|
ASSERTDD(l1 == l2, "face name length problem\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return (pifi->dpwszStyleName - pifi->dpwszFaceName);
|
|
#endif
|
|
case QFF_NUMFACES:
|
|
//
|
|
// Currently, only one face per TrueType file. This may one day change!
|
|
//
|
|
|
|
#ifdef FE_SB
|
|
return (PTTC(hff))->ulNumEntry;
|
|
#else
|
|
return (PFF(hff))->ulNumFaces;
|
|
#endif
|
|
|
|
default:
|
|
WARNING("ttfd!ttfdQueryFontFile(): invalid mode\n");
|
|
return FD_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vCopyAndZeroOutPaddingBits
|
|
*
|
|
* copies the bits of the bitmap and zeroes out padding bits
|
|
*
|
|
* History:
|
|
* 18-Mar-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
// array of masks for the last byte in a row
|
|
|
|
static BYTE gjMask[8] = {0XFF, 0X80, 0XC0, 0XE0, 0XF0, 0XF8, 0XFC, 0XFE };
|
|
|
|
VOID vCopyAndZeroOutPaddingBits(
|
|
FONTCONTEXT *pfc,
|
|
GLYPHBITS *pgb,
|
|
BYTE *pjSrc,
|
|
GMC *pgmc
|
|
)
|
|
{
|
|
BYTE jMask = gjMask[pgmc->cxCor & 7];
|
|
ULONG cjScanSrc = CJ_TT_SCAN(pgmc->cxCor+pgmc->dxLeft+pgmc->dxRight,pfc);
|
|
ULONG cxDst = pgmc->cxCor + ((pfc->flFontType & FO_SIM_BOLD) ? 1 : 0);
|
|
ULONG cjScanDst = CJ_MONOCHROME_SCAN(cxDst); // includes emboldening if any
|
|
ULONG cjDst = CJ_MONOCHROME_SCAN(pgmc->cxCor); // does not include emboldening
|
|
BYTE *pjScan, *pjScanEnd;
|
|
ULONG iByteLast = cjDst - 1;
|
|
|
|
// sanity checks
|
|
|
|
ASSERTDD(!IS_GRAY(pfc),"Monochrome Images Only Please!\n");
|
|
ASSERTDD(pfc->flFontType & FO_CHOSE_DEPTH,
|
|
"We haven't decided about pixel depth\n"
|
|
);
|
|
ASSERTDD(pgmc->cxCor < LONG_MAX, "TTFD!vCopyAndZeroOutPaddingBits, cxCor\n");
|
|
ASSERTDD(pgmc->cyCor < LONG_MAX, "TTFD!vCopyAndZeroOutPaddingBits, cyCor\n");
|
|
ASSERTDD(pgmc->cxCor > 0, "vCopyAndZeroOutPaddingBits, cxCor == 0\n");
|
|
ASSERTDD(pgmc->cyCor > 0, "vCopyAndZeroOutPaddingBits, cyCor == 0\n");
|
|
|
|
pgb->sizlBitmap.cx = cxDst;
|
|
pgb->sizlBitmap.cy = pgmc->cyCor;
|
|
|
|
// skip the rows at the top that we want to chop off
|
|
|
|
if (pgmc->dyTop)
|
|
{
|
|
pjSrc += (pgmc->dyTop * cjScanSrc);
|
|
}
|
|
|
|
// if must chop off a few columns (on the right, this should almost
|
|
// never happen), put the warning for now to detect these
|
|
// situations and look at them, it does not matter if this is slow
|
|
|
|
pjScan = pgb->aj;
|
|
|
|
|
|
if ((pgmc->dxLeft & 7) == 0) // common fast case
|
|
{
|
|
pjSrc += (pgmc->dxLeft >> 3); // adjust the source
|
|
for (
|
|
pjScanEnd = pjScan + (pgmc->cyCor * cjScanDst);
|
|
pjScan < pjScanEnd;
|
|
pjScan += cjScanDst, pjSrc += cjScanSrc
|
|
)
|
|
{
|
|
RtlCopyMemory((PVOID)pjScan,(PVOID)pjSrc,cjDst);
|
|
pjScan[iByteLast] &= jMask; // mask off the last byte
|
|
}
|
|
}
|
|
else // must shave off from the left:
|
|
{
|
|
BYTE *pjD, *pjS, *pjDEnd, *pjSrcEnd;
|
|
ULONG iShiftL, iShiftR;
|
|
|
|
iShiftL = pgmc->dxLeft & 7;
|
|
iShiftR = 8 - iShiftL;
|
|
|
|
pjSrcEnd = pjSrc + (pgmc->cyCor * cjScanSrc);
|
|
pjSrc += (pgmc->dxLeft >> 3); // adjust the source
|
|
for (
|
|
pjScanEnd = pjScan + (pgmc->cyCor * cjScanDst);
|
|
pjScan < pjScanEnd;
|
|
pjScan += cjScanDst, pjSrc += cjScanSrc
|
|
)
|
|
{
|
|
pjS = pjSrc;
|
|
pjD = pjScan;
|
|
pjDEnd = pjD + iByteLast;
|
|
|
|
// the last byte has to be done outside the loop
|
|
|
|
for (;pjD < pjDEnd; pjD++) // loop for the bytes in the middle
|
|
{
|
|
*pjD = (*pjS << iShiftL);
|
|
pjS++;
|
|
*pjD |= (*pjS >> iShiftR);
|
|
}
|
|
|
|
// do the last byte outside of the loop
|
|
|
|
*pjD = (*pjS << iShiftL);
|
|
if (++pjS < pjSrcEnd)
|
|
*pjD |= (*pjS >> iShiftR);
|
|
|
|
*pjD &= jMask; // mask off the last byte
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* STATIC VOID vMakeAFixedPitchBitmap
|
|
*
|
|
* History:
|
|
* 05-Nov-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vMakeAFixedPitchBitmap(
|
|
FONTCONTEXT *pfc,
|
|
GLYPHBITS *pgb,
|
|
BYTE *pjSrc,
|
|
GLYPHDATA *pgd,
|
|
GMC *pgmc
|
|
)
|
|
{
|
|
BYTE jMask;
|
|
ULONG cjScanSrc = CJ_TT_SCAN(pgmc->cxCor+pgmc->dxLeft+pgmc->dxRight,pfc);
|
|
ULONG cjScanDst = CJ_MONOCHROME_SCAN(pfc->lD);
|
|
ULONG cjD; // number of bytes per row in the destination
|
|
// that are actually going to be modified
|
|
BYTE *pjScan, *pjScanEnd;
|
|
register BYTE *pjD, *pjS, *pjDEnd, *pjSrcEnd;
|
|
LONG lA, lAB, iFirst, iLast;
|
|
register LONG iShiftL, iShiftR;
|
|
ULONG iByteLast;
|
|
|
|
//!!! This doesn't handle gray glyphs as yet [kirko]
|
|
|
|
// sanity checks
|
|
|
|
ASSERTDD(!IS_GRAY(pfc),"Monochrome Images Only Please!\n");
|
|
ASSERTDD(pgmc->cxCor < LONG_MAX, "TTFD!vMakeAFixedPitchBitmap, cxCor\n");
|
|
ASSERTDD(pgmc->cyCor < LONG_MAX, "TTFD!vMakeAFixedPitchBitmap, cyCor\n");
|
|
|
|
|
|
if (!(pfc->flFontType & FO_SIM_BOLD))
|
|
{
|
|
ASSERTDD(pgmc->cxCor == (ULONG)((pgd->fxAB - pgd->fxA) >> 4),
|
|
"vMakeAFixedPitchBitmap, SUM RULE\n");
|
|
}
|
|
else // SIM_BOLD
|
|
{
|
|
ASSERTDD((pgmc->cxCor + 1) == (ULONG)((pgd->fxAB - pgd->fxA) >> 4),
|
|
"vMakeAFixedPitchBitmap, SUM RULE\n");
|
|
}
|
|
|
|
|
|
// skip the raws at the top that we want to chop off
|
|
|
|
if (pgmc->dyTop)
|
|
{
|
|
pjSrc += (pgmc->dyTop * cjScanSrc);
|
|
}
|
|
|
|
// points to the first scan that is going to be affected by blt
|
|
|
|
pjScan = pgb->aj + (pfc->lAscDev + pgd->rclInk.top) * cjScanDst;
|
|
|
|
// compute iFirst, iLast, the first and the last byte in a Dst scan that
|
|
// are going to be written into by the copy. iFirst and iLast are inclusive.
|
|
// For iLast chop off anything that extends beyond lD. For the true console
|
|
// fonts we should be able to put an assert here that fxAB <= fxD,
|
|
// (fxC nonnegative) but we will not do this for there may be a bug
|
|
// in these fonts, so that we may still have to shave off a glyph
|
|
// on the left or right;
|
|
|
|
lAB = pgd->fxAB + (pgmc->dxRight << 4);
|
|
lAB = min(lAB, pgd->fxD) >> 4;
|
|
|
|
// we want lAB to reflect the properties of the source in this routine
|
|
// for it determines how many src bytes are to be blted to every scan of dst.
|
|
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
lAB -= 1;
|
|
|
|
ASSERTDD(lAB > 0, "lAB <= 0\n");
|
|
|
|
// lAB > 0, lAB is exclusive, lAB - 1 inclusive
|
|
|
|
iLast = (lAB - 1) >> 3;
|
|
jMask = gjMask[lAB & 7];
|
|
|
|
lA = (pgd->fxA >> 4) - pgmc->dxLeft;
|
|
iFirst = lA >> 3; // lA is inclusive
|
|
|
|
if (lA >= 0) // quite common, guaranteed for real console fonts
|
|
{
|
|
iByteLast = iLast - iFirst;
|
|
cjD = iByteLast + 1;
|
|
|
|
pjScan += iFirst; // adjust to point to the first dst byte to be touched
|
|
|
|
if ((lA & 7) == 0) // simplest case, src and dst aligned
|
|
{
|
|
for (
|
|
pjScanEnd = pjScan + (pgmc->cyCor * cjScanDst);
|
|
pjScan < pjScanEnd;
|
|
pjScan += cjScanDst, pjSrc += cjScanSrc
|
|
)
|
|
{
|
|
RtlCopyMemory((PVOID)pjScan,(PVOID)pjSrc,cjD);
|
|
pjScan[iByteLast] &= jMask; // mask off the last byte
|
|
}
|
|
}
|
|
else // (lA & 7 != 0) && (lA > 0)
|
|
{
|
|
iShiftR = lA & 7;
|
|
iShiftL = 8 - iShiftR;
|
|
|
|
pjSrcEnd = pjSrc + (pgmc->cyCor * cjScanSrc);
|
|
|
|
for (
|
|
pjScanEnd = pjScan + (pgmc->cyCor * cjScanDst);
|
|
pjScan < pjScanEnd;
|
|
pjScan += cjScanDst, pjSrc += cjScanSrc
|
|
)
|
|
{
|
|
pjS = pjSrc;
|
|
pjD = pjScan;
|
|
pjDEnd = pjD + iByteLast;
|
|
|
|
// the first byte has to be done outside the loop
|
|
|
|
*pjD++ = (*pjS >> iShiftR); // first byte
|
|
|
|
for (;pjD < pjDEnd; pjD++) // loop for bytes in the middle
|
|
{
|
|
*pjD = (*pjS << iShiftL);
|
|
pjS++;
|
|
*pjD |= (*pjS >> iShiftR);
|
|
}
|
|
|
|
// do the last byte,
|
|
// take the pjS check outside of the loop.
|
|
// Must do check for it may try to read
|
|
// where there is no memory to read
|
|
|
|
*pjD = (*pjS << iShiftL);
|
|
if (++pjS < pjSrcEnd)
|
|
*pjD |= (*pjS >> iShiftR);
|
|
*pjD &= jMask; // mask off the last byte
|
|
}
|
|
}
|
|
}
|
|
else // lA < 0, this case will be gone for real console
|
|
// fonts if we ever get one, but for now it stays
|
|
{
|
|
lA = -lA; // easier to work with
|
|
pjSrc += (lA >> 3); // adjust the source
|
|
|
|
// iFirst is zero, chop off columns to the left of char origin
|
|
|
|
iByteLast = iLast;
|
|
cjD = iByteLast + 1;
|
|
|
|
if ((lA & 7) == 0) // simplest case, src and dst aligned
|
|
{
|
|
for (
|
|
pjScanEnd = pjScan + (pgmc->cyCor * cjScanDst);
|
|
pjScan < pjScanEnd;
|
|
pjScan += cjScanDst, pjSrc += cjScanSrc
|
|
)
|
|
{
|
|
RtlCopyMemory((PVOID)pjScan,(PVOID)pjSrc,cjD);
|
|
pjScan[iByteLast] &= jMask; // mask off the last byte
|
|
}
|
|
}
|
|
else // (lA & 7 != 0) && (lA < 0)
|
|
{
|
|
iShiftL = lA & 7;
|
|
iShiftR = 8 - iShiftL;
|
|
|
|
pjSrcEnd = pjSrc + (pgmc->cyCor * cjScanSrc);
|
|
for (
|
|
pjScanEnd = pjScan + (pgmc->cyCor * cjScanDst);
|
|
pjScan < pjScanEnd;
|
|
pjScan += cjScanDst, pjSrc += cjScanSrc
|
|
)
|
|
{
|
|
pjS = pjSrc;
|
|
pjD = pjScan;
|
|
pjDEnd = pjD + iByteLast;
|
|
|
|
// the last byte has to be done outside the loop
|
|
|
|
for (;pjD < pjDEnd; pjD++) // loop for the bytes in the middle
|
|
{
|
|
*pjD = (*pjS << iShiftL);
|
|
pjS++;
|
|
*pjD |= (*pjS >> iShiftR);
|
|
}
|
|
|
|
// do the last byte outside of the loop
|
|
|
|
*pjD = (*pjS << iShiftL);
|
|
if (++pjS < pjSrcEnd)
|
|
*pjD |= (*pjS >> iShiftR);
|
|
|
|
*pjD &= jMask; // mask off the last byte
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vGetNotionalGlyphMetrics
|
|
*
|
|
*
|
|
\**************************************************************************/
|
|
|
|
// be values for the format of the indexToLocation table
|
|
|
|
#define BE_ITOLOCF_SHORT 0X0000
|
|
#define BE_ITOLOCF_LONG 0X0100
|
|
|
|
// offsets to the non scaled glyphdata
|
|
|
|
#define OFF_nc 0
|
|
#define OFF_xMin 2
|
|
#define OFF_yMin 4
|
|
#define OFF_xMax 6
|
|
#define OFF_yMax 8
|
|
|
|
|
|
VOID vGetNotionalGlyphMetrics(
|
|
FONTCONTEXT *pfc, // IN
|
|
ULONG ig, // IN , glyph index
|
|
NOT_GM *pngm // OUT, notional glyph metrics
|
|
)
|
|
{
|
|
sfnt_FontHeader * phead;
|
|
sfnt_HorizontalHeader * phhea;
|
|
sfnt_HorizontalMetrics * phmtx;
|
|
PBYTE pjGlyph;
|
|
PBYTE pjLoca;
|
|
ULONG numberOf_LongHorMetrics;
|
|
BYTE * pjView = pfc->pff->pvView;
|
|
|
|
#if DBG
|
|
sfnt_maxProfileTable * pmaxp;
|
|
ULONG cig;
|
|
|
|
pmaxp = (sfnt_maxProfileTable *)(pjView + pfc->ptp->ateReq[IT_REQ_MAXP].dp);
|
|
cig = BE_UINT16(&pmaxp->numGlyphs) + 1;
|
|
ASSERTDD(ig < cig, "ig >= numGlyphs\n");
|
|
#endif
|
|
|
|
// compute the relevant pointers:
|
|
|
|
phead = (sfnt_FontHeader *)(pjView + pfc->ptp->ateReq[IT_REQ_HEAD].dp);
|
|
phhea = (sfnt_HorizontalHeader *)(pjView + pfc->ptp->ateReq[IT_REQ_HHEAD].dp);
|
|
phmtx = (sfnt_HorizontalMetrics *)(pjView + pfc->ptp->ateReq[IT_REQ_HMTX].dp);
|
|
pjGlyph = pjView + pfc->ptp->ateReq[IT_REQ_GLYPH].dp;
|
|
pjLoca = pjView + pfc->ptp->ateReq[IT_REQ_LOCA].dp;
|
|
numberOf_LongHorMetrics = BE_UINT16(&phhea->numberOf_LongHorMetrics);
|
|
|
|
// get the pointer to the beginning of the glyphdata for this glyph
|
|
// if short format, offset divided by 2 is stored in the table, if long format,
|
|
// the actual offset is stored. Offsets are measured from the beginning
|
|
// of the glyph data table, i.e. from pjGlyph
|
|
|
|
switch (phead->indexToLocFormat)
|
|
{
|
|
case BE_ITOLOCF_SHORT:
|
|
pjGlyph += 2 * BE_UINT16(pjLoca + (sizeof(uint16) * ig));
|
|
break;
|
|
|
|
case BE_ITOLOCF_LONG :
|
|
pjGlyph += BE_UINT32(pjLoca + (sizeof(uint32) * ig));
|
|
break;
|
|
|
|
default:
|
|
RIP("TTFD!_illegal phead->indexToLocFormat\n");
|
|
break;
|
|
}
|
|
|
|
// get the bounds, flip y
|
|
|
|
pngm->xMin = BE_INT16(pjGlyph + OFF_xMin);
|
|
pngm->xMax = BE_INT16(pjGlyph + OFF_xMax);
|
|
pngm->yMin = - BE_INT16(pjGlyph + OFF_yMax);
|
|
pngm->yMax = - BE_INT16(pjGlyph + OFF_yMin);
|
|
|
|
// get the adwance width and the lsb
|
|
// the piece of code stolen from the rasterizer [bodind]
|
|
|
|
if (ig < numberOf_LongHorMetrics)
|
|
{
|
|
pngm->sD = BE_INT16(&phmtx[ig].advanceWidth);
|
|
pngm->sA = BE_INT16(&phmtx[ig].leftSideBearing);
|
|
}
|
|
else
|
|
{
|
|
// first entry after[AW,LSB] array
|
|
|
|
int16 * psA = (int16 *) &phmtx[numberOf_LongHorMetrics];
|
|
|
|
pngm->sD = BE_INT16(&phmtx[numberOf_LongHorMetrics-1].advanceWidth);
|
|
pngm->sA = BE_INT16(&psA[ig - numberOf_LongHorMetrics]);
|
|
}
|
|
|
|
// redefine x coords so that they correspond to being measured relative to
|
|
// the real character origin
|
|
|
|
pngm->xMax = pngm->xMax - pngm->xMin + pngm->sA;
|
|
pngm->xMin = pngm->sA;
|
|
|
|
if (pfc->flFontType & FO_SIM_ITALIC)
|
|
{
|
|
// IF there is italic simulation A,B,C spaces change
|
|
|
|
pngm->sA -= (SHORT)FixMul(pngm->yMax, FX_SIN20);
|
|
pngm->xMax -= (SHORT)FixMul(pngm->yMin, FX_SIN20);
|
|
}
|
|
}
|
|
|
|
LONG lFFF(LONG l);
|
|
#define FFF(e,l) *(LONG*)(&(e)) = lFFF(l)
|
|
|
|
/******************************Public*Routine******************************\
|
|
* lQueryDEVICEMETRICS
|
|
*
|
|
* History:
|
|
* 08-Apr-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG lQueryDEVICEMETRICS (
|
|
FONTCONTEXT *pfc,
|
|
ULONG cjBuffer,
|
|
FD_DEVICEMETRICS *pdevm
|
|
)
|
|
{
|
|
sfnt_FontHeader *phead;
|
|
|
|
LONG lULThickness,
|
|
lSOThickness,
|
|
lStrikeoutPosition,
|
|
lUnderscorePosition,
|
|
lTotalLeading;
|
|
|
|
BYTE *pjView = (BYTE *)pfc->pff->pvView;
|
|
|
|
PBYTE pjOS2 = (pfc->pff->tp.ateOpt[IT_OPT_OS2].dp) ?
|
|
(pjView + pfc->pff->tp.ateOpt[IT_OPT_OS2].dp):
|
|
NULL ;
|
|
|
|
Fixed fxXScale = pfc->mx.transform[0][0];
|
|
if (fxXScale < 0)
|
|
fxXScale = - fxXScale;
|
|
|
|
// actually requesting the data
|
|
|
|
ASSERTDD (
|
|
sizeof(FD_DEVICEMETRICS) <= cjBuffer,
|
|
"FD_QUERY_DEVICEMETRICS: buffer too small\n");
|
|
|
|
// get the pointers to needed tables in the tt file
|
|
|
|
phead = (sfnt_FontHeader *)(pjView + pfc->ptp->ateReq[IT_REQ_HEAD].dp);
|
|
|
|
// first store precomputed quantities
|
|
|
|
pdevm->pteBase = pfc->pteUnitBase;
|
|
pdevm->pteSide = pfc->pteUnitSide;
|
|
pdevm->cxMax = pfc->cxMax;
|
|
|
|
pdevm->fxMaxAscender = LTOFX(pfc->lAscDev);
|
|
pdevm->fxMaxDescender = LTOFX(pfc->lDescDev);
|
|
|
|
// get the notional space values for the strike out and underline quantities:
|
|
|
|
lSOThickness = (LONG)pfc->pff->ifi.fwdStrikeoutSize;
|
|
lStrikeoutPosition = (LONG)pfc->pff->ifi.fwdStrikeoutPosition;
|
|
|
|
lULThickness = (LONG)pfc->pff->ifi.fwdUnderscoreSize;
|
|
lUnderscorePosition = (LONG)pfc->pff->ifi.fwdUnderscorePosition;
|
|
|
|
// compute the accelerator flags for this font
|
|
|
|
pdevm->flRealizedType = 0;
|
|
|
|
pdevm->lD = pfc->lD;
|
|
if (pfc->lD)
|
|
{
|
|
// stolen from bmfd
|
|
|
|
pdevm->flRealizedType =
|
|
(
|
|
FDM_TYPE_BM_SIDE_CONST | // all char bitmaps have the same cy
|
|
FDM_TYPE_CONST_BEARINGS | // ac spaces for all chars the same, not 0 necessarilly
|
|
FDM_TYPE_MAXEXT_EQUAL_BM_SIDE | // really means tops aligned
|
|
FDM_TYPE_ZERO_BEARINGS |
|
|
FDM_TYPE_CHAR_INC_EQUAL_BM_BASE
|
|
);
|
|
}
|
|
|
|
// things interesting for private user apis:
|
|
|
|
pdevm->lMinA = (LONG)pfc->pff->sMinA;
|
|
pdevm->lMinC = (LONG)pfc->pff->sMinC;
|
|
pdevm->lMinD = (LONG)pfc->pff->usMinD;
|
|
|
|
if (pfc->flXform & XFORM_HORIZ)
|
|
{
|
|
Fixed fxYScale = pfc->mx.transform[1][1];
|
|
|
|
// strike out and underline size:
|
|
|
|
lULThickness *= fxYScale;
|
|
lULThickness = F16_16TOLROUND(lULThickness);
|
|
if (lULThickness == 0)
|
|
lULThickness = (fxYScale > 0) ? 1 : -1;
|
|
|
|
pdevm->ptlULThickness.x = 0;
|
|
pdevm->ptlULThickness.y = lULThickness;
|
|
|
|
lSOThickness *= fxYScale;
|
|
lSOThickness = F16_16TOLROUND(lSOThickness);
|
|
if (lSOThickness == 0)
|
|
lSOThickness = (fxYScale > 0) ? 1 : -1;
|
|
|
|
pdevm->ptlSOThickness.x = 0;
|
|
pdevm->ptlSOThickness.y = lSOThickness;
|
|
|
|
// strike out and underline position
|
|
|
|
lStrikeoutPosition *= fxYScale;
|
|
pdevm->ptlStrikeOut.y = -F16_16TOLROUND(lStrikeoutPosition);
|
|
|
|
lUnderscorePosition *= fxYScale;
|
|
pdevm->ptlUnderline1.y = -F16_16TOLROUND(lUnderscorePosition);
|
|
|
|
pdevm->ptlUnderline1.x = 0L;
|
|
pdevm->ptlStrikeOut.x = 0L;
|
|
|
|
// things needed for private a user api:
|
|
|
|
pdevm->lMinA = F16_16TOLROUND(fxXScale * pdevm->lMinA);
|
|
pdevm->lMinC = F16_16TOLROUND(fxXScale * pdevm->lMinC);
|
|
pdevm->lMinD = F16_16TOLROUND(fxXScale * pdevm->lMinD);
|
|
}
|
|
else // nontrivial transform
|
|
{
|
|
POINTL aptl[4];
|
|
POINTFIX aptfx[4];
|
|
BOOL b;
|
|
|
|
pdevm->lD = 0;
|
|
|
|
// xform so and ul vectors
|
|
|
|
aptl[0].x = 0;
|
|
aptl[0].y = lSOThickness;
|
|
|
|
aptl[1].x = 0;
|
|
aptl[1].y = -lStrikeoutPosition;
|
|
|
|
aptl[2].x = 0;
|
|
aptl[2].y = lULThickness;
|
|
|
|
aptl[3].x = 0;
|
|
aptl[3].y = -lUnderscorePosition;
|
|
|
|
// !!! [GilmanW] 27-Oct-1992
|
|
// !!! Should change over to engine user object helper functions
|
|
// !!! instead of the fontmath.cxx functions.
|
|
|
|
b = bFDXform(&pfc->xfm, aptfx, aptl, 4);
|
|
if (!b) {RIP("TTFD!_bFDXform, fd_query.c\n");}
|
|
|
|
pdevm->ptlSOThickness.x = FXTOLROUND(aptfx[0].x);
|
|
pdevm->ptlSOThickness.y = FXTOLROUND(aptfx[0].y);
|
|
|
|
pdevm->ptlStrikeOut.x = FXTOLROUND(aptfx[1].x);
|
|
pdevm->ptlStrikeOut.y = FXTOLROUND(aptfx[1].y);
|
|
|
|
pdevm->ptlULThickness.x = FXTOLROUND(aptfx[2].x);
|
|
pdevm->ptlULThickness.y = FXTOLROUND(aptfx[2].y);
|
|
|
|
pdevm->ptlUnderline1.x = FXTOLROUND(aptfx[3].x);
|
|
pdevm->ptlUnderline1.y = FXTOLROUND(aptfx[3].y);
|
|
|
|
// things needed for private a user api:
|
|
|
|
pdevm->lMinA = FXTOLROUND(fxLTimesEf(&pfc->efBase, pdevm->lMinA));
|
|
pdevm->lMinC = FXTOLROUND(fxLTimesEf(&pfc->efBase, pdevm->lMinC));
|
|
pdevm->lMinD = FXTOLROUND(fxLTimesEf(&pfc->efBase, pdevm->lMinD));
|
|
}
|
|
|
|
// Compute the device metrics.
|
|
// HACK ALLERT, overwrite the result if the transformation
|
|
// to be really used has changed as a result of "vdmx" quantization.
|
|
// Not a hack any more, this is even documented now in DDI spec:
|
|
|
|
if (pfc->flXform & (XFORM_HORIZ | XFORM_2PPEM))
|
|
{
|
|
FFF(pdevm->fdxQuantized.eXX, pfc->mx.transform[0][0]);
|
|
FFF(pdevm->fdxQuantized.eYY, pfc->mx.transform[1][1]);
|
|
|
|
if (!(pfc->flXform & XFORM_HORIZ))
|
|
{
|
|
FFF(pdevm->fdxQuantized.eXY,-pfc->mx.transform[0][1]);
|
|
FFF(pdevm->fdxQuantized.eYX,-pfc->mx.transform[1][0]);
|
|
}
|
|
}
|
|
|
|
// finally we have to do nonlinear external leading for type 1 conversions
|
|
|
|
if (pfc->pff->fl & FF_TYPE_1_CONVERSION)
|
|
{
|
|
LONG lPtSize = F16_16TOLROUND(pfc->fxPtSize);
|
|
|
|
LONG lIntLeading = pfc->lAscDev + pfc->lDescDev - pfc->lEmHtDev;
|
|
|
|
// I need this, PS driver does it and so does makepfm utility.
|
|
|
|
if (lIntLeading < 0)
|
|
lIntLeading = 0;
|
|
|
|
switch (pfc->pff->ifi.jWinPitchAndFamily & 0xf0)
|
|
{
|
|
case FF_ROMAN:
|
|
|
|
lTotalLeading = (pfc->sizLogResPpi.cy + 18) / 32; // 2 pt leading;
|
|
break;
|
|
|
|
case FF_SWISS:
|
|
|
|
if (lPtSize <= 12)
|
|
lTotalLeading = (pfc->sizLogResPpi.cy + 18) / 32; // 2 pt
|
|
if (lPtSize < 14)
|
|
lTotalLeading = (pfc->sizLogResPpi.cy + 12) / 24; // 3 pt
|
|
else
|
|
lTotalLeading = (pfc->sizLogResPpi.cy + 9) / 18; // 4 pt
|
|
break;
|
|
|
|
default:
|
|
|
|
// use 19.6% of the Em height for leading, do not do any rounding.
|
|
|
|
lTotalLeading = (pfc->lEmHtDev * 196) / 1000;
|
|
break;
|
|
}
|
|
|
|
pdevm->lNonLinearExtLeading = (lTotalLeading - lIntLeading) << 4; // TO 28.4
|
|
if (pdevm->lNonLinearExtLeading < 0)
|
|
pdevm->lNonLinearExtLeading = 0;
|
|
}
|
|
|
|
// for emboldened fonts MaxCharWidth and AveCharWidth can not be computed
|
|
// by linear scaling. These nonlinarly transformed values we will store in
|
|
// pdevm->lNonLinearMaxCharWidth // max and pdevm->lNonLinearAvgCharWidth // avg.
|
|
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
{
|
|
|
|
if (pfc->lD)
|
|
{
|
|
pdevm->lNonLinearMaxCharWidth = pdevm->lNonLinearAvgCharWidth = (pfc->lD << 4);
|
|
}
|
|
else
|
|
{
|
|
if (pfc->flXform & XFORM_HORIZ)
|
|
{
|
|
// notice +1 we are adding: this is the nonlinearity we are talking about
|
|
|
|
pdevm->lNonLinearMaxCharWidth = fxXScale * (LONG)pfc->pff->ifi.fwdMaxCharInc;
|
|
pdevm->lNonLinearMaxCharWidth = F16_16TO28_4(pdevm->lNonLinearMaxCharWidth) + 16;
|
|
|
|
pdevm->lNonLinearAvgCharWidth = fxXScale * ((LONG)pfc->pff->ifi.fwdAveCharWidth);
|
|
pdevm->lNonLinearAvgCharWidth = F16_16TO28_4(pdevm->lNonLinearAvgCharWidth) + 16;
|
|
}
|
|
else // nontrivial transform
|
|
{
|
|
pdevm->lNonLinearMaxCharWidth =
|
|
fxLTimesEf(&pfc->efBase, (LONG)pfc->pff->ifi.fwdMaxCharInc) + 16;
|
|
|
|
pdevm->lNonLinearAvgCharWidth =
|
|
fxLTimesEf(&pfc->efBase, (LONG)pfc->pff->ifi.fwdAveCharWidth) + 16;
|
|
}
|
|
}
|
|
}
|
|
|
|
// add new fields:
|
|
|
|
|
|
// If singular transform, the TrueType driver will provide a blank
|
|
// 1x1 bitmap. This is so device drivers will not have to implement
|
|
// special case code to handle singular transforms.
|
|
|
|
if ( pfc->flXform & XFORM_SINGULAR )
|
|
{
|
|
ASSERTDD(pfc->flFontType & FO_CHOSE_DEPTH,"Depth Not Chosen Yet!\n");
|
|
pdevm->cyMax = 1;
|
|
pdevm->cjGlyphMax = (CJGD(1,1,pfc));
|
|
}
|
|
else // Otherwise, the max glyph size is cached in the FONTCONTEXT.
|
|
{
|
|
pdevm->cyMax = pfc->yMax - pfc->yMin;
|
|
pdevm->cjGlyphMax = pfc->cjGlyphMax;
|
|
}
|
|
|
|
// we are outa here
|
|
|
|
return sizeof(FD_DEVICEMETRICS);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vAddPOINTQF
|
|
*
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vAddPOINTQF( POINTQF *pptq1, POINTQF *pptq2)
|
|
{
|
|
pptq1->x.LowPart += pptq2->x.LowPart;
|
|
pptq1->x.HighPart += pptq2->x.HighPart + (pptq1->x.LowPart < pptq2->x.LowPart);
|
|
|
|
pptq1->y.LowPart += pptq2->y.LowPart;
|
|
pptq1->y.HighPart += pptq2->y.HighPart + (pptq1->y.LowPart < pptq2->y.LowPart);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vEmbolden_GLYPHDATA
|
|
*
|
|
* Effects: modifies the field of the glyphdata structure that are affected by
|
|
* emboldening simulation
|
|
*
|
|
* History:
|
|
* 16-Oct-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vEmbolden_GLYPHDATA (FONTCONTEXT *pfc, GLYPHDATA *pgldt)
|
|
{
|
|
// pgldt->gdf.pgb unchanged
|
|
|
|
// pgldt->rclInk.left unchanged
|
|
// pgldt->rclInk.top unchanged
|
|
// pgldt->rclInk.bottom unchanged
|
|
|
|
pgldt->rclInk.right += 1;
|
|
|
|
if (!pfc->lD)
|
|
{
|
|
// If fixed pitch font, lD has been already set
|
|
// correctly, so that nothing needs to be done at this time
|
|
|
|
pgldt->fxD += LTOFX(1); // this is the absolute value by def
|
|
}
|
|
|
|
// go on to compute the positioning info:
|
|
|
|
if (pfc->flXform & XFORM_HORIZ) // scaling only
|
|
{
|
|
FIX fxTmp;
|
|
|
|
pgldt->ptqD.x.HighPart = (LONG)pgldt->fxD;
|
|
|
|
if (pfc->mx.transform[0][0] < 0)
|
|
pgldt->ptqD.x.HighPart = - pgldt->ptqD.x.HighPart;
|
|
|
|
pgldt->fxA = LTOFX(pgldt->rclInk.left);
|
|
pgldt->fxAB = LTOFX(pgldt->rclInk.right);
|
|
|
|
if (pfc->mx.transform[0][0] < 0)
|
|
{
|
|
fxTmp = pgldt->fxA;
|
|
pgldt->fxA = -pgldt->fxAB;
|
|
pgldt->fxAB = -fxTmp;
|
|
}
|
|
}
|
|
else // non trivial information
|
|
{
|
|
// add a unit vector in the baseline direction to each char inc vector.
|
|
// This is consistent with fxD += LTOFX(1) and compatible with win31.
|
|
// This makes sense.
|
|
|
|
vAddPOINTQF(&pgldt->ptqD,&pfc->ptqUnitBase);
|
|
|
|
//!!! not sure how to compute fxA, fxAB, fxInkTop and fxInkBottom.
|
|
//!!! These are really tricky. LEAVE IT WRONG FOR NOW [bodind]
|
|
|
|
//!!! in most of the cases however, top and bottom and a
|
|
//!!! should remain unchanged and ab should be increased by 1.
|
|
//!!! This is the case when the xform is composed of the scaling followed
|
|
//!!! by rotation:
|
|
|
|
pgldt->fxAB += LTOFX(1);
|
|
|
|
// pgldt->fxInkTop
|
|
// pgldt->fxInkBottom
|
|
|
|
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ttfdQueryFontData
|
|
*
|
|
* dhpdev Not used.
|
|
*
|
|
* pfo Pointer to a FONTOBJ.
|
|
*
|
|
* iMode This is a 32-bit number that must be one of the following
|
|
* values:
|
|
*
|
|
* Allowed ulMode values:
|
|
* ----------------------
|
|
*
|
|
* QFD_GLYPH -- return glyph metrics only
|
|
*
|
|
* QFD_GLYPHANDBITMAP -- return glyph metrics and bitmap
|
|
*
|
|
* QFD_GLYPHANDOUTLINE -- return glyph metrics and outline
|
|
*
|
|
* QFD_MAXEXTENTS -- return FD_DEVICEMETRICS structure
|
|
*
|
|
* pgd Buffer to hold glyphdata structure, if any
|
|
*
|
|
* pv Output buffer to hold glyphbits or pathobj, if any.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Otherwise, returns the size of the glyphbits
|
|
*
|
|
* FD_ERROR is returned if an error occurs.
|
|
*
|
|
* History:
|
|
* 31-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG ttfdQueryFontData (
|
|
FONTOBJ *pfo,
|
|
ULONG iMode,
|
|
HGLYPH hg,
|
|
GLYPHDATA *pgd,
|
|
PVOID pv,
|
|
ULONG cjSize
|
|
)
|
|
{
|
|
extern LONG lGetSingularGlyphBitmap(FONTCONTEXT*, HGLYPH, GLYPHDATA*, PVOID);
|
|
extern STATIC LONG lQueryDEVICEMETRICS(FONTCONTEXT*, ULONG, FD_DEVICEMETRICS*);
|
|
extern LONG ttfdGlyphBitmap(FONTCONTEXT*, ULONG, HGLYPH, GLYPHDATA*, VOID*, ULONG);
|
|
extern LONG lGetGlyphBitmapErrRecover(FONTCONTEXT*, HGLYPH, GLYPHDATA*, PVOID, BOOL);
|
|
extern LONG lGetGlyphBitmap(FONTCONTEXT*, HGLYPH, GLYPHDATA*, PVOID, BOOL, FS_ENTRY*);
|
|
extern BOOL ttfdQueryGlyphOutline(FONTCONTEXT*, HGLYPH, GLYPHDATA*, PATHOBJ*);
|
|
|
|
// declare the locals
|
|
|
|
PFONTCONTEXT pfc;
|
|
LONG cj = 0, cjDataRet = 0;
|
|
|
|
cjSize; // bizzare, why is this passed in ? [bodind]
|
|
|
|
// if this font file is gone we are not gonna be able to answer any questions
|
|
// about it
|
|
|
|
ASSERTDD(pfo->iFile, "ttfdQueryFontData, pfo->iFile\n");
|
|
|
|
#ifdef FE_SB
|
|
if (((TTC_FONTFILE *)pfo->iFile)->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
#else
|
|
if (((FONTFILE *)pfo->iFile)->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
#endif
|
|
{
|
|
WARNING("ttfd, ttfdQueryFontData(): file is gone\n");
|
|
return FD_ERROR;
|
|
}
|
|
|
|
// If pfo->pvProducer is NULL, then we need to open a font context.
|
|
|
|
if ( pfo->pvProducer == (PVOID) NULL )
|
|
{
|
|
pfo->pvProducer = pfc = ttfdOpenFontContext(pfo);
|
|
}
|
|
else
|
|
{
|
|
pfc = (FONTCONTEXT*) pfo->pvProducer;
|
|
pfc->flFontType = (pfc->flFontType & FO_CHOSE_DEPTH) | pfo->flFontType;
|
|
}
|
|
|
|
if ( pfc == (FONTCONTEXT *) NULL )
|
|
{
|
|
WARNING("gdisrv!ttfdQueryFontData(): cannot create font context\n");
|
|
return FD_ERROR;
|
|
}
|
|
|
|
pfc->pfo = pfo;
|
|
|
|
// call fs_NewTransformation if needed:
|
|
|
|
if (!bGrabXform(pfc))
|
|
{
|
|
RETURN("gdisrv!ttfd bGrabXform failed\n", FD_ERROR);
|
|
}
|
|
|
|
switch ( iMode )
|
|
{
|
|
case QFD_TT_GRAY1_BITMAP: // monochrome
|
|
case QFD_TT_GRAY2_BITMAP: // one byte per pixel: 0..4
|
|
case QFD_TT_GRAY4_BITMAP: // one byte per pixel: 0..16
|
|
case QFD_TT_GRAY8_BITMAP: // one byte per pixel: 0..64
|
|
|
|
return( ttfdGlyphBitmap( pfc, iMode, hg, pgd, pv, cjSize) );
|
|
break;
|
|
|
|
case QFD_GLYPHANDBITMAP:
|
|
case QFD_TT_GLYPHANDBITMAP:
|
|
{
|
|
// Engine should not be querying on the HGLYPH_INVALID.
|
|
|
|
ASSERTDD (
|
|
hg != HGLYPH_INVALID,
|
|
"ttfdQueryFontData(QFD_GLYPHANDBITMAP): HGLYPH_INVALID \n"
|
|
);
|
|
|
|
// If singular transform, the TrueType driver will provide a blank
|
|
// 1x1 bitmap. This is so device drivers will not have to implement
|
|
// special case code to handle singular transforms.
|
|
//
|
|
// So depending on the transform type, choose a function to retrieve
|
|
// bitmaps.
|
|
|
|
if (pfc->flXform & XFORM_SINGULAR)
|
|
{
|
|
cj = lGetSingularGlyphBitmap(pfc, hg, pgd, pv);
|
|
}
|
|
else
|
|
{
|
|
FS_ENTRY iRet;
|
|
|
|
// if minimal bitmap is requested, this is what we have to
|
|
// return even if otherwise we might want to pad bitmap
|
|
// to the width pfc->lD (in case of console fonts)
|
|
|
|
BOOL bMinBmp = !pfc->lD || (iMode == QFD_TT_GLYPHANDBITMAP);
|
|
|
|
if ( pfc->bVertical )
|
|
{
|
|
cj = lGetGlyphBitmapVertical( pfc, hg, pgd, pv, bMinBmp, &iRet);
|
|
}
|
|
else
|
|
{
|
|
cj = lGetGlyphBitmap(pfc,
|
|
hg,
|
|
pgd,
|
|
pv,
|
|
bMinBmp,
|
|
&iRet);
|
|
}
|
|
|
|
if ((cj == FD_ERROR) && (iRet == POINT_MIGRATION_ERR))
|
|
{
|
|
// this is buggy glyph where hinting has so severly distorted
|
|
// the glyph that one of the points went out of range.
|
|
// We will just return a blank glyph but with correct
|
|
// abcd info. That way only that buggy glyph will not be printed
|
|
// correctly, the rest will of glyphs will.
|
|
// More importantly, if psciprt driver tries to
|
|
// download this font, the download operation will not fail just because
|
|
// one glyph in a font is buggy. [BodinD]
|
|
|
|
cj = lGetGlyphBitmapErrRecover(pfc, hg, pgd, pv, bMinBmp);
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if (cj == FD_ERROR)
|
|
{
|
|
WARNING("ttfdQueryFontData(QFD_GLYPHANDBITMAP): get bitmap failed\n");
|
|
}
|
|
#endif
|
|
}
|
|
return cj;
|
|
|
|
case QFD_GLYPHANDOUTLINE:
|
|
|
|
ASSERTDD (
|
|
hg != HGLYPH_INVALID,
|
|
"ttfdQueryFontData(QFD_GLYPHANDOUTLINE): HGLYPH_INVALID \n"
|
|
);
|
|
|
|
if (!ttfdQueryGlyphOutline(pfc, hg, pgd, (PATHOBJ *) pv))
|
|
{
|
|
WARNING("ttfdQueryFontData(QFD_GLYPHANDOUTLINE): failed to get outline\n");
|
|
return FD_ERROR;
|
|
}
|
|
return sizeof(GLYPHDATA);
|
|
|
|
case QFD_MAXEXTENTS:
|
|
|
|
return lQueryDEVICEMETRICS(
|
|
pfc,
|
|
sizeof(FD_DEVICEMETRICS),
|
|
(FD_DEVICEMETRICS *) pv
|
|
);
|
|
|
|
|
|
default:
|
|
|
|
WARNING("gdisrv!ttfdQueryFontData(): unsupported mode\n");
|
|
return FD_ERROR;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Routine Name:
|
|
*
|
|
* ttfdGlyphBitmap
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Routines called:
|
|
*
|
|
* EngSetLastError
|
|
* lGGOBitmap
|
|
*
|
|
* Called by:
|
|
*
|
|
* ttfdQueryFontData
|
|
*
|
|
* Return Value:
|
|
*
|
|
* If pv is zero then then return the size of the required buffer
|
|
* in bytes. If pv is not zero, then return the number of bytes
|
|
* copied to the buffer. An error is indicated by a return value
|
|
* of FD_ERROR.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
LONG ttfdGlyphBitmap(
|
|
FONTCONTEXT *pfc,
|
|
ULONG iMode,
|
|
HGLYPH hg,
|
|
GLYPHDATA *pgd,
|
|
VOID *pv,
|
|
ULONG cjSize
|
|
)
|
|
{
|
|
extern LONG lGGOBitmap(FONTCONTEXT*,unsigned,HGLYPH,GLYPHDATA*,VOID*,unsigned);
|
|
|
|
unsigned uOverScale;
|
|
LONG lRet;
|
|
|
|
// RIP("ttfdGlypBitmap\n");
|
|
|
|
lRet = 0;
|
|
if ( hg == HGLYPH_INVALID )
|
|
{
|
|
WARNING( "ttfdGlyphBitamp -- invalid hg\n" );
|
|
EngSetLastError( ERROR_INVALID_PARAMETER );
|
|
lRet = FD_ERROR;
|
|
}
|
|
else
|
|
{
|
|
switch ( iMode )
|
|
{
|
|
case QFD_TT_GRAY1_BITMAP: // monochrome
|
|
|
|
uOverScale = 1;
|
|
break;
|
|
|
|
case QFD_TT_GRAY2_BITMAP: // one byte per pixel: 0..4
|
|
|
|
uOverScale = 2;
|
|
break;
|
|
|
|
case QFD_TT_GRAY4_BITMAP: // one byte per pixel: 0..16
|
|
|
|
uOverScale = 4;
|
|
break;
|
|
|
|
case QFD_TT_GRAY8_BITMAP: // one byte per pixel: 0..64
|
|
|
|
uOverScale = 8;
|
|
break;
|
|
|
|
default:
|
|
|
|
WARNING( "ttfdGlyphBitmap -- invalid iMode\n");
|
|
EngSetLastError( ERROR_INVALID_PARAMETER );
|
|
lRet = FD_ERROR;
|
|
}
|
|
if ( lRet != FD_ERROR )
|
|
{
|
|
if ( pfc->bVertical )
|
|
{
|
|
if ( bChangeXform( pfc, TRUE ))
|
|
{
|
|
pfc->ulControl |= VERTICAL_MODE;
|
|
pfc->hgSave = hg;
|
|
if ( pfc->pff->hgSearchVerticalGlyph )
|
|
{
|
|
hg = (*pfc->pff->hgSearchVerticalGlyph)( pfc, hg );
|
|
}
|
|
lRet = lGGOBitmap(pfc, uOverScale, hg, pgd, pv, cjSize);
|
|
pfc->ulControl &= ~VERTICAL_MODE;
|
|
if ( !bChangeXform( pfc, FALSE ))
|
|
{
|
|
lRet = FD_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lRet = FD_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lRet = lGGOBitmap(pfc, uOverScale, hg, pgd, pv, cjSize);
|
|
}
|
|
}
|
|
}
|
|
return( lRet );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Routine Name:
|
|
*
|
|
* lGGOBitmap
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* For returning bitmaps in the format as required by GetGlyphOutline
|
|
*
|
|
* Routines called:
|
|
*
|
|
* EngSetLastError
|
|
* vCharacterCode
|
|
* fs_NewGlyph
|
|
* fs_FindBitmapSize
|
|
* fs_FindGraySize
|
|
* pvSetMemoryBases
|
|
* V_FREE
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return Value:
|
|
*
|
|
* if (pv == 0)
|
|
* <return the size of buffer needed to receive the bitmap>;
|
|
* else
|
|
* <return the number of bytes written to the recieving buffer>;
|
|
*
|
|
\**************************************************************************/
|
|
|
|
LONG lGGOBitmap(
|
|
FONTCONTEXT *pfc,
|
|
unsigned uOverScale, // 1 (monochrome) ,2,4,8 (antialiased)
|
|
HGLYPH hg,
|
|
GLYPHDATA *pgd,
|
|
VOID *pv,
|
|
unsigned cjSize
|
|
)
|
|
{
|
|
|
|
LONG lRet; // returned to caller
|
|
ULONG iError; // for EngSetLastError
|
|
ULONG ig; // index of glyph (fs_NewGlyph)
|
|
BitMap *pbm; // pointer into fs_ structure
|
|
Rect *pRect; // pointer into fs_ structure
|
|
fs_GlyphInputType *pin = pfc->pgin; // used a lot
|
|
fs_GlyphInfoType *pout = pfc->pgout; // used a lot
|
|
int isMonochrome = ( uOverScale == 1 ); // TRUE iff monochrome glyph
|
|
|
|
// RIP("lGGOBitmap\n");
|
|
|
|
iError = NO_ERROR; // keep going until this changes
|
|
vInitGlyphState( &pfc->gstat ); // invalidate cache
|
|
vCharacterCode( pfc->pff, hg, pin ); // translate the glyph handle
|
|
if ( fs_NewGlyph(pin, pout) != NO_ERR ) // inform the rasterizer of new glyph
|
|
{ // rasterizer not happy, get out
|
|
WARNING("lGGOBitmap -- fs_NewGlyph failed\n");
|
|
iError = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
else
|
|
{
|
|
ig = pfc->pgout->glyphIndex;
|
|
pin->param.gridfit.styleFunc = 0;
|
|
pin->param.gridfit.traceFunc = 0;
|
|
pin->param.gridfit.bSkipIfBitmap = isMonochrome; // if monochrome then no hints
|
|
if ( fs_ContourGridFit(pin, pout) != NO_ERR ) // have rasterizer generate outlines
|
|
{ // something went wrong, get out
|
|
WARNING("lGGOBitmap -- fs_ContourGridFit failed\n");
|
|
iError = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
else
|
|
{ // if you get here, the rasterizer has accepted the new glyph now we must
|
|
// get glyph metrics and initialize pgin for later rasterization calls
|
|
// of the required bitmaps
|
|
|
|
if ( isMonochrome ) // monochrome glyph?
|
|
{ // find size of monochrome glyph
|
|
if ( fs_FindBitMapSize(pin, pout) != NO_ERR )
|
|
{ // no, get out
|
|
WARNING("lGGOBitmap -- fs_FindBitMapSize failed\n");
|
|
iError = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
else
|
|
{ // find size of antialiased glyph
|
|
pin->param.gray.usOverScale = (uint16) uOverScale;
|
|
pin->param.gray.bMatchBBox = FALSE;
|
|
if ( fs_FindGraySize(pin, pout) != NO_ERR ) // get size from rasterizer
|
|
{ // rasterizer is not happy, get out
|
|
WARNING("lGGOBitmap -- fs_FindGraySize failed\n");
|
|
iError = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( iError == NO_ERROR ) // everything OK so far?
|
|
{ // yes
|
|
if ( pgd ) // caller provided GLYPHDATA?
|
|
{ // yes, fill it in
|
|
GMC gmc; // necessary scratch space
|
|
POINTL ptlOrg; // necessary scratch space
|
|
fs_GlyphInfoType gout, *pgout;
|
|
HGLYPH hgTemp;
|
|
|
|
if ( pfc->bVertical && ( pfc->ulControl & VERTICAL_MODE ) ) // vertical?
|
|
{ // yes
|
|
hgTemp = pfc->hgSave;
|
|
pgout = &gout;
|
|
vShiftBitmapInfo( pfc, pgout, pfc->pgout );
|
|
}
|
|
else
|
|
{ // not vertical
|
|
hgTemp = hg;
|
|
pgout = pfc->pgout;
|
|
}
|
|
|
|
// fill the GLYPHDATA structure
|
|
|
|
vFillGLYPHDATA(hgTemp,ig,pfc,pgout,pgd,&gmc,&ptlOrg,FALSE);
|
|
}
|
|
|
|
if ( pv == 0 ) // buffer provided for bits?
|
|
{ // no, return necessary size
|
|
if ( cjSize ) // is the input size zero?
|
|
{ // no, caller is a fool, get out
|
|
WARNING("lGGOBitmap -- pv == 0 && cjRet != 0\n");
|
|
iError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else // input size zero
|
|
{ // so caller is not a fool
|
|
pbm = &pfc->pgout->bitMapInfo; // calculate necessary size
|
|
pRect = &pbm->bounds; // and return
|
|
lRet = (LONG) (pRect->bottom - pRect->top) * (LONG) pbm->rowBytes;
|
|
}
|
|
}
|
|
else
|
|
{ // buffer for bits is provided
|
|
if ( cjSize == 0 ) // is the size reasonable?
|
|
{ // no
|
|
WARNING("lGGOBitmap -- pv != 0 && cjRet == 0\n");
|
|
iError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else // caller provided a buffer for
|
|
{ // the bits representing the glyph
|
|
if (pfc->flXform & XFORM_SINGULAR) // is the transform bad?
|
|
{ // yes! Make a blank 1 x 1 bitmap
|
|
*(BYTE*)pv = 0; // legal for both monochrome
|
|
} // and gray glyphs
|
|
else // notional to device transform ok
|
|
{ // prepare to rasterize glyph
|
|
pfc->gstat.pv = // allocate scratch space
|
|
pvSetMemoryBases(pfc->pgout, pin, !isMonochrome );
|
|
// be sure you free this!
|
|
if ( pfc->gstat.pv == 0 ) // successful allocation?
|
|
{ // no, get out
|
|
WARNING("lGGOBitmap -- pfc->gstat.pv == 0\n");
|
|
iError = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else // memory has been allocated!
|
|
{ // free it when leaving this scope
|
|
if ( isMonochrome ) // monochrome glyph?
|
|
{ // monochrome!, try to rasterize
|
|
if ( fs_ContourScan(pin, pout) != NO_ERR )
|
|
{ // no, get out
|
|
WARNING("lGGOBitmap -- fs_ContourScan failed\n");
|
|
iError = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
else // call the rasterizer to generate
|
|
{ // the antialiased glyph
|
|
if ( fs_ContourGrayScan(pin, pout) != NO_ERR )
|
|
{ // rasterizer unhappy, get out
|
|
WARNING("lGGOBitmap -- fs_ContourGrayScan failed\n");
|
|
iError = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
if ( iError == NO_ERROR ) // everthing ok so far?
|
|
{ // yes
|
|
pbm = &pfc->pgout->bitMapInfo; // calculate size of bitmap
|
|
pRect = &pbm->bounds; // just in case it changed
|
|
lRet = (LONG) (pRect->bottom - pRect->top) * (LONG) pbm->rowBytes;
|
|
lRet = min((LONG) cjSize, lRet); // don't overwrite buffer
|
|
if ( pfc->pgout->bitMapInfo.baseAddr ) // bitmap there?
|
|
{ // yes, copy to caller's buffer
|
|
RtlCopyMemory(pv, pfc->pgout->bitMapInfo.baseAddr, lRet);
|
|
}
|
|
else
|
|
{ // bitmap not there, get out
|
|
WARNING("lGGOBitmap -- invalid pointer to bitmap\n");
|
|
iError = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
V_FREE(pfc->gstat.pv); // free memory before leaving scope
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( iError != NO_ERROR ) // has an error occurred?
|
|
{ // yes
|
|
EngSetLastError( iError ); // regitster the error
|
|
lRet = FD_ERROR; // return value indicates error
|
|
}
|
|
vInitGlyphState( &pfc->gstat ); // invalidate cache
|
|
return( lRet );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* pvSetMemoryBases
|
|
*
|
|
* To release this memory simply do vFreeMemoryBases(&pv); where pv is
|
|
* returned from bSetMemoryBases in ppv
|
|
*
|
|
* Looks into memory request in fs_GlyphInfoType and allocates this memory
|
|
* , than it fills memoryBases in fs_GlyphInputType with pointers to the
|
|
* requested memory
|
|
*
|
|
* History:
|
|
* 08-Nov-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
void *pvSetMemoryBases(fs_GlyphInfoType *pgout,fs_GlyphInputType *pgin,int isGray)
|
|
{
|
|
FS_MEMORY_SIZE adp[MEMORYFRAGMENTS];
|
|
FS_MEMORY_SIZE cjTotal;
|
|
INT i;
|
|
PBYTE pjMem;
|
|
|
|
#define I_LO 5
|
|
#define I_HI 7
|
|
|
|
cjTotal = 0; // total memory to allocate for all fragments
|
|
|
|
|
|
// unroll the loop:
|
|
|
|
// for (i = I_LO; i <= I_HI; i++)
|
|
// {
|
|
// adp[i] = cjTotal;
|
|
// cjTotal += NATURAL_ALIGN(pgin->memorySizes[i]);
|
|
// }
|
|
|
|
adp[5] = cjTotal;
|
|
cjTotal += NATURAL_ALIGN(pgout->memorySizes[5]);
|
|
adp[6] = cjTotal;
|
|
cjTotal += NATURAL_ALIGN(pgout->memorySizes[6]);
|
|
adp[7] = cjTotal;
|
|
cjTotal += NATURAL_ALIGN(pgout->memorySizes[7]);
|
|
if (isGray)
|
|
{
|
|
adp[8] = cjTotal;
|
|
cjTotal += NATURAL_ALIGN(pgout->memorySizes[8]);
|
|
}
|
|
|
|
|
|
//
|
|
// BUGBUG - Bodin needs to llok at this.
|
|
//
|
|
|
|
if (cjTotal == 0)
|
|
{
|
|
cjTotal = 4;
|
|
}
|
|
|
|
if ((pjMem = (PBYTE)PV_ALLOC((ULONG)cjTotal)) == (PBYTE)NULL)
|
|
{
|
|
for (i = I_LO; i <= I_HI; i++)
|
|
pgin->memoryBases[i] = (PBYTE)NULL;
|
|
|
|
RETURN("TTFD!_bSetMemoryBases mem alloc failed\n",NULL);
|
|
}
|
|
|
|
// unroll the loop:
|
|
// set the pointers
|
|
|
|
// for (i = I_LO; i <= I_HI; i++)
|
|
// {
|
|
// if (pgin->memorySizes[i] != (FS_MEMORY_SIZE)0)
|
|
// {
|
|
// pgout->memoryBases[i] = pjMem + adp[i];
|
|
// }
|
|
// else
|
|
// {
|
|
// // if no mem was required set to NULL to prevent accidental use
|
|
//
|
|
// pgout->memoryBases[i] = (PBYTE)NULL;
|
|
// }
|
|
// }
|
|
|
|
if (pgout->memorySizes[5] != (FS_MEMORY_SIZE)0)
|
|
{
|
|
pgin->memoryBases[5] = pjMem + adp[5];
|
|
}
|
|
else
|
|
{
|
|
pgin->memoryBases[5] = (PBYTE)NULL;
|
|
}
|
|
|
|
if (pgout->memorySizes[6] != (FS_MEMORY_SIZE)0)
|
|
{
|
|
pgin->memoryBases[6] = pjMem + adp[6];
|
|
}
|
|
else
|
|
{
|
|
pgin->memoryBases[6] = (PBYTE)NULL;
|
|
}
|
|
|
|
if (pgout->memorySizes[7] != (FS_MEMORY_SIZE)0)
|
|
{
|
|
pgin->memoryBases[7] = pjMem + adp[7];
|
|
}
|
|
else
|
|
{
|
|
pgin->memoryBases[7] = (PBYTE)NULL;
|
|
}
|
|
if (isGray)
|
|
{
|
|
if (pgout->memorySizes[8] != (FS_MEMORY_SIZE)0)
|
|
{
|
|
pgin->memoryBases[8] = pjMem + adp[8];
|
|
}
|
|
else
|
|
{
|
|
pgin->memoryBases[8] = (PBYTE)NULL;
|
|
}
|
|
}
|
|
|
|
return pjMem;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vFreeMemoryBases() *
|
|
* *
|
|
* Releases the memory allocated by bSetMemoryBases. *
|
|
* *
|
|
* History: *
|
|
* 08-Nov-1991 -by- Bodin Dresevic [BodinD] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
VOID vFreeMemoryBases(PVOID * ppv)
|
|
{
|
|
if (*ppv != (PVOID) NULL)
|
|
{
|
|
V_FREE(*ppv);
|
|
*ppv = (PVOID) NULL; // clean up the state and prevent accidental use
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bQueryAdvanceWidths *
|
|
* *
|
|
* A routine to compute advance widths, as long as they're simple enough. *
|
|
*
|
|
* Warnings: !!! if a bug is found in bGetFastAdvanceWidth this routine has *
|
|
* !!! to be changed as well *
|
|
* *
|
|
* Sun 17-Jan-1993 21:23:30 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
typedef struct
|
|
{
|
|
unsigned short Version;
|
|
unsigned short cGlyphs;
|
|
unsigned char PelsHeight[1];
|
|
} LSTHHEADER;
|
|
|
|
|
|
|
|
|
|
BOOL bQueryAdvanceWidths(
|
|
FONTOBJ *pfo,
|
|
ULONG iMode,
|
|
HGLYPH *phg,
|
|
LONG *plWidths,
|
|
ULONG cGlyphs
|
|
)
|
|
{
|
|
VOID
|
|
vQueryFixedPitchAdvanceWidths(
|
|
FONTCONTEXT*
|
|
, USHORT*
|
|
, ULONG
|
|
);
|
|
|
|
FONTCONTEXT *pfc;
|
|
USHORT *psWidths = (USHORT *) plWidths; // True for the cases we handle.
|
|
HDMXTABLE *phdmx;
|
|
sfnt_FontHeader *phead;
|
|
sfnt_HorizontalHeader *phhea;
|
|
sfnt_HorizontalMetrics *phmtx;
|
|
LSTHHEADER *plsth;
|
|
ULONG cHMTX;
|
|
USHORT dxLastWidth;
|
|
LONG dx;
|
|
ULONG ii;
|
|
BOOL bRet;
|
|
ULONG iBias;
|
|
BYTE *pjView;
|
|
|
|
// if this font file is gone we are not gonna be able to answer any questions
|
|
// about it
|
|
|
|
ASSERTDD(pfo->iFile, "bQueryAdvanceWidths, pfo->iFile\n");
|
|
#ifdef FE_SB
|
|
if (((TTC_FONTFILE *)pfo->iFile)->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
#else
|
|
if (((FONTFILE *)pfo->iFile)->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
#endif
|
|
{
|
|
WARNING("ttfd, : bQueryAdvanceWidths, file is gone\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// make sure that there is the font context is initialized
|
|
|
|
if ( pfo->pvProducer == (PVOID) NULL )
|
|
{
|
|
pfo->pvProducer = pfc = ttfdOpenFontContext(pfo);
|
|
}
|
|
else
|
|
{
|
|
pfc = (FONTCONTEXT*) pfo->pvProducer;
|
|
pfc->flFontType = (pfc->flFontType & FO_CHOSE_DEPTH) | pfo->flFontType;
|
|
}
|
|
|
|
if ( pfc == (FONTCONTEXT *) NULL )
|
|
{
|
|
WARNING("winsrv!bQueryAdvanceWidths(): cannot create font context\n");
|
|
return FD_ERROR;
|
|
}
|
|
pfc->pfo = pfo;
|
|
|
|
phdmx = pfc->phdmx;
|
|
|
|
// Make sure we understand the call.
|
|
|
|
if (iMode > QAW_GETEASYWIDTHS)
|
|
return FALSE;
|
|
|
|
// check for quick exit in case of fixed pitch fonts:
|
|
|
|
if (pfc->lD)
|
|
{
|
|
vQueryFixedPitchAdvanceWidths(pfc,psWidths,cGlyphs);
|
|
return TRUE;
|
|
}
|
|
|
|
// Convert the HGLYPHs into glyph indices. We'll do this in place, since
|
|
// GDI allows it.
|
|
|
|
if (pfc->pff->iGlyphSet != GSET_TYPE_GENERAL &&
|
|
pfc->pff->iGlyphSet != GSET_TYPE_GENERAL_NOT_UNICODE &&
|
|
pfc->pff->iGlyphSet != GSET_TYPE_HIGH_BYTE)
|
|
{
|
|
// Perform any preliminary adjustment.
|
|
|
|
switch (pfc->pff->iGlyphSet)
|
|
{
|
|
case GSET_TYPE_MAC_ROMAN:
|
|
|
|
//!!! this is piece of ... stolen from JeanP. This routine should
|
|
//!!! be replaced by a proper NLS routine that takes into acount
|
|
//!!! mac lang id. [bodind]
|
|
|
|
for (ii=0; ii<cGlyphs; ii++)
|
|
phg[ii] = ui16UnicodeToMac((WCHAR) phg[ii]);
|
|
break;
|
|
|
|
case GSET_TYPE_SYMBOL:
|
|
|
|
// hg on the entry is an "ansi" code point for the glyph.
|
|
|
|
iBias = pfc->pff->wcBiasFirst; // offset by high byte of chfirst
|
|
|
|
for (ii=0; ii<cGlyphs; ii++)
|
|
phg[ii] += iBias;
|
|
break;
|
|
|
|
case GSET_TYPE_PSEUDO_WIN:
|
|
break;
|
|
|
|
default:
|
|
RIP("TTFD!_ulGsetType\n");
|
|
break;
|
|
}
|
|
|
|
// Ask the mysterious TT converter to do the conversion.
|
|
|
|
for (ii=0; ii<cGlyphs; ii++)
|
|
{
|
|
pfc->pgin->param.newglyph.characterCode = (uint16) phg[ii];
|
|
pfc->pgin->param.newglyph.glyphIndex = 0;
|
|
|
|
// Compute the glyph index from the character code:
|
|
|
|
if (fs_NewGlyph(pfc->pgin,pfc->pgout) == NO_ERR)
|
|
phg[ii] = pfc->pgout->glyphIndex;
|
|
else
|
|
phg[ii] = 0;
|
|
}
|
|
|
|
// make sure that the cached glyph index in the KEY struct
|
|
// is considered invalid and that fs_NewGlyph is called again
|
|
// when the time comes to hint and rasterize glyphs again
|
|
|
|
vInitGlyphState(&pfc->gstat);
|
|
}
|
|
|
|
// Try to use the HDMX table.
|
|
|
|
if (phdmx != (HDMXTABLE *) NULL)
|
|
{
|
|
USHORT cxExtra = (pfc->flFontType & FO_SIM_BOLD) ? 16 : 0;
|
|
|
|
// while (cGlyphs)
|
|
// *psWidths++ = ((USHORT) phdmx->aucInc[*phg++]) << 4;
|
|
|
|
unroll_here:
|
|
switch (cGlyphs)
|
|
{
|
|
default:
|
|
psWidths[7] = (((USHORT) phdmx->aucInc[phg[7]]) << 4) + cxExtra;
|
|
case 7:
|
|
psWidths[6] = (((USHORT) phdmx->aucInc[phg[6]]) << 4) + cxExtra;
|
|
case 6:
|
|
psWidths[5] = (((USHORT) phdmx->aucInc[phg[5]]) << 4) + cxExtra;
|
|
case 5:
|
|
psWidths[4] = (((USHORT) phdmx->aucInc[phg[4]]) << 4) + cxExtra;
|
|
case 4:
|
|
psWidths[3] = (((USHORT) phdmx->aucInc[phg[3]]) << 4) + cxExtra;
|
|
case 3:
|
|
psWidths[2] = (((USHORT) phdmx->aucInc[phg[2]]) << 4) + cxExtra;
|
|
case 2:
|
|
psWidths[1] = (((USHORT) phdmx->aucInc[phg[1]]) << 4) + cxExtra;
|
|
case 1:
|
|
psWidths[0] = (((USHORT) phdmx->aucInc[phg[0]]) << 4) + cxExtra;
|
|
case 0:
|
|
break;
|
|
}
|
|
if (cGlyphs > 8)
|
|
{
|
|
psWidths += 8;
|
|
phg += 8;
|
|
cGlyphs -= 8;
|
|
goto unroll_here;
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
// Otherwise, try to scale. Pick up the tables.
|
|
|
|
pjView = (BYTE *)pfc->pff->pvView;
|
|
ASSERTDD(pjView, "pjView is NULL 1\n");
|
|
|
|
phead = (sfnt_FontHeader *)(pjView + pfc->ptp->ateReq[IT_REQ_HEAD ].dp);
|
|
phhea = (sfnt_HorizontalHeader *)(pjView + pfc->ptp->ateReq[IT_REQ_HHEAD].dp);
|
|
phmtx = (sfnt_HorizontalMetrics *)(pjView + pfc->ptp->ateReq[IT_REQ_HMTX].dp);
|
|
plsth = (LSTHHEADER *)(
|
|
(pfc->ptp->ateOpt[IT_OPT_LSTH].dp) ?
|
|
(pjView + pfc->ptp->ateOpt[IT_OPT_LSTH ].dp):
|
|
NULL
|
|
);
|
|
|
|
cHMTX = (ULONG) BE_UINT16(&phhea->numberOf_LongHorMetrics);
|
|
dxLastWidth = BE_UINT16(&phmtx[cHMTX-1].advanceWidth);
|
|
|
|
// Try a simple horizontal scaling.
|
|
|
|
if (pfc->flXform & XFORM_HORIZ)
|
|
{
|
|
LONG cxExtra = (pfc->flFontType & FO_SIM_BOLD) ? 0x18000L : 0x8000L;
|
|
LONG xScale;
|
|
LONG lEmHt = pfc->lEmHtDev;
|
|
|
|
//
|
|
// An attempt was made to use fractional widths for ATM Type 1 fonts
|
|
// converted to TrueType to ensure better WYSIWYG when the real ATM
|
|
// font is downloaded for printing, but the converted font is used
|
|
// for the display.
|
|
//
|
|
// However, this introduces a WYSIWYG problem if the converted
|
|
// TrueType font is used for both display and printer output.
|
|
// If we allow fractional widths, then apps like Winword have a
|
|
// problem because they cache the integral widths returned by
|
|
// GetCharWidths. They assume that the sum of the intergral widths
|
|
// will match GetTextExtent/TextOut.
|
|
//
|
|
//if (!(pfc->pff->fl & FF_TYPE_1_CONVERSION))
|
|
//{
|
|
// cxExtra = (pfc->flFontType & FO_SIM_BOLD) ? 0x18000L : 0x8000L;
|
|
//}
|
|
//else // for t1's we want more precission:
|
|
//{
|
|
// cxExtra = (pfc->flFontType & FO_SIM_BOLD) ? 0x10800L : 0x0800L;
|
|
//}
|
|
//
|
|
cxExtra = (pfc->flFontType & FO_SIM_BOLD) ? 0x18000L : 0x8000L;
|
|
|
|
// See if there is cause for worry.
|
|
|
|
if
|
|
(
|
|
!(pfc->flXform & XFORM_POSITIVE_SCALE)
|
|
|| ((((BYTE *) &phead->flags)[1] & 0x14)==0) // Bits indicating nonlinearity.
|
|
|| (pfc->ptp->ateOpt[IT_OPT_LSTH].cj == 0)
|
|
)
|
|
{
|
|
plsth = (LSTHHEADER *) NULL;
|
|
}
|
|
|
|
// OK, let's scale using the FIXED transform.
|
|
|
|
xScale = pfc->mx.transform[0][0];
|
|
if (xScale < 0)
|
|
xScale = -xScale;
|
|
|
|
bRet = TRUE;
|
|
for (ii=0; ii<cGlyphs; ii++,phg++,psWidths++)
|
|
{
|
|
if
|
|
(
|
|
(plsth != (LSTHHEADER *) NULL)
|
|
&& (lEmHt < plsth->PelsHeight[*phg])
|
|
)
|
|
{
|
|
*psWidths = 0xFFFF;
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (*phg < cHMTX)
|
|
dx = (LONG) BE_UINT16(&phmtx[*phg].advanceWidth);
|
|
else
|
|
dx = (LONG) dxLastWidth;
|
|
|
|
//
|
|
// An attempt was made to use fractional widths for ATM Type 1 fonts
|
|
// converted to TrueType to ensure better WYSIWYG when the real ATM
|
|
// font is downloaded for printing, but the converted font is used
|
|
// for the display.
|
|
//
|
|
// However, this introduces a WYSIWYG problem if the converted
|
|
// TrueType font is used for both display and printer output.
|
|
// If we allow fractional widths, then apps like Winword have a
|
|
// problem because they cache the integral widths returned by
|
|
// GetCharWidths. They assume that the sum of the intergral widths
|
|
// will match GetTextExtent/TextOut.
|
|
//
|
|
//if (!(pfc->pff->fl & FF_TYPE_1_CONVERSION))
|
|
//{
|
|
// *psWidths = (USHORT) (((xScale * dx + cxExtra) >> 12) & 0xFFF0);
|
|
//}
|
|
//else
|
|
//{
|
|
//// type 1 font, return fractional widths
|
|
//
|
|
// *psWidths = (USHORT) ((xScale * dx + cxExtra) >> 12);
|
|
//}
|
|
//
|
|
*psWidths = (USHORT) (((xScale * dx + cxExtra) >> 12) & 0xFFF0);
|
|
}
|
|
}
|
|
return(bRet);
|
|
}
|
|
|
|
// Must be some random transform. In this case, vComputeMaxGlyph computes
|
|
// pfc->efBase, which we will use here.
|
|
|
|
else
|
|
{
|
|
USHORT cxExtra = (pfc->flFontType & FO_SIM_BOLD) ? 16 : 0;
|
|
|
|
for (ii=0; ii<cGlyphs; ii++,phg++,psWidths++)
|
|
{
|
|
if (*phg < cHMTX)
|
|
dx = BE_UINT16(&phmtx[*phg].advanceWidth);
|
|
else
|
|
dx = dxLastWidth;
|
|
|
|
*psWidths = lCvt(*(EFLOAT *) &pfc->efBase,(LONG) dx) + cxExtra;
|
|
}
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vQueryFixedPitchAdvanceWidths
|
|
*
|
|
* quick optimized routine for fixed pitch fonts
|
|
*
|
|
* History:
|
|
* 08-Nov-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
VOID vQueryFixedPitchAdvanceWidths(
|
|
FONTCONTEXT *pfc,
|
|
USHORT *psWidths,
|
|
ULONG cGlyphs
|
|
)
|
|
{
|
|
USHORT fxD = (USHORT)(pfc->lD << 4);
|
|
|
|
vInitGlyphState(&pfc->gstat);
|
|
|
|
// while (cGlyphs)
|
|
// *psWidths++ = ((USHORT) phdmx->aucInc[*phg++]) << 4;
|
|
|
|
fixed_unroll_here:
|
|
switch (cGlyphs)
|
|
{
|
|
default:
|
|
psWidths[7] = fxD;
|
|
case 7:
|
|
psWidths[6] = fxD;
|
|
case 6:
|
|
psWidths[5] = fxD;
|
|
case 5:
|
|
psWidths[4] = fxD;
|
|
case 4:
|
|
psWidths[3] = fxD;
|
|
case 3:
|
|
psWidths[2] = fxD;
|
|
case 2:
|
|
psWidths[1] = fxD;
|
|
case 1:
|
|
psWidths[0] = fxD;
|
|
case 0:
|
|
break;
|
|
}
|
|
if (cGlyphs > 8)
|
|
{
|
|
psWidths += 8;
|
|
cGlyphs -= 8;
|
|
goto fixed_unroll_here;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bGetFastAdvanceWidth
|
|
*
|
|
*
|
|
* Effects: retrieves the same result as bQueryAdvanceWidth, except it
|
|
* ignores adding 1 for EMBOLDENING and it does not do anything
|
|
* for non horiz. xforms
|
|
*
|
|
* Warnings: !!! if a bug is found in bQueryAdvanceWidth this routine has to
|
|
* !!! changed as well
|
|
*
|
|
* History:
|
|
* 25-Mar-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
|
|
BOOL bGetFastAdvanceWidth(
|
|
FONTCONTEXT *pfc,
|
|
ULONG ig, // glyph index
|
|
FIX *pfxD // result in 28.4
|
|
)
|
|
{
|
|
HDMXTABLE *phdmx = pfc->phdmx;
|
|
sfnt_FontHeader *phead;
|
|
sfnt_HorizontalHeader *phhea;
|
|
sfnt_HorizontalMetrics *phmtx;
|
|
LSTHHEADER *plsth;
|
|
ULONG cHMTX;
|
|
USHORT dxLastWidth;
|
|
LONG dx;
|
|
BOOL bRet;
|
|
BYTE *pjView;
|
|
|
|
ASSERTDD(pfc->flXform & XFORM_HORIZ, "bGetFastAdvanceWidth xform\n");
|
|
|
|
if (phdmx != (HDMXTABLE *) NULL)
|
|
{
|
|
*pfxD = (((FIX) phdmx->aucInc[ig]) << 4);
|
|
return(TRUE);
|
|
}
|
|
|
|
// Otherwise, try to scale. Pick up the tables.
|
|
|
|
|
|
pjView = (BYTE *)pfc->pff->pvView;
|
|
ASSERTDD(pjView, "pjView is NULL 1\n");
|
|
|
|
phead = (sfnt_FontHeader *)(pjView + pfc->ptp->ateReq[IT_REQ_HEAD ].dp);
|
|
phhea = (sfnt_HorizontalHeader *)(pjView + pfc->ptp->ateReq[IT_REQ_HHEAD].dp);
|
|
phmtx = (sfnt_HorizontalMetrics *)(pjView + pfc->ptp->ateReq[IT_REQ_HMTX].dp);
|
|
plsth = (LSTHHEADER *)(
|
|
(pfc->ptp->ateOpt[IT_OPT_LSTH].dp) ?
|
|
(pjView + pfc->ptp->ateOpt[IT_OPT_LSTH ].dp):
|
|
NULL
|
|
);
|
|
|
|
cHMTX = (ULONG) BE_UINT16(&phhea->numberOf_LongHorMetrics);
|
|
dxLastWidth = BE_UINT16(&phmtx[cHMTX-1].advanceWidth);
|
|
|
|
// See if there is cause for worry.
|
|
|
|
if
|
|
(
|
|
!(pfc->flXform & XFORM_POSITIVE_SCALE)
|
|
|| ((((BYTE *) &phead->flags)[1] & 0x14)==0) // Bits indicating nonlinearity.
|
|
|| (pfc->ptp->ateOpt[IT_OPT_LSTH].cj == 0)
|
|
)
|
|
{
|
|
plsth = (LSTHHEADER *) NULL;
|
|
}
|
|
|
|
// OK, let's scale using the FIXED transform.
|
|
|
|
bRet = TRUE;
|
|
if
|
|
(
|
|
(plsth != (LSTHHEADER *) NULL)
|
|
&& (pfc->lEmHtDev < plsth->PelsHeight[ig])
|
|
)
|
|
{
|
|
*pfxD = 0xFFFFFFFF;
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (ig < cHMTX)
|
|
dx = (LONG) BE_UINT16(&phmtx[ig].advanceWidth);
|
|
else
|
|
dx = (LONG) dxLastWidth;
|
|
|
|
//
|
|
// An attempt was made to use fractional widths for ATM Type 1 fonts
|
|
// converted to TrueType to ensure better WYSIWYG when the real ATM
|
|
// font is downloaded for printing, but the converted font is used
|
|
// for the display.
|
|
//
|
|
// However, this introduces a WYSIWYG problem if the converted
|
|
// TrueType font is used for both display and printer output.
|
|
// If we allow fractional widths, then apps like Winword have a
|
|
// problem because they cache the integral widths returned by
|
|
// GetCharWidths. They assume that the sum of the intergral widths
|
|
// will match GetTextExtent/TextOut.
|
|
//
|
|
//if (!(pfc->pff->fl & FF_TYPE_1_CONVERSION))
|
|
//{
|
|
// *pfxD = (FIX) (((pfc->mx.transform[0][0] * dx + 0x8000L) >> 12) & 0xFFFFFFF0);
|
|
//}
|
|
//else
|
|
//{
|
|
//// t1 conversion, use fractional width, this is what ps driver does
|
|
//
|
|
// *pfxD = (FIX) ((pfc->mx.transform[0][0] * dx + 0x0800L) >> 12);
|
|
//}
|
|
//
|
|
*pfxD = (FIX) (((pfc->mx.transform[0][0] * dx + 0x8000L) >> 12) & 0xFFFFFFF0);
|
|
}
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vFillGLYPHDATA_ErrRecover
|
|
*
|
|
* Effects: error recovery routine, if rasterizer messed up just
|
|
* provide linearly scaled values with blank bitmap.
|
|
*
|
|
* History:
|
|
* 24-Jun-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
VOID vFillGLYPHDATA_ErrRecover(
|
|
HGLYPH hg,
|
|
ULONG ig,
|
|
FONTCONTEXT *pfc,
|
|
GLYPHDATA *pgldt // OUT
|
|
)
|
|
{
|
|
|
|
extern VOID vGetNotionalGlyphMetrics(FONTCONTEXT*, ULONG, NOT_GM*);
|
|
NOT_GM ngm; // notional glyph data
|
|
|
|
pgldt->gdf.pgb = NULL; // may get changed by the calling routine if bits requested too
|
|
pgldt->hg = hg;
|
|
|
|
// this is a fake blank 1x1 bitmap, no ink
|
|
|
|
pgldt->rclInk.left = 0;
|
|
pgldt->rclInk.top = 0;
|
|
pgldt->rclInk.right = 0;
|
|
pgldt->rclInk.bottom = 0;
|
|
|
|
pgldt->fxInkTop = 0;
|
|
pgldt->fxInkBottom = 0;
|
|
|
|
// go on to compute the positioning info:
|
|
|
|
vGetNotionalGlyphMetrics(pfc,ig,&ngm);
|
|
|
|
if (pfc->flXform & XFORM_HORIZ) // scaling only
|
|
{
|
|
Fixed fxMxx = pfc->mx.transform[0][0];
|
|
if (fxMxx < 0)
|
|
fxMxx = -fxMxx;
|
|
|
|
// bGetFastAdvanceWidth returns the same aw that would get
|
|
// computed by bQueryAdvanceWidths and propagated to an api
|
|
// level through GetTextExtent and GetCharWidths. We have to
|
|
// fill in the same aw for consistency reasons.
|
|
// This also has to be done for win31 compatibility.
|
|
|
|
if (pfc->lD)
|
|
{
|
|
pgldt->fxD = LTOFX(pfc->lD);
|
|
}
|
|
else
|
|
{
|
|
if (!bGetFastAdvanceWidth(pfc,ig, &pgldt->fxD))
|
|
{
|
|
// just provide something reasonable, force linear scaling
|
|
// even if we would not normally do it.
|
|
|
|
pgldt->fxD = FixMul(ngm.sD,pfc->mx.transform[0][0]) << 4;
|
|
}
|
|
}
|
|
|
|
pgldt->ptqD.x.HighPart = (LONG)pgldt->fxD;
|
|
pgldt->ptqD.x.LowPart = 0;
|
|
|
|
if (pfc->mx.transform[0][0] < 0)
|
|
pgldt->fxD = - pgldt->fxD; // this is an absolute value
|
|
|
|
pgldt->ptqD.y.HighPart = 0;
|
|
pgldt->ptqD.y.LowPart = 0;
|
|
|
|
pgldt->fxA = FixMul(fxMxx, (LONG)ngm.sA) << 4;
|
|
pgldt->fxAB = FixMul(fxMxx, (LONG)ngm.xMax) << 4;
|
|
|
|
}
|
|
else // non trivial information
|
|
{
|
|
// here we will just xform the notional space data:
|
|
|
|
// xforms are computed by simple multiplication
|
|
|
|
pgldt->fxD = fxLTimesEf(&pfc->efBase, (LONG)ngm.sD);
|
|
pgldt->fxA = fxLTimesEf(&pfc->efBase, (LONG)ngm.sA);
|
|
pgldt->fxAB = fxLTimesEf(&pfc->efBase, (LONG)ngm.xMax);
|
|
|
|
vLTimesVtfl((LONG)ngm.sD, &pfc->vtflBase, &pgldt->ptqD);
|
|
}
|
|
|
|
// finally check if the glyphdata will need to get modified because of the
|
|
// emboldening simulation:
|
|
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
{
|
|
pgldt->fxD += LTOFX(1); // this is the absolute value by def
|
|
|
|
// go on to compute the positioning info:
|
|
|
|
if (pfc->flXform & XFORM_HORIZ) // scaling only
|
|
{
|
|
pgldt->ptqD.x.HighPart = (LONG)pgldt->fxD;
|
|
|
|
if (pfc->mx.transform[0][0] < 0)
|
|
pgldt->ptqD.x.HighPart = - pgldt->ptqD.x.HighPart;
|
|
|
|
}
|
|
else // non trivial information
|
|
{
|
|
// add a unit vector in the baseline direction to each char inc vector.
|
|
// This is consistent with fxD += LTOFX(1) and compatible with win31.
|
|
// This makes sense.
|
|
|
|
vAddPOINTQF(&pgldt->ptqD,&pfc->ptqUnitBase);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* LONG lGetGlyphBitmapErrRecover
|
|
*
|
|
* Effects: error recovery routine, if rasterizer messed up just
|
|
* provide linearly scaled values with blank bitmap.
|
|
*
|
|
* History:
|
|
* Thu 24-Jun-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG lGetGlyphBitmapErrRecover (
|
|
FONTCONTEXT *pfc,
|
|
HGLYPH hglyph,
|
|
GLYPHDATA *pgd,
|
|
PVOID pv,
|
|
BOOL bMinBmp
|
|
)
|
|
{
|
|
LONG cjGlyphData;
|
|
GLYPHDATA gd; // Scummy hack
|
|
FS_ENTRY iRet;
|
|
ULONG ig; // <--> hglyph
|
|
|
|
|
|
ASSERTDD(hglyph != HGLYPH_INVALID, "lGetGlyphBitmap, hglyph == -1\n");
|
|
ASSERTDD(pfc == pfc->pff->pfcLast, "pfc! = pfcLast\n");
|
|
|
|
// return a small 1x1 bitmap, which will be blank, i.e. all bits will be off
|
|
// this prevents having to insert an if(cx && cy) check to a time critical
|
|
// loop in all device drivers before calling DrawGlyph routine.
|
|
|
|
if (!bMinBmp)
|
|
{
|
|
// we shall be returning a big empty glyph bitmap pfc->lD x cyMax
|
|
|
|
cjGlyphData = (LONG)pfc->cjGlyphMax;
|
|
}
|
|
else // usual case
|
|
{
|
|
ASSERTDD(pfc->flFontType & FO_CHOSE_DEPTH,"Depth Not Chosen Yet!\n");
|
|
cjGlyphData = CJGD(1,1,pfc);
|
|
}
|
|
|
|
if ( (pgd == NULL) && (pv == NULL))
|
|
return cjGlyphData;
|
|
|
|
// at this time we know that the caller wants the whole GLYPHDATA with
|
|
// bitmap bits, or maybe just the glypdata without the bits.
|
|
|
|
if ( pgd == NULL )
|
|
{
|
|
pgd = &gd;
|
|
}
|
|
|
|
// compute the glyph index from the character code:
|
|
|
|
vCharacterCode(pfc->pff,hglyph,pfc->pgin);
|
|
|
|
if ((iRet = fs_NewGlyph(pfc->pgin, pfc->pgout)) != NO_ERR)
|
|
{
|
|
V_FSERROR(iRet);
|
|
return FD_ERROR; // even backup funcion can fail
|
|
}
|
|
|
|
// return the glyph index corresponding to this hglyph:
|
|
|
|
ig = pfc->pgout->glyphIndex;
|
|
|
|
vFillGLYPHDATA_ErrRecover(
|
|
hglyph,
|
|
ig,
|
|
pfc,
|
|
pgd
|
|
);
|
|
|
|
// the caller wants the bits too
|
|
|
|
if ( pv != NULL )
|
|
{
|
|
GLYPHBITS *pgb = (GLYPHBITS *)pv;
|
|
|
|
if (!bMinBmp)
|
|
{
|
|
pgb->sizlBitmap.cx = pfc->lD;
|
|
pgb->sizlBitmap.cy = pfc->yMax - pfc->yMin;
|
|
|
|
pgb->ptlOrigin.x = 0;
|
|
pgb->ptlOrigin.y = pfc->yMin;
|
|
|
|
// clear the whole destination, i.e. fill in a blank bitmap
|
|
|
|
RtlZeroMemory(pgb->aj, pfc->cjGlyphMax - offsetof(GLYPHBITS,aj));
|
|
}
|
|
else // usual case
|
|
{
|
|
// return blank 1x1 bitmap
|
|
|
|
pgb->ptlOrigin.x = pfc->ptlSingularOrigin.x;
|
|
pgb->ptlOrigin.y = pfc->ptlSingularOrigin.y;
|
|
|
|
pgb->sizlBitmap.cx = 1; // cheating
|
|
pgb->sizlBitmap.cy = 1; // cheating
|
|
|
|
pgb->aj[0] = (BYTE)0; // fill in a blank 1x1 bmp
|
|
}
|
|
|
|
pgd->gdf.pgb = pgb;
|
|
}
|
|
|
|
if (!bMinBmp) // need to fix this for err recover case
|
|
{
|
|
// need to fix glyph data because we may have shaved off some columns
|
|
|
|
ASSERTDD((pfc->lD << 4) == pgd->fxD, "err recover, fxD bogus\n");
|
|
if (pgd->fxA < 0)
|
|
{
|
|
pgd->fxA = 0;
|
|
// pgd->rclInk.left = 0;
|
|
}
|
|
if (pgd->fxAB > pgd->fxD)
|
|
{
|
|
pgd->fxAB = pgd->fxD;
|
|
// pgd->rclInk.right = pfc->lD;
|
|
}
|
|
}
|
|
|
|
return(cjGlyphData);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vTtfdEmboldenBitmapInPlace
|
|
*
|
|
* emboldens fixed pitch bitmap in place. Assumes that the
|
|
* scans are already wide enough to contain bold font.
|
|
*
|
|
* History:
|
|
* 28-Feb-1994 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vTtfdEmboldenBitmapInPlace(FONTCONTEXT *pfc, GLYPHBITS *pgb)
|
|
{
|
|
ULONG cjScanDst;
|
|
register BYTE *pjScan;
|
|
register BYTE *pjD;
|
|
BYTE *pjScanEnd;
|
|
register ULONG iLast = (pgb->sizlBitmap.cx - 1) >> 3;
|
|
|
|
ULONG iMask = (pgb->sizlBitmap.cx - 1) & 7;
|
|
BYTE jMask = iMask ? gjMask[iMask] : (BYTE)0;
|
|
|
|
ASSERTDD(!IS_GRAY(pfc),"Monochrome Images Only Please!\n");
|
|
cjScanDst = CJ_MONOCHROME_SCAN(pgb->sizlBitmap.cx);
|
|
pjScanEnd = pgb->aj + cjScanDst * pgb->sizlBitmap.cy;
|
|
|
|
for (pjScan = pgb->aj; pjScan < pjScanEnd; pjScan += cjScanDst)
|
|
{
|
|
// have to do it backwards so as not to overwrite the source:
|
|
|
|
pjD = &pjScan[iLast];
|
|
*pjD &= jMask; // clean any garbage in the destination
|
|
|
|
for ( ; pjD > pjScan; pjD--)
|
|
{
|
|
*pjD = (pjD[-1] << 7) | (*pjD >> 1) | *pjD;
|
|
}
|
|
|
|
// do the first byte in a scan, must do out of the loop,
|
|
// must not read backwards beyond the beginning of the scan
|
|
|
|
*pjD = (*pjD >> 1) | *pjD;
|
|
}
|
|
}
|
|
|
|
#if(WINVER < 0x0400)
|
|
|
|
typedef struct tagFONTSIGNATURE
|
|
{
|
|
DWORD fsUsb[4];
|
|
DWORD fsCsb[2];
|
|
} FONTSIGNATURE, *PFONTSIGNATURE,FAR *LPFONTSIGNATURE;
|
|
#endif
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* VOID vGetFontSignature(HFF hff, FONTSIGNATURE *pfs);
|
|
*
|
|
*
|
|
* Effects: If font file contains the font signature,
|
|
* it copies the data out, else computes it using win95 mechanism.
|
|
*
|
|
* History:
|
|
* 10-Jan-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vGetFontSignature(FONTFILE *pff, FONTSIGNATURE *pfs)
|
|
{
|
|
pff;
|
|
pfs;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* DWORD ttfdQueryLpkInfo
|
|
*
|
|
*
|
|
* Effects: returns per font information needed to support various new
|
|
* multilingual api's invented by DavidMS from Chicago team
|
|
*
|
|
* History:
|
|
* 10-Jan-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
// called by GetFontLanguageInfo
|
|
|
|
#define LPK_GCP_FLAGS 1
|
|
#define LPK_FONTSIGNATURE 2
|
|
|
|
DWORD ttfdQueryLpkInfo(
|
|
FONTFILE *pff,
|
|
ULONG ulFont,
|
|
ULONG ulMode,
|
|
ULONG cj,
|
|
BYTE *pj
|
|
)
|
|
{
|
|
FONTSIGNATURE *pfs = (FONTSIGNATURE *)pj;
|
|
|
|
switch (ulMode)
|
|
{
|
|
case LPK_GCP_FLAGS:
|
|
return 0;
|
|
case LPK_FONTSIGNATURE:
|
|
if (pj)
|
|
{
|
|
vGetFontSignature(pff, pfs);
|
|
return sizeof(FONTSIGNATURE);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Routine Name:
|
|
*
|
|
* vDumpGrayGLYPHBITS
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* Dumps a 4bpp gray glyph bitmap to the debugging screen
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pgb -- pointer to a gray GLYPHBITS structure
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void vDumpGrayGLYPHBITS(GLYPHBITS *pgb)
|
|
{
|
|
#define CH_TOP_LEFT_CORNER '\xDA'
|
|
#define CH_HORIZONTAL_BAR '\xC4'
|
|
#define CH_VERTICAL_BAR '\xB3'
|
|
#define CH_PIXEL_ON '\x02'
|
|
#define CH_PIXEL_OFF '\xFA'
|
|
|
|
BYTE *pj8, *pj, *pjNext, *pjEnd;
|
|
int cjScan, i, k, c8, c4, cj;
|
|
static char achGray[16] = {
|
|
CH_PIXEL_OFF,
|
|
'1','2','3','4','5','6','7','8','9','a','b','c','d','e',
|
|
CH_PIXEL_ON
|
|
};
|
|
|
|
TtfdDbgPrint(
|
|
"\n\n"
|
|
"ptlOrigin = (%d,%d)\n"
|
|
"sizlBitmap = (%d,%d)\n"
|
|
"\n\n"
|
|
, pgb->ptlOrigin.x
|
|
, pgb->ptlOrigin.y
|
|
, pgb->sizlBitmap.cx
|
|
, pgb->sizlBitmap.cy
|
|
);
|
|
cjScan = (pgb->sizlBitmap.cx + 1)/2;
|
|
cj = cjScan * pgb->sizlBitmap.cy;
|
|
TtfdDbgPrint("\n\n ");
|
|
for (i = 0, k = 0; i < pgb->sizlBitmap.cx; i++, k++)
|
|
{
|
|
k = (k > 9) ? 0 : k;
|
|
TtfdDbgPrint("%1d", k);
|
|
}
|
|
TtfdDbgPrint("\n %c",CH_TOP_LEFT_CORNER);
|
|
for (i = 0; i < pgb->sizlBitmap.cx; i++)
|
|
{
|
|
TtfdDbgPrint("%c",CH_HORIZONTAL_BAR);
|
|
}
|
|
TtfdDbgPrint("\n");
|
|
c8 = pgb->sizlBitmap.cx / 2;
|
|
c4 = pgb->sizlBitmap.cx % 2;
|
|
for (
|
|
pj = pgb->aj, pjNext=pj+cjScan , pjEnd=pjNext+cj, k=0
|
|
; pjNext < pjEnd
|
|
; pj=pjNext , pjNext+=cjScan, k++
|
|
)
|
|
{
|
|
k = (k > 9) ? 0 : k;
|
|
TtfdDbgPrint("%1d%c",k,CH_VERTICAL_BAR);
|
|
for (pj8 = pj+c8 ; pj < pj8; pj++)
|
|
{
|
|
TtfdDbgPrint("%c%c", achGray[*pj>>4], achGray[*pj & 0xf]);
|
|
}
|
|
if (c4)
|
|
{
|
|
TtfdDbgPrint("%c%c", achGray[*pj>>4], achGray[*pj & 0xf]);
|
|
}
|
|
TtfdDbgPrint("\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vEmboldenGrayBitmap
|
|
*
|
|
* History:
|
|
* Wed 22-Feb-1995 13:21:55 by Kirk Olynyk [kirko]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void vEmboldenGrayBitmap(FONTCONTEXT *pfc, GLYPHBITS *pgb)
|
|
{
|
|
BYTE *pj;
|
|
BYTE pixel_A, pixel_B, pixel_C, pixel_D;
|
|
int cx = pgb->sizlBitmap.cx;
|
|
BYTE jMask = (cx & 1) ? 0x0f : 0xff;
|
|
unsigned cjScan = (cx + 1)/2; // 4 bpp
|
|
BYTE *pjScan = pgb->aj;
|
|
BYTE *pjOut = pjScan + cjScan * pgb->sizlBitmap.cy;
|
|
#if DBG
|
|
if (gflTtfdDebug & DEBUG_GRAY)
|
|
{
|
|
TtfdDbgPrint(
|
|
"vEmboldenGrayBitmap(\n"
|
|
" FONTCONTEXT *pfc = %-#x\n"
|
|
" GLYPHBITS *pgb = %-#x\n"
|
|
")\n"
|
|
, pfc, pgb
|
|
);
|
|
TtfdDbgPrint(
|
|
" cx = %d\n"
|
|
" cy = %d\n"
|
|
" jMask = %-#x\n"
|
|
" cjScan = %u\n"
|
|
" pjScan = %-#x\n"
|
|
" pjOut = %-#x\n\n"
|
|
, cx
|
|
, pgb->sizlBitmap.cy
|
|
, jMask
|
|
, cjScan
|
|
, pjScan
|
|
, pjOut
|
|
);
|
|
TtfdDbgPrint("This is the bitmap BEFORE emboldening...\n\n");
|
|
vDumpGrayGLYPHBITS(pgb);
|
|
EngDebugBreak();
|
|
}
|
|
#endif
|
|
|
|
for (pjScan = pgb->aj ; pjScan < pjOut ; pjScan += cjScan)
|
|
{
|
|
// set pj to point to the last byte in the scan
|
|
|
|
pj = pjScan + cjScan - 1;
|
|
|
|
/***************************************************************
|
|
* Before emboldening,the origninal image had scans of width *
|
|
* pgb->sizlBitmap.cx - 1. Any pixels beyond this limit are *
|
|
* currently garbage and must be cleared. This means that *
|
|
* if the width of the emboldened bitmap is even then the low*
|
|
* nibble of the last byte of each scan must be cleared *
|
|
* otherwise the last byte of each scan must be cleared. *
|
|
***************************************************************/
|
|
|
|
*pj &= jMask;
|
|
|
|
/***************************************************
|
|
* start at the right edge of the scan and work *
|
|
* back toward the left edge *
|
|
***************************************************/
|
|
|
|
pixel_A = *pj >> 4;
|
|
pixel_B = *pj & 15;
|
|
for ( ; pjScan < pj; pj--)
|
|
{
|
|
pixel_C = pixel_A;
|
|
pixel_D = pixel_B;
|
|
pixel_A = *(pj-1) >> 4;
|
|
pixel_B = *(pj-1) & 15;
|
|
/*************************************************
|
|
* *
|
|
* pj - 1 pj *
|
|
* +----+----+-----+-----+ *
|
|
* | | | *
|
|
* | A B | C D | *
|
|
* | | | *
|
|
* | | | *
|
|
* +----+----+-----+-----+ *
|
|
* *
|
|
* D = D + C; *
|
|
* if (D > 15) D = 15; *
|
|
* C = C + B; *
|
|
* if (C > 15) C = 15; *
|
|
* *
|
|
*************************************************/
|
|
|
|
if ((pixel_D += pixel_C) > 15)
|
|
{
|
|
pixel_D = 15;
|
|
}
|
|
if ((pixel_C += pixel_B) > 15)
|
|
{
|
|
pixel_C = 15;
|
|
}
|
|
*pj = pixel_D + 16 * pixel_C;
|
|
}
|
|
|
|
// Do the first pixel outside the loop
|
|
|
|
if ((pixel_B += pixel_A) > 15)
|
|
{
|
|
pixel_B = 15;
|
|
}
|
|
*pj = pixel_B + 16 * pixel_A;
|
|
}
|
|
#if DBG
|
|
if (gflTtfdDebug & DEBUG_GRAY)
|
|
{
|
|
TtfdDbgPrint("This is the bitmap AFTER emboldening...\n\n");
|
|
vDumpGrayGLYPHBITS(pgb);
|
|
TtfdDbgPrint("\n\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vGCGB
|
|
*
|
|
* Called by: vCopyGrayBits, vMakeAFixedPitchGrayBitmap
|
|
*
|
|
* void General Copy Gray Bits
|
|
*
|
|
* History:
|
|
* Wed 22-Feb-1995 13:14:36 by Kirk Olynyk [kirko]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vGCGB(
|
|
FONTCONTEXT *pfc, // pointer to the FONTCONTEXT this is used
|
|
// to determine if the font is bold simulated
|
|
GLYPHBITS *pgb, // pointer to destination GRAY GLYPHBITS structure
|
|
// In the case where dY is zero, all the fields
|
|
// of the GLYPHBITS structure must be filled
|
|
// this includes sizlBitmap and the bits; in
|
|
// the case where dY is non-zero, the
|
|
// sizlBitmap components are precomputed and
|
|
// must not be touched.
|
|
BYTE *pjSrc, // pointer to TT gray scale bitmap
|
|
// This is 8-bit per pixel bitmap whose scans
|
|
// are aligned on 4-byte multiples. The values
|
|
// stored in the bitmaps are in the range
|
|
// 0-16. In order to fit 17 levels in the 4 bit
|
|
// per pixel destination we reduce the level
|
|
// value by 1, except for zero which is left alone.
|
|
GMC *pgmc, // pointer to the glyph-metric-correction structure
|
|
// which has information on how to "shave" the
|
|
// bitmap so that it does not get above a guaranteed
|
|
// value
|
|
LONG dY // vertical offset into destination bitmap used
|
|
// for "special fixed pitch fonts" like Lucida
|
|
// Console.
|
|
)
|
|
{
|
|
unsigned cxDst; // width of destination bitmap
|
|
unsigned cjSrcScan; // count of bytes in a source scan including
|
|
// padding out to nearest 4-byte multiple boundary
|
|
unsigned cjDstScan; // count of bytes in a desintation scan including
|
|
// padding out to nearest byte boundary
|
|
|
|
BYTE j, *pjDst, *pjSrcScan, *pjDstScan, *pjDstScanEnd;
|
|
|
|
static const BYTE ajGray[17] = {0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
|
|
|
|
#if DBG
|
|
if (gflTtfdDebug & DEBUG_GRAY)
|
|
{
|
|
typedef struct _FLAGDEF {
|
|
char *psz; // description
|
|
FLONG fl; // flag
|
|
} FLAGDEF;
|
|
FLAGDEF *pfd;
|
|
FLONG fl;
|
|
|
|
static FLAGDEF afdFO[] = {
|
|
{"FO_TYPE_RASTER ", FO_TYPE_RASTER },
|
|
{"FO_TYPE_DEVICE ", FO_TYPE_DEVICE },
|
|
{"FO_TYPE_TRUETYPE", FO_TYPE_TRUETYPE},
|
|
{"FO_SIM_BOLD ", FO_SIM_BOLD },
|
|
{"FO_SIM_ITALIC ", FO_SIM_ITALIC },
|
|
{"FO_EM_HEIGHT ", FO_EM_HEIGHT },
|
|
{"FO_GRAY16 ", FO_GRAY16 },
|
|
{"FO_NOGRAY16 ", FO_NOGRAY16 },
|
|
{"FO_NOHINTS ", FO_NOHINTS },
|
|
{"FO_NO_CHOICE ", FO_NO_CHOICE },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
TtfdDbgPrint(
|
|
"vGCGB(\n"
|
|
" FONTCONTEXT *pfc = %-#x\n"
|
|
" GLYPHBITS *pgb = %-#x\n"
|
|
" BYTE *pjSrc = %-#x\n"
|
|
" GMC *pgmc = %-#x\n"
|
|
" LONG dY = %d\n"
|
|
")\n"
|
|
, pfc, pgb, pjSrc, pgmc, dY
|
|
);
|
|
TtfdDbgPrint(
|
|
"---"
|
|
" GMC\n"
|
|
"\n"
|
|
" dyTop = %u\n"
|
|
" dyBottom = %u\n"
|
|
" dxLeft = %u\n"
|
|
" dxRight = %u\n"
|
|
" cxCor = %u\n"
|
|
" cyCor = %u\n"
|
|
"---\n\n"
|
|
, pgmc->dyTop
|
|
, pgmc->dyBottom
|
|
, pgmc->dxLeft
|
|
, pgmc->dxRight
|
|
, pgmc->cxCor
|
|
, pgmc->cyCor
|
|
);
|
|
fl = pfc->flFontType;
|
|
TtfdDbgPrint("pfc->flFontType = %-#x\n",pfc->flFontType);
|
|
for ( pfd=afdFO; pfd->psz; pfd++ )
|
|
{
|
|
if (fl & pfd->fl)
|
|
{
|
|
TtfdDbgPrint(" %s\n", pfd->psz);
|
|
fl &= ~pfd->fl;
|
|
}
|
|
}
|
|
if ( fl )
|
|
{
|
|
TtfdDbgPrint(" UNKNOWN FLAGS\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ASSERTDD(
|
|
pfc->flFontType & FO_CHOSE_DEPTH
|
|
,"We haven't decided about pixel depth\n"
|
|
);
|
|
ASSERTDD(pgmc->cxCor < LONG_MAX && pgmc->cyCor < LONG_MAX
|
|
, "vCopyGrayBits -- bad gmc\n"
|
|
);
|
|
|
|
cjSrcScan = CJ_TT_SCAN(pgmc->cxCor+pgmc->dxLeft+pgmc->dxRight,pfc);
|
|
if (pfc->lD)
|
|
{
|
|
cxDst = pfc->lD;
|
|
}
|
|
else
|
|
{
|
|
cxDst = pgmc->cxCor + ((pfc->flFontType & FO_SIM_BOLD) ? 1 : 0);
|
|
}
|
|
cjDstScan = CJ_GRAY_SCAN(cxDst);
|
|
|
|
// correct source pointer for shaving
|
|
|
|
if (pgmc->dyTop)
|
|
{
|
|
pjSrc += pgmc->dyTop * cjSrcScan;
|
|
}
|
|
pjSrc += pgmc->dxLeft;
|
|
pjSrcScan = pjSrc;
|
|
pjDstScan = pgb->aj;
|
|
|
|
// destination correction for special fixed pitch fonts
|
|
|
|
if (dY)
|
|
{
|
|
pjDstScan += dY * cjDstScan;
|
|
// the size of the bitmap has been established already
|
|
}
|
|
else
|
|
{
|
|
pgb->sizlBitmap.cx = cxDst;
|
|
pgb->sizlBitmap.cy = pgmc->cyCor;
|
|
}
|
|
pjDstScanEnd = pjDstScan + pgmc->cyCor * cjDstScan;
|
|
|
|
#if DBG
|
|
if (gflTtfdDebug & DEBUG_GRAY)
|
|
{
|
|
int bBad;
|
|
BYTE *pjScan, *pjScanEnd;
|
|
|
|
TtfdDbgPrint(
|
|
"cjSrcScan = %u\n"
|
|
"cjDstScan = %u\n"
|
|
"cxDst = %u\n"
|
|
"pgb->sizlBitmap.cx = %u\n"
|
|
"pgb->sizlBitmap.cy = %u\n"
|
|
"pjSrc = %-#x\n"
|
|
"pjSrcScan = %-#x\n"
|
|
"pjDstScan = %-#x\n"
|
|
"pjDstScanEnd = %-#x\n"
|
|
, cjSrcScan
|
|
, cjDstScan
|
|
, cxDst
|
|
, pgb->sizlBitmap.cx
|
|
, pgb->sizlBitmap.cy
|
|
, pjSrc
|
|
, pjSrcScan
|
|
, pjDstScan
|
|
, pjDstScanEnd
|
|
);
|
|
|
|
// scan the source for gray values greater than 16
|
|
|
|
pjScan = pjSrcScan;
|
|
pjScanEnd = pjSrcScan + cjSrcScan * pgmc->cyCor;
|
|
for (; pjScan < pjScanEnd; pjScan+=cjSrcScan) {
|
|
BYTE *pj;
|
|
BYTE *pjEnd = pjScan + cjSrcScan;
|
|
for (pj = pjScan; pj < pjEnd; pj++) {
|
|
if (*pj > 16)
|
|
break;
|
|
}
|
|
if (pj != pjEnd)
|
|
break;
|
|
}
|
|
if (pjScan != pjScanEnd) {
|
|
TtfdDbgPrint("\n\nBad Source Gray Bitmap\n\n");
|
|
pjScan = pjSrcScan;
|
|
pjScanEnd = pjSrcScan + cjSrcScan * pgmc->cyCor;
|
|
for (; pjScan < pjScanEnd; pjScan+=cjSrcScan) {
|
|
BYTE *pj;
|
|
BYTE *pjEnd = pjScan + cjSrcScan;
|
|
for (pj = pjScan; pj < pjEnd; pj++) {
|
|
TtfdDbgPrint("%02x ", *pj);
|
|
}
|
|
TtfdDbgPrint("\n");
|
|
}
|
|
EngDebugBreak();
|
|
}
|
|
|
|
TtfdDbgPrint(
|
|
"\n"
|
|
"Source 8-bit-per-pixel-bitmap\n"
|
|
"\n"
|
|
);
|
|
pjScan = pjSrcScan;
|
|
pjScanEnd = pjSrcScan + cjSrcScan * pgmc->cyCor;
|
|
for (; pjScan < pjScanEnd; pjScan+=cjSrcScan) {
|
|
BYTE *pj;
|
|
BYTE *pjEnd = pjScan + cjSrcScan;
|
|
for (pj = pjScan; pj < pjEnd; pj++) {
|
|
TtfdDbgPrint("%1x", ajGray[*pj]);
|
|
}
|
|
TtfdDbgPrint("\n");
|
|
}
|
|
TtfdDbgPrint("\n");
|
|
|
|
EngDebugBreak();
|
|
}
|
|
#endif
|
|
for (
|
|
; pjDstScan < pjDstScanEnd // whole byte loop
|
|
; pjDstScan += cjDstScan, pjSrcScan += cjSrcScan)
|
|
{
|
|
for (
|
|
pjSrc = pjSrcScan, pjDst = pjDstScan
|
|
; pjDst < pjDstScan + (pgmc->cxCor / 2)
|
|
; pjDst += 1
|
|
)
|
|
{
|
|
*pjDst = 16*ajGray[*pjSrc++]; // set high nyble
|
|
*pjDst += ajGray[*pjSrc++]; // set low nyble
|
|
}
|
|
if (pgmc->cxCor & 1) // one more pixel in source?
|
|
{ // yes
|
|
*pjDst = 16*ajGray[*pjSrc]; // set high nyble
|
|
} // low nyble is cleared
|
|
// embodening is taken care of
|
|
else if (cxDst > pgmc->cxCor) // emboldened?
|
|
{ // yes; clear last byte
|
|
*pjDst = 0; //
|
|
}
|
|
}
|
|
#if DBG
|
|
if (gflTtfdDebug & DEBUG_GRAY)
|
|
{
|
|
vDumpGrayGLYPHBITS(pgb);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
vCopyGrayBits(
|
|
FONTCONTEXT *pfc
|
|
, GLYPHBITS *pgb
|
|
, BYTE *pjSrc
|
|
, GMC *pgmc
|
|
)
|
|
{
|
|
vGCGB(pfc, pgb, pjSrc, pgmc, 0);
|
|
}
|
|
|
|
VOID
|
|
vMakeAFixedPitchGrayBitmap(
|
|
FONTCONTEXT *pfc
|
|
, GLYPHBITS *pgb
|
|
, BYTE *pjSrc
|
|
, GLYPHDATA *pgd
|
|
, GMC *pgmc
|
|
)
|
|
{
|
|
vGCGB(pfc, pgb, pjSrc, pgmc, pgd->rclInk.top + pfc->lAscDev);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* LONG lGetBitmapVertical
|
|
*
|
|
* History:
|
|
* 20-Mar-1993 -by- Takao Kitano [TakaoK]
|
|
* grabbed lGetBitmap() and modified
|
|
*
|
|
\**************************************************************************/
|
|
|
|
LONG lGetGlyphBitmapVertical (
|
|
FONTCONTEXT *pfc,
|
|
HGLYPH hglyph,
|
|
GLYPHDATA *pgd,
|
|
PVOID pv,
|
|
BOOL bMinBmp,
|
|
FS_ENTRY *piRet
|
|
)
|
|
{
|
|
LONG cjGlyphData;
|
|
WCHAR wc;
|
|
|
|
bIndexToWchar( pfc->pff, &wc, (uint16)hglyph );
|
|
|
|
if ( !IsFullWidthCharacter( pfc->pff->uiFontCodePage, wc ) )
|
|
{
|
|
return (lGetGlyphBitmap(pfc, hglyph, pgd, pv, bMinBmp, piRet));
|
|
}
|
|
|
|
//
|
|
// change the transformation
|
|
//
|
|
if ( !bChangeXform( pfc, TRUE ) )
|
|
{
|
|
WARNING("TTFD!bChangeXform(TRUE) failed\n");
|
|
return FD_ERROR;
|
|
}
|
|
|
|
//
|
|
// set vertical mode
|
|
//
|
|
pfc->ulControl |= VERTICAL_MODE;
|
|
|
|
//
|
|
// if font file has alternate glyph index, use it.
|
|
//
|
|
pfc->hgSave = hglyph;
|
|
|
|
if ( pfc->pff->hgSearchVerticalGlyph )
|
|
hglyph = (*pfc->pff->hgSearchVerticalGlyph)( pfc, hglyph );
|
|
|
|
//
|
|
// call ordinary function
|
|
//
|
|
cjGlyphData = lGetGlyphBitmap( pfc, hglyph, pgd, pv, bMinBmp, piRet);
|
|
|
|
//
|
|
// restore the transformation and return
|
|
//
|
|
if ( ! bChangeXform( pfc, FALSE ) )
|
|
{
|
|
WARNING("TTFD!bChangeXform(FALSE) failed\n");
|
|
}
|
|
|
|
pfc->ulControl &= ~VERTICAL_MODE;
|
|
return(cjGlyphData);
|
|
}
|