kernel32: Update version to Win 10.
[wine.git] / dlls / wineps.drv / init.c
blobad6d6a0737399249c9d8a97c2866aa3e43f04cfe
1 /*
2 * PostScript driver initialization functions
4 * Copyright 1998 Huw D M Davies
5 * Copyright 2001 Marcus Meissner
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <string.h>
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winerror.h"
31 #include "winreg.h"
32 #include "winnls.h"
33 #include "winuser.h"
34 #include "psdrv.h"
35 #include "winspool.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
40 static const PSDRV_DEVMODE DefaultDevmode =
42 { /* dmPublic */
43 /* dmDeviceName */ L"Wine PostScript Driver",
44 /* dmSpecVersion */ 0x30a,
45 /* dmDriverVersion */ 0x001,
46 /* dmSize */ sizeof(DEVMODEW),
47 /* dmDriverExtra */ sizeof(PSDRV_DEVMODE)-sizeof(DEVMODEW),
48 /* dmFields */ DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH |
49 DM_SCALE | DM_COPIES | DM_DEFAULTSOURCE | DM_PRINTQUALITY |
50 DM_COLOR | DM_DUPLEX | DM_YRESOLUTION | DM_TTOPTION |
51 DM_COLLATE | DM_FORMNAME,
52 { /* u1 */
53 { /* s1 */
54 /* dmOrientation */ DMORIENT_PORTRAIT,
55 /* dmPaperSize */ DMPAPER_LETTER,
56 /* dmPaperLength */ 2794,
57 /* dmPaperWidth */ 2159,
58 /* dmScale */ 100,
59 /* dmCopies */ 1,
60 /* dmDefaultSource */ DMBIN_AUTO,
61 /* dmPrintQuality */ 300
64 /* dmColor */ DMCOLOR_COLOR,
65 /* dmDuplex */ DMDUP_SIMPLEX,
66 /* dmYResolution */ 300,
67 /* dmTTOption */ DMTT_SUBDEV,
68 /* dmCollate */ DMCOLLATE_FALSE,
69 /* dmFormName */ L"Letter",
70 /* dmLogPixels */ 0,
71 /* dmBitsPerPel */ 0,
72 /* dmPelsWidth */ 0,
73 /* dmPelsHeight */ 0,
74 { /* u2 */
75 /* dmDisplayFlags */ 0
77 /* dmDisplayFrequency */ 0,
78 /* dmICMMethod */ 0,
79 /* dmICMIntent */ 0,
80 /* dmMediaType */ 0,
81 /* dmDitherType */ 0,
82 /* dmReserved1 */ 0,
83 /* dmReserved2 */ 0,
84 /* dmPanningWidth */ 0,
85 /* dmPanningHeight */ 0
87 { /* dmDocPrivate */
88 /* dummy */ 0
90 { /* dmDrvPrivate */
91 /* numInstalledOptions */ 0
95 HINSTANCE PSDRV_hInstance = 0;
96 HANDLE PSDRV_Heap = 0;
98 static HFONT PSDRV_DefaultFont = 0;
99 static const LOGFONTA DefaultLogFont = {
100 100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 0, 0,
101 DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, ""
104 static const struct gdi_dc_funcs psdrv_funcs;
106 /*********************************************************************
107 * DllMain
109 * Initializes font metrics and registers driver. wineps dll entry point.
112 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
114 TRACE("(%p, %d, %p)\n", hinst, reason, reserved);
116 switch(reason) {
118 case DLL_PROCESS_ATTACH:
119 PSDRV_hInstance = hinst;
120 DisableThreadLibraryCalls(hinst);
122 PSDRV_Heap = HeapCreate(0, 0x10000, 0);
123 if (PSDRV_Heap == NULL)
124 return FALSE;
126 if (PSDRV_GetFontMetrics() == FALSE) {
127 HeapDestroy(PSDRV_Heap);
128 return FALSE;
131 PSDRV_DefaultFont = CreateFontIndirectA(&DefaultLogFont);
132 if (PSDRV_DefaultFont == NULL) {
133 HeapDestroy(PSDRV_Heap);
134 return FALSE;
136 break;
138 case DLL_PROCESS_DETACH:
139 if (reserved) break;
140 DeleteObject( PSDRV_DefaultFont );
141 HeapDestroy( PSDRV_Heap );
142 break;
145 return TRUE;
148 static void dump_fields(DWORD fields)
150 int add_space = 0;
152 #define CHECK_FIELD(flag) \
153 do \
155 if (fields & flag) \
157 if (add_space++) TRACE(" "); \
158 TRACE(#flag); \
159 fields &= ~flag; \
162 while (0)
164 CHECK_FIELD(DM_ORIENTATION);
165 CHECK_FIELD(DM_PAPERSIZE);
166 CHECK_FIELD(DM_PAPERLENGTH);
167 CHECK_FIELD(DM_PAPERWIDTH);
168 CHECK_FIELD(DM_SCALE);
169 CHECK_FIELD(DM_POSITION);
170 CHECK_FIELD(DM_NUP);
171 CHECK_FIELD(DM_DISPLAYORIENTATION);
172 CHECK_FIELD(DM_COPIES);
173 CHECK_FIELD(DM_DEFAULTSOURCE);
174 CHECK_FIELD(DM_PRINTQUALITY);
175 CHECK_FIELD(DM_COLOR);
176 CHECK_FIELD(DM_DUPLEX);
177 CHECK_FIELD(DM_YRESOLUTION);
178 CHECK_FIELD(DM_TTOPTION);
179 CHECK_FIELD(DM_COLLATE);
180 CHECK_FIELD(DM_FORMNAME);
181 CHECK_FIELD(DM_LOGPIXELS);
182 CHECK_FIELD(DM_BITSPERPEL);
183 CHECK_FIELD(DM_PELSWIDTH);
184 CHECK_FIELD(DM_PELSHEIGHT);
185 CHECK_FIELD(DM_DISPLAYFLAGS);
186 CHECK_FIELD(DM_DISPLAYFREQUENCY);
187 CHECK_FIELD(DM_ICMMETHOD);
188 CHECK_FIELD(DM_ICMINTENT);
189 CHECK_FIELD(DM_MEDIATYPE);
190 CHECK_FIELD(DM_DITHERTYPE);
191 CHECK_FIELD(DM_PANNINGWIDTH);
192 CHECK_FIELD(DM_PANNINGHEIGHT);
193 if (fields) TRACE(" %#x", fields);
194 TRACE("\n");
195 #undef CHECK_FIELD
198 /* Dump DEVMODE structure without a device specific part.
199 * Some applications and drivers fail to specify correct field
200 * flags (like DM_FORMNAME), so dump everything.
202 static void dump_devmode(const DEVMODEW *dm)
204 if (!TRACE_ON(psdrv)) return;
206 TRACE("dmDeviceName: %s\n", debugstr_w(dm->dmDeviceName));
207 TRACE("dmSpecVersion: 0x%04x\n", dm->dmSpecVersion);
208 TRACE("dmDriverVersion: 0x%04x\n", dm->dmDriverVersion);
209 TRACE("dmSize: 0x%04x\n", dm->dmSize);
210 TRACE("dmDriverExtra: 0x%04x\n", dm->dmDriverExtra);
211 TRACE("dmFields: 0x%04x\n", dm->dmFields);
212 dump_fields(dm->dmFields);
213 TRACE("dmOrientation: %d\n", dm->u1.s1.dmOrientation);
214 TRACE("dmPaperSize: %d\n", dm->u1.s1.dmPaperSize);
215 TRACE("dmPaperLength: %d\n", dm->u1.s1.dmPaperLength);
216 TRACE("dmPaperWidth: %d\n", dm->u1.s1.dmPaperWidth);
217 TRACE("dmScale: %d\n", dm->u1.s1.dmScale);
218 TRACE("dmCopies: %d\n", dm->u1.s1.dmCopies);
219 TRACE("dmDefaultSource: %d\n", dm->u1.s1.dmDefaultSource);
220 TRACE("dmPrintQuality: %d\n", dm->u1.s1.dmPrintQuality);
221 TRACE("dmColor: %d\n", dm->dmColor);
222 TRACE("dmDuplex: %d\n", dm->dmDuplex);
223 TRACE("dmYResolution: %d\n", dm->dmYResolution);
224 TRACE("dmTTOption: %d\n", dm->dmTTOption);
225 TRACE("dmCollate: %d\n", dm->dmCollate);
226 TRACE("dmFormName: %s\n", debugstr_w(dm->dmFormName));
227 TRACE("dmLogPixels %u\n", dm->dmLogPixels);
228 TRACE("dmBitsPerPel %u\n", dm->dmBitsPerPel);
229 TRACE("dmPelsWidth %u\n", dm->dmPelsWidth);
230 TRACE("dmPelsHeight %u\n", dm->dmPelsHeight);
233 static void PSDRV_UpdateDevCaps( PSDRV_PDEVICE *physDev )
235 PAGESIZE *page;
236 RESOLUTION *res;
237 INT width = 0, height = 0, resx = 0, resy = 0;
239 dump_devmode(&physDev->Devmode->dmPublic);
241 if (physDev->Devmode->dmPublic.dmFields & (DM_PRINTQUALITY | DM_YRESOLUTION | DM_LOGPIXELS))
243 if (physDev->Devmode->dmPublic.dmFields & DM_PRINTQUALITY)
244 resx = resy = physDev->Devmode->dmPublic.u1.s1.dmPrintQuality;
246 if (physDev->Devmode->dmPublic.dmFields & DM_YRESOLUTION)
247 resy = physDev->Devmode->dmPublic.dmYResolution;
249 if (physDev->Devmode->dmPublic.dmFields & DM_LOGPIXELS)
250 resx = resy = physDev->Devmode->dmPublic.dmLogPixels;
252 LIST_FOR_EACH_ENTRY(res, &physDev->pi->ppd->Resolutions, RESOLUTION, entry)
254 if (res->resx == resx && res->resy == resy)
256 physDev->logPixelsX = resx;
257 physDev->logPixelsY = resy;
258 break;
262 if (&res->entry == &physDev->pi->ppd->Resolutions)
264 WARN("Requested resolution %dx%d is not supported by device\n", resx, resy);
265 physDev->logPixelsX = physDev->pi->ppd->DefaultResolution;
266 physDev->logPixelsY = physDev->logPixelsX;
269 else
271 WARN("Using default device resolution %d\n", physDev->pi->ppd->DefaultResolution);
272 physDev->logPixelsX = physDev->pi->ppd->DefaultResolution;
273 physDev->logPixelsY = physDev->logPixelsX;
276 if(physDev->Devmode->dmPublic.dmFields & DM_PAPERSIZE) {
277 LIST_FOR_EACH_ENTRY(page, &physDev->pi->ppd->PageSizes, PAGESIZE, entry) {
278 if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize)
279 break;
282 if(&page->entry == &physDev->pi->ppd->PageSizes) {
283 FIXME("Can't find page\n");
284 SetRectEmpty(&physDev->ImageableArea);
285 physDev->PageSize.cx = 0;
286 physDev->PageSize.cy = 0;
287 } else if(page->ImageableArea) {
288 /* physDev sizes in device units; ppd sizes in 1/72" */
289 SetRect(&physDev->ImageableArea, page->ImageableArea->llx * physDev->logPixelsX / 72,
290 page->ImageableArea->ury * physDev->logPixelsY / 72,
291 page->ImageableArea->urx * physDev->logPixelsX / 72,
292 page->ImageableArea->lly * physDev->logPixelsY / 72);
293 physDev->PageSize.cx = page->PaperDimension->x *
294 physDev->logPixelsX / 72;
295 physDev->PageSize.cy = page->PaperDimension->y *
296 physDev->logPixelsY / 72;
297 } else {
298 physDev->ImageableArea.left = physDev->ImageableArea.bottom = 0;
299 physDev->ImageableArea.right = physDev->PageSize.cx =
300 page->PaperDimension->x * physDev->logPixelsX / 72;
301 physDev->ImageableArea.top = physDev->PageSize.cy =
302 page->PaperDimension->y * physDev->logPixelsY / 72;
304 } else if((physDev->Devmode->dmPublic.dmFields & DM_PAPERLENGTH) &&
305 (physDev->Devmode->dmPublic.dmFields & DM_PAPERWIDTH)) {
306 /* physDev sizes in device units; Devmode sizes in 1/10 mm */
307 physDev->ImageableArea.left = physDev->ImageableArea.bottom = 0;
308 physDev->ImageableArea.right = physDev->PageSize.cx =
309 physDev->Devmode->dmPublic.u1.s1.dmPaperWidth *
310 physDev->logPixelsX / 254;
311 physDev->ImageableArea.top = physDev->PageSize.cy =
312 physDev->Devmode->dmPublic.u1.s1.dmPaperLength *
313 physDev->logPixelsY / 254;
314 } else {
315 FIXME("Odd dmFields %x\n", physDev->Devmode->dmPublic.dmFields);
316 SetRectEmpty(&physDev->ImageableArea);
317 physDev->PageSize.cx = 0;
318 physDev->PageSize.cy = 0;
321 TRACE("ImageableArea = %s: PageSize = %dx%d\n", wine_dbgstr_rect(&physDev->ImageableArea),
322 physDev->PageSize.cx, physDev->PageSize.cy);
324 /* these are in device units */
325 width = physDev->ImageableArea.right - physDev->ImageableArea.left;
326 height = physDev->ImageableArea.top - physDev->ImageableArea.bottom;
328 if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_PORTRAIT) {
329 physDev->horzRes = width;
330 physDev->vertRes = height;
331 } else {
332 physDev->horzRes = height;
333 physDev->vertRes = width;
336 /* these are in mm */
337 physDev->horzSize = (physDev->horzRes * 25.4) / physDev->logPixelsX;
338 physDev->vertSize = (physDev->vertRes * 25.4) / physDev->logPixelsY;
340 TRACE("devcaps: horzSize = %dmm, vertSize = %dmm, "
341 "horzRes = %d, vertRes = %d\n",
342 physDev->horzSize, physDev->vertSize,
343 physDev->horzRes, physDev->vertRes);
346 static PSDRV_PDEVICE *create_psdrv_physdev( PRINTERINFO *pi )
348 PSDRV_PDEVICE *physDev;
350 physDev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev) );
351 if (!physDev) return NULL;
353 physDev->Devmode = HeapAlloc( GetProcessHeap(), 0, sizeof(PSDRV_DEVMODE) );
354 if (!physDev->Devmode)
356 HeapFree( GetProcessHeap(), 0, physDev );
357 return NULL;
360 *physDev->Devmode = *pi->Devmode;
361 physDev->pi = pi;
362 physDev->logPixelsX = pi->ppd->DefaultResolution;
363 physDev->logPixelsY = pi->ppd->DefaultResolution;
364 return physDev;
367 /**********************************************************************
368 * PSDRV_CreateDC
370 static BOOL CDECL PSDRV_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
371 LPCWSTR output, const DEVMODEW* initData )
373 PSDRV_PDEVICE *physDev;
374 PRINTERINFO *pi;
376 TRACE("(%s %s %s %p)\n", debugstr_w(driver), debugstr_w(device),
377 debugstr_w(output), initData);
379 if (!device) return FALSE;
380 pi = PSDRV_FindPrinterInfo( device );
381 if(!pi) return FALSE;
383 if(!pi->Fonts) {
384 RASTERIZER_STATUS status;
385 if(!GetRasterizerCaps(&status, sizeof(status)) ||
386 !(status.wFlags & TT_AVAILABLE) ||
387 !(status.wFlags & TT_ENABLED)) {
388 MESSAGE("Disabling printer %s since it has no builtin fonts and there are no TrueType fonts available.\n",
389 debugstr_w(device));
390 return FALSE;
394 if (!(physDev = create_psdrv_physdev( pi ))) return FALSE;
396 if (output && *output) physDev->job.output = strdupW( output );
398 if(initData)
400 dump_devmode(initData);
401 PSDRV_MergeDevmodes(physDev->Devmode, (const PSDRV_DEVMODE *)initData, pi);
404 PSDRV_UpdateDevCaps(physDev);
405 SelectObject( (*pdev)->hdc, PSDRV_DefaultFont );
406 push_dc_driver( pdev, &physDev->dev, &psdrv_funcs );
407 return TRUE;
411 /**********************************************************************
412 * PSDRV_CreateCompatibleDC
414 static BOOL CDECL PSDRV_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
416 HDC hdc = (*pdev)->hdc;
417 PSDRV_PDEVICE *physDev, *orig_dev = get_psdrv_dev( orig );
418 PRINTERINFO *pi = PSDRV_FindPrinterInfo( orig_dev->pi->friendly_name );
420 if (!pi) return FALSE;
421 if (!(physDev = create_psdrv_physdev( pi ))) return FALSE;
422 PSDRV_MergeDevmodes( physDev->Devmode, orig_dev->Devmode, pi );
423 PSDRV_UpdateDevCaps(physDev);
424 SelectObject( hdc, PSDRV_DefaultFont );
425 push_dc_driver( pdev, &physDev->dev, &psdrv_funcs );
426 return TRUE;
431 /**********************************************************************
432 * PSDRV_DeleteDC
434 static BOOL CDECL PSDRV_DeleteDC( PHYSDEV dev )
436 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
438 TRACE("\n");
440 HeapFree( GetProcessHeap(), 0, physDev->Devmode );
441 HeapFree( GetProcessHeap(), 0, physDev->job.output );
442 HeapFree( GetProcessHeap(), 0, physDev );
444 return TRUE;
448 /**********************************************************************
449 * ResetDC (WINEPS.@)
451 static HDC CDECL PSDRV_ResetDC( PHYSDEV dev, const DEVMODEW *lpInitData )
453 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
455 if (lpInitData)
457 PSDRV_MergeDevmodes(physDev->Devmode, (const PSDRV_DEVMODE *)lpInitData, physDev->pi);
458 PSDRV_UpdateDevCaps(physDev);
460 return dev->hdc;
463 /***********************************************************************
464 * GetDeviceCaps (WINEPS.@)
466 static INT CDECL PSDRV_GetDeviceCaps( PHYSDEV dev, INT cap )
468 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
470 TRACE("%p,%d\n", dev->hdc, cap);
472 switch(cap)
474 case DRIVERVERSION:
475 return 0;
476 case TECHNOLOGY:
477 return DT_RASPRINTER;
478 case HORZSIZE:
479 return MulDiv(physDev->horzSize, 100,
480 physDev->Devmode->dmPublic.u1.s1.dmScale);
481 case VERTSIZE:
482 return MulDiv(physDev->vertSize, 100,
483 physDev->Devmode->dmPublic.u1.s1.dmScale);
484 case HORZRES:
485 return physDev->horzRes;
486 case VERTRES:
487 return physDev->vertRes;
488 case BITSPIXEL:
489 /* Although Windows returns 1 for monochrome printers, we want
490 CreateCompatibleBitmap to provide something other than 1 bpp */
491 return 32;
492 case NUMPENS:
493 return 10;
494 case NUMFONTS:
495 return 39;
496 case NUMCOLORS:
497 return -1;
498 case PDEVICESIZE:
499 return sizeof(PSDRV_PDEVICE);
500 case TEXTCAPS:
501 return TC_CR_ANY | TC_VA_ABLE; /* psdrv 0x59f7 */
502 case RASTERCAPS:
503 return (RC_BITBLT | RC_BITMAP64 | RC_GDI20_OUTPUT | RC_DIBTODEV |
504 RC_STRETCHBLT | RC_STRETCHDIB); /* psdrv 0x6e99 */
505 case ASPECTX:
506 return physDev->logPixelsX;
507 case ASPECTY:
508 return physDev->logPixelsY;
509 case LOGPIXELSX:
510 return MulDiv(physDev->logPixelsX,
511 physDev->Devmode->dmPublic.u1.s1.dmScale, 100);
512 case LOGPIXELSY:
513 return MulDiv(physDev->logPixelsY,
514 physDev->Devmode->dmPublic.u1.s1.dmScale, 100);
515 case NUMRESERVED:
516 return 0;
517 case COLORRES:
518 return 0;
519 case PHYSICALWIDTH:
520 return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ?
521 physDev->PageSize.cy : physDev->PageSize.cx;
522 case PHYSICALHEIGHT:
523 return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ?
524 physDev->PageSize.cx : physDev->PageSize.cy;
525 case PHYSICALOFFSETX:
526 if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) {
527 if(physDev->pi->ppd->LandscapeOrientation == -90)
528 return physDev->PageSize.cy - physDev->ImageableArea.top;
529 else
530 return physDev->ImageableArea.bottom;
532 return physDev->ImageableArea.left;
534 case PHYSICALOFFSETY:
535 if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) {
536 if(physDev->pi->ppd->LandscapeOrientation == -90)
537 return physDev->PageSize.cx - physDev->ImageableArea.right;
538 else
539 return physDev->ImageableArea.left;
541 return physDev->PageSize.cy - physDev->ImageableArea.top;
543 default:
544 dev = GET_NEXT_PHYSDEV( dev, pGetDeviceCaps );
545 return dev->funcs->pGetDeviceCaps( dev, cap );
549 static PRINTER_ENUM_VALUESA *load_font_sub_table( HANDLE printer, DWORD *num_entries )
551 DWORD res, needed, num;
552 PRINTER_ENUM_VALUESA *table = NULL;
553 static const char fontsubkey[] = "PrinterDriverData\\FontSubTable";
555 *num_entries = 0;
557 res = EnumPrinterDataExA( printer, fontsubkey, NULL, 0, &needed, &num );
558 if (res != ERROR_MORE_DATA) return NULL;
560 table = HeapAlloc( PSDRV_Heap, 0, needed );
561 if (!table) return NULL;
563 res = EnumPrinterDataExA( printer, fontsubkey, (LPBYTE)table, needed, &needed, &num );
564 if (res != ERROR_SUCCESS)
566 HeapFree( PSDRV_Heap, 0, table );
567 return NULL;
570 *num_entries = num;
571 return table;
574 static PSDRV_DEVMODE *get_printer_devmode( HANDLE printer )
576 DWORD needed, dm_size;
577 BOOL res;
578 PRINTER_INFO_9W *info;
579 PSDRV_DEVMODE *dm;
581 GetPrinterW( printer, 9, NULL, 0, &needed );
582 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL;
584 info = HeapAlloc( PSDRV_Heap, 0, needed );
585 res = GetPrinterW( printer, 9, (BYTE *)info, needed, &needed );
586 if (!res || !info->pDevMode)
588 HeapFree( PSDRV_Heap, 0, info );
589 return NULL;
592 /* sanity check the sizes */
593 dm_size = info->pDevMode->dmSize + info->pDevMode->dmDriverExtra;
594 if ((char *)info->pDevMode - (char *)info + dm_size > needed)
596 HeapFree( PSDRV_Heap, 0, info );
597 return NULL;
600 dm = (PSDRV_DEVMODE*)info;
601 memmove( dm, info->pDevMode, dm_size );
602 return dm;
605 static PSDRV_DEVMODE *get_devmode( HANDLE printer, const WCHAR *name, BOOL *is_default )
607 PSDRV_DEVMODE *dm = get_printer_devmode( printer );
609 *is_default = FALSE;
611 if (dm && dm->dmPublic.dmSize + dm->dmPublic.dmDriverExtra >= sizeof(DefaultDevmode))
613 TRACE( "Retrieved devmode from winspool\n" );
614 return dm;
616 HeapFree( PSDRV_Heap, 0, dm );
618 TRACE( "Using default devmode\n" );
619 dm = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) );
620 if (dm)
622 *dm = DefaultDevmode;
623 lstrcpynW( (WCHAR *)dm->dmPublic.dmDeviceName, name, CCHDEVICENAME );
624 *is_default = TRUE;
626 return dm;
629 static BOOL set_devmode( HANDLE printer, PSDRV_DEVMODE *dm )
631 PRINTER_INFO_9W info;
632 info.pDevMode = &dm->dmPublic;
634 return SetPrinterW( printer, 9, (BYTE *)&info, 0 );
637 static WCHAR *get_ppd_filename( HANDLE printer )
639 DWORD needed;
640 DRIVER_INFO_2W *info;
641 WCHAR *name;
643 GetPrinterDriverW( printer, NULL, 2, NULL, 0, &needed );
644 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL;
645 info = HeapAlloc( GetProcessHeap(), 0, needed );
646 if (!info) return NULL;
647 GetPrinterDriverW( printer, NULL, 2, (BYTE*)info, needed, &needed );
648 name = (WCHAR *)info;
649 memmove( name, info->pDataFile, (lstrlenW( info->pDataFile ) + 1) * sizeof(WCHAR) );
650 return name;
653 static struct list printer_list = LIST_INIT( printer_list );
655 /**********************************************************************
656 * PSDRV_FindPrinterInfo
658 PRINTERINFO *PSDRV_FindPrinterInfo(LPCWSTR name)
660 PRINTERINFO *pi;
661 FONTNAME *font;
662 const AFM *afm;
663 HANDLE hPrinter = 0;
664 WCHAR *ppd_filename = NULL;
665 char *nameA = NULL;
666 BOOL using_default_devmode = FALSE;
667 int len;
669 TRACE("'%s'\n", debugstr_w(name));
671 LIST_FOR_EACH_ENTRY( pi, &printer_list, PRINTERINFO, entry )
673 if (!wcscmp( pi->friendly_name, name ))
674 return pi;
677 pi = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*pi) );
678 if (pi == NULL) return NULL;
680 if (!(pi->friendly_name = HeapAlloc( PSDRV_Heap, 0, (lstrlenW(name)+1)*sizeof(WCHAR) ))) goto fail;
681 lstrcpyW( pi->friendly_name, name );
683 if (OpenPrinterW( pi->friendly_name, &hPrinter, NULL ) == 0) {
684 ERR ("OpenPrinter failed with code %i\n", GetLastError ());
685 goto fail;
688 len = WideCharToMultiByte( CP_ACP, 0, name, -1, NULL, 0, NULL, NULL );
689 nameA = HeapAlloc( GetProcessHeap(), 0, len );
690 WideCharToMultiByte( CP_ACP, 0, name, -1, nameA, len, NULL, NULL );
692 pi->Devmode = get_devmode( hPrinter, name, &using_default_devmode );
693 if (!pi->Devmode) goto fail;
695 ppd_filename = get_ppd_filename( hPrinter );
696 if (!ppd_filename) goto fail;
698 pi->ppd = PSDRV_ParsePPD( ppd_filename, hPrinter );
699 if (!pi->ppd)
701 WARN( "Couldn't parse PPD file %s\n", debugstr_w(ppd_filename) );
702 goto fail;
705 if(using_default_devmode) {
706 DWORD papersize;
708 if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE | LOCALE_RETURN_NUMBER,
709 (LPWSTR)&papersize, sizeof(papersize)/sizeof(WCHAR))) {
710 PSDRV_DEVMODE dm;
711 memset(&dm, 0, sizeof(dm));
712 dm.dmPublic.dmFields = DM_PAPERSIZE;
713 dm.dmPublic.u1.s1.dmPaperSize = papersize;
714 PSDRV_MergeDevmodes(pi->Devmode, &dm, pi);
718 if(pi->ppd->DefaultPageSize) { /* We'll let the ppd override the devmode */
719 PSDRV_DEVMODE dm;
720 memset(&dm, 0, sizeof(dm));
721 dm.dmPublic.dmFields = DM_PAPERSIZE;
722 dm.dmPublic.u1.s1.dmPaperSize = pi->ppd->DefaultPageSize->WinPage;
723 PSDRV_MergeDevmodes(pi->Devmode, &dm, pi);
726 /* Duplex is indicated by the setting of the DM_DUPLEX bit in dmFields.
727 WinDuplex == 0 is a special case which means that the ppd has a
728 *DefaultDuplex: NotCapable entry. In this case we'll try not to confuse
729 apps and set dmDuplex to DMDUP_SIMPLEX but leave the DM_DUPLEX clear.
730 PSDRV_WriteHeader understands this and copes. */
731 pi->Devmode->dmPublic.dmFields &= ~DM_DUPLEX;
732 if(pi->ppd->DefaultDuplex) {
733 pi->Devmode->dmPublic.dmDuplex = pi->ppd->DefaultDuplex->WinDuplex;
734 if(pi->Devmode->dmPublic.dmDuplex != 0)
735 pi->Devmode->dmPublic.dmFields |= DM_DUPLEX;
736 else
737 pi->Devmode->dmPublic.dmDuplex = DMDUP_SIMPLEX;
740 set_devmode( hPrinter, pi->Devmode );
742 pi->FontSubTable = load_font_sub_table( hPrinter, &pi->FontSubTableSize );
744 LIST_FOR_EACH_ENTRY( font, &pi->ppd->InstalledFonts, FONTNAME, entry )
746 afm = PSDRV_FindAFMinList(PSDRV_AFMFontList, font->Name);
747 if(!afm) {
748 TRACE( "Couldn't find AFM file for installed printer font '%s' - "
749 "ignoring\n", font->Name);
751 else {
752 BOOL added;
753 if (PSDRV_AddAFMtoList(&pi->Fonts, afm, &added) == FALSE) {
754 PSDRV_FreeAFMList(pi->Fonts);
755 goto fail;
760 ClosePrinter( hPrinter );
761 HeapFree( GetProcessHeap(), 0, nameA );
762 HeapFree( GetProcessHeap(), 0, ppd_filename );
763 list_add_head( &printer_list, &pi->entry );
764 return pi;
766 fail:
767 if (hPrinter) ClosePrinter( hPrinter );
768 HeapFree(PSDRV_Heap, 0, pi->FontSubTable);
769 HeapFree(PSDRV_Heap, 0, pi->friendly_name);
770 HeapFree(PSDRV_Heap, 0, pi->Devmode);
771 HeapFree(PSDRV_Heap, 0, pi);
772 HeapFree( GetProcessHeap(), 0, nameA );
773 HeapFree( GetProcessHeap(), 0, ppd_filename );
774 return NULL;
778 static const struct gdi_dc_funcs psdrv_funcs =
780 NULL, /* pAbortDoc */
781 NULL, /* pAbortPath */
782 NULL, /* pAlphaBlend */
783 NULL, /* pAngleArc */
784 PSDRV_Arc, /* pArc */
785 NULL, /* pArcTo */
786 NULL, /* pBeginPath */
787 NULL, /* pBlendImage */
788 PSDRV_Chord, /* pChord */
789 NULL, /* pCloseFigure */
790 PSDRV_CreateCompatibleDC, /* pCreateCompatibleDC */
791 PSDRV_CreateDC, /* pCreateDC */
792 PSDRV_DeleteDC, /* pDeleteDC */
793 NULL, /* pDeleteObject */
794 PSDRV_DeviceCapabilities, /* pDeviceCapabilities */
795 PSDRV_Ellipse, /* pEllipse */
796 PSDRV_EndDoc, /* pEndDoc */
797 PSDRV_EndPage, /* pEndPage */
798 NULL, /* pEndPath */
799 PSDRV_EnumFonts, /* pEnumFonts */
800 NULL, /* pEnumICMProfiles */
801 NULL, /* pExcludeClipRect */
802 PSDRV_ExtDeviceMode, /* pExtDeviceMode */
803 PSDRV_ExtEscape, /* pExtEscape */
804 NULL, /* pExtFloodFill */
805 NULL, /* pExtSelectClipRgn */
806 PSDRV_ExtTextOut, /* pExtTextOut */
807 PSDRV_FillPath, /* pFillPath */
808 NULL, /* pFillRgn */
809 NULL, /* pFlattenPath */
810 NULL, /* pFontIsLinked */
811 NULL, /* pFrameRgn */
812 NULL, /* pGdiComment */
813 NULL, /* pGetBoundsRect */
814 NULL, /* pGetCharABCWidths */
815 NULL, /* pGetCharABCWidthsI */
816 PSDRV_GetCharWidth, /* pGetCharWidth */
817 NULL, /* pGetCharWidthInfo */
818 PSDRV_GetDeviceCaps, /* pGetDeviceCaps */
819 NULL, /* pGetDeviceGammaRamp */
820 NULL, /* pGetFontData */
821 NULL, /* pGetFontRealizationInfo */
822 NULL, /* pGetFontUnicodeRanges */
823 NULL, /* pGetGlyphIndices */
824 NULL, /* pGetGlyphOutline */
825 NULL, /* pGetICMProfile */
826 NULL, /* pGetImage */
827 NULL, /* pGetKerningPairs */
828 NULL, /* pGetNearestColor */
829 NULL, /* pGetOutlineTextMetrics */
830 NULL, /* pGetPixel */
831 NULL, /* pGetSystemPaletteEntries */
832 NULL, /* pGetTextCharsetInfo */
833 PSDRV_GetTextExtentExPoint, /* pGetTextExtentExPoint */
834 NULL, /* pGetTextExtentExPointI */
835 NULL, /* pGetTextFace */
836 PSDRV_GetTextMetrics, /* pGetTextMetrics */
837 NULL, /* pGradientFill */
838 NULL, /* pIntersectClipRect */
839 NULL, /* pInvertRgn */
840 PSDRV_LineTo, /* pLineTo */
841 NULL, /* pModifyWorldTransform */
842 NULL, /* pMoveTo */
843 NULL, /* pOffsetClipRgn */
844 NULL, /* pOffsetViewportOrg */
845 NULL, /* pOffsetWindowOrg */
846 PSDRV_PaintRgn, /* pPaintRgn */
847 PSDRV_PatBlt, /* pPatBlt */
848 PSDRV_Pie, /* pPie */
849 PSDRV_PolyBezier, /* pPolyBezier */
850 PSDRV_PolyBezierTo, /* pPolyBezierTo */
851 NULL, /* pPolyDraw */
852 PSDRV_PolyPolygon, /* pPolyPolygon */
853 PSDRV_PolyPolyline, /* pPolyPolyline */
854 NULL, /* pPolygon */
855 NULL, /* pPolyline */
856 NULL, /* pPolylineTo */
857 PSDRV_PutImage, /* pPutImage */
858 NULL, /* pRealizeDefaultPalette */
859 NULL, /* pRealizePalette */
860 PSDRV_Rectangle, /* pRectangle */
861 PSDRV_ResetDC, /* pResetDC */
862 NULL, /* pRestoreDC */
863 PSDRV_RoundRect, /* pRoundRect */
864 NULL, /* pSaveDC */
865 NULL, /* pScaleViewportExt */
866 NULL, /* pScaleWindowExt */
867 NULL, /* pSelectBitmap */
868 PSDRV_SelectBrush, /* pSelectBrush */
869 NULL, /* pSelectClipPath */
870 PSDRV_SelectFont, /* pSelectFont */
871 NULL, /* pSelectPalette */
872 PSDRV_SelectPen, /* pSelectPen */
873 NULL, /* pSetArcDirection */
874 PSDRV_SetBkColor, /* pSetBkColor */
875 NULL, /* pSetBkMode */
876 NULL, /* pSetBoundsRect */
877 PSDRV_SetDCBrushColor, /* pSetDCBrushColor */
878 PSDRV_SetDCPenColor, /* pSetDCPenColor */
879 NULL, /* pSetDIBitsToDevice */
880 NULL, /* pSetDeviceClipping */
881 NULL, /* pSetDeviceGammaRamp */
882 NULL, /* pSetLayout */
883 NULL, /* pSetMapMode */
884 NULL, /* pSetMapperFlags */
885 PSDRV_SetPixel, /* pSetPixel */
886 NULL, /* pSetPolyFillMode */
887 NULL, /* pSetROP2 */
888 NULL, /* pSetRelAbs */
889 NULL, /* pSetStretchBltMode */
890 NULL, /* pSetTextAlign */
891 NULL, /* pSetTextCharacterExtra */
892 PSDRV_SetTextColor, /* pSetTextColor */
893 NULL, /* pSetTextJustification */
894 NULL, /* pSetViewportExt */
895 NULL, /* pSetViewportOrg */
896 NULL, /* pSetWindowExt */
897 NULL, /* pSetWindowOrg */
898 NULL, /* pSetWorldTransform */
899 PSDRV_StartDoc, /* pStartDoc */
900 PSDRV_StartPage, /* pStartPage */
901 NULL, /* pStretchBlt */
902 NULL, /* pStretchDIBits */
903 PSDRV_StrokeAndFillPath, /* pStrokeAndFillPath */
904 PSDRV_StrokePath, /* pStrokePath */
905 NULL, /* pUnrealizePalette */
906 NULL, /* pWidenPath */
907 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
908 NULL, /* pD3DKMTSetVidPnSourceOwner */
909 NULL, /* wine_get_wgl_driver */
910 NULL, /* wine_get_vulkan_driver */
911 GDI_PRIORITY_GRAPHICS_DRV /* priority */
915 /******************************************************************************
916 * PSDRV_get_gdi_driver
918 const struct gdi_dc_funcs * CDECL PSDRV_get_gdi_driver( unsigned int version )
920 if (version != WINE_GDI_DRIVER_VERSION)
922 ERR( "version mismatch, gdi32 wants %u but wineps has %u\n", version, WINE_GDI_DRIVER_VERSION );
923 return NULL;
925 return &psdrv_funcs;