init.c 25.2 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
Alexandre Julliard's avatar
Alexandre Julliard committed
2
 *	PostScript driver initialization functions
Alexandre Julliard's avatar
Alexandre Julliard committed
3 4
 *
 *	Copyright 1998 Huw D M Davies
5
 *	Copyright 2001 Marcus Meissner
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * 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
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
20
 */
21

22
#include "config.h"
23
#include "wine/port.h"
24

25
#include <stdarg.h>
26
#include <string.h>
27 28 29
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
30 31 32
#ifdef HAVE_CUPS_CUPS_H
# include <cups/cups.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
33

34 35
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
36

37 38
#include "windef.h"
#include "winbase.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
39
#include "winerror.h"
40 41 42
#include "winreg.h"
#include "psdrv.h"
#include "winspool.h"
43
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
44

45 46
WINE_DEFAULT_DEBUG_CHANNEL(psdrv);

47
#ifdef SONAME_LIBCUPS
48 49
static void *cupshandle = NULL;
#endif
50

51
static const PSDRV_DEVMODEA DefaultDevmode =
Alexandre Julliard's avatar
Alexandre Julliard committed
52 53 54 55 56
{
  { /* dmPublic */
/* dmDeviceName */	"Wine PostScript Driver",
/* dmSpecVersion */	0x30a,
/* dmDriverVersion */	0x001,
57
/* dmSize */		sizeof(DEVMODEA),
58
/* dmDriverExtra */	sizeof(PSDRV_DEVMODEA)-sizeof(DEVMODEA),
59 60
/* dmFields */		DM_ORIENTATION | DM_PAPERSIZE | DM_SCALE |
			DM_COPIES | DM_DEFAULTSOURCE | DM_COLOR |
61
		        DM_YRESOLUTION | DM_TTOPTION,
62 63
   { /* u1 */
     { /* s1 */
Alexandre Julliard's avatar
Alexandre Julliard committed
64
/* dmOrientation */	DMORIENT_PORTRAIT,
65 66
/* dmPaperSize */	DMPAPER_LETTER,
/* dmPaperLength */	2794,
67
/* dmPaperWidth */      2159,
Alexandre Julliard's avatar
Alexandre Julliard committed
68 69 70
/* dmScale */		100, /* ?? */
/* dmCopies */		1,
/* dmDefaultSource */	DMBIN_AUTO,
71 72 73
/* dmPrintQuality */	0
     }
   },
74
/* dmColor */		DMCOLOR_COLOR,
75
/* dmDuplex */		DMDUP_SIMPLEX,
Alexandre Julliard's avatar
Alexandre Julliard committed
76 77 78 79 80 81 82 83
/* dmYResolution */	0,
/* dmTTOption */	DMTT_SUBDEV,
/* dmCollate */		0,
/* dmFormName */	"",
/* dmUnusedPadding */   0,
/* dmBitsPerPel */	0,
/* dmPelsWidth */	0,
/* dmPelsHeight */	0,
84 85 86
   { /* u2 */
/* dmDisplayFlags */	0
   },
87 88 89 90 91 92 93 94 95
/* dmDisplayFrequency */ 0,
/* dmICMMethod */       0,
/* dmICMIntent */       0,
/* dmMediaType */       0,
/* dmDitherType */      0,
/* dmReserved1 */       0,
/* dmReserved2 */       0,
/* dmPanningWidth */    0,
/* dmPanningHeight */   0
Alexandre Julliard's avatar
Alexandre Julliard committed
96 97
  },
  { /* dmDocPrivate */
98
    /* dummy */ 0
Alexandre Julliard's avatar
Alexandre Julliard committed
99 100
  },
  { /* dmDrvPrivate */
101
    /* numInstalledOptions */ 0
Alexandre Julliard's avatar
Alexandre Julliard committed
102 103 104
  }
};

105
HINSTANCE PSDRV_hInstance = 0;
106
HANDLE PSDRV_Heap = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
107

108
static HFONT PSDRV_DefaultFont = 0;
109
static const LOGFONTA DefaultLogFont = {
Alexandre Julliard's avatar
Alexandre Julliard committed
110 111 112 113
    100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 0, 0,
    DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, ""
};

Alexandre Julliard's avatar
Alexandre Julliard committed
114
/*********************************************************************
115
 *	     DllMain
Alexandre Julliard's avatar
Alexandre Julliard committed
116
 *
117
 * Initializes font metrics and registers driver. wineps dll entry point.
Alexandre Julliard's avatar
Alexandre Julliard committed
118 119
 *
 */
