comctl32/tests: Make test_combo_WS_VSCROLL() static.
[wine.git] / dlls / wineps.drv / escape.c
blob636ad2a2b3d34ebfab7e9dd1c7b63e0ffd173ef1
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 "winuser.h"
40 #include "winreg.h"
41 #include "psdrv.h"
42 #include "wine/debug.h"
43 #include "winspool.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
47 static const char psbegindocument[] =
48 "%%BeginDocument: Wine passthrough\n";
51 DWORD write_spool( PHYSDEV dev, const void *data, DWORD num )
53 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
54 DWORD written;
56 if (!WritePrinter(physDev->job.hprinter, (LPBYTE) data, num, &written) || (written != num))
57 return SP_OUTOFDISK;
59 return num;
62 /**********************************************************************
63 * ExtEscape (WINEPS.@)
65 INT PSDRV_ExtEscape( PHYSDEV dev, INT nEscape, INT cbInput, LPCVOID in_data,
66 INT cbOutput, LPVOID out_data )
68 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
70 TRACE("%p,%d,%d,%p,%d,%p\n",
71 dev->hdc, nEscape, cbInput, in_data, cbOutput, out_data);
73 switch(nEscape)
75 case QUERYESCSUPPORT:
76 if(cbInput < sizeof(SHORT))
78 WARN("cbInput < sizeof(SHORT) (=%d) for QUERYESCSUPPORT\n", cbInput);
79 return 0;
80 } else {
81 DWORD num = (cbInput < sizeof(DWORD)) ? *(const USHORT *)in_data : *(const DWORD *)in_data;
82 TRACE("QUERYESCSUPPORT for %d\n", num);
84 switch(num) {
85 case NEXTBAND:
86 /*case BANDINFO:*/
87 case SETCOPYCOUNT:
88 case GETTECHNOLOGY:
89 case SETLINECAP:
90 case SETLINEJOIN:
91 case SETMITERLIMIT:
92 case SETCHARSET:
93 case EXT_DEVICE_CAPS:
94 case SET_BOUNDS:
95 case EPSPRINTING:
96 case POSTSCRIPT_DATA:
97 case PASSTHROUGH:
98 case POSTSCRIPT_PASSTHROUGH:
99 case POSTSCRIPT_IGNORE:
100 case BEGIN_PATH:
101 case CLIP_TO_PATH:
102 case END_PATH:
103 /*case DRAWPATTERNRECT:*/
104 return TRUE;
106 default:
107 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
108 return FALSE;
112 case MFCOMMENT:
114 FIXME("MFCOMMENT(%p, %d)\n", in_data, cbInput);
115 return 1;
117 case DRAWPATTERNRECT:
119 DRAWPATRECT *dpr = (DRAWPATRECT*)in_data;
121 FIXME("DRAWPATTERNRECT(pos (%d,%d), size %dx%d, style %d, pattern %x), stub!\n",
122 dpr->ptPosition.x, dpr->ptPosition.y,
123 dpr->ptSize.x, dpr->ptSize.y,
124 dpr->wStyle, dpr->wPattern
126 return 1;
128 case BANDINFO:
130 BANDINFOSTRUCT *ibi = (BANDINFOSTRUCT*)in_data;
131 BANDINFOSTRUCT *obi = (BANDINFOSTRUCT*)out_data;
133 FIXME("BANDINFO(graphics %d, text %d, rect %s), stub!\n", ibi->GraphicsFlag,
134 ibi->TextFlag, wine_dbgstr_rect(&ibi->GraphicsRect));
135 *obi = *ibi;
136 return 1;
138 case NEXTBAND:
140 RECT *r = out_data;
141 if(!physDev->job.banding) {
142 physDev->job.banding = TRUE;
143 SetRect(r, 0, 0, physDev->horzRes, physDev->vertRes);
144 TRACE("NEXTBAND returning %s\n", wine_dbgstr_rect(r));
145 return 1;
147 SetRectEmpty(r);
148 TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
149 physDev->job.banding = FALSE;
150 return EndPage( dev->hdc );
153 case SETCOPYCOUNT:
155 const INT *NumCopies = in_data;
156 INT *ActualCopies = out_data;
157 if(cbInput != sizeof(INT)) {
158 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
159 return 0;
161 TRACE("SETCOPYCOUNT %d\n", *NumCopies);
162 *ActualCopies = 1;
163 return 1;
166 case GETTECHNOLOGY:
168 LPSTR p = out_data;
169 strcpy(p, "PostScript");
170 *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
171 return 1;
174 case SETLINECAP:
176 INT newCap = *(const INT *)in_data;
177 if(cbInput != sizeof(INT)) {
178 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
179 return 0;
181 TRACE("SETLINECAP %d\n", newCap);
182 return 0;
185 case SETLINEJOIN:
187 INT newJoin = *(const INT *)in_data;
188 if(cbInput != sizeof(INT)) {
189 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
190 return 0;
192 TRACE("SETLINEJOIN %d\n", newJoin);
193 return 0;
196 case SETMITERLIMIT:
198 INT newLimit = *(const INT *)in_data;
199 if(cbInput != sizeof(INT)) {
200 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
201 return 0;
203 TRACE("SETMITERLIMIT %d\n", newLimit);
204 return 0;
207 case SETCHARSET:
208 /* Undocumented escape used by winword6.
209 Switches between ANSI and a special charset.
210 If *lpInData == 1 we require that
211 0x91 is quoteleft
212 0x92 is quoteright
213 0x93 is quotedblleft
214 0x94 is quotedblright
215 0x95 is bullet
216 0x96 is endash
217 0x97 is emdash
218 0xa0 is non break space - yeah right.
220 If *lpInData == 0 we get ANSI.
221 Since there's nothing else there, let's just make these the default
222 anyway and see what happens...
224 return 1;
226 case EXT_DEVICE_CAPS:
228 UINT cap = *(const UINT *)in_data;
229 if(cbInput != sizeof(UINT)) {
230 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
231 return 0;
233 TRACE("EXT_DEVICE_CAPS %d\n", cap);
234 return 0;
237 case SET_BOUNDS:
239 const RECT *r = in_data;
240 if(cbInput != sizeof(RECT)) {
241 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
242 return 0;
244 TRACE("SET_BOUNDS %s\n", wine_dbgstr_rect(r));
245 return 0;
248 case EPSPRINTING:
250 UINT epsprint = *(const UINT*)in_data;
251 /* FIXME: In this mode we do not need to send page intros and page
252 * ends according to the doc. But I just ignore that detail
253 * for now.
255 TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
256 return 1;
259 case POSTSCRIPT_DATA:
260 case PASSTHROUGH:
261 case POSTSCRIPT_PASSTHROUGH:
263 /* Write directly to spool file, bypassing normal PS driver
264 * processing that is done along with writing PostScript code
265 * to the spool.
266 * We have a WORD before the data counting the size, but
267 * cbInput is just this +2.
268 * However Photoshop 7 has a bug that sets cbInput to 2 less than the
269 * length of the string, rather than 2 more. So we'll use the WORD at
270 * in_data[0] instead.
272 if(!physDev->job.in_passthrough) {
273 write_spool(dev, psbegindocument, sizeof(psbegindocument)-1);
274 physDev->job.in_passthrough = TRUE;
276 return write_spool(dev,((char*)in_data)+2,*(const WORD*)in_data);
279 case POSTSCRIPT_IGNORE:
281 BOOL ret = physDev->job.quiet;
282 TRACE("POSTSCRIPT_IGNORE %d\n", *(const short*)in_data);
283 physDev->job.quiet = *(const short*)in_data;
284 return ret;
287 case GETSETPRINTORIENT:
289 /* If lpInData is present, it is a 20 byte structure, first 32
290 * bit LONG value is the orientation. if lpInData is NULL, it
291 * returns the current orientation.
293 FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
294 return 1;
296 case BEGIN_PATH:
297 TRACE("BEGIN_PATH\n");
298 if(physDev->pathdepth)
299 FIXME("Nested paths not yet handled\n");
300 return ++physDev->pathdepth;
302 case END_PATH:
304 const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
306 TRACE("END_PATH\n");
307 if(!physDev->pathdepth) {
308 ERR("END_PATH called without a BEGIN_PATH\n");
309 return -1;
311 TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
312 info->RenderMode, info->FillMode, info->BkMode);
313 switch(info->RenderMode) {
314 case RENDERMODE_NO_DISPLAY:
315 PSDRV_WriteClosePath(dev); /* not sure if this is necessary, but it can't hurt */
316 break;
317 case RENDERMODE_OPEN:
318 case RENDERMODE_CLOSED:
319 default:
320 FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
321 break;
323 return --physDev->pathdepth;
326 case CLIP_TO_PATH:
328 WORD mode = *(const WORD*)in_data;
330 switch(mode) {
331 case CLIP_SAVE:
332 TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
333 PSDRV_WriteGSave(dev);
334 return 1;
335 case CLIP_RESTORE:
336 TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
337 PSDRV_WriteGRestore(dev);
338 return 1;
339 case CLIP_INCLUSIVE:
340 TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
341 /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
342 PSDRV_WriteClip(dev);
343 PSDRV_WriteNewPath(dev);
344 return 1;
345 case CLIP_EXCLUSIVE:
346 FIXME("CLIP_EXCLUSIVE: not implemented\n");
347 return 0;
348 default:
349 FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
350 return 0;
353 default:
354 FIXME("Unimplemented code %d\n", nEscape);
355 return 0;
359 /************************************************************************
360 * PSDRV_StartPage
362 INT PSDRV_StartPage( PHYSDEV dev )
364 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
366 if(!physDev->job.OutOfPage) {
367 FIXME("Already started a page?\n");
368 return 1;
371 if(physDev->job.PageNo++ == 0) {
372 if(!PSDRV_WriteHeader( dev, physDev->job.doc_name ))
373 return 0;
376 if(!PSDRV_WriteNewPage( dev ))
377 return 0;
378 physDev->job.OutOfPage = FALSE;
379 return 1;
383 /************************************************************************
384 * PSDRV_EndPage
386 INT PSDRV_EndPage( PHYSDEV dev )
388 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
390 if(physDev->job.OutOfPage) {
391 FIXME("Already ended a page?\n");
392 return 1;
394 if(!PSDRV_WriteEndPage( dev ))
395 return 0;
396 PSDRV_EmptyDownloadList(dev, FALSE);
397 physDev->job.OutOfPage = TRUE;
398 return 1;
402 /************************************************************************
403 * PSDRV_StartDoc
405 INT PSDRV_StartDoc( PHYSDEV dev, const DOCINFOW *doc )
407 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
408 DOC_INFO_1W di;
409 PRINTER_DEFAULTSW prn_def;
411 TRACE("(%p, %p) => %s, %s, %s\n", physDev, doc, debugstr_w(doc->lpszDocName),
412 debugstr_w(doc->lpszOutput), debugstr_w(doc->lpszDatatype));
414 if(physDev->job.id) {
415 FIXME("hJob != 0. Now what?\n");
416 return 0;
419 prn_def.pDatatype = NULL;
420 prn_def.pDevMode = &physDev->pi->Devmode->dmPublic;
421 prn_def.DesiredAccess = PRINTER_ACCESS_USE;
423 if (!OpenPrinterW( physDev->pi->friendly_name, &physDev->job.hprinter, &prn_def ))
425 WARN("OpenPrinter(%s, ...) failed: %d\n",
426 debugstr_w(physDev->pi->friendly_name), GetLastError());
427 return 0;
430 di.pDocName = (LPWSTR) doc->lpszDocName;
431 di.pDatatype = NULL;
433 if(doc->lpszOutput)
434 di.pOutputFile = (LPWSTR) doc->lpszOutput;
435 else if(physDev->job.output)
436 di.pOutputFile = physDev->job.output;
437 else
438 di.pOutputFile = NULL;
440 TRACE("using output: %s\n", debugstr_w(di.pOutputFile));
442 /* redirection located in HKCU\Software\Wine\Printing\Spooler
443 is done during winspool.drv,ScheduleJob */
444 physDev->job.id = StartDocPrinterW(physDev->job.hprinter, 1, (LPBYTE) &di);
445 if(!physDev->job.id) {
446 WARN("StartDocPrinter() failed: %d\n", GetLastError());
447 ClosePrinter(physDev->job.hprinter);
448 return 0;
450 physDev->job.banding = FALSE;
451 physDev->job.OutOfPage = TRUE;
452 physDev->job.PageNo = 0;
453 physDev->job.quiet = FALSE;
454 physDev->job.in_passthrough = FALSE;
455 physDev->job.had_passthrough_rect = FALSE;
456 physDev->job.doc_name = strdupW( doc->lpszDocName );
458 return physDev->job.id;
461 /************************************************************************
462 * PSDRV_EndDoc
464 INT PSDRV_EndDoc( PHYSDEV dev )
466 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
467 INT ret = 1;
469 if(!physDev->job.id) {
470 FIXME("hJob == 0. Now what?\n");
471 return 0;
474 if(!physDev->job.OutOfPage) {
475 WARN("Somebody forgot an EndPage\n");
476 PSDRV_EndPage( dev );
479 if (physDev->job.PageNo)
480 PSDRV_WriteFooter( dev );
482 ret = EndDocPrinter(physDev->job.hprinter);
483 ClosePrinter(physDev->job.hprinter);
484 physDev->job.hprinter = NULL;
485 physDev->job.id = 0;
486 HeapFree( GetProcessHeap(), 0, physDev->job.doc_name );
487 physDev->job.doc_name = NULL;
489 return ret;