user32/tests: Remove superfluous code from WM_PAINT loop test.
[wine] / dlls / wineps.drv / ps.c
1 /*
2  *      PostScript output functions
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <locale.h>
26
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "psdrv.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
36
37 static const char psheader[] = /* title llx lly urx ury */
38 "%%!PS-Adobe-3.0\n"
39 "%%%%Creator: Wine PostScript Driver\n"
40 "%%%%Title: %s\n"
41 "%%%%BoundingBox: %d %d %d %d\n"
42 "%%%%Pages: (atend)\n"
43 "%%%%EndComments\n";
44
45 static const char psbeginprolog[] =
46 "%%BeginProlog\n";
47
48 static const char psendprolog[] =
49 "%%EndProlog\n";
50
51 static const char psprolog[] =
52 "/tmpmtrx matrix def\n"
53 "/hatch {\n"
54 "  pathbbox\n"
55 "  /b exch def /r exch def /t exch def /l exch def /gap 32 def\n"
56 "  l cvi gap idiv gap mul\n"
57 "  gap\n"
58 "  r cvi gap idiv gap mul\n"
59 "  {t moveto 0 b t sub rlineto}\n"
60 "  for\n"
61 "} bind def\n"
62 "/B {pop pop pop pop} def\n"
63 "/N {newpath} def\n"
64 "/havetype42gdir {version cvi 2015 ge} bind def\n";
65
66 static const char psbeginsetup[] =
67 "%%BeginSetup\n";
68
69 static const char psendsetup[] =
70 "%%EndSetup\n";
71
72 static const char psbeginfeature[] = /* feature, value */
73 "mark {\n"
74 "%%%%BeginFeature: %s %s\n";
75
76 static const char psendfeature[] =
77 "\n%%EndFeature\n"
78 "} stopped cleartomark\n";
79
80 static const char psnewpage[] = /* name, number, xres, yres, xtrans, ytrans, rot */
81 "%%%%Page: %s %d\n"
82 "%%%%BeginPageSetup\n"
83 "/pgsave save def\n"
84 "72 %d div 72 %d div scale\n"
85 "%d %d translate\n"
86 "1 -1 scale\n"
87 "%d rotate\n"
88 "%%%%EndPageSetup\n";
89
90 static const char psendpage[] =
91 "pgsave restore\n"
92 "showpage\n";
93
94 static const char psfooter[] = /* pages */
95 "%%%%Trailer\n"
96 "%%%%Pages: %d\n"
97 "%%%%EOF\n";
98
99 static const char psmoveto[] = /* x, y */
100 "%d %d moveto\n";
101
102 static const char pslineto[] = /* x, y */
103 "%d %d lineto\n";
104
105 static const char psstroke[] =
106 "stroke\n";
107
108 static const char psrectangle[] = /* x, y, width, height, -width */
109 "%d %d moveto\n"
110 "%d 0 rlineto\n"
111 "0 %d rlineto\n"
112 "%d 0 rlineto\n"
113 "closepath\n";
114
115 static const char psglyphshow[] = /* glyph name */
116 "/%s glyphshow\n";
117
118 static const char pssetfont[] = /* fontname, xscale, yscale, ascent, escapement */
119 "/%s findfont\n"
120 "[%d 0 0 %d 0 0]\n"
121 "%d 10 div matrix rotate\n"
122 "matrix concatmatrix\n"
123 "makefont setfont\n";
124
125 static const char pssetline[] = /* width, join, endcap */
126 "%d setlinewidth %u setlinejoin %u setlinecap\n";
127
128 static const char pssetdash[] = /* dash, offset */
129 "[%s] %d setdash\n";
130
131 static const char pssetgray[] = /* gray */
132 "%.2f setgray\n";
133
134 static const char pssetrgbcolor[] = /* r, g, b */
135 "%.2f %.2f %.2f setrgbcolor\n";
136
137 static const char psarc[] = /* x, y, w, h, ang1, ang2 */
138 "tmpmtrx currentmatrix pop\n"
139 "%d %d translate\n"
140 "%d %d scale\n"
141 "0 0 0.5 %.1f %.1f arc\n"
142 "tmpmtrx setmatrix\n";
143
144 static const char psgsave[] =
145 "gsave\n";
146
147 static const char psgrestore[] =
148 "grestore\n";
149
150 static const char psfill[] =
151 "fill\n";
152
153 static const char pseofill[] =
154 "eofill\n";
155
156 static const char psnewpath[] =
157 "newpath\n";
158
159 static const char psclosepath[] =
160 "closepath\n";
161
162 static const char psclip[] =
163 "clip\n";
164
165 static const char pseoclip[] =
166 "eoclip\n";
167
168 static const char psrectclip[] =
169 "%d %d %d %d rectclip\n";
170
171 static const char psrectclip2[] =
172 "%s rectclip\n";
173
174 static const char pshatch[] =
175 "hatch\n";
176
177 static const char psrotate[] = /* ang */
178 "%.1f rotate\n";
179
180 static const char psarrayput[] =
181 "%s %d %d put\n";
182
183 static const char psarraydef[] =
184 "/%s %d array def\n";
185
186 static const char psenddocument[] =
187 "\n%%EndDocument\n";
188
189 DWORD PSDRV_WriteSpool(PSDRV_PDEVICE *physDev, LPCSTR lpData, DWORD cch)
190 {
191     int num, num_left = cch;
192
193     if(physDev->job.quiet) {
194         TRACE("ignoring output\n");
195         return 0;
196     }
197
198     if(physDev->job.in_passthrough) { /* Was in PASSTHROUGH mode */
199         WriteSpool16( physDev->job.hJob, (LPSTR)psenddocument, sizeof(psenddocument)-1 );
200         physDev->job.in_passthrough = physDev->job.had_passthrough_rect = FALSE;
201     }
202
203     if(physDev->job.OutOfPage) { /* Will get here after NEWFRAME Escape */
204         if( !PSDRV_StartPage(physDev) )
205             return 0;
206     }
207
208     do {
209         num = min(num_left, 0x8000);
210         if(WriteSpool16( physDev->job.hJob, (LPSTR)lpData, num ) != num)
211             return 0;
212         lpData += num;
213         num_left -= num;
214     } while(num_left);
215
216     return cch;
217 }
218
219
220 static INT PSDRV_WriteFeature(HANDLE16 hJob, LPCSTR feature, LPCSTR value, LPSTR invocation)
221 {
222
223     char *buf = HeapAlloc( PSDRV_Heap, 0, sizeof(psbeginfeature) +
224                            strlen(feature) + strlen(value));
225
226
227     sprintf(buf, psbeginfeature, feature, value);
228     WriteSpool16( hJob, buf, strlen(buf) );
229
230     WriteSpool16( hJob, invocation, strlen(invocation) );
231
232     WriteSpool16( hJob, (LPSTR)psendfeature, strlen(psendfeature) );
233
234     HeapFree( PSDRV_Heap, 0, buf );
235     return 1;
236 }
237
238 /********************************************************
239  *         escape_title
240  *
241  * Helper for PSDRV_WriteHeader.  Escape any non-printable characters
242  * as octal.  If we've had to use an escape then surround the entire string
243  * in brackets.  Truncate string to represent at most 0x80 characters.
244  *
245  */
246 static char *escape_title(LPCSTR str)
247 {
248     char *ret, *cp;
249     int i, extra = 0;
250
251     if(!str)
252     {
253         ret = HeapAlloc(GetProcessHeap(), 0, 1);
254         *ret = '\0';
255         return ret;
256     }
257
258     for(i = 0; i < 0x80 && str[i]; i++)
259     {
260         if(!isprint(str[i]))
261            extra += 3;
262     }
263
264     if(!extra)
265     {
266         ret = HeapAlloc(GetProcessHeap(), 0, i + 1);
267         memcpy(ret, str, i);
268         ret[i] = '\0';
269         return ret;
270     }
271
272     extra += 2; /* two for the brackets */
273     cp = ret = HeapAlloc(GetProcessHeap(), 0, i + extra + 1);
274     *cp++ = '(';
275     for(i = 0; i < 0x80 && str[i]; i++)
276     {
277         if(!isprint(str[i]))
278         {
279             BYTE b = (BYTE)str[i];
280             *cp++ = '\\';
281             *cp++ = ((b >> 6) & 0x7) + '0';
282             *cp++ = ((b >> 3) & 0x7) + '0';
283             *cp++ = ((b)      & 0x7) + '0';
284         }
285         else
286             *cp++ = str[i];
287     }
288     *cp++ = ')';
289     *cp = '\0';
290     return ret;
291 }
292        
293
294 INT PSDRV_WriteHeader( PSDRV_PDEVICE *physDev, LPCSTR title )
295 {
296     char *buf, *escaped_title;
297     INPUTSLOT *slot;
298     PAGESIZE *page;
299     DUPLEX *duplex;
300     int win_duplex;
301     int llx, lly, urx, ury;
302
303     TRACE("%s\n", debugstr_a(title));
304
305     escaped_title = escape_title(title);
306     buf = HeapAlloc( PSDRV_Heap, 0, sizeof(psheader) +
307                      strlen(escaped_title) + 30 );
308     if(!buf) {
309         WARN("HeapAlloc failed\n");
310         return 0;
311     }
312
313     /* BBox co-ords are in default user co-ord system so urx < ury even in
314        landscape mode */
315     llx = physDev->ImageableArea.left * 72.0 / physDev->logPixelsX;
316     lly = physDev->ImageableArea.bottom * 72.0 / physDev->logPixelsY;
317     urx = physDev->ImageableArea.right * 72.0 / physDev->logPixelsX;
318     ury = physDev->ImageableArea.top * 72.0 / physDev->logPixelsY;
319     /* FIXME should do something better with BBox */
320
321     sprintf(buf, psheader, escaped_title, llx, lly, urx, ury);
322
323     HeapFree(GetProcessHeap(), 0, escaped_title);
324     if( WriteSpool16( physDev->job.hJob, buf, strlen(buf) ) !=
325                                                      strlen(buf) ) {
326         WARN("WriteSpool error\n");
327         HeapFree( PSDRV_Heap, 0, buf );
328         return 0;
329     }
330     HeapFree( PSDRV_Heap, 0, buf );
331
332     WriteSpool16( physDev->job.hJob, (LPSTR)psbeginprolog, strlen(psbeginprolog) );
333     WriteSpool16( physDev->job.hJob, (LPSTR)psprolog, strlen(psprolog) );
334     WriteSpool16( physDev->job.hJob, (LPSTR)psendprolog, strlen(psendprolog) );
335
336     WriteSpool16( physDev->job.hJob, (LPSTR)psbeginsetup, strlen(psbeginsetup) );
337
338     if(physDev->Devmode->dmPublic.u1.s1.dmCopies > 1) {
339         char copies_buf[100];
340         sprintf(copies_buf, "mark {\n << /NumCopies %d >> setpagedevice\n} stopped cleartomark\n", physDev->Devmode->dmPublic.u1.s1.dmCopies);
341         WriteSpool16(physDev->job.hJob, copies_buf, strlen(copies_buf));
342     }
343
344     for(slot = physDev->pi->ppd->InputSlots; slot; slot = slot->next) {
345         if(slot->WinBin == physDev->Devmode->dmPublic.u1.s1.dmDefaultSource) {
346             if(slot->InvocationString) {
347                 PSDRV_WriteFeature(physDev->job.hJob, "*InputSlot", slot->Name,
348                              slot->InvocationString);
349                 break;
350             }
351         }
352     }
353
354     LIST_FOR_EACH_ENTRY(page, &physDev->pi->ppd->PageSizes, PAGESIZE, entry) {
355         if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize) {
356             if(page->InvocationString) {
357                 PSDRV_WriteFeature(physDev->job.hJob, "*PageSize", page->Name,
358                              page->InvocationString);
359                 break;
360             }
361         }
362     }
363
364     win_duplex = physDev->Devmode->dmPublic.dmFields & DM_DUPLEX ?
365         physDev->Devmode->dmPublic.dmDuplex : 0;
366     for(duplex = physDev->pi->ppd->Duplexes; duplex; duplex = duplex->next) {
367         if(duplex->WinDuplex == win_duplex) {
368             if(duplex->InvocationString) {
369                 PSDRV_WriteFeature(physDev->job.hJob, "*Duplex", duplex->Name,
370                              duplex->InvocationString);
371                 break;
372             }
373         }
374     }
375
376     WriteSpool16( physDev->job.hJob, (LPSTR)psendsetup, strlen(psendsetup) );
377
378
379     return 1;
380 }
381
382
383 INT PSDRV_WriteFooter( PSDRV_PDEVICE *physDev )
384 {
385     char *buf;
386
387     buf = HeapAlloc( PSDRV_Heap, 0, sizeof(psfooter) + 100 );
388     if(!buf) {
389         WARN("HeapAlloc failed\n");
390         return 0;
391     }
392
393     sprintf(buf, psfooter, physDev->job.PageNo);
394
395     if( WriteSpool16( physDev->job.hJob, buf, strlen(buf) ) !=
396                                                      strlen(buf) ) {
397         WARN("WriteSpool error\n");
398         HeapFree( PSDRV_Heap, 0, buf );
399         return 0;
400     }
401     HeapFree( PSDRV_Heap, 0, buf );
402     return 1;
403 }
404
405
406
407 INT PSDRV_WriteEndPage( PSDRV_PDEVICE *physDev )
408 {
409     if( WriteSpool16( physDev->job.hJob, (LPSTR)psendpage, sizeof(psendpage)-1 ) !=
410                                                      sizeof(psendpage)-1 ) {
411         WARN("WriteSpool error\n");
412         return 0;
413     }
414     return 1;
415 }
416
417
418
419
420 INT PSDRV_WriteNewPage( PSDRV_PDEVICE *physDev )
421 {
422     char *buf;
423     char name[100];
424     signed int xtrans, ytrans, rotation;
425
426     sprintf(name, "%d", physDev->job.PageNo);
427
428     buf = HeapAlloc( PSDRV_Heap, 0, sizeof(psnewpage) + 200 );
429     if(!buf) {
430         WARN("HeapAlloc failed\n");
431         return 0;
432     }
433
434     if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) {
435         if(physDev->pi->ppd->LandscapeOrientation == -90) {
436             xtrans = physDev->ImageableArea.right;
437             ytrans = physDev->ImageableArea.top;
438             rotation = 90;
439         } else {
440             xtrans = physDev->ImageableArea.left;
441             ytrans = physDev->ImageableArea.bottom;
442             rotation = -90;
443         }
444     } else {
445         xtrans = physDev->ImageableArea.left;
446         ytrans = physDev->ImageableArea.top;
447         rotation = 0;
448     }
449
450     sprintf(buf, psnewpage, name, physDev->job.PageNo,
451             physDev->logPixelsX, physDev->logPixelsY,
452             xtrans, ytrans, rotation);
453
454     if( WriteSpool16( physDev->job.hJob, buf, strlen(buf) ) !=
455                                                      strlen(buf) ) {
456         WARN("WriteSpool error\n");
457         HeapFree( PSDRV_Heap, 0, buf );
458         return 0;
459     }
460     HeapFree( PSDRV_Heap, 0, buf );
461     return 1;
462 }
463
464
465 BOOL PSDRV_WriteMoveTo(PSDRV_PDEVICE *physDev, INT x, INT y)
466 {
467     char buf[100];
468
469     sprintf(buf, psmoveto, x, y);
470     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
471 }
472
473 BOOL PSDRV_WriteLineTo(PSDRV_PDEVICE *physDev, INT x, INT y)
474 {
475     char buf[100];
476
477     sprintf(buf, pslineto, x, y);
478     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
479 }
480
481
482 BOOL PSDRV_WriteStroke(PSDRV_PDEVICE *physDev)
483 {
484     return PSDRV_WriteSpool(physDev, psstroke, sizeof(psstroke)-1);
485 }
486
487
488
489 BOOL PSDRV_WriteRectangle(PSDRV_PDEVICE *physDev, INT x, INT y, INT width,
490                         INT height)
491 {
492     char buf[100];
493
494     sprintf(buf, psrectangle, x, y, width, height, -width);
495     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
496 }
497
498 BOOL PSDRV_WriteArc(PSDRV_PDEVICE *physDev, INT x, INT y, INT w, INT h, double ang1,
499                       double ang2)
500 {
501     char buf[256];
502
503     /* Make angles -ve and swap order because we're working with an upside
504        down y-axis */
505     push_lc_numeric("C");
506     sprintf(buf, psarc, x, y, w, h, -ang2, -ang1);
507     pop_lc_numeric();
508     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
509 }
510
511
512 BOOL PSDRV_WriteSetFont(PSDRV_PDEVICE *physDev, const char *name, INT size, INT escapement)
513 {
514     char *buf;
515
516     buf = HeapAlloc( PSDRV_Heap, 0, sizeof(pssetfont) +
517                              strlen(name) + 40);
518
519     if(!buf) {
520         WARN("HeapAlloc failed\n");
521         return FALSE;
522     }
523
524     sprintf(buf, pssetfont, name, size, -size, -escapement);
525
526     PSDRV_WriteSpool(physDev, buf, strlen(buf));
527     HeapFree(PSDRV_Heap, 0, buf);
528     return TRUE;
529 }
530
531 BOOL PSDRV_WriteSetColor(PSDRV_PDEVICE *physDev, PSCOLOR *color)
532 {
533     char buf[256];
534
535     PSDRV_CopyColor(&physDev->inkColor, color);
536     switch(color->type) {
537     case PSCOLOR_RGB:
538         push_lc_numeric("C");
539         sprintf(buf, pssetrgbcolor, color->value.rgb.r, color->value.rgb.g,
540                 color->value.rgb.b);
541         pop_lc_numeric();
542         return PSDRV_WriteSpool(physDev, buf, strlen(buf));
543
544     case PSCOLOR_GRAY:
545         push_lc_numeric("C");
546         sprintf(buf, pssetgray, color->value.gray.i);
547         pop_lc_numeric();
548         return PSDRV_WriteSpool(physDev, buf, strlen(buf));
549
550     default:
551         ERR("Unkonwn colour type %d\n", color->type);
552         break;
553     }
554
555     return FALSE;
556 }
557
558 BOOL PSDRV_WriteSetPen(PSDRV_PDEVICE *physDev)
559 {
560     char buf[256];
561
562     sprintf(buf, pssetline, physDev->pen.width, physDev->pen.join, physDev->pen.endcap);
563     PSDRV_WriteSpool(physDev, buf, strlen(buf));
564
565     if(physDev->pen.dash) {
566         sprintf(buf, pssetdash, physDev->pen.dash, 0);
567     }
568     else
569         sprintf(buf, pssetdash, "", 0);
570    
571    PSDRV_WriteSpool(physDev, buf, strlen(buf));
572         
573    return TRUE;
574 }
575
576 BOOL PSDRV_WriteGlyphShow(PSDRV_PDEVICE *physDev, LPCSTR g_name)
577 {
578     char    buf[128];
579     int     l;
580
581     l = snprintf(buf, sizeof(buf), psglyphshow, g_name);
582
583     if (l < sizeof(psglyphshow) - 2 || l > sizeof(buf) - 1) {
584         WARN("Unusable glyph name '%s' - ignoring\n", g_name);
585         return FALSE;
586     }
587
588     PSDRV_WriteSpool(physDev, buf, l);
589     return TRUE;
590 }
591
592 BOOL PSDRV_WriteFill(PSDRV_PDEVICE *physDev)
593 {
594     return PSDRV_WriteSpool(physDev, psfill, sizeof(psfill)-1);
595 }
596
597 BOOL PSDRV_WriteEOFill(PSDRV_PDEVICE *physDev)
598 {
599     return PSDRV_WriteSpool(physDev, pseofill, sizeof(pseofill)-1);
600 }
601
602 BOOL PSDRV_WriteGSave(PSDRV_PDEVICE *physDev)
603 {
604     return PSDRV_WriteSpool(physDev, psgsave, sizeof(psgsave)-1);
605 }
606
607 BOOL PSDRV_WriteGRestore(PSDRV_PDEVICE *physDev)
608 {
609     return PSDRV_WriteSpool(physDev, psgrestore, sizeof(psgrestore)-1);
610 }
611
612 BOOL PSDRV_WriteNewPath(PSDRV_PDEVICE *physDev)
613 {
614     return PSDRV_WriteSpool(physDev, psnewpath, sizeof(psnewpath)-1);
615 }
616
617 BOOL PSDRV_WriteClosePath(PSDRV_PDEVICE *physDev)
618 {
619     return PSDRV_WriteSpool(physDev, psclosepath, sizeof(psclosepath)-1);
620 }
621
622 BOOL PSDRV_WriteClip(PSDRV_PDEVICE *physDev)
623 {
624     return PSDRV_WriteSpool(physDev, psclip, sizeof(psclip)-1);
625 }
626
627 BOOL PSDRV_WriteEOClip(PSDRV_PDEVICE *physDev)
628 {
629     return PSDRV_WriteSpool(physDev, pseoclip, sizeof(pseoclip)-1);
630 }
631
632 BOOL PSDRV_WriteHatch(PSDRV_PDEVICE *physDev)
633 {
634     return PSDRV_WriteSpool(physDev, pshatch, sizeof(pshatch)-1);
635 }
636
637 BOOL PSDRV_WriteRotate(PSDRV_PDEVICE *physDev, float ang)
638 {
639     char buf[256];
640
641     push_lc_numeric("C");
642     sprintf(buf, psrotate, ang);
643     pop_lc_numeric();
644     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
645 }
646
647 BOOL PSDRV_WriteIndexColorSpaceBegin(PSDRV_PDEVICE *physDev, int size)
648 {
649     char buf[256];
650     sprintf(buf, "[/Indexed /DeviceRGB %d\n<\n", size);
651     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
652 }
653
654 BOOL PSDRV_WriteIndexColorSpaceEnd(PSDRV_PDEVICE *physDev)
655 {
656     static const char buf[] = ">\n] setcolorspace\n";
657     return PSDRV_WriteSpool(physDev, buf, sizeof(buf) - 1);
658 }
659
660 BOOL PSDRV_WriteRGB(PSDRV_PDEVICE *physDev, COLORREF *map, int number)
661 {
662     char *buf = HeapAlloc(PSDRV_Heap, 0, number * 7 + 1), *ptr;
663     int i;
664
665     ptr = buf;
666     for(i = 0; i < number; i++) {
667         sprintf(ptr, "%02x%02x%02x%c", (int)GetRValue(map[i]),
668                 (int)GetGValue(map[i]), (int)GetBValue(map[i]),
669                 ((i & 0x7) == 0x7) || (i == number - 1) ? '\n' : ' ');
670         ptr += 7;
671     }
672     PSDRV_WriteSpool(physDev, buf, number * 7);
673     HeapFree(PSDRV_Heap, 0, buf);
674     return TRUE;
675 }
676
677 static BOOL PSDRV_WriteImageDict(PSDRV_PDEVICE *physDev, WORD depth,
678                                  INT widthSrc, INT heightSrc, char *bits)
679 {
680     static const char start[] = "<<\n"
681       " /ImageType 1\n /Width %d\n /Height %d\n /BitsPerComponent %d\n"
682       " /ImageMatrix [%d 0 0 %d 0 %d]\n";
683
684     static const char decode1[] = " /Decode [0 %d]\n";
685     static const char decode3[] = " /Decode [0 1 0 1 0 1]\n";
686
687     static const char end[] = " /DataSource currentfile /ASCII85Decode filter /RunLengthDecode filter\n>>\n";
688     static const char endbits[] = " /DataSource <%s>\n>>\n";
689
690     char *buf = HeapAlloc(PSDRV_Heap, 0, 1000);
691
692     sprintf(buf, start, widthSrc, heightSrc,
693             (depth < 8) ? depth : 8, widthSrc, -heightSrc, heightSrc);
694
695     PSDRV_WriteSpool(physDev, buf, strlen(buf));
696
697     switch(depth) {
698     case 8:
699         sprintf(buf, decode1, 255);
700         break;
701
702     case 4:
703         sprintf(buf, decode1, 15);
704         break;
705
706     case 1:
707         sprintf(buf, decode1, 1);
708         break;
709
710     default:
711         strcpy(buf, decode3);
712         break;
713     }
714
715     PSDRV_WriteSpool(physDev, buf, strlen(buf));
716
717     if(!bits) {
718         PSDRV_WriteSpool(physDev, end, sizeof(end) - 1);
719     } else {
720         sprintf(buf, endbits, bits);
721         PSDRV_WriteSpool(physDev, buf, strlen(buf));
722     }
723
724     HeapFree(PSDRV_Heap, 0, buf);
725     return TRUE;
726 }
727
728 BOOL PSDRV_WriteImage(PSDRV_PDEVICE *physDev, WORD depth, INT xDst, INT yDst,
729                       INT widthDst, INT heightDst, INT widthSrc,
730                       INT heightSrc, BOOL mask)
731 {
732     static const char start[] = "%d %d translate\n%d %d scale\n";
733     static const char image[] = "image\n";
734     static const char imagemask[] = "imagemask\n";
735     char buf[100];
736
737     sprintf(buf, start, xDst, yDst, widthDst, heightDst);
738     PSDRV_WriteSpool(physDev, buf, strlen(buf));
739     PSDRV_WriteImageDict(physDev, depth, widthSrc, heightSrc, NULL);
740     if(mask)
741         PSDRV_WriteSpool(physDev, imagemask, sizeof(imagemask) - 1);
742     else
743         PSDRV_WriteSpool(physDev, image, sizeof(image) - 1);
744     return TRUE;
745 }
746
747
748 BOOL PSDRV_WriteBytes(PSDRV_PDEVICE *physDev, const BYTE *bytes, DWORD number)
749 {
750     char *buf = HeapAlloc(PSDRV_Heap, 0, number * 3 + 1);
751     char *ptr;
752     unsigned int i;
753
754     ptr = buf;
755
756     for(i = 0; i < number; i++) {
757         sprintf(ptr, "%02x", bytes[i]);
758         ptr += 2;
759         if(((i & 0xf) == 0xf) || (i == number - 1)) {
760             strcpy(ptr, "\n");
761             ptr++;
762         }
763     }
764     PSDRV_WriteSpool(physDev, buf, ptr - buf);
765     HeapFree(PSDRV_Heap, 0, buf);
766     return TRUE;
767 }
768
769 BOOL PSDRV_WriteData(PSDRV_PDEVICE *physDev, const BYTE *data, DWORD number)
770 {
771     int num, num_left = number;
772
773     do {
774         num = min(num_left, 60);
775         PSDRV_WriteSpool(physDev, (LPCSTR)data, num);
776         PSDRV_WriteSpool(physDev, "\n", 1);
777         data += num;
778         num_left -= num;
779     } while(num_left);
780
781     return TRUE;
782 }
783
784 BOOL PSDRV_WriteArrayPut(PSDRV_PDEVICE *physDev, CHAR *pszArrayName, INT nIndex, LONG lObject)
785 {
786     char buf[100];
787
788     sprintf(buf, psarrayput, pszArrayName, nIndex, lObject);
789     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
790 }
791
792 BOOL PSDRV_WriteArrayDef(PSDRV_PDEVICE *physDev, CHAR *pszArrayName, INT nSize)
793 {
794     char buf[100];
795
796     sprintf(buf, psarraydef, pszArrayName, nSize);
797     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
798 }
799
800 BOOL PSDRV_WriteRectClip(PSDRV_PDEVICE *physDev, INT x, INT y, INT w, INT h)
801 {
802     char buf[100];
803
804     sprintf(buf, psrectclip, x, y, w, h);
805     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
806 }
807
808 BOOL PSDRV_WriteRectClip2(PSDRV_PDEVICE *physDev, CHAR *pszArrayName)
809 {
810     char buf[100];
811
812     sprintf(buf, psrectclip2, pszArrayName);
813     return PSDRV_WriteSpool(physDev, buf, strlen(buf));
814 }
815
816 BOOL PSDRV_WritePatternDict(PSDRV_PDEVICE *physDev, BITMAP *bm, BYTE *bits)
817 {
818     static const char mypat[] = "/mypat\n";
819     static const char do_pattern[] = "<<\n /PaintType 1\n /PatternType 1\n /TilingType 1\n "
820       "/BBox [0 0 %d %d]\n /XStep %d\n /YStep %d\n /PaintProc {\n  begin\n  0 0 translate\n"
821       "  %d %d scale\n  mypat image\n  end\n }\n>>\n matrix makepattern setpattern\n";
822
823     char *buf, *ptr;
824     INT w, h, x, y, w_mult, h_mult;
825     COLORREF map[2];
826
827     w = bm->bmWidth & ~0x7;
828     h = bm->bmHeight & ~0x7;
829
830     buf = HeapAlloc(PSDRV_Heap, 0, sizeof(do_pattern) + 100);
831     ptr = buf;
832     for(y = h-1; y >= 0; y--) {
833         for(x = 0; x < w/8; x++) {
834             sprintf(ptr, "%02x", *(bits + x/8 + y * bm->bmWidthBytes));
835             ptr += 2;
836         }
837     }
838     PSDRV_WriteSpool(physDev, mypat, sizeof(mypat) - 1);
839     PSDRV_WriteImageDict(physDev, 1, 8, 8, buf);
840     PSDRV_WriteSpool(physDev, "def\n", 4);
841
842     PSDRV_WriteIndexColorSpaceBegin(physDev, 1);
843     map[0] = GetTextColor( physDev->hdc );
844     map[1] = GetBkColor( physDev->hdc );
845     PSDRV_WriteRGB(physDev, map, 2);
846     PSDRV_WriteIndexColorSpaceEnd(physDev);
847
848     /* Windows seems to scale patterns so that a one pixel corresponds to 1/300" */
849     w_mult = (physDev->logPixelsX + 150) / 300;
850     h_mult = (physDev->logPixelsY + 150) / 300;
851     sprintf(buf, do_pattern, w * w_mult, h * h_mult, w * w_mult, h * h_mult, w * w_mult, h * h_mult);
852     PSDRV_WriteSpool(physDev,  buf, strlen(buf));
853
854     HeapFree(PSDRV_Heap, 0, buf);
855     return TRUE;
856 }
857
858 BOOL PSDRV_WriteDIBPatternDict(PSDRV_PDEVICE *physDev, BITMAPINFO *bmi, UINT usage)
859 {
860     static const char mypat[] = "/mypat\n";
861     static const char do_pattern[] = "<<\n /PaintType 1\n /PatternType 1\n /TilingType 1\n "
862       "/BBox [0 0 %d %d]\n /XStep %d\n /YStep %d\n /PaintProc {\n  begin\n  0 0 translate\n"
863       "  %d %d scale\n  mypat image\n  end\n }\n>>\n matrix makepattern setpattern\n";
864     char *buf, *ptr;
865     BYTE *bits;
866     INT w, h, x, y, colours, w_mult, h_mult;
867     COLORREF map[2];
868
869     if(bmi->bmiHeader.biBitCount != 1) {
870         FIXME("dib depth %d not supported\n", bmi->bmiHeader.biBitCount);
871         return FALSE;
872     }
873
874     bits = (LPBYTE)bmi + bmi->bmiHeader.biSize;
875     colours = bmi->bmiHeader.biClrUsed;
876     if (colours > 256) colours = 256;
877     if(!colours && bmi->bmiHeader.biBitCount <= 8)
878         colours = 1 << bmi->bmiHeader.biBitCount;
879     bits += colours * ((usage == DIB_RGB_COLORS) ?
880                        sizeof(RGBQUAD) : sizeof(WORD));
881
882     w = bmi->bmiHeader.biWidth & ~0x7;
883     h = bmi->bmiHeader.biHeight & ~0x7;
884
885     buf = HeapAlloc(PSDRV_Heap, 0, sizeof(do_pattern) + 100);
886     ptr = buf;
887     for(y = h-1; y >= 0; y--) {
888         for(x = 0; x < w/8; x++) {
889             sprintf(ptr, "%02x", *(bits + x/8 + y *
890                                    (bmi->bmiHeader.biWidth + 31) / 32 * 4));
891             ptr += 2;
892         }
893     }
894     PSDRV_WriteSpool(physDev, mypat, sizeof(mypat) - 1);
895     PSDRV_WriteImageDict(physDev, 1, 8, 8, buf);
896     PSDRV_WriteSpool(physDev, "def\n", 4);
897
898     PSDRV_WriteIndexColorSpaceBegin(physDev, 1);
899     map[0] = GetTextColor( physDev->hdc );
900     map[1] = GetBkColor( physDev->hdc );
901     PSDRV_WriteRGB(physDev, map, 2);
902     PSDRV_WriteIndexColorSpaceEnd(physDev);
903
904     /* Windows seems to scale patterns so that a one pixel corresponds to 1/300" */
905     w_mult = (physDev->logPixelsX + 150) / 300;
906     h_mult = (physDev->logPixelsY + 150) / 300;
907     sprintf(buf, do_pattern, w * w_mult, h * h_mult, w * w_mult, h * h_mult, w * w_mult, h * h_mult);
908     PSDRV_WriteSpool(physDev,  buf, strlen(buf));
909     HeapFree(PSDRV_Heap, 0, buf);
910     return TRUE;
911 }