|  | /* | 
|  | *	PostScript driver initialization functions | 
|  | * | 
|  | *	Copyright 1998 Huw D M Davies | 
|  | *	Copyright 2001 Marcus Meissner | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <string.h> | 
|  | #ifdef HAVE_UNISTD_H | 
|  | # include <unistd.h> | 
|  | #endif | 
|  |  | 
|  | #define NONAMELESSUNION | 
|  | #define NONAMELESSSTRUCT | 
|  | #include "psdrv.h" | 
|  | #include "wine/debug.h" | 
|  | #include "winreg.h" | 
|  | #include "winspool.h" | 
|  | #include "winerror.h" | 
|  | #include "wownt32.h" | 
|  | #include "heap.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(psdrv); | 
|  |  | 
|  | #ifdef HAVE_CUPS_CUPS_H | 
|  | #include <cups/cups.h> | 
|  |  | 
|  | #ifndef SONAME_LIBCUPS | 
|  | #define SONAME_LIBCUPS "libcups.so" | 
|  | #endif | 
|  |  | 
|  | static void *cupshandle = NULL; | 
|  | #endif | 
|  |  | 
|  | static PSDRV_DEVMODEA DefaultDevmode = | 
|  | { | 
|  | { /* dmPublic */ | 
|  | /* dmDeviceName */	"Wine PostScript Driver", | 
|  | /* dmSpecVersion */	0x30a, | 
|  | /* dmDriverVersion */	0x001, | 
|  | /* dmSize */		sizeof(DEVMODEA), | 
|  | /* dmDriverExtra */	sizeof(PSDRV_DEVMODEA)-sizeof(DEVMODEA), | 
|  | /* dmFields */		DM_ORIENTATION | DM_PAPERSIZE | DM_SCALE | | 
|  | DM_COPIES | DM_DEFAULTSOURCE | DM_COLOR | | 
|  | DM_YRESOLUTION | DM_TTOPTION, | 
|  | { /* u1 */ | 
|  | { /* s1 */ | 
|  | /* dmOrientation */	DMORIENT_PORTRAIT, | 
|  | /* dmPaperSize */	DMPAPER_LETTER, | 
|  | /* dmPaperLength */	2794, | 
|  | /* dmPaperWidth */      2159 | 
|  | } | 
|  | }, | 
|  | /* dmScale */		100, /* ?? */ | 
|  | /* dmCopies */		1, | 
|  | /* dmDefaultSource */	DMBIN_AUTO, | 
|  | /* dmPrintQuality */	0, | 
|  | /* dmColor */		DMCOLOR_COLOR, | 
|  | /* dmDuplex */		DMDUP_SIMPLEX, | 
|  | /* dmYResolution */	0, | 
|  | /* dmTTOption */	DMTT_SUBDEV, | 
|  | /* dmCollate */		0, | 
|  | /* dmFormName */	"", | 
|  | /* dmUnusedPadding */   0, | 
|  | /* dmBitsPerPel */	0, | 
|  | /* dmPelsWidth */	0, | 
|  | /* dmPelsHeight */	0, | 
|  | /* dmDisplayFlags */	0, | 
|  | /* dmDisplayFrequency */ 0, | 
|  | /* dmICMMethod */       0, | 
|  | /* dmICMIntent */       0, | 
|  | /* dmMediaType */       0, | 
|  | /* dmDitherType */      0, | 
|  | /* dmReserved1 */       0, | 
|  | /* dmReserved2 */       0, | 
|  | /* dmPanningWidth */    0, | 
|  | /* dmPanningHeight */   0 | 
|  | }, | 
|  | { /* dmDocPrivate */ | 
|  | /* dummy */ 0 | 
|  | }, | 
|  | { /* dmDrvPrivate */ | 
|  | /* numInstalledOptions */ 0 | 
|  | } | 
|  | }; | 
|  |  | 
|  | HINSTANCE PSDRV_hInstance = 0; | 
|  | HANDLE PSDRV_Heap = 0; | 
|  |  | 
|  | static HFONT PSDRV_DefaultFont = 0; | 
|  | static LOGFONTA DefaultLogFont = { | 
|  | 100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 0, 0, | 
|  | DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" | 
|  | }; | 
|  |  | 
|  | /********************************************************************* | 
|  | *	     DllMain | 
|  | * | 
|  | * Initializes font metrics and registers driver. wineps dll entry point. | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) | 
|  | { | 
|  | TRACE("(%p, 0x%08lx, %p)\n", hinst, reason, reserved); | 
|  |  | 
|  | switch(reason) { | 
|  |  | 
|  | case DLL_PROCESS_ATTACH: | 
|  | PSDRV_hInstance = hinst; | 
|  | DisableThreadLibraryCalls(hinst); | 
|  |  | 
|  | PSDRV_Heap = HeapCreate(0, 0x10000, 0); | 
|  | if (PSDRV_Heap == NULL) | 
|  | return FALSE; | 
|  |  | 
|  | if (PSDRV_GetFontMetrics() == FALSE) { | 
|  | HeapDestroy(PSDRV_Heap); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | PSDRV_DefaultFont = CreateFontIndirectA(&DefaultLogFont); | 
|  | if (PSDRV_DefaultFont == NULL) { | 
|  | HeapDestroy(PSDRV_Heap); | 
|  | return FALSE; | 
|  | } | 
|  | #ifdef HAVE_CUPS_CUPS_H | 
|  | /* dynamically load CUPS if not yet loaded */ | 
|  | if (!cupshandle) { | 
|  | cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0); | 
|  | if (!cupshandle) cupshandle = (void*)-1; | 
|  | } | 
|  | #endif | 
|  | break; | 
|  |  | 
|  | case DLL_PROCESS_DETACH: | 
|  |  | 
|  | DeleteObject( PSDRV_DefaultFont ); | 
|  | HeapDestroy( PSDRV_Heap ); | 
|  | #ifdef HAVE_CUPS_CUPS_H | 
|  | if (cupshandle && (cupshandle != (void*)-1)) { | 
|  | wine_dlclose(cupshandle, NULL, 0); | 
|  | cupshandle = NULL; | 
|  | } | 
|  | #endif | 
|  | break; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void PSDRV_UpdateDevCaps( PSDRV_PDEVICE *physDev ) | 
|  | { | 
|  | PAGESIZE *page; | 
|  | INT width = 0, height = 0; | 
|  |  | 
|  | if(physDev->Devmode->dmPublic.dmFields & DM_PAPERSIZE) { | 
|  | for(page = physDev->pi->ppd->PageSizes; page; page = page->next) { | 
|  | if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if(!page) { | 
|  | FIXME("Can't find page\n"); | 
|  | physDev->ImageableArea.left = 0; | 
|  | physDev->ImageableArea.right = 0; | 
|  | physDev->ImageableArea.bottom = 0; | 
|  | physDev->ImageableArea.top = 0; | 
|  | physDev->PageSize.cx = 0; | 
|  | physDev->PageSize.cy = 0; | 
|  | } else if(page->ImageableArea) { | 
|  | /* physDev sizes in device units; ppd sizes in 1/72" */ | 
|  | physDev->ImageableArea.left = page->ImageableArea->llx * | 
|  | physDev->logPixelsX / 72; | 
|  | physDev->ImageableArea.right = page->ImageableArea->urx * | 
|  | physDev->logPixelsX / 72; | 
|  | physDev->ImageableArea.bottom = page->ImageableArea->lly * | 
|  | physDev->logPixelsY / 72; | 
|  | physDev->ImageableArea.top = page->ImageableArea->ury * | 
|  | physDev->logPixelsY / 72; | 
|  | physDev->PageSize.cx = page->PaperDimension->x * | 
|  | physDev->logPixelsX / 72; | 
|  | physDev->PageSize.cy = page->PaperDimension->y * | 
|  | physDev->logPixelsY / 72; | 
|  | } else { | 
|  | physDev->ImageableArea.left = physDev->ImageableArea.bottom = 0; | 
|  | physDev->ImageableArea.right = physDev->PageSize.cx = | 
|  | page->PaperDimension->x * physDev->logPixelsX / 72; | 
|  | physDev->ImageableArea.top = physDev->PageSize.cy = | 
|  | page->PaperDimension->y * physDev->logPixelsY / 72; | 
|  | } | 
|  | } else if((physDev->Devmode->dmPublic.dmFields & DM_PAPERLENGTH) && | 
|  | (physDev->Devmode->dmPublic.dmFields & DM_PAPERWIDTH)) { | 
|  | /* physDev sizes in device units; Devmode sizes in 1/10 mm */ | 
|  | physDev->ImageableArea.left = physDev->ImageableArea.bottom = 0; | 
|  | physDev->ImageableArea.right = physDev->PageSize.cx = | 
|  | physDev->Devmode->dmPublic.u1.s1.dmPaperWidth * | 
|  | physDev->logPixelsX / 254; | 
|  | physDev->ImageableArea.top = physDev->PageSize.cy = | 
|  | physDev->Devmode->dmPublic.u1.s1.dmPaperLength * | 
|  | physDev->logPixelsY / 254; | 
|  | } else { | 
|  | FIXME("Odd dmFields %lx\n", physDev->Devmode->dmPublic.dmFields); | 
|  | physDev->ImageableArea.left = 0; | 
|  | physDev->ImageableArea.right = 0; | 
|  | physDev->ImageableArea.bottom = 0; | 
|  | physDev->ImageableArea.top = 0; | 
|  | physDev->PageSize.cx = 0; | 
|  | physDev->PageSize.cy = 0; | 
|  | } | 
|  |  | 
|  | TRACE("ImageableArea = %ld,%ld - %ld,%ld: PageSize = %ldx%ld\n", | 
|  | physDev->ImageableArea.left, physDev->ImageableArea.bottom, | 
|  | physDev->ImageableArea.right, physDev->ImageableArea.top, | 
|  | physDev->PageSize.cx, physDev->PageSize.cy); | 
|  |  | 
|  | /* these are in device units */ | 
|  | width = physDev->ImageableArea.right - physDev->ImageableArea.left; | 
|  | height = physDev->ImageableArea.top - physDev->ImageableArea.bottom; | 
|  |  | 
|  | if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_PORTRAIT) { | 
|  | physDev->horzRes = width; | 
|  | physDev->vertRes = height; | 
|  | } else { | 
|  | physDev->horzRes = height; | 
|  | physDev->vertRes = width; | 
|  | } | 
|  |  | 
|  | /* these are in mm */ | 
|  | physDev->horzSize = (physDev->horzRes * 25.4) / physDev->logPixelsX; | 
|  | physDev->vertSize = (physDev->vertRes * 25.4) / physDev->logPixelsY; | 
|  |  | 
|  | TRACE("devcaps: horzSize = %dmm, vertSize = %dmm, " | 
|  | "horzRes = %d, vertRes = %d\n", | 
|  | physDev->horzSize, physDev->vertSize, | 
|  | physDev->horzRes, physDev->vertRes); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************** | 
|  | *      DEVMODEdupWtoA | 
|  | * | 
|  | * Creates an ascii copy of supplied devmode on heap | 
|  | * | 
|  | * Copied from dlls/winspool/info.c until full unicodification | 
|  | */ | 
|  | static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW) | 
|  | { | 
|  | LPDEVMODEA dmA; | 
|  | DWORD size; | 
|  | BOOL Formname; | 
|  | ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW; | 
|  |  | 
|  | if(!dmW) return NULL; | 
|  | Formname = (dmW->dmSize > off_formname); | 
|  | size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0); | 
|  | dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra); | 
|  | WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName, | 
|  | CCHDEVICENAME, NULL, NULL); | 
|  | if(!Formname) { | 
|  | memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion, | 
|  | dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR)); | 
|  | } else { | 
|  | memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion, | 
|  | off_formname - CCHDEVICENAME * sizeof(WCHAR)); | 
|  | WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName, | 
|  | CCHFORMNAME, NULL, NULL); | 
|  | memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - | 
|  | (off_formname + CCHFORMNAME * sizeof(WCHAR))); | 
|  | } | 
|  | dmA->dmSize = size; | 
|  | memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, | 
|  | dmW->dmDriverExtra); | 
|  | return dmA; | 
|  | } | 
|  |  | 
|  |  | 
|  | /********************************************************************** | 
|  | *	     PSDRV_CreateDC | 
|  | */ | 
|  | BOOL PSDRV_CreateDC( HDC hdc, PSDRV_PDEVICE **pdev, LPCWSTR driver, LPCWSTR device, | 
|  | LPCWSTR output, const DEVMODEW* initData ) | 
|  | { | 
|  | PSDRV_PDEVICE *physDev; | 
|  | PRINTERINFO *pi; | 
|  | char deviceA[CCHDEVICENAME]; | 
|  |  | 
|  | /* If no device name was specified, retrieve the device name | 
|  | * from the DEVMODE structure from the DC's physDev. | 
|  | * (See CreateCompatibleDC) */ | 
|  | if ( !device && *pdev ) | 
|  | { | 
|  | physDev = *pdev; | 
|  | strcpy(deviceA, physDev->Devmode->dmPublic.dmDeviceName); | 
|  | } | 
|  | else | 
|  | WideCharToMultiByte(CP_ACP, 0, device, -1, deviceA, sizeof(deviceA), NULL, NULL); | 
|  | pi = PSDRV_FindPrinterInfo(deviceA); | 
|  |  | 
|  | TRACE("(%s %s %s %p)\n", debugstr_w(driver), debugstr_w(device), | 
|  | debugstr_w(output), initData); | 
|  |  | 
|  | if(!pi) return FALSE; | 
|  |  | 
|  | if(!pi->Fonts) { | 
|  | MESSAGE("To use WINEPS you need to install some AFM files.\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | physDev = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*physDev) ); | 
|  | if (!physDev) return FALSE; | 
|  | *pdev = physDev; | 
|  | physDev->hdc = hdc; | 
|  |  | 
|  | physDev->pi = pi; | 
|  |  | 
|  | physDev->Devmode = HeapAlloc( PSDRV_Heap, 0, sizeof(PSDRV_DEVMODEA) ); | 
|  | if(!physDev->Devmode) { | 
|  | HeapFree( PSDRV_Heap, 0, physDev ); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | memcpy( physDev->Devmode, pi->Devmode, sizeof(PSDRV_DEVMODEA) ); | 
|  |  | 
|  | physDev->logPixelsX = physDev->pi->ppd->DefaultResolution; | 
|  | physDev->logPixelsY = physDev->pi->ppd->DefaultResolution; | 
|  |  | 
|  | if (output) { | 
|  | physDev->job.output = HEAP_strdupWtoA( PSDRV_Heap, 0, output ); | 
|  | } else | 
|  | physDev->job.output = NULL; | 
|  | physDev->job.hJob = 0; | 
|  |  | 
|  | if(initData) { | 
|  | DEVMODEA *devmodeA = DEVMODEdupWtoA(PSDRV_Heap, initData); | 
|  | PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODEA *)devmodeA, pi); | 
|  | HeapFree(PSDRV_Heap, 0, devmodeA); | 
|  | } | 
|  |  | 
|  | PSDRV_UpdateDevCaps(physDev); | 
|  | SelectObject( hdc, PSDRV_DefaultFont ); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /********************************************************************** | 
|  | *	     PSDRV_DeleteDC | 
|  | */ | 
|  | BOOL PSDRV_DeleteDC( PSDRV_PDEVICE *physDev ) | 
|  | { | 
|  | TRACE("\n"); | 
|  |  | 
|  | HeapFree( PSDRV_Heap, 0, physDev->Devmode ); | 
|  | HeapFree( PSDRV_Heap, 0, physDev->job.output ); | 
|  | HeapFree( PSDRV_Heap, 0, physDev ); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /********************************************************************** | 
|  | *	     ResetDC   (WINEPS.@) | 
|  | */ | 
|  | HDC PSDRV_ResetDC( PSDRV_PDEVICE *physDev, const DEVMODEW *lpInitData ) | 
|  | { | 
|  | if(lpInitData) { | 
|  | HRGN hrgn; | 
|  | DEVMODEA *devmodeA = DEVMODEdupWtoA(PSDRV_Heap, lpInitData); | 
|  | PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODEA *)devmodeA, physDev->pi); | 
|  | HeapFree(PSDRV_Heap, 0, devmodeA); | 
|  | PSDRV_UpdateDevCaps(physDev); | 
|  | hrgn = CreateRectRgn(0, 0, physDev->horzRes, physDev->vertRes); | 
|  | SelectVisRgn16(HDC_16(physDev->hdc), HRGN_16(hrgn)); | 
|  | DeleteObject(hrgn); | 
|  | } | 
|  | return physDev->hdc; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GetDeviceCaps    (WINEPS.@) | 
|  | */ | 
|  | INT PSDRV_GetDeviceCaps( PSDRV_PDEVICE *physDev, INT cap ) | 
|  | { | 
|  | switch(cap) | 
|  | { | 
|  | case DRIVERVERSION: | 
|  | return 0; | 
|  | case TECHNOLOGY: | 
|  | return DT_RASPRINTER; | 
|  | case HORZSIZE: | 
|  | return MulDiv(physDev->horzSize, 100, | 
|  | physDev->Devmode->dmPublic.dmScale); | 
|  | case VERTSIZE: | 
|  | return MulDiv(physDev->vertSize, 100, | 
|  | physDev->Devmode->dmPublic.dmScale); | 
|  | case HORZRES: | 
|  | return physDev->horzRes; | 
|  | case VERTRES: | 
|  | return physDev->vertRes; | 
|  | case BITSPIXEL: | 
|  | return physDev->pi->ppd->ColorDevice ? 8 : 1; | 
|  | case PLANES: | 
|  | return 1; | 
|  | case NUMBRUSHES: | 
|  | return -1; | 
|  | case NUMPENS: | 
|  | return 10; | 
|  | case NUMMARKERS: | 
|  | return 0; | 
|  | case NUMFONTS: | 
|  | return 39; | 
|  | case NUMCOLORS: | 
|  | return (physDev->pi->ppd->ColorDevice ? 256 : -1); | 
|  | case PDEVICESIZE: | 
|  | return sizeof(PSDRV_PDEVICE); | 
|  | case CURVECAPS: | 
|  | return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE | | 
|  | CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT); | 
|  | case LINECAPS: | 
|  | return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE | | 
|  | LC_STYLED | LC_WIDESTYLED | LC_INTERIORS); | 
|  | case POLYGONALCAPS: | 
|  | return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE | | 
|  | PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS); | 
|  | case TEXTCAPS: | 
|  | return TC_CR_ANY | TC_VA_ABLE; /* psdrv 0x59f7 */ | 
|  | case CLIPCAPS: | 
|  | return CP_RECTANGLE; | 
|  | case RASTERCAPS: | 
|  | return (RC_BITBLT | RC_BITMAP64 | RC_GDI20_OUTPUT | RC_DIBTODEV | | 
|  | RC_STRETCHBLT | RC_STRETCHDIB); /* psdrv 0x6e99 */ | 
|  | /* Are aspect[XY] and logPixels[XY] correct? */ | 
|  | /* Need to handle different res in x and y => fix ppd */ | 
|  | case ASPECTX: | 
|  | case ASPECTY: | 
|  | return physDev->pi->ppd->DefaultResolution; | 
|  | case ASPECTXY: | 
|  | return (int)hypot( (double)physDev->pi->ppd->DefaultResolution, | 
|  | (double)physDev->pi->ppd->DefaultResolution ); | 
|  | case LOGPIXELSX: | 
|  | return MulDiv(physDev->logPixelsX, | 
|  | physDev->Devmode->dmPublic.dmScale, 100); | 
|  | case LOGPIXELSY: | 
|  | return MulDiv(physDev->logPixelsY, | 
|  | physDev->Devmode->dmPublic.dmScale, 100); | 
|  | case SIZEPALETTE: | 
|  | return 0; | 
|  | case NUMRESERVED: | 
|  | return 0; | 
|  | case COLORRES: | 
|  | return 0; | 
|  | case PHYSICALWIDTH: | 
|  | return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ? | 
|  | physDev->PageSize.cy : physDev->PageSize.cx; | 
|  | case PHYSICALHEIGHT: | 
|  | return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ? | 
|  | physDev->PageSize.cx : physDev->PageSize.cy; | 
|  | case PHYSICALOFFSETX: | 
|  | if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) { | 
|  | if(physDev->pi->ppd->LandscapeOrientation == -90) | 
|  | return physDev->PageSize.cy - physDev->ImageableArea.top; | 
|  | else | 
|  | return physDev->ImageableArea.bottom; | 
|  | } | 
|  | return physDev->ImageableArea.left; | 
|  |  | 
|  | case PHYSICALOFFSETY: | 
|  | if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) { | 
|  | if(physDev->pi->ppd->LandscapeOrientation == -90) | 
|  | return physDev->PageSize.cx - physDev->ImageableArea.right; | 
|  | else | 
|  | return physDev->ImageableArea.left; | 
|  | } | 
|  | return physDev->PageSize.cy - physDev->ImageableArea.top; | 
|  |  | 
|  | case SCALINGFACTORX: | 
|  | case SCALINGFACTORY: | 
|  | case VREFRESH: | 
|  | case DESKTOPVERTRES: | 
|  | case DESKTOPHORZRES: | 
|  | case BTLALIGNMENT: | 
|  | return 0; | 
|  | default: | 
|  | FIXME("(%p): unsupported capability %d, will return 0\n", physDev->hdc, cap ); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /********************************************************************** | 
|  | *		PSDRV_FindPrinterInfo | 
|  | */ | 
|  | PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) | 
|  | { | 
|  | static PRINTERINFO *PSDRV_PrinterList; | 
|  | DWORD type = REG_BINARY, needed, res, dwPaperSize; | 
|  | PRINTERINFO *pi = PSDRV_PrinterList, **last = &PSDRV_PrinterList; | 
|  | FONTNAME *font; | 
|  | const AFM *afm; | 
|  | HANDLE hPrinter; | 
|  | const char *ppd = NULL; | 
|  | DWORD ppdType; | 
|  | char* ppdFileName = NULL; | 
|  | HKEY hkey; | 
|  | BOOL using_default_devmode = FALSE; | 
|  |  | 
|  | TRACE("'%s'\n", name); | 
|  |  | 
|  | /* | 
|  | *	If this loop completes, last will point to the 'next' element of the | 
|  | *	final PRINTERINFO in the list | 
|  | */ | 
|  | for( ; pi; last = &pi->next, pi = pi->next) | 
|  | if(!strcmp(pi->FriendlyName, name)) | 
|  | return pi; | 
|  |  | 
|  | pi = *last = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*pi) ); | 
|  | if (pi == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (!(pi->FriendlyName = HeapAlloc( PSDRV_Heap, 0, strlen(name)+1 ))) goto fail; | 
|  | strcpy( pi->FriendlyName, name ); | 
|  |  | 
|  | /* Use Get|SetPrinterDataExA instead? */ | 
|  |  | 
|  | res = DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type, | 
|  | NULL, 0, &needed ); | 
|  |  | 
|  | if(res == ERROR_INVALID_PRINTER_NAME || needed != sizeof(DefaultDevmode)) { | 
|  | pi->Devmode = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) ); | 
|  | if (pi->Devmode == NULL) | 
|  | goto cleanup; | 
|  | memcpy(pi->Devmode, &DefaultDevmode, sizeof(DefaultDevmode) ); | 
|  | strcpy(pi->Devmode->dmPublic.dmDeviceName,name); | 
|  | using_default_devmode = TRUE; | 
|  |  | 
|  | /* need to do something here AddPrinter?? */ | 
|  | } | 
|  | else { | 
|  | pi->Devmode = HeapAlloc( PSDRV_Heap, 0, needed ); | 
|  | DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type, | 
|  | (LPBYTE)pi->Devmode, needed, &needed); | 
|  | } | 
|  |  | 
|  | if (OpenPrinterA (pi->FriendlyName, &hPrinter, NULL) == 0) { | 
|  | ERR ("OpenPrinterA failed with code %li\n", GetLastError ()); | 
|  | goto cleanup; | 
|  | } | 
|  |  | 
|  | #ifdef HAVE_CUPS_CUPS_H | 
|  | if (cupshandle != (void*)-1) { | 
|  | typeof(cupsGetPPD) * pcupsGetPPD = NULL; | 
|  |  | 
|  | pcupsGetPPD = wine_dlsym(cupshandle, "cupsGetPPD", NULL, 0); | 
|  | if (pcupsGetPPD) { | 
|  | ppd = pcupsGetPPD(name); | 
|  |  | 
|  | if (ppd) { | 
|  | needed=strlen(ppd)+1; | 
|  | ppdFileName=HeapAlloc(PSDRV_Heap, 0, needed); | 
|  | memcpy(ppdFileName, ppd, needed); | 
|  | ppdType=REG_SZ; | 
|  | res = ERROR_SUCCESS; | 
|  | /* we should unlink() that file later */ | 
|  | } else { | 
|  | res = ERROR_FILE_NOT_FOUND; | 
|  | WARN("Did not find ppd for %s\n",name); | 
|  | } | 
|  | } | 
|  | } | 
|  | #endif | 
|  | if (!ppdFileName) { | 
|  | res = GetPrinterDataA(hPrinter, "PPD File", NULL, NULL, 0, &needed); | 
|  | if ((res==ERROR_SUCCESS) || (res==ERROR_MORE_DATA)) { | 
|  | ppdFileName=HeapAlloc(PSDRV_Heap, 0, needed); | 
|  | res = GetPrinterDataA(hPrinter, "PPD File", &ppdType, ppdFileName, needed, &needed); | 
|  | } | 
|  | } | 
|  | /* Look for a ppd file for this printer in the config file. | 
|  | * First look under that printer's name, and then under 'generic' | 
|  | */ | 
|  | /* @@ Wine registry key: HKLM\Software\Wine\Wine\Config\ppd */ | 
|  | if((res != ERROR_SUCCESS) && !RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd", &hkey)) | 
|  | { | 
|  | const char* value_name; | 
|  |  | 
|  | if (RegQueryValueExA(hkey, name, 0, NULL, NULL, &needed) == ERROR_SUCCESS) { | 
|  | value_name=name; | 
|  | } else if (RegQueryValueExA(hkey, "generic", 0, NULL, NULL, &needed) == ERROR_SUCCESS) { | 
|  | value_name="generic"; | 
|  | } else { | 
|  | value_name=NULL; | 
|  | } | 
|  | if (value_name) { | 
|  | ppdFileName=HeapAlloc(PSDRV_Heap, 0, needed); | 
|  | RegQueryValueExA(hkey, value_name, 0, &ppdType, ppdFileName, &needed); | 
|  | } | 
|  | RegCloseKey(hkey); | 
|  | } | 
|  |  | 
|  | if (!ppdFileName) { | 
|  | res = ERROR_FILE_NOT_FOUND; | 
|  | ERR ("Error %li getting PPD file name for printer '%s'\n", res, name); | 
|  | goto closeprinter; | 
|  | } else { | 
|  | res = ERROR_SUCCESS; | 
|  | if (ppdType==REG_EXPAND_SZ) { | 
|  | char* tmp; | 
|  |  | 
|  | /* Expand environment variable references */ | 
|  | needed=ExpandEnvironmentStringsA(ppdFileName,NULL,0); | 
|  | tmp=HeapAlloc(PSDRV_Heap, 0, needed); | 
|  | ExpandEnvironmentStringsA(ppdFileName,tmp,needed); | 
|  | HeapFree(PSDRV_Heap, 0, ppdFileName); | 
|  | ppdFileName=tmp; | 
|  | } | 
|  | } | 
|  |  | 
|  | pi->ppd = PSDRV_ParsePPD(ppdFileName); | 
|  | if(!pi->ppd) { | 
|  | MESSAGE("Couldn't find PPD file '%s', expect a crash now!\n", | 
|  | ppdFileName); | 
|  | goto closeprinter; | 
|  | } | 
|  |  | 
|  | /* Some gimp-print ppd files don't contain a DefaultResolution line | 
|  | set it to 300 if it's not specified */ | 
|  | if(pi->ppd->DefaultResolution == 0) | 
|  | pi->ppd->DefaultResolution = 300; | 
|  |  | 
|  | if(using_default_devmode) { | 
|  | DWORD papersize; | 
|  |  | 
|  | if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE | LOCALE_RETURN_NUMBER, | 
|  | (LPWSTR)&papersize, sizeof(papersize)/sizeof(WCHAR))) { | 
|  | PSDRV_DEVMODEA dm; | 
|  | memset(&dm, 0, sizeof(dm)); | 
|  | dm.dmPublic.dmFields = DM_PAPERSIZE; | 
|  | dm.dmPublic.u1.s1.dmPaperSize = papersize; | 
|  | PSDRV_MergeDevmodes(pi->Devmode, &dm, pi); | 
|  | } | 
|  | DrvSetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, | 
|  | REG_BINARY, (LPBYTE)pi->Devmode, sizeof(DefaultDevmode) ); | 
|  | } | 
|  |  | 
|  | if(pi->ppd->DefaultPageSize) { /* We'll let the ppd override the devmode */ | 
|  | PSDRV_DEVMODEA dm; | 
|  | memset(&dm, 0, sizeof(dm)); | 
|  | dm.dmPublic.dmFields = DM_PAPERSIZE; | 
|  | dm.dmPublic.u1.s1.dmPaperSize = pi->ppd->DefaultPageSize->WinPage; | 
|  | PSDRV_MergeDevmodes(pi->Devmode, &dm, pi); | 
|  | } | 
|  |  | 
|  | /* | 
|  | *	This is a hack.  The default paper size should be read in as part of | 
|  | *	the Devmode structure, but Wine doesn't currently provide a convenient | 
|  | *	way to configure printers. | 
|  | */ | 
|  | res = GetPrinterDataA (hPrinter, "Paper Size", NULL, (LPBYTE) &dwPaperSize, | 
|  | sizeof (DWORD), &needed); | 
|  | if (res == ERROR_SUCCESS) | 
|  | pi->Devmode->dmPublic.u1.s1.dmPaperSize = (SHORT) dwPaperSize; | 
|  | else if (res == ERROR_FILE_NOT_FOUND) | 
|  | TRACE ("No 'Paper Size' for printer '%s'\n", name); | 
|  | else { | 
|  | ERR ("GetPrinterDataA returned %li\n", res); | 
|  | goto closeprinter; | 
|  | } | 
|  |  | 
|  | /* Duplex is indicated by the setting of the DM_DUPLEX bit in dmFields. | 
|  | WinDuplex == 0 is a special case which means that the ppd has a | 
|  | *DefaultDuplex: NotCapable entry.  In this case we'll try not to confuse | 
|  | apps and set dmDuplex to DMDUP_SIMPLEX but leave the DM_DUPLEX clear. | 
|  | PSDRV_WriteHeader understands this and copes. */ | 
|  | pi->Devmode->dmPublic.dmFields &= ~DM_DUPLEX; | 
|  | if(pi->ppd->DefaultDuplex) { | 
|  | pi->Devmode->dmPublic.dmDuplex = pi->ppd->DefaultDuplex->WinDuplex; | 
|  | if(pi->Devmode->dmPublic.dmDuplex != 0) | 
|  | pi->Devmode->dmPublic.dmFields |= DM_DUPLEX; | 
|  | else | 
|  | pi->Devmode->dmPublic.dmDuplex = DMDUP_SIMPLEX; | 
|  | } | 
|  |  | 
|  | res = EnumPrinterDataExA (hPrinter, "PrinterDriverData\\FontSubTable", NULL, | 
|  | 0, &needed, &pi->FontSubTableSize); | 
|  | if (res == ERROR_SUCCESS || res == ERROR_FILE_NOT_FOUND) { | 
|  | TRACE ("No 'FontSubTable' for printer '%s'\n", name); | 
|  | } | 
|  | else if (res == ERROR_MORE_DATA) { | 
|  | pi->FontSubTable = HeapAlloc (PSDRV_Heap, 0, needed); | 
|  | if (pi->FontSubTable == NULL) { | 
|  | ERR ("Failed to allocate %li bytes from heap\n", needed); | 
|  | goto closeprinter; | 
|  | } | 
|  |  | 
|  | res = EnumPrinterDataExA (hPrinter, "PrinterDriverData\\FontSubTable", | 
|  | (LPBYTE) pi->FontSubTable, needed, &needed, | 
|  | &pi->FontSubTableSize); | 
|  | if (res != ERROR_SUCCESS) { | 
|  | ERR ("EnumPrinterDataExA returned %li\n", res); | 
|  | goto closeprinter; | 
|  | } | 
|  | } | 
|  | else { | 
|  | ERR("EnumPrinterDataExA returned %li\n", res); | 
|  | goto closeprinter; | 
|  | } | 
|  |  | 
|  | if (ClosePrinter (hPrinter) == 0) { | 
|  | ERR ("ClosePrinter failed with code %li\n", GetLastError ()); | 
|  | goto cleanup; | 
|  | } | 
|  |  | 
|  | pi->next = NULL; | 
|  | pi->Fonts = NULL; | 
|  |  | 
|  | for(font = pi->ppd->InstalledFonts; font; font = font->next) { | 
|  | afm = PSDRV_FindAFMinList(PSDRV_AFMFontList, font->Name); | 
|  | if(!afm) { | 
|  | TRACE( "Couldn't find AFM file for installed printer font '%s' - " | 
|  | "ignoring\n", font->Name); | 
|  | } | 
|  | else { | 
|  | BOOL added; | 
|  | if (PSDRV_AddAFMtoList(&pi->Fonts, afm, &added) == FALSE) { | 
|  | PSDRV_FreeAFMList(pi->Fonts); | 
|  | goto cleanup; | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  | if (ppd) unlink(ppd); | 
|  | return pi; | 
|  |  | 
|  | closeprinter: | 
|  | ClosePrinter(hPrinter); | 
|  | cleanup: | 
|  | HeapFree(PSDRV_Heap, 0, ppdFileName); | 
|  | HeapFree(PSDRV_Heap, 0, pi->FontSubTable); | 
|  | HeapFree(PSDRV_Heap, 0, pi->FriendlyName); | 
|  | HeapFree(PSDRV_Heap, 0, pi->Devmode); | 
|  | fail: | 
|  | HeapFree(PSDRV_Heap, 0, pi); | 
|  | if (ppd) unlink(ppd); | 
|  | *last = NULL; | 
|  | return NULL; | 
|  | } |