comctl32: Use SetRect() instead of open coding it.
[wine.git] / dlls / wineps.drv / escape.c
blob00a4a6c136fb8599dd840f1a0d449c293a1a5e84
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 %s\n", wine_dbgstr_rect(r));
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 %s\n", wine_dbgstr_rect(r));
256 return 0;
259 case EPSPRINTING:
261 UINT epsprint = *(const UINT*)in_data;
262 /* FIXME: In this mode we do not need to send page intros and page
263 * ends according to the doc. But I just ignore that detail
264 * for now.
266 TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
267 return 1;
270 case POSTSCRIPT_DATA:
271 case PASSTHROUGH:
272 case POSTSCRIPT_PASSTHROUGH:
274 /* Write directly to spool file, bypassing normal PS driver
275 * processing that is done along with writing PostScript code
276 * to the spool.
277 * We have a WORD before the data counting the size, but
278 * cbInput is just this +2.
279 * However Photoshop 7 has a bug that sets cbInput to 2 less than the
280 * length of the string, rather than 2 more. So we'll use the WORD at
281 * in_data[0] instead.
283 if(!physDev->job.in_passthrough) {
284 write_spool(dev, psbegindocument, sizeof(psbegindocument)-1);
285 physDev->job.in_passthrough = TRUE;
287 return write_spool(dev,((char*)in_data)+2,*(const WORD*)in_data);
290 case POSTSCRIPT_IGNORE:
292 BOOL ret = physDev->job.quiet;
293 TRACE("POSTSCRIPT_IGNORE %d\n", *(const short*)in_data);
294 physDev->job.quiet = *(const short*)in_data;
295 return ret;
298 case GETSETPRINTORIENT:
300 /* If lpInData is present, it is a 20 byte structure, first 32
301 * bit LONG value is the orientation. if lpInData is NULL, it
302 * returns the current orientation.
304 FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
305 return 1;
307 case BEGIN_PATH:
308 TRACE("BEGIN_PATH\n");
309 if(physDev->pathdepth)
310 FIXME("Nested paths not yet handled\n");
311 return ++physDev->pathdepth;
313 case END_PATH:
315 const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
317 TRACE("END_PATH\n");
318 if(!physDev->pathdepth) {
319 ERR("END_PATH called without a BEGIN_PATH\n");
320 return -1;
322 TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
323 info->RenderMode, info->FillMode, info->BkMode);
324 switch(info->RenderMode) {
325 case RENDERMODE_NO_DISPLAY:
326 PSDRV_WriteClosePath(dev); /* not sure if this is necessary, but it can't hurt */
327 break;
328 case RENDERMODE_OPEN:
329 case RENDERMODE_CLOSED:
330 default:
331 FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
332 break;
334 return --physDev->pathdepth;
337 case CLIP_TO_PATH:
339 WORD mode = *(const WORD*)in_data;
341 switch(mode) {
342 case CLIP_SAVE:
343 TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
344 PSDRV_WriteGSave(dev);
345 return 1;
346 case CLIP_RESTORE:
347 TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
348 PSDRV_WriteGRestore(dev);
349 return 1;
350 case CLIP_INCLUSIVE:
351 TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
352 /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
353 PSDRV_WriteClip(dev);
354 PSDRV_WriteNewPath(dev);
355 return 1;
356 case CLIP_EXCLUSIVE:
357 FIXME("CLIP_EXCLUSIVE: not implemented\n");
358 return 0;
359 default:
360 FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
361 return 0;
364 default:
365 FIXME("Unimplemented code %d\n", nEscape);
366 return 0;
370 /************************************************************************
371 * PSDRV_StartPage
373 INT PSDRV_StartPage( PHYSDEV dev )
375 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
377 if(!physDev->job.OutOfPage) {
378 FIXME("Already started a page?\n");
379 return 1;
382 if(physDev->job.PageNo++ == 0) {
383 if(!PSDRV_WriteHeader( dev, physDev->job.doc_name ))
384 return 0;
387 if(!PSDRV_WriteNewPage( dev ))
388 return 0;
389 physDev->job.OutOfPage = FALSE;
390 return 1;
394 /************************************************************************
395 * PSDRV_EndPage
397 INT PSDRV_EndPage( PHYSDEV dev )
399 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
401 if(physDev->job.OutOfPage) {
402 FIXME("Already ended a page?\n");
403 return 1;
405 if(!PSDRV_WriteEndPage( dev ))
406 return 0;
407 PSDRV_EmptyDownloadList(dev, FALSE);
408 physDev->job.OutOfPage = TRUE;
409 return 1;
413 /************************************************************************
414 * PSDRV_StartDoc
416 INT PSDRV_StartDoc( PHYSDEV dev, const DOCINFOW *doc )
418 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
419 DOC_INFO_1W di;
420 PRINTER_DEFAULTSW prn_def;
422 TRACE("(%p, %p) => %s, %s, %s\n", physDev, doc, debugstr_w(doc->lpszDocName),
423 debugstr_w(doc->lpszOutput), debugstr_w(doc->lpszDatatype));
425 if(physDev->job.id) {
426 FIXME("hJob != 0. Now what?\n");
427 return 0;
430 prn_def.pDatatype = NULL;
431 prn_def.pDevMode = &physDev->pi->Devmode->dmPublic;
432 prn_def.DesiredAccess = PRINTER_ACCESS_USE;
434 if (!OpenPrinterW( physDev->pi->friendly_name, &physDev->job.hprinter, &prn_def ))
436 WARN("OpenPrinter(%s, ...) failed: %d\n",
437 debugstr_w(physDev->pi->friendly_name), GetLastError());
438 return 0;
441 di.pDocName = (LPWSTR) doc->lpszDocName;
442 di.pDatatype = NULL;
444 if(doc->lpszOutput)
445 di.pOutputFile = (LPWSTR) doc->lpszOutput;
446 else if(physDev->job.output)
447 di.pOutputFile = physDev->job.output;
448 else
449 di.pOutputFile = NULL;
451 TRACE("using output: %s\n", debugstr_w(di.pOutputFile));
453 /* redirection located in HKCU\Software\Wine\Printing\Spooler
454 is done during winspool.drv,ScheduleJob */
455 physDev->job.id = StartDocPrinterW(physDev->job.hprinter, 1, (LPBYTE) &di);
456 if(!physDev->job.id) {
457 WARN("StartDocPrinter() failed: %d\n", GetLastError());
458 ClosePrinter(physDev->job.hprinter);
459 return 0;
461 physDev->job.banding = FALSE;
462 physDev->job.OutOfPage = TRUE;
463 physDev->job.PageNo = 0;
464 physDev->job.quiet = FALSE;
465 physDev->job.in_passthrough = FALSE;
466 physDev->job.had_passthrough_rect = FALSE;
467 physDev->job.doc_name = strdupW( doc->lpszDocName );
469 return physDev->job.id;
472 /************************************************************************
473 * PSDRV_EndDoc
475 INT PSDRV_EndDoc( PHYSDEV dev )
477 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
478 INT ret = 1;
480 if(!physDev->job.id) {
481 FIXME("hJob == 0. Now what?\n");
482 return 0;
485 if(!physDev->job.OutOfPage) {
486 WARN("Somebody forgot an EndPage\n");
487 PSDRV_EndPage( dev );
490 if (physDev->job.PageNo)
491 PSDRV_WriteFooter( dev );
493 ret = EndDocPrinter(physDev->job.hprinter);
494 ClosePrinter(physDev->job.hprinter);
495 physDev->job.hprinter = NULL;
496 physDev->job.id = 0;
497 HeapFree( GetProcessHeap(), 0, physDev->job.doc_name );
498 physDev->job.doc_name = NULL;
500 return ret;