2 * PostScript driver initialization functions
4 * Copyright 1998 Huw D M Davies
5 * Copyright 2001 Marcus Meissner
16 #include "debugtools.h"
23 # include <cups/cups.h>
26 DEFAULT_DEBUG_CHANNEL(psdrv
);
28 static BOOL
PSDRV_CreateDC( DC
*dc
, LPCSTR driver
, LPCSTR device
,
29 LPCSTR output
, const DEVMODEA
* initData
);
30 static BOOL
PSDRV_DeleteDC( DC
*dc
);
32 static const DC_FUNCTIONS PSDRV_Funcs
=
35 NULL
, /* pAbortPath */
39 NULL
, /* pBeginPath */
41 NULL
, /* pBitmapBits */
42 NULL
, /* pChoosePixelFormat */
43 PSDRV_Chord
, /* pChord */
44 NULL
, /* pCloseFigure */
45 NULL
, /* pCreateBitmap */
46 PSDRV_CreateDC
, /* pCreateDC */
47 NULL
, /* pCreateDIBSection */
48 PSDRV_DeleteDC
, /* pDeleteDC */
49 NULL
, /* pDeleteObject */
50 NULL
, /* pDescribePixelFormat */
51 PSDRV_DeviceCapabilities
, /* pDeviceCapabilities */
52 PSDRV_Ellipse
, /* pEllipse */
53 PSDRV_EndDoc
, /* pEndDoc */
54 PSDRV_EndPage
, /* pEndPage */
56 PSDRV_EnumDeviceFonts
, /* pEnumDeviceFonts */
57 PSDRV_Escape
, /* pEscape */
58 NULL
, /* pExcludeClipRect */
59 PSDRV_ExtDeviceMode
, /* pExtDeviceMode */
60 NULL
, /* pExtFloodFill */
61 PSDRV_ExtTextOut
, /* pExtTextOut */
64 NULL
, /* pFlattenPath */
66 PSDRV_GetCharWidth
, /* pGetCharWidth */
67 NULL
, /* pGetDCOrgEx */
68 NULL
, /* pGetDeviceGammaRamp */
70 NULL
, /* pGetPixelFormat */
71 PSDRV_GetTextExtentPoint
, /* pGetTextExtentPoint */
72 PSDRV_GetTextMetrics
, /* pGetTextMetrics */
73 NULL
, /* pIntersectClipRect */
74 NULL
, /* pInvertRgn */
75 PSDRV_LineTo
, /* pLineTo */
77 NULL
, /* pOffsetClipRgn */
78 NULL
, /* pOffsetViewportOrg (optional) */
79 NULL
, /* pOffsetWindowOrg (optional) */
81 PSDRV_PatBlt
, /* pPatBlt */
83 NULL
, /* pPolyBezier */
84 NULL
, /* pPolyBezierTo */
86 PSDRV_PolyPolygon
, /* pPolyPolygon */
87 PSDRV_PolyPolyline
, /* pPolyPolyline */
88 PSDRV_Polygon
, /* pPolygon */
89 PSDRV_Polyline
, /* pPolyline */
90 NULL
, /* pPolylineTo */
91 NULL
, /* pRealizePalette */
92 PSDRV_Rectangle
, /* pRectangle */
93 NULL
, /* pRestoreDC */
94 PSDRV_RoundRect
, /* pRoundRect */
96 NULL
, /* pScaleViewportExt (optional) */
97 NULL
, /* pScaleWindowExt (optional) */
98 NULL
, /* pSelectClipPath */
99 NULL
, /* pSelectClipRgn */
100 PSDRV_SelectObject
, /* pSelectObject */
101 NULL
, /* pSelectPalette */
102 PSDRV_SetBkColor
, /* pSetBkColor */
103 NULL
, /* pSetBkMode */
104 PSDRV_SetDeviceClipping
, /* pSetDeviceClipping */
105 NULL
, /* pSetDeviceGammaRamp */
106 NULL
, /* pSetDIBitsToDevice */
107 NULL
, /* pSetMapMode (optional) */
108 NULL
, /* pSetMapperFlags */
109 PSDRV_SetPixel
, /* pSetPixel */
110 NULL
, /* pSetPixelFormat */
111 NULL
, /* pSetPolyFillMode */
113 NULL
, /* pSetRelAbs */
114 NULL
, /* pSetStretchBltMode */
115 NULL
, /* pSetTextAlign */
116 NULL
, /* pSetTextCharacterExtra */
117 PSDRV_SetTextColor
, /* pSetTextColor */
118 NULL
, /* pSetTextJustification */
119 NULL
, /* pSetViewportExt (optional) */
120 NULL
, /* pSetViewportOrg (optional) */
121 NULL
, /* pSetWindowExt (optional) */
122 NULL
, /* pSetWindowOrg (optional) */
123 PSDRV_StartDoc
, /* pStartDoc */
124 PSDRV_StartPage
, /* pStartPage */
125 NULL
, /* pStretchBlt */
126 PSDRV_StretchDIBits
, /* pStretchDIBits */
127 NULL
, /* pStrokeAndFillPath */
128 NULL
, /* pStrokePath */
129 NULL
, /* pSwapBuffers */
130 NULL
/* pWidenPath */
134 /* Default entries for devcaps */
136 static DeviceCaps PSDRV_DevCaps
= {
138 /* technology */ DT_RASPRINTER
,
149 /* numColors */ 0xffff,
151 /* curveCaps */ CC_CIRCLES
| CC_PIE
| CC_CHORD
| CC_ELLIPSES
|
152 CC_WIDE
| CC_STYLED
| CC_WIDESTYLED
| CC_INTERIORS
|
154 /* lineCaps */ LC_POLYLINE
| LC_MARKER
| LC_POLYMARKER
| LC_WIDE
|
155 LC_STYLED
| LC_WIDESTYLED
| LC_INTERIORS
,
156 /* polygoalnCaps */ PC_POLYGON
| PC_RECTANGLE
| PC_WINDPOLYGON
|
157 PC_SCANLINE
| PC_WIDE
| PC_STYLED
| PC_WIDESTYLED
|
159 /* textCaps */ TC_CR_ANY
, /* psdrv 0x59f7 */
160 /* clipCaps */ CP_RECTANGLE
,
161 /* rasterCaps */ RC_BITBLT
| RC_BITMAP64
| RC_GDI20_OUTPUT
|
162 RC_DIBTODEV
| RC_STRETCHBLT
|
163 RC_STRETCHDIB
, /* psdrv 0x6e99 */
168 /* logPixelsX */ 600,
169 /* logPixelsY */ 600,
171 /* palette size */ 0,
174 static PSDRV_DEVMODEA DefaultDevmode
=
177 /* dmDeviceName */ "Wine PostScript Driver",
178 /* dmSpecVersion */ 0x30a,
179 /* dmDriverVersion */ 0x001,
180 /* dmSize */ sizeof(DEVMODEA
),
181 /* dmDriverExtra */ 0,
182 /* dmFields */ DM_ORIENTATION
| DM_PAPERSIZE
| DM_SCALE
|
183 DM_COPIES
| DM_DEFAULTSOURCE
| DM_COLOR
|
184 DM_DUPLEX
| DM_YRESOLUTION
| DM_TTOPTION
,
187 /* dmOrientation */ DMORIENT_PORTRAIT
,
188 /* dmPaperSize */ DMPAPER_A4
,
189 /* dmPaperLength */ 2969,
190 /* dmPaperWidth */ 2101
193 /* dmScale */ 100, /* ?? */
195 /* dmDefaultSource */ DMBIN_AUTO
,
196 /* dmPrintQuality */ 0,
197 /* dmColor */ DMCOLOR_COLOR
,
199 /* dmYResolution */ 0,
200 /* dmTTOption */ DMTT_SUBDEV
,
203 /* dmUnusedPadding */ 0,
204 /* dmBitsPerPel */ 0,
206 /* dmPelsHeight */ 0,
207 /* dmDisplayFlags */ 0,
208 /* dmDisplayFrequency */ 0,
212 /* dmDitherType */ 0,
215 /* dmPanningWidth */ 0,
216 /* dmPanningHeight */ 0
222 /* numInstalledOptions */ 0
226 HANDLE PSDRV_Heap
= 0;
228 static HANDLE PSDRV_DefaultFont
= 0;
229 static LOGFONTA DefaultLogFont
= {
230 100, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
, 0, 0,
231 DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
, ""
234 /*********************************************************************
237 * Initializes font metrics and registers driver. Called from GDI_Init()
240 BOOL WINAPI
PSDRV_Init( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
242 TRACE("(0x%4x, 0x%08lx, %p)\n", hinst
, reason
, reserved
);
246 case DLL_PROCESS_ATTACH
:
248 PSDRV_Heap
= HeapCreate(0, 0x10000, 0);
249 if (PSDRV_Heap
== (HANDLE
)NULL
)
252 if (PSDRV_GetFontMetrics() == FALSE
) {
253 HeapDestroy(PSDRV_Heap
);
257 PSDRV_DefaultFont
= CreateFontIndirectA(&DefaultLogFont
);
258 if (PSDRV_DefaultFont
== (HANDLE
)NULL
) {
259 HeapDestroy(PSDRV_Heap
);
263 /* Register driver as "WINEPS", "WINEPS.DLL" and "WINEPS.DRV"
264 to allow an easy configuring for users */
266 if (DRIVER_RegisterDriver("WINEPS", &PSDRV_Funcs
) == FALSE
) {
267 HeapDestroy(PSDRV_Heap
);
271 if (DRIVER_RegisterDriver("WINEPS.DLL", &PSDRV_Funcs
) == FALSE
) {
272 DRIVER_UnregisterDriver("WINEPS");
273 HeapDestroy(PSDRV_Heap
);
277 if (DRIVER_RegisterDriver("WINEPS.DRV", &PSDRV_Funcs
) == FALSE
) {
278 DRIVER_UnregisterDriver("WINEPS");
279 DRIVER_UnregisterDriver("WINEPS.DLL");
280 HeapDestroy(PSDRV_Heap
);
286 case DLL_PROCESS_DETACH
:
288 DeleteObject( PSDRV_DefaultFont
);
289 HeapDestroy( PSDRV_Heap
);
290 DRIVER_UnregisterDriver( "WINEPS" );
291 DRIVER_UnregisterDriver( "WINEPS.DLL" );
292 DRIVER_UnregisterDriver( "WINEPS.DRV" );
301 /**********************************************************************
304 static BOOL
PSDRV_CreateDC( DC
*dc
, LPCSTR driver
, LPCSTR device
,
305 LPCSTR output
, const DEVMODEA
* initData
)
307 PSDRV_PDEVICE
*physDev
;
311 INT width
= 0, height
= 0;
313 /* If no device name was specified, retrieve the device name
314 * from the DEVMODE structure from the DC's physDev.
315 * (See CreateCompatibleDC) */
316 if ( !device
&& dc
->physDev
)
318 physDev
= (PSDRV_PDEVICE
*)dc
->physDev
;
319 device
= physDev
->Devmode
->dmPublic
.dmDeviceName
;
321 pi
= PSDRV_FindPrinterInfo(device
);
323 TRACE("(%s %s %s %p)\n", driver
, device
, output
, initData
);
325 if(!pi
) return FALSE
;
328 MESSAGE("To use WINEPS you need to install some AFM files.\n");
332 physDev
= (PSDRV_PDEVICE
*)HeapAlloc( PSDRV_Heap
, HEAP_ZERO_MEMORY
,
334 if (!physDev
) return FALSE
;
335 dc
->physDev
= physDev
;
339 physDev
->Devmode
= (PSDRV_DEVMODEA
*)HeapAlloc( PSDRV_Heap
, 0,
340 sizeof(PSDRV_DEVMODEA
) );
341 if(!physDev
->Devmode
) {
342 HeapFree( PSDRV_Heap
, 0, physDev
);
346 memcpy( physDev
->Devmode
, pi
->Devmode
, sizeof(PSDRV_DEVMODEA
) );
349 PSDRV_MergeDevmodes(physDev
->Devmode
, (PSDRV_DEVMODEA
*)initData
, pi
);
353 devCaps
= HeapAlloc( PSDRV_Heap
, 0, sizeof(PSDRV_DevCaps
) );
354 memcpy(devCaps
, &PSDRV_DevCaps
, sizeof(PSDRV_DevCaps
));
356 /* Are aspect[XY] and logPixels[XY] correct? */
357 /* Need to handle different res in x and y => fix ppd */
358 devCaps
->aspectX
= devCaps
->logPixelsX
=
359 physDev
->pi
->ppd
->DefaultResolution
;
360 devCaps
->aspectY
= devCaps
->logPixelsY
=
361 physDev
->pi
->ppd
->DefaultResolution
;
362 devCaps
->aspectXY
= (int)hypot( (double)devCaps
->aspectX
,
363 (double)devCaps
->aspectY
);
366 for(page
= pi
->ppd
->PageSizes
; page
; page
= page
->next
) {
367 if(page
->WinPage
== physDev
->Devmode
->dmPublic
.u1
.s1
.dmPaperSize
)
371 FIXME("Can't find page\n");
372 physDev
->PageSize
.left
= 0;
373 physDev
->PageSize
.right
= 0;
374 physDev
->PageSize
.bottom
= 0;
375 physDev
->PageSize
.top
= 0;
376 } else if(page
->ImageableArea
) { /* PageSize is in device units */
377 physDev
->PageSize
.left
= page
->ImageableArea
->llx
*
378 devCaps
->logPixelsX
/ 72;
379 physDev
->PageSize
.right
= page
->ImageableArea
->urx
*
380 devCaps
->logPixelsX
/ 72;
381 physDev
->PageSize
.bottom
= page
->ImageableArea
->lly
*
382 devCaps
->logPixelsY
/ 72;
383 physDev
->PageSize
.top
= page
->ImageableArea
->ury
*
384 devCaps
->logPixelsY
/ 72;
386 physDev
->PageSize
.left
= physDev
->PageSize
.bottom
= 0;
387 physDev
->PageSize
.right
= page
->PaperDimension
->x
*
388 devCaps
->logPixelsX
/ 72;
389 physDev
->PageSize
.top
= page
->PaperDimension
->y
*
390 devCaps
->logPixelsY
/ 72;
392 TRACE("PageSize = (%d,%d - %d,%d)\n", physDev
->PageSize
.left
, physDev
->PageSize
.bottom
, physDev
->PageSize
.right
, physDev
->PageSize
.top
);
394 /* these are in device units */
395 width
= physDev
->PageSize
.right
- physDev
->PageSize
.left
;
396 height
= physDev
->PageSize
.top
- physDev
->PageSize
.bottom
;
398 if(physDev
->Devmode
->dmPublic
.u1
.s1
.dmOrientation
== DMORIENT_PORTRAIT
) {
399 devCaps
->horzRes
= width
;
400 devCaps
->vertRes
= height
;
402 devCaps
->horzRes
= height
;
403 devCaps
->vertRes
= width
;
406 /* these are in mm */
407 devCaps
->horzSize
= (devCaps
->horzRes
* 25.4) / devCaps
->logPixelsX
;
408 devCaps
->vertSize
= (devCaps
->vertRes
* 25.4) / devCaps
->logPixelsY
;
410 TRACE("devcaps: horzSize = %dmm, vertSize = %dmm, "
411 "horzRes = %d, vertRes = %d\n",
412 devCaps
->horzSize
, devCaps
->vertSize
,
413 devCaps
->horzRes
, devCaps
->vertRes
);
415 if(physDev
->pi
->ppd
->ColorDevice
) {
416 devCaps
->bitsPixel
= 8;
417 devCaps
->numColors
= 256;
418 /* FIXME are these values OK? */
423 dc
->devCaps
= devCaps
;
425 dc
->hVisRgn
= CreateRectRgn(0, 0, dc
->devCaps
->horzRes
,
426 dc
->devCaps
->vertRes
);
428 dc
->hFont
= PSDRV_DefaultFont
;
429 physDev
->job
.output
= output
?
430 HEAP_strdupA( PSDRV_Heap
, 0, output
) :
431 HEAP_strdupA( PSDRV_Heap
, 0, "LPT1:" ); /* HACK */
432 physDev
->job
.hJob
= 0;
437 /**********************************************************************
440 static BOOL
PSDRV_DeleteDC( DC
*dc
)
442 PSDRV_PDEVICE
*physDev
= (PSDRV_PDEVICE
*)dc
->physDev
;
446 HeapFree( PSDRV_Heap
, 0, physDev
->Devmode
);
447 HeapFree( PSDRV_Heap
, 0, physDev
->job
.output
);
448 HeapFree( PSDRV_Heap
, 0, (void *)dc
->devCaps
);
449 HeapFree( PSDRV_Heap
, 0, physDev
);
456 /**********************************************************************
457 * PSDRV_FindPrinterInfo
459 PRINTERINFO
*PSDRV_FindPrinterInfo(LPCSTR name
)
461 static PRINTERINFO
*PSDRV_PrinterList
;
462 DWORD type
= REG_BINARY
, needed
, res
, dwPaperSize
;
463 PRINTERINFO
*pi
= PSDRV_PrinterList
, **last
= &PSDRV_PrinterList
;
467 const char *ppd
= NULL
;
468 char ppdFileName
[256];
471 TRACE("'%s'\n", name
);
474 * If this loop completes, last will point to the 'next' element of the
475 * final PRINTERINFO in the list
477 for( ; pi
; last
= &pi
->next
, pi
= pi
->next
)
478 if(!strcmp(pi
->FriendlyName
, name
))
481 pi
= *last
= HeapAlloc( PSDRV_Heap
, HEAP_ZERO_MEMORY
, sizeof(*pi
) );
485 pi
->FriendlyName
= HEAP_strdupA( PSDRV_Heap
, 0, name
);
486 if (pi
->FriendlyName
== NULL
)
489 /* Use Get|SetPrinterDataExA instead? */
491 res
= DrvGetPrinterData16((LPSTR
)name
, (LPSTR
)INT_PD_DEFAULT_DEVMODE
, &type
,
494 if(res
== ERROR_INVALID_PRINTER_NAME
|| needed
!= sizeof(DefaultDevmode
)) {
495 pi
->Devmode
= HeapAlloc( PSDRV_Heap
, 0, sizeof(DefaultDevmode
) );
496 if (pi
->Devmode
== NULL
)
498 memcpy(pi
->Devmode
, &DefaultDevmode
, sizeof(DefaultDevmode
) );
499 strcpy(pi
->Devmode
->dmPublic
.dmDeviceName
,name
);
500 DrvSetPrinterData16((LPSTR
)name
, (LPSTR
)INT_PD_DEFAULT_DEVMODE
,
501 REG_BINARY
, (LPBYTE
)&DefaultDevmode
, sizeof(DefaultDevmode
) );
503 /* need to do something here AddPrinter?? */
506 pi
->Devmode
= HeapAlloc( PSDRV_Heap
, 0, needed
);
507 DrvGetPrinterData16((LPSTR
)name
, (LPSTR
)INT_PD_DEFAULT_DEVMODE
, &type
,
508 (LPBYTE
)pi
->Devmode
, needed
, &needed
);
511 if (OpenPrinterA (pi
->FriendlyName
, &hPrinter
, NULL
) == 0) {
512 ERR ("OpenPrinterA failed with code %li\n", GetLastError ());
520 ppd
= cupsGetPPD(name
);
523 strncpy(ppdFileName
, ppd
, sizeof(ppdFileName
));
525 /* we should unlink() that file later */
527 res
= ERROR_FILE_NOT_FOUND
;
528 WARN("Did not find ppd for %s\n",name
);
533 if (!ppdFileName
[0]) {
534 res
= GetPrinterDataA (hPrinter
, "PPD File", NULL
, ppdFileName
,
535 sizeof(ppdFileName
), &needed
);
537 /* Look for a ppd file for this printer in the config file.
538 * First look for the names of the printer, then for 'generic'
540 if((res
!= ERROR_SUCCESS
) && !RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\ppd", &hkey
))
542 DWORD count
= sizeof(ppdFileName
);
544 if(RegQueryValueExA(hkey
, name
, 0, &type
, ppdFileName
, &count
) != ERROR_SUCCESS
)
545 RegQueryValueExA(hkey
, "generic", 0, &type
, ppdFileName
, &count
);
550 res
= ERROR_FILE_NOT_FOUND
;
554 if (res
!= ERROR_SUCCESS
) {
555 ERR ("Error %li getting PPD file name for printer '%s'\n", res
, name
);
559 ppdFileName
[sizeof(ppdFileName
) - 1] = '\0';
561 pi
->ppd
= PSDRV_ParsePPD(ppdFileName
);
563 MESSAGE("Couldn't find PPD file '%s', expect a crash now!\n",
569 * This is a hack. The default paper size should be read in as part of
570 * the Devmode structure, but Wine doesn't currently provide a convenient
571 * way to configure printers.
573 res
= GetPrinterDataA (hPrinter
, "Paper Size", NULL
, (LPBYTE
) &dwPaperSize
,
574 sizeof (DWORD
), &needed
);
575 if (res
== ERROR_SUCCESS
)
576 pi
->Devmode
->dmPublic
.u1
.s1
.dmPaperSize
= (SHORT
) dwPaperSize
;
577 else if (res
== ERROR_FILE_NOT_FOUND
)
578 TRACE ("No 'Paper Size' for printer '%s'\n", name
);
580 ERR ("GetPrinterDataA returned %li\n", res
);
584 res
= EnumPrinterDataExA (hPrinter
, "PrinterDriverData\\FontSubTable", NULL
,
585 0, &needed
, &pi
->FontSubTableSize
);
586 if (res
== ERROR_SUCCESS
|| res
== ERROR_FILE_NOT_FOUND
) {
587 TRACE ("No 'FontSubTable' for printer '%s'\n", name
);
589 else if (res
== ERROR_MORE_DATA
) {
590 pi
->FontSubTable
= HeapAlloc (PSDRV_Heap
, 0, needed
);
591 if (pi
->FontSubTable
== NULL
) {
592 ERR ("Failed to allocate %li bytes from heap\n", needed
);
596 res
= EnumPrinterDataExA (hPrinter
, "PrinterDriverData\\FontSubTable",
597 (LPBYTE
) pi
->FontSubTable
, needed
, &needed
,
598 &pi
->FontSubTableSize
);
599 if (res
!= ERROR_SUCCESS
) {
600 ERR ("EnumPrinterDataExA returned %li\n", res
);
605 ERR("EnumPrinterDataExA returned %li\n", res
);
609 if (ClosePrinter (hPrinter
) == 0) {
610 ERR ("ClosePrinter failed with code %li\n", GetLastError ());
617 for(font
= pi
->ppd
->InstalledFonts
; font
; font
= font
->next
) {
618 afm
= PSDRV_FindAFMinList(PSDRV_AFMFontList
, font
->Name
);
620 TRACE( "Couldn't find AFM file for installed printer font '%s' - "
621 "ignoring\n", font
->Name
);
624 if (PSDRV_AddAFMtoList(&pi
->Fonts
, afm
) == FALSE
) {
625 PSDRV_FreeAFMList(pi
->Fonts
);
631 if (ppd
) unlink(ppd
);
635 ClosePrinter(hPrinter
);
637 if (pi
->FontSubTable
)
638 HeapFree(PSDRV_Heap
, 0, pi
->FontSubTable
);
639 if (pi
->FriendlyName
)
640 HeapFree(PSDRV_Heap
, 0, pi
->FriendlyName
);
642 HeapFree(PSDRV_Heap
, 0, pi
->Devmode
);
644 HeapFree(PSDRV_Heap
, 0, pi
);
645 if (ppd
) unlink(ppd
);