120
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
Alexandre Julliard's avatar
Alexandre Julliard committed
121
{
122
    TRACE("(%p, %d, %p)\n", hinst, reason, reserved);
123

124
    switch(reason) {
125

126
	case DLL_PROCESS_ATTACH:
127
            PSDRV_hInstance = hinst;
128
            DisableThreadLibraryCalls(hinst);
129 130

	    PSDRV_Heap = HeapCreate(0, 0x10000, 0);
131
	    if (PSDRV_Heap == NULL)
132 133 134 135 136 137 138 139
		return FALSE;

	    if (PSDRV_GetFontMetrics() == FALSE) {
		HeapDestroy(PSDRV_Heap);
		return FALSE;
	    }

	    PSDRV_DefaultFont = CreateFontIndirectA(&DefaultLogFont);
140
	    if (PSDRV_DefaultFont == NULL) {
141 142 143
		HeapDestroy(PSDRV_Heap);
		return FALSE;
	    }
144
#ifdef SONAME_LIBCUPS
145 146
	    /* dynamically load CUPS if not yet loaded */
	    if (!cupshandle) {
147
		cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
148 149 150
		if (!cupshandle) cupshandle = (void*)-1;
	    }
#endif
151 152
            break;

153
	case DLL_PROCESS_DETACH:
154 155 156

	    DeleteObject( PSDRV_DefaultFont );
	    HeapDestroy( PSDRV_Heap );
157
#ifdef SONAME_LIBCUPS
158 159 160 161 162
	    if (cupshandle && (cupshandle != (void*)-1)) {
		wine_dlclose(cupshandle, NULL, 0);
		cupshandle = NULL;
	    }
#endif
163
            break;
164
    }
165

166
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
167 168
}

169

