1 /* HTML-PSformat.c - Module for NCSA's Mosaic software
2 *
3 * Purpose: to parse Hypertext widget contents into appropriate PostScript
4 *
5 * Author: Ameet A. Raval & Frans van Hoesel
6 * (aar@gfdl.gov & hoesel@chem.rug.nl).
7 * send bugreports to hoesel@chem.rug.nl
8 *
9 * Institution: for Ameet A. Raval:
10 * Geophysical Fluid Dynamics Laboratory,
11 * National Oceanic and Atmospheric Administration,
12 * U.S. Department of Commerce
13 * P.O. Box 308
14 * Princeton, NJ 08542
15 * for Frans van Hoesel:
16 * Xtreme graphics software
17 * Herepoortenmolendrift 36
18 * 9711 DH Groningen
19 * The Netherlands
20 *
21 * Date: 1 aug 1993
22 * Modification: 8 nov 1993
23 * o added support for bold/italics courier
24 * o removed unused or no longer needed stuff
25 * o fixed the font alignment problem
26 * 23 nov 1993
27 * o added support for horizontal ruler
28 * o on request of Ameet, added a specific
29 * line about whome to send bugreports to
30 *
31 * Copyright: This work is the product of the United States Government,
32 * and is precluded from copyright protection. It is hereby
33 * released into the public domain.
34 *
35 * WE MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
36 * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
37 * WARRANTY. WE SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE
38 * USERS OF THIS SOFTWARE.
39 *
40 * pieces of code are taken from xvps by kind
41 * permission of John Bradley.
42 */
43
44 #include <varargs.h>
45
46 #include <string.h>
47 #include <stdio.h>
48 #include <ctype.h>
49 #include <math.h>
50 #include <stdlib.h>
51 #include "HTMLP.h"
52
53 /* Fix thanks to robm. */
54 #ifdef __alpha
55 #include <Xm/VaSimpleP.h>
56 #endif
57
58 #define CR '\015'
59 #define LF '\012'
60
61 extern int SwapElements();
62
63 /* the next page sizes are a compromise between letter sized paper
64 * (215.9 x 279.4 mm) and european standard A4 sized paper (210.0 x 297.0 mm).
65 * Note that PAGE_WIDTH is not the actual width of the paper
66 */
67 #define TOP_MARGIN (10*72)
68 #define BOT_MARGIN (0.7*72)
69 #define LEFT_MARGIN (0.6*72)
70 #define PAGE_HEIGHT (TOP_MARGIN - BOT_MARGIN)
71 #define PAGE_WIDTH (8*72)
72
73 #define F_FULLCOLOR 0
74 #define F_GREYSCALE 1
75 #define F_BWDITHER 2
76 #define F_REDUCED 3
77
78 #define L_PAREN '('
79 #define R_PAREN ')'
80 #define B_SLASH '\\'
81 #define MAX_ASCII '\177'
82
83 #ifdef _NO_PROTO
84 # define ARG0(v0) ()
85 # define ARG1(t1,v1) (v1) t1 v1;
86 # define ARG2(t1,v1,t2,v2) (v1,v2) t1 v1;t2 v2;
87 # define ARG3(t1,v1,t2,v2,t3,v3) (v1,v2,v3) t1 v1;t2 v2;t3 v3;
88 # define ARG4(t1,v1,t2,v2,t3,v3,t4,v4) (v1,v2,v3,v4) t1 v1;t2 v2;t3 v3;t4 v4;
89 # define ARG5(t1,v1,t2,v2,t3,v3,t4,v4,t5,v5) (v1,v2,v3,v4,v5) t1 v1;t2 v2;t3 v3;t4 v4; t5 v5;
90 # define ARG1V(t1,v1,e2) (v1) t1 v1;
91 #else
92 # define ARG0(v0) (v0)
93 # define ARG1(t1,v1) (t1 v1)
94 # define ARG2(t1,v1,t2,v2) (t1 v1, t2 v2)
95 # define ARG3(t1,v1,t2,v2,t3,v3) (t1 v1, t2 v2, t3 v3)
96 # define ARG4(t1,v1,t2,v2,t3,v3,t4,v4) (t1 v1, t2 v2, t3 v3, t4 v4)
97 # define ARG5(t1,v1,t2,v2,t3,v3,t4,v4,t5,v5) (t1 v1, t2 v2, t3 v3, t4 v4, t5 v5)
98 # define ARG1V(t1,v1,e2) (t1 v1, e2)
99 #endif /* _NO_PROTO */
100
101 /* MONO returns total intensity of r,g,b components .33R+ .5G+ .17B */
102 #define MONO(rd,gn,bl) (((rd)*11 + (gn)*16 + (bl)*5) >> 13)
103
104 /* PSconst_out outputs to the postscript buffer an array of constant
105 * strings
106 */
107 #define PSconst_out(txt) {\
108 int n=(sizeof txt)/(sizeof txt[0]); \
109 int i; \
110 for (i=0; i<n; i++) { \
111 PSprintf("%s\n", txt[i]) ; \
112 } \
113 }
114
115
116 /* for regular-font, bold-font, italic-font, fixed-font */
117 typedef enum { RF, BF, IF, FF, FB, FI } PS_fontstyle;
118
119 static int PS_size, PS_len, PS_offset, PS_curr_page, PS_start_y, PS_hexi;
120 static int PS_page_offset;
121 static char *PS_string;
122 static float Points_Pixel;
123 static int Pixels_Page;
124 static PS_fontstyle PS_oldfn = RF;
125 static int PS_fontascent = 0;
126 static int PS_oldfs = 0;
127
128 static XColor fg_color, bg_color;
129
130
131 /*__________________________________________________________________________
132 |
133 | GetDpi - return Dots-per-inch of the screen
134 |
135 | calculate the pixel density in dots per inch on the current widget
136 | screen
137 |
138 */
139
ARG1(HTMLWidget,hw)140 static float GetDpi ARG1(HTMLWidget, hw) {
141 Screen *s = XtScreen(hw);
142 float dpi;
143
144 dpi = 25.4 * WidthOfScreen(s) / WidthMMOfScreen(s);
145 /* no earthly monitor does this */
146 if (dpi<1.0 || dpi>10000.0)
147 dpi = 72.0;
148 return dpi;
149 }
150
151
152 /*__________________________________________________________________________
153 |
154 | PSprintf - dynamic string concatenation function.
155 |
156 | In successive calls, the formatted string will be appended to the global
157 | output string Sp.
158 | It assumes that on each call, the length of the text appended to Sp
159 | is less than 1024.
160 | The format string is used as in printf, so you can use additional
161 | arguments.
162 |
163 | When successful, PSprintf returns the number of characters printed
164 | in this call, otherwise it returns EOF (just as printf does)
165 |
166 */
167
168 #ifdef BROKEN_SOLARIS_COMPILER_STDARG
169 /* "Looks like there's a bug in Sun's C compiler and the stdarg.h use
170 of va_start() in HTML-PSformat.c. Until the SunPro folks can take a
171 look at the problem, the following pre-ANSI code should workaround
172 the problem." */
ARG1V(char *,format,...)173 static int PSprintf ARG1V(char *,format, ...) {
174 va_dcl
175 va_list args;
176 int len;
177 char *s;
178
179 if (PS_size - PS_len < 1024) {
180 PS_size += 1024;
181 if ((s = (char *) realloc(PS_string, PS_size)) == NULL) {
182 fprintf(stderr, "PSprintf malloc failed\n");
183 return(EOF);
184 }
185 PS_string = s;
186 }
187 va_start(args);
188 len = vsprintf(PS_string+PS_len, format, args);
189 /* this is a hack to make it work on systems were vsprintf(s,.)
190 * returns s, instead of the len.
191 */
192 if (len != EOF && len != NULL)
193 PS_len += strlen(PS_string+PS_len);
194 va_end(args);
195 return(len);
196 }
197 #else /* not BROKEN_SOLARIS_COMPILER_STDARG */
198 static int
PSprintf(format,va_alist)199 PSprintf (format, va_alist)
200 char* format;
201 va_dcl
202 {
203 int len;
204 char *s;
205 va_list args;
206
207 if (PS_size - PS_len < 1024) {
208 PS_size += 1024;
209 if ((s = (char *) realloc(PS_string, PS_size)) == NULL) {
210 fprintf(stderr, "PSprintf malloc failed\n");
211 return(EOF);
212 }
213 PS_string = s;
214 }
215 va_start(args);
216 len = vsprintf(PS_string+PS_len, format, args);
217 /* this is a hack to make it work on systems were vsprintf(s,...)
218 * returns s, instead of the len.
219 */
220 if (len != EOF && len != 0)
221 PS_len += strlen(PS_string+PS_len);
222 va_end(args);
223 return(len);
224 }
225 #endif /* not BROKEN_SOLARIS_COMPILER_STDARG */
226
227 /*__________________________________________________________________________
228 |
229 | PShex - output hex byte
230 |
231 | Append the byte "val" to an internal string buffer in hexadecimal
232 | format. If the argument "flush" is True, or if the buffer has filled
233 | up, flush the buffer to the larger postscript output buffer (using
234 | PSprintf).
235 |
236 */
237
ARG2(unsigned char,val,int,flush)238 static int PShex ARG2(unsigned char,val, int,flush) {
239
240 static unsigned char hexline[80];
241 static char digit[] = "0123456789abcdef";
242
243 if (!flush) {
244 hexline[PS_hexi++] = (char) digit[((unsigned) val >>
245 (unsigned) 4) & (unsigned) 0x0f];
246 hexline[PS_hexi++] = (char) digit[(unsigned) val &
247 (unsigned) 0x0f];
248 }
249
250 /* Changed from ">78" to ">77" on advice of
251 debra@info.win.tue.nl (Paul De Bra). */
252 if ((flush && PS_hexi) || (PS_hexi>77)) {
253 hexline[PS_hexi] = '\0';
254 PS_hexi=0;
255 return (PSprintf("%s\n", hexline));
256 }
257 return (0);
258 }
259
260
261 /*__________________________________________________________________________
262 | PSfont - change font
263 |
264 | change local font in buf to "font"
265 | fontfamily indicates if the overall style is times, helvetica, century
266 | schoolbook or lucida.
267 |
268 */
269
ARG3(HTMLWidget,hw,XFontStruct *,font,int,fontfamily)270 static void PSfont ARG3( HTMLWidget,hw, XFontStruct *,font, int,fontfamily) {
271
272 PS_fontstyle fn;
273 int style, size;
274 int fs;
275
276 static PS_fontstyle fontstyle[17] = {
277 RF, IF, BF, FF, BF, BF, BF, BF, BF,
278 BF, IF, FF, FF, FB, FI, FB, FI
279 };
280
281 static char fnchar[6][3] = {"RF", "BF", "IF", "FF", "FB", "FI"};
282
283 /* fontsizes as set in gui.c and in HTML.c (listing font is only
284 * defined in HTML.c)
285 */
286 static int fontsizes[4][3][17] = {
287 /* times font sizes */
288 14, 14, 14, 14, 18, 17, 14, 12, 10, 8, 14, 12, 12, 14, 14, 12, 12,
289 17, 17, 17, 17, 24, 18, 17, 14, 12, 10, 17, 14, 12, 17, 17, 14, 14,
290 20, 20, 20, 20, 25, 24, 20, 18, 17, 14, 20, 18, 12, 20, 20, 18, 18,
291 /* helvetica sizes */
292 14, 14, 14, 14, 18, 17, 14, 12, 10, 8,
293 14, 12, 12, 14, 14, 12, 12,
294 17, 17, 17, 17, 24, 18, 17, 14, 12, 10,
295 17, 14, 12, 17, 17, 14, 14,
296 20, 20, 20, 20, 25, 24, 20, 18, 17, 14,
297 20, 18, 12, 20, 20, 18, 18,
298 /* new century schoolbook sizes */
299 14, 14, 14, 14, 18, 17, 14, 12, 10, 8,
300 14, 12, 12, 14, 14, 12, 12,
301 18, 18, 18, 18, 24, 18, 17, 14, 12, 10,
302 18, 14, 12, 18, 18, 14, 14,
303 20, 20, 20, 20, 25, 24, 20, 18, 17, 14,
304 20, 18, 12, 20, 20, 18, 18,
305 /* lucida sizes */
306 14, 14, 14, 14, 18, 17, 14, 12, 11, 10,
307 14, 12, 12, 14, 14, 12, 12,
308 17, 17, 17, 17, 24, 18, 17, 14, 12, 10,
309 17, 14, 12, 17, 17, 14, 14,
310 20, 20, 20, 20, 25, 24, 20, 18, 17, 14,
311 20, 18, 12, 20, 20, 18, 18
312 };
313
314 /* next is for each fontfamily the ascent value as given by the
315 * medium sized bold x-font (the regular font has the same
316 * ascent value for both the medium and the large size Century
317 * font).
318 * it is use in the check for the fontsize (small, medium, large)
319 */
320 static int medium_fontascent[4] = {
321 14, 14, 16, 15
322 };
323
324 /* for each fontfamily, for each fontsize, and for each font style
325 * give the ascent value, so the output from Postscript is correct.
326 * If the value is given between parenthesis, then it is different
327 * from the value as stored in the x-font.
328 * Note that this is a fix, and need to be changed, if the browser
329 * is fixed (in the current version 1.2 the baseline of various fonts
330 * is not aligned very well).
331 */
332 static int fontascent[4][3][17] = {
333 /*rg, itl, bld, fix, h1, h2, h3, h4, h5, h6,
334 add, pla, lis, fixbold, fixital, plabold, plaital, */
335 /* times */
336 12 ,(11), 12 ,(10),(15),(14), 12 ,(10), (8), (6),
337 11 , (9), 10, 10 , 10 , (9), (9),
338 (13),(13),(14),(12),(20),(15),(14), 12 ,(10), (8),
339 13 ,(10), 10 ,(12),(12),(10),(10),
340 (16),(15),(15),(13),(21),(20),(15),(15),(14), 12 ,
341 15 ,(13), 10,(13),(13),(13),(13),
342 /* helvetica */
343 (12),(12),(12),(10),(15),(14),(12),(10), (9), (7),
344 (12), (9), 10 ,(10),(10), (9), (9),
345 (14),(14),(14),(12),(22),(15),(14),(12),(10), (9),
346 (14),(10), 10 ,(12),(12),(10),(10),
347 (16),(16),(16),(13),(22),(22),(16),(15),(14),(12),
348 (16),(13), 10 ,(13),(13),(13),(13),
349 /* new century schoolbook */
350 (12),(12), 13 ,(10),(16), 14 , 13 ,(10), (9), (7),
351 (12), (9), 10 ,(10),(10), (9), (9),
352 (16),(14),(16),(13),(22),(16), 14 , 13 ,(10), (9),
353 (14),(10), 10 ,(13),(13),(10),(10),
354 (17),(16),(17),(13),(22),(22),(17),(16), 14 , 13 ,
355 (16),(13), 10 ,(13),(13),(13),(13),
356 /* lucida bright */
357 11 ,(11), 11 ,(11),(15),(14), 11 ,(10), (9), (7),
358 11 , (9), 10, 11 , 10 , (9), (9),
359 (14),(15),(14),(13),(20),(15),(14), 11 ,(10), (7),
360 15 ,(11), 10 ,(13),(13),(11),(10),
361 (17),(17),(17),(16),(21),(20),(17),(15),(14), 11 ,
362 17 ,(14), 10,(16),(13),(14),(13)
363 };
364
365 /* NULL case - reflush old font or the builtin default: */
366 if (hw==NULL || font==NULL) {
367 if (PS_oldfs != 0)
368 PSprintf( "%2s %d SF\n", fnchar[PS_oldfn], PS_oldfs);
369 return;
370 }
371 /* added the next line in case xmosaic version 199.4 has more fonts */
372 style = 3;
373
374 if (font == hw->html.font) {
375 style = 0;
376 } else if (font == hw->html.italic_font) {
377 style = 1;
378 } else if (font == hw->html.bold_font) {
379 style = 2;
380 } else if (font == hw->html.fixed_font) {
381 style = 3;
382 } else if (font == hw->html.header1_font) {
383 style = 4;
384 } else if (font == hw->html.header2_font) {
385 style = 5;
386 } else if (font == hw->html.header3_font) {
387 style = 6;
388 } else if (font == hw->html.header4_font) {
389 style = 7;
390 } else if (font == hw->html.header5_font) {
391 style = 8;
392 } else if (font == hw->html.header6_font) {
393 style = 9;
394 } else if (font == hw->html.address_font) {
395 style = 10;
396 } else if (font == hw->html.plain_font) {
397 style = 11;
398 } else if (font == hw->html.listing_font) {
399 style = 12;
400 } else if (font == hw->html.fixedbold_font) {
401 style = 13;
402 } else if (font == hw->html.fixeditalic_font) {
403 style = 14;
404 } else if (font == hw->html.plainbold_font) {
405 style = 15;
406 } else if (font == hw->html.plainitalic_font) {
407 style = 16;
408 }
409
410 /* check size, by looking at the size of the regular font */
411 size = 1;
412 if (hw->html.bold_font->ascent > medium_fontascent[fontfamily]) {
413 /* large font */
414 size = 2;
415 } else if (hw->html.bold_font->ascent < medium_fontascent[fontfamily]) {
416 /* small font */
417 size = 0;
418 }
419 fn = fontstyle[style];
420 fs = fontsizes[fontfamily][size][style];
421 PS_fontascent = fontascent[fontfamily][size][style];
422
423 if (fn != PS_oldfn || fs != PS_oldfs) {
424 PSprintf( "%2s %d SF\n", fnchar[fn], fs);
425 PS_oldfn=fn, PS_oldfs=fs;
426 }
427 }
428
429
430 /*__________________________________________________________________________
431 |
432 | PSshowpage - end of page function
433 |
434 | show the current page and restore any changes to the printer state
435 |
436 */
437
ARG0(void)438 static void PSshowpage ARG0(void) {
439
440 PSprintf("showpage restore\n");
441 }
442
443
444 /*__________________________________________________________________________
445 |
446 | PSnewpage - begin a fresh page
447 |
448 | increment the page count and handle the structured comment
449 | conventions
450 |
451 */
452
ARG0(void)453 static void PSnewpage ARG0(void) {
454
455 PS_curr_page++;
456
457 /* the PostScript reference Manual states that the Page: Tag
458 should have a label and a ordinal; otherwise programs like
459 psutils fail -gustaf */
460 PSprintf("%%%%Page: %d %d\n", PS_curr_page, PS_curr_page);
461 PSprintf("save\nNP\n");
462 PSfont( NULL, NULL, 0); /* force re-flush of last font used */
463 }
464
465
466 /*__________________________________________________________________________
467 |
468 | PSinit_latin1 - handle ISO encoding
469 |
470 | print out initializing PostScript text for ISO Latin1 font encoding
471 | This code is copied from the Idraw program (from Stanford's InterViews
472 | package), courtesy of Steinar Kjaernsr|d, steinar@ifi.uio.no
473 |
474 */
475
ARG0(void)476 static void PSinit_latin1 ARG0(void) {
477
478 static char *txt[] = {
479
480 "/reencodeISO {",
481 "dup dup findfont dup length dict begin",
482 "{ 1 index /FID ne { def }{ pop pop } ifelse } forall",
483 "/Encoding ISOLatin1Encoding D",
484 "currentdict end definefont",
485 "} D",
486 "/ISOLatin1Encoding [",
487 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
488 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
489 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
490 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
491 "/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright",
492 "/parenleft/parenright/asterisk/plus/comma/minus/period/slash",
493 "/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon",
494 "/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N",
495 "/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright",
496 "/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m",
497 "/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde",
498 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
499 "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
500 "/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve",
501 "/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut",
502 "/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar",
503 "/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot",
504 "/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior",
505 "/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine",
506 "/guillemotright/onequarter/onehalf/threequarters/questiondown",
507 "/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla",
508 "/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex",
509 "/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis",
510 "/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute",
511 "/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis",
512 "/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave",
513 "/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex",
514 "/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis",
515 "/yacute/thorn/ydieresis",
516 "] D",
517 "[RF BF IF FF FB FI] {reencodeISO D} forall"
518 };
519
520 PSconst_out(txt);
521 }
522
523
524 /*__________________________________________________________________________
525 |
526 | PSinit - initialize Postscript output
527 |
528 | does the initialization per html document
529 |
530 */
531
ARG0(void)532 static void PSinit ARG0(void) {
533 PS_size = PS_len = PS_offset = PS_hexi = PS_page_offset = 0;
534 PS_start_y = 0;
535 PS_string = (char *) malloc(1);
536 PS_oldfs = 0;
537 PS_oldfn = RF;
538 PS_curr_page = 0 ;
539 }
540
541
542 /*__________________________________________________________________________
543 |
544 | PSheader - initialize Postscript output
545 |
546 | prints out the prolog
547 |
548 */
549
ARG2(char *,title,int,font)550 static void PSheader ARG2(char *,title, int,font) {
551
552 static char *fontname[] = {
553 /* in order: regular, bold, italic */
554 "Times-Roman", "Times-Bold", "Times-Italic",
555 "Helvetica", "Helvetica-Bold", "Helvetica-Oblique",
556 "NewCenturySchlbk-Roman", "NewCenturySchlbk-Bold",
557 "NewCenturySchlbk-Italic",
558 /* this is a nasty trick, I have put Times in place of
559 * Lucida, becaus emost printers don't have Lucida font
560 */
561 "Times-Roman", "Times-Bold", "Times-Italic"
562 /* "Lucida", "Lucida-Bold", "Lucida-Italic" */
563 };
564
565 static char *txt[] = {
566
567 "%%Creator: NCSA Mosaic, Postscript by Ameet Raval & Frans van Hoesel",
568 "%%Pages: (atend)",
569 "%%EndComments",
570 "save",
571 "/D {def} def /E {exch} D",
572 "/M {moveto} D",
573 "/S {show} D",
574 "/R {rmoveto} D",
575 "/L {lineto} D",
576 "/RL {rlineto} D",
577 "/SQ {newpath 0 0 M 0 1 L 1 1 L 1 0 L closepath} D",
578 "/U {gsave currentpoint currentfont /FontInfo get /UnderlinePosition get",
579 " 0 E currentfont /FontMatrix get dtransform E pop add newpath moveto",
580 " dup stringwidth rlineto stroke grestore S } D",
581 "/B {/r E D gsave -13 0 R currentpoint ",
582 " newpath r 0 360 arc closepath fill grestore } D",
583 "/OB {/r E D gsave -13 0 R currentpoint ",
584 " newpath r 0 360 arc closepath stroke grestore } D",
585 "/NP {xmargin topmargin translate scalfac dup scale } D",
586 "/HR {/l E D gsave l 0 RL stroke grestore } D",
587 "/SF {E findfont E scalefont setfont } D",
588 "/FF {/Courier } D",
589 "/FB {/Courier-Bold } D",
590 "/FI {/Courier-Oblique } D"
591 };
592
593
594 PSprintf("%%!PS-Adobe-1.0\n");
595 if (title)
596 {
597 char *tmp;
598 for (tmp = title; *tmp; tmp++)
599 if (*tmp == CR || *tmp == LF)
600 *tmp = ' ';
601 PSprintf("%%%%Title: %s\n", title);
602 }
603 PSprintf("%%%%DocumentFonts: %s %s %s Courier Courier-Bold Courier-Oblique\n",
604 fontname[font*3], fontname[font*3+1], fontname[font*3+2]);
605 PSconst_out(txt);
606 PSprintf("/RF {/%s} D\n", fontname[font*3]);
607 PSprintf("/BF {/%s} D\n", fontname[font*3+1]);
608 PSprintf("/IF {/%s} D\n", fontname[font*3+2]);
609
610 PSinit_latin1();
611
612 PSprintf("/xmargin %d D\n", (int) LEFT_MARGIN);
613 PSprintf("/topmargin %d D\n", (int) TOP_MARGIN);
614 PSprintf("/scalfac %.5f D\n", Points_Pixel);
615 PSprintf("%%%%EndProlog\n");
616
617 }
618
619
620 /*__________________________________________________________________________
621 |
622 | PStrailer - write postscript trailer
623 |
624 */
625
ARG0(void)626 static void PStrailer ARG0(void) {
627
628 PSprintf("%%%%Trailer\n");
629 PSprintf("restore\n");
630 PSprintf("%%%%Pages: %d\n", PS_curr_page);
631 }
632
633
634 /*__________________________________________________________________________
635 |
636 | PStext - output text
637 |
638 | show text "t", and protect special characters if needed
639 | if Underline is non-zero, the text is underlined.
640 |
641 */
642
ARG2(String,t,int,underline)643 static void PStext ARG2(String,t, int,underline) {
644 String tp, t2;
645 int nspecial=0, nisochar=0;
646
647 tp=t;
648 /* count # of special char's in text */
649 while (*tp != '\0') {
650 if (*tp == L_PAREN || *tp == R_PAREN || *tp == B_SLASH)
651 nspecial++;
652 else if (*(unsigned char *)tp > (unsigned char )MAX_ASCII)
653 nisochar++;
654 tp++;
655 }
656
657 if (nspecial == 0 && nisochar == 0) {
658 /* no special char's, send out original string */
659 PSprintf("(%s)%c\n", t, (underline)?'U':'S');
660 return;
661 }
662 /* create t2 to hold original text + "\"'s */
663 t2 = (String) malloc((tp-t) + nspecial + 3*nisochar + 1);
664
665 if (t2==NULL) {
666 fprintf(stderr, "PStext malloc failed\n");
667 return;
668 }
669
670 /* for each char in t, if it is a special char, insert "\"
671 * into the new string t2, then insert the actual char
672 */
673 tp = t2;
674 while (*t != '\0') {
675 if (*t == L_PAREN || *t == R_PAREN || *t == B_SLASH) {
676 *(tp++) = B_SLASH;
677 *(tp++) = *t;
678 } else if (*(unsigned char *)t > (unsigned char) MAX_ASCII) {
679 /* convert to octal */
680 *(tp++) = B_SLASH;
681 *(tp++) = ((int)(*(unsigned char *)t)>>6 & 007) + '0';
682 *(tp++) = ((int)(*(unsigned char *)t)>>3 & 007) + '0';
683 *(tp++) = ((int)(*(unsigned char *)t) & 007) + '0';
684 } else {
685 *(tp++) = *t;
686 }
687 t++;
688 }
689 *(tp) = '\0';
690 PSprintf("(%s)%c\n", t2, (underline)?'U':'S');
691
692 free(t2);
693 }
694
695
696 /*__________________________________________________________________________
697 |
698 | PSbullet - output a bullet
699 |
700 | the bullet is normally filled, except for a bullet with an indent level
701 | of two. The size of the higher level bullets is just somewhat smaller
702 |
703 */
704
ARG2(int,level,int,size)705 static void PSbullet ARG2( int, level, int, size) {
706
707 if (size < 6) size = 6;
708
709 if (level <2 )
710 PSprintf( " %f B\n", size/5.5);
711 else if (level == 2)
712 PSprintf( " %f OB\n", size/5.5);
713 else
714 PSprintf(" %f B\n", size/7.5);
715 }
716
717 /*__________________________________________________________________________
718 |
719 | PShrule - draw a horizontal line with the given width
720 |
721 | nothing special, just draw a line, from the current position to
722 | the right side of the paper.
723 |
724 */
725
ARG1(int,length)726 static void PShrule ARG1(int, length) {
727
728 PSprintf("%d HR\n", length);
729 }
730
731
732 /*__________________________________________________________________________
733 |
734 | PSmoveto - move to new x,y location
735 |
736 | if the Y value does not fit on the current page, begin a new page
737 | (I think in the current implementation, this never happens)
738 |
739 */
740
ARG2(int,x,int,y)741 static void PSmoveto ARG2( int,x, int,y) {
742
743 if (y > PS_start_y + Pixels_Page) {
744 PS_start_y = y;
745 PSshowpage();
746 PSnewpage();
747 }
748 PS_offset = 0;
749 PSprintf( "%d %d M\n", x, -(y - PS_start_y));
750 }
751
752
753 /*__________________________________________________________________________
754 |
755 | PSmove_offset - set Y-offset
756 |
757 | do a relative vertical move, whenever the offset changes
758 |
759 */
760
ARG1(int,offset)761 static void PSmove_offset ARG1( int, offset) {
762
763 if (offset != PS_offset) {
764 PSprintf("0 %d R\n", PS_offset - offset );
765 PS_offset = offset;
766 }
767 }
768
769
770 /*__________________________________________________________________________
771 |
772 | PSrle_encode - perform run length encoding
773 |
774 | does the run-length encoding. This is done to reduce the file size and
775 | therefore the time to send the file to the printer. You get longer
776 | processing time instead.
777 |
778 | rle is encoded as such:
779 | <count> <value> # 'run' of count+1 equal pixels
780 | <count | 0x80> <count+1 data bytes> # count+1 non-equal pixels
781 | count can range between 0 and 127
782 |
783 | returns length of the rleline vector
784 |
785 */
786
ARG3(unsigned char *,scanline,unsigned char *,rleline,int,wide)787 static int PSrle_encode ARG3(unsigned char *, scanline,
788 unsigned char *,rleline,
789 int,wide)
790 {
791 int i, j, blocklen, isrun, rlen;
792 unsigned char block[256], pix;
793
794 blocklen = isrun = rlen = 0;
795
796 for (i=0; i<wide; i++) {
797 /* there are 5 possible states:
798 * 0: block empty.
799 * 1: block is a run, current pix == previous pix
800 * 2: block is a run, current pix != previous pix
801 * 3: block not a run, current pix == previous pix
802 * 4: block not a run, current pix != previous pix
803 */
804
805 pix = scanline[i];
806
807 if (!blocklen) {
808 /* case 0: empty */
809 block[blocklen++] = pix;
810 isrun = 1;
811 } else if (isrun) {
812 if (pix == block[blocklen-1]) {
813 /* case 1: isrun, prev==cur */
814 block[blocklen++] = pix;
815 } else {
816 /* case 2: isrun, prev!=cur */
817 if (blocklen>1) {
818 /* we have a run block to flush */
819 rleline[rlen++] = blocklen-1;
820 rleline[rlen++] = block[0];
821 /* start new run block with pix */
822 block[0] = pix;
823 blocklen = 1;
824 } else {
825 isrun = 0;
826 /* blocklen<=1, turn into non-run */
827 block[blocklen++] = pix;
828 }
829 }
830 } else {
831 /* not a run */
832 if (pix == block[blocklen-1]) {
833 /* case 3: non-run, prev==cur */
834 if (blocklen>1) {
835 /* have a non-run block to flush */
836 rleline[rlen++] = (blocklen-1) | 0x80;
837 for (j=0; j<blocklen; j++)
838 rleline[rlen++] = block[j];
839 /* start new run block with pix */
840 block[0] = pix;
841 blocklen = isrun = 1;
842 } else {
843 isrun = 1;
844 /* blocklen<=1 turn into a run */
845 block[blocklen++] = pix;
846 }
847 } else {
848 /* case 4: non-run, prev!=cur */
849 block[blocklen++] = pix;
850 }
851 }
852
853 if (blocklen == 128) { /* max block length. flush */
854 if (isrun) {
855 rleline[rlen++] = blocklen-1;
856 rleline[rlen++] = block[0];
857 } else {
858 rleline[rlen++] = (blocklen-1) | 0x80;
859 for (j=0; j<blocklen; j++)
860 rleline[rlen++] = block[j];
861 }
862 blocklen = 0;
863 }
864 }
865
866 if (blocklen) { /* flush last block */
867 if (isrun) {
868 rleline[rlen++] = blocklen-1;
869 rleline[rlen++] = block[0];
870 } else {
871 rleline[rlen++] = (blocklen-1) | 0x80;
872 for (j=0; j<blocklen; j++)
873 rleline[rlen++] = block[j];
874 }
875 }
876
877 return rlen;
878 }
879
880
881 /*__________________________________________________________________________
882 |
883 | PScolor_image - created postscript colorimage operator
884 |
885 | spits out code that checks if the PostScript device in question
886 | knows about the 'colorimage' operator. If it doesn't, it defines
887 | 'colorimage' in terms of image (ie, generates a greyscale image from
888 | RGB data)
889 |
890 */
891
ARG0(void)892 static void PScolor_image ARG0(void) {
893
894 static char *txt[] = {
895
896 "% define 'colorimage' if it isn't defined",
897 "% ('colortogray' and 'mergeprocs' come from xwd2ps",
898 "% via xgrab)",
899 "/colorimage where % do we know about 'colorimage'?",
900 " { pop } % yes: pop off the 'dict' returned",
901 " { % no: define one",
902 " /colortogray { % define an RGB->I function",
903 " /rgbdata exch store % call input 'rgbdata'",
904 " rgbdata length 3 idiv",
905 " /npixls exch store",
906 " /rgbindx 0 store",
907 " /grays npixls string store % str to hold the result",
908 " 0 1 npixls 1 sub {",
909 " grays exch",
910 " rgbdata rgbindx get 20 mul % Red",
911 " rgbdata rgbindx 1 add get 32 mul % Green",
912 " rgbdata rgbindx 2 add get 12 mul % Blue",
913 " add add 64 idiv % I = .5G + .31R + .18B",
914 " put",
915 " /rgbindx rgbindx 3 add store",
916 " } for",
917 " grays",
918 " } bind def\n",
919 /* Utility procedure for colorimage operator.
920 * This procedure takes two procedures off the
921 * stack and merges them into a single procedure
922 */
923 " /mergeprocs { % def",
924 " dup length",
925 " 3 -1 roll dup length dup 5 1 roll",
926 " 3 -1 roll add array cvx dup",
927 " 3 -1 roll 0 exch putinterval",
928 " dup 4 2 roll putinterval",
929 " } bind def\n",
930 " /colorimage { % def",
931 /* remove 'false 3' operands */
932 " pop pop",
933 " {colortogray} mergeprocs",
934 " image",
935 " } bind def",
936 /* end of 'false' case */
937 " } ifelse"
938 };
939
940 PSconst_out(txt);
941 }
942
943 /*__________________________________________________________________________
944 |
945 | PScolormap - write colormap
946 |
947 | spits out code for the colormap of the following image
948 | if !color, it spits out a mono-ized graymap
949 |
950 */
951
ARG5(int,color,int,nc,int *,rmap,int *,gmap,int *,bmap)952 static void PScolormap ARG5(int,color,
953 int,nc,
954 int *,rmap,
955 int *,gmap,
956 int *,bmap) {
957
958 int i;
959
960 /* define the colormap */
961 PSprintf("/cmap %d string def\n\n\n", nc * ((color) ? 3 : 1));
962
963 /* load up the colormap */
964 PSprintf("currentfile cmap readhexstring\n");
965
966 for (i=0; i<nc; i++) {
967 if (color)
968 PSprintf("%02x%02x%02x ", rmap[i]>>8,
969 gmap[i]>>8, bmap[i]>>8);
970 else
971 PSprintf("%02x ", MONO(rmap[i], gmap[i], bmap[i]));
972 if ((i%10) == 9)
973 PSprintf("\n");
974 }
975 PSprintf("\n");
976 PSprintf("pop pop\n"); /* lose return values from readhexstring */
977 }
978
979
980 /*__________________________________________________________________________
981 |
982 | PSrle_cmapimage - define rlecmapimage operator
983 |
984 */
985
ARG1(int,color)986 static void PSrle_cmapimage ARG1(int,color) {
987
988 static char *txt[] = {
989
990 /* rlecmapimage expects to have 'w h bits matrix' on stack */
991 "/rlecmapimage {",
992 " /buffer 1 string def",
993 " /rgbval 3 string def",
994 " /block 384 string def",
995 " { currentfile buffer readhexstring pop",
996 " /bcount exch 0 get store",
997 " bcount 128 ge",
998 " { ",
999 " 0 1 bcount 128 sub",
1000 " { currentfile buffer readhexstring pop pop"
1001 };
1002
1003 static char *txt_color[] = {
1004 " /rgbval cmap buffer 0 get 3 mul 3 getinterval store",
1005 " block exch 3 mul rgbval putinterval",
1006 " } for",
1007 " block 0 bcount 127 sub 3 mul getinterval",
1008 " }",
1009 " { ",
1010 " currentfile buffer readhexstring pop pop",
1011 " /rgbval cmap buffer 0 get 3 mul 3 getinterval store",
1012 " 0 1 bcount { block exch 3 mul rgbval putinterval } for",
1013 " block 0 bcount 1 add 3 mul getinterval",
1014 " } ifelse",
1015 " }",
1016 " false 3 colorimage",
1017 "} bind def"
1018 };
1019
1020 static char *txt_gray[] = {
1021 " /rgbval cmap buffer 0 get 1 getinterval store",
1022 " block exch rgbval putinterval",
1023 " } for",
1024 " block 0 bcount 127 sub getinterval",
1025 " }",
1026 " { ",
1027 " currentfile buffer readhexstring pop pop",
1028 " /rgbval cmap buffer 0 get 1 getinterval store",
1029 " 0 1 bcount { block exch rgbval putinterval } for",
1030 " block 0 bcount 1 add getinterval",
1031 " } ifelse",
1032 " }",
1033 " image",
1034 "} bind def"
1035 };
1036
1037 PSconst_out(txt);
1038 if (color) {
1039 PSconst_out(txt_color);
1040 } else {
1041 PSconst_out(txt_gray);
1042 }
1043 }
1044
1045
1046 /*__________________________________________________________________________
1047 |
1048 | PSwrite_bw - write B&W image
1049 |
1050 | Write the given image array 'pic' (B/W stippled, 1 byte per pixel,
1051 | 0=blk,1=wht) out as hexadecimal, max of 72 hex chars per line. If
1052 | 'flipbw', then 0=white, 1=black. Returns '0' if everythings fine,
1053 | 'EOF' if writing failed.
1054 |
1055 */
1056
ARG4(unsigned char *,pic,int,w,int,h,int,flipbw)1057 static int PSwrite_bw ARG4(unsigned char *,pic, int,w, int,h, int,flipbw) {
1058
1059 int i, j;
1060 int err=0;
1061 unsigned char outbyte, bitnum, bit;
1062
1063 outbyte = bitnum = 0;
1064 for (i=0; i<h && err != EOF; i++) {
1065 for (j=0; j<w && err != EOF; j++) {
1066 bit = *(pic++);
1067 outbyte = (outbyte<<1) | ((bit)&0x01);
1068 bitnum++;
1069
1070 if (bitnum==8) {
1071 if (flipbw)
1072 outbyte = ~outbyte & 0xff;
1073 err=PShex(outbyte, False);
1074 outbyte = bitnum = 0;
1075 }
1076 }
1077 if (bitnum) { /* few bits left over in this row */
1078 outbyte <<= 8-bitnum;
1079 if (flipbw)
1080 outbyte = ~outbyte & 0xff;
1081 err=PShex(outbyte, False);
1082 outbyte = bitnum = 0;
1083 }
1084 }
1085 err=PShex('\0', True); /* Flush the hex buffer if needed */
1086
1087 return err;
1088 }
1089
1090
1091 /*__________________________________________________________________________
1092 |
1093 | PSimage - generate image Postscript code
1094 |
1095 | Draw the image, unless there was no image, in which case an empty grey
1096 | rectangle is shown.
1097 | If anchor is set, a black border is shown around the image.
1098 | Positioning is not exactly that of Xmosaic's screen, but close enough.
1099 |
1100 */
1101
ARG2(ImageInfo *,img,int,anchor)1102 static void PSimage ARG2( ImageInfo *,img , int, anchor) {
1103
1104 int ncolors = img->num_colors;
1105 int i, j;
1106 int w = img->width;
1107 int h = img->height;
1108 unsigned char *imgp;
1109 int slen, colorps, colortype, bits;
1110 int err=0;
1111 int extra = 0;
1112
1113 imgp = img->image_data;
1114
1115 /* Isgray returns true if the nth color index is a gray value */
1116 # define Isgray(i,n) (i->reds[n]==i->greens[n] && i->reds[n]==i->blues[n])
1117 /* Is_bg returns true if the nth color index is the screen background */
1118 # define Is_bg(i,n) (i->reds[n]==bg_color.red && \
1119 i->greens[n]==bg_color.green && i->blues[n]==bg_color.blue)
1120 /* Is_fg returns true if the nth color index is the screen foreground */
1121 # define Is_fg(i,n) (i->reds[n]==fg_color.red && \
1122 i->greens[n]==fg_color.green && i->blues[n]==fg_color.blue)
1123
1124
1125 if (anchor) {
1126 /* draw an outline by drawing a slightly larger black square
1127 * below the actual image
1128 */
1129 PSprintf("gsave currentpoint %d sub translate ", h);
1130 PSprintf("0 -2 translate %d %d scale\n", w+4, h+4);
1131 PSprintf("SQ fill\n");
1132 PSprintf("grestore\n");
1133 extra = 4;
1134 }
1135
1136 if (imgp == NULL) {
1137 /* image was not available... do something instead
1138 * draw an empty square for example
1139 */
1140 PSprintf("gsave currentpoint %d sub translate", h);
1141 if (anchor)
1142 PSprintf(" 2 0 translate");
1143 else
1144 PSprintf(" 0 2 translate");
1145 PSprintf(" %d %d scale\n", w, h);
1146 PSprintf("0.9 setgray SQ fill\n");
1147 PSprintf("grestore\n");
1148 /* move currentpoint just right of image */
1149 PSprintf("%d 0 R\n", w+extra);
1150 return;
1151 }
1152
1153 /* this is a hack to see if the image is Black & White,
1154 * Greyscale or 8 bit color
1155 * assume it's bw if it has only one or two colors, both some grey's
1156 * assume it's greyscale if all the colors (>2) are grey
1157 * Images with only one color do occur too.
1158 */
1159
1160 if ((ncolors == 2 && ( (Isgray(img,0) && Isgray(img,1)) ||
1161 (Is_bg(img,0) && Is_fg(img,1)) ||
1162 (Is_fg(img,0) && Is_bg(img,1)) )) ||
1163 ncolors == 1 && (Isgray(img,0) || Is_bg(img,0) ||
1164 Is_fg(img,0))) {
1165 colortype = F_BWDITHER;
1166 slen = (w+7)/8;
1167 bits = 1;
1168 colorps = 0;
1169 } else {
1170 colortype = F_GREYSCALE;
1171 slen = w;
1172 bits = 8;
1173 colorps = 0;
1174 for (i=0; i<ncolors; i++) {
1175 if (!Isgray(img,i)) {
1176 colortype = F_REDUCED;
1177 slen = w*3;
1178 bits = 8;
1179 colorps = 1;
1180 break;
1181 }
1182 }
1183 }
1184
1185 /* build a temporary dictionary */
1186 PSprintf("20 dict begin\n\n");
1187
1188 /* define string to hold a scanline's worth of data */
1189 PSprintf("/pix %d string def\n\n", slen);
1190
1191 /* position and scaling */
1192 PSprintf("gsave currentpoint %d sub translate", h);
1193 if (anchor)
1194 PSprintf(" 2 0 translate");
1195 else
1196 PSprintf(" 0 2 translate");
1197 PSprintf(" %d %d scale\n", w, h);
1198
1199 if (colortype == F_BWDITHER) {
1200 /* 1-bit dither code uses 'image' */
1201 int flipbw = 0;
1202
1203 /* set if color#0 is 'white' */
1204 if ((ncolors == 2 &&
1205 MONO(img->reds[0], img->greens[0],img->blues[0]) >
1206 MONO(img->reds[1], img->greens[1], img->blues[1])) ||
1207 (ncolors == 1 &&
1208 MONO(img->reds[0], img->greens[0],img->blues[0]) >
1209 MONO(127, 127, 127) )) {
1210 flipbw=1;
1211 }
1212
1213 /* dimensions of data */
1214 PSprintf("%d %d %d\n", w, h, bits);
1215
1216 /* mapping matrix */
1217 PSprintf("[%d 0 0 %d 0 %d]\n\n", w, -h, h);
1218
1219 PSprintf("{currentfile pix readhexstring pop}\n");
1220 PSprintf("image\n");
1221
1222 /* write the actual image data */
1223 err = PSwrite_bw(imgp, w, h, flipbw);
1224 } else {
1225 /* all other formats */
1226 unsigned char *rleline = (unsigned char *) NULL;
1227 int rlen;
1228
1229 /* if we're using color, make sure 'colorimage' is defined */
1230 if (colorps)
1231 PScolor_image();
1232
1233 PScolormap(colorps, ncolors, img->reds, img->greens, img->blues);
1234 PSrle_cmapimage(colorps);
1235
1236 /* dimensions of data */
1237 PSprintf("%d %d %d\n", w, h, bits);
1238 /* mapping matrix */
1239 PSprintf("[%d 0 0 %d 0 %d]\n", w, -h, h);
1240 PSprintf("rlecmapimage\n");
1241
1242 rleline = (unsigned char *) malloc(w * 2);
1243 if (!rleline) {
1244 fprintf(stderr,"failed to malloc space for rleline\n");
1245 return;
1246 }
1247
1248 for (i=0; i<h && err != EOF; i++) {
1249 rlen = PSrle_encode(imgp, rleline, w);
1250 imgp += w;
1251 for (j=0; j<rlen && err != EOF; j++)
1252 err=PShex(rleline[j], False);
1253 err=PShex('\0', True); /* Flush the hex buffer */
1254 }
1255 free(rleline);
1256 }
1257
1258 /* stop using temporary dictionary */
1259 PSprintf("end\n");
1260 PSprintf("grestore\n");
1261
1262 /* move currentpoint just right of image */
1263 PSprintf("%d 0 R\n", w + extra);
1264
1265 /* forget about the macro's */
1266 # undef Isgray
1267 # undef Is_fg
1268 # undef Is_bg
1269 }
1270
1271 /*__________________________________________________________________________
1272 |
1273 | ParseTextToPSString - entry point for postscript output
1274 |
1275 | Parse all the formatted text elements from start to end
1276 | into an ascii text string, and return it.
1277 | Very like ParseTextToString() except the text is prettied up
1278 | into Postscript to show headers and the like.
1279 | space_width and lmargin tell us how many spaces
1280 | to indent lines.
1281 | Because this routine is only used to print whole documents,
1282 | some parameters are not needed at all!
1283 | Also it assumes that you are indeed printing the whole document, and
1284 | not just a selected portion of it. It therefore can assume that
1285 | only for the first page the initialization is needed, and only
1286 | the last page has the trailers. You cannot use ParseTextToPSString()
1287 | as you can use ParseTextToString() because of this initialization code.
1288 |
1289 */
1290
ParseTextToPSString(hw,elist,startp,endp,start_pos,end_pos,space_width,lmargin,fontfamily)1291 String ParseTextToPSString(hw, elist, startp, endp, start_pos, end_pos,
1292 space_width, lmargin, fontfamily)
1293 HTMLWidget hw;
1294 struct ele_rec *elist;
1295 struct ele_rec *startp;
1296 struct ele_rec *endp;
1297 int start_pos, end_pos;
1298 int space_width;
1299 int lmargin;
1300 int fontfamily;
1301 {
1302
1303 /* the fontfamily parameter is new
1304 * The font is encoded as:
1305 * 0: times (default for now)
1306 * 1: helvetica
1307 * 2: new century schoolbook
1308 * 3: lucida
1309 */
1310
1311 int xpos, ypos, epos;
1312 int height;
1313 int pagewidth;
1314 int line = -1;
1315 struct ele_rec *eptr;
1316 struct ele_rec *start;
1317 struct ele_rec *end;
1318 struct ele_rec *last;
1319 struct ele_rec *tmpptr;
1320
1321 if (startp == NULL)
1322 return(NULL);
1323
1324
1325 /*
1326 * Get the foreground and background colors so we can check later
1327 * for black&white documents
1328 */
1329 {
1330 unsigned long fg_pixel, bg_pixel;
1331
1332
1333 XtVaGetValues (hw->html.view,
1334 #ifdef MOTIF
1335 XtNforeground, &fg_pixel,
1336 #endif
1337 XtNbackground, &bg_pixel,
1338 NULL);
1339 #ifndef MOTIF
1340 XtVaGetValues ((Widget)hw,
1341 XtNforeground, &fg_pixel,
1342 NULL);
1343 #endif
1344 fg_color.pixel = fg_pixel;
1345 bg_color.pixel = bg_pixel;
1346 XQueryColor (XtDisplay (hw->html.view),
1347 DefaultColormap (XtDisplay (hw->html.view),
1348 DefaultScreen (XtDisplay (hw->html.view))),
1349 &fg_color);
1350 XQueryColor (XtDisplay (hw->html.view),
1351 DefaultColormap (XtDisplay (hw->html.view),
1352 DefaultScreen (XtDisplay (hw->html.view))),
1353 &bg_color);
1354 }
1355
1356 /* this piece of code is needed if the user selects a portion
1357 * of the document with the mouse.
1358 * I think it will never be used, but I left it in anyway. F.
1359 */
1360 if (SwapElements(startp, endp, start_pos, end_pos)) {
1361 start = endp;
1362 end = startp;
1363 epos = start_pos;
1364 start_pos = end_pos;
1365 end_pos = epos;
1366 } else {
1367 start = startp;
1368 end = endp;
1369 }
1370
1371 /* Calculate the number of Postscript points per pixel of current
1372 * screen, and the height of the page in pixels (used in figuring
1373 * when we've hit the bottom of the page).
1374 */
1375 Points_Pixel = 72.0 / GetDpi(hw);
1376 #ifdef OLD
1377 pagewidth = hw->html.doc_width;
1378 #else /* gustaf fix */
1379 pagewidth = hw->html.view_width; /* seems more reasonable */
1380 #endif /* gustaf fix */
1381
1382 /* reduce the scaling if the width used for formatting is greater
1383 * than 8 * 72 pixels (8 inch)
1384 * In theory, this is not what you want for A4 paper (only 8.27 inch
1385 * wide), but I guess that the hw->html.doc_width includes some
1386 * left and right margins, so it seems to work in practice.
1387 */
1388 if (pagewidth > PAGE_WIDTH)
1389 Points_Pixel = Points_Pixel * (float) PAGE_WIDTH / pagewidth;
1390 Pixels_Page = (int) (PAGE_HEIGHT / Points_Pixel);
1391
1392
1393 PSinit();
1394 PSheader(hw->html.title, fontfamily);
1395 PSnewpage();
1396
1397 last = start;
1398 eptr = start;
1399
1400 while ((eptr != NULL) && (eptr != end)) {
1401 /* Skip the special internal text added for multi-page
1402 * documents.
1403 */
1404 if (eptr->internal == True) {
1405 if (eptr->type == E_LINEFEED) {
1406 PS_page_offset += eptr->line_height;
1407 }
1408 eptr = eptr->next;
1409 continue;
1410 }
1411 /* check if this is a newline */
1412 if (line != eptr->line_number) {
1413 /* calculate max height */
1414 height = 0;
1415 line = eptr->line_number;
1416 tmpptr = eptr;
1417 while (tmpptr != NULL && tmpptr->line_number == line) {
1418 if (tmpptr->line_height > height)
1419 height = tmpptr->line_height;
1420 tmpptr = tmpptr->next;
1421 }
1422 ypos = eptr->y - PS_page_offset ;
1423 xpos = eptr->x - lmargin;
1424 if (xpos < 0)
1425 xpos = 0;
1426
1427 /* check if line fits completly on page */
1428 if (ypos + height > PS_start_y + Pixels_Page) {
1429 PS_start_y = ypos;
1430 PSshowpage();
1431 PSnewpage();
1432 }
1433 PSmoveto( xpos, ypos);
1434 }
1435
1436 switch(eptr->type) {
1437
1438 case E_TEXT: {
1439 String tptr;
1440 int ascent;
1441
1442 if (eptr == start)
1443 tptr = (String)(eptr->edata + start_pos);
1444 else
1445 tptr = (String)eptr->edata;
1446
1447 PSfont(hw, eptr->font, fontfamily); /* set font */
1448 if (PS_fontascent == 0)
1449 ascent = eptr->font->ascent;
1450 else
1451 ascent = PS_fontascent;
1452 PSmove_offset(eptr->y_offset + ascent);
1453 PStext(tptr, eptr->underline_number); /* insert text */
1454 break;
1455 }
1456
1457 case E_BULLET: {
1458 int width;
1459 int offset;
1460
1461 PSfont(hw, eptr->font, fontfamily);
1462 width = eptr->font->max_bounds.lbearing +
1463 eptr->font->max_bounds.rbearing;
1464 /* the next line is a hack to get a good position of the
1465 * bullet in most practical cases, otherwise the
1466 * bullet may appear just a bit too low (for large fonts)
1467 * What is does is to compare the lineheight with
1468 * the lineheight of the next element, to correct
1469 * for the possibly too large y_offset
1470 */
1471 if (eptr->next != NULL && (eptr->next->type == E_TEXT
1472 || eptr->next->type == E_IMAGE))
1473 offset = eptr->line_height -
1474 eptr->next->line_height +
1475 eptr->y_offset +
1476 eptr->next->font->ascent;
1477 else
1478 offset = eptr->y_offset + eptr->font->ascent;
1479
1480 PSmove_offset(offset - width/4);
1481 PSbullet(eptr->indent_level, eptr->line_height);
1482 break;
1483 }
1484
1485 case E_IMAGE: {
1486
1487 PSmove_offset(eptr->y_offset);
1488 PSimage(eptr->pic_data ,(eptr->anchorHRef != NULL));
1489 break;
1490 }
1491
1492 case E_LINEFEED: {
1493 break;
1494 }
1495 case E_HRULE: {
1496 PSmove_offset(eptr->y_offset);
1497 PShrule(hw->html.doc_width);
1498 break;
1499 }
1500 }
1501 last = eptr;
1502 eptr = eptr->next;
1503 }
1504
1505 PSshowpage();
1506 PStrailer();
1507
1508 return( PS_string);
1509 }
1510
1511