/****************************** 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 #include #include #include #include #include #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 #include /* Rasdd lib GPC functions */ #include "rasdd.h" #include "oem.h" #include /* * 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, POEMENABLEPDEVPARAM pParam) { 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 *pWorkingEDM; /* 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 /* HP */ BOOL bRet = FALSE; BOOL bFreeWinResData = FALSE; BOOL bFreeUDMDev = FALSE; BOOL bFreeUDPDev = FALSE; int iModel = 0; TRY /* * 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 ) )) ) { TRACE( ("Rasdd!udInit: cannot allocate WINRESDATA.\n") ); LEAVE; } if( !InitWinResData( pPDev->pvWinResData, pPDev->hheap, pPDev->pstrDataFile ) ) { // JLS HeapFree( pPDev->hheap, 0, (LPSTR)pPDev->pvWinResData ); bFreeWinResData = TRUE; LEAVE; } } /* * 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 )) { TRACE(( "Rasdd!udInit: Can't read/allocate GPC data\n" )); LEAVE; } 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 */ TRACE(( "Rasdd!udInit: Bad DATAHDR\n" )); SetLastError( ERROR_INVALID_CHARACTERISATION_DATA ); pPDev->pGPCData = 0; /* Just to be sure */ LEAVE; } /* * 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 ) { TRACE(( "Rasdd!udInit: HeapAlloc fails for UD_PDEV\n" )); LEAVE; } bFreeUDPDev = TRUE; // derryd - added for WDL release pMDev = (MDEV *)HeapAlloc( pPDev->hheap, 0, sizeof( MDEV ) ); if( pMDev == NULL ) { TRACE(( "Rasdd!udInit: HeapAlloc fails for MDEV\n" )); LEAVE; } // end pPDev->pUDPDev = pUDPDev; bFreeUDMDev = TRUE; } /* * 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 /* JLS. Point back at PDEV for command callbacks. */ pUDPDev->pdev = pPDev; 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 */ /* Call OEM's OEMEnableDriver if there is one. We need to be able to get * OEM's devmode routines now. */ if (!bOEMEnableDriver(pPDev)) { LEAVE; } /* * 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. */ iModel = iGetModel(pPDev->pvWinResData, pPDev->pGPCData, pPDev->pstrModel); pWorkingEDM = pGenerateEDM( pPDev, iModel, pedm ); if (!pWorkingEDM) { LEAVE; } pedm = pWorkingEDM; /* 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 ) { TRACE(( "Rasdd!udInit: Invalid GPC data\n" )); SetLastError( ERROR_INVALID_CHARACTERISATION_DATA ); LEAVE; } /* * 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) ) { TRACE(( "Rasdd!udInit: Old style minidriver with code - nogo\n" )); SetLastError( ERROR_INVALID_CHARACTERISATION_DATA ); LEAVE; } /* !!!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 ) ) { TRACE(( "Rasdd!udInit: Invalid paper format data\n" )); SetLastError( ERROR_INVALID_CHARACTERISATION_DATA ); LEAVE; } /* * 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; PITRACE(("Value of pRes->ptTextScale.x is %d \n", pRes->ptTextScale.x)); PITRACE(("Value of pRes->ptTextScale.y is %d \n", pRes->ptTextScale.y)); PITRACE(("Value of pRes->ptScaleFac.x is %d \n", pRes->ptScaleFac.x)); PITRACE(("Value of pRes->ptScaleFac.y is %d \n", pRes->ptScaleFac.y)); PITRACE(("Value of pGDIInfo->ulLogPixelsX is %d\n",pGDIInfo->ulLogPixelsX)); PITRACE(("Value of pGDIInfo->ulLogPixelsY is %d\n",pGDIInfo->ulLogPixelsY)); PITRACE(("Resolution (DPI): " )); IFPITRACE( pedm->dm.dmOrientation == DMORIENT_LANDSCAPE, ("Master (%ld, %ld), ", pdh->ptMaster.y, pdh->ptMaster.x) ); IFPITRACE( pedm->dm.dmOrientation != DMORIENT_LANDSCAPE, ( "Master (%ld, %ld), ", pdh->ptMaster.x, pdh->ptMaster.y )); PITRACE(("Text (%ld, %ld), Graphics (%ld, %ld)\n", xdpi, ydpi, gxdpi, gydpi)); PITRACE(("%d actual pins, %d logical pins\n", pRes->sPinsPerPass, pRes->sNPins)); /* * 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; } } PITRACE(("rasdd!udInit:value of pUDPDev->dwMem is %d \n",pUDPDev->dwMem)); PITRACE(("rasdd!udInit:value of pUDPDev->dwTotalMem is %d \n",pUDPDev->dwTotalMem)); PITRACE(("rasdd!udInit:value of pedm->dx.dmMemory is %d \n",pedm->dx.dmMemory)); PITRACE(("rasdd!udInit:value of fGpcVersion2 is %d \n",fGpcVersion2)); PITRACE(("rasdd!udInit:value of pdw is %d \n",fGpcVersion2?( *((WORD*)pdw) ):DWFETCH(pdw) )); IFPITRACE(pUDPDev->dwMem != MIN_MEMORY, ("rasdd!udInit:value of pUDPDev->dwMem in Megb is %d \n",(pUDPDev->dwMem/1024))); IFPITRACE(pUDPDev->dwMem != MIN_MEMORY, ("rasdd!udInit:value of pUDPDev->dwTotalMem in Megb is %d \n",(pUDPDev->dwTotalMem / 1024))); 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->dwFontMem = pUDPDev->dwMem; 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 ) ) { LEAVE; } /* * 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"); LEAVE; } hModule = pPDev->hImageMod; // Minidriver is Non-US - We should Fail. if ( EngFindImageProcAddress( hModule, "bInitFEProc" ) ) { LEAVE; } if ( pUDPDev->Resolution.sNPins == -1 ) { if (!(pRes->fDump & RES_DM_GDI)) // Works only for GDI style graphics { LEAVE; } // 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 /* Give OEM a chance to build a PDEV. */ bRet = bOEMEnablePDEV(pPDev, pedm, pParam); ENDTRY FINALLY /* Clean up on error. */ if (pPDev && !bRet) { if (bFreeUDMDev && pMDev) { HeapFree( pPDev->hheap, 0, (LPSTR)pMDev ); } if (bFreeUDPDev && pUDPDev) { HeapFree( pPDev->hheap, 0, (LPSTR)pUDPDev ); pPDev->pUDPDev = 0; } if (bFreeWinResData && pPDev->pvWinResData) { HeapFree( pPDev->hheap, 0, (LPSTR)pPDev->pvWinResData ); pPDev->pvWinResData = 0; } if (pWorkingEDM) { LibFree(pWorkingEDM); pWorkingEDM = 0; } vOEMDisableDriver(pPDev); } ENDFINALLY return(bRet); } /************************* 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 */ PITRACE(( "Paper size (Text units): (%ld, %ld)\n", pPF->ptPhys.x, pPF->ptPhys.y )); PITRACE(( "Printable area (Text units): (%ld, %ld)\n", pPF->ptRes.x, pPF->ptRes.y )); 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 ); PITRACE(( " pPaperSize = 0x%lx, cbSize = %d, Index = %d\n", pPaperSize, pPaperSize ? pPaperSize->cbSize : 0, pedm->dx.rgindex[ HE_PAPERSIZE ] )); 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 */ PITRACE(("rasdd!bBuildCommandTable:value of fLowMemLaser3 is %d \n",fLowMemLaser3)); PITRACE(("rasdd!bBuildCommandTable:value of pUDPDev->iCompMode is %d \n",pUDPDev->iCompMode)); 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 ); TRACE(( "Rasdd!bBuildCmdTable: Invalid/missing CURSORMOVE in GPC\n" )); 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; //OverFlow Conditin;Not good IFTRACE(pDLI->wIDMax < 0, ("Rasdd!bBuildCmdTable: Invalid/missing max font index in GPC(%d)\n",pDLI->wIDMax )); 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. */ PITRACE(("rasdd!bBuildCommandTable:Value of pedm->dm.dmTTOption is %d\n",pedm->dm.dmTTOption)); 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; /* !!!ganeshp:TT Outline code Temporary disabled for 5Si * Testing. Comment Out the following line to enable * Download TT Outline Code. */ pUDPDev->fMode &= ~PF_DLTT_ASTT_PREF; } } IFPITRACE(pUDPDev->fMode & PF_DLTT, ( "....Enabling download of GDI fonts\n" )); IFPITRACE(pUDPDev->fMode & PF_DLTT_ASTT_PREF, ( "....Enabling download of GDI fonts as TT Outline\n" )); IFPITRACE(!(pUDPDev->fMode & PF_DLTT), ( "....Disabling download of GDI fonts\n" )); } /* * 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; }