170 171 172 173
static void PSDRV_UpdateDevCaps( PSDRV_PDEVICE *physDev )
{
    PAGESIZE *page;
    INT width = 0, height = 0;
174

175
    if(physDev->Devmode->dmPublic.dmFields & DM_PAPERSIZE) {
176
        LIST_FOR_EACH_ENTRY(page, &physDev->pi->ppd->PageSizes, PAGESIZE, entry) {
177 178 179 180
	    if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize)
	        break;
	}

181
	if(&page->entry == &physDev->pi->ppd->PageSizes) {
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
	    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 {
221
        FIXME("Odd dmFields %x\n", physDev->Devmode->dmPublic.dmFields);
222 223 224 225 226 227 228 229
	physDev->ImageableArea.left = 0;
	physDev->ImageableArea.right = 0;
	physDev->ImageableArea.bottom = 0;
	physDev->ImageableArea.top = 0;
	physDev->PageSize.cx = 0;
	physDev->PageSize.cy = 0;
    }

230
    TRACE("ImageableArea = %d,%d - %d,%d: PageSize = %dx%d\n",
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
	  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);
}


258 259 260 261 262 263 264 265 266 267 268 269
/***********************************************************
 *      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;
Eric Pouech's avatar
Eric Pouech committed
270
    ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
271 272 273 274 275

    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);
Mike McCormack's avatar
Mike McCormack committed
276
    WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, (LPSTR)dmA->dmDeviceName,
277 278 279 280 281 282 283
			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));
Mike McCormack's avatar
Mike McCormack committed
284
      WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, (LPSTR)dmA->dmFormName,
285 286 287 288 289
			  CCHFORMNAME, NULL, NULL);
      memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
	     (off_formname + CCHFORMNAME * sizeof(WCHAR)));
    }
    dmA->dmSize = size;
Eric Pouech's avatar
Eric Pouech committed
290
    memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
291 292 293 294 295
	   dmW->dmDriverExtra);
    return dmA;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
296 297 298
/**********************************************************************
 *	     PSDRV_CreateDC
 */
299
BOOL PSDRV_CreateDC( HDC hdc, PSDRV_PDEVICE **pdev, LPCWSTR driver, LPCWSTR device,
300
                     LPCWSTR output, const DEVMODEW* initData )
Alexandre Julliard's avatar
Alexandre Julliard committed
301 302
{
    PSDRV_PDEVICE *physDev;
303
    PRINTERINFO *pi;
304
    char *deviceA;
Alexandre Julliard's avatar
Alexandre Julliard committed
305

306 307 308
    /* If no device name was specified, retrieve the device name
     * from the DEVMODE structure from the DC's physDev.
     * (See CreateCompatibleDC) */
309
    if ( !device && *pdev )
310
    {
311
        physDev = *pdev;
312
        deviceA = HeapAlloc(GetProcessHeap(), 0, CCHDEVICENAME);
Mike McCormack's avatar
Mike McCormack committed
313
        lstrcpynA(deviceA, (LPCSTR)physDev->Devmode->dmPublic.dmDeviceName, CCHDEVICENAME);
314
    }
315
    else
316 317 318 319 320
    {
        DWORD len = WideCharToMultiByte(CP_ACP, 0, device, -1, NULL, 0, NULL, NULL);
        deviceA = HeapAlloc(GetProcessHeap(), 0, len);
        WideCharToMultiByte(CP_ACP, 0, device, -1, deviceA, len, NULL, NULL);
    }
321
    pi = PSDRV_FindPrinterInfo(deviceA);
322

323 324 325
    HeapFree(GetProcessHeap(), 0, deviceA);
    deviceA = NULL;

326 327
    TRACE("(%s %s %s %p)\n", debugstr_w(driver), debugstr_w(device),
                             debugstr_w(output), initData);
Alexandre Julliard's avatar
Alexandre Julliard committed
328

Alexandre Julliard's avatar
Alexandre Julliard committed
329 330
    if(!pi) return FALSE;

Alexandre Julliard's avatar
Alexandre Julliard committed
331
    if(!pi->Fonts) {
332 333 334 335 336 337 338 339
        RASTERIZER_STATUS status;
        if(!GetRasterizerCaps(&status, sizeof(status)) ||
           !(status.wFlags & TT_AVAILABLE) ||
           !(status.wFlags & TT_ENABLED)) {
            MESSAGE("Disabling printer %s since it has no builtin fonts and there are no TrueType fonts available.\n",
                    debugstr_w(device));
            return FALSE;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
340 341
    }

342
    physDev = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*physDev) );
Alexandre Julliard's avatar
Alexandre Julliard committed
343
    if (!physDev) return FALSE;
344
    *pdev = physDev;
345
    physDev->hdc = hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
346 347 348

    physDev->pi = pi;

349
    physDev->Devmode = HeapAlloc( PSDRV_Heap, 0, sizeof(PSDRV_DEVMODEA) );
Alexandre Julliard's avatar
Alexandre Julliard committed
350 351 352 353
    if(!physDev->Devmode) {
        HeapFree( PSDRV_Heap, 0, physDev );
	return FALSE;
    }
354

355
    *physDev->Devmode = *pi->Devmode;
Alexandre Julliard's avatar
Alexandre Julliard committed
356

357 358
    physDev->logPixelsX = physDev->pi->ppd->DefaultResolution;
    physDev->logPixelsY = physDev->pi->ppd->DefaultResolution;
359

360
    if (output && *output) {
361 362 363
        INT len = WideCharToMultiByte( CP_ACP, 0, output, -1, NULL, 0, NULL, NULL );
        if ((physDev->job.output = HeapAlloc( PSDRV_Heap, 0, len )))
            WideCharToMultiByte( CP_ACP, 0, output, -1, physDev->job.output, len, NULL, NULL );
364 365
    } else
        physDev->job.output = NULL;
366
    physDev->job.hJob = 0;
367

368
    if(initData) {
369 370 371
        DEVMODEA *devmodeA = DEVMODEdupWtoA(PSDRV_Heap, initData);
        PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODEA *)devmodeA, pi);
        HeapFree(PSDRV_Heap, 0, devmodeA);
372 373
    }

374
    PSDRV_UpdateDevCaps(physDev);
375
    SelectObject( hdc, PSDRV_DefaultFont );
Alexandre Julliard's avatar
Alexandre Julliard committed
376 377 378 379
    return TRUE;
}


380

Alexandre Julliard's avatar
Alexandre Julliard committed
381 382 383
/**********************************************************************
 *	     PSDRV_DeleteDC
 */
