Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2166 lines
67 KiB

/****************************** Module Header *******************************
* udenable.c
* The enable routines, based on the windows unidrv code.
*
* HISTORY:
* 10:16 on Mon 03 Dec 1990 -by- Lindsay Harris [lindsayh]
* Copied from Windows code
*
* 28-May-1991 Tue 14:41:15 updated -by- Daniel Chou (danielc)
* Add in halftone stuff
*
* Thursday November 25 1993 -by- Norman Hendley [normanh]
* Enabled GPC3 type page protection & memory config's
* Enabled loading of GPC3 minidrivers
* Necessarily removed gpc structure size sanity checks
* Structure sizes have changed with GPC3
*
* Copyright (C) 1990 - 1993 Microsoft Corporation
*
****************************************************************************/
#define _HTUI_APIS_
#include <stddef.h>
#include <windows.h>
#include <winspool.h>
#include <winddi.h>
#include <winres.h>
#include <libproto.h>
#include "win30def.h"
#include "udmindrv.h"
#include "udpfm.h"
#include "uddevice.h"
#include "udresrc.h"
#include "pdev.h"
#include "udresid.h"
#include "stretch.h"
#include "udrender.h"
#include "udfnprot.h"
#include "ntres.h"
#include "fontinst.h"
#include <sf_pcl.h>
#include <udproto.h> /* Rasdd lib GPC functions */
#include "rasdd.h"
/*
* A temporary define until we get our own error message!
*/
#define ERROR_INVALID_CHARACTERISATION_DATA ERROR_BAD_FORMAT
#define BBITS 8 // Bits per byte
#define MIN_MEMORY 1024
/*
* A default COLORINFO structure in the event the registry and minidriver
* have no data.
*/
//
// 02-Apr-1995 Sun 11:11:14 updated -by- Daniel Chou (danielc)
// Move the defcolor adjustment into the printers\lib\halftone.c
//
extern DEVHTINFO DefDevHTInfo;
/*
* Local function prototypes
*/
int iGCD( int, int );
int hypot( int, int );
void InitOutputCtl( UD_PDEV *, PEDM );
BOOL bGetPaperFormat( PAPERFORMAT *, PEDM, PDH );
BOOL bGetMinPaperMargins( PDH, PEDM, RECT * );
BOOL bCanCompress( PDH, PEDM );
BOOL bBuildCommandTable( UD_PDEV *, PDH, PEDM );
void vSetCDAddr( UD_PDEV *, int, OCD *, int );
void vSetHTData( PDEV *, GDIINFO * );
// added by DerryD
void InitMDev (UD_PDEV *,PEDM);
// end
/***************************** Function Header ******************************
* udInit()
* Perform the unidrv code initialisation operations. This requires
* reading the device description data from the minidriver, and
* turning that into the internal format required.
*
* RETURNS:
* TRUE/FALSE, TRUE for success.
*
* HISTORY:
* 15:47 on Mon 04 May 1992 -by- Lindsay Harris [lindsayh]
* Add proper error code handling.
*
* 15:11 on Fri 26 Apr 1991 -by- Lindsay Harris [lindsayh]
* Changes associated with accepting NT format Dlls
*
* 11:08 on Mon 03 Dec 1990 -by- Lindsay Harris [lindsayh]
* Major modifications of unidrv enable.c code.
*
****************************************************************************/
BOOL
udInit(
PDEV *pPDev, /* RasDD style PDEV */
PGDIINFO pGDIInfo, /* Filled in by us */
PEDM pedm)
{
int xdpi, ydpi; /* Text resolutions */
int gxdpi, gydpi; /* Graphics resolutions */
WORD fText;
DWORD *pdw; /* For accessing minidriver heap */
UD_PDEV *pUDPDev; /* UniDrv's PDEV */
MODELDATA *pModelData;
RESOLUTION *pRes;
PAPERSIZE *pSize;
EXTDEVMODE edm; /* Filtered, validated version */
PDH pdh;
RES_ELEM ResElem; /* Resource address and size */
BOOL fGpcVersion2;
int iRealMaxHE;
// derryd
MDEV *pMDev; // Pointer to Minidriver callback structure
//end
/*
* Check to see if we have already done this - it may be there,
* since RestartPDEV also comes this way, and it will have everything
* set up, and there is no real need to do it again!
*/
if( !(pPDev->pvWinResData) )
{
/*
* Setup the pathname of the minidriver, and then allocate a
* WinResData structure on the heap and initialise it. After that,
* call the resource reading stuff to get the characterisation data.
*/
if( !(pPDev->pvWinResData = (WINRESDATA *)HeapAlloc( pPDev->hheap, 0,
sizeof( WINRESDATA ) )) )
{
#if DBG
DbgPrint( "Rasdd!udInit: cannot allocate WINRESDATA.\n" );
#endif
return FALSE;
}
if( !InitWinResData( pPDev->pvWinResData, pPDev->hheap, pPDev->pstrDataFile ) )
{
HeapFree( pPDev->hheap, 0, (LPSTR)pPDev->pvWinResData );
return FALSE;
}
}
/*
* Get the table data out of the minidriver resource. But note that
* we may already have this data! If we come here because of a
* RestartPDEV call, then the characterisation data is already
* available to us, so there is nothing to be gained from re-reading
* it!
*/
if( !pPDev->pGPCData )
{
/*
* Make a copy of the GPC data. The resource may be freed before
* we have finished with it.
*/
if( !GetWinRes( pPDev->pvWinResData, 1, RC_TABLES, &ResElem ))
{
#if DBG
DbgPrint( "Rasdd!udInit: Can't read/allocate GPC data\n" );
#endif
return FALSE;
}
pdh = ResElem.pvResData;
pPDev->pGPCData = pdh;
/*
* Look for any additional data - especially NT specific stuff.
* A NULL return is quite OK, as it means we have no NT stuff.
*/
pPDev->pNTRes = pntresLoad( pPDev->pvWinResData );
}
else
{
/* Data is already available, so use it! */
pdh = pPDev->pGPCData;
}
/* Is the data format acceptable??? */
fGpcVersion2 = pdh->wVersion < GPC_VERSION3;
iRealMaxHE = fGpcVersion2 ? MAXHE_GPC2 : MAXHE;
if( pdh->sMagic != 0x7f00 || pdh->sMaxHE != (iRealMaxHE) ||
!VERSION_CHECK( pdh->wVersion ) )
{
/* Bad stuff - we should ignore it now & return error */
#if DBG
DbgPrint( "Rasdd!udInit: Bad DATAHDR\n" );
#endif
SetLastError( ERROR_INVALID_CHARACTERISATION_DATA );
pPDev->pGPCData = 0; /* Just to be sure */
return FALSE;
}
/*
* Allocate storage for the UDPDev structure. This is used by
* the functions taken from UniDrv. But note that there may be one
* already, resulting from a call to RestartPDEV().
*/
if( (pUDPDev = pPDev->pUDPDev) == NULL )
{
/* Allocate one now */
pUDPDev = (UD_PDEV *)HeapAlloc( pPDev->hheap, 0, sizeof( UD_PDEV ) );
if( pUDPDev == NULL )
{
#if DBG
DbgPrint( "Rasdd!udInit: HeapAlloc fails for UD_PDEV\n" );
#endif
return FALSE;
}
// derryd - added for WDL release
pMDev = (MDEV *)HeapAlloc( pPDev->hheap, 0, sizeof( MDEV ) );
if( pMDev == NULL )
{
#if DBG
DbgPrint( "Rasdd!udInit: HeapAlloc fails for MDEV\n" );
#endif
return FALSE;
}
// end
pPDev->pUDPDev = pUDPDev;
}
/*
* Start with a clean slate.
*/
ZeroMemory( pUDPDev, sizeof( UD_PDEV ) );
// derryd - Zero the new structure !
ZeroMemory( pMDev, sizeof( MDEV ) );
// derryd Initialise pUDPDev.MDEV to newly allocated area
pUDPDev->pMDev = pMDev;
// end
pUDPDev->pdh = pdh;
pUDPDev->hPrinter = pPDev->hPrinter; /* For WriteSpoolBuf() */
if( pPDev->pNTRes && (((NT_RES *)pPDev->pNTRes)->dwFlags & NR_SEIKO) )
pUDPDev->fMode |= PF_SEIKO; /* !!! Seiko HACK */
/*
* Next step is to take the DEVMODE data that may be passed in,
* and amalgamate that with the data for this printer from the
* system database.
*/
vGenerateEDM( pPDev, &edm, pedm );
pedm = &edm; /* The one to use */
/*
* Now initialise the data needed.
*/
pModelData = GetTableInfo( pdh, HE_MODELDATA, pedm );
pRes = GetTableInfo( pdh, HE_RESOLUTION, pedm );
pSize = GetTableInfo( pdh, HE_PAPERSIZE, pedm );
// Some additional checks for GPC3 features we don't (yet) support
if( pModelData == 0 || pRes == 0 || pSize == 0 ||
(pModelData->fGeneral & MD_CMD_CALLBACK) )
{
#if DBG
DbgPrint( "Rasdd!udInit: Invalid GPC data\n" );
#endif
SetLastError( ERROR_INVALID_CHARACTERISATION_DATA );
HeapFree( pPDev->hheap, 0, (LPSTR)pUDPDev );
// derryd
HeapFree( pPDev->hheap, 0, (LPSTR)pMDev );
// end
pPDev->pUDPDev = 0; /* Stop others freeing it */
return FALSE;
}
/*
* Check if a non-NT minidriver has code in it - if so, we cannot
* use it.
*/
if( (pRes->fBlockOut & RES_BO_OEMGRXFILTER) &&
!(((WINRESDATA *)(pPDev->pvWinResData))->fStatus & WRD_NT_DLL) )
{
#if DBG
DbgPrint( "Rasdd!udInit: Old style minidriver with code - nogo\n" );
#endif
SetLastError( ERROR_INVALID_CHARACTERISATION_DATA );
HeapFree( pPDev->hheap, 0, (LPSTR)pUDPDev );
// derryd
HeapFree( pPDev->hheap, 0, (LPSTR)pMDev );
// end
pPDev->pUDPDev = 0;
return FALSE;
}
/* !!!LindsayH - hack until GPC supports Seiko Color Point */
if( pUDPDev->fMode & PF_SEIKO )
pRes->fBlockOut |= RES_BO_ALL_GRAPHICS;
/*
* Obtain the text resolution, and allow for orientation too. Also
* want the graphics resolutions, since the font metrics info needs
* to be returned to the engine in graphics units.
*/
xdpi = pdh->ptMaster.x / pRes->ptTextScale.x;
ydpi = pdh->ptMaster.y / pRes->ptTextScale.y;
gxdpi = xdpi >> pRes->ptScaleFac.x;
gydpi = ydpi >> pRes->ptScaleFac.y;
/* Switch resolutions if we are in landscape orientation */
if( pedm->dm.dmOrientation == DMORIENT_LANDSCAPE )
{
/* Sidewards printing, so swap the numbers */
int iSwap;
iSwap = xdpi;
xdpi = ydpi;
ydpi = iSwap;
iSwap = gxdpi;
gxdpi = gydpi;
gydpi = iSwap;
/* Also check whether we need to rotate */
if( !(pModelData->fGeneral & MD_LANDSCAPE_GRX_ABLE) )
{
pUDPDev->fMode |= PF_ROTATE; /* We do it */
if( pModelData->fGeneral & MD_LANDSCAPE_RT90 )
pUDPDev->fMode |= PF_CCW_ROTATE;
}
pUDPDev->dwSelBits |= FDH_LANDSCAPE;
}
else
pUDPDev->dwSelBits |= FDH_PORTRAIT;
/* Remember the graphics resolution for when it is needed */
pUDPDev->ixgRes = gxdpi;
pUDPDev->iygRes = gydpi;
pUDPDev->iLookAhead = pModelData->sLookAhead / pRes->ptTextScale.y;
/* Set the styled line information for this printer */
if( gxdpi == gydpi )
{
/*
* Special case: resolution is the same in both directions. This
* is typically true for laser and inkjet printers.
*/
pGDIInfo->xStyleStep = 1;
pGDIInfo->yStyleStep = 1;
pGDIInfo->denStyleStep = gxdpi / 50; /* 50 elements per inch */
if( pGDIInfo->denStyleStep == 0 )
pGDIInfo->denStyleStep = 1;
}
else
{
/* Resolutions differ, so figure out lowest common multiple */
int igcd;
igcd = iGCD( gxdpi, gydpi );
pGDIInfo->xStyleStep = gydpi / igcd;
pGDIInfo->yStyleStep = gxdpi / igcd;
pGDIInfo->denStyleStep = pGDIInfo->xStyleStep * pGDIInfo->yStyleStep / 2;
}
/*
* If the printer can rotate fonts, then we don't care about
* the orientation of fonts. Hence, set both selection bits.
*/
if( pModelData->fGeneral & MD_ROTATE_FONT_ABLE )
pUDPDev->dwSelBits |= FDH_PORTRAIT | FDH_LANDSCAPE;
/*
* Presume we can always print bitmap fonts, so now add that
* capability.
*/
pUDPDev->dwSelBits |= FDH_BITMAP;
/* Paper size and printable area */
if( !bGetPaperFormat( &pUDPDev->pfPaper, pedm, pdh ) )
{
#if DBG
DbgPrint( "Rasdd!udInit: Invalid paper format data\n" );
#endif
SetLastError( ERROR_INVALID_CHARACTERISATION_DATA );
HeapFree( pPDev->hheap, 0, (LPSTR)pUDPDev );
// derryd
HeapFree( pPDev->hheap, 0, (LPSTR)pMDev );
// end
pPDev->pUDPDev = 0; /* Stop others freeing it */
return FALSE;
}
/*
* Following data is the distance that the top left corner of the
* printable area is offset from the top left corner of the paper.
*/
pGDIInfo->ptlPhysOffset.x = pUDPDev->pfPaper.ptMargin.x >> pRes->ptScaleFac.x;
pGDIInfo->ptlPhysOffset.y = pUDPDev->pfPaper.ptMargin.y >> pRes->ptScaleFac.y;
/*
* Now calculate the printable area in units of 1 mm. There is
* 25.4 mm to the inch, a little rounding is used below. Note
* also that the pfPaper fields are rotated (if required) within
* bGetPaperFormat().
*/
pGDIInfo->ulHorzSize = (ULONG)-(LONG)MulDiv( pUDPDev->pfPaper.ptRes.x,
25400, xdpi );
pGDIInfo->ulVertSize = (ULONG)-(LONG)MulDiv( pUDPDev->pfPaper.ptRes.y,
25400, ydpi );
pGDIInfo->ulHorzRes = pUDPDev->pfPaper.ptRes.x >> pRes->ptScaleFac.x;
pGDIInfo->ulVertRes = pUDPDev->pfPaper.ptRes.y >> pRes->ptScaleFac.y;
pGDIInfo->ulLogPixelsX = gxdpi;
pGDIInfo->ulLogPixelsY = gydpi;
pGDIInfo->szlPhysSize.cx = pUDPDev->pfPaper.ptPhys.x >> pRes->ptScaleFac.x;
pGDIInfo->szlPhysSize.cy = pUDPDev->pfPaper.ptPhys.y >> pRes->ptScaleFac.y;
pGDIInfo->flRaster = 0;
#if PRINT_INFO
DbgPrint("Value of pRes->ptTextScale.x is %d \n", pRes->ptTextScale.x);
DbgPrint("Value of pRes->ptTextScale.y is %d \n", pRes->ptTextScale.y);
DbgPrint("Value of pRes->ptScaleFac.x is %d \n", pRes->ptScaleFac.x);
DbgPrint("Value of pRes->ptScaleFac.y is %d \n", pRes->ptScaleFac.y);
DbgPrint("Value of pGDIInfo->ulLogPixelsX is %d\n",pGDIInfo->ulLogPixelsX);
DbgPrint("Value of pGDIInfo->ulLogPixelsY is %d\n",pGDIInfo->ulLogPixelsY);
DbgPrint( "Resolution (DPI): " );
if( pedm->dm.dmOrientation == DMORIENT_LANDSCAPE )
DbgPrint( "Master (%ld, %ld), ", pdh->ptMaster.y, pdh->ptMaster.x );
else
DbgPrint( "Master (%ld, %ld), ", pdh->ptMaster.x, pdh->ptMaster.y );
DbgPrint( "Text (%ld, %ld), Graphics (%ld, %ld)\n",
xdpi, ydpi, gxdpi, gydpi );
DbgPrint( "%d actual pins, %d logical pins\n",
pRes->sPinsPerPass, pRes->sNPins );
#endif
/*
* The following are for Win 3.1 compatability. The X and Y values
* are reversed.
*/
pGDIInfo->ulAspectX = ydpi;
pGDIInfo->ulAspectY = xdpi;
pGDIInfo->ulAspectXY = hypot( xdpi, ydpi );
/* Text capability is orientation sensitive */
fText = (pedm->dm.dmOrientation == DMORIENT_LANDSCAPE) ?
pModelData->fLText: pModelData->fText;
if( pRes->ptScaleFac.x != 0 || pRes->ptScaleFac.y != 0 )
fText &= ~TC_RA_ABLE;
pUDPDev->fText = fText;
/*
* Initialise the GDIINFO structure.
*/
pGDIInfo->ulVersion = 0x100; /* SHOULD BE DEFINED SOMEWHERE */
if(pUDPDev->pdh->fTechnology != GPC_TECH_TTY)
pGDIInfo->ulTechnology = DT_RASPRINTER;
else
pGDIInfo->ulTechnology = DT_CHARSTREAM;
/*
* Fill in the UDPDev fields too, now that we have the data.
*/
pUDPDev->iOrient = pedm->dm.dmOrientation;
/*
* Set a local copy of the clip region. This is just the size of
* the printable area.
*/
pUDPDev->szlPage.cx = pUDPDev->pfPaper.ptRes.x >> pRes->ptScaleFac.x;
pUDPDev->szlPage.cy = pUDPDev->pfPaper.ptRes.y >> pRes->ptScaleFac.y;
pUDPDev->fMDGeneral = pModelData->fGeneral;
/* retain the model id (might be used for enumerating resources). */
pUDPDev->iModel = pedm->dx.rgindex[ HE_MODELDATA ];
/* Miscellaneous stuff that is useful elsewhere */
pUDPDev->sCopies = pedm->dm.dmCopies;
pUDPDev->sDuplex = pedm->dm.dmDuplex;
/* sandram */
pUDPDev->sColor = pedm->dm.dmColor;
pUDPDev->Resolution = *pRes;
/* scale 'sTextYOffset' which is used to align graphics and text. */
pUDPDev->Resolution.sTextYOffset /= pRes->ptTextScale.y;
/* get the currently selected brush type, Not used */
pUDPDev->Resolution.iDitherBrush = pedm->dx.dmBrush;
/*
* Record the memory available, and also available for use.
*/
//GP:02/09/94 for DWORD Alignment problem on mips and alpha
#define DWFETCH(PDW) ((DWORD)((((WORD *)(PDW))[1] << 16) | ((WORD *)(PDW))[0]))
//For GPC2 minidrivers values are actually WORD aligned
pdw = (DWORD *)((BYTE *)pdh + pdh->loHeap +
pModelData->rgoi[ MD_OI_MEMCONFIG ] );
/*
* The memory data is stored in pairs; the first is the amount to
* show the user when setting up the printer, the second is the
* amount of usable memory after the printer takes its share.
* Note that the data is in units of kb, so turn that into
* bytes. AND ALSO PRESUME THAT ALL OF THE AVAILABLE MEMORY
* IS USABLE. THIS MAY NEED REVISION.
*
* need to make sure the dwords are always accessed as words since they
* are not guaranteed to be DWORD aligned and will cause an a/v on MIPS.
*/
if (fGpcVersion2)
{
//Check if there is a valid memory configuration (Null Terminated)
if ( *((WORD*)pdw) )
{
pUDPDev->dwMem = *((WORD *)pdw + 2 * pedm->dx.dmMemory + 1) * 1024;
pUDPDev->dwTotalMem = *((WORD *)pdw + 2 * pedm->dx.dmMemory ) * 1024;
}
//No Memory config so set the memory to Minimum
else
{
pUDPDev->dwMem = pUDPDev->dwTotalMem = MIN_MEMORY;
}
}
else
{
if ( DWFETCH(pdw) )
{
pUDPDev->dwMem = DWFETCH(pdw + 2 * pedm->dx.dmMemory + 1) * 1024;
pUDPDev->dwTotalMem = DWFETCH(pdw + 2 * pedm->dx.dmMemory ) * 1024;
}
//No Memory config so set the memory to Minimum
else
{
pUDPDev->dwMem = pUDPDev->dwTotalMem = MIN_MEMORY;
}
}
#if PRINT_INFO
DbgPrint("rasdd!udInit:value of pUDPDev->dwMem is %d \n",pUDPDev->dwMem);
DbgPrint("rasdd!udInit:value of pUDPDev->dwTotalMem is %d \n",pUDPDev->dwTotalMem);
DbgPrint("rasdd!udInit:value of pedm->dx.dmMemory is %d \n",pedm->dx.dmMemory);
DbgPrint("rasdd!udInit:value of fGpcVersion2 is %d \n",fGpcVersion2);
DbgPrint("rasdd!udInit:value of pdw is %d \n",fGpcVersion2?( *((WORD*)pdw) ):DWFETCH(pdw) );
if ( pUDPDev->dwMem != MIN_MEMORY )
{
DbgPrint("rasdd!udInit:value of pUDPDev->dwMem in Megb is %d \n",(pUDPDev->dwMem/1024));
DbgPrint("rasdd!udInit:value of pUDPDev->dwTotalMem in Megb is %d \n",(pUDPDev->dwTotalMem / 1024));
}
#endif
if( (pedm->dx.sFlags & DXF_PAGEPROT) &&
(pModelData->fGeneral & MD_PCL_PAGEPROTECT) )
{
/*
* Page protection is enabled, so reduce the amount of memory
* available by the size of the page.
*/
DWORD dwPageMem;
if (!fGpcVersion2)
{
PAPERSIZE *pSize;
pSize = GetTableInfo( pdh, HE_PAPERSIZE, pedm );
dwPageMem = (DWORD)pSize->wPageProtMem * 1024;
if( dwPageMem < pUDPDev->dwMem )
{
pUDPDev->fMode |= PF_PAGEPROTECT;
pUDPDev->dwMem -= dwPageMem;
}
}
else
{
//Not valid for Colour page printers !!
dwPageMem = (pGDIInfo->szlPhysSize.cx + 32) *
pGDIInfo->szlPhysSize.cy / BBITS;
if( dwPageMem < pUDPDev->dwMem )
pUDPDev->dwMem -= dwPageMem; /* Size of page memory */
}
}
if( (pedm->dx.sFlags & DXF_NOEMFSPOOL) )
pUDPDev->fMode |= PF_NOEMFSPOOL;
if( !(pModelData->fGeneral & MD_FONT_MEMCFG) )
pUDPDev->dwFontMem = pUDPDev->dwMem / 2;
else
pUDPDev->dwFontMemUsed = 0; /* No DL font memory used */
/*
* Initialise the font data. There may be a considerable amount
* of work involved here, since it requires rummaging through
* the minidriver's resources and examing printer modes etc.
*/
BuildFontMapTable( pPDev, pdh, pedm );
if( !bBuildCommandTable( pUDPDev, pdh, pedm ) )
{
HeapFree( pPDev->hheap, 0, (LPSTR)pUDPDev );
// derryd
HeapFree( pPDev->hheap, 0, (LPSTR)pMDev );
// end
pPDev->pUDPDev = 0; /* Stop others freeing it */
return FALSE;
}
/*
* The bBuildCommandTable() function initialises the colour information,
* CORRECTLY considering the printer's capabilities and whether the user
* wishes to print in colour (according to the DEVMODE information).
* Now set GDIINFO to contain the same information.
*/
// For color devvices with more that one palne, we still have to report
// in GDIInfo structure as a 1 plane 4 bit per pixel pallete devices, as
// rasdd creates the surface as 4BPP 1 plane, beecause GDI doesn't support
// multi plane surfaces. We return ulnumColors as 16; the palette indexes
//from 8 to 15 are duplicated.
if( (pUDPDev->Resolution.fDump & RES_DM_COLOR) &&
(pUDPDev->sDevPlanes > 1) )
{
pGDIInfo->cBitsPixel = 4;
pGDIInfo->cPlanes = 1;
}
// monochrome or a Palette device
else
{
pGDIInfo->cBitsPixel = pUDPDev->sBitsPixel;
pGDIInfo->cPlanes = pUDPDev->sDevPlanes;
}
pGDIInfo->ulNumColors = 1 << (pGDIInfo->cBitsPixel + pGDIInfo->cPlanes - 1);
/* Now also have valid fText flags */
pGDIInfo->flTextCaps = pUDPDev->fText;
/*
* Set up the default HALFTONE and colour calibration data.
*/
vSetHTData( pPDev, pGDIInfo );
/*
* Copy the COLORADJUSTMENT structure from the input EXTDEVMODE to
* the UD_PDEV, as it is required during DrvStretchBlt() if the
* application did not provide one.
*/
pUDPDev->ca = pedm->dx.ca;
/*
* Check if a seperate text band should be enumerated.
* There are 2 possibilities:
* - when the scale factor is not zero, no matter what's the
* current orientation; or:
* - the scale factor is zero but the printer cannot output
* graphics in the orientation of the logical page (i.e.
* requiring the driver to rotate the bitmap when printing
* in the landscape mode).
* Implication:
* If the printer:
* (1) has MD_SERIAL bit set; and
* (2) cannot rotate bitmaps in the landscape mode,
* then, it cannot have hardware fonts in the landscape mode
* because text in hardware fonts has to be enumerated in a
* seperate text band and saved in TOS structures (one list
* for the whole page). These strings may cross banding
* boundaries.
* We don't expect this case will ever occur.
*/
if( pRes->ptScaleFac.x != 0 || pRes->ptScaleFac.y != 0 ||
( (pUDPDev->iOrient == DMORIENT_LANDSCAPE) &&
(pUDPDev->fMDGeneral & MD_LANDSCAPE_GRX_ABLE) ) )
{
pUDPDev->fMode |= PF_SEPARATE_TEXT;
}
else
pUDPDev->fMode &= ~PF_SEPARATE_TEXT;
InitOutputCtl( pUDPDev, pedm );
// derryd - initialise the struct. passed to minidriver callback routine
if ( pRes->fBlockOut & RES_BO_OEMGRXFILTER )
{
HANDLE hModule;
//Get a handle for loading minidrivers for callbacks.
if (!( pPDev->hImageMod = EngLoadImage(pPDev->pstrDataFile)) )
{
RIP("Rasdd!udInit:EngLoadImage Failed\n");
HeapFree( pPDev->hheap, 0, (LPSTR)pUDPDev );
HeapFree( pPDev->hheap, 0, (LPSTR)pMDev );
pPDev->pUDPDev = 0; /* Stop others freeing it */
return FALSE;
}
hModule = pPDev->hImageMod;
// Minidriver is Non-US - We should Fail.
if ( EngFindImageProcAddress( hModule, "bInitFEProc" ) )
{
HeapFree( pPDev->hheap, 0, (LPSTR)pUDPDev );
HeapFree( pPDev->hheap, 0, (LPSTR)pMDev );
pPDev->pUDPDev = 0; /* Stop others freeing it */
return FALSE;
}
if ( pUDPDev->Resolution.sNPins == -1 )
{
if (!(pRes->fDump & RES_DM_GDI)) // Works only for GDI style graphics
{
HeapFree( pPDev->hheap, 0, (LPSTR)pUDPDev );
HeapFree( pPDev->hheap, 0, (LPSTR)pMDev );
pPDev->pUDPDev = 0; /* Stop others freeing it */
return FALSE;
}
// Full band sent to minidrver BlockOut
pUDPDev->fMode |= PF_BLOCK_IS_BAND;
pUDPDev->fMode &= ~PF_ROTATE; // Minidriver needs to do rotation
pUDPDev->Resolution.sNPins = 1;// Reset to meaningful value, man
}
InitMDev ( pUDPDev, pedm );
if(pUDPDev->pdh->fTechnology == GPC_TECH_TTY)
pUDPDev->fMode &= ~PF_ROTATE; //Rotation Not allowed.
}
// end
return TRUE;
}
/************************* Function Header ***********************************
* Function: InitOutputCtl
*
* Action: Initializes output control structure, which becomes part of
* pUDPDev, physical device structure
*
* History: 5/21/90 Scale to current resolution
*****************************************************************************/
void
InitOutputCtl(pUDPDev, pedm )
UD_PDEV *pUDPDev;
PEDM pedm; /* Printer specific data */
{
if (pedm->dx.rgindex[HE_COLOR] < 0)
{
/* the printer is B/W. */
/* bypass sending any CMD_GRX_COLOR sequence for B/W models. */
pUDPDev->ctl.sColor = 0;
pUDPDev->ctl.ulTextColor = 0;
}
else
{
/* force sending one CMD_GRX_COLOR sequence before any output. */
pUDPDev->ctl.sColor = -1;
pUDPDev->ctl.ulTextColor = 0xffffffff;
}
/* initialize the id of last font used. */
pUDPDev->ctl.iFont = 0x7fffffff;
pUDPDev->ctl.sBytesPerPinPass = (SHORT)((pUDPDev->Resolution.sPinsPerPass + 7) >> 3);
return;
}
/************************* Function Header ***********************************
* Function: InitMDev
*
* Action: Initializes Minidriver callback function
*
* History: created 15.08.1995 by DerryD for WDL release
*
*****************************************************************************/
void
InitMDev (pUDPDev , pEDM)
UD_PDEV *pUDPDev;
PEDM pEDM;
{
MDEV *pMDev;
pMDev = pUDPDev->pMDev;
// so lets now set up MDEV
pMDev->pMemBuf = NULL;
pMDev->iMemReq = 0;
pMDev->iOrient = pUDPDev->iOrient;
pMDev->sDevPlanes = pUDPDev->sDevPlanes;
pMDev->sBitsPixel = pUDPDev->sBitsPixel;
pMDev->iyPrtLine = 0;
pMDev->szlPage = pUDPDev->szlPage;
pMDev->igRes.x = pUDPDev->ixgRes;
pMDev->igRes.y = pUDPDev->iygRes;
pMDev->iModel = pUDPDev->iModel;
pMDev->sImageControl = pEDM->dx.rgindex[ HE_IMAGECONTROL ]; ;
pMDev->sTextQuality = pEDM->dx.rgindex[ HE_TEXTQUAL ]; ;
pMDev->sPaperQuality = pEDM->dx.rgindex[ HE_PAPERQUALITY ];
pMDev->sPrintDensity = pEDM->dx.rgindex[ HE_PRINTDENSITY ];
pMDev->sColor = pEDM->dx.rgindex[ HE_COLOR ];
#if 0
// dead fields.
pMDev->fGeneral = 0;
pMDev->fMGeneral = 0;
pMDev->fColorFormat = pUDPDev->fColorFormat;
pMDev->iLookAhead = pUDPDev->iLookAhead;
pMDev->pfPaper = pUDPDev->pfPaper;
pMDev->szlBand = pUDPDev->szlBand;
pMDev->iCompMode = pUDPDev->iCompMode;
#endif
return;
}
/*************************** Function Header *********************************
* bGetPaperFormat
* Fill PAPERFORMAT structure with the physical page size,
* printable page size, translate from master units to device
* units. Calculates number of bands and band dimemnsions.
*
* RETURNS:
* TRUE/FALSE - FALSE usually means GPC data is incorrect.
*
* HISTORY:
* 15:19 on Wed 22 May 1991 -by- Lindsay Harris [lindsayh]
* Updated to current Unidrv code (more or less)
*
* 15:44 on Wed 01 May 1991 -by- Lindsay Harris [lindsayh]
* Added sanity checks, deleted unused variables
*
*****************************************************************************/
BOOL
bGetPaperFormat( pPF, pedm, pdh )
PAPERFORMAT *pPF; /* Paper format structure */
PEDM pedm;
PDH pdh;
{
short xscale, yscale;
PAPERSIZE *pSize;
RESOLUTION *pRes;
RECT rcMargins;
MODELDATA *pModDat;
pSize = GetTableInfo( pdh, HE_PAPERSIZE, pedm );
pRes = GetTableInfo( pdh, HE_RESOLUTION, pedm );
pModDat = GetTableInfo( pdh, HE_MODELDATA, pedm );
if( pSize == 0 || pRes == 0 || pModDat == 0 )
return FALSE;
/* Get physical paper size */
if (pSize->sPaperSizeID == DMPAPER_USER)
{
pPF->ptPhys.x = MetricToMaster(pedm->dm.dmPaperWidth, pdh->ptMaster.x);
pPF->ptPhys.y = MetricToMaster(pedm->dm.dmPaperLength, pdh->ptMaster.y);
}
else
{
pPF->ptPhys.x = pSize->ptSize.x;
pPF->ptPhys.y = pSize->ptSize.y;
}
if( !bGetMinPaperMargins( pdh, pedm, &rcMargins ) )
return FALSE;
pPF->ptRes.x = pPF->ptPhys.x - rcMargins.left - rcMargins.right;
pPF->ptRes.y = pPF->ptPhys.y - rcMargins.top - rcMargins.bottom;
/* translate to device units. */
xscale = pRes->ptTextScale.x;
yscale = pRes->ptTextScale.y;
/*
* Check if need to rotate paper dimensions. Some paper sizes
* (e.x. envelopes on some printers) require the exchange of
* the X/Y dimensions.
*/
if( pSize->fGeneral & PS_ROTATE )
{
/*
* Rotate the paper dimensions. The documentation says
* something about when paper needs to be fed in with the
* reverse orientation (e.g. envelopes). However, the
* margins must not be reversed! I don't understand the
* logic behind reversing the paper dimensions without
* changin margins.
*/
long lTmp; /* For the switch */
lTmp = pPF->ptPhys.x;
pPF->ptPhys.x = pPF->ptPhys.y;
pPF->ptPhys.y = lTmp;
lTmp = pPF->ptRes.x;
pPF->ptRes.x = pPF->ptRes.y;
pPF->ptRes.y = lTmp;
}
if( pedm->dm.dmOrientation == DMORIENT_LANDSCAPE )
{
/*
* Landscape, so switch the paper dimensions. Also the
* margins are calculated, and this is messy because there
* are two directions of rotation, and the margins will be
* different, depending upon the direction.
*/
long lTmp;
/* Swap the paper sizes */
lTmp = pPF->ptPhys.x;
pPF->ptPhys.x = pPF->ptPhys.y;
pPF->ptPhys.y = lTmp;
lTmp = pPF->ptRes.x;
pPF->ptRes.x = pPF->ptRes.y;
pPF->ptRes.y = lTmp;
/* Scaling factor is hardware dependent, so swap it too! */
lTmp = xscale;
xscale = yscale;
yscale = (short)lTmp;
/* Swap the margins too! */
if( pModDat->fGeneral & MD_LANDSCAPE_RT90 )
{
/* Typified by the LaserJet family */
pPF->ptMargin.x = rcMargins.bottom;
pPF->ptMargin.y = rcMargins.left;
}
else
{
pPF->ptMargin.x = rcMargins.top;
pPF->ptMargin.y = rcMargins.right;
}
}
else
{
/* Portrait, so margins are as determined. */
pPF->ptMargin.x = rcMargins.left;
pPF->ptMargin.y = rcMargins.top;
}
/*
* set the offset of the printable origin relative to cursor (0,0)
* (in MASTER units)
*/
#if 0
This code has been disabled, as it causes problems with LaserJet printers,
other than the Series II. The problem is that everything is shifted
right, typically by 7 pels. This pushes things into either the unprintable
or unaddressable regions of the page, and so they may or may not print.
if( pModDat->fGeneral & MD_USE_CURSOR_ORIG )
{
/* Origin relative to paper origin is important */
if( pedm->dm.dmOrientation == DMORIENT_LANDSCAPE )
{
/*
* 3 cases:
* (1) the coordinate system doesn't change but the graphics should
* be rotated 270 degrees (e.g. dot-matrix printers)
* (2) both the coordinate system and the graphics should be
* rotated 90 degrees counter-clockwise (e.g. LaserJets)
* (3) rotate 270 AND the printer can rotate landscape
* graphics itself.
*
*/
if( pModDat->fGeneral & (MD_LANDSCAPE_GRX_ABLE | MD_LANDSCAPE_RT90))
{
/*
* Typified by the LaserJet family. This corresponds to
* cases (2) and (3) above, although the above scheme
* does not map to any reality that I know. We come here
* when there is a 90 degree clockwise rotation (e.g.
* LaserJet Series II), or the printer can do the
* rotation (e.g. LaserJet III).
*/
pPF->ptPrintOrig.x = pPF->ptMargin.x - pSize->ptLCursorOrig.x;
pPF->ptPrintOrig.y = pPF->ptMargin.y - pSize->ptLCursorOrig.y;
}
else
{
/* Dot matrix style */
pPF->ptPrintOrig.x = rcMargins.left - pSize->ptLCursorOrig.x;
pPF->ptPrintOrig.y = rcMargins.top - pSize->ptLCursorOrig.y;
}
}
else
{
/* Portrait mode. */
pPF->ptPrintOrig.x = pPF->ptMargin.x - pSize->ptCursorOrig.x;
pPF->ptPrintOrig.y = pPF->ptMargin.y - pSize->ptCursorOrig.y;
}
}
else
#endif
{
/* Print origin corresponds with the cursor origin. */
pPF->ptPrintOrig.x = 0;
pPF->ptPrintOrig.y = 0;
}
/*
* Scale the results for the text resolution. Note that the
* scale factors have also been rotated, if that is required.
*/
pPF->ptPhys.x /= xscale;
pPF->ptPhys.y /= yscale;
pPF->ptRes.x /= xscale;
pPF->ptRes.y /= yscale;
pPF->ptMargin.x /= xscale;
pPF->ptMargin.y /= yscale;
/* Note that ptPrintOrig is left in master units */
#if PRINT_INFO
DbgPrint( "Paper size (Text units): (%ld, %ld)\n",
pPF->ptPhys.x, pPF->ptPhys.y );
DbgPrint( "Printable area (Text units): (%ld, %ld)\n",
pPF->ptRes.x, pPF->ptRes.y );
#endif
return TRUE; /* Must be OK if we got here! */
}
/************************** Function Header *********************************
* GetMinPaperMargins
* Compute the minimum paper margins, i.e. the non-printable
* region.
*
* RETURNS:
* TRUE/FALSE, FALSE being incorrect/invalid GPC data!
*
* HISTORY:
* 15:49 on Wed 01 May 1991 -by- Lindsay Harris [lindsayh]
* Sanity checks
*
****************************************************************************/
BOOL
bGetMinPaperMargins( pdh, pedm, prcMargins )
PDH pdh;
PEDM pedm;
RECT *prcMargins; /* Calculated margins in here */
{
PPAPERSOURCE pPaperSource;
PAPERSIZE *pPaperSize;
MODELDATA *pModelData;
int iWidth;
int iHorMargin, iLeftMargin;
BOOL fGpcVersion2;
fGpcVersion2 = pdh->wVersion < GPC_VERSION3;
pPaperSource = GetTableInfo( pdh, HE_PAPERSOURCE, pedm );
pPaperSize = GetTableInfo( pdh , HE_PAPERSIZE, pedm );
pModelData = GetTableInfo( pdh, HE_MODELDATA, pedm );
/*
* Verify the values we have - both that an address is returned,
* and that they point at an appropriate sized structure. Note that
* MODELDATA is not verified, as it presumed to have been done
* before reaching here.
*/
if( pPaperSize == 0 || pModelData == 0 )
{
SetLastError( ERROR_INVALID_CHARACTERISATION_DATA );
#if PRINT_INFO
DbgPrint( " pPaperSize = 0x%lx, cbSize = %d, Index = %d\n",
pPaperSize,
pPaperSize ? pPaperSize->cbSize : 0,
pedm->dx.rgindex[ HE_PAPERSIZE ] );
#endif
return FALSE;
}
/*
* The top (and bottom) margin is the larger of the margin of
* the printer and margin of the form/paper. Assume that the margins
* of those of the paper, and change it to the printer's value if
* these should happen to be larger.
*/
if( pedm->dm.dmOrientation == DMORIENT_LANDSCAPE && !fGpcVersion2 )
{
prcMargins->top = pPaperSize->rcLMargins.top;
prcMargins->left = pPaperSize->rcLMargins.left;
prcMargins->bottom = pPaperSize->rcLMargins.bottom;
prcMargins->right = pPaperSize->rcLMargins.right;
}
else
{
prcMargins->top = pPaperSize->rcMargins.top;
prcMargins->left = pPaperSize->rcMargins.left;
prcMargins->bottom = pPaperSize->rcMargins.bottom;
prcMargins->right = pPaperSize->rcMargins.right;
}
if( pPaperSource != 0 )
{
/*
* PaperSource data is available, so check if this is more
* limiting than the paper size limits.
*/
if( pPaperSource->sTopMargin > (short)prcMargins->top )
prcMargins->top = pPaperSource->sTopMargin;
if( pPaperSource->sBottomMargin > (short)prcMargins->bottom )
prcMargins->bottom = pPaperSource->sBottomMargin;
}
iWidth = pPaperSize->ptSize.x;
if( pPaperSize->sPaperSizeID == DMPAPER_USER )
{
/* User defined form size, so convert width to pels */
iWidth = (short)MetricToMaster(pedm->dm.dmPaperWidth, pdh->ptMaster.x);
}
if( (iHorMargin = iWidth - pModelData->ptMax.x) < 0 )
iHorMargin = 0;
/*
* Determine the horizontal margins. If they are centered, then the
* Left margin is simply the overall divided in two. But, we need to
* consider both the printer's and form's margins, and choose the largest.
*/
if( pPaperSize->fGeneral & PS_CENTER )
iLeftMargin = (short)(iHorMargin / 2);
else
iLeftMargin = 0;
if( pModelData->sLeftMargin > (short)prcMargins->left )
prcMargins->left = pModelData->sLeftMargin;
if( iLeftMargin > prcMargins->left )
prcMargins->left = iLeftMargin;
if( iHorMargin - prcMargins->left > prcMargins->right )
prcMargins->right = iHorMargin - prcMargins->left;
/* Check that none of the margins are negative */
if( prcMargins->top < 0 )
prcMargins->top = 0;
if( prcMargins->bottom < 0 )
prcMargins->bottom = 0;
if( prcMargins->left < 0 )
prcMargins->left = 0;
if( prcMargins->right < 0 )
prcMargins->right = 0;
return TRUE;
}
/******************************** Function Header ****************************
* bCanCompress
* Determine whether the printer supports compression. Compression
* modes supported are TIFF V4, and vanilla Run Length Encoding (RLE).
* TIFF is preferred over RLE, but RLE is better than none - mostly!
*
* RETURNS:
* TRUE/FALSE, depending upon whether compression is supported
*
* HISTORY:
* 14:45 on Tue 30 Jun 1992 -by- Lindsay Harris [lindsayh]
* Generalise to include RLE too.
*
* 16:32 on Wed 01 May 1991 -by- Lindsay Harris [lindsayh]
* Add verification of GPC data.
*
*****************************************************************************/
BOOL
bCanCompress( pdh, pedm )
PDH pdh; /* Access to all things */
PEDM pedm; /* Fill in the compression mode field, if found */
{
MODELDATA *pModelData;
COMPRESSMODE *pCompressMode;
short oi;
short *pIndex;
BOOL bGotOne;
pModelData = GetTableInfo( pdh, HE_MODELDATA, pedm );
oi = pModelData->rgoi[ MD_OI_COMPRESSION ];
pIndex = (short *)((BYTE *)pdh + pdh->loHeap + oi);
/*
* Loop through the available compression mode data for this printer.
* Remember the TIFF and RLE entries if found.
*/
for( bGotOne = FALSE; *pIndex != 0; pIndex++ )
{
pCompressMode = GetTableInfoIndex( pdh, HE_COMPRESSION, *pIndex - 1 );
if( pCompressMode)
{
switch( pCompressMode->iMode )
{
case CMP_ID_TIFF40: /* All done if here */
pedm->dx.rgindex[ HE_COMPRESSION ] = (short)(*pIndex - 1);
return TRUE;
case CMP_ID_RLE: /* Fine as a backup */
pedm->dx.rgindex[ HE_COMPRESSION ] = (short)(*pIndex - 1);
bGotOne = TRUE;
break;
}
}
}
return bGotOne;
}
/************************ Function Header **********************************
* bBuildCommandTable
* Construct the internal command table from various structures,
* such as PAGECONTROL, CURSORMOVE, FONTSIMULATION, DEVCOLOR, etc..
* Also, retain the order of sending BEGIN_DOC escape sequences
* and other relevant information as well.
* Check for compression support as well.
*
* RETURNS:
* TRUE/FALSE, FALSE if vital data is inconsisten or missing.
*
* HISTORY:
* 16:38 on Wed 01 May 1991 -by- Lindsay Harris [lindsayh]
* Sanity checks on data.
*
* Created: 09/07/90 ZhanW
****************************************************************************/
BOOL
bBuildCommandTable( pUDPDev, pdh, pedm )
UD_PDEV *pUDPDev;
PDH pdh;
PEDM pedm;
{
RESOLUTION *pRes;
COMPRESSMODE *pCompressMode;
PAGECONTROL *pPageControl;
CURSORMOVE *pCursorMove;
FONTSIMULATION *pFontSim;
DEVCOLOR *pDevColor;
RECTFILL *pRectFill;
PAPERSIZE *pSize;
PAPERSOURCE *pSource;
PAPERDEST *pDest;
PTEXTQUALITY pTextQuality;
PAPERQUALITY *pPaperQuality;
// added by Derry Durand [derryd] for WDL release - July 1995
PRINTDENSITY *pPrintDensity;
IMAGECONTROL *pImageControl;
// end
PDOWNLOADINFO pDLI;
MODELDATA *pModelData;
BYTE *pbHeap; /* For colour capability checking */
BOOL fGpcVersion2;
BOOL fLowMemLaser3 = FALSE;
BOOL isColorLaserJet = FALSE;
fGpcVersion2 = pdh->wVersion < GPC_VERSION3;
/*
* Nothing too hard - just work through the various structures in
* the GPC data, and fill in the table data in the UD_PDEV structure.
*/
pRes = GetTableInfo( pdh, HE_RESOLUTION, pedm );
if( pRes)
{
vSetCDAddr( pUDPDev, CMD_RES_FIRST, pRes->rgocd, RES_OCD_MAX );
}
pPaperQuality = GetTableInfo( pdh, HE_PAPERQUALITY, pedm );
if( pPaperQuality )
{
vSetCDAddr( pUDPDev, CMD_PAPERQUALITY, &pPaperQuality->ocdSelect, 1 );
}
// Added by Derry Durand [derry] July 1995
if (!(pdh->wVersion < GPC_VERSION3 ))
{
pPrintDensity = GetTableInfo( pdh, HE_PRINTDENSITY, pedm );
if( pPrintDensity )
vSetCDAddr( pUDPDev, CMD_PRINTDENSITY, &pPrintDensity->ocdSelect, 1 );
pImageControl = GetTableInfo( pdh, HE_IMAGECONTROL, pedm );
if( pImageControl )
vSetCDAddr( pUDPDev, CMD_IMAGECONTROL, &pImageControl->ocdSelect, 1 );
} // check for GPC version no.
// end
/*
* Check if this printer can support any of the compression modes
* that we know about. If so, we have some additional setting up.
*/
//Check for LaserJet Series III with 1 MB of memory,No Compression
fLowMemLaser3 = ( (pUDPDev->dwMem / 1024) == 400 ) &&
( (pUDPDev->dwTotalMem / 1024) == 1024 ) ;
if( bCanCompress( pdh, pedm ) && !fLowMemLaser3)
{
/*
* pedm->rgindex[HE_COMPRESSION] has been set up in bCanCompress.
* bCanCompress returns FALSE for failure of the following
* call, so we can presume it is OK.
*/
pCompressMode = GetTableInfo( pdh, HE_COMPRESSION, pedm );
vSetCDAddr( pUDPDev, CMD_CMP_FIRST, pCompressMode->rgocd, CMP_OCD_MAX );
/*
* When TIFF compression is available, it is better to include
* enclosed white space - generally less data will be sent to
* the printer. So, do the disable now!
*/
pUDPDev->Resolution.fBlockOut &= ~RES_BO_ENCLOSED_BLNKS;
/* !!!LindsayH - consider also including leading white space */
/*
* Remember which compression method we are using!
*/
pUDPDev->iCompMode = pCompressMode->iMode;
}
else
pUDPDev->iCompMode = CMP_ID_FIRST - 1; /* Invalid value */
#if PRINT_INFO
DbgPrint("rasdd!bBuildCommandTable:value of fLowMemLaser3 is %d \n",fLowMemLaser3);
DbgPrint("rasdd!bBuildCommandTable:value of pUDPDev->iCompMode is %d \n",pUDPDev->iCompMode);
#endif
pPageControl = GetTableInfo( pdh, HE_PAGECONTROL, pedm );
if( pPageControl == 0 )
{
/*
* Fudge it - default to 1 copy and DEFAULT initialisation order.
*/
pUDPDev->sMaxCopies = 1;
pUDPDev->orgwStartDocCmdOrder = (OCD)NOT_USED;
}
else
{
/* Have data that is OK, so use it! */
pUDPDev->orgwStartDocCmdOrder = pPageControl->orgwOrder;
pUDPDev->sMaxCopies = pPageControl->sMaxCopyCount;
vSetCDAddr( pUDPDev, CMD_PC_FIRST, pPageControl->rgocd, PC_OCD_MAX );
}
pCursorMove = GetTableInfo( pdh, HE_CURSORMOVE, pedm );
if( pCursorMove == 0 )
{
SetLastError( ERROR_INVALID_CHARACTERISATION_DATA );
#if DBG
DbgPrint( "Rasdd!bBuildCmdTable: Invalid/missing CURSORMOVE in GPC\n" );
#endif
return FALSE;
}
pUDPDev->fXMove = pCursorMove->fXMove;
pUDPDev->fYMove = pCursorMove->fYMove;
vSetCDAddr( pUDPDev, CMD_CM_FIRST, pCursorMove->rgocd, CM_OCD_MAX );
/*
* Do some testing of the available move commands. The same test is
* applied to both X and Y directions, so this description applies
* to both. The Move command functions want to know whether there
* is a move command - they will use it if available, otherwise some
* other method is available.
* Also disable the leading and trailing null skipping operations
* if there is no move command - otherwise things end up in a rather
* messy state, and we will probably send more data to the printer
* than is needed.
*/
if( pUDPDev->apcdCmd[ CMD_CM_XM_ABS ] == NULL &&
pUDPDev->apcdCmd[ CMD_CM_XM_REL ] == NULL )
{
/* No X move command available, so flag it */
pUDPDev->fMode |= PF_NO_X_MOVE_CMD;
pUDPDev->Resolution.fBlockOut &=
~(RES_BO_LEADING_BLNKS | RES_BO_ENCLOSED_BLNKS);
}
/* Set MOVE available command flags, if appropriate */
if( pUDPDev->apcdCmd[ CMD_CM_YM_ABS ] == NULL &&
pUDPDev->apcdCmd[ CMD_CM_YM_REL ] == NULL )
{
/* No X move command available, so flag it */
pUDPDev->fMode |= PF_NO_Y_MOVE_CMD;
pUDPDev->Resolution.fBlockOut &=
~(RES_BO_LEADING_BLNKS | RES_BO_ENCLOSED_BLNKS);
}
/*
* The same is true of relative move commands. They are mostly used in
* text justification, and are especially important to compensate for
* the brain dead way that LaserJets rotate fonts.
*
* NOTE: IF WE DO NOT HAVE RELATIVE MOVE COMMANDS, TURN OF THE
* TC_CR_90 BIT IN fTextCaps. THE ROTATED TEXT CODE ASSUMES THIS
* FUNCTIONALITY IS AVAILABLE, SO DISABLE IT IF NOT THERE. This does
* not usually happen, as the only printers with the TC_CR_90
* bit set are LJ III and 4 models, which have the relative move
* commands available.
*/
if( pUDPDev->apcdCmd[ CMD_CM_XM_REL ] == NULL ||
pUDPDev->apcdCmd[ CMD_CM_XM_RELLEFT ] == NULL )
{
pUDPDev->fMode |= PF_NO_RELX_MOVE;
pUDPDev->fText &= ~TC_CR_90; /* Can't handle rotated text */
}
if( pUDPDev->apcdCmd[ CMD_CM_YM_REL ] == NULL ||
pUDPDev->apcdCmd[ CMD_CM_YM_RELUP ] == NULL )
{
pUDPDev->fMode |= PF_NO_RELY_MOVE;
pUDPDev->fText &= ~TC_CR_90; /* Can't handle rotated text */
}
//!!!ganeshp: Temporary solution for rotated text using device fonts.
//Disable this capability as rasdd can't handle rotated device fonts.
//This code will be removed once the device font rotation is fixed.
pUDPDev->fText &= ~TC_CR_90; /* Can't handle rotated text */
//!!!ganeshp: End of Device Font Rotation Hack
pFontSim = GetTableInfo(pdh, HE_FONTSIM, pedm);
if( pFontSim )
vSetCDAddr( pUDPDev, CMD_FS_FIRST, pFontSim->rgocd,
CMD_FS_LAST - CMD_FS_FIRST + 1 );
pDLI = GetTableInfo( pdh, HE_DOWNLOADINFO, pedm );
if( pDLI )
{
/* Printer can download fonts, so set up the data */
vSetCDAddr( pUDPDev, CMD_DLI_FIRST, pDLI->rgocd, DLI_OCD_MAX );
/* Start index */
pUDPDev->iFirstSFIndex = pUDPDev->iNextSFIndex = pDLI->wIDMin;
#if DBG
//OverFlow Conditin;Not good
if (pDLI->wIDMax < 0 )
{
DbgPrint( "Rasdd!bBuildCmdTable: Invalid/missing max font index in GPC(%d)\n",pDLI->wIDMax );
}
#endif
pUDPDev->iLastSFIndex = pDLI->wIDMax;
pUDPDev->fDLFormat = pDLI->fFormat; /* Controls what's sent */
/*
* There may also be a limit on the number of softfonts that the
* printer can support. If not, the limit is < 0, so when
* we see this, set the value to a large number.
*/
if( (pUDPDev->iMaxSoftFonts = pDLI->sMaxFontCount) < 0 )
pUDPDev->iMaxSoftFonts = pDLI->wIDMax + 100;
/*
* Consider enabling downloading of TT fonts. This is done only
* if text and graphics resolutions are the same - otherwise
* the TT fonts will come out smaller than expected, since they
* will be generated for the lower graphics resolution yet
* printed at the higher text resolution! LaserJet 4 printers
* can also download fonts digitised at 300dpi when operating
* at 600 dpi, so we also accept that as a valid mode.
*
* Also check if the user wants this: if the no cache flag
* is set in the driver extra part of the DEVMODE structure,
* then we also do not set this flag.
*/
#if PRINT_INFO
DbgPrint("rasdd!bBuildCommandTable:Value of pedm->dm.dmTTOption is %d\n",pedm->dm.dmTTOption);
#endif
if( ((pUDPDev->Resolution.ptScaleFac.x == 0 &&
pUDPDev->Resolution.ptScaleFac.y == 0) ||
((pUDPDev->fDLFormat & DLI_FMT_RES_SPECIFIED) &&
pUDPDev->ixgRes >= 300 && pUDPDev->iygRes >= 300) ) &&
(pDLI->cbBitmapFontDescriptor == sizeof( SF_HEADER ) ||
pDLI->cbBitmapFontDescriptor == sizeof( SF_HEADER20 )) &&
(!(pedm->dx.sFlags & DXF_TEXTASGRAPHICS )) )
{
/* Conditions have been met, so set the flag */
/* Check the application preference */
if (( pedm->dm.dmFields & DM_TTOPTION) &&
(pedm->dm.dmTTOption == DMTT_DOWNLOAD) )
{
pUDPDev->fMode |= PF_DLTT;
/* Find Out if Download TT as TT is available or not */
if ( (pUDPDev->fDLFormat & DLI_FMT_OUTLINE) &&
(pUDPDev->Resolution.fDump & RES_DM_DOWNLOAD_OUTLINE) )
pUDPDev->fMode |= PF_DLTT_ASTT_PREF;
#if PRINT_INFO
DbgPrint( "....Enabling download of GDI fonts\n" );
#endif
}
#if PRINT_INFO
else
DbgPrint( "....Disabling download of GDI fonts\n" );
#endif
}
#if PRINT_INFO
else
DbgPrint( "....Disabling download of GDI fonts\n" );
#endif
}
/*
* Check for a colour printer. This is not as easy as it sounds,
* since some of the data used may indicate a colour printer, when
* it is actually monochrome! The determination is done in the
* following if(). If it is decided that this is NOT a colour
* printer, turn of the RES_DM_COLOR bit in the Resolution.fDump
* field in the UDPDEV - this stops other parts of the driver
* from assuming colour.
*
* THIS TEST is based on information supplied from EricBi, on
* the UNIDRV team. It basically determines that there is colour
* information applicable to this printer, that this resolution
* of this printer supports colour, and that there is a specified
* DEVCOLOR structure to use. If ANY one of these is not true,
* presume a monochrome printer, or mode.
*/
pModelData = GetTableInfo( pdh, HE_MODELDATA, pedm );
pbHeap = (BYTE *)pdh + pdh->loHeap;
/*
* sandram - add for monochrome mode - still want to be a
* color printer even though dmColor is DMCOLOR_MONOCHROME
* Color LaserJet still needs the color info for printing
* in monochrome mode.
*
*/
pUDPDev->pDevColor = pDevColor = GetTableInfo( pdh, HE_COLOR, pedm );
if (pDevColor)
{
if (pedm->dm.dmColor == DMCOLOR_MONOCHROME)
if (ocdGetCommandOffset ( pUDPDev, CMD_DC_FIRST,
pDevColor->rgocd, DC_OCD_PC_MONOCHROMEMODE) == (OCD)NOOCD)
isColorLaserJet = FALSE;
else if ((pDevColor->sBitsPixel == 24 || pDevColor->sBitsPixel == 8) &&
(pDevColor->sPlanes == 1))
{
isColorLaserJet = TRUE;
}
else
{
isColorLaserJet = FALSE;
}
}
if(( pedm->dm.dmColor == DMCOLOR_COLOR || isColorLaserJet) &&
*((short *)(pbHeap + pModelData->rgoi[ MD_OI_COLOR ])) &&
(pUDPDev->Resolution.fDump & RES_DM_COLOR) &&
(pDevColor = GetTableInfo( pdh, HE_COLOR, pedm )))
{
/* Printer has colour capability - so set it up. */
/* process text colors first, and then graphics colors. */
vSetCDAddr( pUDPDev, CMD_DC_FIRST, pDevColor->rgocd, DC_NUM_OCDS_USED );
pUDPDev->fColorFormat = pDevColor->fGeneral;
/* !!!LindsayH - logic wrong for Seiko colour point - need planes AND pixels */
if( pDevColor->sPlanes > 1 )
{
/* Plane model */
pUDPDev->sDevPlanes = pDevColor->sPlanes;
pUDPDev->sBitsPixel = pDevColor->sBitsPixel;
vSetCDAddr( pUDPDev, CMD_DC_GC_FIRST,
(OCD *)((LPSTR)pdh + pdh->loHeap + pDevColor->orgocdPlanes),
pDevColor->sPlanes );
}
else
{
/* pixel model. This implementation is incomplete! --- haven't */
/* saved 'wBitsPerPixel', 'wFormat', and 'wModel'. */
/* !!!LindsayH - need to consider what to do about commands - CMD_DC_GC_FIRST */
pUDPDev->sBitsPixel = pDevColor->sBitsPixel;
pUDPDev->sDevPlanes = pDevColor->sPlanes;
/* sandram - add flags for Color LaserJet
* There are two modes for the printer - one is 8 bits per pixel
* This mode is used to print 1, 2, 4, and 8 bits per pixel bitmaps.
* the second mode is 24 bit color mode and can print 16 and 24 bit
* bitmaps. Colors are sent direct by pixel to the printer.
*/
if ((pUDPDev->sBitsPixel == 8) && (pUDPDev->sDevPlanes == 1))
pUDPDev->fMode |= PF_8BPP;
else if ((pUDPDev->sBitsPixel == 24) && (pUDPDev->sDevPlanes == 1))
pUDPDev->fMode |= PF_24BPP;
vSetCDAddr( pUDPDev, CMD_DC_GC_FIRST,
(OCD *)((LPSTR)pdh + pdh->loHeap + pDevColor->orgocdPlanes),
pDevColor->sPlanes );
}
// DWORD "msb 3sb 2sb lsb" is stored in memory as
// "lsb 2sb 3sb msb", so when referenced as a byte array
// the following makes sense:
//
if (!fGpcVersion2)
*((DWORD UNALIGNED *)(pUDPDev->rgbOrder)) =
*((DWORD UNALIGNED *)(pDevColor->rgbOrder));
else if (pDevColor->fGeneral & DC_EXTRACT_BLK)
*((DWORD UNALIGNED *)(pUDPDev->rgbOrder)) =
(DWORD)DC_PLANE_BLACK |
(DWORD)DC_PLANE_CYAN << 8 |
(DWORD)DC_PLANE_MAGENTA << 16 |
(DWORD)DC_PLANE_YELLOW << 24 ;
else if (pDevColor->fGeneral & DC_PRIMARY_RGB)
*((DWORD UNALIGNED *)(pUDPDev->rgbOrder)) =
(DWORD)DC_PLANE_RED |
(DWORD)DC_PLANE_GREEN << 8 |
(DWORD)DC_PLANE_BLUE << 16 |
(DWORD)DC_PLANE_NONE << 24 ;
else
*((DWORD UNALIGNED *)(pUDPDev->rgbOrder)) =
(DWORD)DC_PLANE_CYAN |
(DWORD)DC_PLANE_MAGENTA << 8 |
(DWORD)DC_PLANE_YELLOW << 16 |
(DWORD)DC_PLANE_NONE << 24 ;
/* !!! Seiko HACK */
if( pUDPDev->fMode & PF_SEIKO )
{
pUDPDev->sBitsPixel = 8;
pUDPDev->sDevPlanes = 1;
/* Add all the new mode bits - will be required enventually! */
pUDPDev->fColorFormat |= DC_SEND_ALL_PLANES | DC_SEND_PALETTE | DC_SEND_PAGE_PLANE | DC_EXPLICIT_COLOR;
}
}
else
{
pUDPDev->Resolution.fDump &= ~RES_DM_COLOR; /* No colour */
/* Also set number of planes and bits per pixel to match */
pUDPDev->sBitsPixel = 1;
pUDPDev->sDevPlanes = 1;
// MONO is one plane of red (it comes out black, don't worry):
*((DWORD UNALIGNED *)(pUDPDev->rgbOrder)) = (DWORD)DC_PLANE_RED ;
}
pRectFill = GetTableInfo(pdh, HE_RECTFILL,pedm);
if( !(pedm->dx.sFlags & DXF_NORULES) && pRectFill &&
pModelData->rgi[ MD_I_RECTFILL ] != NOT_USED )
{
pUDPDev->fMode |= PF_RECT_FILL;
pUDPDev->fRectFillGeneral = pRectFill->fGeneral;
pUDPDev->wMinGray = pRectFill->wMinGray;
pUDPDev->wMaxGray = pRectFill->wMaxGray;
vSetCDAddr( pUDPDev, CMD_RF_FIRST, pRectFill->rgocd, RF_OCD_MAX );
}
/* How big is this paper??? */
pSize = GetTableInfo( pdh, HE_PAPERSIZE, pedm );
if( pSize )
{
//GPC3 feature: Page protection command per papersize
if (!fGpcVersion2)
if (pUDPDev->fMode & PF_PAGEPROTECT)
vSetCDAddr( pUDPDev, CMD_PAGEPROTECT, &pSize->rgocd[PSZ_OCD_PAGEPROTECT_ON] , 1);
else
vSetCDAddr( pUDPDev, CMD_PAGEPROTECT, &pSize->rgocd[PSZ_OCD_PAGEPROTECT_OFF] , 1);
//GPC3 feature: separate select commands for orientation
if( pedm->dm.dmOrientation == DMORIENT_LANDSCAPE && !fGpcVersion2 )
vSetCDAddr( pUDPDev, CMD_PAPERSIZE, &pSize->rgocd[PSZ_OCD_SELECTLANDSCAPE] , 1);
else
vSetCDAddr( pUDPDev, CMD_PAPERSIZE, &pSize->rgocd[PSZ_OCD_SELECTPORTRAIT] , 1);
if (pSize->fGeneral & PS_EJECTFF)
pUDPDev->fMode |= PF_USE_FF;
}
/* Paper source - from where the paper comes */
pSource = GetTableInfo( pdh, HE_PAPERSOURCE, pedm );
pUDPDev->sPaperSource = pedm->dx.rgindex[HE_PAPERSOURCE];
if( pSource)
{
vSetCDAddr( pUDPDev, CMD_PAPERSOURCE, &pSource->ocdSelect, 1 );
if( pSource->fGeneral & PSRC_EJECTFF )
pUDPDev->fMode |= PF_USE_FF;
}
/* Paper destination info - if applicable! */
pDest = GetTableInfo( pdh, HE_PAPERDEST, pedm );
if( pDest )
vSetCDAddr( pUDPDev, CMD_PAPERDEST, &pDest->ocdSelect, 1 );
/* Text quality */
pTextQuality = GetTableInfo( pdh, HE_TEXTQUAL, pedm );
if( pTextQuality)
vSetCDAddr( pUDPDev, CMD_TEXTQUALITY, &pTextQuality->ocdSelect, 1 );
return TRUE; /* OK if we get here */
}
/**************************** Function Header *******************************
* vSetCDAddr
* Function to compute the addresses of a bunch of CD (command
* descriptors). These are stored in the UD_PDEV structure, so
* as to speed access to these frequently used addresses.
*
* RETURNS:
* Nothing.
*
* HISTORY:
* 10:07 on Fri 26 Mar 1993 -by- Lindsay Harris [lindsayh]
* First version, as it is part of the performance work.
*
****************************************************************************/
void
vSetCDAddr( pUDPDev, iIndex, pocdBase, iNum )
UD_PDEV *pUDPDev; /* Access to all the data */
int iIndex; /* Which slot the output data starts in */
OCD *pocdBase; /* Base address of GPC offset data */
int iNum; /* Number of entries to copy/convert */
{
/*
* Nothing too sophisticated here. Simply convert the array of
* offsets into the GPC data into the corresponding address. This
* speeds things up considerably at run time.
*/
BYTE *pbBase; /* Base of GPC heap data - offset base */
CD **pcdOut; /* Output area */
pbBase = (BYTE *)pUDPDev->pdh + pUDPDev->pdh->loHeap;
pcdOut = &pUDPDev->apcdCmd[ iIndex ];
while( --iNum >= 0 )
{
OCD ocd;
/* ONLY copy if this is a valid value! */
if( (ocd = *pocdBase++) != (OCD)NOOCD )
*pcdOut = (CD *)(pbBase + ocd);
++pcdOut;
}
return;
}
/**************************** Function Header *******************************
* iGCD
* Returns the Greatest Common Divisor. Uses Euclid's algorithm.
*
* RETURNS:
* The GCD.
*
* HISTORY:
* 13:42 on Tue 19 May 1992 -by- Lindsay Harris [lindsayh]
* Created it, based on Knuth, Vol 1, page 2!
*
*****************************************************************************/
int
iGCD( i0, i1 )
int i0; /* The first of the numbers */
int i1; /* The second of the numbers */
{
int iRem; /* Will be the remainder */
if( i0 < i1 )
{
/* Need to interchange them */
iRem = i0;
i0 = i1;
i1 = iRem;
}
while( iRem = (i0 % i1) )
{
/* Step along to the next value */
i0 = i1;
i1 = iRem;
}
return i1; /* The answer! */
}
/***************************** Function Header ******************************
* hypot
* Returns the length of the hypotenous of a right triangle whose sides
* are passed in as the parameters.
*
* RETURNS:
* The length of the hypotenous (integer version).
*
* HISTORY:
* 13:54 on Tue 02 Feb 1993 -by- Lindsay Harris [lindsayh]
* Re-instated from Win 3.1, for compatability.
*
****************************************************************************/
int
hypot( x, y )
int x; /* One side */
int y; /* The other side */
{
register int hypo;
int delta, target;
/*
* Finds the hypoteneous of a right triangle with legs equal to x
* and y. Assumes x, y, hypo are integers.
* Use sq(x) + sq(y) = sq(hypo);
* Start with MAX(x, y),
* use sq(x + 1) = sq(x) + 2x + 1 to incrementally get to the
* target hypotenouse.
*/
hypo = max( x, y );
target = min( x, y );
target = target * target;
for( delta = 0; delta < target; hypo++ )
delta += (hypo << 1) + 1;
return hypo;
}
/**************************** Function Header *******************************
* vSetHTData
* Fill in the halftone information required by GDI. These are filled
* in from either the registry (if the user has twiddled the data) or
* from the NT extensions to GPC data, or (finally) from default
* values, should there be no other data.
*
* RETURNS:
* Nothing.
*
* HISTORY:
* 17:12 on Mon 03 May 1993 -by- Lindsay Harris [lindsayh]
* Moved from above, when cleaned up.
*
****************************************************************************/
void
vSetHTData( pPDev, pGDIInfo )
PDEV *pPDev;
GDIINFO *pGDIInfo;
{
DWORD dwType; /* Needed for GetPrinterData */
DWORD cbNeeded; /* Ditto */
UD_PDEV *pUDPDev; /* Speedier access */
DEVHTINFO dht; /* Filled in from registry */
pUDPDev = pPDev->pUDPDev;
dwType = REG_BINARY;
/*
* Check to see if there is half tone information in the registry.
* If present, use it. Otherwise, then get it from the minidriver,
* that is, the printer's default.
*/
if( GetPrinterData( pPDev->hPrinter,
REGKEY_CUR_DEVHTINFO,
&dwType,
(BYTE *)&dht,
sizeof( DEVHTINFO ),
&cbNeeded ) == NO_ERROR &&
cbNeeded == sizeof( DEVHTINFO ) )
{
pGDIInfo->ciDevice = dht.ColorInfo;
pGDIInfo->ulDevicePelsDPI = (ULONG)dht.DevPelsDPI;
pGDIInfo->ulHTPatternSize = (ULONG)dht.HTPatternSize;
}
else
{
/*
* Not in the registry, so get it from the minidriver. There
* are 2 collections of data: one is colour calibration data,
* the other is halftoning data (pixel size, etc).
*/
if( !bGetHTGPC( pPDev->pNTRes, pUDPDev->iModel,
&pGDIInfo->ulDevicePelsDPI,
&pGDIInfo->ulHTPatternSize ) )
{
/*
* Couldn't get the data from the minidriver (could be
* Win 3.1, for example) so invent some.
*/
pGDIInfo->ulDevicePelsDPI = (ULONG)0; /* Filled in later */
pGDIInfo->ulHTPatternSize =
(ULONG)PickDefaultHTPatSize((DWORD)pGDIInfo->ulLogPixelsX,
(DWORD)pGDIInfo->ulLogPixelsY,
(BOOL)(pUDPDev->fMode & PF_SEIKO));
}
//Check for default HT pattern. For 1 bit/pixel 3 planes it should
// be 6X6 and for 8 bit/pixel it should be 4X4 Enhanced.
if (pUDPDev->pDevColor != NULL)
{
if( ((pUDPDev->pDevColor)->sBitsPixel == 1) &&
((pUDPDev->pDevColor)->sPlanes == 3) )
{
/* Set The HalfTone Patternsize to 6X6 enhanced if the default is
* Less that 6X6.This is needed for multiple color models.
*/
if ( pGDIInfo->ulHTPatternSize < HT_PATSIZE_6x6 )
pGDIInfo->ulHTPatternSize = HT_PATSIZE_6x6_M;
}
else if( ((pUDPDev->pDevColor)->sBitsPixel == 8) &&
((pUDPDev->pDevColor)->sPlanes == 1) )
{
/* Set The HalfTone Patternsize to 4X4 enhanced.
* This is needed for multiple color models.
*/
if ( pGDIInfo->ulHTPatternSize > HT_PATSIZE_4x4_M )
pGDIInfo->ulHTPatternSize = HT_PATSIZE_4x4_M;
}
}
if( !bGetCIGPC( pPDev->pNTRes, pUDPDev->iModel, &pGDIInfo->ciDevice ) )
{
/*
* Use the default values, defined up above.
*/
pGDIInfo->ciDevice = DefDevHTInfo.ColorInfo;
}
}
/* Sanity check on pattern size */
if( pGDIInfo->ulHTPatternSize > HT_PATSIZE_16x16_M )
pGDIInfo->ulHTPatternSize = HT_PATSIZE_6x6_M;
return;
}