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.
1445 lines
41 KiB
1445 lines
41 KiB
/*++
|
|
|
|
Copyright (c) 1990-2003 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
textout.c
|
|
|
|
|
|
Abstract:
|
|
|
|
This module contains the DrvTextOut entry point. This is the main routine
|
|
called by the NT graphics engine in order to get text rendered on the
|
|
target device. This implementation handles both drawing device paths that
|
|
represent the glyphs of the STROBJ (the line of text to output), as well
|
|
as outputing bitmaps that represent the glyphs on devices that can
|
|
handle raster output.
|
|
|
|
Author:
|
|
|
|
Written by AP on 8/17/92.
|
|
|
|
15-Nov-1993 Mon 19:43:58 updated
|
|
clean up / fixed / add debugging information
|
|
|
|
|
|
[Environment:]
|
|
|
|
GDI Device Driver - Plotter.
|
|
|
|
|
|
[Notes:]
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define DBG_PLOTFILENAME DbgTextOut
|
|
|
|
#define DBG_GETGLYPHMODE 0x00000001
|
|
#define DBG_TEXTOUT 0x00000002
|
|
#define DBG_TEXTOUT1 0x00000004
|
|
#define DBG_TEXTOUT2 0x00000008
|
|
#define DBG_DRAWLINE 0x00000010
|
|
#define DBG_TRUETYPE 0x00000020
|
|
#define DBG_TRUETYPE1 0x00000040
|
|
#define DBG_TRUETYPE2 0x00000080
|
|
#define DBG_BMPFONT 0x00000100
|
|
#define DBG_BMPTEXTCLR 0x00000200
|
|
#define DBG_DEFCHARINC 0x00000400
|
|
#define DBG_SET_FONTTYPE 0x20000000
|
|
#define DBG_SHOWRASFONT 0x40000000
|
|
#define DBG_NO_RASTER_FONT 0x80000000
|
|
|
|
DEFINE_DBGVAR(0);
|
|
|
|
|
|
extern PALENTRY HTPal[];
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
DrvGetGlyphMode(
|
|
DHPDEV dhpdev,
|
|
FONTOBJ *pfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Asks the driver what sort of font information should be cached for a
|
|
particular font. For remote printer devices, this determines the format
|
|
that gets spooled. For local devices, this determines what GDI stores in
|
|
its font cache. This call will be made for each particular font
|
|
realization.
|
|
|
|
Arguments:
|
|
|
|
dhpdev - Pointer to our PDEV
|
|
|
|
pfo - Pointer to the font object
|
|
|
|
Return Value:
|
|
|
|
DWORD as FO_xxxx
|
|
|
|
|
|
Author:
|
|
|
|
27-Jan-1994 Thu 12:51:59 created
|
|
|
|
10-Mar-1994 Thu 00:36:30 updated
|
|
Re-write, so we will pre-examine the Font type, source and its
|
|
technology together with PDEV setting to let engine know which type of
|
|
the font output we are interested in the DrvTextOut(). Currently this
|
|
is broken in GDI which caused a GP in winsrv. (this is why a
|
|
DBG_SET_FONTTYPE switch is on by default)
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
#define pPDev ((PPDEV)dhpdev)
|
|
|
|
PIFIMETRICS pifi;
|
|
DWORD FOType;
|
|
|
|
|
|
PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: Type=%08lx, cxMax=%ld",
|
|
pfo->flFontType, pfo->cxMax));
|
|
|
|
//
|
|
// If we cannot get the IFI metrics for the passed FONTOBJ, only
|
|
// ask for PATHS.
|
|
//
|
|
|
|
if (!(pifi = FONTOBJ_pifi(pfo))) {
|
|
|
|
PLOTERR(("DrvGetGlyphMode: FONTOBJ_pifi()=NULL, return FO_PATHOBJ"));
|
|
|
|
return(FO_PATHOBJ);
|
|
}
|
|
|
|
FOType = FO_PATHOBJ;
|
|
|
|
//
|
|
// If its a bitmap font, ask for BITS
|
|
//
|
|
|
|
if (pifi->flInfo & FM_INFO_TECH_BITMAP) {
|
|
|
|
PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: BITMAP FONT, return FO_GLYPHBITS"));
|
|
|
|
FOType = FO_GLYPHBITS;
|
|
|
|
} else if (pifi->flInfo & FM_INFO_TECH_STROKE) {
|
|
|
|
PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: STROKE (Vector) FONT, return FO_PATHOBJ"));
|
|
|
|
} else if (pifi->flInfo & FM_INFO_RETURNS_BITMAPS) {
|
|
|
|
//
|
|
// Now make a decision on whether to ask for glyphbits or paths.
|
|
// This decision is based on the target device being raster, that
|
|
// bitmap fonts are okay to use, and that the threshold for doing
|
|
// raster fonts versus paths is met.
|
|
//
|
|
|
|
DWORD cxBMFontMax = (DWORD)pPDev->pPlotGPC->RasterXDPI;
|
|
|
|
if (pPDev->PlotDM.dm.dmPrintQuality == DMRES_HIGH) {
|
|
|
|
cxBMFontMax <<= 3;
|
|
|
|
} else {
|
|
|
|
cxBMFontMax >>= 2;
|
|
}
|
|
|
|
PLOTDBG(DBG_GETGLYPHMODE,
|
|
("DrvGetGlyphMode: Font CAN return BITMAP, cxBMFontMax=%ld",
|
|
cxBMFontMax));
|
|
|
|
#if DBG
|
|
if ((!(DBG_PLOTFILENAME & DBG_NO_RASTER_FONT)) &&
|
|
(IS_RASTER(pPDev)) &&
|
|
(!NO_BMP_FONT(pPDev)) &&
|
|
(pfo->cxMax <= cxBMFontMax)) {
|
|
#else
|
|
if ((IS_RASTER(pPDev)) &&
|
|
(!NO_BMP_FONT(pPDev)) &&
|
|
(pfo->cxMax <= cxBMFontMax)) {
|
|
#endif
|
|
PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: Convert to BITMAP FONT, FO_GLYPHBITS"));
|
|
|
|
FOType = FO_GLYPHBITS;
|
|
|
|
} else {
|
|
|
|
PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: Return as FO_PATHOBJ"));
|
|
}
|
|
|
|
} else if (pifi->flInfo & FM_INFO_RETURNS_OUTLINES) {
|
|
|
|
PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: Font CAN return OUTLINES"));
|
|
|
|
} else if (pifi->flInfo & FM_INFO_RETURNS_STROKES) {
|
|
|
|
PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: Font CAN return STROKES"));
|
|
}
|
|
|
|
#if DBG
|
|
if (DBG_PLOTFILENAME & DBG_SET_FONTTYPE) {
|
|
|
|
if ((FOType == FO_GLYPHBITS) &&
|
|
(!(pfo->flFontType & FO_TYPE_RASTER))) {
|
|
|
|
PLOTWARN(("DrvGetGlyphMode: Set FontType to RASTER"));
|
|
|
|
pfo->flFontType &= ~(FO_TYPE_TRUETYPE | FO_TYPE_DEVICE);
|
|
pfo->flFontType |= FO_TYPE_RASTER;
|
|
}
|
|
}
|
|
#endif
|
|
return(FOType);
|
|
|
|
#undef pPDev
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
BitmapTextOut(
|
|
PPDEV pPDev,
|
|
STROBJ *pstro,
|
|
FONTOBJ *pfo,
|
|
PRECTL pClipRect,
|
|
LPDWORD pOHTFlags,
|
|
DWORD Rop3
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine outputs the passed STROBJ with bitmaps that represent
|
|
each of the glyphs, rather than converting the glyphs to paths that
|
|
will be filled in the target device.
|
|
|
|
Arguments:
|
|
|
|
pPDev - Pointer to our PDEV
|
|
|
|
pstro - We pass a string object to be drawn
|
|
|
|
pfo - Pointer to the FONTOBJ
|
|
|
|
pClipRect - Current enumerated clipping rectangle
|
|
|
|
pOHTFlags - Pointer to the current OutputHTBitmap() flags
|
|
|
|
Rop3 - Rop3 to be used in the device
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE
|
|
|
|
|
|
Author:
|
|
|
|
18-Feb-1994 Fri 12:41:57 updated
|
|
change that so if pfo=NULL then the font already in BITMAP format
|
|
|
|
14-Feb-1994 Mon 18:16:25 create
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
GLYPHPOS *pgp;
|
|
GLYPHBITS *pgb;
|
|
SURFOBJ soGlyph;
|
|
POINTL ptlCur;
|
|
SIZEL sizlInc;
|
|
RECTL rclSrc;
|
|
RECTL rclDst;
|
|
BOOL MoreGlyphs;
|
|
BOOL Ok;
|
|
BOOL FirstCh;
|
|
ULONG cGlyphs;
|
|
|
|
|
|
//
|
|
// The public fields of SURFOBJ is what will be used by OutputHTBitmap
|
|
// instead of actually creating a SURFOBJ from the graphics engine. This
|
|
// is a safe thing to do, since only we look at these fields.
|
|
//
|
|
|
|
ZeroMemory(&soGlyph, sizeof(SURFOBJ));
|
|
|
|
soGlyph.dhsurf = (DHSURF)'PLOT';
|
|
soGlyph.hsurf = (HSURF)'TEXT';
|
|
soGlyph.dhpdev = (DHPDEV)pPDev;
|
|
soGlyph.iBitmapFormat = BMF_1BPP;
|
|
soGlyph.iType = STYPE_BITMAP;
|
|
soGlyph.fjBitmap = BMF_TOPDOWN;
|
|
|
|
//
|
|
// We will now enumerate each of the glyphs in the STROBJ such that
|
|
// we can image them. If the STROBJ has a non NULL pgp field, this means
|
|
// that the GLYPH definitions are already available, and no enumeration
|
|
// is required. If not, we will make a sequence of calls to STROBJ_bEnum
|
|
// (an engine helper) to enumerate the glyphs. The actual imaging code
|
|
// is the same, regardless of the stat of STROBJ->pgp
|
|
//
|
|
|
|
if (pstro->pgp) {
|
|
|
|
pgp = pstro->pgp;
|
|
MoreGlyphs = FALSE;
|
|
cGlyphs = pstro->cGlyphs;
|
|
|
|
PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: Character info already there (%ld glyphs)", cGlyphs));
|
|
|
|
} else {
|
|
|
|
STROBJ_vEnumStart(pstro);
|
|
MoreGlyphs = TRUE;
|
|
|
|
PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: STROBJ enub"));
|
|
}
|
|
|
|
//
|
|
// Now straring drawing the glyphs, if we have MoreGlyphs = TRUE then we
|
|
// will initially do a STROBJ_bEnum first to initialize enumeration of
|
|
// the glyphs
|
|
//
|
|
|
|
Ok = TRUE;
|
|
Rop3 &= 0xFF;
|
|
sizlInc.cx =
|
|
sizlInc.cy = 0;
|
|
FirstCh = TRUE;
|
|
|
|
do {
|
|
|
|
//
|
|
// Verify the job is not aborting, if it is break out now.
|
|
//
|
|
|
|
if (PLOT_CANCEL_JOB(pPDev)) {
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Check to see if we need to do an enumeration and start it if
|
|
// it is required.
|
|
//
|
|
|
|
if (MoreGlyphs) {
|
|
|
|
MoreGlyphs = STROBJ_bEnum(pstro, &cGlyphs, &pgp);
|
|
|
|
if (MoreGlyphs == DDI_ERROR) {
|
|
|
|
PLOTERR(("DrvTextOut: STROBJ_bEnum()=DDI_ERROR"));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
PLOTDBG(DBG_BMPFONT,
|
|
("BitmapTextOut: New batch of cGlyphs=%d", cGlyphs));
|
|
|
|
//
|
|
// Get the first character position
|
|
//
|
|
|
|
if ((FirstCh) && (cGlyphs)) {
|
|
|
|
ptlCur = pgp->ptl;
|
|
FirstCh = FALSE;
|
|
}
|
|
|
|
//
|
|
// Start sending each bitmap to the device
|
|
//
|
|
|
|
for ( ; (Ok) && (cGlyphs--); pgp++) {
|
|
|
|
GLYPHDATA gd;
|
|
GLYPHDATA *pgd;
|
|
|
|
|
|
if (PLOT_CANCEL_JOB(pPDev)) {
|
|
|
|
break;
|
|
}
|
|
|
|
if (pfo) {
|
|
|
|
//
|
|
// This is true type font, so query the bitmap
|
|
//
|
|
|
|
pgd = &gd;
|
|
|
|
if (FONTOBJ_cGetGlyphs(pfo,
|
|
FO_GLYPHBITS,
|
|
1,
|
|
&(pgp->hg),
|
|
(LPVOID)&pgd) != 1) {
|
|
|
|
PLOTERR(("BitmapTextOut: FONTOBJ_cGetGlyphs() FAILED"));
|
|
return(FALSE);
|
|
}
|
|
|
|
pgb = pgd->gdf.pgb;
|
|
|
|
} else {
|
|
|
|
//
|
|
// For bitmap font, we already have the bitmap
|
|
//
|
|
|
|
pgb = pgp->pgdf->pgb;
|
|
}
|
|
|
|
//
|
|
// Get the size of the bitmap
|
|
//
|
|
|
|
soGlyph.sizlBitmap = pgb->sizlBitmap;
|
|
|
|
//
|
|
// Compute new destination position for the text, based on the
|
|
// passed accelerators.
|
|
//
|
|
|
|
if (pstro->ulCharInc) {
|
|
|
|
sizlInc.cx =
|
|
sizlInc.cy = (LONG)pstro->ulCharInc;
|
|
|
|
} else if (pstro->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) {
|
|
|
|
sizlInc = soGlyph.sizlBitmap;
|
|
|
|
} else {
|
|
|
|
ptlCur = pgp->ptl;
|
|
}
|
|
|
|
if (!(pstro->flAccel & SO_HORIZONTAL)) {
|
|
|
|
sizlInc.cx = 0;
|
|
}
|
|
|
|
if (!(pstro->flAccel & SO_VERTICAL)) {
|
|
|
|
sizlInc.cy = 0;
|
|
}
|
|
|
|
if (pstro->flAccel & SO_REVERSED) {
|
|
|
|
sizlInc.cx = -sizlInc.cx;
|
|
sizlInc.cy = -sizlInc.cy;
|
|
}
|
|
|
|
|
|
//
|
|
// The pgp->ptl informs us where to position the glyph origin in
|
|
// the device surface, and pgb->ptlOrigin informs us of the
|
|
// relationship between character origin and bitmap origin. For
|
|
// example, if (2,-24) is passed in as the character origin, then
|
|
// we would need to reposition rclDst.left right 2 pixels and
|
|
// rclDst.top up 24 pixels.
|
|
//
|
|
|
|
rclDst.left = ptlCur.x + pgb->ptlOrigin.x;
|
|
rclDst.top = ptlCur.y + pgb->ptlOrigin.y;
|
|
rclDst.right = rclDst.left + soGlyph.sizlBitmap.cx;
|
|
rclDst.bottom = rclDst.top + soGlyph.sizlBitmap.cy;
|
|
ptlCur.x += sizlInc.cx;
|
|
ptlCur.y += sizlInc.cy;
|
|
|
|
|
|
//
|
|
// NOTE: If the bitmap size is 1x1 and the value of the glyphdata
|
|
// is 0 (background only) then we skip this glyph. This is
|
|
// GDI's way of telling us we have an empty glyph (like a
|
|
// space).
|
|
|
|
if ((soGlyph.sizlBitmap.cx == 1) &&
|
|
(soGlyph.sizlBitmap.cy == 1) &&
|
|
((pgb->aj[0] & 0x80) == 0x0)) {
|
|
|
|
PLOTDBG(DBG_BMPFONT,
|
|
("BitmapTextOut: Getting (1x1)=0 bitmap, SKIP it"));
|
|
|
|
soGlyph.sizlBitmap.cx =
|
|
soGlyph.sizlBitmap.cy = 0;
|
|
|
|
} else {
|
|
|
|
rclSrc = rclDst;
|
|
|
|
PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: pgp=%08lx, pgb=%08lx, ptl=(%ld, %ld) Inc=(%ld, %ld)",
|
|
pgp, pgb, pgp->ptl.x, pgp->ptl.y,
|
|
sizlInc.cx, sizlInc.cy));
|
|
PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: Bmp=%ld x %ld, pgb->ptlOrigin=[%ld, %ld]",
|
|
soGlyph.sizlBitmap.cx,
|
|
soGlyph.sizlBitmap.cy,
|
|
pgb->ptlOrigin.x, pgb->ptlOrigin.y));
|
|
PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: rclDst=(%ld, %ld)-(%ld, %ld)",
|
|
rclDst.left, rclDst.top, rclDst.right, rclDst.bottom));
|
|
|
|
}
|
|
|
|
//
|
|
// Now verify that we have a glyph to send, and that the glyphs
|
|
// destination position in the target device, lies inside
|
|
// the clipping region.
|
|
//
|
|
|
|
|
|
if ((soGlyph.sizlBitmap.cx) &&
|
|
(soGlyph.sizlBitmap.cy) &&
|
|
(IntersectRECTL(&rclDst, pClipRect))) {
|
|
|
|
//
|
|
// We will pass the internal version of soGlyph without making
|
|
// a temp. copy.
|
|
//
|
|
|
|
soGlyph.pvBits =
|
|
soGlyph.pvScan0 = (LPVOID)pgb->aj;
|
|
soGlyph.lDelta = (LONG)((soGlyph.sizlBitmap.cx + 7) >> 3);
|
|
soGlyph.cjBits = (LONG)(soGlyph.lDelta *
|
|
soGlyph.sizlBitmap.cy);
|
|
rclSrc.left = rclDst.left - rclSrc.left;
|
|
rclSrc.top = rclDst.top - rclSrc.top;
|
|
rclSrc.right = rclSrc.left + (rclDst.right - rclDst.left);
|
|
rclSrc.bottom = rclSrc.top + (rclDst.bottom - rclDst.top);
|
|
|
|
PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: rclSrc=(%ld, %ld)-(%ld, %ld)",
|
|
rclSrc.left, rclSrc.top, rclSrc.right, rclSrc.bottom));
|
|
|
|
#if DBG
|
|
if (DBG_PLOTFILENAME & DBG_SHOWRASFONT) {
|
|
|
|
LPBYTE pbSrc;
|
|
LPBYTE pbCur;
|
|
UINT x;
|
|
UINT y;
|
|
UINT Size;
|
|
BYTE bData;
|
|
BYTE Mask;
|
|
BYTE Buf[128];
|
|
|
|
DBGP(("================================================="));
|
|
DBGP(("BitmapTextOut: Size=%ld x %ld, Origin=(%ld, %ld), Clip=(%ld, %ld)-(%ld, %ld)",
|
|
soGlyph.sizlBitmap.cx, soGlyph.sizlBitmap.cy,
|
|
pgb->ptlOrigin.x, pgb->ptlOrigin.y,
|
|
rclSrc.left, rclSrc.top,
|
|
rclSrc.right, rclSrc.bottom));
|
|
|
|
pbSrc = soGlyph.pvScan0;
|
|
|
|
for (y = 0; y < (UINT)soGlyph.sizlBitmap.cy; y++) {
|
|
|
|
pbCur = pbSrc;
|
|
pbSrc += soGlyph.lDelta;
|
|
Mask = 0x0;
|
|
Size = 0;
|
|
|
|
for (x = 0;
|
|
x < (UINT)soGlyph.sizlBitmap.cx && Size < sizeof(Buf);
|
|
x++)
|
|
{
|
|
|
|
if (!(Mask >>= 1)) {
|
|
|
|
Mask = 0x80;
|
|
bData = *pbCur++;
|
|
}
|
|
|
|
if ((y >= (UINT)rclSrc.top) &&
|
|
(y < (UINT)rclSrc.bottom) &&
|
|
(x >= (UINT)rclSrc.left) &&
|
|
(x < (UINT)rclSrc.right)) {
|
|
|
|
Buf[Size++] = (BYTE)((bData & Mask) ? 219 :
|
|
177);
|
|
|
|
} else {
|
|
|
|
Buf[Size++] = (BYTE)((bData & Mask) ? 178 :
|
|
176);
|
|
}
|
|
}
|
|
|
|
if (Size < sizeof(Buf))
|
|
{
|
|
Buf[Size] = '\0';
|
|
}
|
|
else
|
|
{
|
|
Buf[sizeof(Buf) - 1] = '\0';
|
|
}
|
|
|
|
DBGP((Buf));
|
|
}
|
|
}
|
|
#endif
|
|
//
|
|
// Now output the bitmap that represents the glyph
|
|
//
|
|
|
|
Ok = OutputHTBitmap(pPDev, // pPDev
|
|
&soGlyph, // psoHT
|
|
NULL, // pco
|
|
(PPOINTL)&rclDst, // pptlDst
|
|
&rclSrc, // prclSrc
|
|
Rop3, // Rop3
|
|
pOHTFlags); // pOHTFlags
|
|
}
|
|
}
|
|
|
|
} while ((Ok) && (MoreGlyphs));
|
|
|
|
return(Ok);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
OutlineTextOut(
|
|
PPDEV pPDev,
|
|
STROBJ *pstro,
|
|
FONTOBJ *pfo,
|
|
PRECTL pClipRect,
|
|
BRUSHOBJ *pboBrush,
|
|
POINTL *pptlBrushOrg,
|
|
DWORD OutlineFlags,
|
|
ROP4 Rop4
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
This routine outputs the passed STROBJ by outputing a path that
|
|
represents each glyph to the target device.
|
|
|
|
Arguments:
|
|
|
|
pPDev - Pointer to our PDEV
|
|
|
|
pstro - We pass a string object to be drawn
|
|
|
|
pfo - Pointer to the FONTOBJ
|
|
|
|
pClipRect - Current enumerated clipping rectangle
|
|
|
|
pboBrush - Brush object to be used for the text
|
|
|
|
pptlBrushOrg - Brush origin alignment
|
|
|
|
OutlineFlags - specified how to do outline font from FPOLY_xxxx flags
|
|
|
|
Rop4 - Rop4 to be used
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE
|
|
|
|
|
|
Author:
|
|
|
|
18-Feb-1994 Fri 12:41:17 updated
|
|
Adding the OutlineFlags to specified how to do fill/stroke
|
|
|
|
27-Jan-1994 Thu 13:10:34 updated
|
|
re-write, style update, and arrange codes
|
|
|
|
25-Jan-1994 Wed 16:30:08 modified
|
|
Added FONTOBJ as a parameter and now we only FILL truetype fonts,
|
|
all others are stroked
|
|
|
|
18-Dec-1993 Sat 10:38:08 created
|
|
Change style
|
|
|
|
[t-kenl] Mar 14, 93 taken from DrvTextOut()
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
GLYPHPOS *pgp;
|
|
PATHOBJ *ppo;
|
|
RECTFX rectfxBound;
|
|
RECTFX rclfxClip;
|
|
POINTL ptlCur;
|
|
SIZEL sizlInc;
|
|
BOOL MoreGlyphs;
|
|
BOOL Ok;
|
|
BOOL FirstCh;
|
|
ULONG cGlyphs;
|
|
|
|
//
|
|
// We will enumerate each of the glyphs in the passed STROBJ and use
|
|
// the core polygon routine (DoPolygon) to draw each of them as a path.
|
|
// If the STROBJ has a non NULL pgp field, then all the data is already
|
|
// available on each gpyph. If not, we need to make a sequence of calls
|
|
// to the engine helper function STROBJ_bEnum in order to enumerate the
|
|
// glyphs. We will use the same code to output the data in both cases.
|
|
//
|
|
|
|
if (pClipRect) {
|
|
|
|
rclfxClip.xLeft = LTOFX(pClipRect->left);
|
|
rclfxClip.yTop = LTOFX(pClipRect->top);
|
|
rclfxClip.xRight = LTOFX(pClipRect->right);
|
|
rclfxClip.yBottom = LTOFX(pClipRect->bottom);
|
|
}
|
|
|
|
if (pstro->pgp) {
|
|
|
|
pgp = pstro->pgp;
|
|
MoreGlyphs = FALSE;
|
|
cGlyphs = pstro->cGlyphs;
|
|
|
|
PLOTDBG(DBG_TRUETYPE, ("OutlineTextOut: Character info already there (%ld glyphs)", cGlyphs));
|
|
|
|
} else {
|
|
|
|
STROBJ_vEnumStart(pstro);
|
|
MoreGlyphs = TRUE;
|
|
|
|
PLOTDBG(DBG_TRUETYPE, ("OutlineTextOut: STROBJ enub"));
|
|
}
|
|
|
|
//
|
|
// Now start drawing the glyphs, if we have MoreGlyphs = TRUE then we
|
|
// will do a STROBJ_bEnum first, in order to load up the Glyph data.
|
|
//
|
|
// Check the fill flags and set the flag appropriately out of the DEVMODE.
|
|
// We will ONLY fill TrueType fonts, all other types (vector) will only be
|
|
// stroked.
|
|
//
|
|
|
|
Ok = TRUE;
|
|
sizlInc.cx =
|
|
sizlInc.cy = 0;
|
|
FirstCh = TRUE;
|
|
|
|
do {
|
|
|
|
//
|
|
// Check to see if the job is being aborted, and exit out if such
|
|
// is the case.
|
|
//
|
|
|
|
if (PLOT_CANCEL_JOB(pPDev)) {
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We need to enum for more glyph data so do it now.
|
|
//
|
|
|
|
if (MoreGlyphs) {
|
|
|
|
MoreGlyphs = STROBJ_bEnum(pstro, &cGlyphs, &pgp);
|
|
|
|
if (MoreGlyphs == DDI_ERROR) {
|
|
|
|
PLOTERR(("DrvTextOut: STROBJ_bEnum()=DDI_ERROR"));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
PLOTDBG(DBG_TRUETYPE1,
|
|
("OutlineTextOut: New batch of cGlyphs=%d", cGlyphs));
|
|
|
|
//
|
|
// Stroke each glyph in this batch, then check if there are more.
|
|
// Getting the first character position
|
|
//
|
|
|
|
if ((FirstCh) && (cGlyphs)) {
|
|
|
|
ptlCur = pgp->ptl;
|
|
FirstCh = FALSE;
|
|
}
|
|
|
|
for ( ; (Ok) && (cGlyphs--); pgp++) {
|
|
|
|
#ifdef USERMODE_DRIVER
|
|
|
|
GLYPHDATA gd;
|
|
GLYPHDATA *pgd;
|
|
|
|
#endif // USERMODE_DRIVER
|
|
|
|
if (PLOT_CANCEL_JOB(pPDev)) {
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set up to enumerate path
|
|
//
|
|
|
|
#ifdef USERMODE_DRIVER
|
|
|
|
pgd = &gd;
|
|
|
|
if (FONTOBJ_cGetGlyphs(pfo,
|
|
FO_PATHOBJ,
|
|
1,
|
|
&(pgp->hg),
|
|
(LPVOID)&pgd) != 1) {
|
|
|
|
PLOTRIP(("OutlineTextOut: FONTOBJ_cGetGlyphs() FAILED"));
|
|
return(FALSE);
|
|
}
|
|
|
|
ppo = pgd->gdf.ppo;
|
|
|
|
#else
|
|
|
|
ppo = pgp->pgdf->ppo;
|
|
|
|
#endif // USERMODE_DRIVER
|
|
|
|
//
|
|
// If the clip rect is not null then verify the glyph actually lies
|
|
// within the clipping rect then OUTPUT!!!
|
|
//
|
|
|
|
if (pstro->ulCharInc) {
|
|
|
|
PLOTDBG(DBG_DEFCHARINC, ("OutlineTextOut: CharInc=(%ld, %ld)->(%ld, %ld), [%ld]",
|
|
ptlCur.x, ptlCur.y,
|
|
ptlCur.x + pstro->ulCharInc, ptlCur.y,
|
|
pstro->ulCharInc));
|
|
|
|
sizlInc.cx =
|
|
sizlInc.cy = (LONG)pstro->ulCharInc;
|
|
|
|
|
|
//
|
|
// Check the text Accelators and adjust accordingly.
|
|
//
|
|
|
|
if (!(pstro->flAccel & SO_HORIZONTAL)) {
|
|
|
|
sizlInc.cx = 0;
|
|
}
|
|
|
|
if (!(pstro->flAccel & SO_VERTICAL)) {
|
|
|
|
sizlInc.cy = 0;
|
|
}
|
|
|
|
if (pstro->flAccel & SO_REVERSED) {
|
|
|
|
sizlInc.cx = -sizlInc.cx;
|
|
sizlInc.cy = -sizlInc.cy;
|
|
}
|
|
|
|
ptlCur.x += sizlInc.cx;
|
|
ptlCur.y += sizlInc.cy;
|
|
|
|
} else {
|
|
|
|
ptlCur = pgp->ptl;
|
|
}
|
|
|
|
if (pClipRect) {
|
|
|
|
//
|
|
// Create a rect in correct device space and compare to the
|
|
// clip rect
|
|
//
|
|
|
|
PATHOBJ_vGetBounds(ppo, &rectfxBound);
|
|
|
|
//
|
|
// Since the glyph positioning is based on the glyph origin
|
|
// transform now to device space, in order to check if the
|
|
// glyph lies inside the current clipping region.
|
|
//
|
|
|
|
rectfxBound.xLeft += LTOFX(ptlCur.x);
|
|
rectfxBound.yTop += LTOFX(ptlCur.y);
|
|
rectfxBound.xRight += LTOFX(ptlCur.x);
|
|
rectfxBound.yBottom += LTOFX(ptlCur.y);
|
|
|
|
if ((rectfxBound.xLeft > rclfxClip.xRight) ||
|
|
(rectfxBound.xRight < rclfxClip.xLeft) ||
|
|
(rectfxBound.yTop > rclfxClip.yBottom) ||
|
|
(rectfxBound.yBottom < rclfxClip.yTop)) {
|
|
|
|
PLOTDBG(DBG_TRUETYPE1, ("OutlineTextOut: Outside of CLIP, skipping glyph ..."));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Utilize the core path building function, taking advantage of
|
|
// its ability to offset the passed PATH by a specific amount.
|
|
//
|
|
|
|
if (!(Ok = DoPolygon(pPDev,
|
|
&ptlCur,
|
|
NULL,
|
|
ppo,
|
|
pptlBrushOrg,
|
|
pboBrush,
|
|
pboBrush,
|
|
Rop4,
|
|
NULL,
|
|
OutlineFlags))) {
|
|
|
|
PLOTERR(("OutlineTextOut: Failed in DoPolygon(Options=%08lx)",
|
|
OutlineFlags));
|
|
|
|
//
|
|
// If we failed to draw it, then try just stroking it, since
|
|
// that won't depend on any polygon constraints used in the
|
|
// target device, and failing DrvStrokePath, won't make the
|
|
// Text output get broken down to any simpler format.
|
|
//
|
|
|
|
if ((OutlineFlags & FPOLY_MASK) != FPOLY_STROKE) {
|
|
|
|
//
|
|
// If we failed then just stroke it
|
|
//
|
|
|
|
PLOTERR(("OutlineTextOut: Now TRY DoPolygon(FPOLY_STROKE)"));
|
|
|
|
Ok = DoPolygon(pPDev,
|
|
&ptlCur,
|
|
NULL,
|
|
ppo,
|
|
pptlBrushOrg,
|
|
NULL,
|
|
pboBrush,
|
|
Rop4,
|
|
NULL,
|
|
FPOLY_STROKE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Go to next position
|
|
|
|
ptlCur.x += sizlInc.cx;
|
|
ptlCur.y += sizlInc.cy;
|
|
}
|
|
|
|
} while ((Ok) && (MoreGlyphs));
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DrvTextOut(
|
|
SURFOBJ *pso,
|
|
STROBJ *pstro,
|
|
FONTOBJ *pfo,
|
|
CLIPOBJ *pco,
|
|
RECTL *prclExtra,
|
|
RECTL *prclOpaque,
|
|
BRUSHOBJ *pboFore,
|
|
BRUSHOBJ *pboOpaque,
|
|
POINTL *pptlBrushOrg,
|
|
MIX mix
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The Graphics Engine will call this routine to render a set of glyphs at
|
|
specified positions. This function will review the passed data, and
|
|
image the glyph either as a path to be filled or stroked, or as a bitmap.
|
|
|
|
Arguments:
|
|
|
|
pso - pointer to our surface object
|
|
|
|
pstro - pointer to the string object
|
|
|
|
pfo - pointer to the font object
|
|
|
|
pco - clipping object
|
|
|
|
prclExtra - pointer to array of rectangles to be merge with glyphs
|
|
|
|
prclOpaque - Pointer to a rectangle to be fill with pboOpaque brush
|
|
|
|
pboFore - pointer to the brush object for the foreground color
|
|
|
|
pboOpqaue - pointer to the brush object for the opaque rectangle
|
|
|
|
pptlBrushOrg- Pointer to the brush alignment
|
|
|
|
mix - Two Rop2 mode
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE
|
|
|
|
|
|
Author:
|
|
|
|
23-Jan-1994 Thu 2:59:31 created
|
|
|
|
27-Jan-1994 Thu 12:56:11 updated
|
|
Style, re-write, commented
|
|
|
|
10-Mar-1994 Thu 00:30:38 updated
|
|
1. Make sure we not fill the stroke type of font
|
|
2. Move rclOpqaue and rclExtra process out from the do loop, so that
|
|
when it in the RTL mode for the font it will be correctly processed
|
|
and it will also save output data size by not switching in/out
|
|
RTL/HPGL2 mode just try to do the prclOpaque/prclExtra
|
|
3. Process FO_TYPE correctly for all type of fonts (outline, truetype,
|
|
bitmap, vector, stroke and others)
|
|
|
|
11-Mar-1994 Fri 19:24:56 updated
|
|
Bug# 10276, the clipping window is set for the raster font and clear
|
|
clipping window is done before the exit to HPGL2 mode, this causes
|
|
all raster font after the first clip is not visible to end of the
|
|
page. Now changed it so we only do clipping window when the font is
|
|
NOT RASTER.
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
#define pDrvHTInfo ((PDRVHTINFO)(pPDev->pvDrvHTData))
|
|
|
|
|
|
PPDEV pPDev;
|
|
PRECTL pCurClipRect;
|
|
HTENUMRCL EnumRects;
|
|
DWORD RTLPalDW[2];
|
|
DWORD rgbText;
|
|
DWORD OHTFlags;
|
|
DWORD OutlineFlags;
|
|
BOOL DoRasterFont;
|
|
BOOL bMore;
|
|
BOOL bDoClipWindow;
|
|
BOOL Ok;
|
|
DWORD BMFontRop3;
|
|
ROP4 Rop4;
|
|
|
|
|
|
//
|
|
// Transform the MIX to ROP4
|
|
//
|
|
|
|
Rop4 = MixToRop4(mix);
|
|
|
|
PLOTDBG(DBG_TEXTOUT, ("DrvTextOut: prclOpaque = %08lx", prclOpaque));
|
|
PLOTDBG(DBG_TEXTOUT, (" prclExtra = %08lx", prclExtra));
|
|
PLOTDBG(DBG_TEXTOUT, (" pstro->flAccel = %08lx", pstro->flAccel));
|
|
PLOTDBG(DBG_TEXTOUT, (" pstro->ulCharInc = %ld", pstro->ulCharInc));
|
|
PLOTDBG(DBG_TEXTOUT, (" pfo->cxMax = %ld", pfo->cxMax));
|
|
PLOTDBG(DBG_TEXTOUT, (" FontType = %08lx", pfo->flFontType));
|
|
PLOTDBG(DBG_TEXTOUT, (" MIX = %04lx (Rop=%04lx)", mix, Rop4));
|
|
|
|
if (!(pPDev = SURFOBJ_GETPDEV(pso))) {
|
|
|
|
PLOTERR(("DoTextOut: Invalid pPDev in pso"));
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pPDev->PlotDM.Flags & PDMF_PLOT_ON_THE_FLY) {
|
|
|
|
PLOTWARN(("DoTextOut: POSTER Mode IGNORE All Texts"));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Since we dont support device fonts, make sure we are not getting one
|
|
// now.
|
|
//
|
|
|
|
if (pfo->flFontType & FO_TYPE_DEVICE) {
|
|
|
|
PLOTASSERT(1, "DrvTextOut: Getting DEVICE font (%08lx)",
|
|
!(pfo->flFontType & FO_TYPE_DEVICE ), pfo->flFontType);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (DoRasterFont = (BOOL)(pfo->flFontType & FO_TYPE_RASTER)) {
|
|
|
|
PLOTDBG(DBG_TEXTOUT1, ("DrvTextOut: We got the BITMAP Font from GDI"));
|
|
|
|
//
|
|
// Make pfo = NULL so later we will not try to do FONTOBJ_cGetGlyph in
|
|
// BitmapTextOut
|
|
//
|
|
|
|
#ifndef USERMODE_DRIVER
|
|
|
|
pfo = NULL;
|
|
|
|
#endif // !USERMODE_DRIVER
|
|
|
|
} else {
|
|
|
|
PIFIMETRICS pifi;
|
|
|
|
//
|
|
// Try to find out if we need to fill the font, or just stroke it.
|
|
//
|
|
|
|
if ((pifi = FONTOBJ_pifi(pfo)) &&
|
|
(pifi->flInfo & FM_INFO_RETURNS_STROKES)) {
|
|
|
|
PLOTDBG(DBG_TEXTOUT1, ("DrvTextOut() Font can only do STROKE"));
|
|
|
|
OutlineFlags = FPOLY_STROKE;
|
|
|
|
} else {
|
|
|
|
PLOTDBG(DBG_TEXTOUT1, ("DrvTextOut() Font We can do FILL, User Said=%hs",
|
|
(pPDev->PlotDM.Flags & PDMF_FILL_TRUETYPE) ? "FILL" : "STROKE"));
|
|
|
|
OutlineFlags = (pPDev->PlotDM.Flags & PDMF_FILL_TRUETYPE) ?
|
|
(DWORD)FPOLY_FILL : (DWORD)FPOLY_STROKE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if we need to opaque the area
|
|
//
|
|
|
|
if (prclOpaque) {
|
|
|
|
PLOTDBG(DBG_TEXTOUT2, ("prclOpaque=(%ld, %ld) - (%ld, %ld)",
|
|
prclOpaque->left, prclOpaque->top,
|
|
prclOpaque->right, prclOpaque->bottom));
|
|
|
|
if (!DrvBitBlt(pso, // Target
|
|
NULL, // Source
|
|
NULL, // Mask Obj
|
|
pco, // Clip Obj
|
|
NULL, // XlateOBj
|
|
prclOpaque, // Dest Rect Ptr
|
|
NULL, // Source Pointl
|
|
NULL, // Mask Pointl
|
|
pboOpaque, // Brush Obj
|
|
pptlBrushOrg, // Brush Origin
|
|
0xF0F0)) { // ROP4 (PATCOPY)
|
|
|
|
PLOTERR(("DrvTextOut: DrvBitBltBit(pboOpqaue) FAILED!"));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We will do prclExtra only if it is not NULL, this simulates the
|
|
// underline or strikeout effects.
|
|
//
|
|
|
|
if (prclExtra) {
|
|
|
|
//
|
|
// The prclExtra terminated only if all points in rectangle coordinate
|
|
// are all set to zeros
|
|
//
|
|
|
|
while ((prclExtra->left) ||
|
|
(prclExtra->top) ||
|
|
(prclExtra->right) ||
|
|
(prclExtra->bottom)) {
|
|
|
|
PLOTDBG(DBG_TEXTOUT2, ("prclExtra=(%ld, %ld) - (%ld, %ld)",
|
|
prclExtra->left, prclExtra->top,
|
|
prclExtra->right, prclExtra->bottom));
|
|
|
|
if (!DrvBitBlt(pso, // Target
|
|
NULL, // Source
|
|
NULL, // Mask Obj
|
|
pco, // Clip Obj
|
|
NULL, // XlateOBj
|
|
prclExtra, // Dest Rect Ptr
|
|
NULL, // Source Pointl
|
|
NULL, // Mask Pointl
|
|
pboFore, // Brush Obj
|
|
pptlBrushOrg, // Brush Origin
|
|
Rop4)) { // ROP4
|
|
|
|
PLOTERR(("DrvTextOut: DrvBitBltBit(pboFore) FAILED!"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Now try next EXTRA rectangle
|
|
//
|
|
|
|
++prclExtra;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are using Raster Font then the mode will be set as following
|
|
//
|
|
|
|
if (DoRasterFont) {
|
|
|
|
RTLPalDW[0] = pDrvHTInfo->RTLPal[0].dw;
|
|
RTLPalDW[1] = pDrvHTInfo->RTLPal[1].dw;
|
|
|
|
//
|
|
// Get the color to use.
|
|
//
|
|
|
|
if (!GetColor(pPDev,
|
|
pboFore,
|
|
&(pDrvHTInfo->RTLPal[1].dw),
|
|
NULL,
|
|
Rop4)) {
|
|
|
|
PLOTERR(("DrvTextOut: Get Raster Font Text Color failed! use BLACK"));
|
|
|
|
rgbText = 0x0;
|
|
}
|
|
|
|
if (pDrvHTInfo->RTLPal[1].dw == 0xFFFFFF) {
|
|
|
|
//
|
|
// White Text, our white is 1 and 0=black, so do:"not S and D"
|
|
//
|
|
|
|
PLOTDBG(DBG_BMPTEXTCLR, ("DrvTextOut: Doing WHITE TEXT (0xEEEE)"));
|
|
|
|
pDrvHTInfo->RTLPal[0].dw = 0x0;
|
|
OHTFlags = 0;
|
|
BMFontRop3 = 0xEE; // S | D
|
|
|
|
} else {
|
|
|
|
pDrvHTInfo->RTLPal[0].dw = 0xFFFFFF;
|
|
OHTFlags = OHTF_SET_TR1;
|
|
BMFontRop3 = 0xCC; // S
|
|
}
|
|
|
|
PLOTDBG(DBG_BMPTEXTCLR,
|
|
("DrvTextOut: BG=%02x:%02x:%02x, FG=%02x:%02x:%02x, Rop3=%04lx",
|
|
(DWORD)pDrvHTInfo->RTLPal[0].Pal.R,
|
|
(DWORD)pDrvHTInfo->RTLPal[0].Pal.G,
|
|
(DWORD)pDrvHTInfo->RTLPal[0].Pal.B,
|
|
(DWORD)pDrvHTInfo->RTLPal[1].Pal.R,
|
|
(DWORD)pDrvHTInfo->RTLPal[1].Pal.G,
|
|
(DWORD)pDrvHTInfo->RTLPal[1].Pal.B,
|
|
BMFontRop3));
|
|
|
|
//
|
|
// We do not need clip window command in RTL mode
|
|
//
|
|
|
|
bDoClipWindow = FALSE;
|
|
|
|
} else {
|
|
|
|
bDoClipWindow = TRUE;
|
|
}
|
|
|
|
bMore = FALSE;
|
|
Ok = TRUE;
|
|
EnumRects.c = 1;
|
|
|
|
if ((!pco) || (pco->iDComplexity == DC_TRIVIAL)) {
|
|
|
|
//
|
|
// The whole output destination rectangle is visible
|
|
//
|
|
|
|
PLOTDBG(DBG_TEXTOUT, ("DrvTextOut: pco=%hs",
|
|
(pco) ? "DC_TRIVIAL" : "NULL"));
|
|
|
|
EnumRects.rcl[0] = pstro->rclBkGround;
|
|
bDoClipWindow = FALSE;
|
|
|
|
} else if (pco->iDComplexity == DC_RECT) {
|
|
|
|
//
|
|
// The visible area is one rectangle intersect with the destinaiton
|
|
//
|
|
|
|
PLOTDBG(DBG_TEXTOUT, ("DrvTextOut: pco=DC_RECT"));
|
|
|
|
EnumRects.rcl[0] = pco->rclBounds;
|
|
|
|
} else {
|
|
|
|
//
|
|
// We have complex clipping region to be computed, call engine to start
|
|
// enumerating the rectangles and set More = TRUE so we can get the
|
|
// first batch of rectangles.
|
|
//
|
|
|
|
PLOTDBG(DBG_TEXTOUT, ("DrvTextOut: pco=DC_COMPLEX, EnumRects now"));
|
|
|
|
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
|
|
bMore = TRUE;
|
|
}
|
|
|
|
do {
|
|
|
|
//
|
|
// If More is true then we need to get next batch of rectangles. In
|
|
// this mode, we have a set of rectangles that represents the
|
|
// clipping region in the target device. Since none of the devices
|
|
// we handle can acommodate a complex clipping path, we enumerate the
|
|
// cliping path (CLIPOBJ) as rectangles and image the entire STROBJ
|
|
// through these rectangles, trying to determine as quickly as possible
|
|
// when a glyph does not lie in the current clipping rect.
|
|
//
|
|
|
|
if (bMore) {
|
|
|
|
bMore = CLIPOBJ_bEnum(pco, sizeof(EnumRects), (ULONG *)&EnumRects);
|
|
}
|
|
|
|
//
|
|
// prcl will point to the first enumerated rectangle, which may just
|
|
// be the RECT of the clipping area if its DC_RECT.
|
|
//
|
|
|
|
pCurClipRect = (PRECTL)&EnumRects.rcl[0];
|
|
|
|
while ((Ok) && bMore != DDI_ERROR && (EnumRects.c--)) {
|
|
|
|
PLOTDBG(DBG_TEXTOUT, ("DrvTextOut: Clip=(%ld, %ld)-(%ld, %ld) %ld x %ld, Bound=(%ld, %d)-(%ld, %ld), %ld x %ld",
|
|
pCurClipRect->left, pCurClipRect->top,
|
|
pCurClipRect->right, pCurClipRect->bottom,
|
|
pCurClipRect->right - pCurClipRect->left,
|
|
pCurClipRect->bottom - pCurClipRect->top,
|
|
pstro->rclBkGround.left, pstro->rclBkGround.top,
|
|
pstro->rclBkGround.right, pstro->rclBkGround.bottom,
|
|
pstro->rclBkGround.right - pstro->rclBkGround.left,
|
|
pstro->rclBkGround.bottom - pstro->rclBkGround.top));
|
|
|
|
//
|
|
// If we will output the STROBJ as bitmaps that represent the
|
|
// glyphs of the STROBJ, do it now.
|
|
//
|
|
|
|
if (DoRasterFont) {
|
|
|
|
if (!(Ok = BitmapTextOut(pPDev,
|
|
pstro,
|
|
pfo,
|
|
pCurClipRect,
|
|
&OHTFlags,
|
|
BMFontRop3))) {
|
|
|
|
PLOTERR(("DrvTextOut: BitmapTypeTextOut() FAILED"));
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// If we have a clip window, set it now, this will allow
|
|
// the target device to do any clipping
|
|
//
|
|
|
|
if (bDoClipWindow) {
|
|
|
|
SetClipWindow(pPDev, pCurClipRect);
|
|
}
|
|
|
|
if (!(Ok = OutlineTextOut(pPDev,
|
|
pstro,
|
|
pfo,
|
|
pCurClipRect,
|
|
pboFore,
|
|
pptlBrushOrg,
|
|
OutlineFlags,
|
|
Rop4))) {
|
|
|
|
PLOTERR(("DrvTextOut: TrueTypeTextOut() FAILED!"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Goto next clip rectangle
|
|
//
|
|
|
|
pCurClipRect++;
|
|
}
|
|
|
|
} while ((Ok) && (bMore == TRUE));
|
|
|
|
|
|
if (DoRasterFont) {
|
|
|
|
pDrvHTInfo->RTLPal[0].dw = RTLPalDW[0];
|
|
pDrvHTInfo->RTLPal[1].dw = RTLPalDW[1];
|
|
|
|
if (OHTFlags & OHTF_MASK) {
|
|
|
|
OHTFlags |= OHTF_EXIT_TO_HPGL2;
|
|
|
|
OutputHTBitmap(pPDev, NULL, NULL, NULL, NULL, 0xAA, &OHTFlags);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we had set a clip window now is the time to clear it after exit from
|
|
// RTL Mode
|
|
//
|
|
|
|
if (bDoClipWindow) {
|
|
|
|
ClearClipWindow(pPDev);
|
|
}
|
|
|
|
return(Ok);
|
|
|
|
|
|
#undef pDrvHTInfo
|
|
}
|