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.
3543 lines
105 KiB
3543 lines
105 KiB
|
|
/*++
|
|
|
|
Copyright (c) 1996 - 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
textout.c
|
|
|
|
Abstract:
|
|
|
|
The FMTextOut() function - the call used to output Text.
|
|
|
|
Environment:
|
|
|
|
Windows NT Unidrv driver
|
|
|
|
Revision History:
|
|
|
|
01/16/97 -ganeshp-
|
|
Created
|
|
|
|
--*/
|
|
|
|
//
|
|
//This line should be before the line including font.h.
|
|
//Comment out this line to disable FTRC and FTST macroes.
|
|
//
|
|
//#define FILETRACE
|
|
|
|
#include "font.h"
|
|
|
|
/*
|
|
* Some clipping constants. With a complex clip region, it is desirable
|
|
* to avoid enumerating the clip rectangles more than once. To do so,
|
|
* we have a bit array, with each bit being set if the glyph is inside
|
|
* the clipping region, cleared if not. This allows us to obtain a
|
|
* set of glyphs, then determine whether they are printed when the clip
|
|
* rectangles are enumerated. Finally, use the bit array to stop
|
|
* printing any glyphs outside the clip region. This is slightly heavy
|
|
* handed for the simple case.
|
|
*/
|
|
|
|
#define RECT_LIMIT 100 // Clipping rectangle max
|
|
|
|
#define DC_TC_BLACK 0 /* Fixed Text Colors in 4 bit mode */
|
|
#define DC_TC_MAX 8 /* used for 16 colour palette wrap around */
|
|
|
|
#define CMD_TC_FIRST CMD_SELECTBLACKCOLOR
|
|
|
|
// For Dithered Color BRUSHOBJ.iSolidColor is -1.
|
|
#define DITHERED_COLOR -1
|
|
|
|
//Various TextOut specific flags.
|
|
#define TXTOUT_CACHED 0x00000001 // Text is cached and printed after graphics.
|
|
#define TXTOUT_SETPOS 0x00000002 // True if cursor position to be set.
|
|
#define TXTOUT_FGCOLOR 0x00000004 // Device can paint the text.
|
|
#define TXTOUT_COLORBK 0x00000008 // For z-ordering fixes
|
|
#define TXTOUT_NOTROTATED 0x00000010 // Set if Text is not rotated.
|
|
#define TXTOUT_PRINTASGRX 0x00000020 // Set if Text should be printed as
|
|
// Graphics.
|
|
#define TXTOUT_DMS 0x00000040 // Set if Device Managed surface
|
|
#define TXTOUT_90_ROTATION 0x00000080 // Set if font is 90-rotated.
|
|
|
|
#define DEVICE_FONT(pfo, tod) ( (pfo->flFontType & DEVICE_FONTTYPE) || \
|
|
(tod.iSubstFace) )
|
|
|
|
#define ERROR_PER_GLYPH_POS 3
|
|
#define ERROR_PER_ENUMERATION 15
|
|
#define EROOR_PER_GLYPHRECT 5 // For Adjusting height of the glyph rect.
|
|
|
|
|
|
/* NOTE: this must be the same as the winddi.h ENUMRECT */
|
|
typedef struct
|
|
{
|
|
ULONG c; /* Number of rectangles returned */
|
|
RECTL arcl[ RECT_LIMIT ]; /* Rectangles supplied */
|
|
} MY_ENUMRECTS;
|
|
|
|
/*
|
|
* Local function prototypes.
|
|
*/
|
|
VOID
|
|
SelectTextColor(
|
|
PDEV *pPDev,
|
|
PVOID pvColor
|
|
);
|
|
|
|
VOID
|
|
VClipIt(
|
|
BYTE *pbClipBits,
|
|
TO_DATA *ptod,
|
|
CLIPOBJ *pco,
|
|
STROBJ *pstro,
|
|
int cGlyphs,
|
|
int iRot,
|
|
BOOL bPartialClipOn
|
|
);
|
|
|
|
BOOL
|
|
BPSGlyphOut(
|
|
register TO_DATA *pTOD
|
|
);
|
|
|
|
BOOL
|
|
BRealGlyphOut(
|
|
register TO_DATA *pTOD
|
|
);
|
|
|
|
BOOL
|
|
BWhiteText(
|
|
TO_DATA *pTOD
|
|
);
|
|
|
|
BOOL
|
|
BDLGlyphOut(
|
|
TO_DATA *pTOD
|
|
);
|
|
|
|
VOID
|
|
VCopyAlign(
|
|
BYTE *pjDest,
|
|
BYTE *pjSrc,
|
|
int cx,
|
|
int cy
|
|
);
|
|
|
|
INT
|
|
ISubstituteFace(
|
|
PDEV *pPDev,
|
|
FONTOBJ *pfo);
|
|
|
|
HGLYPH
|
|
HWideCharToGlyphHandle(
|
|
PDEV *pPDev,
|
|
FONTMAP *pFM,
|
|
WCHAR wchOrg);
|
|
|
|
PHGLYPH
|
|
PhAllCharsPrintable(
|
|
PDEV *pPDev,
|
|
INT iSubst,
|
|
ULONG ulGlyphs,
|
|
PWCHAR pwchUnicode);
|
|
|
|
BOOL
|
|
BGetStartGlyphandCount(
|
|
BYTE *pbClipBits,
|
|
DWORD dwEndIndex,
|
|
DWORD *pdwStartIndex,
|
|
DWORD *pdwGlyphToPrint);
|
|
|
|
BOOL
|
|
BPrintTextAsGraphics(
|
|
PDEV *pPDev,
|
|
ULONG iSolidColor,
|
|
DWORD dwForeColor,
|
|
DWORD dwFlags,
|
|
INT iSubstFace
|
|
);
|
|
|
|
|
|
BOOL
|
|
FMTextOut(
|
|
SURFOBJ *pso,
|
|
STROBJ *pstro,
|
|
FONTOBJ *pfo,
|
|
CLIPOBJ *pco,
|
|
RECTL *prclExtra,
|
|
RECTL *prclOpaque,
|
|
BRUSHOBJ *pboFore,
|
|
BRUSHOBJ *pboOpaque,
|
|
POINTL *pptlBrushOrg,
|
|
MIX mix
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
The call to use for output of text. Our behaviour depends
|
|
upon the type of printer. Page printers (e.g. LaserJets) do
|
|
whatever is required to send the relevant commands to the printer
|
|
during this call. Otherwise (typified by dot matrix printers),
|
|
we store the data about the glyph so that we can output the
|
|
characters as we are rendering the bitmap. This allows the output
|
|
to be printed unidirectionally DOWN the page.
|
|
|
|
Arguments:
|
|
|
|
pso; Surface to be drawn on
|
|
pstro; The "string" to be produced
|
|
pfo; The font to use
|
|
pco; Clipping region to limit output
|
|
prclExtra; Underline/strikethrough rectangles
|
|
prclOpaque; Opaquing rectangle
|
|
pboFore; Foreground brush object
|
|
pboOpaque; Opaqueing brush
|
|
pptlBrushOrg; Brush origin for both above brushes
|
|
mix; The mix mode
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE for success and FALSE for failure.FALSE logs the error.
|
|
|
|
Note:
|
|
|
|
1/16/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
|
|
{
|
|
PDEV *pPDev; // Our main PDEV
|
|
FONTPDEV *pFontPDev; // FONTMODULE based PDEV
|
|
FONTMAP *pfm; // Font's details
|
|
GLYPHPOS *pgp, *pgpTmp; // Value passed from gre
|
|
XFORMOBJ *pxo; // The transform of interest
|
|
FLOATOBJ_XFORM xform;
|
|
TO_DATA tod; // Our convenience
|
|
RECTL rclRegion; // For z-ordering fixes
|
|
HGLYPH *phSubstGlyphOrg, *phSubstGlyph;
|
|
POINTL ptlRem;
|
|
|
|
BOOL (*pfnDrawGlyph)( TO_DATA * ); // How to produce the glyph
|
|
PFN_OEMTextOutAsBitmap pfnOEMTextOutAsBitmap = NULL;
|
|
|
|
I_UNIFONTOBJ UFObj;
|
|
|
|
ULONG iSolidColor;
|
|
|
|
DWORD dwGlyphToPrint, dwTotalGlyph, dwPGPStartIndex, dwFlags;
|
|
DWORD dwForeColor;
|
|
|
|
INT iyAdjust; // Adjust for printing position WRT baseline
|
|
INT iXInc, iYInc; // Glyph to glyph movement, if needed
|
|
INT iRot; // The rotation factor
|
|
INT iI, iJ, iStartIndex;
|
|
|
|
WCHAR *pwchUnicode;
|
|
|
|
BYTE *pbClipBits; // For clip limits
|
|
BYTE ubMask;
|
|
|
|
BOOL bMore; // Getting glyphs from engine loop
|
|
BOOL bRet = FALSE; // Return Value.
|
|
|
|
//
|
|
// First step is to extract the PDEV address from the surface.
|
|
// Then we can get to all the other bits & pieces that we need.
|
|
// We should also initialize the TO_DATA as much as possible.
|
|
//
|
|
|
|
pPDev = (PDEV *) pso->dhpdev;
|
|
if( !(VALID_PDEV(pPDev)) )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
ERR(( "Invalid or NULL PDEV\n" ))
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Quick check on abort - should we return failure NOW
|
|
//
|
|
if( pPDev->fMode & PF_ABORTED )
|
|
return FALSE;
|
|
|
|
//
|
|
// Misc initialization
|
|
//
|
|
|
|
dwFlags = 0;
|
|
iRot = 0;
|
|
pgp =
|
|
pgpTmp = NULL;
|
|
pfm = NULL;
|
|
pbClipBits = NULL;
|
|
phSubstGlyphOrg = NULL;
|
|
|
|
//
|
|
// Initialize TO_DATA
|
|
//
|
|
ZeroMemory(&tod, sizeof(TO_DATA));
|
|
tod.pPDev = pPDev;
|
|
tod.pfo = pfo;
|
|
tod.flAccel= pstro->flAccel;
|
|
|
|
pFontPDev = pPDev->pFontPDev; // The important stuff
|
|
|
|
//
|
|
// Initialize TT file pointer to NULL to avoid caching. TT File pointer
|
|
// should be initialized per DrvTextOut. Also initialize the TOD pointer.
|
|
// This is needed by download routines, which have access to PDEV only.
|
|
//
|
|
|
|
pFontPDev->pTTFile = NULL;
|
|
pFontPDev->pcjTTFile = 0;
|
|
pFontPDev->ptod = &tod;
|
|
|
|
pFontPDev->pso = pso; // SURFOBJ changes every call - so reset
|
|
pFontPDev->pIFI = FONTOBJ_pifi(pfo);
|
|
|
|
if( pPDev->dwFreeMem && (pFontPDev->flFlags & FDV_TRACK_FONT_MEM) )
|
|
pFontPDev->dwFontMem = pPDev->dwFreeMem;
|
|
|
|
iSolidColor = pboFore->iSolidColor; // Local Copy.
|
|
dwForeColor = BRUSHOBJ_ulGetBrushColor(pboFore);
|
|
|
|
//
|
|
//
|
|
// Flag Initialization
|
|
//
|
|
//
|
|
// Check if the printer can set the foreground color.This is necessary
|
|
// to support grey or dithered device fonts.
|
|
//
|
|
if (pFontPDev->flFlags & FDV_SUPPORTS_FGCOLOR)
|
|
dwFlags |= TXTOUT_FGCOLOR;
|
|
|
|
if (DRIVER_DEVICEMANAGED (pPDev))
|
|
dwFlags |= TXTOUT_DMS;
|
|
|
|
//
|
|
// Device managed surface has to send White text when it's received.Also
|
|
// we don't need to do any Z-order specific checking.
|
|
//
|
|
|
|
if (!(dwFlags & TXTOUT_DMS))
|
|
{
|
|
BOOL bIsRegionW;
|
|
|
|
//
|
|
// Get rectangle for background checking - z-ordering fix
|
|
//
|
|
|
|
if ( !BIntersectRect(&rclRegion, &(pstro->rclBkGround),&(pco->rclBounds)))
|
|
return TRUE;
|
|
|
|
bIsRegionW = bIsRegionWhite(pso, &rclRegion);
|
|
|
|
#ifndef DISABLE_NEWRULES
|
|
//
|
|
// if there is an opaque background or the text color is not black, we
|
|
// need to test whether the text overlaps the rules array
|
|
//
|
|
if (bIsRegionW && pPDev->pbRulesArray && pPDev->dwRulesCount > 0)
|
|
{
|
|
PRECTL pTmpR = prclOpaque;
|
|
if (!pTmpR &&
|
|
((pso->iBitmapFormat == BMF_24BPP ||
|
|
iSolidColor != (ULONG)((PAL_DATA*)(pPDev->pPalData))->iBlackIndex) &&
|
|
(pso->iBitmapFormat != BMF_24BPP ||
|
|
iSolidColor != 0)))
|
|
{
|
|
pTmpR = &rclRegion;
|
|
}
|
|
if (pTmpR)
|
|
{
|
|
DWORD i;
|
|
for (i = 0;i < pPDev->dwRulesCount;i++)
|
|
{
|
|
PRECTL pTmp = &pPDev->pbRulesArray[i];
|
|
if (pTmp->right > pTmpR->left &&
|
|
pTmp->left < pTmpR->right &&
|
|
pTmp->bottom > pTmpR->top &&
|
|
pTmp->top < pTmpR->bottom)
|
|
{
|
|
bIsRegionW = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
if (((ULONG)pFontPDev->iWhiteIndex == iSolidColor) && !bIsRegionW)
|
|
dwFlags |= TXTOUT_CACHED;
|
|
|
|
//
|
|
// Z-ordering fix, check if we are not printing Text as graphics.
|
|
//
|
|
|
|
if (pFontPDev->flFlags & FDV_DLTT || pfo->flFontType & DEVICE_FONTTYPE)
|
|
{
|
|
//
|
|
// If we are banding and this isn't a device font we want to
|
|
// use EngTextOut if the textbox crosses a band boundary. This
|
|
// is because the bIsRegionWhite test can't test the entire
|
|
// region so it is invalid.
|
|
//
|
|
if ((pPDev->bBanding && !(pfo->flFontType & DEVICE_FONTTYPE) &&
|
|
(rclRegion.left != pstro->rclBkGround.left ||
|
|
rclRegion.right != pstro->rclBkGround.right ||
|
|
rclRegion.bottom != pstro->rclBkGround.bottom ||
|
|
(rclRegion.top != pstro->rclBkGround.top &&
|
|
pPDev->rcClipRgn.top != 0))) ||
|
|
!bIsRegionW)
|
|
{
|
|
dwFlags |= TXTOUT_COLORBK;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is necessary because we map low intensity color to black
|
|
// in palette management,
|
|
// However, if we detect text and graphic overlapping, we map
|
|
// low intensity color to white so it's visible over graphics
|
|
//
|
|
if ( pso->iBitmapFormat == BMF_4BPP &&
|
|
dwFlags & TXTOUT_COLORBK)
|
|
{
|
|
if (pboFore->iSolidColor == 8)
|
|
{
|
|
iSolidColor = pFontPDev->iWhiteIndex;
|
|
dwFlags |= TXTOUT_CACHED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Font substitution initialization
|
|
//
|
|
// Get iFace to substitute TrueType font with.
|
|
// Note: pwszOrg is available only when SO_GLYPHINDEX_TEXTOUT is set
|
|
// in pstro->flAccel.
|
|
// SO_DO_NOT_SUBSTITUTE_DEVICE_FONT also has to be checked for BI-DI
|
|
// fonts.
|
|
//
|
|
// We should now get the transform. This is only really needed
|
|
// for a scalable font OR a printer which can do font rotations
|
|
// relative to the graphics orientation (i.e. PCL5 printers!).
|
|
// It is easier just to get the transform all the time.
|
|
//
|
|
|
|
pxo = FONTOBJ_pxoGetXform( pfo );
|
|
XFORMOBJ_iGetFloatObjXform(pxo, &xform);
|
|
pFontPDev->pxform = &xform;
|
|
|
|
|
|
if (NO_ROTATION(xform))
|
|
dwFlags |= TXTOUT_NOTROTATED;
|
|
|
|
if (pFontPDev->pIFI->flInfo & FM_INFO_90DEGREE_ROTATIONS)
|
|
dwFlags |= TXTOUT_90_ROTATION;
|
|
|
|
tod.iSubstFace = 0;
|
|
tod.phGlyph = NULL;
|
|
pwchUnicode = NULL;
|
|
tod.cGlyphsToPrint = pstro->cGlyphs;
|
|
|
|
if (!(pstro->flAccel & SO_GLYPHINDEX_TEXTOUT))
|
|
{
|
|
pwchUnicode = pstro->pwszOrg;
|
|
}
|
|
|
|
//
|
|
// Conditions to substitute:
|
|
// The Text is not supposed to be printed as graphics and
|
|
// Device can substitute font and
|
|
// Font is True Type and
|
|
// STROBJ flags have no conflict with substitution.
|
|
//
|
|
|
|
if ( (pfo->flFontType & TRUETYPE_FONTTYPE) &&
|
|
!(pstro->flAccel & ( SO_GLYPHINDEX_TEXTOUT |
|
|
SO_DO_NOT_SUBSTITUTE_DEVICE_FONT)) )
|
|
{
|
|
INT iSubstFace;
|
|
|
|
if ((iSubstFace = ISubstituteFace(pPDev, pfo)) &&
|
|
(phSubstGlyphOrg = PhAllCharsPrintable(pPDev,
|
|
iSubstFace,
|
|
pstro->cGlyphs,
|
|
pwchUnicode)))
|
|
{
|
|
tod.iSubstFace = iSubstFace;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if Text should be printed as graphics or not.
|
|
//
|
|
if( BPrintTextAsGraphics(pPDev, iSolidColor, dwForeColor, dwFlags, tod.iSubstFace) )
|
|
{
|
|
dwFlags |= TXTOUT_PRINTASGRX;
|
|
tod.iSubstFace = 0;
|
|
}
|
|
|
|
//
|
|
// Initialize for OEM Callback function
|
|
// ulFontID
|
|
// dwFlags
|
|
// pIFIMetrics
|
|
// pfnGetInfo
|
|
// pFontObj
|
|
// pStrObj
|
|
// pFontMap
|
|
// pFontPDev
|
|
// ptGrxRes
|
|
// pGlyph
|
|
//
|
|
|
|
if(pPDev->pOemHookInfo || (pPDev->ePersonality == kPCLXL))
|
|
{
|
|
ZeroMemory(&UFObj, sizeof(I_UNIFONTOBJ));
|
|
UFObj.pfnGetInfo = UNIFONTOBJ_GetInfo;
|
|
UFObj.pPDev = pPDev;
|
|
UFObj.pFontObj = pfo;
|
|
UFObj.pStrObj = pstro;
|
|
UFObj.ptGrxRes = pPDev->ptGrxRes;
|
|
UFObj.pIFIMetrics = pFontPDev->pIFI;
|
|
|
|
if (tod.cGlyphsToPrint)
|
|
UFObj.pGlyph = MemAlloc(sizeof(DWORD) * tod.cGlyphsToPrint);
|
|
|
|
if (pfo &&
|
|
!(pfo->flFontType & DEVICE_FONTTYPE) )
|
|
{
|
|
PFN_OEMTTDownloadMethod pfnOEMTTDownloadMethod;
|
|
|
|
|
|
if (tod.iSubstFace == 0 &&
|
|
( (pPDev->pOemHookInfo &&
|
|
(pfnOEMTTDownloadMethod = (PFN_OEMTTDownloadMethod)pPDev->pOemHookInfo[EP_OEMTTDownloadMethod].pfnHook))
|
|
|| (pPDev->ePersonality == kPCLXL))
|
|
)
|
|
{
|
|
DWORD dwRet = TTDOWNLOAD_DONTCARE;
|
|
|
|
HANDLE_VECTORPROCS(pPDev, VMTTDownloadMethod, ((PDEVOBJ)pPDev,
|
|
(PUNIFONTOBJ)&UFObj,
|
|
&dwRet))
|
|
else
|
|
if(pPDev->pOemEntry)
|
|
{
|
|
FIX_DEVOBJ(pPDev, EP_OEMTTDownloadMethod);
|
|
|
|
if(((POEM_PLUGIN_ENTRY)pPDev->pOemEntry)->pIntfOem ) // OEM plug in uses COM and function is implemented.
|
|
{
|
|
HRESULT hr ;
|
|
hr = HComTTDownloadMethod((POEM_PLUGIN_ENTRY)pPDev->pOemEntry,
|
|
&pPDev->devobj, (PUNIFONTOBJ)&UFObj, &dwRet);
|
|
if(SUCCEEDED(hr))
|
|
; // cool !
|
|
}
|
|
else
|
|
{
|
|
dwRet = pfnOEMTTDownloadMethod(&pPDev->devobj,
|
|
(PUNIFONTOBJ)&UFObj);
|
|
}
|
|
}
|
|
|
|
switch (dwRet)
|
|
{
|
|
case TTDOWNLOAD_GRAPHICS:
|
|
case TTDOWNLOAD_DONTCARE:
|
|
dwFlags |= TXTOUT_PRINTASGRX;
|
|
break;
|
|
//
|
|
// A default is to download as bitmap.
|
|
//
|
|
case TTDOWNLOAD_BITMAP:
|
|
UFObj.dwFlags |= UFOFLAG_TTDOWNLOAD_BITMAP | UFOFLAG_TTFONT;
|
|
break;
|
|
case TTDOWNLOAD_TTOUTLINE:
|
|
UFObj.dwFlags |= UFOFLAG_TTDOWNLOAD_TTOUTLINE | UFOFLAG_TTFONT;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
pFontPDev->pUFObj = &UFObj;
|
|
}
|
|
else
|
|
{
|
|
pFontPDev->pUFObj = NULL;
|
|
}
|
|
|
|
pPDev->fMode |= PF_DOWNLOADED_TEXT;
|
|
|
|
//
|
|
// Get FONTMAP
|
|
//
|
|
|
|
//
|
|
// Conditions to download:
|
|
// Text should not be printed as graphics and
|
|
// Font should be TRUETYPE and
|
|
// It is not getting substituted.
|
|
//
|
|
|
|
if ( !(dwFlags & TXTOUT_PRINTASGRX) &&
|
|
(pfo->flFontType & TRUETYPE_FONTTYPE) &&
|
|
!tod.iSubstFace )
|
|
{
|
|
|
|
//
|
|
// This function sets pfm pointer and iFace in TO_DATA.
|
|
// tod.iFace
|
|
// tod.pfm
|
|
//
|
|
if (IDownloadFont(&tod, pstro, &iRot) >= 0)
|
|
{
|
|
pfm = tod.pfm;
|
|
|
|
//
|
|
// yAdj has to be added to tod.pgp->ptl.y
|
|
//
|
|
iyAdjust = pfm ? (int)(pfm->syAdj) : 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If the call fails call engine to draw.
|
|
//
|
|
|
|
pfm = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if ( DEVICE_FONT(pfo, tod) ) // Device Font
|
|
{
|
|
if( pfo->iFace < 1 || (int)pfo->iFace > pPDev->iFonts )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
ERR(( "Invalid iFace (%ld) in DrvTextOut",pfo->iFace ));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get the stuff we really need for this font
|
|
//
|
|
|
|
tod.iFace = pfo->iFace;
|
|
|
|
pfm = PfmGetDevicePFM(pPDev, tod.iSubstFace?tod.iSubstFace:tod.iFace);
|
|
|
|
if (tod.iSubstFace)
|
|
{
|
|
UFObj.dwFlags |= UFOFLAG_TTSUBSTITUTED;
|
|
((FONTMAP_DEV*)pfm->pSubFM)->fwdFOAveCharWidth = pFontPDev->pIFI->fwdAveCharWidth;
|
|
((FONTMAP_DEV*)pfm->pSubFM)->fwdFOMaxCharInc = pFontPDev->pIFI->fwdMaxCharInc;
|
|
((FONTMAP_DEV*)pfm->pSubFM)->fwdFOUnitsPerEm = pFontPDev->pIFI->fwdUnitsPerEm;
|
|
((FONTMAP_DEV*)pfm->pSubFM)->fwdFOWinAscender = pFontPDev->pIFI->fwdWinAscender;
|
|
}
|
|
|
|
//
|
|
// Deivce font PFM must be returned.
|
|
//
|
|
if (pfm == NULL)
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
ERR(( "Invalid iFace (%ld) in DrvTextOut",pfo->iFace ));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Set the transform for Device fonts.For downloaded fonts we have already
|
|
// set the transform in download code. Check also for HP Intellifont
|
|
//
|
|
if ( DEVICE_FONT(pfo, tod) )
|
|
{
|
|
iRot = ISetScale( &pFontPDev->ctl,
|
|
pxo,
|
|
(( pfm->flFlags & FM_SCALABLE) &&
|
|
(((PFONTMAP_DEV)pfm->pSubFM)->wDevFontType ==
|
|
DF_TYPE_HPINTELLIFONT)),
|
|
(pFontPDev->flText & TC_CR_ANY)?TRUE:FALSE);
|
|
|
|
}
|
|
}
|
|
|
|
tod.iRot = iRot;
|
|
|
|
UFObj.pFontMap = pfm;
|
|
UFObj.apdlGlyph = tod.apdlGlyph;
|
|
UFObj.dwNumInGlyphTbl = pstro->cGlyphs;
|
|
|
|
//
|
|
// TO_DATA initialization
|
|
//
|
|
tod.pfm = pfm;
|
|
if (tod.iSubstFace)
|
|
{
|
|
BOOL bT2Bold, bT2Italic;
|
|
BOOL bDevBold, bDevItalic, bUnderline;
|
|
|
|
bT2Bold = (pFontPDev->pIFI->fsSelection & FM_SEL_BOLD) ||
|
|
(pfo->flFontType & FO_SIM_BOLD);
|
|
bT2Italic = (pFontPDev->pIFI->fsSelection & FM_SEL_ITALIC) ||
|
|
(pfo->flFontType & FO_SIM_ITALIC);
|
|
|
|
bDevBold = (pfm->pIFIMet->fsSelection & FM_SEL_BOLD) ||
|
|
(pfm->pIFIMet->usWinWeight > FW_NORMAL);
|
|
bDevItalic = (pfm->pIFIMet->fsSelection & FM_SEL_ITALIC) ||
|
|
(pfm->pIFIMet->lItalicAngle != 0);
|
|
|
|
bUnderline = ((pFontPDev->flFlags & FDV_UNDERLINE) && prclExtra)?FONTATTR_UNDERLINE:0;
|
|
|
|
tod.dwAttrFlags =
|
|
((bT2Bold && !bDevBold)?FONTATTR_BOLD:0) |
|
|
((bT2Italic && !bDevItalic)?FONTATTR_ITALIC:0) |
|
|
(bUnderline?FONTATTR_UNDERLINE:0) |
|
|
FONTATTR_SUBSTFONT;
|
|
}
|
|
else
|
|
tod.dwAttrFlags =
|
|
( ((pfo->flFontType & FO_SIM_BOLD)?FONTATTR_BOLD:0)|
|
|
((pfo->flFontType & FO_SIM_ITALIC)?FONTATTR_ITALIC:0)|
|
|
(((pFontPDev->flFlags & FDV_UNDERLINE) && prclExtra)?FONTATTR_UNDERLINE:0)
|
|
);
|
|
|
|
//
|
|
// If DEVICE_FONTTYPE not set, we are dealing with a GDI font. If
|
|
// the printer can handle it, we should consider downloading the font
|
|
// to make it a pseudo device font. If this is a heavily used font,
|
|
// then printing will be MUCH faster.
|
|
//
|
|
// However there are some points to consider. Firstly, we need to
|
|
// consider the available memory in the printer; little will be gained
|
|
// by downloading a 72 point font, since there can only be a few
|
|
// glyphs per page. Also, if the font is not black (or at least a
|
|
// solid colour), then it cannot be treated as a downloaded font.
|
|
//
|
|
// If the font is TT and we are not doing font substitution,
|
|
// then check for Conditions for not downloading, which are:
|
|
//
|
|
// GDI Font with no cache (DDI spec, iUniq == 0) or
|
|
// Text should be printed as graphics or
|
|
// The Text is white, Assume that there is some merged graphics or
|
|
// iDownLoadFont fails and returns an invalid download index or
|
|
// OEM font download callback doesn't support correct formats.
|
|
//
|
|
|
|
if ( !(DEVICE_FONT(pfo, tod)) &&
|
|
( (pfo->iUniq == 0) ||
|
|
(dwFlags & TXTOUT_PRINTASGRX) ||
|
|
( pfm == NULL ) ||
|
|
( pPDev->pOemHookInfo &&
|
|
pPDev->pOemHookInfo[EP_OEMTTDownloadMethod].pfnHook &&
|
|
(UFObj.dwFlags & (UFOFLAG_TTDOWNLOAD_BITMAP |
|
|
UFOFLAG_TTDOWNLOAD_TTOUTLINE)) == 0)
|
|
)
|
|
)
|
|
{
|
|
|
|
/*
|
|
* GDI font, and either cannot or do not wish to download.
|
|
* So, let the engine handle it!
|
|
*/
|
|
PrintAsBitmap:
|
|
|
|
if (!(dwFlags & TXTOUT_DMS)) // bitmap surface
|
|
{
|
|
CheckBitmapSurface(pso,&pstro->rclBkGround);
|
|
#ifdef WINNT_40 //NT 4.0
|
|
STROBJ_vEnumStart(pstro);
|
|
#endif
|
|
bRet = EngTextOut( pso,
|
|
pstro,
|
|
pfo,
|
|
pco,
|
|
prclExtra,
|
|
prclOpaque,
|
|
pboFore,
|
|
pboOpaque,
|
|
pptlBrushOrg,
|
|
mix );
|
|
|
|
}
|
|
else
|
|
HANDLE_VECTORPROCS_RET(pPDev, VMTextOutAsBitmap, bRet, (pso, pstro, pfo, pco, prclExtra, prclOpaque, pboFore, pboOpaque, pptlBrushOrg, mix))
|
|
else
|
|
{
|
|
if ( pPDev->pOemHookInfo &&
|
|
(pfnOEMTextOutAsBitmap = (PFN_OEMTextOutAsBitmap)
|
|
pPDev->pOemHookInfo[EP_OEMTextOutAsBitmap].pfnHook))
|
|
{
|
|
|
|
bRet = FALSE;
|
|
FIX_DEVOBJ(pPDev, EP_OEMTextOutAsBitmap);
|
|
|
|
if(pPDev->pOemEntry)
|
|
{
|
|
if(((POEM_PLUGIN_ENTRY)pPDev->pOemEntry)->pIntfOem ) // OEM plug in uses COM and function is implemented.
|
|
{
|
|
HRESULT hr ;
|
|
hr = HComTextOutAsBitmap((POEM_PLUGIN_ENTRY)pPDev->pOemEntry,
|
|
pso,
|
|
pstro,
|
|
pfo,
|
|
pco,
|
|
prclExtra,
|
|
prclOpaque,
|
|
pboFore,
|
|
pboOpaque,
|
|
pptlBrushOrg,
|
|
mix );
|
|
if(SUCCEEDED(hr))
|
|
bRet = TRUE ; // cool !
|
|
}
|
|
else
|
|
{
|
|
bRet = pfnOEMTextOutAsBitmap (pso,
|
|
pstro,
|
|
pfo,
|
|
pco,
|
|
prclExtra,
|
|
prclOpaque,
|
|
pboFore,
|
|
pboOpaque,
|
|
pptlBrushOrg,
|
|
mix );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
bRet = FALSE;
|
|
}
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Mark the scanlines to indicate the present of text, z-ordering fix
|
|
//
|
|
// returns BYTE
|
|
//
|
|
|
|
if (!(dwFlags & TXTOUT_DMS)) // bitmap surface
|
|
{
|
|
//
|
|
// Mark the scanlines to indicate the present of text, z-ordering fix
|
|
//
|
|
|
|
ubMask = BGetMask(pPDev, &rclRegion);
|
|
for (iI = rclRegion.top; iI < rclRegion.bottom ; iI++)
|
|
{
|
|
pPDev->pbScanBuf[iI] |= ubMask;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Serial printers (those requiring the text be fed out at the same
|
|
* time as the raster data) are processed by storing all the text
|
|
* at this time, then playing it back while rendering the bitamp.
|
|
* THIS ALSO HAPPENS FOR WHITE TEXT, on those printers capable
|
|
* of doing this. The difference is that the white text is played
|
|
* back in one hit AFTER RENDERING THE BITMAP.
|
|
*/
|
|
|
|
//
|
|
// Realize the Color
|
|
//
|
|
|
|
if ((!(dwFlags & TXTOUT_DMS)) &&
|
|
!(tod.pvColor = GSRealizeBrush(pPDev, pso, pboFore)) )
|
|
{
|
|
ERR(( "GSRealizeBrush Failed;Can't Realize the Color\n" ));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Font selection
|
|
//
|
|
// Initialize pfnDrwaGlyph function pointer
|
|
// pfnDrwaGlyph cound be
|
|
// BPSGlyphOut -- Dot matrics
|
|
// BWhiteText -- White character
|
|
// BRealGlyphOut -- Device font output
|
|
// BDLGlyphOut -- TrueType download font output
|
|
//
|
|
|
|
if( pFontPDev->flFlags & FDV_MD_SERIAL )
|
|
{
|
|
//
|
|
// yAdj has to be added to tod.pgp->ptl.y
|
|
// Device font could be scalable font so that iyAdjust calculation
|
|
// has to be done after BNewFont.
|
|
//
|
|
iyAdjust = (int)pfm->syAdj + (int)((PFONTMAP_DEV)pfm->pSubFM)->sYAdjust;
|
|
|
|
//
|
|
// Dot matrix or white text on an LJ style printer
|
|
//
|
|
pfnDrawGlyph = BPSGlyphOut;
|
|
|
|
//
|
|
//For Serial printer White text is also interlaced.
|
|
//
|
|
dwFlags &= ~(TXTOUT_CACHED|TXTOUT_SETPOS); /* Assume position is set elsewhere */
|
|
}
|
|
else
|
|
{
|
|
|
|
/*
|
|
* Page printer - e.g. LaserJet. If this is a font that we
|
|
* have downloaded, then there is a specific output routine
|
|
* to use. Using a downloaded font is rather tricky, as we need
|
|
* to translate HGLYPHs to char index, or possibly bitblt the
|
|
* bitmap to the page bitmap.
|
|
*/
|
|
|
|
if( DEVICE_FONT(pfo, tod) )
|
|
{
|
|
if (dwFlags & TXTOUT_COLORBK)
|
|
{
|
|
/* Z-ordering fix, delay device font to the end */
|
|
dwFlags |= TXTOUT_CACHED;
|
|
}
|
|
|
|
UFObj.ulFontID = ((PFONTMAP_DEV)pfm->pSubFM)->dwResID;
|
|
|
|
pfnDrawGlyph = BRealGlyphOut;
|
|
BNewFont(pPDev,
|
|
tod.iSubstFace?tod.iSubstFace:tod.iFace,
|
|
pfm,
|
|
tod.dwAttrFlags);
|
|
|
|
//
|
|
// yAdj has to be added to tod.pgp->ptl.y
|
|
// Device font could be scalable font so that iyAdjust calculation
|
|
// has to be done after BNewFont.
|
|
//
|
|
iyAdjust = (int)pfm->syAdj + (int)((PFONTMAP_DEV)pfm->pSubFM)->sYAdjust;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// GDI font (TrueType), so we will want print it. All the glyphs
|
|
// are already downloaded. The font has already been selected by
|
|
// IDownloadFont
|
|
//
|
|
pfnDrawGlyph = BDLGlyphOut;
|
|
UFObj.ulFontID = pfm->ulDLIndex;
|
|
}
|
|
|
|
//
|
|
// For DMS we don't want to not cache the text. So turn off
|
|
// TXTOUT_CACHED flag.
|
|
//
|
|
if (dwFlags & TXTOUT_DMS)
|
|
dwFlags &= ~TXTOUT_CACHED;
|
|
|
|
//
|
|
// For cached text always use BWhiteText as we need to send cached text
|
|
// after the graphics.
|
|
//
|
|
if (dwFlags & TXTOUT_CACHED)
|
|
{
|
|
pfnDrawGlyph = BWhiteText;
|
|
}
|
|
|
|
dwFlags |= TXTOUT_SETPOS;
|
|
|
|
}
|
|
|
|
/*
|
|
* Also set the colour - ignored if already set or irrelevant
|
|
* We want to select the color only if we are not caching the text.
|
|
* Cache text when we have white text or it's a serial printer
|
|
*/
|
|
|
|
if (!((dwFlags & TXTOUT_DMS) || (dwFlags & TXTOUT_CACHED) ||
|
|
(pFontPDev->flFlags & FDV_MD_SERIAL)))
|
|
SelectTextColor( pPDev, tod.pvColor );
|
|
|
|
//
|
|
// Initialize iXInc and iYInc for SO_FLAG_DEFAULT_PLACEMENT
|
|
//
|
|
|
|
iXInc = iYInc = 0; /* We do nothing case */
|
|
|
|
if( (pstro->flAccel & SO_FLAG_DEFAULT_PLACEMENT) && pstro->ulCharInc )
|
|
{
|
|
/*
|
|
* We need to calculate the positions ourselves, as GDI has
|
|
* become lazy to gain some speed - I guess.
|
|
*/
|
|
|
|
if( pstro->flAccel & SO_HORIZONTAL )
|
|
iXInc = pstro->ulCharInc;
|
|
|
|
if( pstro->flAccel & SO_VERTICAL )
|
|
iYInc = pstro->ulCharInc;
|
|
|
|
if( pstro->flAccel & SO_REVERSED )
|
|
{
|
|
/* Going the other way! */
|
|
iXInc = -iXInc;
|
|
iYInc = -iYInc;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate GLYPHPOS structure.
|
|
//
|
|
|
|
pgp = MemAlloc(sizeof(GLYPHPOS) * pstro->cGlyphs);
|
|
|
|
if (!pgp)
|
|
{
|
|
ERR(("pgp memory allocation failed\r\n"));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
//
|
|
// Allocate pbClipBits. size = cMaxGlyphs / BBITS
|
|
//
|
|
|
|
if (!(pbClipBits = MemAlloc((pstro->cGlyphs + BBITS - 1)/ BBITS)))
|
|
{
|
|
ERR(("pbClipBits memory allocation failed\r\n"));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Start Glyph Enumuration
|
|
//
|
|
//
|
|
// Enumuration
|
|
//
|
|
// (a) iStartIndex - phSubstGlyphOrg
|
|
// (b) dwPGPStartIndex - pgp, pbClipBits, tod
|
|
//
|
|
// (pgp, pbClipBits)
|
|
// |
|
|
// | dwPGPStartIndex
|
|
// | |
|
|
// | v +Current point in the string.
|
|
// | |
|
|
// |<----->|
|
|
// | |<----dwGlyphToPrint--->| |
|
|
// v | v |
|
|
// |-----------------------------+-------------------------------|
|
|
// ^ |
|
|
// |<-----iStartIndex--->|<------------dwTotalGlyph------------->|
|
|
// |
|
|
// phSubstGlyphOrg
|
|
//
|
|
|
|
iStartIndex = 0;
|
|
tod.dwCurrGlyph = 0;
|
|
tod.flFlags |= TODFL_FIRST_ENUMRATION;
|
|
|
|
STROBJ_vEnumStart(pstro);
|
|
do
|
|
{
|
|
#ifndef WINNT_40 //NT 5.0
|
|
|
|
bMore = STROBJ_bEnumPositionsOnly( pstro, &dwTotalGlyph, &pgpTmp );
|
|
|
|
#else // NT 4.0
|
|
|
|
bMore = STROBJ_bEnum( pstro, &dwTotalGlyph, &pgpTmp );
|
|
|
|
#endif //!WINNT_40
|
|
|
|
CopyMemory(pgp, pgpTmp, sizeof(GLYPHPOS) * dwTotalGlyph);
|
|
|
|
//
|
|
// Set the first Glyph position in the TextOut data. This can be used
|
|
// by Glyph Output functions to optimize.
|
|
//
|
|
tod.ptlFirstGlyph = pgp[0].ptl;
|
|
|
|
//
|
|
// Evaluate the position of the chars if this is needed.
|
|
// SO_FLAG_DEFAULT_PLACEMENT case
|
|
//
|
|
|
|
if( iXInc || iYInc )
|
|
{
|
|
//
|
|
// NT4.0 font support or GDI soft font
|
|
//
|
|
if ( !(pfo->flFontType & DEVICE_FONTTYPE) ||
|
|
(pfm->flFlags & FM_IFIVER40) )
|
|
{
|
|
for( iI = 1; iI < (int)dwTotalGlyph; ++iI )
|
|
{
|
|
pgp[ iI ].ptl.x = pgp[ iI - 1 ].ptl.x + iXInc;
|
|
pgp[ iI ].ptl.y = pgp[ iI - 1 ].ptl.y + iYInc;
|
|
}
|
|
}
|
|
else
|
|
//
|
|
// NT5.0 device font support
|
|
//
|
|
{
|
|
PMAPTABLE pMapTable;
|
|
PTRANSDATA pTrans;
|
|
|
|
pMapTable = GET_MAPTABLE(((PFONTMAP_DEV)pfm->pSubFM)->pvNTGlyph);
|
|
pTrans = pMapTable->Trans;
|
|
|
|
//
|
|
// iXInc and iYInc are DBCS width when Far East charset.
|
|
//
|
|
for( iI = 1; iI < (int)dwTotalGlyph; ++iI )
|
|
{
|
|
if (pTrans[pgp[iI].hg - 1].ubType & MTYPE_SINGLE)
|
|
{
|
|
pgp[ iI ].ptl.x = pgp[ iI - 1 ].ptl.x + iXInc/2;
|
|
pgp[ iI ].ptl.y = pgp[ iI - 1 ].ptl.y + iYInc;
|
|
}
|
|
else
|
|
{
|
|
pgp[ iI ].ptl.x = pgp[ iI - 1 ].ptl.x + iXInc;
|
|
pgp[ iI ].ptl.y = pgp[ iI - 1 ].ptl.y + iYInc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the pgp in TextOut Data for Clipping.
|
|
//
|
|
tod.pgp = pgp;
|
|
dwPGPStartIndex = 0;
|
|
|
|
//
|
|
// Check to see if there is any character at the boundary of clipping
|
|
// rectangle.
|
|
//
|
|
VClipIt( pbClipBits, &tod, pco, pstro, dwTotalGlyph, iRot, pFontPDev->flFlags & FDV_ENABLE_PARTIALCLIP);
|
|
|
|
//
|
|
// If partial clipping has happend for TT font, call EngTextOut.
|
|
//
|
|
if (tod.flFlags & TODFL_TTF_PARTIAL_CLIPPING )
|
|
{
|
|
//
|
|
// We have to use goto, but no other better way.
|
|
//
|
|
goto PrintAsBitmap;
|
|
}
|
|
|
|
//
|
|
// Replace pgp's hg with Device font glyph handle
|
|
//
|
|
if (tod.iSubstFace)
|
|
{
|
|
tod.phGlyph =
|
|
phSubstGlyph = phSubstGlyphOrg + iStartIndex;
|
|
|
|
pgpTmp = pgp;
|
|
|
|
for (iJ = 0; iJ < (INT)(int)dwTotalGlyph; iJ++, pgpTmp++)
|
|
{
|
|
pgpTmp->hg = *phSubstGlyph++;
|
|
}
|
|
}
|
|
|
|
while ( dwTotalGlyph > dwPGPStartIndex )
|
|
{
|
|
//
|
|
// Got the glyph data, so onto the real work!
|
|
//
|
|
|
|
if (BGetStartGlyphandCount(pbClipBits,
|
|
dwTotalGlyph,
|
|
&dwPGPStartIndex,
|
|
&dwGlyphToPrint))
|
|
{
|
|
//VERBOSE(("dwTotalGlyph = %d\n", dwTotalGlyph));
|
|
//VERBOSE(("dwGlyphToPrint = %d\n", dwGlyphToPrint));
|
|
//VERBOSE(("dwPGPStartIndex = %d\n", dwPGPStartIndex));
|
|
|
|
ASSERT((dwTotalGlyph > dwPGPStartIndex));
|
|
|
|
tod.dwCurrGlyph = iStartIndex + dwPGPStartIndex;
|
|
|
|
//
|
|
// DCR: Add the Glyph position optimization call here.
|
|
// If we are drawing Underline or strike through then disable
|
|
// default placement optimization.
|
|
//
|
|
// if( prclExtra )
|
|
// tod.flFlags &= ~TODFL_DEFAULT_PLACEMENT;
|
|
|
|
if (dwFlags & TXTOUT_SETPOS)
|
|
{
|
|
|
|
//
|
|
// Set initial position so that LaserJets can
|
|
// use relative position. This is deferred until
|
|
// here because applications (e.g. Excel) start
|
|
// printing right off the edge of the page, and
|
|
// our position tracking code then needs to
|
|
// understand what the printer does about moving
|
|
// out of the printable area. This is too risky
|
|
// to be safe, so we save setting the position
|
|
// until we are in the printable region. Note
|
|
// that this assumes that the clipping data we
|
|
// have is limited to the printable region.
|
|
// I believe this to be true (16 June 1993).
|
|
//
|
|
//
|
|
// We need to handle the return value. Devices with
|
|
// resoloutions finer than their movement capability
|
|
// (like LBP-8 IV) get into a knot here , attempting
|
|
// to y-move on each glyph. We pretend we got where
|
|
// we wanted to be.
|
|
//
|
|
|
|
VSetCursor( pPDev,
|
|
pgp[dwPGPStartIndex].ptl.x,
|
|
pgp[dwPGPStartIndex].ptl.y+(iyAdjust?iyAdjust:0),
|
|
MOVE_ABSOLUTE,
|
|
&ptlRem);
|
|
|
|
pPDev->ctl.ptCursor.y += ptlRem.y;
|
|
|
|
|
|
VSetRotation( pFontPDev, iRot ); /* It's safe now */
|
|
|
|
//
|
|
// If the default placement is not set then we need to set
|
|
// the cursor for each enumration. So we clear the SETPOS
|
|
// flag only for default placement.
|
|
//
|
|
|
|
if ((pstro->flAccel & SO_FLAG_DEFAULT_PLACEMENT))
|
|
dwFlags &= ~TXTOUT_SETPOS;
|
|
|
|
//
|
|
// we set the cursor to forst glyph position. So set
|
|
// the TODFL_FIRST_GLYPH_POS_SET flag. Output function
|
|
// don't need to do a explicit move to this position.
|
|
//
|
|
tod.flFlags |= TODFL_FIRST_GLYPH_POS_SET;
|
|
}
|
|
|
|
|
|
tod.pgp = pgp + dwPGPStartIndex;
|
|
tod.cGlyphsToPrint = dwGlyphToPrint;
|
|
|
|
if ( iyAdjust )
|
|
{
|
|
for ( iI = 0; iI < (int)dwGlyphToPrint; iI ++)
|
|
tod.pgp[iI].ptl.y += iyAdjust;
|
|
}
|
|
|
|
if( !pfnDrawGlyph( &tod ) )
|
|
{
|
|
ERR(( "Glyph Drawing Failed;Can't draw the glyph\n" ));
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
else // None of the Glyphs are printable.
|
|
{
|
|
//
|
|
// If none of the glyphs are printable that update the counters
|
|
// to point to next run.
|
|
//
|
|
|
|
dwGlyphToPrint = dwTotalGlyph;
|
|
}
|
|
|
|
dwPGPStartIndex += dwGlyphToPrint;
|
|
}
|
|
|
|
iStartIndex += dwTotalGlyph;
|
|
|
|
//
|
|
// Clear the first enumartion flag, if more glyphs has to be enumerated.
|
|
//
|
|
if (bMore)
|
|
{
|
|
tod.flFlags &= ~TODFL_FIRST_ENUMRATION;
|
|
|
|
}
|
|
|
|
} while( bMore );
|
|
|
|
//
|
|
// Actual character printing. We may have enumurated once for downloading.
|
|
// So call STROBJ_vEnumStart here.
|
|
//
|
|
|
|
//
|
|
// Restore the normal graphics orientation by setting rotation to 0.
|
|
//
|
|
|
|
VSetRotation( pFontPDev, 0 );
|
|
|
|
/*
|
|
* Do the rectangles. If present, these are defined by prclExtra.
|
|
* Typically these are used for strikethrough and underline.
|
|
*/
|
|
|
|
if( prclExtra )
|
|
{
|
|
if (!DRIVER_DEVICEMANAGED (pPDev) && // If not device managed surface
|
|
!(pFontPDev->flFlags & FDV_UNDERLINE))
|
|
{
|
|
/* prclExtra is an array of rectangles; we loop through them
|
|
* until we find one where all 4 points are 0.engine does not
|
|
* follow the spec - only sets x coords to 0.
|
|
*/
|
|
|
|
while( prclExtra->left != prclExtra->right &&
|
|
prclExtra->bottom != prclExtra->top )
|
|
{
|
|
|
|
/* Use the engine's Bitblt function to draw the rectangles.
|
|
* last parameter is 0 for black!!
|
|
*/
|
|
|
|
CheckBitmapSurface(pso,prclExtra);
|
|
if( !EngBitBlt( pso, NULL, NULL, pco, NULL, prclExtra, NULL, NULL,
|
|
pboFore, pptlBrushOrg, 0 ) )
|
|
{
|
|
ERR(( "EngBitBlt Failed;Can't draw rectangle simulations\n" ));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
++prclExtra;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the dwFreeMem in PDEV
|
|
//
|
|
if( pPDev->dwFreeMem && (pFontPDev->flFlags & FDV_TRACK_FONT_MEM) )
|
|
{
|
|
pPDev->dwFreeMem = pFontPDev->dwFontMem - pFontPDev->dwFontMemUsed;
|
|
pFontPDev->dwFontMemUsed = 0;
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
//
|
|
// Free pbClipBits
|
|
//
|
|
ErrorExit:
|
|
|
|
//
|
|
// In case of white text, BPlayWhite text must free the pgp.
|
|
//
|
|
|
|
if (pgp)
|
|
MemFree(pgp);
|
|
if (pbClipBits)
|
|
MemFree(pbClipBits);
|
|
if (phSubstGlyphOrg)
|
|
MemFree(phSubstGlyphOrg);
|
|
MEMFREEANDRESET(tod.apdlGlyph );
|
|
VUFObjFree(pFontPDev);
|
|
pFontPDev->ptod = NULL;
|
|
pFontPDev->pIFI = NULL;
|
|
pFontPDev->pUFObj = NULL;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
BPrintTextAsGraphics(
|
|
PDEV *pPDev,
|
|
ULONG iSolidColor,
|
|
DWORD dwForeColor,
|
|
DWORD dwFlags,
|
|
INT iSubstFace
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This routine checks the textout flag for printing text as graphics.
|
|
|
|
Arguments:
|
|
pPDev PDEV struct.
|
|
dwFlags TextOut Flags
|
|
|
|
Return Value:
|
|
TRUE if text should be printed as graphics else FALSE
|
|
|
|
Note:
|
|
|
|
10/9/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
|
|
{
|
|
FONTPDEV *pFontPDev; // FONTMODULE based PDEV
|
|
|
|
|
|
//
|
|
// Local initialization.
|
|
//
|
|
pFontPDev = pPDev->pFontPDev;
|
|
|
|
//
|
|
// DMS
|
|
//
|
|
if (pPDev->ePersonality == kPCLXL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Condition to print as graphics:
|
|
// No substitution and Download option is FALSE in bitmap mode .
|
|
//
|
|
if ( (!iSubstFace && !(pFontPDev->flFlags & FDV_DLTT)) ||
|
|
//
|
|
// Font is rotated.
|
|
//
|
|
!(dwFlags & TXTOUT_NOTROTATED) ||
|
|
//
|
|
// TXTOUT_COLORBK says that there is a color background. Merging with
|
|
// Graphics. For non DMS case.
|
|
//
|
|
(dwFlags & TXTOUT_COLORBK) ||
|
|
|
|
//
|
|
// Color is non Primary color or Model doesn't supports programmable
|
|
// foreground Color
|
|
//
|
|
// Print text as graphics, if device doesn't support programable
|
|
// foreground color and the color of text is dithered and not black.
|
|
//
|
|
(!(dwFlags & TXTOUT_FGCOLOR) &&
|
|
iSolidColor == DITHERED_COLOR &&
|
|
(0x00FFFFFF & dwForeColor) != 0x00000000) ||
|
|
|
|
//
|
|
// Disable substitution of device font for TrueType, if device does't
|
|
// support programable foreground color and color is not black.
|
|
//
|
|
(iSubstFace &&
|
|
!(dwFlags & TXTOUT_FGCOLOR) &&
|
|
(0x00FFFFFF & dwForeColor) != 0x00000000)
|
|
)
|
|
{
|
|
return TRUE;
|
|
|
|
}
|
|
else
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// pfnDrawGlyph functions
|
|
// BDLGlyphOut
|
|
// BWhiteText
|
|
// BRealGlyphOut
|
|
// BDLGGlyphOut
|
|
//
|
|
|
|
BOOL
|
|
BDLGlyphOut(
|
|
TO_DATA *pTOD
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Function to process a glyph for a GDI font we have downloaded. We
|
|
either treat this as a normal character if this glyph has been
|
|
downloaded, or BitBlt it to the page bitmap if it is one we did
|
|
not download.
|
|
|
|
Arguments:
|
|
|
|
pTOD Textout Data. Holds all necessary information.
|
|
|
|
Return Value:
|
|
|
|
TRUE for success and FALSE for failure
|
|
|
|
Note:
|
|
|
|
1/21/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
|
|
{
|
|
BOOL bRet;
|
|
FONTMAP *pFM;
|
|
|
|
bRet = FALSE;
|
|
|
|
if ( pFM = pTOD->pfm)
|
|
{
|
|
//
|
|
// Check if the glyphout fucntions pointer is not null and then call
|
|
// the function. We also have to check the return value. The fmtxtout
|
|
// function assumes that the Glyphout fucntion will print all the
|
|
// glyphs it requested to print i.e pTOD->cGlyphsToPrint should be
|
|
// equal to return value of pFM->pfnGlyphOut.
|
|
//
|
|
|
|
if ( pFM->pfnGlyphOut )
|
|
{
|
|
DWORD dwGlyphPrinted;
|
|
|
|
dwGlyphPrinted = pFM->pfnGlyphOut(pTOD);
|
|
|
|
if (dwGlyphPrinted != pTOD->cGlyphsToPrint)
|
|
{
|
|
ERR(("UniFont!BDLGlyphOut:pfnGlyphOut didn't print all glyphs\n"));
|
|
}
|
|
else
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ERR(("UniFont!BDLGlyphOut:pFM->pfnGlyphOut is NULL\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERR(("UniFont!BDLGlyphOut:pTOD->pfm is NULL, Can't do glyphout\n"));
|
|
}
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
BRealGlyphOut(
|
|
register TO_DATA *pTOD
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Print this glyph on the printer, at the given position. Unlike
|
|
bPSGlyphOut, the data is actually spooled for output now, since this
|
|
function is used for things like LaserJets, i.e. page printers.
|
|
|
|
Arguments:
|
|
pTOD Textout Data. Holds all necessary information.
|
|
|
|
Return Value:
|
|
TRUE for success and FALSE for failure
|
|
|
|
Note:
|
|
|
|
1/21/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// All we need to do is set the Y position, then call bOutputGlyph
|
|
// to do the actual work.
|
|
//
|
|
|
|
PDEV *pPDev;
|
|
PGLYPHPOS pgp; // Glyph positioning info
|
|
DWORD dwGlyph;
|
|
INT iX,iY; // Calculate real position
|
|
BOOL bRet;
|
|
|
|
ASSERTMSG(pTOD->pfm->pfnGlyphOut, ("NULL GlyphOut Funtion Ptr\n"));
|
|
|
|
pPDev = pTOD->pPDev;
|
|
pgp = pTOD->pgp;
|
|
dwGlyph = pTOD->cGlyphsToPrint;
|
|
|
|
if (pTOD->pfm->pfnGlyphOut)
|
|
{
|
|
pTOD->pfm->pfnGlyphOut( pTOD );
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ASSERTMSG(FALSE,("NULL GlyphOut function pointer\n"));
|
|
bRet = FALSE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BWhiteText(
|
|
TO_DATA *pTOD
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Called to store details of the white text. Basically the data is
|
|
stored away until it is time to send it to the printer. That time
|
|
is AFTER the graphics data has been sent.
|
|
|
|
Arguments:
|
|
pTOD Textout Data. Holds all necessary information.
|
|
|
|
Return Value:
|
|
TRUE for success and FALSE for failure
|
|
|
|
Note:
|
|
|
|
1/21/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
|
|
{
|
|
WHITETEXT *pWT, *pWTLast;
|
|
FONTCTL FontCtl;
|
|
FONTPDEV* pFontPDev;
|
|
DWORD dwWhiteTextAlign;
|
|
DWORD dwIFIAlign;
|
|
BOOL bRet;
|
|
|
|
pFontPDev = pTOD->pPDev->pFontPDev; // The important stuff
|
|
|
|
//
|
|
// Note that we allocate a new one of these for each
|
|
// iteration of this loop - that would be slightly wasteful
|
|
// if we ever executed this loop more than once, but that
|
|
// is unlikely.
|
|
//
|
|
|
|
pWT = NULL;
|
|
//
|
|
// 64 bit align.
|
|
//
|
|
dwWhiteTextAlign = (sizeof(WHITETEXT) + 7) / 8 * 8;
|
|
dwIFIAlign = (pFontPDev->pIFI->cjThis + 7) / 8 * 8;
|
|
|
|
if ( (pWT = (WHITETEXT *)MemAllocZ(dwWhiteTextAlign + dwIFIAlign +
|
|
pTOD->cGlyphsToPrint * sizeof(GLYPHPOS))))
|
|
{
|
|
pWT->next = NULL;
|
|
pWT->sCount = (SHORT)pTOD->cGlyphsToPrint;
|
|
pWT->iFontId = pTOD->iSubstFace?pTOD->iSubstFace:pTOD->iFace;
|
|
pWT->pvColor = pTOD->pvColor;
|
|
pWT->dwAttrFlags = pTOD->dwAttrFlags;
|
|
pWT->flAccel = pTOD->flAccel;
|
|
pWT->rcClipRgn = pTOD->pPDev->rcClipRgn;
|
|
pWT->iRot = pTOD->iRot;
|
|
pWT->eXScale = pFontPDev->ctl.eXScale;
|
|
pWT->eYScale = pFontPDev->ctl.eYScale;
|
|
pWT->pIFI = (IFIMETRICS*)((PBYTE)pWT + dwWhiteTextAlign);
|
|
CopyMemory(pWT->pIFI, pFontPDev->pIFI, pFontPDev->pIFI->cjThis);
|
|
pWT->pgp = (GLYPHPOS *)((PBYTE)pWT->pIFI + dwIFIAlign);
|
|
CopyMemory(pWT->pgp, pTOD->pgp, pWT->sCount * sizeof(GLYPHPOS));
|
|
|
|
//
|
|
// True Type Font download case
|
|
//
|
|
if ( (pTOD->pfo->flFontType & TRUETYPE_FONTTYPE) &&
|
|
(pTOD->iSubstFace == 0) )
|
|
{
|
|
//
|
|
// We need to copy the download glyph array.Allocate the array
|
|
// for DLGLYPHs.
|
|
//
|
|
|
|
if (!(pWT->apdlGlyph = MemAllocZ( pWT->sCount * sizeof(DLGLYPH *))))
|
|
{
|
|
ERR(("UniFont:BWhiteText: MemAlloc for pWT->apdlGlyph failed\n"));
|
|
goto ErrorExit;
|
|
}
|
|
CopyMemory( pWT->apdlGlyph, &(pTOD->apdlGlyph[pTOD->dwCurrGlyph]),
|
|
pWT->sCount * sizeof(DLGLYPH *) );
|
|
|
|
}
|
|
|
|
//
|
|
// Put new text at the end of the list
|
|
//
|
|
if (!(pFontPDev->pvWhiteTextFirst))
|
|
pFontPDev->pvWhiteTextFirst = pWT;
|
|
|
|
if (pWTLast = (WHITETEXT *)pFontPDev->pvWhiteTextLast)
|
|
pWTLast->next = pWT;
|
|
|
|
pFontPDev->pvWhiteTextLast = pWT;
|
|
|
|
bRet = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
ErrorExit:
|
|
ERR(( "MemAlloc failed for white text.\n" ));
|
|
bRet = FALSE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BPSGlyphOut(
|
|
register TO_DATA *pTOD
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Places glyphs for dot matrix type printers. These actually store
|
|
the position and glyph data for later printing. This is because
|
|
dot matrix printers cannot or should not reverse line feed -
|
|
for positioning accuracy. Hence, play the data back when the
|
|
bitmap is being rendered to the printer. Output occurs in the
|
|
following function, bDelayGlyphOut.
|
|
|
|
Arguments:
|
|
pTOD Textout Data. Holds all necessary information.
|
|
|
|
Return Value:
|
|
TRUE/FALSE. FALSE if the glyph storage fails.
|
|
Note:
|
|
|
|
1/21/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
{
|
|
PGLYPHPOS pgp; // Glyph positioning info
|
|
PSGLYPH psg; // Data to store away
|
|
PFONTPDEV pFontPDev;
|
|
|
|
DWORD dwGlyph;
|
|
SHORT sFontIndex;
|
|
|
|
INT iyVal;
|
|
|
|
pFontPDev = (PFONTPDEV)pTOD->pPDev->pFontPDev;
|
|
|
|
pgp = pTOD->pgp;
|
|
dwGlyph = pTOD->cGlyphsToPrint;
|
|
|
|
/*
|
|
* About all that is needed is to take the parameters, store in
|
|
* a PSGLYPH structure, and call bAddPS to add this glyph to the list.
|
|
*/
|
|
|
|
sFontIndex = pTOD->iSubstFace?pTOD->iSubstFace:pTOD->iFace;
|
|
|
|
//
|
|
// Scalable font support
|
|
//
|
|
psg.eXScale = pFontPDev->ctl.eXScale;
|
|
psg.eYScale = pFontPDev->ctl.eYScale;
|
|
|
|
while (dwGlyph--)
|
|
{
|
|
//
|
|
// Transform the input X and Y from band corrdnate to page coordinate.
|
|
//
|
|
if (pTOD->pPDev->bBanding)
|
|
{
|
|
psg.ixVal = pgp->ptl.x + pTOD->pPDev->rcClipRgn.left;
|
|
iyVal = pgp->ptl.y + pTOD->pPDev->rcClipRgn.top;
|
|
}
|
|
else
|
|
{
|
|
psg.ixVal = pgp->ptl.x;
|
|
iyVal = pgp->ptl.y;
|
|
}
|
|
|
|
psg.hg = pgp->hg;
|
|
psg.sFontIndex = sFontIndex;
|
|
psg.pvColor = pTOD->pvColor; // Which colour
|
|
psg.dwAttrFlags = pTOD->dwAttrFlags;
|
|
psg.flAccel = pTOD->flAccel;
|
|
|
|
if ( BAddPS( ((PFONTPDEV)(pTOD->pPDev->pFontPDev))->pPSHeader,
|
|
&psg,
|
|
iyVal,
|
|
((FONTMAP_DEV *)(pTOD->pfm->pSubFM))->fwdFOWinAscender) )
|
|
{
|
|
pgp ++;
|
|
|
|
}
|
|
else // Failure, So fail the call.
|
|
{
|
|
ERR(( "\nUniFont!BPSGlyphOut: BAddPS Failed.\n" ))
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Delay and White test printing entry points
|
|
//
|
|
|
|
BOOL
|
|
BPlayWhiteText(
|
|
PDEV *pPDev
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
pPDev Pointer to PDEV
|
|
|
|
Return Value:
|
|
TRUE for success and FALSE for failure
|
|
|
|
Note:
|
|
|
|
1/21/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
{
|
|
I_UNIFONTOBJ UFObj;
|
|
FONTPDEV *pFontPDev; /* Miscellaneous uses */
|
|
WHITETEXT *pwt;
|
|
TO_DATA Tod;
|
|
GLYPHPOS *pgp;
|
|
RECTL rcClipRgnOld;
|
|
DWORD dwGlyphCount;
|
|
|
|
BOOL bRet = TRUE;
|
|
|
|
//
|
|
// Save the Clip rectangle.
|
|
//
|
|
rcClipRgnOld = pPDev->rcClipRgn;
|
|
|
|
/*
|
|
* Loop through the linked list of these hanging off the PDEV.
|
|
* Mostly, of course, there will be none.
|
|
*/
|
|
|
|
pFontPDev = pPDev->pFontPDev;
|
|
pFontPDev->ptod = &Tod;
|
|
ZeroMemory(&Tod, sizeof(TO_DATA));
|
|
ZeroMemory(&UFObj, sizeof(I_UNIFONTOBJ));
|
|
dwGlyphCount = 0;
|
|
|
|
pPDev->ctl.dwMode |= MODE_BRUSH_RESET_COLOR;
|
|
GSResetBrush(pPDev);
|
|
|
|
for( pwt = pFontPDev->pvWhiteTextFirst; pwt && bRet; pwt = pwt->next )
|
|
{
|
|
int iI; /* Loop index */
|
|
int iRot; /* Rotation amount */
|
|
FONTMAP *pfm;
|
|
|
|
/*
|
|
* Not too hard - we know we are dealing with device fonts,
|
|
* and that this is NOT a serial printer, although we could
|
|
* probably handle that too. Hence, all we need do is fill in
|
|
* a TO_DATA structure, and loop through the glyphs we have.
|
|
*/
|
|
|
|
|
|
if( pwt->sCount < 1 )
|
|
continue; /* No data, so skip it */
|
|
|
|
Tod.pPDev = pPDev;
|
|
Tod.flAccel = pwt->flAccel;
|
|
Tod.dwAttrFlags = pwt->dwAttrFlags;
|
|
pgp = Tod.pgp = pwt->pgp;
|
|
Tod.cGlyphsToPrint = pwt->sCount;
|
|
|
|
if (pwt->dwAttrFlags & FONTATTR_SUBSTFONT)
|
|
{
|
|
Tod.iSubstFace = pwt->iFontId;
|
|
UFObj.dwFlags |= UFOFLAG_TTSUBSTITUTED;
|
|
}
|
|
else
|
|
{
|
|
Tod.iSubstFace = 0;
|
|
UFObj.dwFlags &= ~UFOFLAG_TTSUBSTITUTED;
|
|
}
|
|
|
|
Tod.pfm =
|
|
pfm = PfmGetIt( pPDev, pwt->iFontId );
|
|
|
|
if (NULL == pfm)
|
|
{
|
|
//
|
|
// Fatal error, PFM is not available.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// The glyph positions are wrt banding rect, so set the PDEV clip region
|
|
// to the recorded clip region.
|
|
//
|
|
pPDev->rcClipRgn = pwt->rcClipRgn;
|
|
|
|
//
|
|
// Set the download glyph array for True type downloaded fonts.
|
|
//
|
|
if (pwt->apdlGlyph)
|
|
{
|
|
Tod.apdlGlyph = pwt->apdlGlyph;
|
|
Tod.dwCurrGlyph = 0;
|
|
}
|
|
|
|
/*
|
|
* Before switching fonts, and ESPECIALLY before setting the
|
|
* font rotation, we should move to the starting position of
|
|
* the string. Then we can set the rotation and use relative
|
|
* moves to position the characters.
|
|
*/
|
|
|
|
|
|
if(pPDev->pOemHookInfo)
|
|
{
|
|
// ulFontID
|
|
// dwFlags
|
|
// pIFIMetrics
|
|
// pfnGetInfo
|
|
// pFontObj X (set to NULL)
|
|
// pStrObj X (set to NULL)
|
|
// pFontPDev
|
|
// pFontMap
|
|
// ptGrxRes
|
|
// pGlyph
|
|
|
|
if (pfm->dwFontType == FMTYPE_DEVICE)
|
|
{
|
|
UFObj.ulFontID = ((PFONTMAP_DEV)pfm->pSubFM)->dwResID;
|
|
}
|
|
else
|
|
{
|
|
UFObj.dwFlags = UFOFLAG_TTFONT;
|
|
UFObj.ulFontID = pfm->ulDLIndex;
|
|
}
|
|
|
|
if (Tod.cGlyphsToPrint)
|
|
{
|
|
if (UFObj.pGlyph != NULL && dwGlyphCount < Tod.cGlyphsToPrint)
|
|
{
|
|
MemFree(UFObj.pGlyph);
|
|
UFObj.pGlyph = NULL;
|
|
dwGlyphCount = 0;
|
|
}
|
|
|
|
if (UFObj.pGlyph == NULL)
|
|
{
|
|
UFObj.pGlyph = MemAlloc(sizeof(DWORD) * Tod.cGlyphsToPrint);
|
|
dwGlyphCount = Tod.cGlyphsToPrint;
|
|
}
|
|
}
|
|
|
|
if (pwt->dwAttrFlags & FONTATTR_SUBSTFONT)
|
|
{
|
|
//
|
|
// In the substitution case, UNIDRV needs to pass TrueType font
|
|
// IFIMETRICS to minidriver.
|
|
//
|
|
UFObj.pIFIMetrics = pwt->pIFI;
|
|
}
|
|
else
|
|
{
|
|
UFObj.pIFIMetrics = pfm->pIFIMet;
|
|
}
|
|
|
|
UFObj.pfnGetInfo = UNIFONTOBJ_GetInfo;
|
|
UFObj.pPDev = pPDev;
|
|
UFObj.pFontMap = pfm;
|
|
UFObj.ptGrxRes = pPDev->ptGrxRes;
|
|
if (pwt->apdlGlyph)
|
|
{
|
|
UFObj.apdlGlyph = Tod.apdlGlyph;
|
|
UFObj.dwNumInGlyphTbl = pwt->sCount;
|
|
}
|
|
else
|
|
{
|
|
UFObj.apdlGlyph = NULL;
|
|
UFObj.dwNumInGlyphTbl = 0;
|
|
}
|
|
|
|
pFontPDev->pUFObj = &UFObj;
|
|
}
|
|
else
|
|
pFontPDev->pUFObj = NULL;
|
|
|
|
//
|
|
// If this is a new font, it's time to change it now.
|
|
// BNewFont() checkes to see if a new font is needed.
|
|
//
|
|
pFontPDev->ctl.eXScale = pwt->eXScale;
|
|
pFontPDev->ctl.eYScale = pwt->eYScale;
|
|
|
|
BNewFont(pPDev, pwt->iFontId, pfm, pwt->dwAttrFlags);
|
|
VSetRotation( pFontPDev, pwt->iRot );
|
|
|
|
/* Also set the colour - ignored if already set or irrelevant */
|
|
SelectTextColor( pPDev, pwt->pvColor );
|
|
ASSERTMSG(pfm->pfnGlyphOut, ("NULL GlyphOut Funtion Ptr\n"));
|
|
if( !pfm->pfnGlyphOut( &Tod))
|
|
{
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
VSetRotation( pFontPDev, 0 ); /* For MoveTo calls */
|
|
//
|
|
// Reset TODFL_FIRST_GLYPH_POS_SET so that the cursor is set next time.
|
|
//
|
|
Tod.flFlags &= ~TODFL_FIRST_GLYPH_POS_SET;
|
|
}
|
|
|
|
VSetRotation( pFontPDev, 0 ); /* Back to normal */
|
|
|
|
//
|
|
// Cleanup everything.
|
|
//
|
|
|
|
{
|
|
WHITETEXT *pwt0, *pwt1;
|
|
|
|
for( pwt0 = pFontPDev->pvWhiteTextFirst; pwt0; pwt0 = pwt1 )
|
|
{
|
|
pwt1 = pwt0->next;
|
|
|
|
//Free the download glyph array.
|
|
if (pwt0->apdlGlyph)
|
|
MemFree( pwt0->apdlGlyph );
|
|
MemFree( pwt0 );
|
|
}
|
|
|
|
pFontPDev->pvWhiteTextFirst =
|
|
pFontPDev->pvWhiteTextLast = NULL;
|
|
|
|
VUFObjFree(pFontPDev);
|
|
}
|
|
|
|
//
|
|
// Restore the Clip rectangle.
|
|
//
|
|
pPDev->rcClipRgn = rcClipRgnOld;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
BDelayGlyphOut(
|
|
PDEV *pPDev,
|
|
INT yPos
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Called during output to a dot matrix printer. We are passed the
|
|
PSGLYPH data stored above, and go about placing the characters
|
|
on the line.
|
|
|
|
|
|
Arguments:
|
|
pPDev Pointer to PDEV
|
|
yPos Y coordinate of interest
|
|
|
|
Return Value:
|
|
TRUE for success and FALSE for failure
|
|
|
|
Note:
|
|
|
|
1/21/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
{
|
|
BOOL bRet; /* Return value */
|
|
PSHEAD *pPSH; /* Base data for glyph info */
|
|
PSGLYPH *ppsg; /* Details of the GLYPH to print */
|
|
FONTMAP *pFM; /* Base address of FONTMAP array */
|
|
FONTPDEV *pFontPDev; /* FM's PDEV - for our convenience */
|
|
I_UNIFONTOBJ UFObj;
|
|
TO_DATA Tod;
|
|
GLYPHPOS gp;
|
|
|
|
ASSERT(pPDev);
|
|
|
|
/*
|
|
* Check to see if there are any glyphs for this Y position. If so,
|
|
* loop through each glyph, calling the appropriate output function
|
|
* as we go.
|
|
*/
|
|
|
|
pFontPDev = PFDV; /* UNIDRV data */
|
|
pFontPDev->ptod = &Tod;
|
|
pPSH = pFontPDev->pPSHeader;
|
|
bRet = TRUE; /* Until proven otherwise */
|
|
|
|
/* No Glyph Queue, so return. Check if there are device fonts? */
|
|
if(pPDev->iFonts && !pPSH)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
Tod.pPDev = pPDev;
|
|
Tod.pgp = &gp;
|
|
Tod.iSubstFace = 0;
|
|
Tod.cGlyphsToPrint = 1;
|
|
|
|
//
|
|
// Check if a minidriver supports OEM plugin.
|
|
//
|
|
if(pPDev->pOemHookInfo)
|
|
{
|
|
ZeroMemory(&UFObj, sizeof(I_UNIFONTOBJ));
|
|
UFObj.pfnGetInfo = UNIFONTOBJ_GetInfo;
|
|
UFObj.pPDev = pPDev;
|
|
UFObj.dwFlags = 0;
|
|
UFObj.ptGrxRes = pPDev->ptGrxRes;
|
|
UFObj.pGlyph = MemAlloc(sizeof(DWORD) * Tod.cGlyphsToPrint);
|
|
UFObj.apdlGlyph = NULL;
|
|
UFObj.dwNumInGlyphTbl = 0;
|
|
pFontPDev->pUFObj = &UFObj;
|
|
}
|
|
else
|
|
pFontPDev->pUFObj = NULL;
|
|
|
|
|
|
//
|
|
// Actual print out
|
|
//
|
|
if( pPSH && ISelYValPS( pPSH, yPos ) > 0 )
|
|
{
|
|
/*
|
|
* Got some, so first set the Y position, so that the glyphs
|
|
* will appear on the correct line!
|
|
*/
|
|
|
|
gp.ptl.y = yPos - pPDev->rcClipRgn.top;
|
|
|
|
//
|
|
// Reset Brush, since Raster Module might send color selection
|
|
// commnd.Set MODE_BRUSH_RESET_COLOR flag so that the brush
|
|
// color selection command is sent. This will change the current
|
|
// brush color to be default brush color. We need to reset the
|
|
// brush color as on some printers sending a color plane of
|
|
// raster date cahnges the brush color also.
|
|
//
|
|
pPDev->ctl.dwMode |= MODE_BRUSH_RESET_COLOR;
|
|
GSResetBrush(pPDev);
|
|
|
|
while( bRet && (ppsg = PSGGetNextPSG( pPSH )) )
|
|
{
|
|
/*
|
|
* Check for the correct font! Since the glyphs are now
|
|
* in an indeterminate order, we need to check EACH one for
|
|
* the font, since each one can be different, as we have
|
|
* no idea of how the glyphs arrived in this order.
|
|
*/
|
|
|
|
if (pFM = PfmGetIt( pPDev, ppsg->sFontIndex))
|
|
{
|
|
//
|
|
// Error check.
|
|
// BDelayGlyphOut can only handle printer device fonts.
|
|
//
|
|
if (pFM->dwFontType != FMTYPE_DEVICE)
|
|
{
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
Tod.flAccel = ppsg->flAccel;
|
|
Tod.dwAttrFlags = ppsg->dwAttrFlags;
|
|
Tod.iFace = ppsg->sFontIndex;
|
|
|
|
pFontPDev->ctl.eXScale = ppsg->eXScale;
|
|
pFontPDev->ctl.eYScale = ppsg->eYScale;
|
|
|
|
UFObj.pFontMap = Tod.pfm = pFM;
|
|
UFObj.pIFIMetrics = pFM->pIFIMet;
|
|
|
|
//
|
|
// Reselect new font
|
|
//
|
|
BNewFont(pPDev, ppsg->sFontIndex, pFM, ppsg->dwAttrFlags);
|
|
SelectTextColor( pPDev, ppsg->pvColor );
|
|
|
|
ASSERTMSG(pFM->pfnGlyphOut, ("NULL GlyphOut Funtion Ptr\n"));
|
|
|
|
gp.hg = (HGLYPH)(ppsg->hg);
|
|
gp.ptl.x = ppsg->ixVal - pPDev->rcClipRgn.left;
|
|
|
|
//
|
|
// Send character string
|
|
//
|
|
bRet = pFM->pfnGlyphOut(&Tod);
|
|
}
|
|
else
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
VUFObjFree(pFontPDev);
|
|
return bRet;
|
|
}
|
|
|
|
//
|
|
// Mics. functions
|
|
//
|
|
|
|
VOID
|
|
SelectTextColor(
|
|
PDEV *pPDev,
|
|
PVOID pvColor
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Select a text color.
|
|
|
|
Arguments:
|
|
|
|
pPDev Pointer to PDEV
|
|
color Color of the Text.
|
|
|
|
Return Value:
|
|
|
|
Nothing.
|
|
|
|
Note:
|
|
|
|
1/21/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
|
|
{
|
|
|
|
//Select the Brush and then unrealize it.
|
|
if (!GSSelectBrush( pPDev, pvColor))
|
|
{
|
|
ERR(( "GSSelectBrush Failed;Can't Select the Color\n" ));
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
BCheckForDefaultPlacement(
|
|
GLYPHPOS *pgp,
|
|
SHORT sWidth,
|
|
INT *piTolalError
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
pgp Current Glyph
|
|
sWidth Width of the previous glyph.
|
|
piTolalError Comulative Error
|
|
|
|
Return Value:
|
|
TRUE if the current glyph is at default placement else FALSE.
|
|
|
|
Note:
|
|
|
|
11/11/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
{
|
|
GLYPHPOS *pgpPrevious;
|
|
INT iError;
|
|
|
|
pgpPrevious = pgp -1;
|
|
|
|
iError = (pgpPrevious->ptl.x + sWidth) - pgp->ptl.x;
|
|
*piTolalError += iError;
|
|
|
|
//DbgPrint("\nTODEL!BCheckForDefaultPlacement:pgpPrevious->ptl.x = %d, Previous Glyph sWidth = %d,\n\t\tCurrpgp->ptl.x = %d, iError = %d, *piTolalError = %d\n",
|
|
//pgpPrevious->ptl.x, sWidth, pgp->ptl.x, iError, *piTolalError );
|
|
|
|
if ( (abs(iError) <= ERROR_PER_GLYPH_POS) /*&& (*piTolalError <= ERROR_PER_ENUMERATION)*/ )
|
|
{
|
|
//DbgPrint("TODEL!BCheckForDefaultPlacement: The Glyph is at Default Placement.\n");
|
|
return TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
//DbgPrint("TODEL!BCheckForDefaultPlacement: Non Default Placement Glyph Found.\n");
|
|
//DbgPrint("\nTODEL!BCheckForDefaultPlacement:pgpPrevious->ptl.x = %d, Previous Glyph sWidth = %d,\n\t\tCurrpgp->ptl.x = %d, iError = %d, *piTolalError = %d\n",
|
|
//pgpPrevious->ptl.x, sWidth, pgp->ptl.x, iError, *piTolalError );
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
VClipIt(
|
|
BYTE *pbClipBits,
|
|
TO_DATA *ptod,
|
|
CLIPOBJ *pco,
|
|
STROBJ *pstro,
|
|
int cGlyphs,
|
|
int iRot,
|
|
BOOL bPartialClipOn
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Applies clipping to the glyphos array passed in, and sets bits in
|
|
bClipBits to signify that the corresponding glyph should be printed.
|
|
NOTE: the clipping algorithm is that the glyph is displayed if
|
|
the top, left corner of the character cell is within the clipping
|
|
region. This is the formula of Win 3.1, so it is important for
|
|
us to follow it.
|
|
|
|
|
|
Arguments:
|
|
pbClipBits Output data is placed here
|
|
ptod Much information
|
|
cGlyphs Number of glyphs in following array
|
|
iRot 90 degree rotation amount (0-3)
|
|
|
|
Return Value:
|
|
Nothing
|
|
|
|
Note:
|
|
|
|
1/21/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
int iIndex; /* Classic loop variable! */
|
|
ULONG iClipIndex; /* For clipping rectangle */
|
|
int iYTop; /* Font's ascender, scaled if relevant */
|
|
int iYBot; /* Descender, scaled if required */
|
|
BYTE bVal; /* Determine how to set the bits */
|
|
FONTMAP *pFM; /* Speedier access to data */
|
|
FONTPDEV *pFontPDev; /* Ditto */
|
|
GLYPHPOS *pgp; /* Ditto */
|
|
short *asWidth;
|
|
|
|
|
|
/*
|
|
* Behaviour depends upon the complexity of the clipping region.
|
|
* If it is non-existent (I doubt that this happens, but play it safe)
|
|
* or of complexity DC_TRIVIAL, then set all the relevant bits and
|
|
* return.
|
|
* If DC_RECT is set, the CLIPOBJ contains the clipping rectangle,
|
|
* so clip using that information.
|
|
* Otherwise, it is DC_COMPLEX, and so we need to enumerate clipping
|
|
* rectangles.
|
|
* If we do not need to do anything, then set the bits and return.
|
|
* Otherwise, we have either of the two cases requiring evaluation.
|
|
* For those we want to set the bits to 0 and set the 1 bits as needed.
|
|
*
|
|
* Disable clipping for PCL-XL.
|
|
*/
|
|
|
|
if( pco &&
|
|
(pco->iDComplexity == DC_RECT || pco->iDComplexity == DC_COMPLEX) &&
|
|
!(ptod->pPDev->ePersonality == kPCLXL))
|
|
bVal = 0; /* Requires us to evaluate it */
|
|
else
|
|
bVal = 0xff; /* Do it all */
|
|
|
|
FillMemory( pbClipBits, (cGlyphs + BBITS - 1) / BBITS, bVal );
|
|
|
|
if( bVal == 0xff )
|
|
return; /* All done */
|
|
|
|
if (!(asWidth = MemAlloc(cGlyphs * sizeof(short))))
|
|
{
|
|
return;
|
|
}
|
|
|
|
pFM = ptod->pfm;
|
|
pFontPDev = ptod->pPDev->pFontPDev;
|
|
|
|
/*
|
|
* We now calculate the widths of the glpyhs. We need these to
|
|
* correctly clip the data. However, calculating widths can be
|
|
* expensive, and since we need the data later on, we save
|
|
* the values in the width array that ptod points to. This can
|
|
* then be used in the bottom level function, rather than calculating
|
|
* the width again.
|
|
*/
|
|
|
|
pgp = ptod->pgp;
|
|
|
|
//
|
|
// pgp may be NULL causing problems below. So don't clip, just return.
|
|
//
|
|
|
|
if (pgp == NULL)
|
|
{
|
|
if (asWidth)
|
|
{
|
|
MemFree(asWidth);
|
|
}
|
|
ASSERTMSG((FALSE),("\nCan't Clip the text.Null pgp in VClipIt. \n"));
|
|
return;
|
|
}
|
|
|
|
if (!(ptod->pfo->flFontType & TRUETYPE_FONTTYPE))
|
|
{
|
|
/* The normal case - a standard device font */
|
|
|
|
int iWide; /* Calculate the width */
|
|
|
|
for( iIndex = 0; iIndex < cGlyphs; ++iIndex, ++pgp )
|
|
{
|
|
|
|
iWide = IGetGlyphWidth( ptod->pPDev, pFM, pgp->hg);
|
|
|
|
if( pFM->flFlags & FM_SCALABLE )
|
|
{
|
|
/* Need to transform the value to current size */
|
|
iWide = LMulFloatLong(&pFontPDev->ctl.eXScale,iWide);
|
|
}
|
|
|
|
asWidth[ iIndex ] = iWide - 1; /* Will be used later */
|
|
}
|
|
|
|
|
|
}
|
|
else //GDI Font
|
|
{
|
|
|
|
GLYPHDATA *pgd;
|
|
|
|
/*
|
|
* SPECIAL CASE: DOWNLOADED GDI font. The width is
|
|
* obtained by calling back to GDI to get the data on it.
|
|
*/
|
|
|
|
for( iIndex = 0; iIndex < cGlyphs; ++iIndex, ++pgp )
|
|
{
|
|
pgd = NULL;
|
|
|
|
if( !FONTOBJ_cGetGlyphs( ptod->pfo, FO_GLYPHBITS, (ULONG)1,
|
|
&pgp->hg, &pgd ) )
|
|
{
|
|
if (asWidth)
|
|
{
|
|
MemFree(asWidth);
|
|
}
|
|
|
|
ERR(( "FONTOBJ_cGetGlyphs fails\n" ))
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Note about rotations: we do NOT download rotated fonts,
|
|
* so the following piece of code is quite correct.
|
|
*/
|
|
|
|
if (pgd)
|
|
{
|
|
asWidth[ iIndex ] = (short)(pgd->ptqD.x.HighPart + 15) / 16 - 1;
|
|
|
|
}
|
|
else
|
|
{
|
|
ASSERTMSG(FALSE,("UniFont!VClipIt:GLYPHDATA pointer is NULL\n"));
|
|
if (asWidth)
|
|
{
|
|
MemFree(asWidth);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We also want the Ascender and Descender fields, as these are
|
|
* used to check the Y component. While calculationg these values we have
|
|
* to do special case for Font substitution. In font substitution case
|
|
* True Type font's IFIMERTICS should be used rather than substituted
|
|
* device font's IFIMETRICS.
|
|
*/
|
|
|
|
//
|
|
// Initialize itTop and iyBot to fontmap values. Then based on what font we
|
|
// are using these values will change.
|
|
//
|
|
|
|
iYTop = (INT)((IFIMETRICS *)(pFM->pIFIMet))->fwdWinAscender;
|
|
iYBot = (INT)((IFIMETRICS *)(pFM->pIFIMet))->fwdWinDescender;
|
|
|
|
if (ptod->pfo->flFontType & TRUETYPE_FONTTYPE)
|
|
{
|
|
//
|
|
// True Type Font case. Get the values from FONTOBJ ifimetrics.
|
|
//
|
|
|
|
ASSERTMSG((pFontPDev->pIFI),("NULL pFontPDev->pIFI, TT Font IFIMETRICS\n"));
|
|
|
|
if (pFontPDev->pIFI)
|
|
{
|
|
iYTop = (INT)((IFIMETRICS *)(pFontPDev->pIFI))->fwdWinAscender;
|
|
iYBot = (INT)((IFIMETRICS *)(pFontPDev->pIFI))->fwdWinDescender;
|
|
|
|
}
|
|
//
|
|
// We always need to do the sacling as TT font metrics values
|
|
// are in notional space.
|
|
//
|
|
iYTop = LMulFloatLong(&pFontPDev->ctl.eYScale,iYTop);
|
|
iYBot = LMulFloatLong(&pFontPDev->ctl.eYScale,iYBot);
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Device Font case. We just need to scale for scalable fonts.
|
|
//
|
|
|
|
if( pFM->flFlags & FM_SCALABLE )
|
|
{
|
|
iYTop = LMulFloatLong(&pFontPDev->ctl.eYScale,iYTop);
|
|
iYBot = LMulFloatLong(&pFontPDev->ctl.eYScale,iYBot);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Down here means we are serious! Need to determine which (if any)
|
|
* glyphs are within the clip region.
|
|
*/
|
|
|
|
pgp = ptod->pgp;
|
|
|
|
if( pco->iDComplexity == DC_RECT )
|
|
{
|
|
/* The simpler case - one clipping rectangle. */
|
|
RECTL rclClip;
|
|
LONG lFirstGlyphX;
|
|
|
|
/* Local access -> speedier access */
|
|
rclClip = pco->rclBounds;
|
|
lFirstGlyphX = 0;
|
|
|
|
/*
|
|
* Nothing especially exciting. The clipping is checked for
|
|
* each particular type of rotation, as this is probably faster
|
|
* than having the loop go through the switch statement. The
|
|
* selection criteria are that all the character must be within
|
|
* the clip region in the X direction, while any part of it must
|
|
* be within the clip region in the Y direction. Then we print.
|
|
* Failing either means it is clipped out.
|
|
*
|
|
* NOTE that we fiddle with the clipping rectangle coordinates
|
|
* before the loop, as this saves some computation within the loop.
|
|
*/
|
|
|
|
switch( iRot )
|
|
{
|
|
case 0: /* Normal direction */
|
|
//
|
|
// Save the x position to restore after clipping calculation.
|
|
//
|
|
lFirstGlyphX = pgp->ptl.x;
|
|
|
|
// Check the First Glyph position. If it's just OFF by one or two
|
|
// pixels, print it.
|
|
if ( (pgp->ptl.x != rclClip.left) &&
|
|
(abs(pgp->ptl.x - rclClip.left) <= 2) )
|
|
{
|
|
pgp->ptl.x = rclClip.left;
|
|
}
|
|
|
|
for( iIndex = 0; iIndex < cGlyphs; ++iIndex, ++pgp )
|
|
{
|
|
#ifndef OLDWAY
|
|
//
|
|
// We want to draw the character in the first band
|
|
// in which a portion of it appears. This means that
|
|
// if the character starts in the current band we will
|
|
// draw it. We also draw the character if it starts before
|
|
// the first band but some of it exists within the band.
|
|
// The x and y points are relative to the lower left of the
|
|
// character cell so we calculate a upper left value for
|
|
// our testing purposes.
|
|
//
|
|
INT iyTopLeft;
|
|
INT iyBottomLeft, ixRight;
|
|
|
|
iyTopLeft = pgp->ptl.y - iYTop;
|
|
iyBottomLeft = pgp->ptl.y + iYBot;
|
|
ixRight = pgp->ptl.x + asWidth[ iIndex ];
|
|
|
|
|
|
if ((ptod->pfo->flFontType & TRUETYPE_FONTTYPE) &&
|
|
(ptod->flFlags & TODFL_FIRST_ENUMRATION) &&
|
|
bPartialClipOn)
|
|
{
|
|
BOOL bGlyphVisible; // Set if glyph is totally visible.
|
|
BOOL bLeftVisible, bRightVisible,
|
|
bTopVisible, bBottomVisible;
|
|
INT iError, iYdpi;
|
|
|
|
//
|
|
// Fix iyTopLeft to be maximum of STROBJ background rectangle's
|
|
// top and current calculated value of the top using asender of
|
|
// the font.This is needed because we want to clip using
|
|
// smallest bounding rectangle for the glyph. We also need to
|
|
// fix iyBottomLeft to be smaller of current value and STROBJ
|
|
// background rectangle's bottom.
|
|
//
|
|
|
|
iyTopLeft = max(iyTopLeft, pstro->rclBkGround.top);
|
|
iyBottomLeft = min(iyBottomLeft, pstro->rclBkGround.bottom);
|
|
|
|
//
|
|
// If the glyph rectangle's top or bottom is outside the
|
|
// clipping rectangle, we may need adjust the glyph
|
|
// rectangle. This is needed as the glyph rectangle's top and
|
|
// bottom is calculated using ascender and decender. This
|
|
// gives us a bigger rectangle height(worst case) than needed.
|
|
// Adjust the rectangle height by the Error factor. The
|
|
// error factor value is based upon the graphics dpi. For a
|
|
// 600 or 300 dpi printer it's set to 5 pixels and will
|
|
// scale based upon the graphics resolution.This number
|
|
// makes the glyph bounding rectangle small enough to catch
|
|
// the normal non partial clipping case and still catches
|
|
// the partial clipping of the glyphs.This adjustment should
|
|
// be done only if error factor is smaller than ascender or
|
|
// decender. Finally we must check if ptl.y is between
|
|
// topleft and bottomleft.
|
|
//
|
|
|
|
if ( (iyTopLeft < rclClip.top) ||
|
|
(iyBottomLeft > rclClip.bottom) )
|
|
{
|
|
iYdpi = ptod->pPDev->ptGrxRes.y;
|
|
if (iYdpi == 300)
|
|
iYdpi = 600;
|
|
iError = (EROOR_PER_GLYPHRECT * iYdpi) / 600;
|
|
|
|
if (iYTop > iError)
|
|
iyTopLeft += iError;
|
|
|
|
if (iYBot > iError)
|
|
iyBottomLeft -= iError;
|
|
|
|
}
|
|
|
|
if (iyTopLeft > pgp->ptl.y)
|
|
iyTopLeft = pgp->ptl.y;
|
|
|
|
if (iyBottomLeft < pgp->ptl.y)
|
|
iyBottomLeft = pgp->ptl.y;
|
|
|
|
//
|
|
// Now test for partial clipping. If the charecter is
|
|
// partially clippeed and the font is truetype, then we need
|
|
// to call EngTextOut.
|
|
//
|
|
// We can only call EngTextOut if we are clipping the first
|
|
// enumaration of the glyphs. EngTextOut doesn't support
|
|
// partial glyph printing.
|
|
//
|
|
|
|
//
|
|
// Glyph is fully visible if all the four corners of the
|
|
// glyph rectangle are visible.
|
|
//
|
|
|
|
|
|
bLeftVisible = (pgp->ptl.x >= rclClip.left);
|
|
bRightVisible = (ixRight <= rclClip.right);
|
|
bTopVisible = (iyTopLeft >= rclClip.top);
|
|
bBottomVisible = (iyBottomLeft <= rclClip.bottom);
|
|
|
|
|
|
bGlyphVisible = ( bLeftVisible && bRightVisible &&
|
|
bTopVisible && bBottomVisible );
|
|
|
|
|
|
if (!bGlyphVisible)
|
|
{
|
|
|
|
ptod->flFlags |= TODFL_TTF_PARTIAL_CLIPPING;
|
|
|
|
//
|
|
// No need to test rest of the glyphs for clipping.
|
|
//
|
|
break;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if ( (iyTopLeft < rclClip.top) ||
|
|
(iyBottomLeft > rclClip.bottom) )
|
|
{
|
|
INT iError;
|
|
INT iYdpi = ptod->pPDev->ptGrxRes.y;
|
|
if (iYdpi <= 600)
|
|
iYdpi = 600;
|
|
iError = (EROOR_PER_GLYPHRECT * iYdpi) / 600;
|
|
|
|
if (iYTop > iError)
|
|
iyTopLeft += iError;
|
|
|
|
if (iYBot > iError)
|
|
iyBottomLeft -= iError;
|
|
|
|
}
|
|
}
|
|
|
|
if( pgp->ptl.x >= rclClip.left &&
|
|
pgp->ptl.x <= rclClip.right &&
|
|
iyTopLeft <= rclClip.bottom &&
|
|
(iyTopLeft >= rclClip.top ||
|
|
(pgp->ptl.y >= rclClip.top &&
|
|
ptod->pPDev->rcClipRgn.top == 0)))
|
|
#else
|
|
if( pgp->ptl.x >= rclClip.left &&
|
|
pgp->ptl.x <= rclClip.right &&
|
|
pgp->ptl.y <= rclClip.bottom &&
|
|
pgp->ptl.y >= rclClip.top )
|
|
#endif
|
|
{
|
|
|
|
|
|
/* Got it! So set the bit to print it */
|
|
|
|
*(pbClipBits + (iIndex >> 3) ) |= 1 << (iIndex & 0x7);
|
|
|
|
}
|
|
|
|
//
|
|
// Restore the position of the first glyph. It may have been
|
|
// changed.
|
|
//
|
|
if ( iIndex == 0 )
|
|
pgp->ptl.x = lFirstGlyphX;
|
|
}
|
|
|
|
break;
|
|
|
|
case 1: /* 90 degrees counter clockwise */
|
|
|
|
rclClip.left += iYTop;
|
|
rclClip.right -= iYBot;
|
|
|
|
/* Check the First Glyph. If it's just OFF by One, print it.*/
|
|
if (abs(pgp->ptl.y - rclClip.bottom) == 1)
|
|
pgp->ptl.y = rclClip.bottom;
|
|
|
|
for( iIndex = 0; iIndex < cGlyphs; ++iIndex, ++pgp )
|
|
{
|
|
if( (pgp->ptl.y <= rclClip.bottom) &&
|
|
((pgp->ptl.y - asWidth[ iIndex ]) >= rclClip.top) &&
|
|
(pgp->ptl.x >= rclClip.left) &&
|
|
(pgp->ptl.x <= rclClip.right) )
|
|
{
|
|
*(pbClipBits + (iIndex >> 3) ) |= 1 << (iIndex & 0x7);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 2: /* 180 degrees, CCW (aka right to left) */
|
|
|
|
rclClip.bottom += iYBot;
|
|
rclClip.top -= iYTop;
|
|
|
|
/* Check the First Glyph. If it's just OFF by One, print it.*/
|
|
if (abs(pgp->ptl.x - rclClip.right) == 1)
|
|
pgp->ptl.x = rclClip.right;
|
|
|
|
for( iIndex = 0; iIndex < cGlyphs; ++iIndex, ++pgp )
|
|
{
|
|
if( pgp->ptl.x <= rclClip.right &&
|
|
(pgp->ptl.x - asWidth[ iIndex ]) >= rclClip.left &&
|
|
pgp->ptl.y <= rclClip.bottom &&
|
|
pgp->ptl.y >= rclClip.top )
|
|
{
|
|
*(pbClipBits + (iIndex >> 3) ) |= 1 << (iIndex & 0x7);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 3: /* 270 degrees CCW */
|
|
|
|
rclClip.right += iYBot;
|
|
rclClip.left -= iYTop;
|
|
|
|
/* Check the First Glyph. If it's just OFF by One, print it.*/
|
|
if (abs(pgp->ptl.y - rclClip.top) == 1)
|
|
pgp->ptl.y = rclClip.top;
|
|
|
|
for( iIndex = 0; iIndex < cGlyphs; ++iIndex, ++pgp )
|
|
{
|
|
if( pgp->ptl.y >= rclClip.top &&
|
|
(pgp->ptl.y + asWidth[ iIndex ]) <= rclClip.bottom &&
|
|
pgp->ptl.x <= rclClip.right &&
|
|
pgp->ptl.x >= rclClip.left )
|
|
{
|
|
*(pbClipBits + (iIndex >> 3) ) |= 1 << (iIndex & 0x7);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
else // Complex Clipping.
|
|
{
|
|
//
|
|
// For True type font call engine to draw the text.
|
|
//
|
|
if ( (ptod->pfo->flFontType & TRUETYPE_FONTTYPE) && bPartialClipOn)
|
|
{
|
|
|
|
ptod->flFlags |= TODFL_TTF_PARTIAL_CLIPPING;
|
|
|
|
}
|
|
else // Device font case. We have to clip anyway.
|
|
{
|
|
/* enumerate the rectangles and see */
|
|
|
|
int cGLeft;
|
|
BOOL bMore;
|
|
MY_ENUMRECTS erClip;
|
|
|
|
/*
|
|
* Let the engine know how we want this handled. All we want
|
|
* to set is the use of rectangles rather than trapezoids for
|
|
* the clipping info. Direction of enumeration is of no great
|
|
* interest, and I don't care how many rectangles are involved.
|
|
* I also see no reason to enumerate the whole region.
|
|
*/
|
|
|
|
CLIPOBJ_cEnumStart( pco, FALSE, CT_RECTANGLES, CD_ANY, 0 );
|
|
|
|
cGLeft = cGlyphs;
|
|
|
|
do
|
|
{
|
|
bMore = CLIPOBJ_bEnum( pco, sizeof( erClip ), &erClip.c );
|
|
|
|
for( iIndex = 0; iIndex < cGlyphs; ++iIndex )
|
|
{
|
|
RECTL rclGlyph;
|
|
|
|
if( pbClipBits[ iIndex >> 3 ] & (1 << (iIndex & 0x7)) )
|
|
continue; /* Already done! */
|
|
|
|
/*
|
|
* Compute the RECTL describing this char, then see
|
|
* how this maps to the clipping data.
|
|
*/
|
|
|
|
switch( iRot )
|
|
{
|
|
case 0:
|
|
rclGlyph.left = (pgp + iIndex)->ptl.x;
|
|
rclGlyph.right = rclGlyph.left + asWidth[ iIndex ];
|
|
rclGlyph.top = (pgp + iIndex)->ptl.y - iYTop;
|
|
rclGlyph.bottom = rclGlyph.top + iYTop + iYBot;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
rclGlyph.left = (pgp + iIndex)->ptl.x - iYTop;
|
|
rclGlyph.right = rclGlyph.left + iYTop + iYBot;
|
|
rclGlyph.bottom = (pgp + iIndex)->ptl.y;
|
|
rclGlyph.top = rclGlyph.bottom - asWidth[ iIndex ];
|
|
|
|
break;
|
|
|
|
case 2:
|
|
rclGlyph.right = (pgp + iIndex)->ptl.x;
|
|
rclGlyph.left = rclGlyph.right - asWidth[ iIndex ];
|
|
rclGlyph.bottom = (pgp + iIndex)->ptl.y + iYTop;
|
|
rclGlyph.top = rclGlyph.bottom - iYTop - iYBot;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
rclGlyph.left = (pgp + iIndex)->ptl.x - iYBot;
|
|
rclGlyph.right = rclGlyph.left + iYTop + iYBot;
|
|
rclGlyph.top = (pgp + iIndex)->ptl.y;
|
|
rclGlyph.bottom = rclGlyph.top + asWidth[ iIndex ];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* Define the char as being printed if any part of it
|
|
* is visible in the Y direction, and all of it in the X
|
|
* direction. This is not really what we want for
|
|
* rotated text, but it is hard to do it correctly,
|
|
* and of dubious benefit.
|
|
*/
|
|
|
|
for( iClipIndex = 0; iClipIndex < erClip.c; ++iClipIndex )
|
|
{
|
|
if( rclGlyph.right <= erClip.arcl[ iClipIndex ].right &&
|
|
rclGlyph.left >= erClip.arcl[ iClipIndex ].right &&
|
|
rclGlyph.bottom >= erClip.arcl[ iClipIndex ].top &&
|
|
rclGlyph.top <= erClip.arcl[ iClipIndex ].bottom )
|
|
{
|
|
/*
|
|
* Got one, so set the bit to print, and also
|
|
* decrement the count of those remaining.
|
|
*/
|
|
|
|
pbClipBits[ iIndex >> 3 ] |= (1 << (iIndex & 0x7));
|
|
--cGLeft;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} while( bMore && cGLeft > 0 );
|
|
|
|
}
|
|
}
|
|
|
|
if (asWidth)
|
|
{
|
|
MemFree(asWidth);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
VOID
|
|
VCopyAlign(
|
|
BYTE *pjDest,
|
|
BYTE *pjSrc,
|
|
int cx,
|
|
int cy
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Copy the source area to the destination area, aligning the scan lines
|
|
as they are processed.
|
|
|
|
Arguments:
|
|
pjDest Output area, DWORD aligned
|
|
pjSrc Input area, BYTE aligned
|
|
cx Number of pixels per scan line
|
|
cy Number of scan lines
|
|
|
|
Return Value:
|
|
Nothing.
|
|
|
|
Note:
|
|
|
|
1/22/1997 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
|
|
{
|
|
/*
|
|
* Basically a trivial function.
|
|
*/
|
|
|
|
|
|
int iX, iY; /* For looping through the bytes */
|
|
int cjFill; /* Extra bytes per output scan line */
|
|
int cjWidth; /* Number of bytes per input scan line */
|
|
|
|
|
|
|
|
cjWidth = (cx + BBITS - 1) / BBITS; /* Input scan line bytes */
|
|
cjFill = ((cjWidth + 3) & ~0x3) - cjWidth;
|
|
|
|
|
|
for( iY = 0; iY < cy; ++iY )
|
|
{
|
|
/* Copy the scan line bytes, then fill in the trailing bits */
|
|
for( iX = 0; iX < cjWidth; ++iX )
|
|
{
|
|
*pjDest++ = *pjSrc++;
|
|
}
|
|
|
|
pjDest += cjFill; /* Output alignment */
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
INT
|
|
ISubstituteFace(
|
|
PDEV *pPDev,
|
|
FONTOBJ *pfo)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Return a device font id to substitute TrueType font with.
|
|
|
|
Arguments:
|
|
|
|
pPDev a pointer to PDEV
|
|
pfo a pointer to FONTOBJ
|
|
|
|
Return Value:
|
|
|
|
font id
|
|
|
|
Note:
|
|
|
|
--*/
|
|
{
|
|
PTTFONTSUBTABLE pTTFontSubDefault;
|
|
PIFIMETRICS pIFITT;
|
|
FONTPDEV *pFontPDev;
|
|
PFONTMAP pfm;
|
|
WCHAR awstrFaceName[256];
|
|
|
|
PWSTR pwstrTTFaceName, pwstrTTFaceNameRes, pwstrDevFont, pwstrIFIFace;
|
|
DWORD dwCountOfTTSubTable, dwSize;
|
|
PBYTE pubResourceData;
|
|
BOOL bFound, bNonsquare;
|
|
INT iFace, iFaceSim, iI, iCountOfTTSubTable;
|
|
|
|
iFace = 0;
|
|
iFaceSim = 0;
|
|
pFontPDev = pPDev->pFontPDev;
|
|
|
|
//
|
|
// if dwTTOption is DMTT_DOWNLOAD or DMTT_GRAPHICS,
|
|
// UNIDRV doesn't substitute TrueType font.
|
|
//
|
|
if (pPDev->pdm->dmTTOption != DMTT_SUBDEV)
|
|
{
|
|
//VERBOSE(( "ISubstituteFace: Don't substitute.\n"));
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// If TrueType font is scaled X and Y differently (non-square font),
|
|
// we should not download.
|
|
// Since current UNIDRV can't scale device font x and y independently.
|
|
//
|
|
|
|
bNonsquare = NONSQUARE_FONT(pFontPDev->pxform);
|
|
if (bNonsquare && !(pFontPDev->flText & TC_SF_X_YINDEP))
|
|
{
|
|
//VERBOSE(( "ISubstituteFace: Don't substitute non-square TrueType font.\n"));
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Get TrueType font's facename from IFIMETRICS structure.
|
|
//
|
|
|
|
if (!(pIFITT = pFontPDev->pIFI))
|
|
{
|
|
ERR(( "ISubstituteFace: Invalid pFontPDev->pIFI\n"));
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Get TrueType font face name.
|
|
// In substitution table, there are a list of T2 face name and Device
|
|
// font face name.
|
|
//
|
|
|
|
pwstrTTFaceName = (PWSTR)((BYTE *) pIFITT + pIFITT->dpwszFamilyName);
|
|
|
|
pTTFontSubDefault = NULL;
|
|
|
|
if (!pFontPDev->pTTFontSubReg)
|
|
{
|
|
//
|
|
// Use a default font substitution table, if there no info in registry.
|
|
//
|
|
|
|
bFound = FALSE;
|
|
|
|
pubResourceData = pPDev->pDriverInfo->pubResourceData;
|
|
pTTFontSubDefault = GETTTFONTSUBTABLE(pPDev->pDriverInfo);
|
|
iCountOfTTSubTable = (INT)pPDev->pDriverInfo->DataType[DT_FONTSUBST].dwCount;
|
|
|
|
for (iI = 0; iI < iCountOfTTSubTable; iI++, pTTFontSubDefault++)
|
|
{
|
|
if (!pTTFontSubDefault->arTTFontName.dwCount)
|
|
{
|
|
dwSize = ILoadStringW(&pPDev->WinResData, pTTFontSubDefault->dwRcTTFontNameID, awstrFaceName, 256);
|
|
pwstrTTFaceNameRes = awstrFaceName;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// dwCount is supposed be the number of characters according to
|
|
// a GPD parser.
|
|
// However, the size is actually the size in byte.
|
|
// We need the number of characters.
|
|
//
|
|
|
|
dwSize = pTTFontSubDefault->arTTFontName.dwCount/sizeof(WCHAR);
|
|
pwstrTTFaceNameRes = (PWSTR)(pubResourceData +
|
|
pTTFontSubDefault->arTTFontName.loOffset);
|
|
}
|
|
|
|
if (dwSize > 0 &&
|
|
dwSize == wcslen(pwstrTTFaceName) &&
|
|
NULL != pwstrTTFaceNameRes)
|
|
{
|
|
if (!wcsncmp(pwstrTTFaceNameRes, pwstrTTFaceName, dwSize))
|
|
{
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (pTTFontSubDefault->arDevFontName.dwCount)
|
|
{
|
|
pwstrDevFont = (PWSTR)(pubResourceData +
|
|
pTTFontSubDefault->arDevFontName.loOffset);
|
|
dwSize = pTTFontSubDefault->arDevFontName.dwCount;
|
|
}
|
|
else
|
|
{
|
|
dwSize = ILoadStringW(&pPDev->WinResData, pTTFontSubDefault->dwRcDevFontNameID, awstrFaceName, 256);
|
|
pwstrDevFont = awstrFaceName;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
pwstrDevFont = (PWSTR)PtstrSearchTTSubstTable(pFontPDev->pTTFontSubReg,
|
|
pwstrTTFaceName);
|
|
}
|
|
|
|
if (!pwstrDevFont)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Get iFace of the font name.
|
|
//
|
|
|
|
pfm = pFontPDev->pFontMap;
|
|
|
|
for (iI = 1;
|
|
iI <= pPDev->iFonts;
|
|
iI ++, (PBYTE)pfm += SIZEOFDEVPFM() )
|
|
{
|
|
if( pfm->pIFIMet == NULL )
|
|
{
|
|
if (!BFillinDeviceFM( pPDev, pfm, iI - 1 ) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (pfm->pIFIMet)
|
|
{
|
|
PIFIMETRICS pDevIFI = pfm->pIFIMet;
|
|
BOOL bT2Bold, bT2Italic;
|
|
|
|
bT2Bold = (pIFITT->fsSelection & FM_SEL_BOLD) ||
|
|
(pfo->flFontType & FO_SIM_BOLD);
|
|
bT2Italic = (pIFITT->fsSelection & FM_SEL_ITALIC) ||
|
|
(pfo->flFontType & FO_SIM_ITALIC);
|
|
|
|
pwstrIFIFace = (WCHAR*)((BYTE *)pDevIFI + pDevIFI->dpwszFamilyName);
|
|
|
|
//
|
|
// (1) FaceName match.
|
|
// (2) Character sets match.
|
|
// -> Set iFaceSim.
|
|
// (3) Bold attributes match. !(bT2Bold xor bDevBold)
|
|
// (4) Italic attributes match. !(bT2Italic xor bDevItalic)
|
|
// -> Set iFace.
|
|
//
|
|
|
|
#if 0
|
|
VERBOSE(( "bT2Bold=%d, bT2Italic=%d, IFIFace=%ws, DevFace=%ws\n",
|
|
bT2Bold, bT2Italic, pwstrIFIFace, pwstrDevFont));
|
|
#endif
|
|
if(!wcscmp(pwstrDevFont, pwstrIFIFace) &&
|
|
(pIFITT->jWinCharSet == pDevIFI->jWinCharSet) &&
|
|
((bNonsquare && (pDevIFI->flInfo & FM_INFO_ANISOTROPIC_SCALING_ONLY)) || !bNonsquare)
|
|
)
|
|
{
|
|
|
|
//
|
|
// Substitute TrueType font with simulated device font.
|
|
//
|
|
if( !(((pDevIFI->fsSelection & FM_SEL_BOLD)?TRUE:FALSE) ^ bT2Bold) &&
|
|
!(((pDevIFI->fsSelection & FM_SEL_ITALIC)?TRUE:FALSE) ^ bT2Italic))
|
|
{
|
|
//
|
|
// Attribute match
|
|
// Substitute with bold or italic face device font.
|
|
//
|
|
iFace = iI;
|
|
break;
|
|
}
|
|
else
|
|
if (pfm->pIFIMet->dpFontSim)
|
|
{
|
|
//
|
|
// Attribute doesn't match.
|
|
// Check if this device font can be simulated as bold
|
|
// or italic.
|
|
//
|
|
FONTSIM *pFontSim = (FONTSIM*)((PBYTE)pfm->pIFIMet +
|
|
pfm->pIFIMet->dpFontSim);
|
|
|
|
if (! (pFontPDev->flFlags & FDV_INIT_ATTRIB_CMD))
|
|
{
|
|
pFontPDev->pCmdBoldOn = COMMANDPTR(pPDev->pDriverInfo, CMD_BOLDON);
|
|
pFontPDev->pCmdBoldOff = COMMANDPTR(pPDev->pDriverInfo, CMD_BOLDOFF);
|
|
pFontPDev->pCmdItalicOn = COMMANDPTR(pPDev->pDriverInfo, CMD_ITALICON);
|
|
pFontPDev->pCmdItalicOff = COMMANDPTR(pPDev->pDriverInfo, CMD_ITALICOFF);
|
|
pFontPDev->pCmdUnderlineOn = COMMANDPTR(pPDev->pDriverInfo, CMD_UNDERLINEON);
|
|
pFontPDev->pCmdUnderlineOff = COMMANDPTR(pPDev->pDriverInfo, CMD_UNDERLINEOFF);
|
|
pFontPDev->pCmdClearAllFontAttribs = COMMANDPTR(pPDev->pDriverInfo, CMD_CLEARALLFONTATTRIBS);
|
|
pFontPDev->flFlags |= FDV_INIT_ATTRIB_CMD;
|
|
}
|
|
if (bT2Bold && bT2Italic)
|
|
{
|
|
if( pFontSim->dpBoldItalic &&
|
|
pFontPDev->pCmdBoldOn &&
|
|
pFontPDev->pCmdItalicOn )
|
|
{
|
|
iFaceSim = iI;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if (bT2Bold)
|
|
{
|
|
if( pFontSim->dpBold &&
|
|
pFontPDev->pCmdBoldOn)
|
|
{
|
|
iFaceSim = iI;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if (bT2Italic)
|
|
{
|
|
if (pFontSim->dpItalic &&
|
|
pFontPDev->pCmdItalicOn)
|
|
{
|
|
iFaceSim = iI;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (iFace)
|
|
return iFace;
|
|
else
|
|
return iFaceSim;
|
|
}
|
|
|
|
|
|
|
|
PHGLYPH
|
|
PhAllCharsPrintable(
|
|
PDEV *pPDev,
|
|
INT iSubst,
|
|
ULONG ulGlyphs,
|
|
PWCHAR pwchUnicode)
|
|
{
|
|
PHGLYPH phGlyph;
|
|
PFONTMAP pfm;
|
|
ULONG ulI;
|
|
BOOL bRet;
|
|
|
|
//
|
|
// Error check
|
|
//
|
|
if (!pwchUnicode)
|
|
return NULL;
|
|
|
|
if (!(PVGetUCGlyphSetData( pPDev, iSubst)) ||
|
|
!(pfm = PfmGetIt( pPDev, iSubst)) ||
|
|
!(phGlyph = MemAlloc(sizeof(HGLYPH) * ulGlyphs)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (ulI = 0; ulI < ulGlyphs; ulI ++)
|
|
{
|
|
if (!(*(phGlyph+ulI) = HWideCharToGlyphHandle(pPDev,
|
|
pfm,
|
|
*(pwchUnicode+ulI))))
|
|
{
|
|
MemFree(phGlyph);
|
|
phGlyph = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return phGlyph;
|
|
}
|
|
|
|
HGLYPH
|
|
HWideCharToGlyphHandle(
|
|
PDEV *pPDev,
|
|
FONTMAP *pFM,
|
|
WCHAR wchOrg)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Select a text color.
|
|
|
|
Arguments:
|
|
|
|
pPDev a pointer to PDEV
|
|
ptod a pointer to TO_DATA
|
|
wchOrg Unidrv character
|
|
|
|
Return Value:
|
|
|
|
Glyph handle.
|
|
|
|
Note:
|
|
|
|
--*/
|
|
{
|
|
PFONTMAP_DEV pFMDev;
|
|
HGLYPH hRet;
|
|
DWORD dwI;
|
|
BOOL bFound;
|
|
|
|
if (wchOrg < pFM->wFirstChar || pFM->wLastChar < wchOrg)
|
|
{
|
|
return (HGLYPH)0;
|
|
}
|
|
|
|
hRet = 1;
|
|
pFMDev = pFM->pSubFM;
|
|
bFound = FALSE;
|
|
|
|
if (pFM->flFlags & FM_GLYVER40)
|
|
{
|
|
WCRUN *pWCRuns;
|
|
DWORD dwCRuns;
|
|
|
|
if (!pFMDev->pUCTree)
|
|
return (HGLYPH)0;
|
|
|
|
dwCRuns = ((FD_GLYPHSET*)pFMDev->pUCTree)->cRuns;
|
|
pWCRuns = ((FD_GLYPHSET*)pFMDev->pUCTree)->awcrun;
|
|
|
|
for (dwI = 0; dwI < dwCRuns; dwI ++, pWCRuns ++)
|
|
{
|
|
if (pWCRuns->wcLow <= wchOrg &&
|
|
wchOrg < pWCRuns->wcLow + pWCRuns->cGlyphs )
|
|
{
|
|
hRet = *(pWCRuns->phg + (wchOrg - pWCRuns->wcLow));
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
PUNI_GLYPHSETDATA pGlyphSetData;
|
|
PGLYPHRUN pGlyphRun;
|
|
|
|
if (pFMDev && pFMDev->pvNTGlyph)
|
|
{
|
|
pGlyphSetData = (PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph;
|
|
pGlyphRun = GET_GLYPHRUN(pFMDev->pvNTGlyph);
|
|
}
|
|
else
|
|
{
|
|
return (HGLYPH)0;
|
|
}
|
|
|
|
for (dwI = 0; dwI < pGlyphSetData->dwRunCount; dwI ++, pGlyphRun ++)
|
|
{
|
|
if (pGlyphRun->wcLow <= wchOrg &&
|
|
wchOrg < pGlyphRun->wcLow + pGlyphRun->wGlyphCount )
|
|
{
|
|
hRet += wchOrg - pGlyphRun->wcLow;
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
hRet += pGlyphRun->wGlyphCount;
|
|
}
|
|
}
|
|
|
|
if (bFound)
|
|
{
|
|
return hRet;
|
|
}
|
|
else
|
|
{
|
|
return (HGLYPH)0;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
BGetStartGlyphandCount(
|
|
BYTE *pbClipBits,
|
|
DWORD dwEndIndex,
|
|
DWORD *pdwStartIndex,
|
|
DWORD *pdwGlyphToPrint)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Select a text color.
|
|
|
|
Arguments:
|
|
|
|
pbClipBits bit flags for character clipping
|
|
dwTotalGlyph a total count of glyph
|
|
pdwStartIndex a pointer to the index of starting glyph
|
|
pdwGlyphtoPrint a pointer to the the number of glyphs to print
|
|
|
|
Return Value:
|
|
|
|
True if there is any character to print. Otherwise False.
|
|
|
|
Note:
|
|
|
|
Caller passes the number of characters to print in pdwGlyphCount.
|
|
And the ID of the first character to print.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwI;
|
|
BOOL bRet;
|
|
|
|
dwI = *pdwStartIndex;
|
|
|
|
*pdwStartIndex = *pdwGlyphToPrint = 0;
|
|
bRet = FALSE;
|
|
|
|
for (; dwI < dwEndIndex; dwI ++)
|
|
{
|
|
if (pbClipBits[dwI >> 3] & (1 << (dwI & 0x07)))
|
|
{
|
|
if (bRet)
|
|
{
|
|
(*pdwGlyphToPrint)++;
|
|
}
|
|
else
|
|
{
|
|
bRet = TRUE;
|
|
*pdwStartIndex = dwI;
|
|
*pdwGlyphToPrint = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bRet)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
//
|
|
// If the difference between width and height is not within +-0.5%,
|
|
// returns TRUE.
|
|
//
|
|
|
|
BOOL
|
|
NONSQUARE_FONT(
|
|
PXFORML pxform)
|
|
{
|
|
BOOL bRet;
|
|
FLOATOBJ eMa, eMb, eMc;
|
|
FLOATOBJ Round, RoundM;
|
|
|
|
//
|
|
// PCL5e printers can not scale with and height of fonts idependently.
|
|
// This function checks if font is squarely scaled.
|
|
// It means width and height is same.
|
|
// Also this function is functional in 0, 90, 180, and 270 degree rotation.
|
|
// PCL5e printer can't not scale arbitrary degree, but only on 0, 90, 180,
|
|
// and 270 degree. So this function works fine.
|
|
//
|
|
if (FLOATOBJ_EqualLong(&pxform->eM11, (LONG)0))
|
|
{
|
|
eMa = eMc = pxform->eM21;
|
|
eMb = pxform->eM12;
|
|
}
|
|
else
|
|
{
|
|
eMa = eMc = pxform->eM11;
|
|
eMb = pxform->eM22;
|
|
}
|
|
|
|
//
|
|
// Set 0.005 (0.5%) round values.
|
|
//
|
|
#ifndef WINNT_40 //NT 5.0
|
|
FLOATOBJ_SetFloat(&Round, (FLOAT)0.005);
|
|
FLOATOBJ_SetFloat(&RoundM, (FLOAT)-0.005);
|
|
#else
|
|
FLOATOBJ_SetFloat(&Round, FLOATL_00_005);
|
|
FLOATOBJ_SetFloat(&RoundM, FLOATL_00_005M);
|
|
#endif //!WINNT_40
|
|
//
|
|
// eM11 = (eM11 - eM22) / eM11
|
|
//
|
|
FLOATOBJ_Sub(&eMa, &eMb);
|
|
FLOATOBJ_Div(&eMa, &eMc);
|
|
|
|
//
|
|
// (eM11 - eM22) / eM11 < 0.5%
|
|
//
|
|
bRet = FLOATOBJ_LessThan(&(eMa), &(Round)) &&
|
|
FLOATOBJ_GreaterThan(&(eMa), &(RoundM));
|
|
|
|
|
|
eMa = eMc;
|
|
FLOATOBJ_Add(&eMa, &eMb);
|
|
FLOATOBJ_Div(&eMa, &eMc);
|
|
bRet = bRet
|
|
|| ( FLOATOBJ_LessThan(&eMa, &Round)
|
|
&& FLOATOBJ_GreaterThan(&(eMa), &(RoundM)));
|
|
|
|
return !bRet;
|
|
}
|
|
|
|
#undef FILETRACE
|