msvcrt/tests: Make qsort_comp() static.
[wine.git] / dlls / wineps.drv / escape.c
blob6e898377721308493137b7a1336fab3ec8c80066
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 [%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
140 *obi = *ibi;
141 return 1;
143 case NEXTBAND:
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;
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 );
164 case SETCOPYCOUNT:
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;
172 TRACE("SETCOPYCOUNT %d\n", *NumCopies);
173 *ActualCopies = 1;
174 return 1;
177 case GETTECHNOLOGY:
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;
185 case SETLINECAP:
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;
192 TRACE("SETLINECAP %d\n", newCap);
193 return 0;
196 case SETLINEJOIN:
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;
203 TRACE("SETLINEJOIN %d\n", newJoin);
204 return 0;
207 case SETMITERLIMIT:
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;
214 TRACE("SETMITERLIMIT %d\n", newLimit);
215 return 0;
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.
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...
235 return 1;
237 case EXT_DEVICE_CAPS:
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;
244 TRACE("EXT_DEVICE_CAPS %d\n", cap);
245 return 0;
248 case SET_BOUNDS:
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;
255 TRACE("SET_BOUNDS (%d,%d) - (%d,%d)\n", r->left, r->top,
256 r->right, r->bottom);
257 return 0;
260 case EPSPRINTING:
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.
267 TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
268 return 1;
271 case POSTSCRIPT_DATA:
272 case PASSTHROUGH:
273 case POSTSCRIPT_PASSTHROUGH:
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.
284 if(!physDev->job.in_passthrough) {
285 write_spool(dev, psbegindocument, sizeof(psbegindocument)-1);
286 physDev->job.in_passthrough = TRUE;
288 return write_spool(dev,((char*)in_data)+2,*(const WORD*)in_data);
291 case POSTSCRIPT_IGNORE:
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;
299 case GETSETPRINTORIENT:
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.
305 FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
306 return 1;
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;
314 case END_PATH:
316 const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
318 TRACE("END_PATH\n");
319 if(!physDev->pathdepth) {
320 ERR("END_PATH called without a BEGIN_PATH\n");
321 return -1;
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;
335 return --physDev->pathdepth;
338 case CLIP_TO_PATH:
340 WORD mode = *(const WORD*)in_data;
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;
365 default:
366 FIXME("Unimplemented code %d\n", nEscape);
367 return 0;
371 /************************************************************************
372 * PSDRV_StartPage
374 INT PSDRV_StartPage( PHYSDEV dev )
376 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
378 if(!physDev->job.OutOfPage) {
379 FIXME("Already started a page?\n");
380 return 1;
383 if(physDev->job.PageNo++ == 0) {
384 if(!PSDRV_WriteHeader( dev, physDev->job.doc_name ))
385 return 0;
388 if(!PSDRV_WriteNewPage( dev ))
389 return 0;
390 physDev->job.OutOfPage = FALSE;
391 return 1;
395 /************************************************************************
396 * PSDRV_EndPage
398 INT PSDRV_EndPage( PHYSDEV dev )
400 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
402 if(physDev->job.OutOfPage) {
403 FIXME("Already ended a page?\n");
404 return 1;
406 if(!PSDRV_WriteEndPage( dev ))
407 return 0;
408 PSDRV_EmptyDownloadList(dev, FALSE);
409 physDev->job.OutOfPage = TRUE;
410 return 1;
414 /************************************************************************
415 * PSDRV_StartDoc
417 INT PSDRV_StartDoc( PHYSDEV dev, const DOCINFOW *doc )
419 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
420 DOC_INFO_1W di;
421 PRINTER_DEFAULTSW prn_def;
423 TRACE("(%p, %p) => %s, %s, %s\n", physDev, doc, debugstr_w(doc->lpszDocName),
424 debugstr_w(doc->lpszOutput), debugstr_w(doc->lpszDatatype));
426 if(physDev->job.id) {
427 FIXME("hJob != 0. Now what?\n");
428 return 0;
431 prn_def.pDatatype = NULL;
432 prn_def.pDevMode = &physDev->pi->Devmode->dmPublic;
433 prn_def.DesiredAccess = PRINTER_ACCESS_USE;
435 if (!OpenPrinterW( physDev->pi->friendly_name, &physDev->job.hprinter, &prn_def ))
437 WARN("OpenPrinter(%s, ...) failed: %d\n",
438 debugstr_w(physDev->pi->friendly_name), GetLastError());
439 return 0;
442 di.pDocName = (LPWSTR) doc->lpszDocName;
443 di.pDatatype = NULL;
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;
452 TRACE("using output: %s\n", debugstr_w(di.pOutputFile));
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;
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 );
470 return physDev->job.id;
473 /************************************************************************
474 * PSDRV_EndDoc
476 INT PSDRV_EndDoc( PHYSDEV dev )
478 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
479 INT ret = 1;
481 if(!physDev->job.id) {
482 FIXME("hJob == 0. Now what?\n");
483 return 0;
486 if(!physDev->job.OutOfPage) {
487 WARN("Somebody forgot an EndPage\n");
488 PSDRV_EndPage( dev );
491 if (physDev->job.PageNo)
492 PSDRV_WriteFooter( dev );
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;
501 return ret;