This repository has been archived on 2024-01-04. You can view files and clone it, but cannot push or open issues or pull requests.
ncsa-mosaic/libhtmlw/HTML-PSformat.c.org

49 KiB
Raw Permalink Blame History

/* HTML-PSformat.c - Module for NCSA's Mosaic software

  • Purpose: to parse Hypertext widget contents into appropriate PostScript
  • Author: Ameet A. Raval & Frans van Hoesel & Andrew Ford
  • (aar@gfdl.gov & hoesel@chem.rug.nl).
  • send bugreports to hoesel@chem.rug.nl
  • Institution: for Ameet A. Raval:
  • Geophysical Fluid Dynamics Laboratory,
  • National Oceanic and Atmospheric Administration,
  • U.S. Department of Commerce
  • P.O. Box 308
  • Princeton, NJ 08542
  • for Frans van Hoesel:
  • Xtreme graphics software
  • Herepoortenmolendrift 36
  • 9711 DH Groningen
  • The Netherlands
  • also:
  • Andrew Ford
  • Independent Software Consultant
  • 30 Upper Cheltenham Place,
  • Montpelier, Bristol, BS6 5HR, GB
  • E-mail: andrew@icarus.demon.co.uk
  • Date: 1 aug 1993
  • Modification: 8 nov 1993
  • o added support for bold/italics courier
  • o removed unused or no longer needed stuff
  • o fixed the font alignment problem
  • 23 nov 1993
  • o added support for horizontal ruler
  • o on request of Ameet, added a specific
  • line about whome to send bugreports to
  • 15 jun 1994
  • o add headers, footers and footnotes to convey
  • title, page number, url of document, date (of
  • printing) and urls of links.
  • o use A4 or US Letter size paper (currently hard coded)
  • 9 may 1995 (Andrew Ford)
  • o general overhaul
  • Copyright: This work is the product of the United States Government,
  • and is precluded from copyright protection. It is hereby
  • released into the public domain.
  • WE MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
  • ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
  • WARRANTY. WE SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE
  • USERS OF THIS SOFTWARE.
  • pieces of code are taken from xvps by kind
  • permission of John Bradley.
  • To-do:
    • printing of tables and forms fields (and any new features that appear)

*/ #include "../config.h" #include <varargs.h>

#include <string.h> #include <stdio.h> #include <ctype.h> #include <math.h> #ifdef bsdi #include <sys/malloc.h> #else #ifndef VAXC #include <malloc.h> #endif #endif #include <time.h> #include <sys/types.h> #include "HTMLP.h"

* Fix thanks to robm. * #ifdef __alpha #include <Xm/VaSimpleP.h> #endif

#define CR '\015' #define LF '\012'

#ifndef DISABLE_TRACE extern int htmlwTrace; #endif

extern int SwapElements();

#define USLETTER 0 #define A4 1

#if !defined(DEFAULT_PAGE_SIZE) #define DEFAULT_PAGE_SIZE USLETTER #endif

#define F_FULLCOLOR 0 #define F_GREYSCALE 1 #define F_BWDITHER 2 #define F_REDUCED 3

#define L_PAREN '(' #define R_PAREN ')' #define B_SLASH '\\' #define MAX_ASCII '\177'

* MONO returns total intensity of r,g,b components .33R+ .5G+ .17B * #define MONO(rd,gn,bl) (((rd)*11 + (gn)*16 + (bl)*5) >> 13)

/* PSconst_out outputs to the postscript buffer an array of constant

  • strings

*/ #define PSconst_out(txt) { \ int n=(sizeof txt)/(sizeof txt[0]); \ int i; \ for (i=0; i<n; i++) { \ PSprintf("%s\n", txt[i]) ; \ } \ }

* STREQ tests whether two strings are equal. * #define STREQ(a, b) (strcmp((a), (b)) == 0)

* for regular-font, bold-font, italic-font, fixed-font * typedef enum { RF, BF, IF, FF, FB, FI } PS_fontstyle;

static int PS_size, PS_len, PS_offset, PS_curr_page, PS_start_y, PS_hexi; static int PS_page_offset; static char *PS_string; static float Points_Pixel; static int Pixels_Page; static PS_fontstyle PS_oldfn = RF; static int PS_fontascent = 0; static int PS_oldfs = 0;

static XColor fg_color, bg_color;

static int footnote_space = 8; * Space from main text to footnotes * static int footnote_ptsize = 8; * Point size for footnote text * static int cur_ftn_no; * Current footnote number * static int n_saved_ftns; * Number of saved footnotes on page * static int ftn_array_size=0; * Size of allocated footnote array * static char *footnotes=NULL; / Pointer to array of footnote pointers */

typedef struct { double page_height; double page_width; double top_margin; double bot_margin; double left_margin; double right_margin; double text_height; double text_width; } PAGE_DIMENS_T;

#define INCH 72 #define MM INCH / 25.4

PAGE_DIMENS_T page_dimens; PAGE_DIMENS_T a4_page_dimens = { 297 * MM, 210 * MM, 20 * MM, 20 * MM, 20 * MM, 20 * MM };

PAGE_DIMENS_T us_letter_page_dimens = { 11 * INCH, * page_height * 8.5 * INCH, * page_width * 0.9 * INCH, * top_margin * 0.7 * INCH, 0.9 * INCH, 0.9 * INCH };

* Globals to get button value in print dialog swp/AF *

int HTML_Print_Headers = 1; * Flag whether page headers enabled * int HTML_Print_Footers = 1; * Flag whether footnote printing enabled *

* Paper format (currently either A4 or letter). This should be generalized. *

int HTML_Print_Paper_Size_A4 = DEFAULT_PAGE_SIZE;

extern int installed_colormap; extern Colormap installed_cmap;

/*

  • GetDpi - return Dots-per-inch of the screen
  • calculate the pixel density in dots per inch on the current widget
  • screen

*/ static float GetDpi(HTMLWidget hw) { Screen *s = XtScreen(hw); float dpi;

dpi = 25.4 * WidthOfScreen(s) / WidthMMOfScreen(s); if (dpi<1.0 || dpi>10000.0) dpi = 72.0; return dpi; }

