Release 1.3.7.
[wine/gsoc-2012-control.git] / dlls / wineps.drv / escape.c
blob988381e60e2c63d49d7792693454cdfbc11dbfe4
1 /*
2 * PostScript driver Escape function
4 * Copyright 1998 Huw D M Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wingdi.h"
38 #include "wine/wingdi16.h"
39 #include "winreg.h"
40 #include "psdrv.h"
41 #include "wine/debug.h"
42 #include "winspool.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
46 static const char psbegindocument[] =
47 "%%BeginDocument: Wine passthrough\n";
50 DWORD write_spool( PSDRV_PDEVICE *physDev, const void *data, DWORD num )
52 DWORD written;
53 if (!WritePrinter(physDev->job.hprinter, (LPBYTE) data, num, &written) || (written != num))
54 return SP_OUTOFDISK;
56 return num;
59 /**********************************************************************
60 * ExtEscape (WINEPS.@)
62 INT CDECL PSDRV_ExtEscape( PSDRV_PDEVICE *physDev, INT nEscape, INT cbInput, LPCVOID in_data,
63 INT cbOutput, LPVOID out_data )
65 switch(nEscape)
67 case QUERYESCSUPPORT:
68 if(cbInput < sizeof(INT))
70 WARN("cbInput < sizeof(INT) (=%d) for QUERYESCSUPPORT\n", cbInput);
71 return 0;
72 } else {
73 UINT num = *(const UINT *)in_data;
74 TRACE("QUERYESCSUPPORT for %d\n", num);
76 switch(num) {
77 case NEXTBAND:
78 /*case BANDINFO:*/
79 case SETCOPYCOUNT:
80 case GETTECHNOLOGY:
81 case SETLINECAP:
82 case SETLINEJOIN:
83 case SETMITERLIMIT:
84 case SETCHARSET:
85 case EXT_DEVICE_CAPS:
86 case SET_BOUNDS:
87 case EPSPRINTING:
88 case POSTSCRIPT_DATA:
89 case PASSTHROUGH:
90 case POSTSCRIPT_PASSTHROUGH:
91 case POSTSCRIPT_IGNORE:
92 case BEGIN_PATH:
93 case CLIP_TO_PATH:
94 case END_PATH:
95 /*case DRAWPATTERNRECT:*/
96 return TRUE;
98 default:
99 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
100 return FALSE;
104 case MFCOMMENT:
106 FIXME("MFCOMMENT(%p, %d)\n", in_data, cbInput);
107 return 1;
109 case DRAWPATTERNRECT:
111 DRAWPATRECT *dpr = (DRAWPATRECT*)in_data;
113 FIXME("DRAWPATTERNRECT(pos (%d,%d), size %dx%d, style %d, pattern %x), stub!\n",
114 dpr->ptPosition.x, dpr->ptPosition.y,
115 dpr->ptSize.x, dpr->ptSize.y,
116 dpr->wStyle, dpr->wPattern
118 return 1;
120 case BANDINFO:
122 BANDINFOSTRUCT *ibi = (BANDINFOSTRUCT*)in_data;
123 BANDINFOSTRUCT *obi = (BANDINFOSTRUCT*)out_data;
125 FIXME("BANDINFO(graphics %d, text %d, rect [%dx%d-%dx%d]), stub!\n",
126 ibi->GraphicsFlag,
127 ibi->TextFlag,
128 ibi->GraphicsRect.top,
129 ibi->GraphicsRect.bottom,
130 ibi->GraphicsRect.left,
131 ibi->GraphicsRect.right
133 *obi = *ibi;
134 return 1;
136 case NEXTBAND:
138 RECT *r = out_data;
139 if(!physDev->job.banding) {
140 physDev->job.banding = TRUE;
141 r->left = 0;
142 r->top = 0;
143 r->right = physDev->horzRes;
144 r->bottom = physDev->vertRes;
145 TRACE("NEXTBAND returning %d,%d - %d,%d\n", r->left, r->top, r->right, r->bottom );
146 return 1;
148 r->left = 0;
149 r->top = 0;
150 r->right = 0;
151 r->bottom = 0;
152 TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
153 physDev->job.banding = FALSE;
154 return EndPage( physDev->hdc );
157 case SETCOPYCOUNT:
159 const INT *NumCopies = in_data;
160 INT *ActualCopies = out_data;
161 if(cbInput != sizeof(INT)) {
162 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
163 return 0;
165 TRACE("SETCOPYCOUNT %d\n", *NumCopies);
166 *ActualCopies = 1;
167 return 1;
170 case GETTECHNOLOGY:
172 LPSTR p = out_data;
173 strcpy(p, "PostScript");
174 *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
175 return 1;
178 case SETLINECAP:
180 INT newCap = *(const INT *)in_data;
181 if(cbInput != sizeof(INT)) {
182 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
183 return 0;
185 TRACE("SETLINECAP %d\n", newCap);
186 return 0;
189 case SETLINEJOIN:
191 INT newJoin = *(const INT *)in_data;
192 if(cbInput != sizeof(INT)) {
193 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
194 return 0;
196 TRACE("SETLINEJOIN %d\n", newJoin);
197 return 0;
200 case SETMITERLIMIT:
202 INT newLimit = *(const INT *)in_data;
203 if(cbInput != sizeof(INT)) {
204 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
205 return 0;
207 TRACE("SETMITERLIMIT %d\n", newLimit);
208 return 0;
211 case SETCHARSET:
212 /* Undocumented escape used by winword6.
213 Switches between ANSI and a special charset.
214 If *lpInData == 1 we require that
215 0x91 is quoteleft
216 0x92 is quoteright
217 0x93 is quotedblleft
218 0x94 is quotedblright
219 0x95 is bullet
220 0x96 is endash
221 0x97 is emdash
222 0xa0 is non break space - yeah right.
224 If *lpInData == 0 we get ANSI.
225 Since there's nothing else there, let's just make these the default
226 anyway and see what happens...
228 return 1;
230 case EXT_DEVICE_CAPS:
232 UINT cap = *(const UINT *)in_data;
233 if(cbInput != sizeof(UINT)) {
234 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
235 return 0;
237 TRACE("EXT_DEVICE_CAPS %d\n", cap);
238 return 0;
241 case SET_BOUNDS:
243 const RECT *r = in_data;
244 if(cbInput != sizeof(RECT)) {
245 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
246 return 0;
248 TRACE("SET_BOUNDS (%d,%d) - (%d,%d)\n", r->left, r->top,
249 r->right, r->bottom);
250 return 0;
253 case EPSPRINTING:
255 UINT epsprint = *(const UINT*)in_data;
256 /* FIXME: In this mode we do not need to send page intros and page
257 * ends according to the doc. But I just ignore that detail
258 * for now.
260 TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
261 return 1;
264 case POSTSCRIPT_DATA:
265 case PASSTHROUGH:
266 case POSTSCRIPT_PASSTHROUGH:
268 /* Write directly to spool file, bypassing normal PS driver
269 * processing that is done along with writing PostScript code
270 * to the spool.
271 * We have a WORD before the data counting the size, but
272 * cbInput is just this +2.
273 * However Photoshop 7 has a bug that sets cbInput to 2 less than the
274 * length of the string, rather than 2 more. So we'll use the WORD at
275 * in_data[0] instead.
277 if(!physDev->job.in_passthrough) {
278 write_spool(physDev, psbegindocument, sizeof(psbegindocument)-1);
279 physDev->job.in_passthrough = TRUE;
281 return write_spool(physDev,((char*)in_data)+2,*(const WORD*)in_data);
284 case POSTSCRIPT_IGNORE:
286 BOOL ret = physDev->job.quiet;
287 TRACE("POSTSCRIPT_IGNORE %d\n", *(const short*)in_data);
288 physDev->job.quiet = *(const short*)in_data;
289 return ret;
292 case GETSETPRINTORIENT:
294 /* If lpInData is present, it is a 20 byte structure, first 32
295 * bit LONG value is the orientation. if lpInData is NULL, it
296 * returns the current orientation.
298 FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
299 return 1;
301 case BEGIN_PATH:
302 TRACE("BEGIN_PATH\n");
303 if(physDev->pathdepth)
304 FIXME("Nested paths not yet handled\n");
305 return ++physDev->pathdepth;
307 case END_PATH:
309 const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
311 TRACE("END_PATH\n");
312 if(!physDev->pathdepth) {
313 ERR("END_PATH called without a BEGIN_PATH\n");
314 return -1;
316 TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
317 info->RenderMode, info->FillMode, info->BkMode);
318 switch(info->RenderMode) {
319 case RENDERMODE_NO_DISPLAY:
320 PSDRV_WriteClosePath(physDev); /* not sure if this is necessary, but it can't hurt */
321 break;
322 case RENDERMODE_OPEN:
323 case RENDERMODE_CLOSED:
324 default:
325 FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
326 break;
328 return --physDev->pathdepth;
331 case CLIP_TO_PATH:
333 WORD mode = *(const WORD*)in_data;
335 switch(mode) {
336 case CLIP_SAVE:
337 TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
338 PSDRV_WriteGSave(physDev);
339 return 1;
340 case CLIP_RESTORE:
341 TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
342 PSDRV_WriteGRestore(physDev);
343 return 1;
344 case CLIP_INCLUSIVE:
345 TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
346 /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
347 PSDRV_WriteClip(physDev);
348 PSDRV_WriteNewPath(physDev);
349 return 1;
350 case CLIP_EXCLUSIVE:
351 FIXME("CLIP_EXCLUSIVE: not implemented\n");
352 return 0;
353 default:
354 FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
355 return 0;
358 default:
359 FIXME("Unimplemented code 0x%x\n", nEscape);
360 return 0;
364 /************************************************************************
365 * PSDRV_StartPage
367 INT CDECL PSDRV_StartPage( PSDRV_PDEVICE *physDev )
369 if(!physDev->job.OutOfPage) {
370 FIXME("Already started a page?\n");
371 return 1;
374 if(physDev->job.PageNo++ == 0) {
375 if(!PSDRV_WriteHeader( physDev, physDev->job.DocName ))
376 return 0;
379 if(!PSDRV_WriteNewPage( physDev ))
380 return 0;
381 physDev->job.OutOfPage = FALSE;
382 return 1;
386 /************************************************************************
387 * PSDRV_EndPage
389 INT CDECL PSDRV_EndPage( PSDRV_PDEVICE *physDev )
391 if(physDev->job.OutOfPage) {
392 FIXME("Already ended a page?\n");
393 return 1;
395 if(!PSDRV_WriteEndPage( physDev ))
396 return 0;
397 PSDRV_EmptyDownloadList(physDev, FALSE);
398 physDev->job.OutOfPage = TRUE;
399 return 1;
403 /************************************************************************
404 * PSDRV_StartDocA
406 static INT PSDRV_StartDocA( PSDRV_PDEVICE *physDev, const DOCINFOA *doc )
408 DOC_INFO_1A di;
410 TRACE("(%p, %p) => %s, %s, %s\n", physDev, doc, debugstr_a(doc->lpszDocName),
411 debugstr_a(doc->lpszOutput), debugstr_a(doc->lpszDatatype));
413 if(physDev->job.id) {
414 FIXME("hJob != 0. Now what?\n");
415 return 0;
418 /* FIXME: use PRINTER_DEFAULTS here */
419 if(!OpenPrinterA(physDev->pi->FriendlyName, &physDev->job.hprinter, NULL)) {
420 WARN("OpenPrinter(%s, ...) failed: %d\n",
421 debugstr_a(physDev->pi->FriendlyName), GetLastError());
422 return 0;
425 di.pDocName = (LPSTR) doc->lpszDocName;
426 di.pDatatype = NULL;
428 if(doc->lpszOutput)
429 di.pOutputFile = (LPSTR) doc->lpszOutput;
430 else if(physDev->job.output)
431 di.pOutputFile = physDev->job.output;
432 else
433 di.pOutputFile = NULL;
435 TRACE("using output: %s\n", debugstr_a(di.pOutputFile));
437 /* redirection located in HKCU\Software\Wine\Printing\Spooler
438 is done during winspool.drv,ScheduleJob */
439 physDev->job.id = StartDocPrinterA(physDev->job.hprinter, 1, (LPBYTE) &di);
440 if(!physDev->job.id) {
441 WARN("StartDocPrinter() failed: %d\n", GetLastError());
442 ClosePrinter(physDev->job.hprinter);
443 return 0;
445 physDev->job.banding = FALSE;
446 physDev->job.OutOfPage = TRUE;
447 physDev->job.PageNo = 0;
448 physDev->job.quiet = FALSE;
449 physDev->job.in_passthrough = FALSE;
450 physDev->job.had_passthrough_rect = FALSE;
451 if(doc->lpszDocName) {
452 physDev->job.DocName = HeapAlloc(GetProcessHeap(), 0, strlen(doc->lpszDocName)+1);
453 strcpy(physDev->job.DocName, doc->lpszDocName);
454 } else
455 physDev->job.DocName = NULL;
457 return physDev->job.id;
460 /************************************************************************
461 * PSDRV_StartDoc
463 INT CDECL PSDRV_StartDoc( PSDRV_PDEVICE *physDev, const DOCINFOW *doc )
465 DOCINFOA docA;
466 INT ret, len;
467 LPSTR docname = NULL, output = NULL, datatype = NULL;
469 TRACE("(%p, %p) => %d,%s,%s,%s\n", physDev, doc, doc->cbSize, debugstr_w(doc->lpszDocName),
470 debugstr_w(doc->lpszOutput), debugstr_w(doc->lpszDatatype));
472 docA.cbSize = doc->cbSize;
473 if (doc->lpszDocName)
475 len = WideCharToMultiByte( CP_ACP, 0, doc->lpszDocName, -1, NULL, 0, NULL, NULL );
476 if ((docname = HeapAlloc( GetProcessHeap(), 0, len )))
477 WideCharToMultiByte( CP_ACP, 0, doc->lpszDocName, -1, docname, len, NULL, NULL );
479 if (doc->lpszOutput)
481 len = WideCharToMultiByte( CP_ACP, 0, doc->lpszOutput, -1, NULL, 0, NULL, NULL );
482 if ((output = HeapAlloc( GetProcessHeap(), 0, len )))
483 WideCharToMultiByte( CP_ACP, 0, doc->lpszOutput, -1, output, len, NULL, NULL );
485 if (doc->lpszDatatype)
487 len = WideCharToMultiByte( CP_ACP, 0, doc->lpszDatatype, -1, NULL, 0, NULL, NULL );
488 if ((datatype = HeapAlloc( GetProcessHeap(), 0, len )))
489 WideCharToMultiByte( CP_ACP, 0, doc->lpszDatatype, -1, datatype, len, NULL, NULL );
491 docA.lpszDocName = docname;
492 docA.lpszOutput = output;
493 docA.lpszDatatype = datatype;
494 docA.fwType = doc->fwType;
496 ret = PSDRV_StartDocA(physDev, &docA);
498 HeapFree( GetProcessHeap(), 0, docname );
499 HeapFree( GetProcessHeap(), 0, output );
500 HeapFree( GetProcessHeap(), 0, datatype );
502 return ret;
505 /************************************************************************
506 * PSDRV_EndDoc
508 INT CDECL PSDRV_EndDoc( PSDRV_PDEVICE *physDev )
510 INT ret = 1;
511 if(!physDev->job.id) {
512 FIXME("hJob == 0. Now what?\n");
513 return 0;
516 if(!physDev->job.OutOfPage) {
517 WARN("Somebody forgot an EndPage\n");
518 PSDRV_EndPage( physDev );
520 PSDRV_WriteFooter( physDev );
522 ret = EndDocPrinter(physDev->job.hprinter);
523 ClosePrinter(physDev->job.hprinter);
524 physDev->job.hprinter = NULL;
525 physDev->job.id = 0;
526 HeapFree(GetProcessHeap(), 0, physDev->job.DocName);
527 physDev->job.DocName = NULL;
529 return ret;