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
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);
|
|
}
|