384
BOOL PSDRV_DeleteDC( PSDRV_PDEVICE *physDev )
Alexandre Julliard's avatar
Alexandre Julliard committed
385
{
386
    TRACE("\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
387 388

    HeapFree( PSDRV_Heap, 0, physDev->Devmode );
389
    HeapFree( PSDRV_Heap, 0, physDev->job.output );
Alexandre Julliard's avatar
Alexandre Julliard committed
390 391
    HeapFree( PSDRV_Heap, 0, physDev );

Alexandre Julliard's avatar
Alexandre Julliard committed
392 393 394
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
395

396 397
/**********************************************************************
 *	     ResetDC   (WINEPS.@)
398
 */
399
HDC PSDRV_ResetDC( PSDRV_PDEVICE *physDev, const DEVMODEW *lpInitData )
400
{
401
    if(lpInitData) {
402
        HRGN hrgn;
403 404 405
        DEVMODEA *devmodeA = DEVMODEdupWtoA(PSDRV_Heap, lpInitData);
        PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODEA *)devmodeA, physDev->pi);
        HeapFree(PSDRV_Heap, 0, devmodeA);
406
        PSDRV_UpdateDevCaps(physDev);
407
        hrgn = CreateRectRgn(0, 0, physDev->horzRes, physDev->vertRes);
408
        SelectVisRgn( physDev->hdc, hrgn );
409
        DeleteObject(hrgn);
410
    }
411
    return physDev->hdc;
412 413
}

414 415 416
/***********************************************************************
 *           GetDeviceCaps    (WINEPS.@)
 */
417
INT PSDRV_GetDeviceCaps( PSDRV_PDEVICE *physDev, INT cap )
418 419 420 421 422 423 424 425
{
    switch(cap)
    {
    case DRIVERVERSION:
        return 0;
    case TECHNOLOGY:
        return DT_RASPRINTER;
    case HORZSIZE:
Huw D M Davies's avatar
Huw D M Davies committed
426
        return MulDiv(physDev->horzSize, 100,
427
		      physDev->Devmode->dmPublic.u1.s1.dmScale);
428
    case VERTSIZE:
Huw D M Davies's avatar
Huw D M Davies committed
429
        return MulDiv(physDev->vertSize, 100,
430
		      physDev->Devmode->dmPublic.u1.s1.dmScale);
431
    case HORZRES:
432
    case DESKTOPHORZRES:
433 434
        return physDev->horzRes;
    case VERTRES:
435
    case DESKTOPVERTRES:
436 437
        return physDev->vertRes;
    case BITSPIXEL:
438
        return (physDev->pi->ppd->ColorDevice != CD_False) ? 8 : 1;
439 440 441 442 443 444 445 446 447 448 449
    case PLANES:
        return 1;
    case NUMBRUSHES:
        return -1;
    case NUMPENS:
        return 10;
    case NUMMARKERS:
        return 0;
    case NUMFONTS:
        return 39;
    case NUMCOLORS:
450
        return (physDev->pi->ppd->ColorDevice != CD_False) ? 256 : -1;
451 452 453 454 455 456 457 458 459 460 461 462
    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:
463
        return TC_CR_ANY | TC_VA_ABLE; /* psdrv 0x59f7 */
464 465 466 467 468 469 470 471 472 473 474 475 476 477
    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:
Huw D M Davies's avatar
Huw D M Davies committed
478
        return MulDiv(physDev->logPixelsX,
479
		      physDev->Devmode->dmPublic.u1.s1.dmScale, 100);
480
    case LOGPIXELSY:
Huw D M Davies's avatar
Huw D M Davies committed
481
        return MulDiv(physDev->logPixelsY,
482
		      physDev->Devmode->dmPublic.u1.s1.dmScale, 100);
483 484 485 486 487 488 489
    case SIZEPALETTE:
        return 0;
    case NUMRESERVED:
        return 0;
    case COLORRES:
        return 0;
    case PHYSICALWIDTH:
490 491
        return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ?
	  physDev->PageSize.cy : physDev->PageSize.cx;
492
    case PHYSICALHEIGHT:
493 494
        return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ?
	  physDev->PageSize.cx : physDev->PageSize.cy;
495
    case PHYSICALOFFSETX:
496 497 498 499 500 501 502 503
      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;

504
    case PHYSICALOFFSETY:
505 506 507 508 509 510 511 512
      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;

513 514 515
    case SCALINGFACTORX:
    case SCALINGFACTORY:
    case VREFRESH:
516
    case BLTALIGNMENT:
517 518
        return 0;
    default:
519
        FIXME("(%p): unsupported capability %d, will return 0\n", physDev->hdc, cap );
520 521 522 523 524
        return 0;
    }
}


Alexandre Julliard's avatar
Alexandre Julliard committed
525 526 527
/**********************************************************************
 *		PSDRV_FindPrinterInfo
 */
