Added a few more Unicode digits from Unicode version 4.1.
[wine] / dlls / wineps / escape.c
1 /*
2  *      PostScript driver Escape function
3  *
4  *      Copyright 1998  Huw D M Davies
5  *
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.
10  *
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.
15  *
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
19  */
20 #include <stdarg.h>
21
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"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
34
35 static const char psbegindocument[] =
36 "%%BeginDocument: Wine passthrough\n";
37
38 /**********************************************************************
39  *           ExtEscape  (WINEPS.@)
40  */
41 INT PSDRV_ExtEscape( PSDRV_PDEVICE *physDev, INT nEscape, INT cbInput, LPCVOID in_data,
42                      INT cbOutput, LPVOID out_data )
43 {
44     switch(nEscape)
45     {
46     case QUERYESCSUPPORT:
47         if(cbInput < sizeof(INT))
48         {
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);
54
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;
76
77             default:
78                 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
79                 return FALSE;
80             }
81         }
82
83     case MFCOMMENT:
84     {
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;
90     }
91     case DRAWPATTERNRECT:
92     {
93         DRAWPATRECT     *dpr = (DRAWPATRECT*)in_data;
94
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
99         );
100         return 1;
101     }
102     case BANDINFO:
103     {
104         BANDINFOSTRUCT  *ibi = (BANDINFOSTRUCT*)in_data;
105         BANDINFOSTRUCT  *obi = (BANDINFOSTRUCT*)out_data;
106
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
114         );
115         memcpy (obi, ibi, sizeof(*ibi));
116         return 1;
117     }
118     case NEXTBAND:
119     {
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;
129         }
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 );
137     }
138
139     case SETCOPYCOUNT:
140         {
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;
146             }
147             TRACE("SETCOPYCOUNT %d\n", *NumCopies);
148             *ActualCopies = 1;
149             return 1;
150         }
151
152     case GETTECHNOLOGY:
153         {
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;
158         }
159
160     case SETLINECAP:
161         {
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;
166             }
167             TRACE("SETLINECAP %d\n", newCap);
168             return 0;
169         }
170
171     case SETLINEJOIN:
172         {
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;
177             }
178             TRACE("SETLINEJOIN %d\n", newJoin);
179             return 0;
180         }
181
182     case SETMITERLIMIT:
183         {
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;
188             }
189             TRACE("SETMITERLIMIT %d\n", newLimit);
190             return 0;
191         }
192
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.
205
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...
209       */
210         return 1;
211
212     case EXT_DEVICE_CAPS:
213         {
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;
218             }
219             TRACE("EXT_DEVICE_CAPS %d\n", cap);
220             return 0;
221         }
222
223     case SET_BOUNDS:
224         {
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;
229             }
230             TRACE("SET_BOUNDS (%ld,%ld) - (%ld,%ld)\n", r->left, r->top,
231                   r->right, r->bottom);
232             return 0;
233         }
234
235     case EPSPRINTING:
236         {
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.
241              */
242             TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
243             return 1;
244         }
245
246     case POSTSCRIPT_DATA:
247     case PASSTHROUGH:
248     case POSTSCRIPT_PASSTHROUGH:
249         {
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.
258              */
259             if(!physDev->job.in_passthrough) {
260                 WriteSpool16(physDev->job.hJob, (LPSTR)psbegindocument, sizeof(psbegindocument)-1);
261                 physDev->job.in_passthrough = TRUE;
262             }
263             return WriteSpool16(physDev->job.hJob,((char*)in_data)+2,*(const WORD*)in_data);
264         }
265
266     case POSTSCRIPT_IGNORE:
267       {
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;
272       }
273
274     case GETSETPRINTORIENT:
275         {
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.
279              */
280             FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
281             return 1;
282         }
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;
288
289     case END_PATH:
290       {
291         const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
292
293         TRACE("END_PATH\n");
294         if(!physDev->pathdepth) {
295             ERR("END_PATH called without a BEIGN_PATH\n");
296             return -1;
297         }
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;
309         }
310         return --physDev->pathdepth;
311       }
312
313     case CLIP_TO_PATH:
314       {
315         WORD mode = *(const WORD*)in_data;
316
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;
338         }
339       }
340     default:
341         FIXME("Unimplemented code 0x%x\n", nEscape);
342         return 0;
343     }
344 }
345
346 /************************************************************************
347  *           PSDRV_StartPage
348  */
349 INT PSDRV_StartPage( PSDRV_PDEVICE *physDev )
350 {
351     if(!physDev->job.OutOfPage) {
352         FIXME("Already started a page?\n");
353         return 1;
354     }
355
356     if(physDev->job.PageNo++ == 0) {
357         if(!PSDRV_WriteHeader( physDev, physDev->job.DocName ))
358             return 0;
359     }
360
361     if(!PSDRV_WriteNewPage( physDev ))
362         return 0;
363     physDev->job.OutOfPage = FALSE;
364     return 1;
365 }
366
367
368 /************************************************************************
369  *           PSDRV_EndPage
370  */
371 INT PSDRV_EndPage( PSDRV_PDEVICE *physDev )
372 {
373     if(physDev->job.OutOfPage) {
374         FIXME("Already ended a page?\n");
375         return 1;
376     }
377     if(!PSDRV_WriteEndPage( physDev ))
378         return 0;
379     PSDRV_EmptyDownloadList(physDev, FALSE);
380     physDev->job.OutOfPage = TRUE;
381     return 1;
382 }
383
384
385 /************************************************************************
386  *           PSDRV_StartDocA
387  */
388 INT PSDRV_StartDocA( PSDRV_PDEVICE *physDev, const DOCINFOA *doc )
389 {
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;
395
396     if(physDev->job.hJob) {
397         FIXME("hJob != 0. Now what?\n");
398         return 0;
399     }
400
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;
409         }
410         if(hprn != INVALID_HANDLE_VALUE)
411             ClosePrinter(hprn);
412     }
413
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;
418     }
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;
430
431     return physDev->job.hJob;
432 }
433
434 /************************************************************************
435  *           PSDRV_StartDoc
436  */
437 INT PSDRV_StartDoc( PSDRV_PDEVICE *physDev, const DOCINFOW *doc )
438 {
439     DOCINFOA docA;
440     INT ret;
441
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;
450
451     ret = PSDRV_StartDocA(physDev, &docA);
452
453     HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszDocName );
454     HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszOutput );
455     HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszDatatype );
456
457     return ret;
458 }
459
460 /************************************************************************
461  *           PSDRV_EndDoc
462  */
463 INT PSDRV_EndDoc( PSDRV_PDEVICE *physDev )
464 {
465     INT ret = 1;
466     if(!physDev->job.hJob) {
467         FIXME("hJob == 0. Now what?\n");
468         return 0;
469     }
470
471     if(!physDev->job.OutOfPage) {
472         WARN("Somebody forgot an EndPage\n");
473         PSDRV_EndPage( physDev );
474     }
475     PSDRV_WriteFooter( physDev );
476
477     if( CloseJob16( physDev->job.hJob ) == SP_ERROR ) {
478         WARN("CloseJob error\n");
479         ret = 0;
480     }
481     physDev->job.hJob = 0;
482     HeapFree(GetProcessHeap(), 0, physDev->job.DocName);
483     physDev->job.DocName = NULL;
484
485     return ret;
486 }