/*++ Copyright (c) 1996 Microsoft Corporation Module Name: enable.c Abstract: Implementation of device and surface related DDI entry points: DrvEnableDriver DrvDisableDriver DrvEnablePDEV DrvResetPDEV DrvCompletePDEV DrvDisablePDEV DrvEnableSurface DrvDisableSurface DrvBitBlt DrvStretchBlt DrvDitherColor DrvEscape Environment: Fax driver, kernel mode Revision History: 01/09/96 -davidx- Created it. mm/dd/yy -author- description --*/ #include "faxdrv.h" #include "forms.h" #define CLOSE_HANDLE(h) if (!CloseHandle(h)) Error(("CloseHandle failed: %d.\n", GetLastError())) // // Our DRVFN table which tells the engine where to find the routines we support. // static DRVFN FaxDriverFuncs[] = { { INDEX_DrvEnablePDEV, (PFN) DrvEnablePDEV }, { INDEX_DrvResetPDEV, (PFN) DrvResetPDEV }, { INDEX_DrvCompletePDEV, (PFN) DrvCompletePDEV }, { INDEX_DrvDisablePDEV, (PFN) DrvDisablePDEV }, { INDEX_DrvEnableSurface, (PFN) DrvEnableSurface }, { INDEX_DrvDisableSurface, (PFN) DrvDisableSurface }, { INDEX_DrvStartDoc, (PFN) DrvStartDoc }, { INDEX_DrvEndDoc, (PFN) DrvEndDoc }, { INDEX_DrvStartPage, (PFN) DrvStartPage }, { INDEX_DrvSendPage, (PFN) DrvSendPage }, { INDEX_DrvBitBlt, (PFN) DrvBitBlt }, { INDEX_DrvStretchBlt, (PFN) DrvStretchBlt }, { INDEX_DrvCopyBits, (PFN) DrvCopyBits }, { INDEX_DrvDitherColor, (PFN) DrvDitherColor }, { INDEX_DrvEscape, (PFN) DrvEscape }, }; // // Forward declaration of local functions // VOID SelectPrinterForm(PDEVDATA); BOOL FillDevInfo(PDEVDATA, ULONG, PVOID); BOOL FillGdiInfo(PDEVDATA, ULONG, PVOID); VOID FreeDevData(PDEVDATA); HINSTANCE ghInstance; BOOL DllEntryPoint( HANDLE hModule, ULONG ulReason, PCONTEXT pContext ) /*++ Routine Description: DLL initialization procedure. Arguments: hModule - DLL instance handle ulReason - Reason for the call pContext - Pointer to context (not used by us) Return Value: TRUE if DLL is initialized successfully, FALSE otherwise. --*/ { switch (ulReason) { case DLL_PROCESS_ATTACH: ghInstance = hModule; break; case DLL_PROCESS_DETACH: break; } return TRUE; } BOOL DrvQueryDriverInfo( DWORD dwMode, PVOID pBuffer, DWORD cbBuf, PDWORD pcbNeeded ) /*++ Routine Description: Query driver information Arguments: dwMode - Specify the information being queried pBuffer - Points to output buffer cbBuf - Size of output buffer in bytes pcbNeeded - Return the expected size of output buffer Return Value: TRUE if successful, FALSE if there is an error --*/ { switch (dwMode) { case DRVQUERY_USERMODE: Assert(pcbNeeded != NULL); *pcbNeeded = sizeof(DWORD); if (pBuffer == NULL || cbBuf < sizeof(DWORD)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } *((PDWORD) pBuffer) = TRUE; return TRUE; default: Error(("Unknown dwMode in DrvQueryDriverInfo: %d\n", dwMode)); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } } BOOL DrvEnableDriver( ULONG iEngineVersion, ULONG cb, PDRVENABLEDATA pDrvEnableData ) /*++ Routine Description: Implementation of DDI entry point DrvEnableDriver. Please refer to DDK documentation for more details. Arguments: iEngineVersion - Specifies the DDI version number that GDI is written for cb - Size of the buffer pointed to by pDrvEnableData pDrvEnableData - Points to an DRVENABLEDATA structure Return Value: TRUE if successful, FALSE if there is an error --*/ { Verbose(("Entering DrvEnableDriver...\n")); // // Make sure we have a valid engine version and // we're given enough room for the DRVENABLEDATA. // if (iEngineVersion < DDI_DRIVER_VERSION_NT4 || cb < sizeof(DRVENABLEDATA)) { Error(("DrvEnableDriver failed\n")); SetLastError(ERROR_BAD_DRIVER_LEVEL); return FALSE; } // // Fill in the DRVENABLEDATA structure for the engine. // pDrvEnableData->iDriverVersion = DDI_DRIVER_VERSION_NT4; pDrvEnableData->c = sizeof(FaxDriverFuncs) / sizeof(DRVFN); pDrvEnableData->pdrvfn = FaxDriverFuncs; return TRUE; } DHPDEV DrvEnablePDEV( PDEVMODE pdm, PWSTR pLogAddress, ULONG cPatterns, HSURF *phsurfPatterns, ULONG cjGdiInfo, ULONG *pGdiInfo, ULONG cjDevInfo, DEVINFO *pDevInfo, HDEV hdev, PWSTR pDeviceName, HANDLE hPrinter ) /*++ Routine Description: Implementation of DDI entry point DrvEnablePDEV. Please refer to DDK documentation for more details. Arguments: pdm - Points to a DEVMODE structure that contains driver data pLogAddress - Points to the logical address string cPatterns - Specifies the number of standard patterns phsurfPatterns - Buffer to hold surface handles to standard patterns cjGdiInfo - Size of GDIINFO buffer pGdiInfo - Points to a GDIINFO structure cjDevInfo - Size of DEVINFO buffer pDevInfo - Points to a DEVINFO structure hdev - GDI device handle pDeviceName - Points to device name string hPrinter - Spooler printer handle Return Value: Driver device handle, NULL if there is an error --*/ { PDEVDATA pdev; #ifndef USERMODE_DRIVER ULONG ul; #endif Verbose(("Entering DrvEnablePDEV...\n")); // // Allocate memory for our DEVDATA structure and initialize it // if (! (pdev = MemAllocZ(sizeof(DEVDATA)))) { Error(("Memory allocation failed\n")); return NULL; } pdev->hPrinter = hPrinter; pdev->bPrintPreview = FALSE; pdev->hPreviewMapping = NULL; #ifdef USERMODE_DRIVER pdev->hPreviewFile = INVALID_HANDLE_VALUE; #endif pdev->pTiffPageHeader = NULL; pdev->pbTiffPageFP = NULL; pdev->startDevData = pdev; pdev->endDevData = pdev; // // Save and validate DEVMODE information // start with the driver default // then merge with the system default // finally merge with the input devmode // if (CurrentVersionDevmode(pdm)) { memcpy(&pdev->dm, pdm, sizeof(DRVDEVMODE)); // // NOTE: We now use dmPrintQuality and dmYResolution fields // to store the resolution measured in dots-per-inch. Add // the following check as a safety precaution in case older // DEVMODE is passed to us. // if (pdev->dm.dmPublic.dmPrintQuality <= 0 || pdev->dm.dmPublic.dmYResolution <= 0) { pdev->dm.dmPublic.dmPrintQuality = FAXRES_HORIZONTAL; pdev->dm.dmPublic.dmYResolution = FAXRES_VERTICAL; } // // Check if we were given a mapping file // if (pdev->dm.dmPrivate.szMappingFile[0] != TEXT('\0')) { // // Load the preview file image: // // In user mode this is done by - CreateFile(), CreateFileMapping() and MapViewOfFile(). // In kernel mode this is done by - EngLoadModuleForWrite() and EngMapModule(). // #ifdef USERMODE_DRIVER // // First, open the file // if ( INVALID_HANDLE_VALUE == (pdev->hPreviewFile = SafeCreateFile( pdev->dm.dmPrivate.szMappingFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL)) ) { Error(("Failed opening mapping file.\n")); } else { // // Then create a mapping object // pdev->hPreviewMapping = CreateFileMapping( pdev->hPreviewFile, // handle to file NULL, // security PAGE_READWRITE, // protection 0, // high-order DWORD of size MAX_TIFF_PAGE_SIZE, // low-order DWORD of size NULL // object name ); #else // // First, load the file image // pdev->hPreviewMapping = EngLoadModuleForWrite(pdev->dm.dmPrivate.szMappingFile, 0); #endif if (pdev->hPreviewMapping) { // // Now, open a view to the image in our address space // #ifdef USERMODE_DRIVER pdev->pTiffPageHeader = (PMAP_TIFF_PAGE_HEADER) MapViewOfFile( pdev->hPreviewMapping, // handle to file-mapping object FILE_MAP_WRITE, // access mode 0, // high-order DWORD of offset 0, // low-order DWORD of offset 0 // number of bytes to map ); if ( (NULL != pdev->pTiffPageHeader) && (sizeof(MAP_TIFF_PAGE_HEADER) == pdev->pTiffPageHeader->cb) ) #else pdev->pTiffPageHeader = (PMAP_TIFF_PAGE_HEADER) EngMapModule(pdev->hPreviewMapping, &ul); if ( (NULL != pdev->pTiffPageHeader) && (MAX_TIFF_PAGE_SIZE == ul) && (sizeof(MAP_TIFF_PAGE_HEADER) == pdev->pTiffPageHeader->cb) ) #endif { // // Sucess // pdev->bPrintPreview = pdev->pTiffPageHeader->bPreview; pdev->pbTiffPageFP = (LPBYTE) (pdev->pTiffPageHeader + 1); } else { Error(("Failed opening view.\n")); #ifdef USERMODE_DRIVER if (pdev->pTiffPageHeader) { UnmapViewOfFile(pdev->pTiffPageHeader); } CLOSE_HANDLE(pdev->hPreviewMapping); CLOSE_HANDLE(pdev->hPreviewFile); pdev->hPreviewFile = NULL; #else EngFreeModule(pdev->hPreviewMapping); #endif pdev->hPreviewMapping = NULL; pdev->pTiffPageHeader = NULL; } } else { Error(("Failed mapping file: %s.\n", pdev->dm.dmPrivate.szMappingFile)); #ifdef USERMODE_DRIVER // Close the file handle CLOSE_HANDLE(pdev->hPreviewFile); pdev->hPreviewFile = NULL; #endif } #ifdef USERMODE_DRIVER } #endif } else { Warning(("No mapping file specified.\n")); } } else { Error(("Bad DEVMODE passed to DrvEnablePDEV\n")); DriverDefaultDevmode(&pdev->dm, NULL, hPrinter); } // // Calculate the paper size information // SelectPrinterForm(pdev); // // Fill out GDIINFO and DEVINFO structure // if (! FillGdiInfo(pdev, cjGdiInfo, pGdiInfo) || ! FillDevInfo(pdev, cjDevInfo, pDevInfo)) { FreeDevData(pdev); return NULL; } // // Zero out the array of HSURF's so that the engine will // automatically simulate the standard patterns for us // memset(phsurfPatterns, 0, sizeof(HSURF) * cPatterns); // // Return a pointer to our DEVDATA structure // return (DHPDEV) pdev; } BOOL DrvResetPDEV( DHPDEV dhpdevOld, DHPDEV dhpdevNew ) /*++ Routine Description: Implementation of DDI entry point DrvResetPDEV. Please refer to DDK documentation for more details. Arguments: phpdevOld - Driver handle to the old device phpdevNew - Driver handle to the new device Return Value: TRUE if successful, FALSE if there is an error --*/ { PDEVDATA pdevOld, pdevNew; Verbose(("Entering DrvResetPDEV...\n")); // // Validate both old and new device // pdevOld = (PDEVDATA) dhpdevOld; pdevNew = (PDEVDATA) dhpdevNew; if (! ValidDevData(pdevOld) || ! ValidDevData(pdevNew)) { Error(("ValidDevData failed\n")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } Verbose(("Entering DrvResetPDEV...\n")); // // Transfer information from old device to new device // if (pdevOld->pageCount != 0) { pdevNew->pageCount = pdevOld->pageCount; pdevNew->flags |= PDEV_RESETPDEV; pdevNew->fileOffset = pdevOld->fileOffset; if (pdevOld->pFaxIFD) { pdevNew->pFaxIFD = pdevOld->pFaxIFD; pdevOld->pFaxIFD = NULL; } } // // Carry over relevant flag bits // pdevNew->flags |= pdevOld->flags & PDEV_CANCELLED; return TRUE; } VOID DrvCompletePDEV( DHPDEV dhpdev, HDEV hdev ) /*++ Routine Description: Implementation of DDI entry point DrvCompletePDEV. Please refer to DDK documentation for more details. Arguments: dhpdev - Driver device handle hdev - GDI device handle Return Value: NONE --*/ { PDEVDATA pdev = (PDEVDATA) dhpdev; Verbose(("Entering DrvCompletePDEV...\n")); if (! ValidDevData(pdev)) { Assert(FALSE); return; } // // Remember the engine's handle to the physical device // pdev->hdev = hdev; } HSURF DrvEnableSurface( DHPDEV dhpdev ) /*++ Routine Description: Implementation of DDI entry point DrvEnableSurface. Please refer to DDK documentation for more details. Arguments: dhpdev - Driver device handle Return Value: Handle to newly created surface, NULL if there is an error --*/ { PDEVDATA pdev = (PDEVDATA) dhpdev; FLONG flHooks; Verbose(("Entering DrvEnableSurface...\n")); // // Validate the pointer to our DEVDATA structure // if (! ValidDevData(pdev)) { Error(("ValidDevData failed\n")); SetLastError(ERROR_INVALID_PARAMETER); return NULL; } // // Adjust the bitmap size so that we always end up with 1728 pixels per scanline // Assert(MAX_WIDTH_PIXELS % DWORDBITS == 0); if (IsLandscapeMode(pdev)) { Assert(pdev->imageSize.cy <= MAX_WIDTH_PIXELS); pdev->imageSize.cy = MAX_WIDTH_PIXELS; pdev->imageSize.cx = ((pdev->imageSize.cx + (BYTEBITS - 1)) / BYTEBITS) * BYTEBITS; } else { Assert(pdev->imageSize.cx <= MAX_WIDTH_PIXELS); pdev->imageSize.cx = MAX_WIDTH_PIXELS; } pdev->lineOffset = PadBitsToBytes(pdev->imageSize.cx, sizeof(DWORD)); // // Call the engine to create a standard bitmap surface for us // pdev->hbitmap = (HSURF) EngCreateBitmap(pdev->imageSize, pdev->lineOffset, BMF_1BPP, BMF_TOPDOWN | BMF_NOZEROINIT | BMF_USERMEM, NULL); if (pdev->hbitmap == NULL) { Error(("EngCreateBitmap failed\n")); return NULL; } // // Associate the surface with the device and inform the // engine which functions we have hooked out // if (pdev->dm.dmPrivate.flags & FAXDM_NO_HALFTONE) flHooks = 0; else flHooks = (HOOK_STRETCHBLT | HOOK_BITBLT | HOOK_COPYBITS); EngAssociateSurface(pdev->hbitmap, pdev->hdev, flHooks); // // Return the surface handle to the engine // return pdev->hbitmap; } VOID DrvDisableSurface( DHPDEV dhpdev ) /*++ Routine Description: Implementation of DDI entry point DrvDisableSurface. Please refer to DDK documentation for more details. Arguments: dhpdev - Driver device handle Return Value: NONE --*/ { PDEVDATA pdev = (PDEVDATA) dhpdev; Verbose(("Entering DrvDisableSurface...\n")); if (! ValidDevData(pdev)) { Assert(FALSE); return; } // // Call the engine to delete the surface handle // if (pdev->hbitmap != NULL) { EngDeleteSurface(pdev->hbitmap); pdev->hbitmap = NULL; } } VOID DrvDisablePDEV( DHPDEV dhpdev ) /*++ Routine Description: Implementation of DDI entry point DrvDisablePDEV. Please refer to DDK documentation for more details. Arguments: dhpdev - Driver device handle Return Value: NONE --*/ { PDEVDATA pdev = (PDEVDATA) dhpdev; Verbose(("Entering DrvDisablePDEV...\n")); if (! ValidDevData(pdev)) { Assert(FALSE); return; } // // Free up memory allocated for the current PDEV // FreeDevData(pdev); } VOID DrvDisableDriver( VOID ) /*++ Routine Description: Implementation of DDI entry point DrvDisableDriver. Please refer to DDK documentation for more details. Arguments: NONE Return Value: NONE --*/ { Verbose(("Entering DrvDisableDriver...\n")); } BOOL IsCompatibleSurface( SURFOBJ *psoDst, SURFOBJ *psoSrc, XLATEOBJ *pxlo ) /*++ Routine Description: Check if the source surface is compatible with the destination surface i.e. we can bitblt without halftonig Arguments: psoDst - Specifies the destination surface psoSrc - Specifies the source surface pxlo - How to transform colors between the source surface and the destination surface Return Value: TRUE if the source surface is compatible with the destination surface FALSE otherwise --*/ { BOOL result; // // We know our destination surface is always 1bpp // Assert(psoDst->iBitmapFormat == BMF_1BPP); // // Check whether the transformation is trivial // if (!pxlo || (pxlo->flXlate & XO_TRIVIAL)) { result = (psoSrc->iBitmapFormat == psoDst->iBitmapFormat); } else if ((pxlo->flXlate & XO_TABLE) && pxlo->cEntries <= 2) { ULONG srcPalette[2]; srcPalette[0] = srcPalette[1] = RGB_BLACK; XLATEOBJ_cGetPalette(pxlo, XO_SRCPALETTE, pxlo->cEntries, srcPalette); result = (srcPalette[0] == RGB_BLACK || srcPalette[0] == RGB_WHITE) && (srcPalette[1] == RGB_BLACK || srcPalette[1] == RGB_WHITE); } else result = FALSE; return result; } BOOL DrvCopyBits( SURFOBJ *psoTrg, SURFOBJ *psoSrc, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclDst, POINTL *pptlSrc ) /*++ Routine Description: Implementation of DDI entry point DrvCopyBits. We need to hook out this function. Otherwise bitmaps won't be halftoned. Arguments: Please refer to DDK documentation for more details. Return Value: TRUE if successful, FALSE otherwise --*/ { Verbose(("Entering DrvCopyBits ...\n")); // // Check if halftoning is necessary // If not, let the engine handle it // if ((psoSrc->iType != STYPE_BITMAP) || (psoTrg->iType != STYPE_BITMAP) || IsCompatibleSurface(psoTrg, psoSrc, pxlo)) { return EngCopyBits(psoTrg, psoSrc, pco, pxlo, prclDst, pptlSrc); } else { POINTL ptlBrushOrg; RECTL rclDst, rclSrc; ptlBrushOrg.x = ptlBrushOrg.y = 0; rclDst = *prclDst; rclSrc.left = pptlSrc->x; rclSrc.top = pptlSrc->y; rclSrc.right = rclSrc.left + (rclDst.right - rclDst.left); rclSrc.bottom = rclSrc.top + (rclDst.bottom - rclDst.top); if ((rclSrc.right > psoSrc->sizlBitmap.cx) || (rclSrc.bottom > psoSrc->sizlBitmap.cy)) { rclSrc.right = psoSrc->sizlBitmap.cx; rclSrc.bottom = psoSrc->sizlBitmap.cy; rclDst.right = rclDst.left + (rclSrc.right - rclSrc.left); rclDst.bottom = rclDst.top + (rclSrc.bottom - rclSrc.top); } return EngStretchBlt(psoTrg, psoSrc, NULL, pco, pxlo, &DefHTClrAdj, &ptlBrushOrg, &rclDst, &rclSrc, NULL, HALFTONE); } } BOOL DrvBitBlt( SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclTrg, POINTL *pptlSrc, POINTL *pptlMask, BRUSHOBJ *pbo, POINTL *pptlBrush, ROP4 rop4 ) /*++ Routine Description: Implementation of DDI entry point DrvBitBlt. We need to hook out this function. Otherwise bitmaps won't be halftoned. Arguments: Please refer to DDK documentation for more details. Return Value: TRUE if successful, FALSE otherwise --*/ { COLORADJUSTMENT *pca; PDEVDATA pdev; DWORD rop3Foreground, rop3Background; SURFOBJ *psoNewSrc; HBITMAP hbmpNewSrc; POINTL brushOrg; BOOL result; Verbose(("Entering DrvBitBlt...\n")); // // Validate input parameters // Assert(psoTrg != NULL); pdev = (PDEVDATA) psoTrg->dhpdev; if (! ValidDevData(pdev)) { Error(("ValidDevData failed\n")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } // // Use the system default color adjustment information // pca = &DefHTClrAdj; // // Figure out the foreground and background ROP3 // psoNewSrc = NULL; hbmpNewSrc = NULL; rop3Foreground = GetForegroundRop3(rop4); rop3Background = GetBackgroundRop3(rop4); if ((Rop3NeedPattern(rop3Foreground) || Rop3NeedPattern(rop3Background)) && pptlBrush) { brushOrg = *pptlBrush; } else { brushOrg.x = brushOrg.y = 0; } // // If a source bitmap is involved in the raster operation and // the source is not compatible with the destination surface, // then we'll halftone the source bitmap into a new bitmap and // bitblt the new bitmap onto the destination surface. // if ((Rop3NeedSource(rop3Foreground) || Rop3NeedSource(rop3Background)) && !IsCompatibleSurface(psoTrg, psoSrc, pxlo)) { RECTL rclNewSrc, rclOldSrc; SIZEL bmpSize; LONG lDelta; rclNewSrc.left = rclNewSrc.top = 0; rclNewSrc.right = prclTrg->right - prclTrg->left; rclNewSrc.bottom = prclTrg->bottom - prclTrg->top; rclOldSrc.left = pptlSrc->x; rclOldSrc.top = pptlSrc->y; rclOldSrc.right = rclOldSrc.left + rclNewSrc.right; rclOldSrc.bottom = rclOldSrc.top + rclNewSrc.bottom; // // Express path for the most common case: SRCCOPY // if (rop4 == 0xcccc) { return EngStretchBlt(psoTrg, psoSrc, psoMask, pco, pxlo, pca, &brushOrg, prclTrg, &rclOldSrc, pptlMask, HALFTONE); } // // Modify the brush origin, because when we blt to the clipped bitmap // the origin is at bitmap's (0, 0) minus the original location // brushOrg.x -= prclTrg->left; brushOrg.y -= prclTrg->top; // // Create a temporary bitmap surface // Halftone the source bitmap into the temporary bitmap // Assert(psoTrg->iBitmapFormat == BMF_1BPP); bmpSize.cx = rclNewSrc.right; bmpSize.cy = rclNewSrc.bottom; lDelta = PadBitsToBytes(bmpSize.cx, sizeof(DWORD)); if (! (hbmpNewSrc = EngCreateBitmap(bmpSize, lDelta, BMF_1BPP, BMF_TOPDOWN | BMF_NOZEROINIT, NULL)) || ! EngAssociateSurface((HSURF) hbmpNewSrc, pdev->hdev, 0) || ! (psoNewSrc = EngLockSurface((HSURF) hbmpNewSrc)) || ! EngStretchBlt(psoNewSrc, psoSrc, NULL, NULL, pxlo, pca, &brushOrg, &rclNewSrc, &rclOldSrc, NULL, HALFTONE)) { if (psoNewSrc) EngUnlockSurface(psoNewSrc); if (hbmpNewSrc) EngDeleteSurface((HSURF) hbmpNewSrc); return FALSE; } // // Proceed to bitblt from the temporary bitmap to the destination // psoSrc = psoNewSrc; pptlSrc = (PPOINTL) &rclNewSrc.left; pxlo = NULL; brushOrg.x = brushOrg.y = 0; } // // Let engine do the work // result = EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, prclTrg, pptlSrc, pptlMask, pbo, &brushOrg, rop4); // // Clean up properly before returning // if (psoNewSrc) EngUnlockSurface(psoNewSrc); if (hbmpNewSrc) EngDeleteSurface((HSURF) hbmpNewSrc); return result; } BOOL DrvStretchBlt( SURFOBJ *psoDest, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, COLORADJUSTMENT *pca, POINTL *pptlBrushOrg, RECTL *prclDest, RECTL *prclSrc, POINTL *pptlMask, ULONG iMode ) /*++ Routine Description: Implementation of DDI entry point DrvDisableDriver. We need to hook out this function. Otherwise bitmaps won't be halftoned. Arguments: Please refer to DDK documentation for more details. Return Value: TRUE if successful, FALSE if there is an error --*/ { Verbose(("Entering DrvStretchBlt...\n")); // // If no color adjustment information is provided, use the system default // if (pca == NULL) pca = &DefHTClrAdj; // // Let engine do the work; make sure halftone is enabled // return EngStretchBlt(psoDest, psoSrc, psoMask, pco, pxlo, pca, pptlBrushOrg, prclDest, prclSrc, pptlMask, HALFTONE); } ULONG DrvDitherColor( DHPDEV dhpdev, ULONG iMode, ULONG rgb, ULONG *pul ) /*++ Routine Description: Implementation of DDI entry point DrvDisableDriver. Please refer to DDK documentation for more details. Arguments: dhpdev - Driver device handle iMode - Determines the palette to dither against rgb - Specifies the RGB color that is to be dithered pul - Points to a memory location in which the dithering information is to be recorded Return Value: DCR_HALFTONE to indicate that the engine should create a halftone approximation for the driver. --*/ { return DCR_HALFTONE; } BOOL FillDevInfo( PDEVDATA pdev, ULONG cb, PVOID pdevinfo ) /*++ Routine Description: Fill in the DEVINFO structure pointed to by pdevinfo. Arguments: pdev - Pointer to our DEVDATA structure cb - Size of structure pointed to by pdevinfo pdevinfo - Pointer to DEVINFO structure [Notes:] Since we have to worry about not writing out more than cb bytes to pdevinfo, we will first fill in a local buffer, then copy cb bytes to pdevinfo. Return Value: TRUE if successful. FALSE otherwise. --*/ { static ULONG paletteColors[2] = { RGB_BLACK, RGB_WHITE, }; DEVINFO devinfo; memset(&devinfo, 0, sizeof(devinfo)); // // Fill in the graphics capabilities flags: we let the engine // do almost everything. Also, we have to tell the engine not // to do metafile spooling because we hook out DrvDocumentEvent. // devinfo.flGraphicsCaps = GCAPS_HALFTONE | GCAPS_MONO_DITHER | GCAPS_COLOR_DITHER | GCAPS_DONTJOURNAL; // // No device fonts // devinfo.cFonts = 0; // // Black and white palette: entry 0 is black and entry 1 is white // if (! (pdev->hpal = EngCreatePalette(PAL_INDEXED, 2, paletteColors, 0, 0, 0))) { Error(("EngCreatePalette failed\n")); return FALSE; } devinfo.hpalDefault = pdev->hpal; devinfo.iDitherFormat = BMF_1BPP; devinfo.cxDither = devinfo.cyDither = 4; // // Copy cb bytes from devinfo structure into the caller-provided buffer // if (cb > sizeof(devinfo)) { memset(pdevinfo, 0, cb); memcpy(pdevinfo, &devinfo, sizeof(devinfo)); } else memcpy(pdevinfo, &devinfo, cb); return TRUE; } BOOL FillGdiInfo( PDEVDATA pdev, ULONG cb, PVOID pgdiinfo ) /*++ Routine Description: Fill in the device capabilities information for the engine. Arguments: pdev - Pointer to DEVDATA structure cb - Size of buffer pointed to by pgdiinfo pgdiinfo - Pointer to a GDIINFO buffer Return Value: NONE --*/ { GDIINFO gdiinfo; LONG maxRes; memset(&gdiinfo, 0, sizeof(gdiinfo)); // // This field doesn't seem to have any effect for printer drivers. // Put our driver version number in there anyway. // gdiinfo.ulVersion = DRIVER_VERSION; // // We're raster printers // gdiinfo.ulTechnology = DT_RASPRINTER; // // Width and height of the imageable area measured in microns. // Remember to turn on the sign bit. // gdiinfo.ulHorzSize = - (pdev->imageArea.right - pdev->imageArea.left); gdiinfo.ulVertSize = - (pdev->imageArea.bottom - pdev->imageArea.top); // // Convert paper size and imageable area from microns to pixels // pdev->paperSize.cx = MicronToPixel(pdev->paperSize.cx, pdev->xres); pdev->paperSize.cy = MicronToPixel(pdev->paperSize.cy, pdev->yres); pdev->imageArea.left = MicronToPixel(pdev->imageArea.left, pdev->xres); pdev->imageArea.right = MicronToPixel(pdev->imageArea.right, pdev->xres); pdev->imageArea.top = MicronToPixel(pdev->imageArea.top, pdev->yres); pdev->imageArea.bottom = MicronToPixel(pdev->imageArea.bottom, pdev->yres); pdev->imageSize.cx = pdev->imageArea.right - pdev->imageArea.left; pdev->imageSize.cy = pdev->imageArea.bottom - pdev->imageArea.top; // // Width and height of the imageable area measured in device pixels // gdiinfo.ulHorzRes = pdev->imageSize.cx; gdiinfo.ulVertRes = pdev->imageSize.cy; // // Color depth information // gdiinfo.cBitsPixel = 1; gdiinfo.cPlanes = 1; gdiinfo.ulNumColors = 2; // // Resolution information // gdiinfo.ulLogPixelsX = pdev->xres; gdiinfo.ulLogPixelsY = pdev->yres; // // Win31 compatible text capability flags. Are they still used by anyone? // gdiinfo.flTextCaps = 0; // // Device pixel aspect ratio // gdiinfo.ulAspectX = pdev->yres; gdiinfo.ulAspectY = pdev->xres; gdiinfo.ulAspectXY = CalcHypot(pdev->xres, pdev->yres); // // Dotted line appears to be approximately 25dpi // We assume either xres is a multiple of yres or yres is a multiple of xres // maxRes = max(pdev->xres, pdev->yres); Assert((maxRes % pdev->xres) == 0 && (maxRes % pdev->yres == 0)); gdiinfo.xStyleStep = maxRes / pdev->xres; gdiinfo.yStyleStep = maxRes / pdev->yres; gdiinfo.denStyleStep = maxRes / 25; // // Size and margins of physical surface measured in device pixels // gdiinfo.szlPhysSize.cx = pdev->paperSize.cx; gdiinfo.szlPhysSize.cy = pdev->paperSize.cy; gdiinfo.ptlPhysOffset.x = pdev->imageArea.left; gdiinfo.ptlPhysOffset.y = pdev->imageArea.top; // // Use default halftone information // gdiinfo.ciDevice = DefDevHTInfo.ColorInfo; gdiinfo.ulDevicePelsDPI = max(pdev->xres, pdev->yres); gdiinfo.ulPrimaryOrder = PRIMARY_ORDER_CBA; gdiinfo.ulHTOutputFormat = HT_FORMAT_1BPP; gdiinfo.flHTFlags = HT_FLAG_HAS_BLACK_DYE; gdiinfo.ulHTPatternSize = HT_PATSIZE_4x4_M; // // Copy cb byte from gdiinfo structure into the caller-provided buffer // if (cb > sizeof(gdiinfo)) { memset(pgdiinfo, 0, cb); memcpy(pgdiinfo, &gdiinfo, sizeof(gdiinfo)); } else memcpy(pgdiinfo, &gdiinfo, cb); return TRUE; } VOID FreeDevData( PDEVDATA pdev ) /*++ Routine Description: Free up all memory associated with the specified PDEV Arguments: pdev Pointer to our DEVDATA structure Return Value: NONE --*/ { if (pdev->hpal) EngDeletePalette(pdev->hpal); // // Close our preview file mapping if opened // #ifdef USERMODE_DRIVER if (pdev->pTiffPageHeader) { UnmapViewOfFile(pdev->pTiffPageHeader); pdev->pTiffPageHeader = NULL; } if (pdev->hPreviewMapping) { CLOSE_HANDLE(pdev->hPreviewMapping); pdev->hPreviewMapping = NULL; } if (INVALID_HANDLE_VALUE != pdev->hPreviewFile) { CLOSE_HANDLE(pdev->hPreviewFile); pdev->hPreviewFile = INVALID_HANDLE_VALUE; } #else if (pdev->hPreviewMapping) { EngFreeModule(pdev->hPreviewMapping); } #endif // USERMODE_DRIVER MemFree(pdev->pFaxIFD); MemFree(pdev); } VOID SelectPrinterForm( PDEVDATA pdev ) /*++ Routine Description: Store printer paper size information in our DEVDATA structure Arguments: pdev - Pointer to our DEVDATA structure Return Value: NONE --*/ { FORM_INFO_1 formInfo; // // Validate devmode form specification; use default form if it's invalid. // if (! ValidDevmodeForm(pdev->hPrinter, &pdev->dm.dmPublic, &formInfo)) { memset(&formInfo, 0, sizeof(formInfo)); // // Default to A4 paper // formInfo.Size.cx = formInfo.ImageableArea.right = A4_WIDTH; formInfo.Size.cy = formInfo.ImageableArea.bottom = A4_HEIGHT; } Assert(formInfo.Size.cx > 0 && formInfo.Size.cy > 0); Assert(formInfo.ImageableArea.left >= 0 && formInfo.ImageableArea.top >= 0 && formInfo.ImageableArea.left < formInfo.ImageableArea.right && formInfo.ImageableArea.top < formInfo.ImageableArea.bottom && formInfo.ImageableArea.right <= formInfo.Size.cx && formInfo.ImageableArea.bottom <= formInfo.Size.cy); // // Take landscape into consideration // if (IsLandscapeMode(pdev)) { LONG width, height; // // Swap the width and height // pdev->paperSize.cy = width = formInfo.Size.cx; pdev->paperSize.cx = height = formInfo.Size.cy; // // Rotate the coordinate system 90 degrees counterclockwise // pdev->imageArea.left = height - formInfo.ImageableArea.bottom; pdev->imageArea.top = formInfo.ImageableArea.left; pdev->imageArea.right = height - formInfo.ImageableArea.top; pdev->imageArea.bottom = formInfo.ImageableArea.right; // // Swap x and y resolution // pdev->xres = pdev->dm.dmPublic.dmYResolution; pdev->yres = pdev->dm.dmPublic.dmPrintQuality; } else { pdev->paperSize = formInfo.Size; pdev->imageArea = formInfo.ImageableArea; pdev->xres = pdev->dm.dmPublic.dmPrintQuality; pdev->yres = pdev->dm.dmPublic.dmYResolution; } } LONG CalcHypot( LONG x, LONG y ) /*++ Routine Description: Returns the length of the hypotenouse of a right triangle Arguments: x, y - Edges of the right triangle Return Value: Hypotenouse of the right triangle --*/ { LONG hypo, delta, target; // // Take care of negative inputs // if (x < 0) x = -x; if (y < 0) y = -y; // // 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; for(delta = 0; delta < target; hypo++) delta += (hypo << 1) + 1; return hypo; }