1 
2 /*
3  * bltPs.c --
4  *
5  *      This module implements general PostScript conversion routines.
6  *
7  * Copyright 1991-1998 Lucent Technologies, Inc.
8  *
9  * Permission to use, copy, modify, and distribute this software and
10  * its documentation for any purpose and without fee is hereby
11  * granted, provided that the above copyright notice appear in all
12  * copies and that both that the copyright notice and warranty
13  * disclaimer appear in supporting documentation, and that the names
14  * of Lucent Technologies any of their entities not be used in
15  * advertising or publicity pertaining to distribution of the software
16  * without specific, written prior permission.
17  *
18  * Lucent Technologies disclaims all warranties with regard to this
19  * software, including all implied warranties of merchantability and
20  * fitness.  In no event shall Lucent Technologies be liable for any
21  * special, indirect or consequential damages or any damages
22  * whatsoever resulting from loss of use, data or profits, whether in
23  * an action of contract, negligence or other tortuous action, arising
24  * out of or in connection with the use or performance of this
25  * software.
26  */
27 
28 #include "bltInt.h"
29 #include "bltPs.h"
30 
31 #include <X11/Xutil.h>
32 #include <X11/Xatom.h>
33 #if defined(__STDC__)
34 #include <stdarg.h>
35 #else
36 #include <varargs.h>
37 #endif
38 
39 #define PS_MAXPATH	1500	/* Maximum number of components in a PostScript
40 				 * (level 1) path. */
41 
42 PsToken
Blt_GetPsToken(interp,tkwin)43 Blt_GetPsToken(interp, tkwin)
44     Tcl_Interp *interp;
45     Tk_Window tkwin;
46 {
47     struct PsTokenStruct *tokenPtr;
48 
49     tokenPtr = Blt_Malloc(sizeof(struct PsTokenStruct));
50     assert(tokenPtr);
51 
52     tokenPtr->fontVarName = tokenPtr->colorVarName = NULL;
53     tokenPtr->interp = interp;
54     tokenPtr->tkwin = tkwin;
55     tokenPtr->colorMode = PS_MODE_COLOR;
56     Tcl_DStringInit(&(tokenPtr->dString));
57     return tokenPtr;
58 }
59 
60 void
Blt_ReleasePsToken(tokenPtr)61 Blt_ReleasePsToken(tokenPtr)
62     struct PsTokenStruct *tokenPtr;
63 {
64     Tcl_DStringFree(&(tokenPtr->dString));
65     Blt_Free(tokenPtr);
66 }
67 
68 char *
Blt_PostScriptFromToken(tokenPtr)69 Blt_PostScriptFromToken(tokenPtr)
70     struct PsTokenStruct *tokenPtr;
71 {
72     return Tcl_DStringValue(&(tokenPtr->dString));
73 }
74 
75 char *
Blt_ScratchBufferFromToken(tokenPtr)76 Blt_ScratchBufferFromToken(tokenPtr)
77     struct PsTokenStruct *tokenPtr;
78 {
79     return tokenPtr->scratchArr;
80 }
81 
82 void
83 Blt_AppendToPostScript
TCL_VARARGS_DEF(PsToken,arg1)84 TCL_VARARGS_DEF(PsToken, arg1)
85 {
86     va_list argList;
87     struct PsTokenStruct *tokenPtr;
88     char *string;
89 
90     tokenPtr = TCL_VARARGS_START(struct PsTokenStruct, arg1, argList);
91     for (;;) {
92 	string = va_arg(argList, char *);
93 	if (string == NULL) {
94 	    break;
95 	}
96 	Tcl_DStringAppend(&(tokenPtr->dString), string, -1);
97     }
98 }
99 
100 void
101 Blt_FormatToPostScript
TCL_VARARGS_DEF(PsToken,arg1)102 TCL_VARARGS_DEF(PsToken, arg1)
103 {
104     va_list argList;
105     struct PsTokenStruct *tokenPtr;
106     char *fmt;
107 
108     tokenPtr = TCL_VARARGS_START(struct PsTokenStruct, arg1, argList);
109     fmt = va_arg(argList, char *);
110     vsprintf(tokenPtr->scratchArr, fmt, argList);
111     va_end(argList);
112     Tcl_DStringAppend(&(tokenPtr->dString), tokenPtr->scratchArr, -1);
113 }
114 
115 int
Blt_FileToPostScript(tokenPtr,fileName)116 Blt_FileToPostScript(tokenPtr, fileName)
117     struct PsTokenStruct *tokenPtr;
118     char *fileName;
119 {
120     Tcl_Channel channel;
121     Tcl_DString dString;
122     Tcl_Interp *interp;
123     char *buf;
124     char *libDir;
125     int nBytes;
126 
127     interp = tokenPtr->interp;
128     buf = tokenPtr->scratchArr;
129 
130     /*
131      * Read in a standard prolog file from file and append it to the
132      * PostScript output stored in the Tcl_DString in tokenPtr.
133      */
134 
135     libDir = (char *)Tcl_GetVar(interp, "blt_library", TCL_GLOBAL_ONLY);
136     if (libDir == NULL) {
137 	Tcl_AppendResult(interp, "couldn't find BLT script library:",
138 	    "global variable \"blt_library\" doesn't exist", (char *)NULL);
139 	return TCL_ERROR;
140     }
141     Tcl_DStringInit(&dString);
142     Tcl_DStringAppend(&dString, libDir, -1);
143     Tcl_DStringAppend(&dString, "/", -1);
144     Tcl_DStringAppend(&dString, fileName, -1);
145     fileName = Tcl_DStringValue(&dString);
146     Blt_AppendToPostScript(tokenPtr, "\n% including file \"", fileName,
147 	"\"\n\n", (char *)NULL);
148     channel = Tcl_OpenFileChannel(interp, fileName, "r", 0);
149     if (channel == NULL) {
150 	Tcl_AppendResult(interp, "couldn't open prologue file \"", fileName,
151 		 "\": ", Tcl_PosixError(interp), (char *)NULL);
152 	return TCL_ERROR;
153     }
154     for(;;) {
155 	nBytes = Tcl_Read(channel, buf, PSTOKEN_BUFSIZ);
156 	if (nBytes < 0) {
157 	    Tcl_AppendResult(interp, "error reading prologue file \"",
158 		     fileName, "\": ", Tcl_PosixError(interp),
159 		     (char *)NULL);
160 	    Tcl_Close(interp, channel);
161 	    Tcl_DStringFree(&dString);
162 	    return TCL_ERROR;
163 	}
164 	if (nBytes == 0) {
165 	    break;
166 	}
167 	buf[nBytes] = '\0';
168 	Blt_AppendToPostScript(tokenPtr, buf, (char *)NULL);
169     }
170     Tcl_DStringFree(&dString);
171     Tcl_Close(interp, channel);
172     return TCL_OK;
173 }
174 /*
175  *----------------------------------------------------------------------
176  *
177  * XColorToPostScript --
178  *
179  *	Convert the a XColor (from its RGB values) to a PostScript
180  *	command.  If a Tk color map variable exists, it will be
181  *	consulted for a PostScript translation based upon the color
182  *	name.
183  *
184  *	Maps an X color intensity (0 to 2^16-1) to a floating point
185  *      value [0..1].  Many versions of Tk don't properly handle the
186  *	the lower 8 bits of the color intensity, so we can only
187  *	consider the upper 8 bits.
188  *
189  * Results:
190  *	The string representing the color mode is returned.
191  *
192  *----------------------------------------------------------------------
193  */
194 static void
XColorToPostScript(tokenPtr,colorPtr)195 XColorToPostScript(tokenPtr, colorPtr)
196     struct PsTokenStruct *tokenPtr;
197     XColor *colorPtr;		/* Color value to be converted */
198 {
199     /*
200      * Shift off the lower byte before dividing because some versions
201      * of Tk don't fill the lower byte correctly.
202      */
203     Blt_FormatToPostScript(tokenPtr, "%g %g %g",
204 	((double)(colorPtr->red >> 8) / 255.0),
205 	((double)(colorPtr->green >> 8) / 255.0),
206 	((double)(colorPtr->blue >> 8) / 255.0));
207 }
208 
209 void
Blt_BackgroundToPostScript(tokenPtr,colorPtr)210 Blt_BackgroundToPostScript(tokenPtr, colorPtr)
211     struct PsTokenStruct *tokenPtr;
212     XColor *colorPtr;
213 {
214     /* If the color name exists in Tcl array variable, use that translation */
215     if (tokenPtr->colorVarName != NULL) {
216 	CONST char *psColor;
217 
218 	psColor = Tcl_GetVar2(tokenPtr->interp, tokenPtr->colorVarName,
219 	    Tk_NameOfColor(colorPtr), 0);
220 	if (psColor != NULL) {
221 	    Blt_AppendToPostScript(tokenPtr, " ", psColor, "\n", (char *)NULL);
222 	    return;
223 	}
224     }
225     XColorToPostScript(tokenPtr, colorPtr);
226     Blt_AppendToPostScript(tokenPtr, " SetBgColor\n", (char *)NULL);
227 }
228 
229 void
Blt_ForegroundToPostScript(tokenPtr,colorPtr)230 Blt_ForegroundToPostScript(tokenPtr, colorPtr)
231     struct PsTokenStruct *tokenPtr;
232     XColor *colorPtr;
233 {
234     /* If the color name exists in Tcl array variable, use that translation */
235     if (tokenPtr->colorVarName != NULL) {
236 	CONST char *psColor;
237 
238 	psColor = Tcl_GetVar2(tokenPtr->interp, tokenPtr->colorVarName,
239 	    Tk_NameOfColor(colorPtr), 0);
240 	if (psColor != NULL) {
241 	    Blt_AppendToPostScript(tokenPtr, " ", psColor, "\n", (char *)NULL);
242 	    return;
243 	}
244     }
245     XColorToPostScript(tokenPtr, colorPtr);
246     Blt_AppendToPostScript(tokenPtr, " SetFgColor\n", (char *)NULL);
247 }
248 
249 /*
250  *----------------------------------------------------------------------
251  *
252  * ReverseBits --
253  *
254  *	Convert a byte from a X image into PostScript image order.
255  *	This requires not only the nybbles to be reversed but also
256  *	their bit values.
257  *
258  * Results:
259  *	The converted byte is returned.
260  *
261  *----------------------------------------------------------------------
262  */
263 INLINE static unsigned char
ReverseBits(byte)264 ReverseBits(byte)
265     register unsigned char byte;
266 {
267     byte = ((byte >> 1) & 0x55) | ((byte << 1) & 0xaa);
268     byte = ((byte >> 2) & 0x33) | ((byte << 2) & 0xcc);
269     byte = ((byte >> 4) & 0x0f) | ((byte << 4) & 0xf0);
270     return byte;
271 }
272 
273 /*
274  *----------------------------------------------------------------------
275  *
276  * ByteToHex --
277  *
278  *	Convert a byte to its ASCII hexidecimal equivalent.
279  *
280  * Results:
281  *	The converted 2 ASCII character string is returned.
282  *
283  *----------------------------------------------------------------------
284  */
285 INLINE static void
ByteToHex(byte,string)286 ByteToHex(byte, string)
287     register unsigned char byte;
288     char *string;
289 {
290     static char hexDigits[] = "0123456789ABCDEF";
291 
292     string[0] = hexDigits[byte >> 4];
293     string[1] = hexDigits[byte & 0x0F];
294 }
295 
296 #ifdef WIN32
297 /*
298  * -------------------------------------------------------------------------
299  *
300  * Blt_BitmapDataToPostScript --
301  *
302  *      Output a PostScript image string of the given bitmap image.
303  *      It is assumed the image is one bit deep and a zero value
304  *      indicates an off-pixel.  To convert to PostScript, the bits
305  *      need to be reversed from the X11 image order.
306  *
307  * Results:
308  *      None.
309  *
310  * Side Effects:
311  *      The PostScript image string is appended.
312  *
313  * -------------------------------------------------------------------------
314  */
315 void
Blt_BitmapDataToPostScript(struct PsTokenStruct * tokenPtr,Display * display,Pixmap bitmap,int width,int height)316 Blt_BitmapDataToPostScript(
317     struct PsTokenStruct *tokenPtr,
318     Display *display,
319     Pixmap bitmap,
320     int width, int height)
321 {
322     register unsigned char byte;
323     register int x, y, bitPos;
324     unsigned long pixel;
325     int byteCount;
326     char string[10];
327     unsigned char *srcBits, *srcPtr;
328     int bytesPerRow;
329 
330     srcBits = Blt_GetBitmapData(display, bitmap, width, height, &bytesPerRow);
331     if (srcBits == NULL) {
332         OutputDebugString("Can't get bitmap data");
333 	return;
334     }
335     Blt_AppendToPostScript(tokenPtr, "\t<", (char *)NULL);
336     byteCount = bitPos = 0;	/* Suppress compiler warning */
337     for (y = height - 1; y >= 0; y--) {
338 	srcPtr = srcBits + (bytesPerRow * y);
339 	byte = 0;
340 	for (x = 0; x < width; x++) {
341 	    bitPos = x % 8;
342 	    pixel = (*srcPtr & (0x80 >> bitPos));
343 	    if (pixel) {
344 		byte |= (unsigned char)(1 << bitPos);
345 	    }
346 	    if (bitPos == 7) {
347 		byte = ReverseBits(byte);
348 		ByteToHex(byte, string);
349 		string[2] = '\0';
350 		byteCount++;
351 		srcPtr++;
352 		byte = 0;
353 		if (byteCount >= 30) {
354 		    string[2] = '\n';
355 		    string[3] = '\t';
356 		    string[4] = '\0';
357 		    byteCount = 0;
358 		}
359 		Blt_AppendToPostScript(tokenPtr, string, (char *)NULL);
360 	    }
361 	}			/* x */
362 	if (bitPos != 7) {
363 	    byte = ReverseBits(byte);
364 	    ByteToHex(byte, string);
365 	    string[2] = '\0';
366 	    Blt_AppendToPostScript(tokenPtr, string, (char *)NULL);
367 	    byteCount++;
368 	}
369     }				/* y */
370     Blt_Free(srcBits);
371     Blt_AppendToPostScript(tokenPtr, ">\n", (char *)NULL);
372 }
373 
374 #else
375 
376 /*
377  * -------------------------------------------------------------------------
378  *
379  * Blt_BitmapDataToPostScript --
380  *
381  *      Output a PostScript image string of the given bitmap image.
382  *      It is assumed the image is one bit deep and a zero value
383  *      indicates an off-pixel.  To convert to PostScript, the bits
384  *      need to be reversed from the X11 image order.
385  *
386  * Results:
387  *      None.
388  *
389  * Side Effects:
390  *      The PostScript image string is appended to interp->result.
391  *
392  * -------------------------------------------------------------------------
393  */
394 void
Blt_BitmapDataToPostScript(tokenPtr,display,bitmap,width,height)395 Blt_BitmapDataToPostScript(tokenPtr, display, bitmap, width, height)
396     struct PsTokenStruct *tokenPtr;
397     Display *display;
398     Pixmap bitmap;
399     int width, height;
400 {
401     register unsigned char byte = 0;
402     register int x, y, bitPos;
403     unsigned long pixel;
404     XImage *imagePtr;
405     int byteCount;
406     char string[10];
407 
408     imagePtr = XGetImage(display, bitmap, 0, 0, width, height, 1, ZPixmap);
409     Blt_AppendToPostScript(tokenPtr, "\t<", (char *)NULL);
410     byteCount = bitPos = 0;	/* Suppress compiler warning */
411     for (y = 0; y < height; y++) {
412 	byte = 0;
413 	for (x = 0; x < width; x++) {
414 	    pixel = XGetPixel(imagePtr, x, y);
415 	    bitPos = x % 8;
416 	    byte |= (unsigned char)(pixel << bitPos);
417 	    if (bitPos == 7) {
418 		byte = ReverseBits(byte);
419 		ByteToHex(byte, string);
420 		string[2] = '\0';
421 		byteCount++;
422 		byte = 0;
423 		if (byteCount >= 30) {
424 		    string[2] = '\n';
425 		    string[3] = '\t';
426 		    string[4] = '\0';
427 		    byteCount = 0;
428 		}
429 		Blt_AppendToPostScript(tokenPtr, string, (char *)NULL);
430 	    }
431 	}			/* x */
432 	if (bitPos != 7) {
433 	    byte = ReverseBits(byte);
434 	    ByteToHex(byte, string);
435 	    string[2] = '\0';
436 	    Blt_AppendToPostScript(tokenPtr, string, (char *)NULL);
437 	    byteCount++;
438 	}
439     }				/* y */
440     Blt_AppendToPostScript(tokenPtr, ">\n", (char *)NULL);
441     XDestroyImage(imagePtr);
442 }
443 
444 #endif /* WIN32 */
445 
446 /*
447  *----------------------------------------------------------------------
448  *
449  * Blt_ColorImageToPsData --
450  *
451  *	Converts a color image to PostScript RGB (3 components)
452  *	or Greyscale (1 component) output.  With 3 components, we
453  *	assume the "colorimage" operator is available.
454  *
455  *	Note that the image converted from bottom to top, to conform
456  *	to the PostScript coordinate system.
457  *
458  * Results:
459  *	The PostScript data comprising the color image is written
460  *	into the dynamic string.
461  *
462  *----------------------------------------------------------------------
463  */
464 int
Blt_ColorImageToPsData(image,nComponents,resultPtr,prefix)465 Blt_ColorImageToPsData(image, nComponents, resultPtr, prefix)
466     Blt_ColorImage image;
467     int nComponents;
468     Tcl_DString *resultPtr;
469     char *prefix;
470 {
471     char string[10];
472     register int count;
473     register int x, y;
474     register Pix32 *pixelPtr;
475     unsigned char byte;
476     int width, height;
477     int offset;
478     int nLines;
479     width = Blt_ColorImageWidth(image);
480     height = Blt_ColorImageHeight(image);
481 
482     nLines = 0;
483     count = 0;
484     offset = (height - 1) * width;
485     if (nComponents == 3) {
486 	for (y = (height - 1); y >= 0; y--) {
487 	    pixelPtr = Blt_ColorImageBits(image) + offset;
488 	    for (x = 0; x < width; x++, pixelPtr++) {
489 		if (count == 0) {
490 		    Tcl_DStringAppend(resultPtr, prefix, -1);
491 		    Tcl_DStringAppend(resultPtr, " ", -1);
492 		}
493 		count += 6;
494 		ByteToHex(pixelPtr->Red, string);
495 		ByteToHex(pixelPtr->Green, string + 2);
496 		ByteToHex(pixelPtr->Blue, string + 4);
497 		string[6] = '\0';
498 		if (count >= 60) {
499 		    string[6] = '\n';
500 		    string[7] = '\0';
501 		    count = 0;
502 		    nLines++;
503 		}
504 		Tcl_DStringAppend(resultPtr, string, -1);
505 	    }
506 	    offset -= width;
507 	}
508     } else if (nComponents == 1) {
509 	for (y = (height - 1); y >= 0; y--) {
510 	    pixelPtr = Blt_ColorImageBits(image) + offset;
511 	    for (x = 0; x < width; x++, pixelPtr++) {
512 		if (count == 0) {
513 		    Tcl_DStringAppend(resultPtr, prefix, -1);
514 		    Tcl_DStringAppend(resultPtr, " ", -1);
515 		}
516 		count += 2;
517 		byte = ~(pixelPtr->Red);
518 		ByteToHex(byte, string);
519 		string[2] = '\0';
520 		if (count >= 60) {
521 		    string[2] = '\n';
522 		    string[3] = '\0';
523 		    count = 0;
524 		    nLines++;
525 		}
526 		Tcl_DStringAppend(resultPtr, string, -1);
527 	    }
528 	    offset -= width;
529 	}
530     }
531     if (count != 0) {
532 	Tcl_DStringAppend(resultPtr, "\n", -1);
533 	nLines++;
534     }
535     return nLines;
536 }
537 
538 /*
539  *----------------------------------------------------------------------
540  *
541  * NameOfAtom --
542  *
543  *	Wrapper routine for Tk_GetAtomName.  Returns NULL instead of
544  *	"?bad atom?" if the atom can't be found.
545  *
546  * Results:
547  *	The name of the atom is returned if found. Otherwise NULL.
548  *
549  *----------------------------------------------------------------------
550  */
551 static char *
NameOfAtom(tkwin,atom)552 NameOfAtom(tkwin, atom)
553     Tk_Window tkwin;
554     Atom atom;
555 {
556     char *result;
557 
558     result = Tk_GetAtomName(tkwin, atom);
559     if ((result[0] == '?') && (strcmp(result, "?bad atom?") == 0)) {
560 	return NULL;
561     }
562     return result;
563 }
564 
565 
566 typedef struct {
567     char *alias;
568     char *fontName;
569 } FontMap;
570 
571 static FontMap psFontMap[] =
572 {
573     {"Arial", "Helvetica",},
574     {"AvantGarde", "AvantGarde",},
575     {"Courier New", "Courier",},
576     {"Courier", "Courier",},
577     {"Geneva", "Helvetica",},
578     {"Helvetica", "Helvetica",},
579     {"Monaco", "Courier",},
580     {"New Century Schoolbook", "NewCenturySchlbk",},
581     {"New York", "Times",},
582     {"Palatino", "Palatino",},
583     {"Symbol", "Symbol",},
584     {"Times New Roman", "Times",},
585     {"Times Roman", "Times",},
586     {"Times", "Times",},
587     {"Utopia", "Utopia",},
588     {"ZapfChancery", "ZapfChancery",},
589     {"ZapfDingbats", "ZapfDingbats",},
590 };
591 
592 static int nFontNames = (sizeof(psFontMap) / sizeof(FontMap));
593 
594 #ifndef  WIN32
595 /*
596  * -----------------------------------------------------------------
597  *
598  * XFontStructToPostScript --
599  *
600  *      Map X11 font to a PostScript font. Currently, only fonts whose
601  *      FOUNDRY property are "Adobe" are converted. Simply gets the
602  *      XA_FULL_NAME and XA_FAMILY properties and pieces together a
603  *      PostScript fontname.
604  *
605  * Results:
606  *      Returns the mapped PostScript font name if one is possible.
607  *	Otherwise returns NULL.
608  *
609  * -----------------------------------------------------------------
610  */
611 static char *
XFontStructToPostScript(tkwin,fontPtr)612 XFontStructToPostScript(tkwin, fontPtr)
613     Tk_Window tkwin;		/* Window to query for atoms */
614     XFontStruct *fontPtr;	/* Font structure to map to name */
615 {
616     Atom atom;
617     char *fullName, *family, *foundry;
618     register char *src, *dest;
619     int familyLen;
620     char *start;
621     static char string[200];	/* What size? */
622 
623     if (XGetFontProperty(fontPtr, XA_FULL_NAME, &atom) == False) {
624 	return NULL;
625     }
626     fullName = NameOfAtom(tkwin, atom);
627     if (fullName == NULL) {
628 	return NULL;
629     }
630     family = foundry = NULL;
631     if (XGetFontProperty(fontPtr, Tk_InternAtom(tkwin, "FOUNDRY"), &atom)) {
632 	foundry = NameOfAtom(tkwin, atom);
633     }
634     if (XGetFontProperty(fontPtr, XA_FAMILY_NAME, &atom)) {
635 	family = NameOfAtom(tkwin, atom);
636     }
637     /*
638      * Try to map the font only if the foundry is Adobe
639      */
640     if ((foundry == NULL) || (family == NULL)) {
641 	return NULL;
642     }
643     src = NULL;
644     familyLen = strlen(family);
645     if (strncasecmp(fullName, family, familyLen) == 0) {
646 	src = fullName + familyLen;
647     }
648     if (strcmp(foundry, "Adobe") != 0) {
649 	register int i;
650 
651 	if (strncasecmp(family, "itc ", 4) == 0) {
652 	    family += 4;	/* Throw out the "itc" prefix */
653 	}
654 	for (i = 0; i < nFontNames; i++) {
655 	    if (strcasecmp(family, psFontMap[i].alias) == 0) {
656 		family = psFontMap[i].fontName;
657 	    }
658 	}
659 	if (i == nFontNames) {
660 	    family = "Helvetica";	/* Default to a known font */
661 	}
662     }
663     /*
664      * PostScript font name is in the form <family>-<type face>
665      */
666     sprintf(string, "%s-", family);
667     dest = start = string + strlen(string);
668 
669     /*
670      * Append the type face (part of the full name trailing the family name)
671      * to the the PostScript font name, removing any spaces or dashes
672      *
673      * ex. " Bold Italic" ==> "BoldItalic"
674      */
675     if (src != NULL) {
676 	while (*src != '\0') {
677 	    if ((*src != ' ') && (*src != '-')) {
678 		*dest++ = *src;
679 	    }
680 	    src++;
681 	}
682     }
683     if (dest == start) {
684 	--dest;			/* Remove '-' to leave just the family name */
685     }
686     *dest = '\0';		/* Make a valid string */
687     return string;
688 }
689 
690 #endif /* !WIN32 */
691 
692 
693 /*
694  * -------------------------------------------------------------------
695  * Routines to convert X drawing functions to PostScript commands.
696  * -------------------------------------------------------------------
697  */
698 void
Blt_ClearBackgroundToPostScript(tokenPtr)699 Blt_ClearBackgroundToPostScript(tokenPtr)
700     struct PsTokenStruct *tokenPtr;
701 {
702     Blt_AppendToPostScript(tokenPtr,
703 	" 1.0 1.0 1.0 SetBgColor\n",
704 	(char *)NULL);
705 }
706 
707 void
Blt_CapStyleToPostScript(tokenPtr,capStyle)708 Blt_CapStyleToPostScript(tokenPtr, capStyle)
709     struct PsTokenStruct *tokenPtr;
710     int capStyle;
711 {
712     /*
713      * X11:not last = 0, butt = 1, round = 2, projecting = 3
714      * PS: butt = 0, round = 1, projecting = 2
715      */
716     if (capStyle > 0) {
717 	capStyle--;
718     }
719     Blt_FormatToPostScript(tokenPtr,
720 	"%d setlinecap\n",
721 	capStyle);
722 }
723 
724 void
Blt_JoinStyleToPostScript(tokenPtr,joinStyle)725 Blt_JoinStyleToPostScript(tokenPtr, joinStyle)
726     struct PsTokenStruct *tokenPtr;
727     int joinStyle;
728 {
729     /*
730      * miter = 0, round = 1, bevel = 2
731      */
732     Blt_FormatToPostScript(tokenPtr,
733 	"%d setlinejoin\n",
734 	joinStyle);
735 }
736 
737 void
Blt_LineWidthToPostScript(tokenPtr,lineWidth)738 Blt_LineWidthToPostScript(tokenPtr, lineWidth)
739     struct PsTokenStruct *tokenPtr;
740     int lineWidth;
741 {
742     if (lineWidth < 1) {
743 	lineWidth = 1;
744     }
745     Blt_FormatToPostScript(tokenPtr,
746 	"%d setlinewidth\n",
747 	lineWidth);
748 }
749 
750 void
Blt_LineDashesToPostScript(tokenPtr,dashesPtr)751 Blt_LineDashesToPostScript(tokenPtr, dashesPtr)
752     struct PsTokenStruct *tokenPtr;
753     Blt_Dashes *dashesPtr;
754 {
755 
756     Blt_AppendToPostScript(tokenPtr, "[ ", (char *)NULL);
757     if (dashesPtr != NULL) {
758 	unsigned char *p;
759 
760 	for (p = dashesPtr->values; *p != 0; p++) {
761 	    Blt_FormatToPostScript(tokenPtr, " %d", *p);
762 	}
763     }
764     Blt_AppendToPostScript(tokenPtr, "] 0 setdash\n", (char *)NULL);
765 }
766 
767 void
Blt_LineAttributesToPostScript(tokenPtr,colorPtr,lineWidth,dashesPtr,capStyle,joinStyle)768 Blt_LineAttributesToPostScript(tokenPtr, colorPtr, lineWidth, dashesPtr,
769     capStyle, joinStyle)
770     struct PsTokenStruct *tokenPtr;
771     XColor *colorPtr;
772     int lineWidth;
773     Blt_Dashes *dashesPtr;
774     int capStyle, joinStyle;
775 {
776     Blt_JoinStyleToPostScript(tokenPtr, joinStyle);
777     Blt_CapStyleToPostScript(tokenPtr, capStyle);
778     Blt_ForegroundToPostScript(tokenPtr, colorPtr);
779     Blt_LineWidthToPostScript(tokenPtr, lineWidth);
780     Blt_LineDashesToPostScript(tokenPtr, dashesPtr);
781     Blt_AppendToPostScript(tokenPtr, "/DashesProc {} def\n", (char *)NULL);
782 }
783 
784 void
Blt_RectangleToPostScript(tokenPtr,x,y,width,height)785 Blt_RectangleToPostScript(tokenPtr, x, y, width, height)
786     struct PsTokenStruct *tokenPtr;
787     double x, y;
788     int width, height;
789 {
790     Blt_FormatToPostScript(tokenPtr,
791 	"%g %g %d %d Box fill\n\n",
792 	x, y, width, height);
793 }
794 
795 void
Blt_RegionToPostScript(tokenPtr,x,y,width,height)796 Blt_RegionToPostScript(tokenPtr, x, y, width, height)
797     struct PsTokenStruct *tokenPtr;
798     double x, y;
799     int width, height;
800 {
801     Blt_FormatToPostScript(tokenPtr, "%g %g %d %d Box\n\n",
802 			   x, y, width, height);
803 }
804 
805 void
Blt_PathToPostScript(tokenPtr,screenPts,nScreenPts)806 Blt_PathToPostScript(tokenPtr, screenPts, nScreenPts)
807     struct PsTokenStruct *tokenPtr;
808     register Point2D *screenPts;
809     int nScreenPts;
810 {
811     register Point2D *pointPtr, *endPtr;
812 
813     if (nScreenPts == 0 ||!screenPts) return;
814     pointPtr = screenPts;
815     Blt_FormatToPostScript(tokenPtr, "newpath %g %g moveto\n",
816 	pointPtr->x, pointPtr->y);
817     pointPtr++;
818     endPtr = screenPts + nScreenPts;
819     while (pointPtr < endPtr) {
820 	Blt_FormatToPostScript(tokenPtr, "%g %g lineto\n",
821 		pointPtr->x, pointPtr->y);
822 	pointPtr++;
823     }
824 }
825 
826 void
Blt_PolygonToPostScript(tokenPtr,screenPts,nScreenPts)827 Blt_PolygonToPostScript(tokenPtr, screenPts, nScreenPts)
828     struct PsTokenStruct *tokenPtr;
829     Point2D *screenPts;
830     int nScreenPts;
831 {
832     if (nScreenPts == 0 ||!screenPts) return;
833     Blt_PathToPostScript(tokenPtr, screenPts, nScreenPts);
834     Blt_FormatToPostScript(tokenPtr, "%g %g ", screenPts[0].x, screenPts[0].y);
835     Blt_AppendToPostScript(tokenPtr, " lineto closepath Fill\n", (char *)NULL);
836 }
837 
838 void
Blt_SegmentsToPostScript(tokenPtr,segPtr,nSegments)839 Blt_SegmentsToPostScript(tokenPtr, segPtr, nSegments)
840     struct PsTokenStruct *tokenPtr;
841     register XSegment *segPtr;
842     int nSegments;
843 {
844     register int i;
845 
846     for (i = 0; i < nSegments; i++, segPtr++) {
847 	Blt_FormatToPostScript(tokenPtr, "%d %d moveto\n",
848 			       segPtr->x1, segPtr->y1);
849 	Blt_FormatToPostScript(tokenPtr, " %d %d lineto\n",
850 			       segPtr->x2, segPtr->y2);
851 	Blt_AppendToPostScript(tokenPtr, "DashesProc stroke\n", (char *)NULL);
852     }
853 }
854 
855 
856 void
Blt_RectanglesToPostScript(tokenPtr,rectArr,nRects)857 Blt_RectanglesToPostScript(tokenPtr, rectArr, nRects)
858     struct PsTokenStruct *tokenPtr;
859     XRectangle rectArr[];
860     int nRects;
861 {
862     register int i;
863 
864     for (i = 0; i < nRects; i++) {
865 	Blt_RectangleToPostScript(tokenPtr,
866 		  (double)rectArr[i].x, (double)rectArr[i].y,
867 		  (int)rectArr[i].width, (int)rectArr[i].height);
868     }
869 }
870 
871 #ifndef TK_RELIEF_SOLID
872 #define TK_RELIEF_SOLID		-1	/* Set the an impossible value. */
873 #endif /* TK_RELIEF_SOLID */
874 
875 void
Blt_Draw3DRectangleToPostScript(tokenPtr,border,x,y,width,height,borderWidth,relief)876 Blt_Draw3DRectangleToPostScript(tokenPtr, border, x, y, width, height,
877     borderWidth, relief)
878     struct PsTokenStruct *tokenPtr;
879     Tk_3DBorder border;		/* Token for border to draw. */
880     double x, y;		/* Coordinates of rectangle */
881     int width, height;		/* Region to be drawn. */
882     int borderWidth;		/* Desired width for border, in pixels. */
883     int relief;			/* Should be either TK_RELIEF_RAISED or
884                                  * TK_RELIEF_SUNKEN;  indicates position of
885                                  * interior of window relative to exterior. */
886 {
887     TkBorder *borderPtr = (TkBorder *) border;
888     XColor lightColor, darkColor;
889     XColor *lightColorPtr, *darkColorPtr;
890     XColor *topColor, *bottomColor;
891     Point2D points[7];
892     int twiceWidth = (borderWidth * 2);
893 
894     if ((width < twiceWidth) || (height < twiceWidth)) {
895 	return;
896     }
897     if ((relief == TK_RELIEF_SOLID) ||
898 	(borderPtr->lightColorPtr == NULL) || (borderPtr->darkColorPtr == NULL)) {
899 	if (relief == TK_RELIEF_SOLID) {
900 	    darkColor.red = darkColor.blue = darkColor.green = 0x00;
901 	    lightColor.red = lightColor.blue = lightColor.green = 0x00;
902 	    relief = TK_RELIEF_SUNKEN;
903 	} else {
904 	    Screen *screenPtr;
905 
906 	    lightColor = *borderPtr->bgColorPtr;
907 	    screenPtr = Tk_Screen(tokenPtr->tkwin);
908 	    if (lightColor.pixel == WhitePixelOfScreen(screenPtr)) {
909 		darkColor.red = darkColor.blue = darkColor.green = 0x00;
910 	    } else {
911 		darkColor.red = darkColor.blue = darkColor.green = 0xFF;
912 	    }
913 	}
914 	lightColorPtr = &lightColor;
915 	darkColorPtr = &darkColor;
916     } else {
917 	lightColorPtr = borderPtr->lightColorPtr;
918 	darkColorPtr = borderPtr->darkColorPtr;
919     }
920 
921 
922     /*
923      * Handle grooves and ridges with recursive calls.
924      */
925 
926     if ((relief == TK_RELIEF_GROOVE) || (relief == TK_RELIEF_RIDGE)) {
927 	int halfWidth, insideOffset;
928 
929 	halfWidth = borderWidth / 2;
930 	insideOffset = borderWidth - halfWidth;
931 	Blt_Draw3DRectangleToPostScript(tokenPtr, border, (double)x, (double)y,
932 	    width, height, halfWidth,
933 	    (relief == TK_RELIEF_GROOVE) ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED);
934 	Blt_Draw3DRectangleToPostScript(tokenPtr, border,
935   	    (double)(x + insideOffset), (double)(y + insideOffset),
936 	    width - insideOffset * 2, height - insideOffset * 2, halfWidth,
937 	    (relief == TK_RELIEF_GROOVE) ? TK_RELIEF_RAISED : TK_RELIEF_SUNKEN);
938 	return;
939     }
940     if (relief == TK_RELIEF_RAISED) {
941 	topColor = lightColorPtr;
942 	bottomColor = darkColorPtr;
943     } else if (relief == TK_RELIEF_SUNKEN) {
944 	topColor = darkColorPtr;
945 	bottomColor = lightColorPtr;
946     } else {
947 	topColor = bottomColor = borderPtr->bgColorPtr;
948     }
949     Blt_BackgroundToPostScript(tokenPtr, bottomColor);
950     Blt_RectangleToPostScript(tokenPtr, x, y + height - borderWidth, width,
951 	borderWidth);
952     Blt_RectangleToPostScript(tokenPtr, x + width - borderWidth, y,
953 	borderWidth, height);
954     points[0].x = points[1].x = points[6].x = x;
955     points[0].y = points[6].y = y + height;
956     points[1].y = points[2].y = y;
957     points[2].x = x + width;
958     points[3].x = x + width - borderWidth;
959     points[3].y = points[4].y = y + borderWidth;
960     points[4].x = points[5].x = x + borderWidth;
961     points[5].y = y + height - borderWidth;
962     if (relief != TK_RELIEF_FLAT) {
963 	Blt_BackgroundToPostScript(tokenPtr, topColor);
964     }
965     Blt_PolygonToPostScript(tokenPtr, points, 7);
966 }
967 
968 void
Blt_Fill3DRectangleToPostScript(tokenPtr,border,x,y,width,height,borderWidth,relief)969 Blt_Fill3DRectangleToPostScript(tokenPtr, border, x, y, width, height,
970     borderWidth, relief)
971     struct PsTokenStruct *tokenPtr;
972     Tk_3DBorder border;		/* Token for border to draw. */
973     double x, y;		/* Coordinates of top-left of border area */
974     int width, height;		/* Dimension of border to be drawn. */
975     int borderWidth;		/* Desired width for border, in pixels. */
976     int relief;			/* Should be either TK_RELIEF_RAISED or
977                                  * TK_RELIEF_SUNKEN;  indicates position of
978                                  * interior of window relative to exterior. */
979 {
980     TkBorder *borderPtr = (TkBorder *) border;
981 
982     /*
983      * I'm assuming that the rectangle is to be drawn as a background.
984      * Setting the pen color as foreground or background only affects
985      * the plot when the colormode option is "monochrome".
986      */
987     Blt_BackgroundToPostScript(tokenPtr, borderPtr->bgColorPtr);
988     Blt_RectangleToPostScript(tokenPtr, x, y, width, height);
989     Blt_Draw3DRectangleToPostScript(tokenPtr, border, x, y, width, height,
990 	borderWidth, relief);
991 }
992 
993 void
Blt_StippleToPostScript(tokenPtr,display,bitmap)994 Blt_StippleToPostScript(tokenPtr, display, bitmap)
995     struct PsTokenStruct *tokenPtr;
996     Display *display;
997     Pixmap bitmap;
998 {
999     int width, height;
1000 
1001     Tk_SizeOfBitmap(display, bitmap, &width, &height);
1002     Blt_FormatToPostScript(tokenPtr,
1003 	"gsave\n  clip\n  %d %d\n",
1004 	width, height);
1005     Blt_BitmapDataToPostScript(tokenPtr, display, bitmap, width, height);
1006     Blt_AppendToPostScript(tokenPtr,
1007 	"  StippleFill\ngrestore\n",
1008 	(char *)NULL);
1009 }
1010 
1011 /*
1012  *----------------------------------------------------------------------
1013  *
1014  * Blt_ColorImageToPostScript --
1015  *
1016  *      Translates a color image into 3 component RGB PostScript output.
1017  *	Uses PS Language Level 2 operator "colorimage".
1018  *
1019  * Results:
1020  *      The dynamic string will contain the PostScript output.
1021  *
1022  *----------------------------------------------------------------------
1023  */
1024 void
Blt_ColorImageToPostScript(tokenPtr,image,x,y)1025 Blt_ColorImageToPostScript(tokenPtr, image, x, y)
1026     struct PsTokenStruct *tokenPtr;
1027     Blt_ColorImage image;
1028     double x, y;
1029 {
1030     int width, height;
1031     int tmpSize;
1032 
1033     width = Blt_ColorImageWidth(image);
1034     height = Blt_ColorImageHeight(image);
1035 
1036     tmpSize = width;
1037     if (tokenPtr->colorMode == PS_MODE_COLOR) {
1038 	tmpSize *= 3;
1039     }
1040     Blt_FormatToPostScript(tokenPtr, "\n/tmpStr %d string def\n", tmpSize);
1041     Blt_AppendToPostScript(tokenPtr, "gsave\n", (char *)NULL);
1042     Blt_FormatToPostScript(tokenPtr, "  %g %g translate\n", x, y);
1043     Blt_FormatToPostScript(tokenPtr, "  %d %d scale\n", width, height);
1044     Blt_FormatToPostScript(tokenPtr, "  %d %d 8\n", width, height);
1045     Blt_FormatToPostScript(tokenPtr, "  [%d 0 0 %d 0 %d] ", width, -height,
1046 	height);
1047     Blt_AppendToPostScript(tokenPtr,
1048 	"{\n    currentfile tmpStr readhexstring pop\n  } ",
1049 	(char *)NULL);
1050     if (tokenPtr->colorMode != PS_MODE_COLOR) {
1051 	Blt_AppendToPostScript(tokenPtr, "image\n", (char *)NULL);
1052 	Blt_ColorImageToGreyscale(image);
1053 	Blt_ColorImageToPsData(image, 1, &(tokenPtr->dString), " ");
1054     } else {
1055 	Blt_AppendToPostScript(tokenPtr,
1056 		"false 3 colorimage\n",
1057 		(char *)NULL);
1058 	Blt_ColorImageToPsData(image, 3, &(tokenPtr->dString), " ");
1059     }
1060     Blt_AppendToPostScript(tokenPtr,
1061 	"\ngrestore\n\n",
1062 	(char *)NULL);
1063 }
1064 
1065 /*
1066  *----------------------------------------------------------------------
1067  *
1068  * Blt_WindowToPostScript --
1069  *
1070  *      Converts a Tk window to PostScript.  If the window could not
1071  *	be "snapped", then a grey rectangle is drawn in its place.
1072  *
1073  * Results:
1074  *      None.
1075  *
1076  *----------------------------------------------------------------------
1077  */
1078 void
Blt_WindowToPostScript(tokenPtr,tkwin,x,y)1079 Blt_WindowToPostScript(tokenPtr, tkwin, x, y)
1080     struct PsTokenStruct *tokenPtr;
1081     Tk_Window tkwin;
1082     double x, y;
1083 {
1084     Blt_ColorImage image;
1085     int width, height;
1086 
1087     width = Tk_Width(tkwin);
1088     height = Tk_Height(tkwin);
1089     image = Blt_DrawableToColorImage(tkwin, Tk_WindowId(tkwin), 0, 0, width,
1090 	height, GAMMA);
1091     if (image == NULL) {
1092 	/* Can't grab window image so paint the window area grey */
1093 	Blt_AppendToPostScript(tokenPtr, "% Can't grab window \"",
1094 	    Tk_PathName(tkwin), "\"\n", (char *)NULL);
1095 	Blt_AppendToPostScript(tokenPtr, "0.5 0.5 0.5 SetBgColor\n",
1096 	    (char *)NULL);
1097 	Blt_RectangleToPostScript(tokenPtr, x, y, width, height);
1098 	return;
1099     }
1100     Blt_ColorImageToPostScript(tokenPtr, image, x, y);
1101     Blt_FreeColorImage(image);
1102 }
1103 
1104 /*
1105  * -------------------------------------------------------------------------
1106  *
1107  * Blt_PhotoToPostScript --
1108  *
1109  *      Output a PostScript image string of the given photo image.
1110  *	The photo is first converted into a color image and then
1111  *	translated into PostScript.
1112  *
1113  * Results:
1114  *      None.
1115  *
1116  * Side Effects:
1117  *      The PostScript output representing the photo is appended to
1118  *	the tokenPtr's dynamic string.
1119  *
1120  * -------------------------------------------------------------------------
1121  */
1122 void
Blt_PhotoToPostScript(tokenPtr,photo,x,y)1123 Blt_PhotoToPostScript(tokenPtr, photo, x, y)
1124     struct PsTokenStruct *tokenPtr;
1125     Tk_PhotoHandle photo;
1126     double x, y;		/* Origin of photo image */
1127 {
1128     Blt_ColorImage image;
1129 
1130     image = Blt_PhotoToColorImage(photo);
1131     Blt_ColorImageToPostScript(tokenPtr, image, x, y);
1132     Blt_FreeColorImage(image);
1133 }
1134 
1135 /*
1136  * -----------------------------------------------------------------
1137  *
1138  * Blt_FontToPostScript --
1139  *
1140  *      Map the Tk font to a PostScript font and point size.
1141  *
1142  *	If a Tcl array variable was specified, each element should be
1143  *	indexed by the X11 font name and contain a list of 1-2
1144  *	elements; the PostScript font name and the desired point size.
1145  *	The point size may be omitted and the X font point size will
1146  *	be used.
1147  *
1148  *	Otherwise, if the foundry is "Adobe", we try to do a plausible
1149  *	mapping looking at the full name of the font and building a
1150  *	string in the form of "Family-TypeFace".
1151  *
1152  * Returns:
1153  *      None.
1154  *
1155  * Side Effects:
1156  *      PostScript commands are output to change the type and the
1157  *      point size of the current font.
1158  *
1159  * -----------------------------------------------------------------
1160  */
1161 
1162 void
Blt_FontToPostScript(tokenPtr,font)1163 Blt_FontToPostScript(tokenPtr, font)
1164     struct PsTokenStruct *tokenPtr;
1165     Tk_Font font;		/* Tk font to query about */
1166 {
1167     XFontStruct *fontPtr = (XFontStruct *)font;
1168     Tcl_Interp *interp = tokenPtr->interp;
1169     char *fontName;
1170     double pointSize;
1171 #if (TK_MAJOR_VERSION > 4)
1172     Tk_Uid family;
1173     register int i;
1174 #endif /* TK_MAJOR_VERSION > 4 */
1175 
1176     fontName = Tk_NameOfFont(font);
1177     pointSize = 12.0;
1178     /*
1179      * Use the font variable information if it exists.
1180      */
1181     if (tokenPtr->fontVarName != NULL) {
1182 	char *fontInfo;
1183 
1184 	fontInfo = (char *)Tcl_GetVar2(interp, tokenPtr->fontVarName, fontName,
1185 	       0);
1186 	if (fontInfo != NULL) {
1187 	    int nProps;
1188 	    char **propArr = NULL;
1189 
1190 	    if (Tcl_SplitList(interp, fontInfo, &nProps, &propArr) == TCL_OK) {
1191 		int newSize;
1192 
1193 		fontName = propArr[0];
1194 		if ((nProps == 2) &&
1195 		    (Tcl_GetInt(interp, propArr[1], &newSize) == TCL_OK)) {
1196 		    pointSize = (double)newSize;
1197 		}
1198 	    }
1199 	    Blt_FormatToPostScript(tokenPtr,
1200 				   "%g /%s SetFont\n",
1201 				   pointSize, fontName);
1202 	    if (propArr != (char **)NULL) {
1203 		Blt_Free(propArr);
1204 	    }
1205 	    return;
1206 	}
1207     }
1208 #if (TK_MAJOR_VERSION > 4)
1209 
1210     /*
1211      * Otherwise do a quick test to see if it's a PostScript font.
1212      * Tk_PostScriptFontName will silently generate a bogus PostScript
1213      * font description, so we have to check to see if this is really a
1214      * PostScript font.
1215      */
1216     family = ((TkFont *) fontPtr)->fa.family;
1217     for (i = 0; i < nFontNames; i++) {
1218 	if (strncasecmp(psFontMap[i].alias, family, strlen(psFontMap[i].alias))
1219 		 == 0) {
1220 	    Tcl_DString dString;
1221 
1222 	    Tcl_DStringInit(&dString);
1223 	    pointSize = (double)Tk_PostscriptFontName(font, &dString);
1224 	    fontName = Tcl_DStringValue(&dString);
1225 	    Blt_FormatToPostScript(tokenPtr, "%g /%s SetFont\n", pointSize,
1226 		fontName);
1227 	    Tcl_DStringFree(&dString);
1228 	    return;
1229 	}
1230     }
1231 
1232 #endif /* TK_MAJOR_VERSION > 4 */
1233 
1234     /*
1235      * Can't find it. Try to use the current point size.
1236      */
1237     fontName = NULL;
1238     pointSize = 12.0;
1239 
1240 #ifndef  WIN32
1241 #if (TK_MAJOR_VERSION > 4)
1242     /* Can you believe what I have to go through to get an XFontStruct? */
1243     fontPtr = XLoadQueryFont(Tk_Display(tokenPtr->tkwin), Tk_NameOfFont(font));
1244 #endif
1245     if (fontPtr != NULL) {
1246 	unsigned long fontProp;
1247 
1248 	if (XGetFontProperty(fontPtr, XA_POINT_SIZE, &fontProp) != False) {
1249 	    pointSize = (double)fontProp / 10.0;
1250 	}
1251 	fontName = XFontStructToPostScript(tokenPtr->tkwin, fontPtr);
1252 #if (TK_MAJOR_VERSION > 4)
1253 	XFreeFont(Tk_Display(tokenPtr->tkwin), fontPtr);
1254 #endif /* TK_MAJOR_VERSION > 4 */
1255     }
1256 #endif /* !WIN32 */
1257     if ((fontName == NULL) || (fontName[0] == '\0')) {
1258 	fontName = "Helvetica-Bold";	/* Defaulting to a known PS font */
1259     }
1260     Blt_FormatToPostScript(tokenPtr, "%g /%s SetFont\n", pointSize, fontName);
1261 }
1262 
1263 static void
TextLayoutToPostScript(tokenPtr,x,y,textPtr)1264 TextLayoutToPostScript(tokenPtr, x, y, textPtr)
1265     struct PsTokenStruct *tokenPtr;
1266     int x, y;
1267     TextLayout *textPtr;
1268 {
1269     char *src, *dst, *end;
1270     int count;			/* Counts the # of bytes written to
1271 				 * the intermediate scratch buffer. */
1272     TextFragment *fragPtr;
1273     int i;
1274     unsigned char c;
1275 #if HAVE_UTF
1276     Tcl_UniChar ch;
1277 #endif
1278     int limit;
1279 
1280     limit = PSTOKEN_BUFSIZ - 4; /* High water mark for the scratch
1281 				   * buffer. */
1282     fragPtr = textPtr->fragArr;
1283     for (i = 0; i < textPtr->nFrags; i++, fragPtr++) {
1284 	if (fragPtr->count < 1) {
1285 	    continue;
1286 	}
1287 	Blt_AppendToPostScript(tokenPtr, "(", (char *)NULL);
1288 	count = 0;
1289 	dst = tokenPtr->scratchArr;
1290 	src = fragPtr->text;
1291 	end = fragPtr->text + fragPtr->count;
1292 	while (src < end) {
1293 	    if (count > limit) {
1294 		/* Don't let the scatch buffer overflow */
1295 		dst = tokenPtr->scratchArr;
1296 		dst[count] = '\0';
1297 		Blt_AppendToPostScript(tokenPtr, dst, (char *)NULL);
1298 		count = 0;
1299 	    }
1300 #if HAVE_UTF
1301 	    /*
1302 	     * INTL: For now we just treat the characters as binary
1303 	     * data and display the lower byte.  Eventually this should
1304 	     * be revised to handle international postscript fonts.
1305 	     */
1306 	    src += Tcl_UtfToUniChar(src, &ch);
1307 	    c = (unsigned char)(ch & 0xff);
1308 #else
1309 	    c = *src++;
1310 #endif
1311 
1312 	    if ((c == '\\') || (c == '(') || (c == ')')) {
1313 		/*
1314 		 * If special PostScript characters characters "\", "(",
1315 		 * and ")" are contained in the text string, prepend
1316 		 * backslashes to them.
1317 		 */
1318 		*dst++ = '\\';
1319 		*dst++ = c;
1320 		count += 2;
1321 	    } else if ((c < ' ') || (c > '~')) {
1322 		/*
1323 		 * Present non-printable characters in their octal
1324 		 * representation.
1325 		 */
1326 		sprintf(dst, "\\%03o", c);
1327 		dst += 4;
1328 		count += 4;
1329 	    } else {
1330 		*dst++ = c;
1331 		count++;
1332 	    }
1333 	}
1334 	tokenPtr->scratchArr[count] = '\0';
1335 	Blt_AppendToPostScript(tokenPtr, tokenPtr->scratchArr, (char *)NULL);
1336 	Blt_FormatToPostScript(tokenPtr, ") %d %d %d DrawAdjText\n",
1337 	    fragPtr->width, x + fragPtr->x, y + fragPtr->y);
1338     }
1339 }
1340 
1341 /*
1342  * -----------------------------------------------------------------
1343  *
1344  * Blt_TextToPostScript --
1345  *
1346  *      Output PostScript commands to print a text string. The string
1347  *      may be rotated at any arbitrary angle, and placed according
1348  *      the anchor type given. The anchor indicates how to interpret
1349  *      the window coordinates as an anchor for the text bounding box.
1350  *
1351  * Results:
1352  *      None.
1353  *
1354  * Side Effects:
1355  *      Text string is drawn using the given font and GC on the graph
1356  *      window at the given coordinates, anchor, and rotation
1357  *
1358  * -----------------------------------------------------------------
1359  */
1360 void
Blt_TextToPostScript(tokenPtr,string,tsPtr,x,y)1361 Blt_TextToPostScript(tokenPtr, string, tsPtr, x, y)
1362     struct PsTokenStruct *tokenPtr;
1363     char *string;		/* String to convert to PostScript */
1364     TextStyle *tsPtr;		/* Text attribute information */
1365     double x, y;		/* Window coordinates where to print text */
1366 {
1367     double theta;
1368     double rotWidth, rotHeight;
1369     TextLayout *textPtr;
1370     Point2D anchorPos;
1371 
1372     if ((string == NULL) || (*string == '\0')) { /* Empty string, do nothing */
1373 	return;
1374     }
1375     theta = FMOD(tsPtr->theta, (double)360.0);
1376     textPtr = Blt_GetTextLayout(string, tsPtr);
1377     Blt_GetBoundingBox(textPtr->width, textPtr->height, theta, &rotWidth,
1378 		       &rotHeight, (Point2D *)NULL);
1379     /*
1380      * Find the center of the bounding box
1381      */
1382     anchorPos.x = x, anchorPos.y = y;
1383     anchorPos = Blt_TranslatePoint(&anchorPos, ROUND(rotWidth),
1384 	ROUND(rotHeight), tsPtr->anchor);
1385     anchorPos.x += (rotWidth * 0.5);
1386     anchorPos.y += (rotHeight * 0.5);
1387 
1388     /* Initialize text (sets translation and rotation) */
1389     Blt_FormatToPostScript(tokenPtr, "%d %d %g %g %g BeginText\n",
1390 	textPtr->width, textPtr->height, tsPtr->theta, anchorPos.x,
1391 	anchorPos.y);
1392 
1393     Blt_FontToPostScript(tokenPtr, tsPtr->font);
1394 
1395     /* All coordinates are now relative to what was set by BeginText */
1396     if ((tsPtr->shadow.offset > 0) && (tsPtr->shadow.color != NULL)) {
1397 	Blt_ForegroundToPostScript(tokenPtr, tsPtr->shadow.color);
1398 	TextLayoutToPostScript(tokenPtr, tsPtr->shadow.offset,
1399 	       tsPtr->shadow.offset, textPtr);
1400     }
1401     Blt_ForegroundToPostScript(tokenPtr, (tsPtr->state & STATE_ACTIVE)
1402 	? tsPtr->activeColor : tsPtr->color);
1403     TextLayoutToPostScript(tokenPtr, 0, 0, textPtr);
1404     Blt_Free(textPtr);
1405     Blt_AppendToPostScript(tokenPtr, "EndText\n", (char *)NULL);
1406 }
1407 
1408 /*
1409  * -----------------------------------------------------------------
1410  *
1411  * Blt_LineToPostScript --
1412  *
1413  *      Outputs PostScript commands to print a multi-segmented line.
1414  *      It assumes a procedure DashesProc was previously defined.
1415  *
1416  * Results:
1417  *      None.
1418  *
1419  * Side Effects:
1420  *      Segmented line is printed.
1421  *
1422  * -----------------------------------------------------------------
1423  */
1424 void
Blt_LineToPostScript(tokenPtr,pointPtr,nPoints)1425 Blt_LineToPostScript(tokenPtr, pointPtr, nPoints)
1426     struct PsTokenStruct *tokenPtr;
1427     register XPoint *pointPtr;
1428     int nPoints;
1429 {
1430     register int i;
1431 
1432     if (nPoints <= 0) {
1433 	return;
1434     }
1435     Blt_FormatToPostScript(tokenPtr, " newpath %d %d moveto\n",
1436 			   pointPtr->x, pointPtr->y);
1437     pointPtr++;
1438     for (i = 1; i < (nPoints - 1); i++, pointPtr++) {
1439 	Blt_FormatToPostScript(tokenPtr, " %d %d lineto\n",
1440 			       pointPtr->x, pointPtr->y);
1441 	if ((i % PS_MAXPATH) == 0) {
1442 	    Blt_FormatToPostScript(tokenPtr,
1443 		"DashesProc stroke\n newpath  %d %d moveto\n",
1444 				   pointPtr->x, pointPtr->y);
1445 	}
1446     }
1447     Blt_FormatToPostScript(tokenPtr, " %d %d lineto\n",
1448 			   pointPtr->x, pointPtr->y);
1449     Blt_AppendToPostScript(tokenPtr, "DashesProc stroke\n", (char *)NULL);
1450 }
1451 
1452 void
Blt_BitmapToPostScript(tokenPtr,display,bitmap,scaleX,scaleY)1453 Blt_BitmapToPostScript(tokenPtr, display, bitmap, scaleX, scaleY)
1454     struct PsTokenStruct *tokenPtr;
1455     Display *display;
1456     Pixmap bitmap;		/* Bitmap to be converted to PostScript */
1457     double scaleX, scaleY;
1458 {
1459     int width, height;
1460     double scaledWidth, scaledHeight;
1461 
1462     Tk_SizeOfBitmap(display, bitmap, &width, &height);
1463     scaledWidth = (double)width * scaleX;
1464     scaledHeight = (double)height * scaleY;
1465     Blt_AppendToPostScript(tokenPtr, "  gsave\n", (char *)NULL);
1466     Blt_FormatToPostScript(tokenPtr, "    %g %g translate\n",
1467 			   scaledWidth * -0.5, scaledHeight * 0.5);
1468     Blt_FormatToPostScript(tokenPtr, "    %g %g scale\n",
1469 			   scaledWidth, -scaledHeight);
1470     Blt_FormatToPostScript(tokenPtr, "    %d %d true [%d 0 0 %d 0 %d] {",
1471 			   width, height, width, -height, height);
1472     Blt_BitmapDataToPostScript(tokenPtr, display, bitmap, width, height);
1473     Blt_AppendToPostScript(tokenPtr, "    } imagemask\n  grestore\n",
1474 	(char *)NULL);
1475 }
1476 
1477 void
Blt_2DSegmentsToPostScript(psToken,segPtr,nSegments)1478 Blt_2DSegmentsToPostScript(psToken, segPtr, nSegments)
1479     PsToken psToken;
1480     register Segment2D *segPtr;
1481     int nSegments;
1482 {
1483     register Segment2D *endPtr;
1484 
1485     for (endPtr = segPtr + nSegments; segPtr < endPtr; segPtr++) {
1486 	Blt_FormatToPostScript(psToken, "%g %g moveto\n",
1487 			       segPtr->p.x, segPtr->p.y);
1488 	Blt_FormatToPostScript(psToken, " %g %g lineto\n",
1489 			       segPtr->q.x, segPtr->q.y);
1490 	Blt_AppendToPostScript(psToken, "DashesProc stroke\n", (char *)NULL);
1491     }
1492 }
1493