/*

  • PSprintf - dynamic string concatenation function.
  • In successive calls, the formatted string will be appended to the global
  • output string Sp.
  • It assumes that on each call, the length of the text appended to Sp
  • is less than 1024.
  • The format string is used as in printf, so you can use additional
  • arguments.
  • When successful, PSprintf returns the number of characters printed
  • in this call, otherwise it returns EOF (just as printf does)

*/ static int PSprintf(format, va_alist) char* format; va_dcl { int len; char *s; va_list args;

if (PS_size - PS_len < 1024) { PS_size += 1024; if ((s = (char *) realloc(PS_string, PS_size)) == NULL) { #ifndef DISABLE_TRACE if (htmlwTrace) { fprintf(stderr, "PSprintf malloc failed\n"); } #endif return(EOF); } PS_string = s; } va_start(args); len = vsprintf(PS_string+PS_len, format, args); /* this is a hack to make it work on systems were vsprintf(s,…)

  • returns s, instead of the len.

*/ if (len != EOF && len != 0) PS_len += strlen(PS_string+PS_len); va_end(args); return(len); }

/*

  • PShex - output hex byte
  • Append the byte "val" to an internal string buffer in hexadecimal
  • format. If the argument "flush" is True, or if the buffer has filled
  • up, flush the buffer to the larger postscript output buffer (using
  • PSprintf).

*/ static int PShex(unsigned char val, int flush) { static unsigned char hexline[80]; static char digit[] = "0123456789abcdef";

if (!flush) { hexline[PS_hexi++] = (char) digit[((unsigned) val >> (unsigned) 4) & (unsigned) 0x0f]; hexline[PS_hexi++] = (char) digit[(unsigned) val & (unsigned) 0x0f]; }

* Changed from ">78" to ">77" on advice of debra@info.win.tue.nl (Paul De Bra). *

if ((flush && PS_hexi) || (PS_hexi>77)) { hexline[PS_hexi] = '\0'; PS_hexi=0; return (PSprintf("%s\n", hexline)); } return (0); }

/*

  • PSfont - change font
  • change local font in buf to "font"
  • fontfamily indicates if the overall style is times, helvetica, century
  • schoolbook or lucida.

*/ static void PSfont(HTMLWidget hw, XFontStruct *font, int fontfamily) { PS_fontstyle fn; int style, size; int fs;

static PS_fontstyle fontstyle[17] = { RF, IF, BF, FF, BF, BF, BF, BF, BF, BF, IF, FF, FF, FB, FI, FB, FI };

static char fnchar[6][3] = {"RF", "BF", "IF", "FF", "FB", "FI"};

/* fontsizes as set in gui.c and in HTML.c (listing font is only

  • defined in HTML.c)

*/ static int fontsizes[4][3][17] = { * times font sizes * { {14, 14, 14, 14, 18, 17, 14, 12, 10, 8, 14, 12, 12, 14, 14, 12, 12}, {17, 17, 17, 17, 24, 18, 17, 14, 12, 10, 17, 14, 12, 17, 17, 14, 14}, {20, 20, 20, 20, 25, 24, 20, 18, 17, 14, 20, 18, 12, 20, 20, 18, 18} }, * helvetica sizes * { {14, 14, 14, 14, 18, 17, 14, 12, 10, 8, 14, 12, 12, 14, 14, 12, 12}, {17, 17, 17, 17, 24, 18, 17, 14, 12, 10, 17, 14, 12, 17, 17, 14, 14}, {20, 20, 20, 20, 25, 24, 20, 18, 17, 14, 20, 18, 12, 20, 20, 18, 18} }, * new century schoolbook sizes * { {14, 14, 14, 14, 18, 17, 14, 12, 10, 8, 14, 12, 12, 14, 14, 12, 12}, {18, 18, 18, 18, 24, 18, 17, 14, 12, 10, 18, 14, 12, 18, 18, 14, 14}, {20, 20, 20, 20, 25, 24, 20, 18, 17, 14, 20, 18, 12, 20, 20, 18, 18} }, * lucida sizes * { {14, 14, 14, 14, 18, 17, 14, 12, 11, 10, 14, 12, 12, 14, 14, 12, 12}, {17, 17, 17, 17, 24, 18, 17, 14, 12, 10, 17, 14, 12, 17, 17, 14, 14}, {20, 20, 20, 20, 25, 24, 20, 18, 17, 14, 20, 18, 12, 20, 20, 18, 18} } };

/* next is for each fontfamily the ascent value as given by the

  • medium sized bold x-font (the regular font has the same
  • ascent value for both the medium and the large size Century
  • font).
  • it is use in the check for the fontsize (small, medium, large)

*/ static int medium_fontascent[4] = { 14, 14, 16, 15 };

/* for each fontfamily, for each fontsize, and for each font style

  • give the ascent value, so the output from Postscript is correct.
  • If the value is given between parenthesis, then it is different
  • from the value as stored in the x-font.
  • Note that this is a fix, and need to be changed, if the browser
  • is fixed (in the current version 1.2 the baseline of various fonts
  • is not aligned very well).

*/ static int fontascent[4][3][17] = { *rg, itl, bld, fix, h1, h2, h3, h4, h5, h6, add, pla, lis, fixbold, fixital, plabold, plaital, * * times * { {12, 11, 12, 10, 15, 14, 12, 10, 8, 6, 11, 9, 10, 10, 10, 9, 9}, {13, 13, 14, 12, 20, 15, 14, 12, 10, 8, 13, 10, 10, 12, 12, 10, 10}, {16, 15, 15, 13, 21, 20, 15, 15, 14, 12, 15, 13, 10, 13, 13, 13, 13} }, * helvetica * { {12, 12, 12, 10, 15, 14, 12, 10, 9, 7, 12, 9, 10, 10, 10, 9, 9}, {14, 14, 14, 12, 22, 15, 14, 12, 10, 9, 14, 10, 10, 12, 12, 10, 10}, {16, 16, 16, 13, 22, 22, 16, 15, 14, 12, 16, 13, 10, 13, 13, 13, 13} }, * new century schoolbook * { {12, 12, 13, 10, 16, 14, 13, 10, 9, 7, 12, 9, 10, 10, 10, 9, 9}, {16, 14, 16, 13, 22, 16, 14, 13, 10, 9, 14, 10, 10, 13, 13, 10, 10}, {17, 16, 17, 13, 22, 22, 17, 16, 14, 13, 16, 13, 10, 13, 13, 13, 13} }, * lucida bright * { {11, 11, 11, 11, 15, 14, 11, 10, 9, 7, 11, 9, 10, 11, 10, 9, 9}, {14, 15, 14, 13, 20, 15, 14, 11, 10, 7, 15, 11, 10, 13, 13, 11, 10}, {17, 17, 17, 16, 21, 20, 17, 15, 14, 11, 17, 14, 10, 16, 13, 14, 13} } };

* NULL case - reflush old font or the builtin default: * if ((hw = NULL) || (font = NULL)) { if (PS_oldfs != 0) PSprintf( "%2s %d SF\n", fnchar[PS_oldfn], PS_oldfs); return; } * added the next line in case xmosaic version 199.4 has more fonts * style = 3;

if (font == hw->html.font) { style = 0; } else if (font == hw->html.italic_font) { style = 1; } else if (font == hw->html.bold_font) { style = 2; } else if (font == hw->html.fixed_font) { style = 3; } else if (font == hw->html.header1_font) { style = 4; } else if (font == hw->html.header2_font) { style = 5; } else if (font == hw->html.header3_font) { style = 6; } else if (font == hw->html.header4_font) { style = 7; } else if (font == hw->html.header5_font) { style = 8; } else if (font == hw->html.header6_font) { style = 9; } else if (font == hw->html.address_font) { style = 10; } else if (font == hw->html.plain_font) { style = 11; } else if (font == hw->html.listing_font) { style = 12; } else if (font == hw->html.fixedbold_font) { style = 13; } else if (font == hw->html.fixeditalic_font) { style = 14; } else if (font == hw->html.plainbold_font) { style = 15; } else if (font == hw->html.plainitalic_font) { style = 16; }

* check size, by looking at the size of the regular font * size = 1; if (hw->html.bold_font->ascent > medium_fontascent[fontfamily]) { * large font * size = 2; } else if (hw->html.bold_font->ascent < medium_fontascent[fontfamily]) { * small font * size = 0; } fn = fontstyle[style]; fs = fontsizes[fontfamily][size][style]; PS_fontascent = fontascent[fontfamily][size][style];

if (fn != PS_oldfn || fs != PS_oldfs) { PSprintf( "%2s %d SF\n", fnchar[fn], fs); PS_oldfn=fn, PS_oldfs=fs; } }

/*

  • PSshowpage - end of page function
  • show the current page and restore any changes to the printer state.
  • Any accumulated footnotes are output and the outstanding footnote count
  • reset to zero. Footnotes are preceded by a footnote rule and each footnote
  • is consists of a raised mark and the footnote text (i.e. the url). The mark
  • is in a smaller font than the text. The ideas are filched from LaTeX.

*/ static void PSshowpage(void) { PSprintf("restore\n"); if (n_saved_ftns > 0) { int i;

PSprintf("gsave 0.2 setlinewidth newpath %.2f %.2f M %.2f 0 RL stroke\n", page_dimens.left_margin, (page_dimens.bot_margin + (footnote_ptsize * n_saved_ftns) + 4), (page_dimens.text_width * 0.4)); for (i = 0; n_saved_ftns; n_saved_ftns, i++) { PSprintf("newpath %.2f %.2f M RF %.2f SF (%d) S 3 -2 R RF %d SF (%s) S\n", page_dimens.left_margin, page_dimens.bot_margin + 5 + (n_saved_ftns - 1) * footnote_ptsize, (0.7 * footnote_ptsize), cur_ftn_no - n_saved_ftns, footnote_ptsize, footnotes[i]); } PSprintf("grestore\n"); } PSprintf("showpage\n"); }

/*

  • PSnewpage - begin a fresh page
  • increment the page count and handle the structured comment
  • conventions

*/ static void PSnewpage(void) { PS_curr_page++;

/* the PostScript reference Manual states that the Page: Tag should have a label and a ordinal; otherwise programs like psutils fail -gustaf */

PSprintf("%%%%Page: %d %d\n", PS_curr_page, PS_curr_page); PSprintf("save\n"); if (HTML_Print_Headers) PSprintf("%d ", PS_curr_page); PSprintf("NP\n"); PSfont( NULL, NULL, 0); * force re-flush of last font used * }

/*

  • PSinit_latin1 - handle ISO encoding
  • print out initializing PostScript text for ISO Latin1 font encoding
  • This code is copied from the Idraw program (from Stanford's InterViews
  • package), courtesy of Steinar Kjaernsr|d, steinar@ifi.uio.no

*/ static void PSinit_latin1(void) {

static char *txt[] = {

"/reencodeISO {", "dup dup findfont dup length dict begin", "{ 1 index /FID ne { def }{ pop pop } ifelse } forall", "/Encoding ISOLatin1Encoding D", "currentdict end definefont", "} D", "ISOLatin1Encoding [", ".notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef", ".notdef.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef", ".notdef.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef", ".notdef.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef", "/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright", "/parenleft/parenright/asterisk/plus/comma/minus/period/slash", "/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon", "/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N", "/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright", "/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m", "n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde", ".notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef", ".notdef.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef", ".notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve", "/dotaccent/dieresis.notdef/ring/cedilla/.notdef/hungarumlaut", "/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar", "/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot", "/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior", "/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine", "/guillemotright/onequarter/onehalf/threequarters/questiondown", "/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla", "/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex", "/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis", "/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute", "/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis", "/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave", "/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex", "/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis", "/yacute/thorn/ydieresis", "] D", "[RF BF IF FF FB FI] {reencodeISO D} forall" };

PSconst_out(txt); }

/*

  • PSinit - initialize Postscript output
  • does the initialization per html document

*/ static void PSinit(void) { PS_size = PS_len = PS_offset = PS_hexi = PS_page_offset = 0; PS_start_y = 0; PS_string = (char *) malloc(1); PS_oldfs = 0; PS_oldfn = RF; PS_curr_page = 0 ; n_saved_ftns = 0; cur_ftn_no = 1; }

/*

  • PSheader - initialize Postscript output
  • Prints out the prolog. The following PostScript macros are defined
  • D def - define a macro
  • E exch - exhange parameters
  • M moveto
  • R rmoveto
  • L lineto
  • RL rlineto
  • SQ draw a unit square
  • U underline a string
  • B draw a bullet
  • OB draw an open bullet
  • HR draw a horizontal rule
  • SF set font
  • RF roman font (dependent on font family)
  • BF bold font (dependent on font family)
  • IF italic font (dependent on font family)
  • FF fixed font (courier)
  • FB fixed bold font (courier bold)
  • FI fixed italic font (courier oblique)
  • nstr buffer for creating page number string
  • pageno literal "Page "
  • url URL of document
  • title title of document
  • date date modified/printed

*/ static void PSheader(char *title, int font, char *url, char *time_str) { static char *notitle="Untitled"; int set_to_null=0; static char fontname[] = { / in order: regular, bold, italic */ "Times-Roman", "Times-Bold", "Times-Italic", "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "NewCenturySchlbk-Roman", "NewCenturySchlbk-Bold", "NewCenturySchlbk-Italic", /* this is a nasty trick, I have put Times in place of

  • Lucida, because most printers don't have Lucida font

*/ "Times-Roman", "Times-Bold", "Times-Italic" * "Lucida", "Lucida-Bold", "Lucida-Italic" * };

static char *txt[] = { "/M {moveto} D", "/S {show} D", "/R {rmoveto} D", "/L {lineto} D", "/RL {rlineto} D", "/SQ {newpath 0 0 M 0 1 L 1 1 L 1 0 L closepath} D", "/U {gsave currentpoint currentfont /FontInfo get /UnderlinePosition get", " 0 E currentfont /FontMatrix get dtransform E pop add newpath moveto", " dup stringwidth rlineto stroke grestore S } D", "/B {/r E D gsave -13 0 R currentpoint ", " newpath r 0 360 arc closepath fill grestore } D", "/OB {/r E D gsave -13 0 R currentpoint ", " newpath r 0 360 arc closepath stroke grestore } D", "/HR {/l E D gsave 0 1 RL l 0 RL 0 -1 RL l neg 0 RL stroke grestore } D", "/SF {E findfont E scalefont setfont } D", "/FF {/Courier } D", "/FB {/Courier-Bold } D", "/FI {/Courier-Oblique } D" };

char time_buf[40]; time_t clock = time(NULL);

#if !defined(VMS) || defined (__DECC) strftime(time_buf, sizeof(time_buf), "Printed %a %b %e %T %Y", localtime(&clock)); #else sprintf(time_buf,"Printed %s",asctime(localtime(&clock))); #endif

* Always show the print date SWP * time_str = time_buf;

/* if (!time_str || (time_str[0] == '\0')) { time_str = time_buf; } */ PSprintf("%%!PS-Adobe-1.0\n"); PSprintf("%%%%Creator: NCSA Mosaic, Postscript by Ameet Raval, Frans van Hoesel\n"); PSprintf("%%%% and Andrew Ford\n");

if (!title) { title=notitle; set_to_null=1; }

{ char *tmp; for (tmp = title; *tmp; tmp++) if (*tmp = CR || *tmp = LF) *tmp = ' '; PSprintf("%%%%Title: %s\n", title); }

PSprintf("%%%%CreationDate: %s\n", time_buf + 8); PSprintf("%%%%Pages: (atend)\n"); PSprintf("%%%%PageOrder: Ascend\n"); PSprintf("%%%%BoundingBox: %d %d %d %d\n", (int)page_dimens.left_margin, (int)(page_dimens.bot_margin - 12), (int)(page_dimens.left_margin + page_dimens.text_width + 0.5), (int)(page_dimens.bot_margin + page_dimens.text_height + 12.5)); PSprintf("%%%%DocumentFonts: %s %s %s Courier Courier-Bold Courier-Oblique\n", fontname[font*3], fontname[font*3+1], fontname[font*3+2]); PSprintf("%%%%EndComments\n"); PSprintf("save /D {def} def /E {exch} D\n"); PSprintf("/RF {/%s} D\n", fontname[font*3]); PSprintf("/BF {/%s} D\n", fontname[font*3+1]); PSprintf("/IF {/%s} D\n", fontname[font*3+2]); PSprintf("/nstr 6 string D /pgno (Page ) D\n"); PSprintf("/url (%s) D\n", url); PSprintf("/title (%s) D\n", title); PSprintf("/date (%s) D\n", time_str); PSconst_out(txt);

* Output the newpage definition. *

PSprintf("/NP {"); if (HTML_Print_Headers) { PSprintf("gsave 0.4 setlinewidth\n"); PSprintf(" newpath %.2f %.2f M %.2f 0 RL stroke", page_dimens.left_margin, (page_dimens.bot_margin + page_dimens.text_height), page_dimens.text_width); PSprintf(" newpath %.2f %.2f M %.2f 0 RL stroke\n", page_dimens.left_margin, page_dimens.bot_margin, page_dimens.text_width); PSprintf(" BF 12 SF %.2f %.2f M (%s) S\n", page_dimens.left_margin, (page_dimens.bot_margin + page_dimens.text_height + 6), title); PSprintf(" nstr cvs dup stringwidth pop pgno stringwidth pop add\n"); PSprintf(" %.2f E sub %.2f M pgno S S\n", (page_dimens.left_margin + page_dimens.text_width), (page_dimens.bot_margin + page_dimens.text_height + 6)); PSprintf(" BF 10 SF %.2f %.2f M (%s) S\n", page_dimens.left_margin, page_dimens.bot_margin - 12, url); PSprintf(" (%s) dup stringwidth pop %.2f E sub %.2f M S grestore\n", time_str, page_dimens.left_margin + page_dimens.text_width, page_dimens.bot_margin - 12); } PSprintf(" %.2f %.2f translate %.5f %.5f scale } D\n", page_dimens.left_margin, page_dimens.bot_margin + page_dimens.text_height, Points_Pixel, Points_Pixel); PSinit_latin1();

PSprintf("%%%%EndProlog\n");

if (set_to_null) { title=NULL; } }

/*

  • PStrailer - write postscript trailer

*/ static void PStrailer(void) {

PSprintf("%%%%Trailer\n"); PSprintf("restore\n"); PSprintf("%%%%Pages: %d\n", PS_curr_page); if (footnotes) { free(footnotes); footnotes = NULL; ftn_array_size = 0; } }

/*

  • PSmoveto - move to new x,y location
  • if the Y value does not fit on the current page, begin a new page
  • (I think in the current implementation, this never happens)

*/ static void PSmoveto(int x, int y) { if (y > PS_start_y + Pixels_Page) { PS_start_y = y; PSshowpage(); PSnewpage(); } PS_offset = 0; PSprintf( "%d %d M\n", x, -(y - PS_start_y)); }

/*

  • PSmove_offset - set Y-offset
  • do a relative vertical move, whenever the offset changes

*/ static void PSmove_offset(int offset) { if (offset != PS_offset) { PSprintf("0 %d R\n", PS_offset - offset ); PS_offset = offset; } }

/*

  • Return an indication of whether or not the current element has a footnote.
  • an element has a footnote if it is text or an image and its anchorHRef is not null.
  • If the element is a textual element with an anchorHRef, that has been split across
  • lines then it should be followed by a linefeed element and a text element with the
  • same anchorHRef. In this case say that the element doesn't have a footnote so as
  • to avoid duplicate footnotes.

*/ static int has_footnote(struct ele_rec *el) { int rc = 0; struct ele_rec *next; char *anchorHRef;

if (el == NULL) { return 0; }

anchorHRef = el->anchorHRef;

if (anchorHRef != NULL) { switch (el->type) { case E_TEXT: case E_IMAGE: for (next = el->next; el; el = next, next = el->next) { if (next == NULL) { rc = 1; break; } else if (next->anchorHRef == NULL) { rc = 1; break; } else if (!STREQ(next->anchorHRef, anchorHRef)) { rc = 1; break; } else if ( (next->type == E_TEXT)

(next->type == E_IMAGE))

{ rc = 0; break; } } break;

default: break; } } return rc; }

/*

  • PSfootnote - output a footnote mark and store the footnote
  • the footnote mark is placed at the current point, enclosed in a gsave/grestore
  • pair so that the position of the following output is not affected.
  • The reference is stored in a malloced array (which may need to be expanded), to
  • be output at the end of the page.

*/ static void PSfootnote(char *href, double height) { PSprintf("gsave 0 %.2f R RF %d SF (%d) S grestore\n", height, footnote_ptsize, cur_ftn_no++);

if (n_saved_ftns == ftn_array_size) { ftn_array_size += 16; if (!footnotes) { footnotes = (char **)calloc(ftn_array_size,sizeof(char *)); } else { footnotes = (char **)realloc((void *)footnotes, (ftn_array_size * sizeof(char *))); } if (footnotes == NULL) { #ifndef DISABLE_TRACE if (htmlwTrace) { fprintf(stderr, "PSfootnote realloc failed\n"); } #endif

return; } }

footnotes[n_saved_ftns++] = href; }

/*

  • PStext - output text
  • show text "t", and protect special characters if needed
  • if Underline is non-zero, the text is underlined.

*/ static void PStext(HTMLWidget hw, struct ele_rec *eptr, int fontfamily, String s) { String s2; String stmp; unsigned char ch; int underline = eptr->underline_number; int ascent;

PSfont(hw, eptr->font, fontfamily); * set font * if (PS_fontascent == 0) ascent = eptr->font->ascent; else ascent = PS_fontascent; PSmove_offset(eptr->y_offset + ascent);

* Allocate a string long enough to hold the original string with every character stored as an octal escape (worst case scenario). *

s2 = (String) malloc(strlen(s) * 4 + 1); if (s2 == NULL) { #ifndef DISABLE_TRACE if (htmlwTrace) { fprintf(stderr, "PStext malloc failed\n"); } #endif

return; }

/* For each char in s, if it is a special char, insert "\"

  • into the new string s2, then insert the actual char

*/ for (stmp = s2; (ch = *s++) != '\0';) { if ((ch = L_PAREN) || (ch = R_PAREN) || (ch == B_SLASH)) { *stmp++ = B_SLASH; *stmp++ = ch; } else if (ch > (unsigned char) MAX_ASCII) { * convert to octal * *stmp++ = B_SLASH; *stmp++ = ((ch >> 6) & 007) + '0'; *stmp++ = ((ch >> 3) & 007) + '0'; *stmp++ = (ch & 007) + '0'; } else { *stmp++ = ch; } } *(stmp) = '\0'; PSprintf("(%s)%c\n", s2, (underline)?'U':'S'); if (HTML_Print_Footers && has_footnote(eptr)) { PSfootnote(eptr->anchorHRef, 0.7 * ascent); } free(s2); }

/*

  • PSbullet - output a bullet
  • The bullet is normally filled, except for a bullet with an indent level
  • of two. The size of the higher level bullets is just somewhat smaller

*/ static void PSbullet(HTMLWidget hw, struct ele_rec *eptr, int fontfamily) { int width = ( eptr->font->max_bounds.lbearing

  • eptr->font->max_bounds.rbearing);

int offset = eptr->y_offset + eptr->font->ascent; int level = eptr->indent_level; double size = eptr->line_height / 5.5;

if (size < 1.1) size = 1.1; if (level > 2) size /= 1.33333;

/* the next line is a hack to get a good position of the

  • bullet in most practical cases, otherwise the
  • bullet may appear just a bit too low (for large fonts)
  • What is does is to compare the lineheight with
  • the lineheight of the next element, to correct
  • for the possibly too large y_offset

*/

if ( (eptr->next != NULL) && ( (eptr->next->type == E_TEXT)

(eptr->next->type == E_IMAGE)))

{ offset += (eptr->line_height - eptr->next->line_height); }

PSfont(hw, eptr->font, fontfamily); PSmove_offset(offset - width/4); PSprintf(" %f %s\n", size, (level == 2) ? "OB" : "B"); }

/*

  • PShrule - draw a horizontal line with the given width
  • nothing special, just draw a line, from the current position to
  • the right side of the paper.

*/ static void PShrule(HTMLWidget hw, struct ele_rec *eptr, int fontfamily) { int length = hw->html.doc_width;

PSmove_offset(eptr->y_offset); PSprintf("%d HR\n", length); }

/*

  • PStable - draw a table
  • Currently just draw a box of the dimensions of the table.

*/ static void PStable(HTMLWidget hw, struct ele_rec *eptr, int fontfamily) { struct table_rec *tptr = eptr->table_data; int width = tptr->width; int height = tptr->height;

#if 0 PSmove_offset(eptr->y_offset); PSprintf("gsave currentpoint %d sub translate ", height); PSprintf("%d %d scale\n", width, height); PSprintf("SQ stroke\n"); PSprintf("grestore\n"); #endif }

/*

  • PSwidget - draw a widget (form field)
  • Currently just draw a grey box of the dimensions of the field.
  • This is nowhere near complete but is a first step.
  • The widget record type field gives the type of field:
  • 0 textfield
  • 1 checkbox
  • 2 radiobox
  • 3 pushbutton
  • 4 password
  • 5 option menu

*/ static void PSwidget(HTMLWidget hw, struct ele_rec *eptr, int fontfamily) { struct wid_rec *wptr = eptr->widget_data; int w = wptr->width; int h = wptr->height;

#if 1 * Comment out? * PSmove_offset(eptr->y_offset); PSprintf("gsave currentpoint %d sub translate ", h); PSprintf("%d %d scale\n", w, h); PSprintf("SQ 0.9 setgray fill\n"); PSprintf("grestore\n"); #endif }

/*

  • PSrle_encode - perform run length encoding
  • does the run-length encoding. This is done to reduce the file size and
  • therefore the time to send the file to the printer. You get longer
  • processing time instead.
  • rle is encoded as such:
  • <count> <value> # 'run' of count+1 equal pixels
  • <count | 0x80> <count+1 data bytes> # count+1 non-equal pixels
  • count can range between 0 and 127
  • returns length of the rleline vector

*/ static int PSrle_encode(unsigned char *scanline, unsigned char *rleline, int wide) { int i, j, blocklen, isrun, rlen; unsigned char block[256], pix;

blocklen = isrun = rlen = 0;

for (i = 0; i < wide; i++) { /* there are 5 possible states:

  • 0: block empty.
  • 1: block is a run, current pix == previous pix
  • 2: block is a run, current pix != previous pix
  • 3: block not a run, current pix == previous pix
  • 4: block not a run, current pix != previous pix

*/

pix = scanline[i];

if (!blocklen) { * case 0: empty * block[blocklen++] = pix; isrun = 1; } else if (isrun) { if (pix == block[blocklen-1]) { * case 1: isrun, prev==cur * block[blocklen++] = pix; } else { * case 2: isrun, prev!=cur * if (blocklen>1) { * we have a run block to flush * rleline[rlen++] = blocklen-1; rleline[rlen++] = block[0]; * start new run block with pix * block[0] = pix; blocklen = 1; } else { * blocklen<=1, turn into non-run * isrun = 0; block[blocklen++] = pix; } } } else { * not a run * if (pix == block[blocklen-1]) { * case 3: non-run, prev==cur * if (blocklen>1) { * have a non-run block to flush * rleline[rlen++] = (blocklen-1) | 0x80; for (j=0; j<blocklen; j++) rleline[rlen++] = block[j]; * start new run block with pix * block[0] = pix; blocklen = isrun = 1; } else { * blocklen<=1 turn into a run * isrun = 1; block[blocklen++] = pix; } } else { * case 4: non-run, prev!=cur * block[blocklen++] = pix; } }

* max block length. flush * if (blocklen == 128) { if (isrun) { rleline[rlen++] = blocklen-1; rleline[rlen++] = block[0]; } else { rleline[rlen++] = (blocklen-1) | 0x80; for (j=0; j<blocklen; j++) rleline[rlen++] = block[j]; } blocklen = 0; } }

* flush last block * if (blocklen) { if (isrun) { rleline[rlen++] = blocklen-1; rleline[rlen++] = block[0]; } else { rleline[rlen++] = (blocklen-1) | 0x80; for (j=0; j<blocklen; j++) rleline[rlen++] = block[j]; } }

return rlen; }

/*

  • PScolor_image - created postscript colorimage operator
  • spits out code that checks if the PostScript device in question
  • knows about the 'colorimage' operator. If it doesn't, it defines
  • 'colorimage' in terms of image (ie, generates a greyscale image from
  • RGB data)

*/

static void PScolor_image(void) { static char *txt[] = {

"% define 'colorimage' if it isn't defined", "% ('colortogray' and 'mergeprocs' come from xwd2ps", "% via xgrab)", "/colorimage where % do we know about 'colorimage'?", " { pop } % yes: pop off the 'dict' returned", " { % no: define one", " /colortogray { % define an RGB->I function", " /rgbdata exch store % call input 'rgbdata'", " rgbdata length 3 idiv", " /npixls exch store", " /rgbindx 0 store", " /grays npixls string store % str to hold the result", " 0 1 npixls 1 sub {", " grays exch", " rgbdata rgbindx get 20 mul % Red", " rgbdata rgbindx 1 add get 32 mul % Green", " rgbdata rgbindx 2 add get 12 mul % Blue", " add add 64 idiv % I = .5G + .31R + .18B", " put", " /rgbindx rgbindx 3 add store", " } for", " grays", " } bind def\n", /* Utility procedure for colorimage operator.

  • This procedure takes two procedures off the
  • stack and merges them into a single procedure

*/ " /mergeprocs { % def", " dup length", " 3 -1 roll dup length dup 5 1 roll", " 3 -1 roll add array cvx dup", " 3 -1 roll 0 exch putinterval", " dup 4 2 roll putinterval", " } bind def\n", " colorimage { % def", /* remove 'false 3' operands * " pop pop", " {colortogray} mergeprocs", " image", " } bind def", * end of 'false' case * " } ifelse" };

PSconst_out(txt); }

/*

  • PScolormap - write colormap
  • spits out code for the colormap of the following image
  • if !color, it spits out a mono-ized graymap

*/ static void PScolormap(int color, int nc, int *rmap, int *gmap, int *bmap) { int i;

* define the colormap * PSprintf("/cmap %d string def\n\n\n", nc * ((color) ? 3 : 1));

* load up the colormap * PSprintf("currentfile cmap readhexstring\n");

for (i=0; i<nc; i++) { if (color) PSprintf("%02x%02x%02x ", rmap[i]>>8, gmap[i]>>8, bmap[i]>>8); else PSprintf("%02x ", MONO(rmap[i], gmap[i], bmap[i])); if ((i%10) == 9) PSprintf("\n"); } PSprintf("\n"); PSprintf("pop pop\n"); * lose return values from readhexstring * }

/*

  • PSrle_cmapimage - define rlecmapimage operator

*/ static void PSrle_cmapimage(int color) {

static char *txt[] = {

* rlecmapimage expects to have 'w h bits matrix' on stack * "/rlecmapimage {", " /buffer 1 string def", " /rgbval 3 string def", " /block 384 string def", " { currentfile buffer readhexstring pop", " /bcount exch 0 get store", " bcount 128 ge", " { ", " 0 1 bcount 128 sub", " { currentfile buffer readhexstring pop pop" };

static char *txt_color[] = { " /rgbval cmap buffer 0 get 3 mul 3 getinterval store", " block exch 3 mul rgbval putinterval", " } for", " block 0 bcount 127 sub 3 mul getinterval", " }", " { ", " currentfile buffer readhexstring pop pop", " /rgbval cmap buffer 0 get 3 mul 3 getinterval store", " 0 1 bcount { block exch 3 mul rgbval putinterval } for", " block 0 bcount 1 add 3 mul getinterval", " } ifelse", " }", " false 3 colorimage", "} bind def" };

static char *txt_gray[] = { " /rgbval cmap buffer 0 get 1 getinterval store", " block exch rgbval putinterval", " } for", " block 0 bcount 127 sub getinterval", " }", " { ", " currentfile buffer readhexstring pop pop", " /rgbval cmap buffer 0 get 1 getinterval store", " 0 1 bcount { block exch rgbval putinterval } for", " block 0 bcount 1 add getinterval", " } ifelse", " }", " image", "} bind def" };

PSconst_out(txt); if (color) { PSconst_out(txt_color); } else { PSconst_out(txt_gray); } }

/*

  • PSwrite_bw - write B&W image
  • Write the given image array 'pic' (B/W stippled, 1 byte per pixel,
  • 0=blk,1=wht) out as hexadecimal, max of 72 hex chars per line. If
  • 'flipbw', then 0=white, 1=black. Returns '0' if everythings fine,
  • 'EOF' if writing failed.

*/ static int PSwrite_bw(unsigned char *pic, int w, int h, int flipbw) { int i, j; int err=0; unsigned char outbyte, bitnum, bit;

outbyte = bitnum = 0; for (i=0; i<h && err != EOF; i++) { for (j=0; j<w && err != EOF; j++) { bit = *(pic++); outbyte = (outbyte<<1) | ((bit)&0x01); bitnum++;

if (bitnum==8) { if (flipbw) outbyte = ~outbyte & 0xff; err=PShex(outbyte, False); outbyte = bitnum = 0; } } if (bitnum) { * few bits left over in this row * outbyte <<= 8-bitnum; if (flipbw) outbyte = ~outbyte & 0xff; err=PShex(outbyte, False); outbyte = bitnum = 0; } } err=PShex('\0', True); * Flush the hex buffer if needed *

return err; }

/*

  • PSimage - generate image Postscript code
  • Draw the image, unless there was no image, in which case an empty grey
  • rectangle is shown.
  • If anchor is set, a black border is shown around the image.
  • Positioning is not exactly that of Xmosaic's screen, but close enough.

*/

static void PSimage(HTMLWidget hw, struct ele_rec *eptr, int fontfamily) { ImageInfo *img = eptr->pic_data; unsigned char *imgp = img->image_data; int anchor = (eptr->anchorHRef != NULL); int ncolors = img->num_colors; int i, j; int w = img->width; int h = img->height; int slen, colorps, colortype, bits; int err=0; int extra = 0;

* Isgray returns true if the nth color index is a gray value *

* Is_bg returns true if the nth color index is the screen background *

i->greens[n]==bg_color.green && i->blues[n]==bg_color.blue) * Is_fg returns true if the nth color index is the screen foreground *

i->greens[n]==fg_color.green && i->blues[n]==fg_color.blue)

PSmove_offset(eptr->y_offset); if (anchor) { /* draw an outline by drawing a slightly larger black square

  • below the actual image

*/ PSprintf("gsave currentpoint %d sub translate ", h); PSprintf("0 -2 translate %d %d scale\n", w+4, h+4); PSprintf("SQ fill\n"); PSprintf("grestore\n"); extra = 4; }

if (imgp == NULL) { /* image was not available… do something instead

  • draw an empty square for example

*/ PSprintf("gsave currentpoint %d sub translate", h); if (anchor) PSprintf(" 2 0 translate"); else PSprintf(" 0 2 translate"); PSprintf(" %d %d scale\n", w, h); PSprintf("0.9 setgray SQ fill\n"); PSprintf("grestore\n"); * move currentpoint just right of image * PSprintf("%d 0 R\n", w+extra); return; }

/* this is a hack to see if the image is Black & White,

  • Greyscale or 8 bit color
  • assume it's bw if it has only one or two colors, both some grey's
  • assume it's greyscale if all the colors (>2) are grey
  • Images with only one color do occur too.

*/

if ( ( (ncolors == 2) && ( (Isgray(img,0) && Isgray(img,1))

(Is_bg(img,0) && Is_fg(img,1))
(Is_fg(img,0) && Is_bg(img,1)) ))
( (ncolors == 1)

&& (Isgray(img,0)

Is_bg(img,0)
Is_fg(img,0))))

{ colortype = F_BWDITHER; slen = (w+7)/8; bits = 1; colorps = 0; } else { colortype = F_GREYSCALE; slen = w; bits = 8; colorps = 0; for (i=0; i<ncolors; i++) { if (!Isgray(img,i)) { colortype = F_REDUCED; slen = w*3; bits = 8; colorps = 1; break; } } }

* build a temporary dictionary * PSprintf("20 dict begin\n\n");

* define string to hold a scanline's worth of data * PSprintf("/pix %d string def\n\n", slen);

* position and scaling * PSprintf("gsave currentpoint %d sub translate", h); if (anchor) PSprintf(" 2 0 translate"); else PSprintf(" 0 2 translate"); PSprintf(" %d %d scale\n", w, h);

if (colortype == F_BWDITHER) { * 1-bit dither code uses 'image' * int flipbw = 0;

* set if color#0 is 'white' * if ((ncolors == 2 && MONO(img->reds[0], img->greens[0],img->blues[0]) > MONO(img->reds[1], img->greens[1], img->blues[1])) || (ncolors == 1 && MONO(img->reds[0], img->greens[0],img->blues[0]) > MONO(127, 127, 127) )) { flipbw=1; }

* dimensions of data * PSprintf("%d %d %d\n", w, h, bits);

* mapping matrix * PSprintf("[%d 0 0 %d 0 %d]\n\n", w, -h, h);

PSprintf("{currentfile pix readhexstring pop}\n"); PSprintf("image\n");

* write the actual image data * err = PSwrite_bw(imgp, w, h, flipbw); } else { * all other formats * unsigned char *rleline = (unsigned char *) NULL; int rlen;

* if we're using color, make sure 'colorimage' is defined * if (colorps) PScolor_image();

PScolormap(colorps, ncolors, img->reds, img->greens, img->blues); PSrle_cmapimage(colorps);

* dimensions of data * PSprintf("%d %d %d\n", w, h, bits); * mapping matrix * PSprintf("[%d 0 0 %d 0 %d]\n", w, -h, h); PSprintf("rlecmapimage\n");

rleline = (unsigned char *) malloc(w * 2); if (!rleline) { #ifndef DISABLE_TRACE if (htmlwTrace) { fprintf(stderr,"failed to malloc space for rleline\n"); } #endif

return; }

for (i=0; i<h && err != EOF; i++) { rlen = PSrle_encode(imgp, rleline, w); imgp = w; for (j=0; j<rlen && err != EOF; j+) err=PShex(rleline[j], False); err=PShex('\0', True); * Flush the hex buffer * } free(rleline); }

* stop using temporary dictionary * PSprintf("end\n"); PSprintf("grestore\n");

* move currentpoint just right of image * PSprintf("%d 0 R\n", w + extra); if (HTML_Print_Footers && has_footnote(eptr)) { PSmove_offset(0); PSfootnote(eptr->anchorHRef, 2.0); }

* forget about the macro's *

}

/*

  • ParseTextToPSString - entry point for postscript output
  • Parse all the formatted text elements from start to end
  • into an ascii text string, and return it.
  • Very like ParseTextToString() except the text is prettied up
  • into Postscript to show headers and the like.
  • space_width and lmargin tell us how many spaces
  • to indent lines.
  • Because this routine is only used to print whole documents,
  • some parameters are not needed at all!
  • Also it assumes that you are indeed printing the whole document, and
  • not just a selected portion of it. It therefore can assume that
  • only for the first page the initialization is needed, and only
  • the last page has the trailers. You cannot use ParseTextToPSString()
  • as you can use ParseTextToString() because of this initialization code.
  • the fontfamily parameter is new
  • The font is encoded as:
  • 0: times (default for now)
  • 1: helvetica
  • 2: new century schoolbook
  • 3: lucida

*/ String ParseTextToPSString(HTMLWidget hw, struct ele_rec *elist, struct ele_rec *startp, struct ele_rec *endp, int start_pos, int end_pos, int space_width, int lmargin, int fontfamily, char *url, char *time_str) { int xpos, ypos, epos; int height; double pagewidth; int line = -1; struct ele_rec *eptr; struct ele_rec *start; struct ele_rec *end; struct ele_rec *last; struct ele_rec *tmpptr; unsigned long fg_pixel, bg_pixel; int footnotes_this_page = 0; int footnotes_this_line; int reserved_space;

if (startp == NULL) return(NULL);

/*

  • Get the foreground and background colors so we can check later
  • for black&white documents

*/ XtVaGetValues (hw->html.view, #ifdef MOTIF XtNforeground, &fg_pixel, #endif XtNbackground, &bg_pixel, NULL); #ifndef MOTIF XtVaGetValues ((Widget)hw, XtNforeground, &fg_pixel, NULL); #endif fg_color.pixel = fg_pixel; bg_color.pixel = bg_pixel; XQueryColor(XtDisplay(hw->html.view), (installed_colormap ? installed_cmap : DefaultColormap(XtDisplay(hw->html.view), DefaultScreen(XtDisplay(hw->html.view)))), &fg_color); XQueryColor(XtDisplay(hw->html.view), (installed_colormap ? installed_cmap : DefaultColormap(XtDisplay(hw->html.view), DefaultScreen(XtDisplay(hw->html.view)))), &bg_color);

/* this piece of code is needed if the user selects a portion

  • of the document with the mouse.
  • I think it will never be used, but I left it in anyway. F.

*/ if (SwapElements(startp, endp, start_pos, end_pos)) { start = endp; end = startp; epos = start_pos; start_pos = end_pos; end_pos = epos; } else { start = startp; end = endp; }

* Setup page size according to user preference. *

if (HTML_Print_Paper_Size_A4) page_dimens = a4_page_dimens; else page_dimens = us_letter_page_dimens;

page_dimens.text_height = ( page_dimens.page_height

  • page_dimens.top_margin
  • page_dimens.bot_margin);

page_dimens.text_width = ( page_dimens.page_width

  • page_dimens.left_margin
  • page_dimens.right_margin);

/* Calculate the number of Postscript points per pixel of current

  • screen, and the height of the page in pixels (used in figuring
  • when we've hit the bottom of the page).

*/ Points_Pixel = 72.0 / GetDpi(hw); #ifdef OLD pagewidth = hw->html.doc_width; #else * gustaf fix * pagewidth = hw->html.view_width; #endif * gustaf fix *

/* reduce the scaling if the width used for formatting is greater

  • than 8 * 72 pixels (8 inch)
  • In theory, this is not what you want for A4 paper (only 8.27 inch
  • wide), but I guess that the hw->html.doc_width includes some
  • left and right margins, so it seems to work in practice.

*/ if (pagewidth > page_dimens.text_width) Points_Pixel = Points_Pixel * page_dimens.text_width / pagewidth; Pixels_Page = (int) (page_dimens.text_height / Points_Pixel);

PSinit(); PSheader(hw->html.title, fontfamily, url, time_str); PSnewpage();

last = start; eptr = start;

while ((eptr != NULL) && (eptr != end)) { /* Skip the special internal text added for multi-page

  • documents.

*/ if (eptr->internal == True) { if (eptr->type == E_LINEFEED) { PS_page_offset += eptr->line_height; } eptr = eptr->next; continue; }

* check if this is a newline * if (line != eptr->line_number) { * calculate max height * height = 0; footnotes_this_line = 0; line = eptr->line_number; tmpptr = eptr; while (tmpptr != NULL && tmpptr->line_number == line) { if (tmpptr->line_height > height) height = tmpptr->line_height; tmpptr = tmpptr->next; if (HTML_Print_Footers && has_footnote(tmpptr)) footnotes_this_line++; } ypos = eptr->y - PS_page_offset ; xpos = eptr->x - lmargin; if (xpos < 0) xpos = 0;

* check if line fits completly on page *

reserved_space = 0; if (footnotes_this_page || footnotes_this_line) { reserved_space = ( ( footnote_space

  • ( footnote_ptsize
  • ( footnotes_this_page

    • footnotes_this_line)))

    / Points_Pixel);

}

if (ypos + height + reserved_space > PS_start_y + Pixels_Page) { PS_start_y = ypos; PSshowpage(); PSnewpage(); footnotes_this_page = 0; } footnotes_this_page += footnotes_this_line; PSmoveto( xpos, ypos); }

switch (eptr->type) { case E_TEXT: PStext(hw, eptr, fontfamily, (String)((eptr == start) ? (eptr->edata + start_pos) : eptr->edata)); break;

case E_BULLET: PSbullet(hw, eptr, fontfamily); break;

case E_IMAGE: PSimage(hw, eptr, fontfamily); break;

case E_LINEFEED: break;

case E_HRULE: PShrule(hw, eptr, fontfamily); break;

case E_TABLE: PStable(hw, eptr, fontfamily); break;

case E_WIDGET: PSwidget(hw, eptr, fontfamily); break;

} last = eptr; eptr = eptr->next; }

PSshowpage(); PStrailer();

return (PS_string); }