528
PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name)
Alexandre Julliard's avatar
Alexandre Julliard committed
529 530
{
    static PRINTERINFO *PSDRV_PrinterList;
531
    DWORD type = REG_BINARY, needed, res, dwPaperSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
532 533
    PRINTERINFO *pi = PSDRV_PrinterList, **last = &PSDRV_PrinterList;
    FONTNAME *font;
534
    const AFM *afm;
535
    HANDLE hPrinter;
536
    const char *ppd = NULL;
537 538
    DWORD ppdType;
    char* ppdFileName = NULL;
539
    HKEY hkey;
540
    BOOL using_default_devmode = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
541

542
    TRACE("'%s'\n", name);
543

544 545 546
    /*
     *	If this loop completes, last will point to the 'next' element of the
     *	final PRINTERINFO in the list
547
     */
548
    for( ; pi; last = &pi->next, pi = pi->next)
Alexandre Julliard's avatar
Alexandre Julliard committed
549 550 551
        if(!strcmp(pi->FriendlyName, name))
	    return pi;

552 553 554
    pi = *last = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*pi) );
    if (pi == NULL)
    	return NULL;
555 556 557 558

    if (!(pi->FriendlyName = HeapAlloc( PSDRV_Heap, 0, strlen(name)+1 ))) goto fail;
    strcpy( pi->FriendlyName, name );

559
    /* Use Get|SetPrinterDataExA instead? */
560

561
    res = DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type,
Alexandre Julliard's avatar
Alexandre Julliard committed
562 563
			    NULL, 0, &needed );

564
    if(res == ERROR_INVALID_PRINTER_NAME || needed != sizeof(DefaultDevmode)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
565
        pi->Devmode = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) );
566
	if (pi->Devmode == NULL)
567
	    goto cleanup;
568
	*pi->Devmode = DefaultDevmode;
Mike McCormack's avatar
Mike McCormack committed
569
	lstrcpynA((LPSTR)pi->Devmode->dmPublic.dmDeviceName,name,CCHDEVICENAME);
570
	using_default_devmode = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
571 572

	/* need to do something here AddPrinter?? */
573 574
    }
    else {
Alexandre Julliard's avatar
Alexandre Julliard committed
575
        pi->Devmode = HeapAlloc( PSDRV_Heap, 0, needed );
576
	DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type,
Alexandre Julliard's avatar
Alexandre Julliard committed
577 578 579
			  (LPBYTE)pi->Devmode, needed, &needed);
    }

580
    if (OpenPrinterA (pi->FriendlyName, &hPrinter, NULL) == 0) {
581
	ERR ("OpenPrinterA failed with code %i\n", GetLastError ());
582
	goto cleanup;
583
    }
584

585
#ifdef SONAME_LIBCUPS
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
    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);
	    }
604 605 606
	}
    }
#endif
607
    if (!ppdFileName) {
608
        res = GetPrinterDataExA(hPrinter, "PrinterDriverData", "PPD File", NULL, NULL, 0, &needed);
609 610
        if ((res==ERROR_SUCCESS) || (res==ERROR_MORE_DATA)) {
            ppdFileName=HeapAlloc(PSDRV_Heap, 0, needed);
611 612
            res = GetPrinterDataExA(hPrinter, "PrinterDriverData", "PPD File", &ppdType,
                                    (LPBYTE)ppdFileName, needed, &needed);
613
        }
614
    }
615
    /* Look for a ppd file for this printer in the config file.
616
     * First look under that printer's name, and then under 'generic'
617
     */
618 619
    /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
    if((res != ERROR_SUCCESS) && !RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files", &hkey))
620
    {
621 622 623 624 625 626 627 628 629 630
        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) {
631
            HeapFree(PSDRV_Heap, 0, ppdFileName);
632
            ppdFileName=HeapAlloc(PSDRV_Heap, 0, needed);
633
            RegQueryValueExA(hkey, value_name, 0, &ppdType, (LPBYTE)ppdFileName, &needed);
634 635
        }
        RegCloseKey(hkey);
636 637
    }

638 639 640 641 642
    if (!ppdFileName)
    {
        const char *data_dir, *filename;

        if ((data_dir = wine_get_data_dir())) filename = "/generic.ppd";
643
        else if ((data_dir = wine_get_build_dir())) filename = "/dlls/wineps.drv/generic.ppd";
644 645 646
        else
        {
            res = ERROR_FILE_NOT_FOUND;
647
            ERR ("Error %i getting PPD file name for printer '%s'\n", res, name);
648 649 650 651 652
            goto closeprinter;
        }
        ppdFileName = HeapAlloc( PSDRV_Heap, 0, strlen(data_dir) + strlen(filename) + 1 );
        strcpy( ppdFileName, data_dir );
        strcat( ppdFileName, filename );
653 654 655 656 657 658 659 660 661 662 663 664
    } 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;
        }
