wineps: Use the unicode version of StartDocPrinter.
[wine/multimedia.git] / dlls / wineps.drv / escape.c
blob66a1a89d019b6de4cffdfe8e8a68efe474ebd743
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 switch(nEscape)
71 case QUERYESCSUPPORT:
72 if(cbInput < sizeof(INT))
74 WARN("cbInput < sizeof(INT) (=%d) for QUERYESCSUPPORT\n", cbInput);
75 return 0;
76 } else {
77 UINT num = *(const UINT *)in_data;
78 TRACE("QUERYESCSUPPORT for %d\n", num);
80 switch(num) {
81 case NEXTBAND:
82 /*case BANDINFO:*/
83 case SETCOPYCOUNT:
84 case GETTECHNOLOGY:
85 case SETLINECAP:
86 case SETLINEJOIN:
87 case SETMITERLIMIT:
88 case SETCHARSET:
89 case EXT_DEVICE_CAPS:
90 case SET_BOUNDS:
91 case EPSPRINTING:
92 case POSTSCRIPT_DATA:
93 case PASSTHROUGH:
94 case POSTSCRIPT_PASSTHROUGH:
95 case POSTSCRIPT_IGNORE:
96 case BEGIN_PATH:
97 case CLIP_TO_PATH:
98 case END_PATH:
99 /*case DRAWPATTERNRECT:*/
100 return TRUE;
102 default:
103 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
104 return FALSE;
108 case MFCOMMENT:
110 FIXME("MFCOMMENT(%p, %d)\n", in_data, cbInput);
111 return 1;
113 case DRAWPATTERNRECT:
115 DRAWPATRECT *dpr = (DRAWPATRECT*)in_data;
117 FIXME("DRAWPATTERNRECT(pos (%d,%d), size %dx%d, style %d, pattern %x), stub!\n",
118 dpr->ptPosition.x, dpr->ptPosition.y,
119 dpr->ptSize.x, dpr->ptSize.y,
120 dpr->wStyle, dpr->wPattern
122 return 1;
124 case BANDINFO:
126 BANDINFOSTRUCT *ibi = (BANDINFOSTRUCT*)in_data;
127 BANDINFOSTRUCT *obi = (BANDINFOSTRUCT*)out_data;
129 FIXME("BANDINFO(graphics %d, text %d, rect [%dx%d-%dx%d]), stub!\n",
130 ibi->GraphicsFlag,
131 ibi->TextFlag,
132 ibi->GraphicsRect.top,
133 ibi->GraphicsRect.bottom,
134 ibi->GraphicsRect.left,
135 ibi->GraphicsRect.right
137 *obi = *ibi;
138 return 1;
140 case NEXTBAND:
142 RECT *r = out_data;
143 if(!physDev->job.banding) {
144 physDev->job.banding = TRUE;
145 r->left = 0;
146 r->top = 0;
147 r->right = physDev->horzRes;
148 r->bottom = physDev->vertRes;
149 TRACE("NEXTBAND returning %d,%d - %d,%d\n", r->left, r->top, r->right, r->bottom );
150 return 1;
152 r->left = 0;
153 r->top = 0;
154 r->right = 0;
155 r->bottom = 0;
156 TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
157 physDev->job.banding = FALSE;
158 return EndPage( dev->hdc );
161 case SETCOPYCOUNT:
163 const INT *NumCopies = in_data;
164 INT *ActualCopies = out_data;
165 if(cbInput != sizeof(INT)) {
166 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
167 return 0;
169 TRACE("SETCOPYCOUNT %d\n", *NumCopies);
170 *ActualCopies = 1;
171 return 1;
174 case GETTECHNOLOGY:
176 LPSTR p = out_data;
177 strcpy(p, "PostScript");
178 *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
179 return 1;
182 case SETLINECAP:
184 INT newCap = *(const INT *)in_data;
185 if(cbInput != sizeof(INT)) {
186 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
187 return 0;
189 TRACE("SETLINECAP %d\n", newCap);
190 return 0;
193 case SETLINEJOIN:
195 INT newJoin = *(const INT *)in_data;
196 if(cbInput != sizeof(INT)) {
197 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
198 return 0;
200 TRACE("SETLINEJOIN %d\n", newJoin);
201 return 0;
204 case SETMITERLIMIT:
206 INT newLimit = *(const INT *)in_data;
207 if(cbInput != sizeof(INT)) {
208 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
209 return 0;
211 TRACE("SETMITERLIMIT %d\n", newLimit);
212 return 0;
215 case SETCHARSET:
216 /* Undocumented escape used by winword6.
217 Switches between ANSI and a special charset.
218 If *lpInData == 1 we require that
219 0x91 is quoteleft
220 0x92 is quoteright
221 0x93 is quotedblleft
222 0x94 is quotedblright
223 0x95 is bullet
224 0x96 is endash
225 0x97 is emdash
226 0xa0 is non break space - yeah right.
228 If *lpInData == 0 we get ANSI.
229 Since there's nothing else there, let's just make these the default
230 anyway and see what happens...
232 return 1;
234 case EXT_DEVICE_CAPS:
236 UINT cap = *(const UINT *)in_data;
237 if(cbInput != sizeof(UINT)) {
238 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
239 return 0;
241 TRACE("EXT_DEVICE_CAPS %d\n", cap);
242 return 0;
245 case SET_BOUNDS:
247 const RECT *r = in_data;
248 if(cbInput != sizeof(RECT)) {
249 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
250 return 0;
252 TRACE("SET_BOUNDS (%d,%d) - (%d,%d)\n", r->left, r->top,
253 r->right, r->bottom);
254 return 0;
257 case EPSPRINTING:
259 UINT epsprint = *(const UINT*)in_data;
260 /* FIXME: In this mode we do not need to send page intros and page
261 * ends according to the doc. But I just ignore that detail
262 * for now.
264 TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
265 return 1;
268 case POSTSCRIPT_DATA:
269 case PASSTHROUGH:
270 case POSTSCRIPT_PASSTHROUGH:
272 /* Write directly to spool file, bypassing normal PS driver
273 * processing that is done along with writing PostScript code
274 * to the spool.
275 * We have a WORD before the data counting the size, but
276 * cbInput is just this +2.
277 * However Photoshop 7 has a bug that sets cbInput to 2 less than the
278 * length of the string, rather than 2 more. So we'll use the WORD at
279 * in_data[0] instead.
281 if(!physDev->job.in_passthrough) {
282 write_spool(dev, psbegindocument, sizeof(psbegindocument)-1);
283 physDev->job.in_passthrough = TRUE;
285 return write_spool(dev,((char*)in_data)+2,*(const WORD*)in_data);
288 case POSTSCRIPT_IGNORE:
290 BOOL ret = physDev->job.quiet;
291 TRACE("POSTSCRIPT_IGNORE %d\n", *(const short*)in_data);
292 physDev->job.quiet = *(const short*)in_data;
293 return ret;
296 case GETSETPRINTORIENT:
298 /* If lpInData is present, it is a 20 byte structure, first 32
299 * bit LONG value is the orientation. if lpInData is NULL, it
300 * returns the current orientation.
302 FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
303 return 1;
305 case BEGIN_PATH:
306 TRACE("BEGIN_PATH\n");
307 if(physDev->pathdepth)
308 FIXME("Nested paths not yet handled\n");
309 return ++physDev->pathdepth;
311 case END_PATH:
313 const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
315 TRACE("END_PATH\n");
316 if(!physDev->pathdepth) {
317 ERR("END_PATH called without a BEGIN_PATH\n");
318 return -1;
320 TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
321 info->RenderMode, info->FillMode, info->BkMode);
322 switch(info->RenderMode) {
323 case RENDERMODE_NO_DISPLAY:
324 PSDRV_WriteClosePath(dev); /* not sure if this is necessary, but it can't hurt */
325 break;
326 case RENDERMODE_OPEN:
327 case RENDERMODE_CLOSED:
328 default:
329 FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
330 break;
332 return --physDev->pathdepth;
335 case CLIP_TO_PATH:
337 WORD mode = *(const WORD*)in_data;
339 switch(mode) {
340 case CLIP_SAVE:
341 TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
342 PSDRV_WriteGSave(dev);
343 return 1;
344 case CLIP_RESTORE:
345 TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
346 PSDRV_WriteGRestore(dev);
347 return 1;
348 case CLIP_INCLUSIVE:
349 TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
350 /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
351 PSDRV_WriteClip(dev);
352 PSDRV_WriteNewPath(dev);
353 return 1;
354 case CLIP_EXCLUSIVE:
355 FIXME("CLIP_EXCLUSIVE: not implemented\n");
356 return 0;
357 default:
358 FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
359 return 0;
362 default:
363 FIXME("Unimplemented code %d\n", nEscape);
364 return 0;
368 /************************************************************************
369 * PSDRV_StartPage
371 INT PSDRV_StartPage( PHYSDEV dev )
373 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
375 if(!physDev->job.OutOfPage) {
376 FIXME("Already started a page?\n");
377 return 1;
380 if(physDev->job.PageNo++ == 0) {
381 if(!PSDRV_WriteHeader( dev, physDev->job.DocName ))
382 return 0;
385 if(!PSDRV_WriteNewPage( dev ))
386 return 0;
387 physDev->job.OutOfPage = FALSE;
388 return 1;
392 /************************************************************************
393 * PSDRV_EndPage
395 INT PSDRV_EndPage( PHYSDEV dev )
397 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
399 if(physDev->job.OutOfPage) {
400 FIXME("Already ended a page?\n");
401 return 1;
403 if(!PSDRV_WriteEndPage( dev ))
404 return 0;
405 PSDRV_EmptyDownloadList(dev, FALSE);
406 physDev->job.OutOfPage = TRUE;
407 return 1;
411 /************************************************************************
412 * PSDRV_StartDoc
414 INT PSDRV_StartDoc( PHYSDEV dev, const DOCINFOW *doc )
416 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
417 DOC_INFO_1W di;
419 TRACE("(%p, %p) => %s, %s, %s\n", physDev, doc, debugstr_w(doc->lpszDocName),
420 debugstr_w(doc->lpszOutput), debugstr_w(doc->lpszDatatype));
422 if(physDev->job.id) {
423 FIXME("hJob != 0. Now what?\n");
424 return 0;
427 /* FIXME: use PRINTER_DEFAULTS here */
428 if(!OpenPrinterA(physDev->pi->FriendlyName, &physDev->job.hprinter, NULL)) {
429 WARN("OpenPrinter(%s, ...) failed: %d\n",
430 debugstr_a(physDev->pi->FriendlyName), GetLastError());
431 return 0;
434 di.pDocName = (LPWSTR) doc->lpszDocName;
435 di.pDatatype = NULL;
437 if(doc->lpszOutput)
438 di.pOutputFile = (LPWSTR) doc->lpszOutput;
439 else if(physDev->job.output)
440 di.pOutputFile = physDev->job.output;
441 else
442 di.pOutputFile = NULL;
444 TRACE("using output: %s\n", debugstr_w(di.pOutputFile));
446 /* redirection located in HKCU\Software\Wine\Printing\Spooler
447 is done during winspool.drv,ScheduleJob */
448 physDev->job.id = StartDocPrinterW(physDev->job.hprinter, 1, (LPBYTE) &di);
449 if(!physDev->job.id) {
450 WARN("StartDocPrinter() failed: %d\n", GetLastError());
451 ClosePrinter(physDev->job.hprinter);
452 return 0;
454 physDev->job.banding = FALSE;
455 physDev->job.OutOfPage = TRUE;
456 physDev->job.PageNo = 0;
457 physDev->job.quiet = FALSE;
458 physDev->job.in_passthrough = FALSE;
459 physDev->job.had_passthrough_rect = FALSE;
460 if(doc->lpszDocName) {
461 INT len = WideCharToMultiByte( CP_ACP, 0, doc->lpszDocName, -1, NULL, 0, NULL, NULL );
462 physDev->job.DocName = HeapAlloc( GetProcessHeap(), 0, len );
463 WideCharToMultiByte( CP_ACP, 0, doc->lpszDocName, -1, physDev->job.DocName, len, NULL, NULL );
464 } else
465 physDev->job.DocName = NULL;
467 return physDev->job.id;
470 /************************************************************************
471 * PSDRV_EndDoc
473 INT PSDRV_EndDoc( PHYSDEV dev )
475 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
476 INT ret = 1;
478 if(!physDev->job.id) {
479 FIXME("hJob == 0. Now what?\n");
480 return 0;
483 if(!physDev->job.OutOfPage) {
484 WARN("Somebody forgot an EndPage\n");
485 PSDRV_EndPage( dev );
488 if (physDev->job.PageNo)
489 PSDRV_WriteFooter( dev );
491 ret = EndDocPrinter(physDev->job.hprinter);
492 ClosePrinter(physDev->job.hprinter);
493 physDev->job.hprinter = NULL;
494 physDev->job.id = 0;
495 HeapFree(GetProcessHeap(), 0, physDev->job.DocName);
496 physDev->job.DocName = NULL;
498 return ret;