Fixed compile when functions are not inlined.
[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 "windef.h"
21 #include "wingdi.h"
22 #include "wine/wingdi16.h"
23 #include "wine/winuser16.h"
24 #include "wownt32.h"
25 #include "psdrv.h"
26 #include "wine/debug.h"
27 #include "winspool.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
30
31 /**********************************************************************
32  *           ExtEscape  (WINEPS.@)
33  */
34 INT PSDRV_ExtEscape( PSDRV_PDEVICE *physDev, INT nEscape, INT cbInput, LPCVOID in_data,
35                      INT cbOutput, LPVOID out_data )
36 {
37     switch(nEscape)
38     {
39     case QUERYESCSUPPORT:
40         if(cbInput < sizeof(INT))
41         {
42             WARN("cbInput < sizeof(INT) (=%d) for QUERYESCSUPPORT\n", cbInput);
43             return 0;
44         } else {
45             UINT num = *(UINT *)in_data;
46             TRACE("QUERYESCSUPPORT for %d\n", num);
47
48             switch(num) {
49             case NEXTBAND:
50             case SETCOPYCOUNT:
51             case GETTECHNOLOGY:
52             case SETLINECAP:
53             case SETLINEJOIN:
54             case SETMITERLIMIT:
55             case SETCHARSET:
56             case EXT_DEVICE_CAPS:
57             case SET_BOUNDS:
58             case EPSPRINTING:
59             case POSTSCRIPT_DATA:
60             case PASSTHROUGH:
61             case POSTSCRIPT_PASSTHROUGH:
62             case POSTSCRIPT_IGNORE:
63             case BEGIN_PATH:
64             case CLIP_TO_PATH:
65             case END_PATH:
66                 return TRUE;
67
68             default:
69                 return FALSE;
70             }
71         }
72
73     case NEXTBAND:
74     {
75         RECT *r = out_data;
76         if(!physDev->job.banding) {
77             physDev->job.banding = TRUE;
78             r->left   = 0;
79             r->top    = 0;
80             r->right  = physDev->horzRes;
81             r->bottom = physDev->vertRes;
82             TRACE("NEXTBAND returning %ld,%ld - %ld,%ld\n", r->left, r->top, r->right, r->bottom );
83             return 1;
84         }
85         r->left   = 0;
86         r->top    = 0;
87         r->right  = 0;
88         r->bottom = 0;
89         TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
90         physDev->job.banding = FALSE;
91         return EndPage( physDev->hdc );
92     }
93
94     case SETCOPYCOUNT:
95         {
96             const INT *NumCopies = in_data;
97             INT *ActualCopies = out_data;
98             if(cbInput != sizeof(INT)) {
99                 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
100                 return 0;
101             }
102             TRACE("SETCOPYCOUNT %d\n", *NumCopies);
103             *ActualCopies = 1;
104             return 1;
105         }
106
107     case GETTECHNOLOGY:
108         {
109             LPSTR p = out_data;
110             strcpy(p, "PostScript");
111             *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
112             return 1;
113         }
114
115     case SETLINECAP:
116         {
117             INT newCap = *(INT *)in_data;
118             if(cbInput != sizeof(INT)) {
119                 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
120                 return 0;
121             }
122             TRACE("SETLINECAP %d\n", newCap);
123             return 0;
124         }
125
126     case SETLINEJOIN:
127         {
128             INT newJoin = *(INT *)in_data;
129             if(cbInput != sizeof(INT)) {
130                 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
131                 return 0;
132             }
133             TRACE("SETLINEJOIN %d\n", newJoin);
134             return 0;
135         }
136
137     case SETMITERLIMIT:
138         {
139             INT newLimit = *(INT *)in_data;
140             if(cbInput != sizeof(INT)) {
141                 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
142                 return 0;
143             }
144             TRACE("SETMITERLIMIT %d\n", newLimit);
145             return 0;
146         }
147
148     case SETCHARSET:
149       /* Undocumented escape used by winword6.
150          Switches between ANSI and a special charset.
151          If *lpInData == 1 we require that
152          0x91 is quoteleft
153          0x92 is quoteright
154          0x93 is quotedblleft
155          0x94 is quotedblright
156          0x95 is bullet
157          0x96 is endash
158          0x97 is emdash
159          0xa0 is non break space - yeah right.
160
161          If *lpInData == 0 we get ANSI.
162          Since there's nothing else there, let's just make these the default
163          anyway and see what happens...
164       */
165         return 1;
166
167     case EXT_DEVICE_CAPS:
168         {
169             UINT cap = *(UINT *)in_data;
170             if(cbInput != sizeof(UINT)) {
171                 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
172                 return 0;
173             }
174             TRACE("EXT_DEVICE_CAPS %d\n", cap);
175             return 0;
176         }
177
178     case SET_BOUNDS:
179         {
180             const RECT *r = in_data;
181             if(cbInput != sizeof(RECT)) {
182                 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
183                 return 0;
184             }
185             TRACE("SET_BOUNDS (%ld,%ld) - (%ld,%ld)\n", r->left, r->top,
186                   r->right, r->bottom);
187             return 0;
188         }
189
190     case EPSPRINTING:
191         {
192             UINT epsprint = *(UINT*)in_data;
193             /* FIXME: In this mode we do not need to send page intros and page
194              * ends according to the doc. But I just ignore that detail
195              * for now.
196              */
197             TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
198             return 1;
199         }
200
201     case POSTSCRIPT_DATA:
202     case PASSTHROUGH:
203     case POSTSCRIPT_PASSTHROUGH:
204         {
205             /* Write directly to spool file, bypassing normal PS driver
206              * processing that is done along with writing PostScript code
207              * to the spool.
208              * We have a WORD before the data counting the size, but
209              * cbInput is just this +2.
210              * However Photoshop 7 has a bug that sets cbInput to 2 less than the
211              * length of the string, rather than 2 more.  So we'll use the WORD at
212              * in_data[0] instead.
213              */
214             return WriteSpool16(physDev->job.hJob,((char*)in_data)+2,*(WORD*)in_data);
215         }
216
217     case POSTSCRIPT_IGNORE:
218       {
219         BOOL ret = physDev->job.quiet;
220         TRACE("POSTSCRIPT_IGNORE %d\n", *(short*)in_data);
221         physDev->job.quiet = *(short*)in_data;
222         return ret;
223       }
224
225     case GETSETPRINTORIENT:
226         {
227             /* If lpInData is present, it is a 20 byte structure, first 32
228              * bit LONG value is the orientation. if lpInData is NULL, it
229              * returns the current orientation.
230              */
231             FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
232             return 1;
233         }
234     case BEGIN_PATH:
235         TRACE("BEGIN_PATH\n");
236         if(physDev->pathdepth)
237             FIXME("Nested paths not yet handled\n");
238         return ++physDev->pathdepth;
239
240     case END_PATH:
241       {
242         struct PATH_INFO *info = (struct PATH_INFO*)in_data;
243
244         TRACE("END_PATH\n");
245         if(!physDev->pathdepth) {
246             ERR("END_PATH called without a BEIGN_PATH\n");
247             return -1;
248         }
249         TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
250               info->RenderMode, info->FillMode, info->BkMode);
251         switch(info->RenderMode) {
252         case RENDERMODE_NO_DISPLAY:
253             PSDRV_WriteClosePath(physDev); /* not sure if this is necessary, but it can't hurt */
254             break;
255         case RENDERMODE_OPEN:
256         case RENDERMODE_CLOSED:
257         default:
258             FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
259             break;
260         }
261         return --physDev->pathdepth;
262       }
263
264     case CLIP_TO_PATH:
265       {
266         WORD mode = *(WORD*)in_data;
267
268         switch(mode) {
269         case CLIP_SAVE:
270             TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
271             PSDRV_WriteGSave(physDev);
272             return 1;
273         case CLIP_RESTORE:
274             TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
275             PSDRV_WriteGRestore(physDev);
276             return 1;
277         case CLIP_INCLUSIVE:
278             TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
279             /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
280             PSDRV_WriteClip(physDev);
281             return 1;
282         case CLIP_EXCLUSIVE:
283             FIXME("CLIP_EXCLUSIVE: not implemented\n");
284             return 0;
285         default:
286             FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
287             return 0;
288         }
289         return 0;
290       }
291     default:
292         FIXME("Unimplemented code 0x%x\n", nEscape);
293         return 0;
294     }
295 }
296
297 /************************************************************************
298  *           PSDRV_StartPage
299  */
300 INT PSDRV_StartPage( PSDRV_PDEVICE *physDev )
301 {
302     if(!physDev->job.OutOfPage) {
303         FIXME("Already started a page?\n");
304         return 1;
305     }
306     physDev->job.PageNo++;
307     if(!PSDRV_WriteNewPage( physDev ))
308         return 0;
309     physDev->job.OutOfPage = FALSE;
310     return 1;
311 }
312
313
314 /************************************************************************
315  *           PSDRV_EndPage
316  */
317 INT PSDRV_EndPage( PSDRV_PDEVICE *physDev )
318 {
319     if(physDev->job.OutOfPage) {
320         FIXME("Already ended a page?\n");
321         return 1;
322     }
323     if(!PSDRV_WriteEndPage( physDev ))
324         return 0;
325     PSDRV_EmptyDownloadList(physDev, FALSE);
326     physDev->job.OutOfPage = TRUE;
327     return 1;
328 }
329
330
331 /************************************************************************
332  *           PSDRV_StartDoc
333  */
334 INT PSDRV_StartDoc( PSDRV_PDEVICE *physDev, const DOCINFOA *doc )
335 {
336     LPCSTR output = "LPT1:";
337     BYTE buf[300];
338     HANDLE hprn = INVALID_HANDLE_VALUE;
339     PRINTER_INFO_5A *pi5 = (PRINTER_INFO_5A*)buf;
340     DWORD needed;
341
342     if(physDev->job.hJob) {
343         FIXME("hJob != 0. Now what?\n");
344         return 0;
345     }
346
347     if(doc->lpszOutput)
348         output = doc->lpszOutput;
349     else if(physDev->job.output)
350         output = physDev->job.output;
351     else {
352         if(OpenPrinterA(physDev->pi->FriendlyName, &hprn, NULL) &&
353            GetPrinterA(hprn, 5, buf, sizeof(buf), &needed)) {
354             output = pi5->pPortName;
355         }
356         if(hprn != INVALID_HANDLE_VALUE)
357             ClosePrinter(hprn);
358     }
359
360     physDev->job.hJob = OpenJob16(output,  doc->lpszDocName, HDC_16(physDev->hdc) );
361     if(!physDev->job.hJob) {
362         WARN("OpenJob failed\n");
363         return 0;
364     }
365     physDev->job.banding = FALSE;
366     physDev->job.OutOfPage = TRUE;
367     physDev->job.PageNo = 0;
368     if(!PSDRV_WriteHeader( physDev, doc->lpszDocName ))
369         return 0;
370
371     return physDev->job.hJob;
372 }
373
374
375 /************************************************************************
376  *           PSDRV_EndDoc
377  */
378 INT PSDRV_EndDoc( PSDRV_PDEVICE *physDev )
379 {
380     INT ret = 1;
381     if(!physDev->job.hJob) {
382         FIXME("hJob == 0. Now what?\n");
383         return 0;
384     }
385
386     if(!physDev->job.OutOfPage) {
387         WARN("Somebody forgot a EndPage\n");
388         PSDRV_EndPage( physDev );
389     }
390     PSDRV_WriteFooter( physDev );
391
392     if( CloseJob16( physDev->job.hJob ) == SP_ERROR ) {
393         WARN("CloseJob error\n");
394         ret = 0;
395     }
396     physDev->job.hJob = 0;
397     return ret;
398 }