665
    }
666

667 668 669 670 671 672
    pi->ppd = PSDRV_ParsePPD(ppdFileName);
    if(!pi->ppd) {
	MESSAGE("Couldn't find PPD file '%s', expect a crash now!\n",
	    ppdFileName);
	goto closeprinter;
    }
673

674 675 676 677
    /* 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;
678 679 680 681 682

    if(using_default_devmode) {
        DWORD papersize;

	if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE | LOCALE_RETURN_NUMBER,
683
			  (LPWSTR)&papersize, sizeof(papersize)/sizeof(WCHAR))) {
684 685 686 687 688 689 690 691 692 693
	    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) );
    }

694 695 696 697 698 699 700
    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);
    }
701

702 703 704 705 706
    /*
     *	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.
     */
707 708
    res = GetPrinterDataExA(hPrinter, "PrinterDriverData", "Paper Size", NULL,
                            (LPBYTE)&dwPaperSize, sizeof(DWORD), &needed);
709 710 711 712
    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);
713
    else {
714
	ERR ("GetPrinterDataA returned %i\n", res);
715
	goto closeprinter;
716 717
    }

718 719 720 721 722 723 724 725 726 727 728 729 730 731
    /* 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;
    }

732 733
    res = EnumPrinterDataExA (hPrinter, "PrinterDriverData\\FontSubTable", NULL,
	    0, &needed, &pi->FontSubTableSize);
734
    if (res == ERROR_SUCCESS || res == ERROR_FILE_NOT_FOUND) {
735
	TRACE ("No 'FontSubTable' for printer '%s'\n", name);
736 737
    }
    else if (res == ERROR_MORE_DATA) {
738
	pi->FontSubTable = HeapAlloc (PSDRV_Heap, 0, needed);
739
	if (pi->FontSubTable == NULL) {
740
	    ERR ("Failed to allocate %i bytes from heap\n", needed);
741
	    goto closeprinter;
742 743 744 745 746
	}

	res = EnumPrinterDataExA (hPrinter, "PrinterDriverData\\FontSubTable",
		(LPBYTE) pi->FontSubTable, needed, &needed,
		&pi->FontSubTableSize);
747
	if (res != ERROR_SUCCESS) {
748
	    ERR ("EnumPrinterDataExA returned %i\n", res);
749
	    goto closeprinter;
750
	}
751 752
    }
    else {
753
	ERR("EnumPrinterDataExA returned %i\n", res);
754
	goto closeprinter;
755 756
    }

757
    if (ClosePrinter (hPrinter) == 0) {
758
	ERR ("ClosePrinter failed with code %i\n", GetLastError ());
759
	goto cleanup;
760 761
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
762 763 764 765 766
    pi->next = NULL;
    pi->Fonts = NULL;

    for(font = pi->ppd->InstalledFonts; font; font = font->next) {
        afm = PSDRV_FindAFMinList(PSDRV_AFMFontList, font->Name);
767 768 769 770 771
	if(!afm) {
	    TRACE( "Couldn't find AFM file for installed printer font '%s' - "
	    	    "ignoring\n", font->Name);
	}
	else {
772 773
	    BOOL added;
	    if (PSDRV_AddAFMtoList(&pi->Fonts, afm, &added) == FALSE) {
774 775 776 777
	    	PSDRV_FreeAFMList(pi->Fonts);
		goto cleanup;
	    }
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
778

779 780
    }
    if (ppd) unlink(ppd);
Alexandre Julliard's avatar
Alexandre Julliard committed
781
    return pi;
782 783 784 785

closeprinter:
    ClosePrinter(hPrinter);
cleanup:
786 787 788 789
    HeapFree(PSDRV_Heap, 0, ppdFileName);
    HeapFree(PSDRV_Heap, 0, pi->FontSubTable);
    HeapFree(PSDRV_Heap, 0, pi->FriendlyName);
    HeapFree(PSDRV_Heap, 0, pi->Devmode);
790
fail:
791 792 793 794
    HeapFree(PSDRV_Heap, 0, pi);
    if (ppd) unlink(ppd);
    *last = NULL;
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
795
}