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