Implemented InternetSetOptionExA/W.
[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              * (Usually we have a WORD before the data counting the size, but
209              * cbInput is just this +2.)
210              */
211             return WriteSpool16(physDev->job.hJob,((char*)in_data)+2,cbInput-2);
212         }
213
214     case POSTSCRIPT_IGNORE:
215       {
216         BOOL ret = physDev->job.quiet;
217         TRACE("POSTSCRIPT_IGNORE %d\n", *(short*)in_data);
218         physDev->job.quiet = *(short*)in_data;
219         return ret;
220       }
221
222     case GETSETPRINTORIENT:
223         {
224             /* If lpInData is present, it is a 20 byte structure, first 32
225              * bit LONG value is the orientation. if lpInData is NULL, it
226              * returns the current orientation.
227              */
228             FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
229             return 1;
230         }
231     case BEGIN_PATH:
232         TRACE("BEGIN_PATH\n");
233         if(physDev->pathdepth)
234             FIXME("Nested paths not yet handled\n");
235         return ++physDev->pathdepth;
236
237     case END_PATH:
238       {
239         struct PATH_INFO *info = (struct PATH_INFO*)in_data;
240
241         TRACE("END_PATH\n");
242         if(!physDev->pathdepth) {
243             ERR("END_PATH called without a BEIGN_PATH\n");
244             return -1;
245         }
246         TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
247               info->RenderMode, info->FillMode, info->BkMode);
248         switch(info->RenderMode) {
249         case RENDERMODE_NO_DISPLAY:
250             PSDRV_WriteClosePath(physDev); /* not sure if this is necessary, but it can't hurt */
251             break;
252         case RENDERMODE_OPEN:
253         case RENDERMODE_CLOSED:
254         default:
255             FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
256             break;
257         }
258         return --physDev->pathdepth;
259       }
260
261     case CLIP_TO_PATH:
262       {
263         WORD mode = *(WORD*)in_data;
264
265         switch(mode) {
266         case CLIP_SAVE:
267             TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
268             PSDRV_WriteGSave(physDev);
269             return 1;
270         case CLIP_RESTORE:
271             TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
272             PSDRV_WriteGRestore(physDev);
273             return 1;
274         case CLIP_INCLUSIVE:
275             TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
276             /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
277             PSDRV_WriteClip(physDev);
278             return 1;
279         case CLIP_EXCLUSIVE:
280             FIXME("CLIP_EXCLUSIVE: not implemented\n");
281             return 0;
282         default:
283             FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
284             return 0;
285         }
286         return 0;
287       }
288     default:
289         FIXME("Unimplemented code 0x%x\n", nEscape);
290         return 0;
291     }
292 }
293
294 /************************************************************************
295  *           PSDRV_StartPage
296  */
297 INT PSDRV_StartPage( PSDRV_PDEVICE *physDev )
298 {
299     if(!physDev->job.OutOfPage) {
300         FIXME("Already started a page?\n");
301         return 1;
302     }
303     physDev->job.PageNo++;
304     if(!PSDRV_WriteNewPage( physDev ))
305         return 0;
306     physDev->job.OutOfPage = FALSE;
307     return 1;
308 }
309
310
311 /************************************************************************
312  *           PSDRV_EndPage
313  */
314 INT PSDRV_EndPage( PSDRV_PDEVICE *physDev )
315 {
316     if(physDev->job.OutOfPage) {
317         FIXME("Already ended a page?\n");
318         return 1;
319     }
320     if(!PSDRV_WriteEndPage( physDev ))
321         return 0;
322     PSDRV_EmptyDownloadList(physDev);
323     physDev->job.OutOfPage = TRUE;
324     return 1;
325 }
326
327
328 /************************************************************************
329  *           PSDRV_StartDoc
330  */
331 INT PSDRV_StartDoc( PSDRV_PDEVICE *physDev, const DOCINFOA *doc )
332 {
333     if(physDev->job.hJob) {
334         FIXME("hJob != 0. Now what?\n");
335         return 0;
336     }
337
338     if(doc->lpszOutput) {
339         HeapFree( PSDRV_Heap, 0, physDev->job.output );
340         physDev->job.output = HeapAlloc( PSDRV_Heap, 0, strlen(doc->lpszOutput)+1 );
341         strcpy( physDev->job.output, doc->lpszOutput );
342     }
343     physDev->job.hJob = OpenJob16(physDev->job.output,  doc->lpszDocName, HDC_16(physDev->hdc) );
344     if(!physDev->job.hJob) {
345         WARN("OpenJob failed\n");
346         return 0;
347     }
348     physDev->job.banding = FALSE;
349     physDev->job.OutOfPage = TRUE;
350     physDev->job.PageNo = 0;
351     if(!PSDRV_WriteHeader( physDev, doc->lpszDocName ))
352         return 0;
353
354     return physDev->job.hJob;
355 }
356
357
358 /************************************************************************
359  *           PSDRV_EndDoc
360  */
361 INT PSDRV_EndDoc( PSDRV_PDEVICE *physDev )
362 {
363     INT ret = 1;
364     if(!physDev->job.hJob) {
365         FIXME("hJob == 0. Now what?\n");
366         return 0;
367     }
368
369     if(!physDev->job.OutOfPage) {
370         WARN("Somebody forgot a EndPage\n");
371         PSDRV_EndPage( physDev );
372     }
373     PSDRV_WriteFooter( physDev );
374
375     if( CloseJob16( physDev->job.hJob ) == SP_ERROR ) {
376         WARN("CloseJob error\n");
377         ret = 0;
378     }
379     physDev->job.hJob = 0;
380     return ret;
381 }