Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1615 lines
47 KiB

/******************************Module*Header*******************************\
* Module Name: ttgdi.cxx
*
* These are TrueType specific calls introduced into GDI by Win 3.1. They
* all assume the existence of the TrueType font driver (or rasterizer
* as it is known in Win 3.1).
*
* Created: 11-Feb-1992 15:03:45
* Author: Gilman Wong [gilmanw]
*
* Copyright (c) 1992-1999 Microsoft Corporation
*
\**************************************************************************/
#include "precomp.hxx"
/*
;********************************Public*Routine********************************
;This function is used to create a font directory for a given engine font file
;in it's native format. This font directory can be used to create .FON like
;DLLs.
;Returns: DX:AX # of bytes copied into lpFontDir buffer or -1L in case of
; some error.
;
; GDI uses the Serif Style value in the Panose record of the OS/2 table to
; drive the Font Family for Windows. This is based on a simple table look
; up and the current mapping is as follows:
;
; Serif Style Font Family
; ----------------------------------------------------------------
; 0 (Any) FF_DONTCARE
; 1 (No Fit) FF_DONTCARE
; 2 (Cove) FF_ROMAN
; 3 (Obtuse Cove) FF_ROMAN
; 4 (Square Cove) FF_ROMAN
; 5 (Obtuse Square Cove) FF_ROMAN
; 6 (Square) FF_ROMAN
; 7 (Thin) FF_ROMAN
; 8 (Bone) FF_ROMAN
; 9 (Exaggerated) FF_ROMAN
;10 (Triangle) FF_ROMAN
;11 (Normal Sans) FF_SWISS
;12 (Obtuse Sans) FF_SWISS
;13 (Perp Sans) FF_SWISS
;14 (Flared) FF_SWISS
;15 (Rounded) FF_SWISS
;
;******************************************************************************
*/
// Generic FFH header information.
#define HEADERSTUFFLEN1 (5 * sizeof(USHORT))
#define COPYRIGHTLEN 60
#define MOREHEADERSTUFFLEN (2 * sizeof(USHORT))
#define HEADERSTUFFLEN (HEADERSTUFFLEN1 + COPYRIGHTLEN)
static USHORT ausHeaderStuff[5] = {
1, 0, 0x0200, ((SIZEFFH)+4+LF_FACESIZE), 0
};
static USHORT ausMoreHeaderStuff[2] = {
WIN_VERSION, GDI_VERSION
};
#define MAXPMWEIGHT 9
#define WOW_EMBEDING 2
/**************************************************************************\
* NtGdiMakeFontDir
*
* Code is over here!
\**************************************************************************/
ULONG GreMakeFontDir(
FLONG flEmbed, // mark file as "hidden"
PBYTE pjFontDir, // pointer to structure to fill
PWSZ pwszPathname // path of font file to use
)
{
ULONG cjNames; // localW nNamesLength
HFF hff; // localD lhFontFile
PIFIMETRICS pifi; // localV pIfiMetrics, %(size IFIMETRICS)
ULONG_PTR idifi;
ULONG cjIFI;
// If TrueType disabled, then fail.
// Not needed since our TrueType driver is part of the engine DLL and
// should never be disabled. At least, not yet...
if (gppdevTrueType == NULL)
{
return ( 0);
}
// Use TrueType driver to load font file.
PDEVOBJ pdo((HDEV)gppdevTrueType);
// Create a bogus PFF that only has the file name set. This insures that
// the call to EngMapFontFile will suceed.
FONTFILEVIEW fv, *pfv = &fv;
memset( (PVOID) &fv, 0, sizeof(fv) );
fv.pwszPath = pwszPathname;
PVOID pvView;
ULONG cjView;
if (!EngMapFontFileFDInternal((ULONG_PTR)&fv, (PULONG *)&pvView, &cjView, FALSE))
{
WARNING("GreMakeFontDir: EngMapFontFile failed\n");
return(FALSE);
}
hff = pdo.LoadFontFile(
1
, (ULONG_PTR *)&pfv
, &pvView
, &cjView
, 0 // pdv
, (ULONG) gusLanguageID
, 0
);
if ( !hff )
{
KdPrint(("gdisrv!cjMakeFontDir(): failed to load TrueType file %ws\n", pwszPathname));
return ( 0);
}
EngUnmapFontFileFD((ULONG_PTR)&fv);
// Grab a pointer to the IFIMETRICS as well as the size of the structure.
if ( (pifi = pdo.QueryFont(
0,
hff,
1, // currently, only 1 .TTF per .FOT
&idifi)) == (PIFIMETRICS) NULL )
{
// Make sure to unload on error exit.
if ( !pdo.UnloadFontFile(hff) )
{
WARNING("cjMakeFontDir(): IFI error--failed to unload file\n");
return (FALSE);
}
// Error exit.
WARNING("cjMakeFontDir(): IFI error in TrueType driver\n");
return (FALSE);
}
cjIFI = pifi->cjThis;
// NOTE PERF: [GilmanW] 01-Nov-1992 A note to myself...
//
// Tsk-tsk! Gilman, this is very inefficient. You should create a stack
// object that loads the font file and ifimetrics. Its destructor will
// automatically free the ifimetrics and unload the file. That saves
// having to do the MALLOCOBJ and copy.
// Copy the IFIMETRICS so we can unload the font file NOW (and simplify
// error cleanup).
MALLOCOBJ moIFI(cjIFI);
if ( !moIFI.bValid() )
{
// Make sure to unload on error exit.
if ( !pdo.UnloadFontFile(hff) )
{
WARNING("cjMakeFontDir(): IFI error--failed to unload file\n");
return (0);
}
// Error exit.
WARNING("cjMakeFontDir(): could not allocate buffer for IFIMETRICS\n");
return ( 0);
}
RtlCopyMemory(moIFI.pv(), (PVOID) pifi, cjIFI);
// Tell the TrueType driver to free the IFIMETRICS.
if ( PPFNVALID(pdo, Free) )
{
pdo.Free(pifi, idifi);
}
pifi = (PIFIMETRICS) moIFI.pv();
IFIOBJ ifio(pifi);
// Tell the TrueType driver to unload the font file.
if ( !pdo.UnloadFontFile(hff) )
{
WARNING("cjMakeFontDir(): IFI error--failed to unload file\n");
return (0);
}
// Copy header info into the font directory.
PBYTE pjWritePointer = pjFontDir;
RtlCopyMemory(pjWritePointer, ausHeaderStuff, HEADERSTUFFLEN1);
pjWritePointer += HEADERSTUFFLEN1;
//
// Add the copyright string.
//
ULONG cjTmp = strlen("Windows! Windows! Windows!") + 1;
RtlCopyMemory(pjWritePointer, "Windows! Windows! Windows!", cjTmp);
// If this is an embeded font we need to embed either a PID or TID depending on
// whether or not we were called from WOW. If we were called from WOW then we
// expect flEmbeded to be WOW_EMBEDING.
if( flEmbed )
{
ULONG pid = (flEmbed == WOW_EMBEDING) ?
(ULONG) W32GetCurrentTID() : (ULONG) W32GetCurrentPID();
// we are overwriting the copyright string with the PID or TID but
// since this is an embeded font we don't care about the copyright
// string
//
// Unaligned write
//
RtlCopyMemory( pjWritePointer,
&pid,
sizeof( ULONG ) );
}
RtlZeroMemory(pjWritePointer + cjTmp, COPYRIGHTLEN - cjTmp);
// pjWritePointer += COPYRIGHTLEN;
pjWritePointer += cjTmp;
// Note: version stamps (Win version, Engine version) are put in the
// copyright field immediately after the copyright string.
RtlCopyMemory(pjWritePointer, ausMoreHeaderStuff, MOREHEADERSTUFFLEN);
// pjWritePointer += MOREHEADERSTUFFLEN;
pjWritePointer += (COPYRIGHTLEN - cjTmp);
// Engine type and embedded flags.
*pjWritePointer++ = (BYTE) ( PF_ENGINE_TYPE |
((flEmbed) ? PF_ENCAPSULATED : 0) |
((flEmbed == WOW_EMBEDING) ? PF_TID : 0));
// Selection type flag.
*pjWritePointer++ = (BYTE) (ifio.fsSelection() & 0x00ff);
// Em square.
WRITE_WORD(pjWritePointer, ifio.fwdUnitsPerEm());
pjWritePointer += 2;
// Horizontal and vertical resolutions.
WRITE_WORD(pjWritePointer, 72);
pjWritePointer += 2;
WRITE_WORD(pjWritePointer, 72);
pjWritePointer += 2;
// Ascent.
WRITE_WORD(pjWritePointer, ifio.fwdWinAscender());
pjWritePointer += 2;
// Internal leading.
WRITE_WORD(pjWritePointer, ifio.fwdInternalLeading());
pjWritePointer += 2;
// External leading.
WRITE_WORD(pjWritePointer, ifio.fwdExternalLeading());
pjWritePointer += 2;
// Italic, strikeout, and underline flags.
*pjWritePointer++ = ifio.bItalic() ? 0xffff : 0;
*pjWritePointer++ = ifio.lfUnderline() ? 0xffff : 0;
*pjWritePointer++ = ifio.lfStrikeOut() ? 0xffff : 0;
WRITE_WORD(pjWritePointer, ifio.lfWeight());
pjWritePointer += 2;
// Character set.
// Old Comment:
// - is this right? Maybe we should check. At least make sure ttfd
// handles this so ifi.usCharSet is correct.
*pjWritePointer++ = ifio.lfCharSet();
// Pix width (set to zero for some reason). [Windows 3.1 compatibility]
WRITE_WORD(pjWritePointer, 0);
pjWritePointer += 2;
// Font height.
WRITE_WORD(pjWritePointer, (WORD) ifio.lfHeight());
pjWritePointer += 2;
// PitchAndFamily.
*pjWritePointer++ = ifio.tmPitchAndFamily();
// Average character width (if zero, estimate as fwdMaxCharInc/2).
WRITE_WORD(
pjWritePointer,
ifio.lfWidth() ? (WORD) ifio.lfWidth() : ifio.fwdMaxCharInc()/2
);
pjWritePointer += 2;
// Maximum width.
WRITE_WORD(pjWritePointer, ifio.fwdMaxCharInc());
pjWritePointer += 2;
// The special characters (first, last, default, break).
*pjWritePointer++ = ifio.chFirstChar();
*pjWritePointer++ = ifio.chLastChar();
WRITE_WORD(pjWritePointer, DEF_BRK_CHARACTER); // write it in one shot
pjWritePointer += 2;
// Force WidthBytes entry to zero, no device name.
*pjWritePointer++ = 0;
*pjWritePointer++ = 0;
*pjWritePointer++ = 0;
*pjWritePointer++ = 0;
*pjWritePointer++ = 0;
*pjWritePointer++ = 0;
// Offset to facename.
WRITE_DWORD(pjWritePointer, (DWORD) SIZEFFH + 4 + 1);
pjWritePointer += 4;
// Store rasterization thresholds.
WRITE_WORD(pjWritePointer, (WORD) ifio.fwdLowestPPEm());
pjWritePointer += 2;
WRITE_WORD(pjWritePointer, ifio.wCharBias());
pjWritePointer += 2;
// Move pointer to where facenames belong.
pjWritePointer = pjFontDir + SIZEFFH + 4 + 1;
// Write out family name.
vToASCIIN((PSZ) pjWritePointer, LF_FACESIZE, ifio.pwszFamilyName(), wcslen(ifio.pwszFamilyName()) + 1);
// measure the ansi string again. If dbcs, it may be longer than cwcTmp
cjNames = strlen((PSZ) pjWritePointer) + 1;
pjWritePointer += cjNames;
// Write out face name.
vToASCIIN((PSZ) pjWritePointer, LF_FULLFACESIZE, ifio.pwszFaceName(), wcslen(ifio.pwszFaceName()) + 1);
// measure the ansi string again. If dbcs, it may be longer than cwcTmp
cjTmp = strlen((PSZ) pjWritePointer) + 1;
cjNames += cjTmp;
pjWritePointer += cjTmp;
// Write out style name.
vToASCIIN((PSZ) pjWritePointer, LF_FACESIZE, ifio.pwszStyleName(), wcslen(ifio.pwszStyleName()) + 1);
cjNames += (strlen((PSZ) pjWritePointer) + 1);
return (cjNames + SIZEFFH + 4 + 1);
}
/******************************Public*Routine******************************\
* GreGetRasterizerCaps
*
* Fills the RASTERIZER_STATUS structure.
*
* Returns:
* TRUE if successful; FALSE otherwise.
*
* History:
* 16-Feb-1992 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL GreGetRasterizerCaps (
LPRASTERIZER_STATUS praststat // pointer to a RASTERIZER_STATUS struc
)
{
// Parameter check.
if (praststat == (LPRASTERIZER_STATUS) NULL)
{
WARNING("GreGetRasterizerCaps(): bad parameter\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return (FALSE);
}
// Fill in size.
praststat->nSize = sizeof(RASTERIZER_STATUS);
// Fill in TrueType driver flags.
praststat->wFlags = (USHORT) ((gppdevTrueType != NULL) ? TT_ENABLED : 0);
praststat->wFlags |= (gcTrueTypeFonts != 0) ? TT_AVAILABLE : 0;
// Fill in language id.
praststat->nLanguageID = gusLanguageID;
return (TRUE);
}
/******************************Public*Routine******************************\
*
* ulGetFontData2
*
* Effects:
*
* History:
* 17-Jul-1995 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
ULONG ulGetFontData2 (
DCOBJ& dco,
DWORD dwTable,
DWORD dwOffset,
PVOID pvBuffer,
ULONG cjData
)
{
ULONG cjRet = (ULONG) -1;
// Get RFONT user object. Need this to realize font.
// Old Comment:
// - This should get changed to an LFONTOBJ (paulb)
RFONTOBJ rfo(dco, FALSE);
if (!rfo.bValid())
{
WARNING("GetFontData(): could not lock HRFONT\n");
return (cjRet);
}
// Get PFE user object. Need this for iFont.
PFEOBJ pfeo(rfo.ppfe());
if (!pfeo.bValid())
{
WARNING("GetFontData(): could not lock HPFE\n");
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return (cjRet);
}
// Get PFF user object. Need this for HFF.
PFFOBJ pffo(pfeo.pPFF());
if (!pffo.bValid())
{
WARNING("GetFontData(): could not lock HPFF\n");
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return (cjRet);
}
// Get FDEV user object.
PDEVOBJ pdo(rfo.hdevProducer());
// As long as the driver LOOKS like the TrueType driver, we will allow the
// call to succeed. Otherwise, we quit right now!
//
// In this case, TrueType means supporting the TrueType Tagged File Format.
cjRet = pdo.QueryTrueTypeTable (
pffo.hff(),
pfeo.iFont(),
(ULONG) dwTable,
(PTRDIFF) dwOffset,
(ULONG) cjData,
(PBYTE) pvBuffer,
0,
0
);
return (cjRet);
}
/******************************Public*Routine******************************\
* GreGetFontData
*
* History:
* 16-Feb-1992 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
ULONG ulGetFontData (
HDC hdc,
DWORD dwTable,
DWORD dwOffset,
PVOID pvBuffer,
ULONG cjData
)
{
ULONG cjRet = (ULONG) -1;
// Get DC user object.
DCOBJ dco(hdc);
if (!dco.bValid())
{
WARNING("GetFontData(): bad handle for DC\n");
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return (cjRet);
}
return ulGetFontData2(dco, dwTable, dwOffset, pvBuffer, cjData);
}
/******************************Public*Routine******************************\
*
* vFixedToEf
*
* History:
* Thu 17-Nov-1994 07:15:12 by Kirk Olynyk [kirko]
* Made it simpler.
* 11-Jun-1992 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
VOID vFixedToEf (
EFLOAT *pef,
FIXED& fxd
)
{
*pef = *(LONG*) &fxd;
pef->vMultByPowerOf2(-16);
}
/*********************************Class************************************\
* class RESETFCOBJ
*
* (brief description)
*
* Public Interface:
*
* History:
* 10-Jun-1992 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
#define B_ONE(e) (((e).value == 1) && ((e).fract == 0))
#define B_ZERO(e) (((e).value == 0) && ((e).fract == 0))
class RESETFCOBJ // resetfco
{
private:
BOOL bValid_;
BOOL bTrivialXform;
RFONTOBJ *prfo;
public:
RESETFCOBJ(
DCOBJ& dco,
RFONTOBJ& rfo,
LPMAT2 lpmat2, // "extra" xform applied after the existing xform in dc
BOOL bIgnoreRotation,
FLONG flType
);
~RESETFCOBJ();
BOOL bValid() {return bValid_;};
BOOL bTrivXform() {return bTrivialXform;};
};
/******************************Public*Routine******************************\
*
* RESETFCOBJ::RESETFCOBJ
*
*
* resets the xform in rfo.hfc() to be what it used to be times lpma2
*
*
* History:
* 01-Nov-1992 Gilman Wong [gilmanw]
* IFI/DDI merge.
*
* 11-Jun-1992 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
RESETFCOBJ::RESETFCOBJ(
DCOBJ& dco,
RFONTOBJ& rfo,
LPMAT2 lpmat2, // "extra" xform applied after the existing xform in dc
BOOL bIgnoreRotation,
FLONG flType
)
{
ASSERTGDI(lpmat2 != (LPMAT2)NULL, "RESETFCOBJ:lpmat2\n");
bValid_ = TRUE;
prfo = &rfo;
bTrivialXform = (
B_ONE(lpmat2->eM11) && B_ONE(lpmat2->eM22) &&
B_ZERO(lpmat2->eM12) && B_ZERO(lpmat2->eM21)
);
// If the escapement or orientation values of the LOGFONT are non-zero and
// we are in compatible mode, we will need to recompute the NtoD transform
// while ingnoring these values. This is for the sake of Win 3.1 compatablity.
LFONTOBJ lfo(dco.pdc->hlfntNew());
if (!lfo.bValid())
{
WARNING("GreGetGlyphOutline(): bad LFONTHANDLE\n");
bValid_ = FALSE;
return;
}
if( ( lfo.plfw()->lfEscapement || lfo.plfw()->lfOrientation ) &&
( bIgnoreRotation ) )
{
bTrivialXform = FALSE;
}
if (!bTrivialXform)
{
// Create an EXFORMOBJ. We will use this to hold the transform passed
// in via the LPMAT2.
MATRIX mxExtra;
EXFORMOBJ xoExtra(&mxExtra, XFORM_FORMAT_LTOL);
// EXFORMOBJ should not be able to fail.
ASSERTGDI (
xoExtra.bValid(),
"GreGetGlyphOutline(): EXFORMOBJ failed\n"
);
// Stuff lpMat2 into the "extra" EXFORMOBJ.
EFLOAT ef11, ef12, ef21, ef22;
vFixedToEf(&ef11, lpmat2->eM11);
vFixedToEf(&ef22, lpmat2->eM22);
vFixedToEf(&ef12, lpmat2->eM12);
vFixedToEf(&ef21, lpmat2->eM21);
{
ef12.vNegate();
ef21.vNegate();
xoExtra.vSetElementsLToL(ef11, ef12, ef21, ef22);
}
// note that the section above is different from
// xoExtra.vSetElementsLToL(ef11, ef12, ef21, ef22);
// because of our interpretation of NtoD xform. with our conventions
// ntod xform transforms notional space defined as having y axis pointing down
// to device space also with y axis down by left vector mult.
// vD = vN * N2D. The matrix passed by the user uses different convention:
// y axis up in both spaces. so we have to use
// Sigma_3 M Sigma_3 instead of M, (Sigma_3 = diag(1,-1)) to convert
// from app convetions to our conventions [bodind]
xoExtra.vRemoveTranslation(); // don't leave translations uninitialized
// Need these EXFORMOBJs to calculate the new CONTEXTINFO.
MATRIX mxN2D;
EXFORMOBJ xoN2D(&mxN2D, XFORM_FORMAT_LTOFX);
MATRIX mxNewN2D;
EXFORMOBJ xoNewN2D(&mxNewN2D, XFORM_FORMAT_LTOFX);
// EXFORMOBJs should not be able to fail.
ASSERTGDI (
xoN2D.bValid() && xoNewN2D.bValid(),
"GreGetGlyphOutline(): EXFORMOBJ failed\n"
);
FD_XFORM fdx;
if( bIgnoreRotation )
{
// If bIgnoreRotation is set it means we've been called from WOW and
// need toingore the orientation and escapment values in the LOGFONT.
// To do this we will need to recompute the font driver transform.
// This behavior is neccesary for Corel Draw 5.0 to be able to print
// rotated text properly.
PFEOBJ pfeo(rfo.ppfe());
ASSERTGDI(pfeo.bValid(), "gdisrv!RFONTOBJ(dco): bad ppfe from mapping\n");
IFIOBJ ifio(pfeo.pifi());
POINTL ptlSim;
ptlSim.x = ptlSim.y = 0;
if (
!pfeo.bSetFontXform(
dco, lfo.plfw(),
&fdx,
ND_IGNORE_ESC_AND_ORIENT,
0,
(POINTL* const) &ptlSim,
ifio,
FALSE
)
)
{
WARNING("RESETFCOBJ: failed to compute font transform\n");
bValid_ = FALSE;
return;
}
xoN2D.vRemoveTranslation();
xoN2D.vSetElementsLToFx( fdx.eXX, fdx.eXY, fdx.eYX, fdx.eYY );
xoN2D.vComputeAccelFlags(XFORM_FORMAT_LTOFX);
}
else
{
rfo.vSetNotionalToDevice(xoN2D);
}
// Combine the transforms.
if ( !xoNewN2D.bMultiply(xoN2D, xoExtra, DONT_COMPUTE_FLAGS | XFORM_FORMAT_LTOFX) )
{
WARNING("GreGetGlyphOutline(): EXFORMOBJ::bMultiply failed\n");
bValid_ = FALSE;
return;
}
// Get the new transform as an FD_XFORM.
xoNewN2D.vGetCoefficient(&fdx);
// Attempt to get an RFONT with the new transform.
bValid_ = rfo.bSetNewFDX(dco, fdx, flType);
}
}
/******************************Public*Routine******************************\
*
* RESETFCOBJ::~RESETFCOBJ()
*
* resets the xform in rfo.hfc to its original value
*
* History:
* 01-Nov-1992 Gilman Wong [gilmanw]
* IFI/DDI merge.
*
* 11-Jun-1992 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
RESETFCOBJ::~RESETFCOBJ()
{
if (bValid_ && !bTrivialXform)
{
// Release the cache semaphore and make inactive.
prfo->vReleaseCache();
prfo->vMakeInactive();
}
}
#define BITS_OFFSET (offsetof(GLYPHBITS,aj))
BOOL IsSingularEudcGlyph
(
GLYPHDATA *wpgd, BOOL bSimulatedBold
);
/******************************Public*Routine******************************\
* GreGetGlyphOutline
*
* History:
* 05-Mar-1995 Kirk Olynyk [kirko]
* Added support for GGO_GRAY2_BITMAP, GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP.
* I have introduced new modes for DrvQueryFontData that require
* that the bitmaps have scans that begin and end on DWORD
* boundaries as required by GetGlyphOutline(). This is the
* natural format of the TrueType driver.
* I also rearranged the code to have a single return point.
* 01-Nov-1992 Gilman Wong [gilmanw]
* IFI/DDI merge.
*
* 16-Feb-1992 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
ULONG GreGetGlyphOutlineInternal (
HDC hdc,
WCHAR wch, // WCHAR or HGLYPH???
UINT ulFormat, // data format
GLYPHMETRICS *lpgm, // glyph metrics
ULONG cjBuffer, // size of buffer
void *pvBuffer, // buffer for data in the format, ulFormat
MAT2 *lpmat2, // "extra" xform applied after existing Notional to Device xform
BOOL bIgnoreRotation
)
{
HGLYPH hg;
GLYPHDATA gd;
ULONG iMode, uRet, cjRet;
BOOL bGlyphIndex, bBufferSizeWanted, flTTO;
BOOL bUnhinted;
FLONG flType;
cjRet = GDI_ERROR; // assume error
bGlyphIndex = (ulFormat & GGO_GLYPH_INDEX); // record glyph index bit
bUnhinted = (ulFormat & GGO_UNHINTED); // remember if unhinted outlines are wanted
ulFormat &= ~(GGO_GLYPH_INDEX | GGO_UNHINTED); // and then erase it from ulFormat
bBufferSizeWanted = (pvBuffer == 0) || (cjBuffer == 0);
flType = bGlyphIndex ? RFONT_TYPE_HGLYPH : RFONT_TYPE_UNICODE;
if ( (lpgm == 0) || (lpmat2 == 0) )
{
WARNING("GreGetGlyphOutline(): bad parameter\n");
SAVE_ERROR_CODE( ERROR_INVALID_PARAMETER );
}
else
{
DCOBJ dco(hdc);
if ( !dco.bValid() )
{
WARNING("GreGetGlyphOutline(): bad handle for DC\n");
SAVE_ERROR_CODE( ERROR_INVALID_HANDLE );
}
else
{
RFONTOBJ rfo(dco, FALSE);
RFONTTMPOBJ rfoLinkSystem;
RFONTTMPOBJ rfoLinkDefault;
RFONTTMPOBJ rfoLinkFace;
GLYPHDATA *wpgdTemp;
PRFONT prfnt;
PRFONT prfntTmp;
UINT EudcType;
UINT numFaceName;
BOOL bEUDC = FALSE;
// Set Basefont as default.
RFONTOBJ *prfo = &rfo;
// restructure this later
if(!rfo.bValid())
{
goto GetGlyphOutlineData;
}
// Get the HGLYPH for the WCHAR. Note we only check bGlyphIndex for the
// original font. If this is an hglyph rfont then we wont allow linked
// glyphs
hg = (bGlyphIndex) ? (HGLYPH) wch : rfo.hgXlat(wch);
// Check the target glyph is linked font or base font.
if ((hg == rfo.hgDefault()) && !bGlyphIndex && rfo.bIsLinkedGlyph(wch))
{
prfnt = rfo.prfntFont();
GreAcquireSemaphore(prfnt->hsemEUDC);
HGLYPH hgFound = HGLYPH_INVALID;
HGLYPH hgLink = HGLYPH_INVALID;
// this value will be decremented in RFONTOBJ::dtHeler()
INCREMENTEUDCCOUNT;
FLINKMESSAGE2(DEBUG_FONTLINK_RFONT,
"GreGetGlyphOutlineInternal():No request to change EUDC \
data %d\n",gcEUDCCount);
// initialize EUDC info
rfo.vInitEUDC(dco);
// if we have system wide eudc, lock the cache.
if( prfnt->prfntSysEUDC != NULL )
{
RFONTTMPOBJ rfoTemp( prfnt->prfntSysEUDC );
rfoTemp.vGetCache();
}
// The linked RFONT is initialized for Default EUDC grab the semaphore.
if( prfnt->prfntDefEUDC != NULL )
{
RFONTTMPOBJ rfoTemp( prfnt->prfntDefEUDC );
rfoTemp.vGetCache();
}
// if we have face name eudc, lock the cache for all the linked fonts
for( UINT ii = 0; ii < prfnt->uiNumLinks; ii++ )
{
RFONTTMPOBJ rfoTemp( prfnt->paprfntFaceName[ii] );
rfoTemp.vGetCache();
}
// Need to indicate that this RFONT's EUDC data has been initialized.
prfnt->flEUDCState |= EUDC_INITIALIZED;
GreReleaseSemaphore(prfnt->hsemEUDC);
// First, try to find out target glyph from facename linked font.
numFaceName = 0;
for( ii = 0; ii < prfnt->uiNumLinks; ii++ )
{
rfoLinkFace.vInit( prfnt->paprfntFaceName[ii] );
if ((hgLink = rfoLinkFace.hgXlat(wch)) != rfoLinkFace.hgDefault())
{
RFONTTMPOBJ rfoTemp( prfnt->paprfntFaceName[ii] );
if (rfoTemp.bValid())
{
if( (wpgdTemp = rfoTemp.pgdGetEudcMetrics( wch, &rfo)) != NULL )
{
if( !IsSingularEudcGlyph(wpgdTemp, rfoTemp.pfo()->flFontType & FO_SIM_BOLD))
{
numFaceName = ii;
EudcType = EUDCTYPE_FACENAME;
hgFound = hgLink;
prfo = &rfoLinkFace;
break;
}
}
}
}
}
// Check if the glyph is in the DEFAULT EUDC font
if( (hgFound == HGLYPH_INVALID) && (prfnt->prfntDefEUDC != NULL) )
{
rfoLinkDefault.vInit( prfnt->prfntDefEUDC );
if ((hgLink = rfoLinkDefault.hgXlat(wch)) != rfoLinkDefault.hgDefault())
{
RFONTTMPOBJ rfoTemp( prfnt->prfntDefEUDC );
if (rfoTemp.bValid())
{
if( (wpgdTemp = rfoTemp.pgdGetEudcMetrics( wch , &rfo)) != NULL )
{
if( !IsSingularEudcGlyph(wpgdTemp, rfoTemp.pfo()->flFontType & FO_SIM_BOLD) )
{
numFaceName = 0;
EudcType = EUDCTYPE_DEFAULT;
hgFound = hgLink;
prfo = &rfoLinkDefault;
}
}
}
}
}
// Try to find out System EUDC.
if( (hgFound == HGLYPH_INVALID) && (prfnt->prfntSysEUDC != NULL) )
{
rfoLinkSystem.vInit( prfnt->prfntSysEUDC );
if ((hgLink = rfoLinkSystem.hgXlat(wch)) != rfoLinkSystem.hgDefault())
{
numFaceName = 0;
EudcType = EUDCTYPE_SYSTEM_WIDE;
hgFound = hgLink;
prfo = &rfoLinkSystem;
}
}
if( hgFound != HGLYPH_INVALID )
{
hg = hgFound;
bEUDC = TRUE; // find any EUDC object. prfo is not rfo object.
}
else
{
rfo.dtHelper();
prfnt->flEUDCState = FALSE;
}
}
GetGlyphOutlineData:
if ( !prfo->bValid() )
{
WARNING("GreGetGlyphOutline(): could not lock HRFONT\n");
SAVE_ERROR_CODE( ERROR_CAN_NOT_COMPLETE );
}
else
{
PDEVOBJ pdo( prfo->hdevProducer() );
if ( !pdo.bValid() )
{
WARNING("GreGetGlyphOutline -- invalid PDEV\n");
SAVE_ERROR_CODE( ERROR_CAN_NOT_COMPLETE );
}
else if ( !PPFNVALID(pdo, QueryTrueTypeOutline) )
{
WARNING1("GreGetGlyphOuline -- DrvQueryTrueTypeOutline\n");
SAVE_ERROR_CODE( ERROR_CAN_NOT_COMPLETE );
}
else
{
// reset the xform in the rfo.hfc() if needed:
RESETFCOBJ resetfco( dco, *prfo, lpmat2, bIgnoreRotation, flType );
if ( !resetfco.bValid() )
{
WARNING("GreGetGlyphOutline(): resetfco\n");
SAVE_ERROR_CODE( ERROR_CAN_NOT_COMPLETE );
}
else
{
prfntTmp = NULL;
if (bEUDC && !resetfco.bTrivXform())
{
switch (EudcType)
{
case EUDCTYPE_SYSTEM_WIDE:
prfntTmp = prfnt->prfntSysEUDC;
prfnt->prfntSysEUDC = NULL;
break;
case EUDCTYPE_DEFAULT:
prfntTmp = prfnt->prfntDefEUDC;
prfnt->prfntDefEUDC = NULL;
break;
case EUDCTYPE_FACENAME:
prfntTmp = prfnt->paprfntFaceName[numFaceName];
prfnt->paprfntFaceName[numFaceName] = NULL;
break;
default:
break;
}
}
switch ( ulFormat )
{
case GGO_BITMAP:
case GGO_GRAY2_BITMAP:
case GGO_GRAY4_BITMAP:
case GGO_GRAY8_BITMAP:
switch ( ulFormat )
{
case GGO_BITMAP:
iMode = QFD_TT_GRAY1_BITMAP; // 8 pixels per byte
break;
case GGO_GRAY2_BITMAP:
iMode = QFD_TT_GRAY2_BITMAP; // one byte per pixel: 0..4
break;
case GGO_GRAY4_BITMAP:
iMode = QFD_TT_GRAY4_BITMAP; // one byte per pixel: 0..16
break;
case GGO_GRAY8_BITMAP:
iMode = QFD_TT_GRAY8_BITMAP; // one byte per pixel: 0..64
break;
}
cjRet =
pdo.QueryFontData(
0, // device handle of PDEV
prfo->pfo(),
iMode, // QFD_TT_GRAY[1248]_BITMAP
hg, // glyph handle
&gd, // pointer to GLYPHDATA structure
pvBuffer, // pointer to dest buffer
cjBuffer // size of dest buffer
);
break;
case GGO_NATIVE:
case GGO_BEZIER:
flTTO = 0;
if (ulFormat == GGO_BEZIER)
flTTO |= TTO_QUBICS;
if (bUnhinted)
flTTO |= TTO_UNHINTED;
// We're lucky, FdQueryTrueTypeOutline will return size if EITHER
// a NULL buffer or size of zero is passed in. So we don't need
// separate cases. Note that this assumes that the outline is
// appropriate to a monochrome bitmap. There should be no scaling
// for the case of antialiased fonts.
cjRet =
pdo.QueryTrueTypeOutline(
0,
prfo->pfo(),
hg,
flTTO,
&gd,
cjBuffer,
(TTPOLYGONHEADER *) pvBuffer
);
if ( cjRet == FD_ERROR )
{
ASSERTGDI(cjRet == GDI_ERROR, "FD_ERROR != GDI_ERROR\n");
WARNING(
"GreGetGlyphOutline(): FdQueryTrueTypeOutline()"
"--couldn't get buffer size\n"
);
}
break;
case GGO_METRICS:
// Call to get just the metrics.
cjRet =
pdo.QueryFontData(
0, // device handle of PDEV
prfo->pfo(),
QFD_TT_GLYPHANDBITMAP, // mode of call
hg, // glyph handle
&gd, // pointer to GLYPHDATA structure
0, // pointer to destination buffer
0 // size of destination buffer in bytes
);
if ( cjRet == FD_ERROR )
{
ASSERTGDI(cjRet == GDI_ERROR, "FD_ERROR != GDI_ERROR\n");
WARNING(
"GreGetGlyphOutline(): FdQueryFontData()"
"--couldn't get GLYPHMETRICS\n"
);
}
break;
default:
WARNING("GreGetGlyphOutline(): bad parameter, unknown format\n");
break;
}
}
if ( cjRet != GDI_ERROR )
{
// Convert the GLYPHDATA metrics to GLYPHMETRICS.
lpgm->gmBlackBoxX = (UINT) (gd.rclInk.right - gd.rclInk.left);
lpgm->gmBlackBoxY = (UINT) (gd.rclInk.bottom - gd.rclInk.top);
// this is true by virtue of the fact that for tt fonts bitmap
// is of the same size as the black box. The exception to this
// rule is the empty space char which is a blank 1x1 bitmap
lpgm->gmptGlyphOrigin.x = gd.rclInk.left;
lpgm->gmptGlyphOrigin.y = - gd.rclInk.top;
lpgm->gmCellIncX = (WORD) FXTOLROUND(gd.ptqD.x.u.HighPart);
lpgm->gmCellIncY = (WORD) FXTOLROUND(gd.ptqD.y.u.HighPart);
}
}
if (bEUDC)
{
rfo.dtHelper(FALSE);
prfnt->flEUDCState = FALSE;
if (prfntTmp)
{
switch (EudcType)
{
case EUDCTYPE_SYSTEM_WIDE:
prfnt->prfntSysEUDC = prfntTmp;
break;
case EUDCTYPE_DEFAULT:
prfnt->prfntDefEUDC = prfntTmp;
break;
case EUDCTYPE_FACENAME:
prfnt->paprfntFaceName[numFaceName] = prfntTmp;
break;
default:
break;
}
}
ASSERTGDI(gcEUDCCount > 0, "gcEUDCCount <= 0");
DECREMENTEUDCCOUNT;
}
}
}
}
return( cjRet );
}
VOID vIFIMetricsToETM(
EXTTEXTMETRIC *petm,
RFONTOBJ& rfo,
DCOBJ& dco,
IFIMETRICS *pifi
);
/******************************Public*Routine******************************\
*
* GreGetETM
*
* support for aldus escape
*
* History:
* 19-Oct-1993 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiGetETM(
HDC hdc,
EXTTEXTMETRIC *petm
)
{
EXTTEXTMETRIC kmETM;
BOOL bRet = FALSE;
// Get DC user object.
DCOBJ dco(hdc);
if (petm && dco.bValid())
{
RFONTOBJ rfo(dco, FALSE);
if (rfo.bValid())
{
// see if we can dispatch the call directly to the device driver
PDEVOBJ pdo(rfo.hdevProducer());
if (PPFNDRV(pdo,FontManagement))
{
ULONG iMode = GETEXTENDEDTEXTMETRICS;
SURFOBJ *pso = NULL;
if (pdo.bUMPD())
{
// we need to have a dhpdev when calling out to UMPD
pso = (SURFOBJ *)pdo.dhpdev();
}
BOOL bSupported = GetETMFontManagement(
rfo,
pdo,
pso,
NULL,
QUERYESCSUPPORT, // iMode
sizeof(ULONG), // cjIn
(PVOID)&iMode, // pvIn
0, // cjOut
(PVOID)NULL // pvOut
);
if (bSupported)
{
SURFOBJ soFake;
SURFOBJ *pso = pdo.pSurface()->pSurfobj();
if (pso == (SURFOBJ *) NULL) // create vanilla surfobj
{
RtlFillMemory((BYTE *) &soFake,sizeof(SURFOBJ),0);
soFake.dhpdev = rfo.prfnt->dhpdev;
soFake.hdev = rfo.hdevConsumer();
soFake.iType = (USHORT)STYPE_DEVICE;
pso = &soFake;
}
bRet = pdo.FontManagement(
pso,
rfo.pfo(),
GETEXTENDEDTEXTMETRICS,
0,
(PVOID)NULL,
(ULONG)sizeof(EXTTEXTMETRIC),
(PVOID)&kmETM
);
}
}
// if GETEXTENDEDTEXTMETRIC is not supported do something:
// Get PFE user object.
if (!bRet)
{
PFEOBJ pfeo(rfo.ppfe());
if (pfeo.bValid())
{
if (pfeo.flFontType() & TRUETYPE_FONTTYPE)
{
vIFIMetricsToETM(&kmETM,rfo,dco,pfeo.pifi());
bRet = TRUE;
}
}
}
}
}
if (bRet)
{
__try
{
ProbeForWrite(petm,sizeof(EXTTEXTMETRIC),sizeof(ULONG));
RtlMoveMemory(petm,&kmETM,sizeof(EXTTEXTMETRIC));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
// SetLastError(GetExceptionCode());
bRet = FALSE;
}
}
return bRet;
}
/******************************Public*Routine******************************\
* GreGetOutlineTextMetricsInternalW
*
* History:
*
* 20-Apr-1993 -by- Gerrit van Wingerden [gerritv]
* Added bTTOnly field so we can service the Aldus escape for Win 3.1 compat.
* Changed to GreGe...InternalW to avoid a header file change in wingdip.h
*
* 16-Feb-1992 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
UINT cjOTMAWSize (
PIFIMETRICS pifi, // compute size of OTM produced by this buffer
UINT *pcjotmw
);
ULONG
GreGetOutlineTextMetricsInternalW(
HDC hdc,
ULONG cjotm,
OUTLINETEXTMETRICW *potmw,
TMDIFF *ptmd
)
{
ULONG cjRet = 0;
// Early out test. Zero data requested.
if ( (cjotm == 0) && (potmw != (OUTLINETEXTMETRICW*) NULL) )
{
WARNING("GreGetOutlineTextMetrics(): bad parameter\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return (cjRet);
}
// Get DC user object.
DCOBJ dco(hdc);
if (!dco.bValid())
{
WARNING("GreGetOutlineTextMetrics(): bad handle for DC\n");
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return (cjRet);
}
// the following is a copy of what is done during GreGetCharSet(), to fix 735873
// where bIFIMetricsToTextMetricWStrict() get called while DIRTY_CHARSET is set and
// copy an unitialized value from dco.pdc->iCS_CP to ptmw->tmCharSet
// if the font is not mapped, we need to map it
if (dco.ulDirty() & DIRTY_CHARSET)
{
// force mapping
FLONG flSim;
POINTL ptlSim;
FLONG flAboutMatch;
PFE *ppfe;
PDEVOBJ pdo(dco.hdev());
ASSERTGDI(pdo.bValid(), "GreGetOutlineTextMetrics: bad pdev in dc\n");
if (!pdo.bGotFonts())
pdo.bGetDeviceFonts();
LFONTOBJ lfo(dco.pdc->hlfntNew(), &pdo);
if (!lfo.bValid())
{
WARNING("GreGetOutlineTextMetrics!RFONTOBJ(dco): bad LFONT handle\n");
return(cjRet);
}
{
// Stabilize the public PFT for mapping.
SEMOBJ so(ghsemPublicPFT);
// LFONTOBJ::ppfeMapFont returns a pointer to the physical font face and
// a simulation type (ist)
// also store charset to the DC
ppfe = lfo.ppfeMapFont(dco, &flSim, &ptlSim, &flAboutMatch);
ASSERTGDI(!(dco.ulDirty() & DIRTY_CHARSET),
"NtGdiGetCharSet, charset is dirty\n");
}
}
// Get RFONT user object.
// Old Comment:
// - This should really be an LFONTOBJ
RFONTOBJ rfo(dco, FALSE);
if (!rfo.bValid())
{
WARNING("GreGetOutlineTextMetrics(): could not lock HRFONT\n");
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return (cjRet);
}
// Get PFE user object.
PFEOBJ pfeo(rfo.ppfe());
if (!pfeo.bValid())
{
WARNING("GreGetOutlineTextMetrics(): could not lock HPFE\n");
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return (cjRet);
}
// Get LDEV user object for the font driver.
PDEVOBJ pdo(rfo.hdevProducer());
// Check the font driver. If we are in TT only mode, we will allow only
// the TrueType driver to succeed. However, in this sense, the TrueType
// driver is any driver that exports DrvQueryTrueTypeOutline. Afterall,
// if it can supply the actual outlines, it should be able to supply the
// metrics.
//
// Actually, it would be nice to allow this function to work for all
// drivers since all drivers supply the IFIMETRICS and therefore can
// answer this question. However, we are much too afraid that this will
// break some obscure compatibility so we will let our TT driver and
// 3rd part TT-like drivers succeed.
//
// If we not in TT only mode, then everybody succeed this function! Yay!
if (PPFNVALID(pdo, QueryTrueTypeOutline))
{
// Size if full OUTLINETEXTMETRICW (including strings) is copied.
UINT cjotmw;
// use cjotma field of tmd to ship cjotma to the client side, [bodind]
ptmd->cjotma = (ULONG)cjOTMAWSize(pfeo.pifi(), &cjotmw);
// If return buffer is NULL, then only size needs to be returned.
if (potmw == NULL)
{
cjRet = cjotmw;
}
else
{
// Is return buffer big enough for the conversion routine (which is not
// capable of converting a partial OUTLINETEXTMETRICW structure [unless,
// of course, it's one without the strings]).
if (cjotm <= sizeof(OUTLINETEXTMETRICW))
{
// Allocate a buffer for a full OUTLINETEXTMETRICW, since conversion
// routine needs at least that much memory.
OUTLINETEXTMETRICW otmwTmp;
RtlZeroMemory(&otmwTmp, sizeof(OUTLINETEXTMETRICW));
// Convert IFIMETRICS to OUTLINETEXTMETRICW using temp buffer.
if (
(cjRet = cjIFIMetricsToOTMW(
ptmd,
&otmwTmp,
rfo,
dco,
pfeo.pifi(),
FALSE // do not need strings
)) == 0 )
{
WARNING("GreGetOutlineTextMetrics(): error creating OUTLINETEXTMETRIC\n");
return (cjRet);
}
// Copy needed part of OUTLINETEXTMETRICW into return buffer.
RtlCopyMemory((PVOID) potmw, (PVOID) &otmwTmp, cjotm);
return cjotm;
}
// Otherwise asking for strings
// We have to assume that all the strings are desired. If
// cjCopy > sizeof(OUTLINETEXTMETRICW) how can we
// know how many strings are requested? Afterall, the app is not
// supposed to have apriori knowledge of the length of the strings.
// Note that this is also a Win3.1 compatible assumption. (They
// assume the same thing).
if ( cjotm >= cjotmw )
{
// Convert IFIMETRICS to OUTLINETEXTMETRICW using return buffer.
cjRet = cjIFIMetricsToOTMW(ptmd,potmw, rfo, dco, pfeo.pifi(), TRUE);
// clean up the rest of the buffer so that neilc - " Mr. c2 guy" is happy
{
LONG lDiff = (LONG)cjotm - (LONG)cjRet;
ASSERTGDI(lDiff >= 0, "GetOTM, lDiff < 0");
if (lDiff > 0)
RtlZeroMemory(((BYTE*)potmw + cjRet), lDiff);
}
}
}
}
return (cjRet);
}