ntoskrnl.exe/tests: Add some IOCTL_HID_WRITE_REPORT tests.
[wine.git] / dlls / wineps.drv / escape.c
blob10eb68a4234c52cfdb09a20e9aaed7607bf5cb5e
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 <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <signal.h>
26 #include <errno.h>
27 #include <fcntl.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "wine/wingdi16.h"
33 #include "winuser.h"
34 #include "winreg.h"
35 #include "psdrv.h"
36 #include "wine/debug.h"
37 #include "winspool.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
41 DWORD write_spool( PHYSDEV dev, const void *data, DWORD num )
43 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
44 DWORD written;
46 if (!WritePrinter(physDev->job.hprinter, (LPBYTE) data, num, &written) || (written != num))
47 return SP_OUTOFDISK;
49 return num;
52 /**********************************************************************
53 * ExtEscape (WINEPS.@)
55 INT CDECL PSDRV_ExtEscape( PHYSDEV dev, INT nEscape, INT cbInput, LPCVOID in_data,
56 INT cbOutput, LPVOID out_data )
58 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
60 TRACE("%p,%d,%d,%p,%d,%p\n",
61 dev->hdc, nEscape, cbInput, in_data, cbOutput, out_data);
63 switch(nEscape)
65 case QUERYESCSUPPORT:
66 if(cbInput < sizeof(SHORT))
68 WARN("cbInput < sizeof(SHORT) (=%d) for QUERYESCSUPPORT\n", cbInput);
69 return 0;
70 } else {
71 DWORD num = (cbInput < sizeof(DWORD)) ? *(const USHORT *)in_data : *(const DWORD *)in_data;
72 TRACE("QUERYESCSUPPORT for %d\n", num);
74 switch(num) {
75 case NEXTBAND:
76 /*case BANDINFO:*/
77 case SETCOPYCOUNT:
78 case GETTECHNOLOGY:
79 case SETLINECAP:
80 case SETLINEJOIN:
81 case SETMITERLIMIT:
82 case SETCHARSET:
83 case EXT_DEVICE_CAPS:
84 case SET_BOUNDS:
85 case EPSPRINTING:
86 case POSTSCRIPT_DATA:
87 case PASSTHROUGH:
88 case POSTSCRIPT_PASSTHROUGH:
89 case POSTSCRIPT_IGNORE:
90 case BEGIN_PATH:
91 case CLIP_TO_PATH:
92 case END_PATH:
93 /*case DRAWPATTERNRECT:*/
95 /* PageMaker checks for it */
96 case DOWNLOADHEADER:
98 /* PageMaker doesn't check for DOWNLOADFACE and GETFACENAME but
99 * uses them, they are supposed to be supported by any PS printer.
101 case DOWNLOADFACE:
103 /* PageMaker checks for these as a part of process of detecting
104 * a "fully compatible" PS printer, but doesn't actually use them.
106 case OPENCHANNEL:
107 case CLOSECHANNEL:
108 return TRUE;
110 /* Windows PS driver reports 0, but still supports this escape */
111 case GETFACENAME:
112 return FALSE; /* suppress the FIXME below */
114 default:
115 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
116 return FALSE;
120 case OPENCHANNEL:
121 FIXME("OPENCHANNEL: stub\n");
122 return 1;
124 case CLOSECHANNEL:
125 FIXME("CLOSECHANNEL: stub\n");
126 return 1;
128 case DOWNLOADHEADER:
129 FIXME("DOWNLOADHEADER: stub\n");
130 /* should return name of the downloaded procset */
131 *(char *)out_data = 0;
132 return 1;
134 case GETFACENAME:
135 FIXME("GETFACENAME: stub\n");
136 lstrcpynA(out_data, "Courier", cbOutput);
137 return 1;
139 case DOWNLOADFACE:
140 FIXME("DOWNLOADFACE: stub\n");
141 return 1;
143 case MFCOMMENT:
145 FIXME("MFCOMMENT(%p, %d)\n", in_data, cbInput);
146 return 1;
148 case DRAWPATTERNRECT:
150 DRAWPATRECT *dpr = (DRAWPATRECT*)in_data;
152 FIXME("DRAWPATTERNRECT(pos (%d,%d), size %dx%d, style %d, pattern %x), stub!\n",
153 dpr->ptPosition.x, dpr->ptPosition.y,
154 dpr->ptSize.x, dpr->ptSize.y,
155 dpr->wStyle, dpr->wPattern
157 return 1;
159 case BANDINFO:
161 BANDINFOSTRUCT *ibi = (BANDINFOSTRUCT*)in_data;
162 BANDINFOSTRUCT *obi = (BANDINFOSTRUCT*)out_data;
164 FIXME("BANDINFO(graphics %d, text %d, rect %s), stub!\n", ibi->GraphicsFlag,
165 ibi->TextFlag, wine_dbgstr_rect(&ibi->GraphicsRect));
166 *obi = *ibi;
167 return 1;
169 case NEXTBAND:
171 RECT *r = out_data;
172 if(!physDev->job.banding) {
173 physDev->job.banding = TRUE;
174 SetRect(r, 0, 0, physDev->horzRes, physDev->vertRes);
175 TRACE("NEXTBAND returning %s\n", wine_dbgstr_rect(r));
176 return 1;
178 SetRectEmpty(r);
179 TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
180 physDev->job.banding = FALSE;
181 return EndPage( dev->hdc );
184 case SETCOPYCOUNT:
186 const INT *NumCopies = in_data;
187 INT *ActualCopies = out_data;
188 if(cbInput != sizeof(INT)) {
189 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
190 return 0;
192 TRACE("SETCOPYCOUNT %d\n", *NumCopies);
193 *ActualCopies = 1;
194 return 1;
197 case GETTECHNOLOGY:
199 LPSTR p = out_data;
200 strcpy(p, "PostScript");
201 *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
202 return 1;
205 case SETLINECAP:
207 INT newCap = *(const INT *)in_data;
208 if(cbInput != sizeof(INT)) {
209 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
210 return 0;
212 TRACE("SETLINECAP %d\n", newCap);
213 return 0;
216 case SETLINEJOIN:
218 INT newJoin = *(const INT *)in_data;
219 if(cbInput != sizeof(INT)) {
220 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
221 return 0;
223 TRACE("SETLINEJOIN %d\n", newJoin);
224 return 0;
227 case SETMITERLIMIT:
229 INT newLimit = *(const INT *)in_data;
230 if(cbInput != sizeof(INT)) {
231 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
232 return 0;
234 TRACE("SETMITERLIMIT %d\n", newLimit);
235 return 0;
238 case SETCHARSET:
239 /* Undocumented escape used by winword6.
240 Switches between ANSI and a special charset.
241 If *lpInData == 1 we require that
242 0x91 is quoteleft
243 0x92 is quoteright
244 0x93 is quotedblleft
245 0x94 is quotedblright
246 0x95 is bullet
247 0x96 is endash
248 0x97 is emdash
249 0xa0 is non break space - yeah right.
251 If *lpInData == 0 we get ANSI.
252 Since there's nothing else there, let's just make these the default
253 anyway and see what happens...
255 return 1;
257 case EXT_DEVICE_CAPS:
259 UINT cap = *(const UINT *)in_data;
260 if(cbInput != sizeof(UINT)) {
261 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
262 return 0;
264 TRACE("EXT_DEVICE_CAPS %d\n", cap);
265 return 0;
268 case SET_BOUNDS:
270 const RECT *r = in_data;
271 if(cbInput != sizeof(RECT)) {
272 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
273 return 0;
275 TRACE("SET_BOUNDS %s\n", wine_dbgstr_rect(r));
276 return 0;
279 case EPSPRINTING:
281 UINT epsprint = *(const UINT*)in_data;
282 /* FIXME: In this mode we do not need to send page intros and page
283 * ends according to the doc. But I just ignore that detail
284 * for now.
286 TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
287 return 1;
290 case POSTSCRIPT_DATA:
291 case PASSTHROUGH:
292 case POSTSCRIPT_PASSTHROUGH:
294 /* Write directly to spool file, bypassing normal PS driver
295 * processing that is done along with writing PostScript code
296 * to the spool.
297 * We have a WORD before the data counting the size, but
298 * cbInput is just this +2.
299 * However Photoshop 7 has a bug that sets cbInput to 2 less than the
300 * length of the string, rather than 2 more. So we'll use the WORD at
301 * in_data[0] instead.
303 passthrough_enter(dev);
304 return write_spool(dev, ((char*)in_data) + 2, *(const WORD*)in_data);
307 case POSTSCRIPT_IGNORE:
309 BOOL ret = physDev->job.quiet;
310 TRACE("POSTSCRIPT_IGNORE %d\n", *(const short*)in_data);
311 physDev->job.quiet = *(const short*)in_data;
312 return ret;
315 case GETSETPRINTORIENT:
317 /* If lpInData is present, it is a 20 byte structure, first 32
318 * bit LONG value is the orientation. if lpInData is NULL, it
319 * returns the current orientation.
321 FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
322 return 1;
324 case BEGIN_PATH:
325 TRACE("BEGIN_PATH\n");
326 if(physDev->pathdepth)
327 FIXME("Nested paths not yet handled\n");
328 return ++physDev->pathdepth;
330 case END_PATH:
332 const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
334 TRACE("END_PATH\n");
335 if(!physDev->pathdepth) {
336 ERR("END_PATH called without a BEGIN_PATH\n");
337 return -1;
339 TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
340 info->RenderMode, info->FillMode, info->BkMode);
341 switch(info->RenderMode) {
342 case RENDERMODE_NO_DISPLAY:
343 PSDRV_WriteClosePath(dev); /* not sure if this is necessary, but it can't hurt */
344 break;
345 case RENDERMODE_OPEN:
346 case RENDERMODE_CLOSED:
347 default:
348 FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
349 break;
351 return --physDev->pathdepth;
354 case CLIP_TO_PATH:
356 WORD mode = *(const WORD*)in_data;
358 switch(mode) {
359 case CLIP_SAVE:
360 TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
361 PSDRV_WriteGSave(dev);
362 return 1;
363 case CLIP_RESTORE:
364 TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
365 PSDRV_WriteGRestore(dev);
366 return 1;
367 case CLIP_INCLUSIVE:
368 TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
369 /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
370 PSDRV_WriteClip(dev);
371 PSDRV_WriteNewPath(dev);
372 return 1;
373 case CLIP_EXCLUSIVE:
374 FIXME("CLIP_EXCLUSIVE: not implemented\n");
375 return 0;
376 default:
377 FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
378 return 0;
381 default:
382 FIXME("Unimplemented code %d\n", nEscape);
383 return 0;
387 /************************************************************************
388 * PSDRV_StartPage
390 INT CDECL PSDRV_StartPage( PHYSDEV dev )
392 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
394 TRACE("%p\n", dev->hdc);
396 if(!physDev->job.OutOfPage) {
397 FIXME("Already started a page?\n");
398 return 1;
401 physDev->job.PageNo++;
403 if(!PSDRV_WriteNewPage( dev ))
404 return 0;
405 physDev->job.OutOfPage = FALSE;
406 return 1;
410 /************************************************************************
411 * PSDRV_EndPage
413 INT CDECL PSDRV_EndPage( PHYSDEV dev )
415 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
417 TRACE("%p\n", dev->hdc);
419 if(physDev->job.OutOfPage) {
420 FIXME("Already ended a page?\n");
421 return 1;
424 passthrough_leave(dev);
425 if(!PSDRV_WriteEndPage( dev ))
426 return 0;
427 PSDRV_EmptyDownloadList(dev, FALSE);
428 physDev->job.OutOfPage = TRUE;
429 return 1;
433 /************************************************************************
434 * PSDRV_StartDoc
436 INT CDECL PSDRV_StartDoc( PHYSDEV dev, const DOCINFOW *doc )
438 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
439 DOC_INFO_1W di;
440 PRINTER_DEFAULTSW prn_def;
442 TRACE("(%p, %p) => %s, %s, %s\n", physDev, doc, debugstr_w(doc->lpszDocName),
443 debugstr_w(doc->lpszOutput), debugstr_w(doc->lpszDatatype));
445 if(physDev->job.id) {
446 FIXME("hJob != 0. Now what?\n");
447 return 0;
450 prn_def.pDatatype = NULL;
451 prn_def.pDevMode = &physDev->pi->Devmode->dmPublic;
452 prn_def.DesiredAccess = PRINTER_ACCESS_USE;
454 if (!OpenPrinterW( physDev->pi->friendly_name, &physDev->job.hprinter, &prn_def ))
456 WARN("OpenPrinter(%s, ...) failed: %d\n",
457 debugstr_w(physDev->pi->friendly_name), GetLastError());
458 return 0;
461 di.pDocName = (LPWSTR) doc->lpszDocName;
462 di.pDatatype = NULL;
464 if(doc->lpszOutput)
465 di.pOutputFile = (LPWSTR) doc->lpszOutput;
466 else if(physDev->job.output)
467 di.pOutputFile = physDev->job.output;
468 else
469 di.pOutputFile = NULL;
471 TRACE("using output: %s\n", debugstr_w(di.pOutputFile));
473 /* redirection located in HKCU\Software\Wine\Printing\Spooler
474 is done during winspool.drv,ScheduleJob */
475 physDev->job.id = StartDocPrinterW(physDev->job.hprinter, 1, (LPBYTE) &di);
476 if(!physDev->job.id) {
477 WARN("StartDocPrinter() failed: %d\n", GetLastError());
478 ClosePrinter(physDev->job.hprinter);
479 return 0;
482 if (!PSDRV_WriteHeader( dev, doc->lpszDocName )) {
483 WARN("Failed to write header\n");
484 ClosePrinter(physDev->job.hprinter);
485 return 0;
488 physDev->job.banding = FALSE;
489 physDev->job.OutOfPage = TRUE;
490 physDev->job.PageNo = 0;
491 physDev->job.quiet = FALSE;
492 physDev->job.passthrough_state = passthrough_none;
493 physDev->job.doc_name = strdupW( doc->lpszDocName );
495 return physDev->job.id;
498 /************************************************************************
499 * PSDRV_EndDoc
501 INT CDECL PSDRV_EndDoc( PHYSDEV dev )
503 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
504 INT ret = 1;
506 TRACE("%p\n", dev->hdc);
508 if(!physDev->job.id) {
509 FIXME("hJob == 0. Now what?\n");
510 return 0;
513 if(!physDev->job.OutOfPage) {
514 WARN("Somebody forgot an EndPage\n");
515 PSDRV_EndPage( dev );
518 if (physDev->job.PageNo)
519 PSDRV_WriteFooter( dev );
521 ret = EndDocPrinter(physDev->job.hprinter);
522 ClosePrinter(physDev->job.hprinter);
523 physDev->job.hprinter = NULL;
524 physDev->job.id = 0;
525 HeapFree( GetProcessHeap(), 0, physDev->job.doc_name );
526 physDev->job.doc_name = NULL;
528 return ret;