Release 2.0-rc1.
[wine.git] / dlls / wineps.drv / escape.c
blob435376c1ddaf811cc9ba1a328b8f0ab928bd21ae
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( PHYSDEV dev, const void *data, DWORD num )
52 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
53 DWORD written;
55 if (!WritePrinter(physDev->job.hprinter, (LPBYTE) data, num, &written) || (written != num))
56 return SP_OUTOFDISK;
58 return num;
61 /**********************************************************************
62 * ExtEscape (WINEPS.@)
64 INT PSDRV_ExtEscape( PHYSDEV dev, INT nEscape, INT cbInput, LPCVOID in_data,
65 INT cbOutput, LPVOID out_data )
67 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
69 TRACE("%p,%d,%d,%p,%d,%p\n",
70 dev->hdc, nEscape, cbInput, in_data, cbOutput, out_data);
72 switch(nEscape)
74 case QUERYESCSUPPORT:
75 if(cbInput < sizeof(SHORT))
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);
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;
105 default:
106 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
107 return FALSE;
111 case MFCOMMENT:
113 FIXME("MFCOMMENT(%p, %d)\n", in_data, cbInput);
114 return 1;
116 case DRAWPATTERNRECT:
118 DRAWPATRECT *dpr = (DRAWPATRECT*)in_data;
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
125 return 1;
127 case BANDINFO:
129 BANDINFOSTRUCT *ibi = (BANDINFOSTRUCT*)in_data;
130 BANDINFOSTRUCT *obi = (BANDINFOSTRUCT*)out_data;
132 FIXME("BANDINFO(graphics %d, text %d, rect %s), stub!\n", ibi->GraphicsFlag,
133 ibi->TextFlag, wine_dbgstr_rect(&ibi->GraphicsRect));
134 *obi = *ibi;
135 return 1;
137 case NEXTBAND:
139 RECT *r = out_data;
140 if(!physDev->job.banding) {
141 physDev->job.banding = TRUE;
142 r->left = 0;
143 r->top = 0;
144 r->right = physDev->horzRes;
145 r->bottom = physDev->vertRes;
146 TRACE("NEXTBAND returning %s\n", wine_dbgstr_rect(r));
147 return 1;
149 r->left = 0;
150 r->top = 0;
151 r->right = 0;
152 r->bottom = 0;
153 TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
154 physDev->job.banding = FALSE;
155 return EndPage( dev->hdc );
158 case SETCOPYCOUNT:
160 const INT *NumCopies = in_data;
161 INT *ActualCopies = out_data;
162 if(cbInput != sizeof(INT)) {
163 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
164 return 0;
166 TRACE("SETCOPYCOUNT %d\n", *NumCopies);
167 *ActualCopies = 1;
168 return 1;
171 case GETTECHNOLOGY:
173 LPSTR p = out_data;
174 strcpy(p, "PostScript");
175 *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
176 return 1;
179 case SETLINECAP:
181 INT newCap = *(const INT *)in_data;
182 if(cbInput != sizeof(INT)) {
183 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
184 return 0;
186 TRACE("SETLINECAP %d\n", newCap);
187 return 0;
190 case SETLINEJOIN:
192 INT newJoin = *(const INT *)in_data;
193 if(cbInput != sizeof(INT)) {
194 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
195 return 0;
197 TRACE("SETLINEJOIN %d\n", newJoin);
198 return 0;
201 case SETMITERLIMIT:
203 INT newLimit = *(const INT *)in_data;
204 if(cbInput != sizeof(INT)) {
205 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
206 return 0;
208 TRACE("SETMITERLIMIT %d\n", newLimit);
209 return 0;
212 case SETCHARSET:
213 /* Undocumented escape used by winword6.
214 Switches between ANSI and a special charset.
215 If *lpInData == 1 we require that
216 0x91 is quoteleft
217 0x92 is quoteright
218 0x93 is quotedblleft
219 0x94 is quotedblright
220 0x95 is bullet
221 0x96 is endash
222 0x97 is emdash
223 0xa0 is non break space - yeah right.
225 If *lpInData == 0 we get ANSI.
226 Since there's nothing else there, let's just make these the default
227 anyway and see what happens...
229 return 1;
231 case EXT_DEVICE_CAPS:
233 UINT cap = *(const UINT *)in_data;
234 if(cbInput != sizeof(UINT)) {
235 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
236 return 0;
238 TRACE("EXT_DEVICE_CAPS %d\n", cap);
239 return 0;
242 case SET_BOUNDS:
244 const RECT *r = in_data;
245 if(cbInput != sizeof(RECT)) {
246 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
247 return 0;
249 TRACE("SET_BOUNDS %s\n", wine_dbgstr_rect(r));
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(dev, psbegindocument, sizeof(psbegindocument)-1);
279 physDev->job.in_passthrough = TRUE;
281 return write_spool(dev,((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(dev); /* 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(dev);
339 return 1;
340 case CLIP_RESTORE:
341 TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
342 PSDRV_WriteGRestore(dev);
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(dev);
348 PSDRV_WriteNewPath(dev);
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 %d\n", nEscape);
360 return 0;
364 /************************************************************************
365 * PSDRV_StartPage
367 INT PSDRV_StartPage( PHYSDEV dev )
369 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
371 if(!physDev->job.OutOfPage) {
372 FIXME("Already started a page?\n");
373 return 1;
376 if(physDev->job.PageNo++ == 0) {
377 if(!PSDRV_WriteHeader( dev, physDev->job.doc_name ))
378 return 0;
381 if(!PSDRV_WriteNewPage( dev ))
382 return 0;
383 physDev->job.OutOfPage = FALSE;
384 return 1;
388 /************************************************************************
389 * PSDRV_EndPage
391 INT PSDRV_EndPage( PHYSDEV dev )
393 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
395 if(physDev->job.OutOfPage) {
396 FIXME("Already ended a page?\n");
397 return 1;
399 if(!PSDRV_WriteEndPage( dev ))
400 return 0;
401 PSDRV_EmptyDownloadList(dev, FALSE);
402 physDev->job.OutOfPage = TRUE;
403 return 1;
407 /************************************************************************
408 * PSDRV_StartDoc
410 INT PSDRV_StartDoc( PHYSDEV dev, const DOCINFOW *doc )
412 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
413 DOC_INFO_1W di;
414 PRINTER_DEFAULTSW prn_def;
416 TRACE("(%p, %p) => %s, %s, %s\n", physDev, doc, debugstr_w(doc->lpszDocName),
417 debugstr_w(doc->lpszOutput), debugstr_w(doc->lpszDatatype));
419 if(physDev->job.id) {
420 FIXME("hJob != 0. Now what?\n");
421 return 0;
424 prn_def.pDatatype = NULL;
425 prn_def.pDevMode = &physDev->pi->Devmode->dmPublic;
426 prn_def.DesiredAccess = PRINTER_ACCESS_USE;
428 if (!OpenPrinterW( physDev->pi->friendly_name, &physDev->job.hprinter, &prn_def ))
430 WARN("OpenPrinter(%s, ...) failed: %d\n",
431 debugstr_w(physDev->pi->friendly_name), GetLastError());
432 return 0;
435 di.pDocName = (LPWSTR) doc->lpszDocName;
436 di.pDatatype = NULL;
438 if(doc->lpszOutput)
439 di.pOutputFile = (LPWSTR) doc->lpszOutput;
440 else if(physDev->job.output)
441 di.pOutputFile = physDev->job.output;
442 else
443 di.pOutputFile = NULL;
445 TRACE("using output: %s\n", debugstr_w(di.pOutputFile));
447 /* redirection located in HKCU\Software\Wine\Printing\Spooler
448 is done during winspool.drv,ScheduleJob */
449 physDev->job.id = StartDocPrinterW(physDev->job.hprinter, 1, (LPBYTE) &di);
450 if(!physDev->job.id) {
451 WARN("StartDocPrinter() failed: %d\n", GetLastError());
452 ClosePrinter(physDev->job.hprinter);
453 return 0;
455 physDev->job.banding = FALSE;
456 physDev->job.OutOfPage = TRUE;
457 physDev->job.PageNo = 0;
458 physDev->job.quiet = FALSE;
459 physDev->job.in_passthrough = FALSE;
460 physDev->job.had_passthrough_rect = FALSE;
461 physDev->job.doc_name = strdupW( doc->lpszDocName );
463 return physDev->job.id;
466 /************************************************************************
467 * PSDRV_EndDoc
469 INT PSDRV_EndDoc( PHYSDEV dev )
471 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
472 INT ret = 1;
474 if(!physDev->job.id) {
475 FIXME("hJob == 0. Now what?\n");
476 return 0;
479 if(!physDev->job.OutOfPage) {
480 WARN("Somebody forgot an EndPage\n");
481 PSDRV_EndPage( dev );
484 if (physDev->job.PageNo)
485 PSDRV_WriteFooter( dev );
487 ret = EndDocPrinter(physDev->job.hprinter);
488 ClosePrinter(physDev->job.hprinter);
489 physDev->job.hprinter = NULL;
490 physDev->job.id = 0;
491 HeapFree( GetProcessHeap(), 0, physDev->job.doc_name );
492 physDev->job.doc_name = NULL;
494 return ret;