Sample Code
Windows Driver Samples/ MSPLOT Plotter Driver Sample/ C++/ plotter/ textout.c/
/*++ 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[]; _Use_decl_annotations_ DWORD WINAPI 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 = NULL; GLYPHBITS *pgb; SURFOBJ soGlyph; POINTL ptlCur = {0}; SIZEL sizlInc; RECTL rclSrc = {0}; RECTL rclDst; BOOL MoreGlyphs; BOOL Ok; BOOL FirstCh; ULONG cGlyphs = 0; // // 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 = 0; 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 = NULL; PATHOBJ *ppo; RECTFX rectfxBound; RECTFX rclfxClip = {0}; POINTL ptlCur = {0}; SIZEL sizlInc; BOOL MoreGlyphs; BOOL Ok; BOOL FirstCh; ULONG cGlyphs = 0; // // 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 WINAPI 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 = 0; DWORD OutlineFlags = 0; BOOL DoRasterFont; BOOL bMore; BOOL bDoClipWindow; BOOL Ok; DWORD BMFontRop3 = 0; 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 }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials