Release 20050930.
[wine/gsoc-2012-control.git] / dlls / wineps / escape.c
blob88445d573be3722487159e82e9e4844ba6509a47
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "wine/wingdi16.h"
26 #include "wine/winuser16.h"
27 #include "wownt32.h"
28 #include "psdrv.h"
29 #include "wine/debug.h"
30 #include "winspool.h"
31 #include "heap.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
35 static const char psbegindocument[] =
36 "%%BeginDocument: Wine passthrough\n";
38 /**********************************************************************
39 * ExtEscape (WINEPS.@)
41 INT PSDRV_ExtEscape( PSDRV_PDEVICE *physDev, INT nEscape, INT cbInput, LPCVOID in_data,
42 INT cbOutput, LPVOID out_data )
44 switch(nEscape)
46 case QUERYESCSUPPORT:
47 if(cbInput < sizeof(INT))
49 WARN("cbInput < sizeof(INT) (=%d) for QUERYESCSUPPORT\n", cbInput);
50 return 0;
51 } else {
52 UINT num = *(const UINT *)in_data;
53 TRACE("QUERYESCSUPPORT for %d\n", num);
55 switch(num) {
56 case NEXTBAND:
57 /*case BANDINFO:*/
58 case SETCOPYCOUNT:
59 case GETTECHNOLOGY:
60 case SETLINECAP:
61 case SETLINEJOIN:
62 case SETMITERLIMIT:
63 case SETCHARSET:
64 case EXT_DEVICE_CAPS:
65 case SET_BOUNDS:
66 case EPSPRINTING:
67 case POSTSCRIPT_DATA:
68 case PASSTHROUGH:
69 case POSTSCRIPT_PASSTHROUGH:
70 case POSTSCRIPT_IGNORE:
71 case BEGIN_PATH:
72 case CLIP_TO_PATH:
73 case END_PATH:
74 /*case DRAWPATTERNRECT:*/
75 return TRUE;
77 default:
78 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
79 return FALSE;
83 case MFCOMMENT:
85 int i;
86 FIXME("MFCOMMENT(%p, %d)\n", in_data, cbInput);
87 for (i=0;i<cbInput;i++) MESSAGE("%02x ", ((LPBYTE)in_data)[i]);
88 MESSAGE("\n");
89 return 1;
91 case DRAWPATTERNRECT:
93 DRAWPATRECT *dpr = (DRAWPATRECT*)in_data;
95 FIXME("DRAWPATTERNRECT(pos (%ld,%ld), size %ldx%ld, style %d, pattern %x), stub!\n",
96 dpr->ptPosition.x, dpr->ptPosition.y,
97 dpr->ptSize.x, dpr->ptSize.y,
98 dpr->wStyle, dpr->wPattern
100 return 1;
102 case BANDINFO:
104 BANDINFOSTRUCT *ibi = (BANDINFOSTRUCT*)in_data;
105 BANDINFOSTRUCT *obi = (BANDINFOSTRUCT*)out_data;
107 FIXME("BANDINFO(graphics %d, text %d, rect [%ldx%ld-%ldx%ld]), stub!\n",
108 ibi->GraphicsFlag,
109 ibi->TextFlag,
110 ibi->GraphicsRect.top,
111 ibi->GraphicsRect.bottom,
112 ibi->GraphicsRect.left,
113 ibi->GraphicsRect.right
115 memcpy (obi, ibi, sizeof(*ibi));
116 return 1;
118 case NEXTBAND:
120 RECT *r = out_data;
121 if(!physDev->job.banding) {
122 physDev->job.banding = TRUE;
123 r->left = 0;
124 r->top = 0;
125 r->right = physDev->horzRes;
126 r->bottom = physDev->vertRes;
127 TRACE("NEXTBAND returning %ld,%ld - %ld,%ld\n", r->left, r->top, r->right, r->bottom );
128 return 1;
130 r->left = 0;
131 r->top = 0;
132 r->right = 0;
133 r->bottom = 0;
134 TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
135 physDev->job.banding = FALSE;
136 return EndPage( physDev->hdc );
139 case SETCOPYCOUNT:
141 const INT *NumCopies = in_data;
142 INT *ActualCopies = out_data;
143 if(cbInput != sizeof(INT)) {
144 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
145 return 0;
147 TRACE("SETCOPYCOUNT %d\n", *NumCopies);
148 *ActualCopies = 1;
149 return 1;
152 case GETTECHNOLOGY:
154 LPSTR p = out_data;
155 strcpy(p, "PostScript");
156 *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
157 return 1;
160 case SETLINECAP:
162 INT newCap = *(const INT *)in_data;
163 if(cbInput != sizeof(INT)) {
164 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
165 return 0;
167 TRACE("SETLINECAP %d\n", newCap);
168 return 0;
171 case SETLINEJOIN:
173 INT newJoin = *(const INT *)in_data;
174 if(cbInput != sizeof(INT)) {
175 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
176 return 0;
178 TRACE("SETLINEJOIN %d\n", newJoin);
179 return 0;
182 case SETMITERLIMIT:
184 INT newLimit = *(const INT *)in_data;
185 if(cbInput != sizeof(INT)) {
186 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
187 return 0;
189 TRACE("SETMITERLIMIT %d\n", newLimit);
190 return 0;
193 case SETCHARSET:
194 /* Undocumented escape used by winword6.
195 Switches between ANSI and a special charset.
196 If *lpInData == 1 we require that
197 0x91 is quoteleft
198 0x92 is quoteright
199 0x93 is quotedblleft
200 0x94 is quotedblright
201 0x95 is bullet
202 0x96 is endash
203 0x97 is emdash
204 0xa0 is non break space - yeah right.
206 If *lpInData == 0 we get ANSI.
207 Since there's nothing else there, let's just make these the default
208 anyway and see what happens...
210 return 1;
212 case EXT_DEVICE_CAPS:
214 UINT cap = *(const UINT *)in_data;
215 if(cbInput != sizeof(UINT)) {
216 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
217 return 0;
219 TRACE("EXT_DEVICE_CAPS %d\n", cap);
220 return 0;
223 case SET_BOUNDS:
225 const RECT *r = in_data;
226 if(cbInput != sizeof(RECT)) {
227 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
228 return 0;
230 TRACE("SET_BOUNDS (%ld,%ld) - (%ld,%ld)\n", r->left, r->top,
231 r->right, r->bottom);
232 return 0;
235 case EPSPRINTING:
237 UINT epsprint = *(const UINT*)in_data;
238 /* FIXME: In this mode we do not need to send page intros and page
239 * ends according to the doc. But I just ignore that detail
240 * for now.
242 TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
243 return 1;
246 case POSTSCRIPT_DATA:
247 case PASSTHROUGH:
248 case POSTSCRIPT_PASSTHROUGH:
250 /* Write directly to spool file, bypassing normal PS driver
251 * processing that is done along with writing PostScript code
252 * to the spool.
253 * We have a WORD before the data counting the size, but
254 * cbInput is just this +2.
255 * However Photoshop 7 has a bug that sets cbInput to 2 less than the
256 * length of the string, rather than 2 more. So we'll use the WORD at
257 * in_data[0] instead.
259 if(!physDev->job.in_passthrough) {
260 WriteSpool16(physDev->job.hJob, (LPSTR)psbegindocument, sizeof(psbegindocument)-1);
261 physDev->job.in_passthrough = TRUE;
263 return WriteSpool16(physDev->job.hJob,((char*)in_data)+2,*(const WORD*)in_data);
266 case POSTSCRIPT_IGNORE:
268 BOOL ret = physDev->job.quiet;
269 TRACE("POSTSCRIPT_IGNORE %d\n", *(const short*)in_data);
270 physDev->job.quiet = *(const short*)in_data;
271 return ret;
274 case GETSETPRINTORIENT:
276 /* If lpInData is present, it is a 20 byte structure, first 32
277 * bit LONG value is the orientation. if lpInData is NULL, it
278 * returns the current orientation.
280 FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
281 return 1;
283 case BEGIN_PATH:
284 TRACE("BEGIN_PATH\n");
285 if(physDev->pathdepth)
286 FIXME("Nested paths not yet handled\n");
287 return ++physDev->pathdepth;
289 case END_PATH:
291 const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
293 TRACE("END_PATH\n");
294 if(!physDev->pathdepth) {
295 ERR("END_PATH called without a BEIGN_PATH\n");
296 return -1;
298 TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
299 info->RenderMode, info->FillMode, info->BkMode);
300 switch(info->RenderMode) {
301 case RENDERMODE_NO_DISPLAY:
302 PSDRV_WriteClosePath(physDev); /* not sure if this is necessary, but it can't hurt */
303 break;
304 case RENDERMODE_OPEN:
305 case RENDERMODE_CLOSED:
306 default:
307 FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
308 break;
310 return --physDev->pathdepth;
313 case CLIP_TO_PATH:
315 WORD mode = *(const WORD*)in_data;
317 switch(mode) {
318 case CLIP_SAVE:
319 TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
320 PSDRV_WriteGSave(physDev);
321 return 1;
322 case CLIP_RESTORE:
323 TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
324 PSDRV_WriteGRestore(physDev);
325 return 1;
326 case CLIP_INCLUSIVE:
327 TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
328 /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
329 PSDRV_WriteClip(physDev);
330 PSDRV_WriteNewPath(physDev);
331 return 1;
332 case CLIP_EXCLUSIVE:
333 FIXME("CLIP_EXCLUSIVE: not implemented\n");
334 return 0;
335 default:
336 FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
337 return 0;
340 default:
341 FIXME("Unimplemented code 0x%x\n", nEscape);
342 return 0;
346 /************************************************************************
347 * PSDRV_StartPage
349 INT PSDRV_StartPage( PSDRV_PDEVICE *physDev )
351 if(!physDev->job.OutOfPage) {
352 FIXME("Already started a page?\n");
353 return 1;
356 if(physDev->job.PageNo++ == 0) {
357 if(!PSDRV_WriteHeader( physDev, physDev->job.DocName ))
358 return 0;
361 if(!PSDRV_WriteNewPage( physDev ))
362 return 0;
363 physDev->job.OutOfPage = FALSE;
364 return 1;
368 /************************************************************************
369 * PSDRV_EndPage
371 INT PSDRV_EndPage( PSDRV_PDEVICE *physDev )
373 if(physDev->job.OutOfPage) {
374 FIXME("Already ended a page?\n");
375 return 1;
377 if(!PSDRV_WriteEndPage( physDev ))
378 return 0;
379 PSDRV_EmptyDownloadList(physDev, FALSE);
380 physDev->job.OutOfPage = TRUE;
381 return 1;
385 /************************************************************************
386 * PSDRV_StartDocA
388 INT PSDRV_StartDocA( PSDRV_PDEVICE *physDev, const DOCINFOA *doc )
390 LPCSTR output = "LPT1:";
391 BYTE buf[300];
392 HANDLE hprn = INVALID_HANDLE_VALUE;
393 PRINTER_INFO_5A *pi5 = (PRINTER_INFO_5A*)buf;
394 DWORD needed;
396 if(physDev->job.hJob) {
397 FIXME("hJob != 0. Now what?\n");
398 return 0;
401 if(doc->lpszOutput)
402 output = doc->lpszOutput;
403 else if(physDev->job.output)
404 output = physDev->job.output;
405 else {
406 if(OpenPrinterA(physDev->pi->FriendlyName, &hprn, NULL) &&
407 GetPrinterA(hprn, 5, buf, sizeof(buf), &needed)) {
408 output = pi5->pPortName;
410 if(hprn != INVALID_HANDLE_VALUE)
411 ClosePrinter(hprn);
414 physDev->job.hJob = OpenJob16(output, doc->lpszDocName, HDC_16(physDev->hdc) );
415 if(!physDev->job.hJob) {
416 WARN("OpenJob failed\n");
417 return 0;
419 physDev->job.banding = FALSE;
420 physDev->job.OutOfPage = TRUE;
421 physDev->job.PageNo = 0;
422 physDev->job.quiet = FALSE;
423 physDev->job.in_passthrough = FALSE;
424 physDev->job.had_passthrough_rect = FALSE;
425 if(doc->lpszDocName) {
426 physDev->job.DocName = HeapAlloc(GetProcessHeap(), 0, strlen(doc->lpszDocName)+1);
427 strcpy(physDev->job.DocName, doc->lpszDocName);
428 } else
429 physDev->job.DocName = NULL;
431 return physDev->job.hJob;
434 /************************************************************************
435 * PSDRV_StartDoc
437 INT PSDRV_StartDoc( PSDRV_PDEVICE *physDev, const DOCINFOW *doc )
439 DOCINFOA docA;
440 INT ret;
442 docA.cbSize = doc->cbSize;
443 docA.lpszDocName = doc->lpszDocName ?
444 HEAP_strdupWtoA( GetProcessHeap(), 0, doc->lpszDocName ) : NULL;
445 docA.lpszOutput = doc->lpszOutput ?
446 HEAP_strdupWtoA( GetProcessHeap(), 0, doc->lpszOutput ) : NULL;
447 docA.lpszDatatype = doc->lpszDatatype ?
448 HEAP_strdupWtoA( GetProcessHeap(), 0, doc->lpszDatatype ) : NULL;
449 docA.fwType = doc->fwType;
451 ret = PSDRV_StartDocA(physDev, &docA);
453 HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszDocName );
454 HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszOutput );
455 HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszDatatype );
457 return ret;
460 /************************************************************************
461 * PSDRV_EndDoc
463 INT PSDRV_EndDoc( PSDRV_PDEVICE *physDev )
465 INT ret = 1;
466 if(!physDev->job.hJob) {
467 FIXME("hJob == 0. Now what?\n");
468 return 0;
471 if(!physDev->job.OutOfPage) {
472 WARN("Somebody forgot an EndPage\n");
473 PSDRV_EndPage( physDev );
475 PSDRV_WriteFooter( physDev );
477 if( CloseJob16( physDev->job.hJob ) == SP_ERROR ) {
478 WARN("CloseJob error\n");
479 ret = 0;
481 physDev->job.hJob = 0;
482 HeapFree(GetProcessHeap(), 0, physDev->job.DocName);
483 physDev->job.DocName = NULL;
485 return ret;