wined3d: Move max_ffp_textures to wined3d_d3d_info.
[wine] / dlls / wineps.drv / escape.c
1 /*
2  *      PostScript driver Escape function
3  *
4  *      Copyright 1998  Huw D M Davies
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
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
34
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"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
45
46 static const char psbegindocument[] =
47 "%%BeginDocument: Wine passthrough\n";
48
49
50 DWORD write_spool( PHYSDEV dev, const void *data, DWORD num )
51 {
52     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
53     DWORD written;
54
55     if (!WritePrinter(physDev->job.hprinter, (LPBYTE) data, num, &written) || (written != num))
56         return SP_OUTOFDISK;
57
58     return num;
59 }
60
61 /**********************************************************************
62  *           ExtEscape  (WINEPS.@)
63  */
64 INT PSDRV_ExtEscape( PHYSDEV dev, INT nEscape, INT cbInput, LPCVOID in_data,
65                      INT cbOutput, LPVOID out_data )
66 {
67     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
68
69     TRACE("%p,%d,%d,%p,%d,%p\n",
70           dev->hdc, nEscape, cbInput, in_data, cbOutput, out_data);
71
72     switch(nEscape)
73     {
74     case QUERYESCSUPPORT:
75         if(cbInput < sizeof(SHORT))
76         {
77             WARN("cbInput < sizeof(SHORT) (=%d) for QUERYESCSUPPORT\n", cbInput);
78             return 0;
79         } else {
80             DWORD num = (cbInput < sizeof(DWORD)) ? *(const USHORT *)in_data : *(const DWORD *)in_data;
81             TRACE("QUERYESCSUPPORT for %d\n", num);
82
83             switch(num) {
84             case NEXTBAND:
85             /*case BANDINFO:*/
86             case SETCOPYCOUNT:
87             case GETTECHNOLOGY:
88             case SETLINECAP:
89             case SETLINEJOIN:
90             case SETMITERLIMIT:
91             case SETCHARSET:
92             case EXT_DEVICE_CAPS:
93             case SET_BOUNDS:
94             case EPSPRINTING:
95             case POSTSCRIPT_DATA:
96             case PASSTHROUGH:
97             case POSTSCRIPT_PASSTHROUGH:
98             case POSTSCRIPT_IGNORE:
99             case BEGIN_PATH:
100             case CLIP_TO_PATH:
101             case END_PATH:
102             /*case DRAWPATTERNRECT:*/
103                 return TRUE;
104
105             default:
106                 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
107                 return FALSE;
108             }
109         }
110
111     case MFCOMMENT:
112     {
113         FIXME("MFCOMMENT(%p, %d)\n", in_data, cbInput);
114         return 1;
115     }
116     case DRAWPATTERNRECT:
117     {
118         DRAWPATRECT     *dpr = (DRAWPATRECT*)in_data;
119
120         FIXME("DRAWPATTERNRECT(pos (%d,%d), size %dx%d, style %d, pattern %x), stub!\n",
121                 dpr->ptPosition.x, dpr->ptPosition.y,
122                 dpr->ptSize.x, dpr->ptSize.y,
123                 dpr->wStyle, dpr->wPattern
124         );
125         return 1;
126     }
127     case BANDINFO:
128     {
129         BANDINFOSTRUCT  *ibi = (BANDINFOSTRUCT*)in_data;
130         BANDINFOSTRUCT  *obi = (BANDINFOSTRUCT*)out_data;
131
132         FIXME("BANDINFO(graphics %d, text %d, rect [%dx%d-%dx%d]), stub!\n",
133                 ibi->GraphicsFlag,
134                 ibi->TextFlag,
135                 ibi->GraphicsRect.top,
136                 ibi->GraphicsRect.bottom,
137                 ibi->GraphicsRect.left,
138                 ibi->GraphicsRect.right
139         );
140         *obi = *ibi;
141         return 1;
142     }
143     case NEXTBAND:
144     {
145         RECT *r = out_data;
146         if(!physDev->job.banding) {
147             physDev->job.banding = TRUE;
148             r->left   = 0;
149             r->top    = 0;
150             r->right  = physDev->horzRes;
151             r->bottom = physDev->vertRes;
152             TRACE("NEXTBAND returning %d,%d - %d,%d\n", r->left, r->top, r->right, r->bottom );
153             return 1;
154         }
155         r->left   = 0;
156         r->top    = 0;
157         r->right  = 0;
158         r->bottom = 0;
159         TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
160         physDev->job.banding = FALSE;
161         return EndPage( dev->hdc );
162     }
163
164     case SETCOPYCOUNT:
165         {
166             const INT *NumCopies = in_data;
167             INT *ActualCopies = out_data;
168             if(cbInput != sizeof(INT)) {
169                 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
170                 return 0;
171             }
172             TRACE("SETCOPYCOUNT %d\n", *NumCopies);
173             *ActualCopies = 1;
174             return 1;
175         }
176
177     case GETTECHNOLOGY:
178         {
179             LPSTR p = out_data;
180             strcpy(p, "PostScript");
181             *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
182             return 1;
183         }
184
185     case SETLINECAP:
186         {
187             INT newCap = *(const INT *)in_data;
188             if(cbInput != sizeof(INT)) {
189                 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
190                 return 0;
191             }
192             TRACE("SETLINECAP %d\n", newCap);
193             return 0;
194         }
195
196     case SETLINEJOIN:
197         {
198             INT newJoin = *(const INT *)in_data;
199             if(cbInput != sizeof(INT)) {
200                 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
201                 return 0;
202             }
203             TRACE("SETLINEJOIN %d\n", newJoin);
204             return 0;
205         }
206
207     case SETMITERLIMIT:
208         {
209             INT newLimit = *(const INT *)in_data;
210             if(cbInput != sizeof(INT)) {
211                 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
212                 return 0;
213             }
214             TRACE("SETMITERLIMIT %d\n", newLimit);
215             return 0;
216         }
217
218     case SETCHARSET:
219       /* Undocumented escape used by winword6.
220          Switches between ANSI and a special charset.
221          If *lpInData == 1 we require that
222          0x91 is quoteleft
223          0x92 is quoteright
224          0x93 is quotedblleft
225          0x94 is quotedblright
226          0x95 is bullet
227          0x96 is endash
228          0x97 is emdash
229          0xa0 is non break space - yeah right.
230
231          If *lpInData == 0 we get ANSI.
232          Since there's nothing else there, let's just make these the default
233          anyway and see what happens...
234       */
235         return 1;
236
237     case EXT_DEVICE_CAPS:
238         {
239             UINT cap = *(const UINT *)in_data;
240             if(cbInput != sizeof(UINT)) {
241                 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
242                 return 0;
243             }
244             TRACE("EXT_DEVICE_CAPS %d\n", cap);
245             return 0;
246         }
247
248     case SET_BOUNDS:
249         {
250             const RECT *r = in_data;
251             if(cbInput != sizeof(RECT)) {
252                 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
253                 return 0;
254             }
255             TRACE("SET_BOUNDS (%d,%d) - (%d,%d)\n", r->left, r->top,
256                   r->right, r->bottom);
257             return 0;
258         }
259
260     case EPSPRINTING:
261         {
262             UINT epsprint = *(const UINT*)in_data;
263             /* FIXME: In this mode we do not need to send page intros and page
264              * ends according to the doc. But I just ignore that detail
265              * for now.
266              */
267             TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
268             return 1;
269         }
270
271     case POSTSCRIPT_DATA:
272     case PASSTHROUGH:
273     case POSTSCRIPT_PASSTHROUGH:
274         {
275             /* Write directly to spool file, bypassing normal PS driver
276              * processing that is done along with writing PostScript code
277              * to the spool.
278              * We have a WORD before the data counting the size, but
279              * cbInput is just this +2.
280              * However Photoshop 7 has a bug that sets cbInput to 2 less than the
281              * length of the string, rather than 2 more.  So we'll use the WORD at
282              * in_data[0] instead.
283              */
284             if(!physDev->job.in_passthrough) {
285                 write_spool(dev, psbegindocument, sizeof(psbegindocument)-1);
286                 physDev->job.in_passthrough = TRUE;
287             }
288             return write_spool(dev,((char*)in_data)+2,*(const WORD*)in_data);
289         }
290
291     case POSTSCRIPT_IGNORE:
292       {
293         BOOL ret = physDev->job.quiet;
294         TRACE("POSTSCRIPT_IGNORE %d\n", *(const short*)in_data);
295         physDev->job.quiet = *(const short*)in_data;
296         return ret;
297       }
298
299     case GETSETPRINTORIENT:
300         {
301             /* If lpInData is present, it is a 20 byte structure, first 32
302              * bit LONG value is the orientation. if lpInData is NULL, it
303              * returns the current orientation.
304              */
305             FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
306             return 1;
307         }
308     case BEGIN_PATH:
309         TRACE("BEGIN_PATH\n");
310         if(physDev->pathdepth)
311             FIXME("Nested paths not yet handled\n");
312         return ++physDev->pathdepth;
313
314     case END_PATH:
315       {
316         const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
317
318         TRACE("END_PATH\n");
319         if(!physDev->pathdepth) {
320             ERR("END_PATH called without a BEGIN_PATH\n");
321             return -1;
322         }
323         TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
324               info->RenderMode, info->FillMode, info->BkMode);
325         switch(info->RenderMode) {
326         case RENDERMODE_NO_DISPLAY:
327             PSDRV_WriteClosePath(dev); /* not sure if this is necessary, but it can't hurt */
328             break;
329         case RENDERMODE_OPEN:
330         case RENDERMODE_CLOSED:
331         default:
332             FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
333             break;
334         }
335         return --physDev->pathdepth;
336       }
337
338     case CLIP_TO_PATH:
339       {
340         WORD mode = *(const WORD*)in_data;
341
342         switch(mode) {
343         case CLIP_SAVE:
344             TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
345             PSDRV_WriteGSave(dev);
346             return 1;
347         case CLIP_RESTORE:
348             TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
349             PSDRV_WriteGRestore(dev);
350             return 1;
351         case CLIP_INCLUSIVE:
352             TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
353             /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
354             PSDRV_WriteClip(dev);
355             PSDRV_WriteNewPath(dev);
356             return 1;
357         case CLIP_EXCLUSIVE:
358             FIXME("CLIP_EXCLUSIVE: not implemented\n");
359             return 0;
360         default:
361             FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
362             return 0;
363         }
364       }
365     default:
366         FIXME("Unimplemented code %d\n", nEscape);
367         return 0;
368     }
369 }
370
371 /************************************************************************
372  *           PSDRV_StartPage
373  */
374 INT PSDRV_StartPage( PHYSDEV dev )
375 {
376     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
377
378     if(!physDev->job.OutOfPage) {
379         FIXME("Already started a page?\n");
380         return 1;
381     }
382
383     if(physDev->job.PageNo++ == 0) {
384         if(!PSDRV_WriteHeader( dev, physDev->job.doc_name ))
385             return 0;
386     }
387
388     if(!PSDRV_WriteNewPage( dev ))
389         return 0;
390     physDev->job.OutOfPage = FALSE;
391     return 1;
392 }
393
394
395 /************************************************************************
396  *           PSDRV_EndPage
397  */
398 INT PSDRV_EndPage( PHYSDEV dev )
399 {
400     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
401
402     if(physDev->job.OutOfPage) {
403         FIXME("Already ended a page?\n");
404         return 1;
405     }
406     if(!PSDRV_WriteEndPage( dev ))
407         return 0;
408     PSDRV_EmptyDownloadList(dev, FALSE);
409     physDev->job.OutOfPage = TRUE;
410     return 1;
411 }
412
413
414 /************************************************************************
415  *           PSDRV_StartDoc
416  */
417 INT PSDRV_StartDoc( PHYSDEV dev, const DOCINFOW *doc )
418 {
419     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
420     DOC_INFO_1W di;
421     PRINTER_DEFAULTSW prn_def;
422
423     TRACE("(%p, %p) => %s, %s, %s\n", physDev, doc, debugstr_w(doc->lpszDocName),
424         debugstr_w(doc->lpszOutput), debugstr_w(doc->lpszDatatype));
425
426     if(physDev->job.id) {
427         FIXME("hJob != 0. Now what?\n");
428         return 0;
429     }
430
431     prn_def.pDatatype = NULL;
432     prn_def.pDevMode = &physDev->pi->Devmode->dmPublic;
433     prn_def.DesiredAccess = PRINTER_ACCESS_USE;
434
435     if (!OpenPrinterW( physDev->pi->friendly_name, &physDev->job.hprinter, &prn_def ))
436     {
437         WARN("OpenPrinter(%s, ...) failed: %d\n",
438             debugstr_w(physDev->pi->friendly_name), GetLastError());
439         return 0;
440     }
441
442     di.pDocName = (LPWSTR) doc->lpszDocName;
443     di.pDatatype = NULL;
444
445     if(doc->lpszOutput)
446         di.pOutputFile = (LPWSTR) doc->lpszOutput;
447     else if(physDev->job.output)
448         di.pOutputFile = physDev->job.output;
449     else
450         di.pOutputFile = NULL;
451
452     TRACE("using output: %s\n", debugstr_w(di.pOutputFile));
453
454     /* redirection located in HKCU\Software\Wine\Printing\Spooler
455        is done during winspool.drv,ScheduleJob */
456     physDev->job.id = StartDocPrinterW(physDev->job.hprinter, 1, (LPBYTE) &di);
457     if(!physDev->job.id) {
458         WARN("StartDocPrinter() failed: %d\n", GetLastError());
459         ClosePrinter(physDev->job.hprinter);
460         return 0;
461     }
462     physDev->job.banding = FALSE;
463     physDev->job.OutOfPage = TRUE;
464     physDev->job.PageNo = 0;
465     physDev->job.quiet = FALSE;
466     physDev->job.in_passthrough = FALSE;
467     physDev->job.had_passthrough_rect = FALSE;
468     physDev->job.doc_name = strdupW( doc->lpszDocName );
469
470     return physDev->job.id;
471 }
472
473 /************************************************************************
474  *           PSDRV_EndDoc
475  */
476 INT PSDRV_EndDoc( PHYSDEV dev )
477 {
478     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
479     INT ret = 1;
480
481     if(!physDev->job.id) {
482         FIXME("hJob == 0. Now what?\n");
483         return 0;
484     }
485
486     if(!physDev->job.OutOfPage) {
487         WARN("Somebody forgot an EndPage\n");
488         PSDRV_EndPage( dev );
489     }
490
491     if (physDev->job.PageNo)
492         PSDRV_WriteFooter( dev );
493
494     ret = EndDocPrinter(physDev->job.hprinter);
495     ClosePrinter(physDev->job.hprinter);
496     physDev->job.hprinter = NULL;
497     physDev->job.id = 0;
498     HeapFree( GetProcessHeap(), 0, physDev->job.doc_name );
499     physDev->job.doc_name = NULL;
500
501     return ret;
502 }