Added GetDeviceCaps to the DC driver interface. Removed devCaps
[wine] / dlls / wineps / escape.c
1 /*
2  *      PostScript driver Escape function
3  *
4  *      Copyright 1998  Huw D M Davies
5  */
6 #include "windef.h"
7 #include "wingdi.h"
8 #include "wine/winuser16.h"
9 #include "psdrv.h"
10 #include "debugtools.h"
11 #include "winspool.h"
12
13 DEFAULT_DEBUG_CHANNEL(psdrv);
14
15
16 INT PSDRV_Escape( DC *dc, INT nEscape, INT cbInput, 
17                   SEGPTR lpInData, SEGPTR lpOutData )
18 {
19     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
20
21     switch(nEscape) {
22
23     case NEXTBAND: {
24         RECT16 *r = MapSL(lpOutData);
25         if(!physDev->job.banding) {
26             physDev->job.banding = TRUE;
27             r->left   = 0;
28             r->top    = 0;
29             r->right  = physDev->horzRes;
30             r->bottom = physDev->vertRes;
31             TRACE("NEXTBAND returning %d,%d - %d,%d\n", r->left,
32                   r->top, r->right, r->bottom );
33             return 1;
34         }
35         r->left   = 0;
36         r->top    = 0;
37         r->right  = 0;
38         r->bottom = 0;
39         TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
40         physDev->job.banding = FALSE;
41     }   /* Fall through */
42
43     case NEWFRAME:
44         TRACE("NEWFRAME\n");
45
46         if(!physDev->job.hJob) {
47             FIXME("hJob == 0. Now what?\n");
48             return SP_ERROR;
49         }
50         
51         if(!PSDRV_EndPage( dc ))
52             return SP_ERROR;
53         return 1;
54           
55     case QUERYESCSUPPORT:
56         if(cbInput < 2) {
57             WARN("cbInput < 2 (=%d) for QUERYESCSUPPORT\n", cbInput);
58             return 0;
59         } else {
60             UINT16 num = *(UINT16 *)MapSL(lpInData);
61             TRACE("QUERYESCSUPPORT for %d\n", num);        
62
63             switch(num) {
64             case NEWFRAME:
65             case NEXTBAND:
66             case QUERYESCSUPPORT:
67             case SETABORTPROC:
68             case STARTDOC:
69             case ENDDOC:
70             case GETPHYSPAGESIZE:
71             case GETPRINTINGOFFSET:
72             case GETSCALINGFACTOR:
73             case SETCOPYCOUNT:
74             case GETTECHNOLOGY:
75             case SETLINECAP:
76             case SETLINEJOIN:
77             case SETMITERLIMIT:
78             case SETCHARSET:
79             case EXT_DEVICE_CAPS:
80             case SET_BOUNDS:
81             case EPSPRINTING:
82             case PASSTHROUGH:
83             case POSTSCRIPT_PASSTHROUGH:
84                 return TRUE;
85
86             default:
87                 return FALSE;
88             }
89         }
90
91     case SETABORTPROC:
92         TRACE("SETABORTPROC\n");
93         return 1;
94
95     case STARTDOC:
96       {
97         DOCINFOA doc;
98         char *name = NULL;
99         INT16 ret;
100
101         TRACE("STARTDOC\n");
102
103         /* lpInData may not be 0 terminated so we must copy it */
104         if(lpInData) {
105             name = HeapAlloc( GetProcessHeap(), 0, cbInput+1 );
106             memcpy(name, MapSL(lpInData), cbInput);
107             name[cbInput] = '\0';
108         }
109         doc.cbSize = sizeof(doc);
110         doc.lpszDocName = name;
111         doc.lpszOutput = doc.lpszDatatype = NULL;
112         doc.fwType = 0;
113
114         ret = PSDRV_StartDoc(dc, &doc);
115         if(name) HeapFree( GetProcessHeap(), 0, name );
116         if(ret <= 0) return -1;
117         ret = PSDRV_StartPage(dc);
118         if(ret <= 0) return -1;
119         return ret;
120       }
121
122     case ENDDOC:
123         TRACE("ENDDOC\n");
124         return PSDRV_EndDoc( dc );
125
126     case GETPHYSPAGESIZE:
127         {
128             PSDRV_PDEVICE   *pdev = (PSDRV_PDEVICE *)(dc->physDev);
129             POINT16         *p = MapSL(lpOutData);
130             
131             p->x = p->y = 0;
132             
133             if ((pdev->Devmode->dmPublic.dmFields & DM_PAPERSIZE) != 0 &&
134                     pdev->Devmode->dmPublic.u1.s1.dmPaperSize != 0)
135             {
136                 PAGESIZE    *page = pdev->pi->ppd->PageSizes;
137                 
138                 while (page != NULL)
139                 {
140                     if (page->WinPage ==
141                             pdev->Devmode->dmPublic.u1.s1.dmPaperSize)
142                         break;
143                     page = page->next;
144                 }
145                 
146                 if (page == NULL)
147                 {
148                     ERR("No entry for papersize %u in PPD file for '%s'\n",
149                             pdev->Devmode->dmPublic.u1.s1.dmPaperSize,
150                             pdev->pi->FriendlyName);
151                     return 0;
152                 }
153                 
154                 TRACE("Found '%s' for paper size %u\n", page->FullName,
155                         pdev->Devmode->dmPublic.u1.s1.dmPaperSize);
156                 
157                 p->x = page->PaperDimension->x * physDev->logPixelsX / 72;
158                 p->y = page->PaperDimension->y * physDev->logPixelsY / 72;
159                 
160                 TRACE("%fx%f PostScript points = %ix%i device units\n", 
161                         page->PaperDimension->x, page->PaperDimension->y,
162                         p->x, p->y);
163             }
164             
165             /* These are in tenths of a millimeter */
166             
167             if ((pdev->Devmode->dmPublic.dmFields & DM_PAPERWIDTH) != 0 &&
168                     pdev->Devmode->dmPublic.u1.s1.dmPaperWidth != 0)
169             {
170                 p->x = (pdev->Devmode->dmPublic.u1.s1.dmPaperWidth *
171                         physDev->logPixelsX) / 254;
172                 TRACE("dmPaperWidth = %i device units\n", p->x);
173             }
174             
175             if ((pdev->Devmode->dmPublic.dmFields & DM_PAPERLENGTH) != 0 &&
176                     pdev->Devmode->dmPublic.u1.s1.dmPaperLength != 0)
177             {
178                 p->y = (pdev->Devmode->dmPublic.u1.s1.dmPaperLength *
179                         physDev->logPixelsY) / 254;
180                 TRACE("dmPaperLength = %i device units\n", p->y);
181             }
182                         
183             if (p->x == 0 || p->y == 0)
184             {
185                 ERR("Paper size not properly set for '%s'\n",
186                         pdev->pi->FriendlyName);
187                 return 0;
188             }
189             
190             if ((pdev->Devmode->dmPublic.dmFields & DM_ORIENTATION) != 0 &&
191                     pdev->Devmode->dmPublic.u1.s1.dmOrientation ==
192                     DMORIENT_LANDSCAPE)
193             {
194                 register INT16  temp = p->y;
195                 p->y = p->x;
196                 p->x = temp;
197             }
198             
199             return 1;
200         }
201
202     case GETPRINTINGOFFSET:
203         {
204             POINT16 *p = MapSL(lpOutData);
205         
206             p->x = p->y = 0;
207             TRACE("GETPRINTINGOFFSET: returning %dx%d\n", p->x, p->y);
208             return 1;
209         }
210       
211     case GETSCALINGFACTOR:
212         {
213             POINT16 *p = MapSL(lpOutData);
214         
215             p->x = p->y = 0;
216             TRACE("GETSCALINGFACTOR: returning %dx%d\n", p->x, p->y);
217             return 1;
218         }
219
220     case SETCOPYCOUNT:
221         {
222             INT16 *NumCopies = MapSL(lpInData);
223             INT16 *ActualCopies = MapSL(lpOutData);
224             if(cbInput != 2) {
225                 WARN("cbInput != 2 (=%d) for SETCOPYCOUNT\n", cbInput);
226                 return 0;
227             }
228             TRACE("SETCOPYCOUNT %d\n", *NumCopies);
229             *ActualCopies = 1;
230             return 1;
231         }
232
233     case GETTECHNOLOGY:
234         {
235             LPSTR p = MapSL(lpOutData);
236             strcpy(p, "PostScript");
237             *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
238             return 1;
239         }
240
241     case SETLINECAP:
242         {
243             INT16 newCap = *(INT16 *)MapSL(lpInData);
244             if(cbInput != 2) {
245                 WARN("cbInput != 2 (=%d) for SETLINECAP\n", cbInput);
246                 return 0;
247             }                   
248             TRACE("SETLINECAP %d\n", newCap);
249             return 0;
250         }
251             
252     case SETLINEJOIN:
253         {
254             INT16 newJoin = *(INT16 *)MapSL(lpInData);
255             if(cbInput != 2) {
256                 WARN("cbInput != 2 (=%d) for SETLINEJOIN\n", cbInput);
257                 return 0;
258             }           
259             TRACE("SETLINEJOIN %d\n", newJoin);
260             return 0;
261         }
262
263     case SETMITERLIMIT:
264         {
265             INT16 newLimit = *(INT16 *)MapSL(lpInData);
266             if(cbInput != 2) {
267                 WARN("cbInput != 2 (=%d) for SETMITERLIMIT\n", cbInput);
268                 return 0;
269             }           
270             TRACE("SETMITERLIMIT %d\n", newLimit);
271             return 0;
272         }
273
274     case SETCHARSET: 
275       /* Undocumented escape used by winword6.
276          Switches between ANSI and a special charset.
277          If *lpInData == 1 we require that
278          0x91 is quoteleft
279          0x92 is quoteright
280          0x93 is quotedblleft
281          0x94 is quotedblright
282          0x95 is bullet
283          0x96 is endash
284          0x97 is emdash
285          0xa0 is non break space - yeah right.
286          
287          If *lpInData == 0 we get ANSI.
288          Since there's nothing else there, let's just make these the default
289          anyway and see what happens...
290       */
291         return 1;
292
293     case EXT_DEVICE_CAPS:
294         {
295             UINT16 cap = *(UINT16 *)MapSL(lpInData);
296             if(cbInput != 2) {
297                 WARN("cbInput != 2 (=%d) for EXT_DEVICE_CAPS\n",
298                      cbInput);
299                 return 0;
300             }           
301             TRACE("EXT_DEVICE_CAPS %d\n", cap);
302             return 0;
303         }
304
305     case SET_BOUNDS:
306         {
307             RECT16 *r = MapSL(lpInData);
308             if(cbInput != 8) {
309                 WARN("cbInput != 8 (=%d) for SET_BOUNDS\n", cbInput);
310                 return 0;
311             }           
312             TRACE("SET_BOUNDS (%d,%d) - (%d,%d)\n", r->left, r->top,
313                   r->right, r->bottom);
314             return 0;
315         }
316
317     case EPSPRINTING:
318         {
319             UINT16      epsprint = *(UINT16*)MapSL(lpInData);
320             /* FIXME: In this mode we do not need to send page intros and page
321              * ends according to the doc. But I just ignore that detail
322              * for now.
323              */
324             TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
325             return 1;
326         }
327     case PASSTHROUGH:
328     case POSTSCRIPT_PASSTHROUGH:
329         {
330             /* Write directly to spool file, bypassing normal PS driver
331              * processing that is done along with writing PostScript code
332              * to the spool.
333              * (Usually we have a WORD before the data counting the size, but
334              * cbInput is just this +2.)
335              */
336             return WriteSpool16(physDev->job.hJob,((char*)lpInData)+2,cbInput-2);
337         }
338
339     case GETSETPRINTORIENT:
340         {
341             /* If lpInData is present, it is a 20 byte structure, first 32
342              * bit LONG value is the orientation. if lpInData is NULL, it
343              * returns the current orientation.
344              */
345             FIXME("GETSETPRINTORIENT not implemented (lpInData %ld)!\n",lpInData);
346             return 1;
347         }
348     default:
349         FIXME("Unimplemented code 0x%x\n", nEscape);
350         return 0;
351     }
352 }
353
354 /************************************************************************
355  *           PSDRV_StartPage
356  */
357 INT PSDRV_StartPage( DC *dc )
358 {
359     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
360
361     if(!physDev->job.OutOfPage) {
362         FIXME("Already started a page?\n");
363         return 1;
364     }
365     physDev->job.PageNo++;
366     if(!PSDRV_WriteNewPage( dc ))
367         return 0;
368     physDev->job.OutOfPage = FALSE;
369     return 1;
370 }
371
372         
373 /************************************************************************
374  *           PSDRV_EndPage
375  */
376 INT PSDRV_EndPage( DC *dc )
377 {
378     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
379
380     if(physDev->job.OutOfPage) {
381         FIXME("Already ended a page?\n");
382         return 1;
383     }
384     if(!PSDRV_WriteEndPage( dc ))
385         return 0;
386     physDev->job.OutOfPage = TRUE;
387     return 1;
388 }
389
390
391 /************************************************************************
392  *           PSDRV_StartDoc
393  */
394 INT PSDRV_StartDoc( DC *dc, const DOCINFOA *doc )
395 {
396     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
397
398     if(physDev->job.hJob) {
399         FIXME("hJob != 0. Now what?\n");
400         return 0;
401     }
402
403     if(doc->lpszOutput) {
404         HeapFree( PSDRV_Heap, 0, physDev->job.output );
405         physDev->job.output = HeapAlloc( PSDRV_Heap, 0, strlen(doc->lpszOutput)+1 );
406         strcpy( physDev->job.output, doc->lpszOutput );
407     }
408     physDev->job.hJob = OpenJob16(physDev->job.output,  doc->lpszDocName,
409                                   dc->hSelf);
410     if(!physDev->job.hJob) {
411         WARN("OpenJob failed\n");
412         return 0;
413     }
414     physDev->job.banding = FALSE;
415     physDev->job.OutOfPage = TRUE;
416     physDev->job.PageNo = 0;
417     if(!PSDRV_WriteHeader( dc, doc->lpszDocName ))
418         return 0;
419
420     return physDev->job.hJob;
421 }
422
423
424 /************************************************************************
425  *           PSDRV_EndDoc
426  */
427 INT PSDRV_EndDoc( DC *dc )
428 {
429     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
430
431     if(!physDev->job.hJob) {
432         FIXME("hJob == 0. Now what?\n");
433         return 0;
434     }
435
436     if(!physDev->job.OutOfPage) {
437         WARN("Somebody forgot a EndPage\n");
438         PSDRV_EndPage( dc );
439     }
440     if(!PSDRV_WriteFooter( dc ))
441         return 0;
442
443     if( CloseJob16( physDev->job.hJob ) == SP_ERROR ) {
444         WARN("CloseJob error\n");
445         return 0;
446     }
447     physDev->job.hJob = 0;
448     return 1;
449 }