diff options
author | Jeffrey H. Kingston <jeff@it.usyd.edu.au> | 2010-09-14 19:21:41 +0000 |
---|---|---|
committer | Jeffrey H. Kingston <jeff@it.usyd.edu.au> | 2010-09-14 19:21:41 +0000 |
commit | 71bdb35d52747e6d7d9f55df4524d57c2966be94 (patch) | |
tree | 480ee5eefccc40d5f3331cc52d66f722fd19bfb9 /z24.c | |
parent | b41263ea7578fa9742486135c762803b52794105 (diff) | |
download | lout-71bdb35d52747e6d7d9f55df4524d57c2966be94.tar.gz |
Lout 3.17.
git-svn-id: http://svn.savannah.nongnu.org/svn/lout/trunk@2 9365b830-b601-4143-9ba8-b4a8e2c3339c
Diffstat (limited to 'z24.c')
-rw-r--r-- | z24.c | 1513 |
1 files changed, 1513 insertions, 0 deletions
@@ -0,0 +1,1513 @@ +/*@z24.c:Print Service:PrintInit()@*******************************************/ +/* */ +/* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.17) */ +/* COPYRIGHT (C) 1991, 1999 Jeffrey H. Kingston */ +/* */ +/* Jeffrey H. Kingston (jeff@cs.usyd.edu.au) */ +/* Basser Department of Computer Science */ +/* The University of Sydney 2006 */ +/* AUSTRALIA */ +/* */ +/* PDF Back End by Vincent Tan, February 1998. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either Version 2, or (at your option) */ +/* any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */ +/* */ +/* FILE: z24.c */ +/* MODULE: Print Service */ +/* EXTERNS: PrintInit(), PrintBeforeFirst(), PrintBetween(), */ +/* PrintWord(), PrintAfterLast(), CoordTranslate(), */ +/* CoordRotate(), CoordScale(), SaveGraphicState(), */ +/* RestoreGraphicState(), PrintGraphicObject(), */ +/* DefineGraphicNames(), PrintGraphicInclude() */ +/* */ +/* This module implements the PostScript back end. */ +/* */ +/*****************************************************************************/ +#include <math.h> /* for fabs() */ + +#include "externs.h" +#define StartUpResource "LoutStartUp" +#define DEFAULT_XHEIGHT 500 +#define NO_FONT 0 /* actually stolen from z37.c */ +#define NO_COLOUR 0 +#define MAX_GS 50 /* maximum depth of graphics states */ + +#define printnum(x, fp) \ +{ char buff[20]; register int i, y; \ + if( x >= 0 ) y = x; \ + else { y = -x; putc(CH_MINUS, fp); } \ + i = 0; \ + do { buff[i++] = numtodigitchar(y % 10); \ + } while( (y = (y / 10)) > 0 ); \ + do { --i; putc(buff[i], fp); \ + } while( i ); \ +} + +static FILE *out_fp; /* output file */ + +/* these variables used by PLAINTEXT back end only */ +static int hsize; /* horizontal size of page in chars */ +static int vsize; /* vertical size of page in chars */ +static FULL_CHAR *page; /* the page (two-dim array of chars) */ + +/* these types and variables used by POSTSCRIPT back end only */ +typedef struct +{ + FONT_NUM gs_font; /* font number of this state */ + COLOUR_NUM gs_colour; /* colour number of this state */ + BOOLEAN gs_cpexists; /* TRUE if a current point exists */ + FULL_LENGTH gs_currenty; /* if cpexists, its y coordinate */ + short gs_xheight2; /* of font exists, half xheight */ +} GRAPHICS_STATE; + +static GRAPHICS_STATE gs_stack[MAX_GS];/* graphics state stack */ +static int gs_stack_top; /* top of graphics state stack */ + +static FONT_NUM currentfont; /* font of most recent atom */ +static COLOUR_NUM currentcolour; /* colour of most recent atom */ +static short currentxheight2;/* half xheight in current font */ +static BOOLEAN cpexists; /* true if a current point exists */ +static FULL_LENGTH currenty; /* if cpexists, its y coordinate */ + +static int wordcount; /* atoms printed since last newline */ +static int pagecount; /* total number of pages printed */ +static BOOLEAN prologue_done; /* TRUE after prologue is printed */ +static OBJECT needs; /* Resource needs of included EPSFs */ +static OBJECT supplied; /* Resources supplied by this file */ + + +/*@::EightBitToPrintForm()@***************************************************/ +/* */ +/* static char *EightBitToPrintForm[] */ +/* */ +/* Given 8-bit character i, returns a string of characters that will be */ +/* interpreted by PostScript as character i when read within a string. */ +/* */ +/* CHAR_OUT==1 Printable ASCII literal, others as escape sequences */ +/* CHAR_OUT==2 Printable ISO-LATIN-1 literal, others escaped */ +/* */ +/*****************************************************************************/ + +static char *EightBitToPrintForm[] = { +#if CHAR_OUT==0 + "", "\\001", "\\002", "\\003", "\\004", "\\005", "\\006", "\\007", + "\\010", "\\011", "\\012", "\\013", "\\014", "\\015", "\\016", "\\017", + "\\020", "\\021", "\\022", "\\023", "\\024", "\\025", "\\026", "\\027", + "\\030", "\\031", "\\032", "\\033", "\\034", "\\035", "\\036", "\\037", + " ", "!", "\"", "#", "$", "%", "&", "'", + "\\(", "\\)", "*", "+", ",", "-", ".", "/", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", ":", ";", "<", "=", ">", "?", + "@", "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", "[", "\\\\", "]", "^", "_", + "`", "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", "{", "|", "}", "~", "\\177", + "\\200", "\\201", "\\202", "\\203", "\\204", "\\205", "\\206", "\\207", + "\\210", "\\211", "\\212", "\\213", "\\214", "\\215", "\\216", "\\217", + "\\220", "\\221", "\\222", "\\223", "\\224", "\\225", "\\226", "\\227", + "\\230", "\\231", "\\232", "\\233", "\\234", "\\235", "\\236", "\\237", + "\\240", "\\241", "\\242", "\\243", "\\244", "\\245", "\\246", "\\247", + "\\250", "\\251", "\\252", "\\253", "\\254", "\\255", "\\256", "\\257", + "\\260", "\\261", "\\262", "\\263", "\\264", "\\265", "\\266", "\\267", + "\\270", "\\271", "\\272", "\\273", "\\274", "\\275", "\\276", "\\277", + "\\300", "\\301", "\\302", "\\303", "\\304", "\\305", "\\306", "\\307", + "\\310", "\\311", "\\312", "\\313", "\\314", "\\315", "\\316", "\\317", + "\\320", "\\321", "\\322", "\\323", "\\324", "\\325", "\\326", "\\327", + "\\330", "\\331", "\\332", "\\333", "\\334", "\\335", "\\336", "\\337", + "\\340", "\\341", "\\342", "\\343", "\\344", "\\345", "\\346", "\\347", + "\\350", "\\351", "\\352", "\\353", "\\354", "\\355", "\\356", "\\357", + "\\360", "\\361", "\\362", "\\363", "\\364", "\\365", "\\366", "\\367", + "\\370", "\\371", "\\372", "\\373", "\\374", "\\375", "\\376", "\\377" +#else +#if CHAR_OUT==1 + "", "\\001", "\\002", "\\003", "\\004", "\\005", "\\006", "\\007", + "\\010", "\\011", "\\012", "\\013", "\\014", "\\015", "\\016", "\\017", + "\\020", "\\021", "\\022", "\\023", "\\024", "\\025", "\\026", "\\027", + "\\030", "\\031", "\\032", "\\033", "\\034", "\\035", "\\036", "\\037", + " ", "!", "\"", "#", "$", "%", "&", "'", + "\\(", "\\)", "*", "+", ",", "-", ".", "/", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", ":", ";", "<", "=", ">", "?", + "@", "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", "[", "\\\\", "]", "^", "_", + "`", "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", "{", "|", "}", "~", "\\177", + "\\200", "\\201", "\\202", "\\203", "\\204", "\\205", "\\206", "\\207", + "\\210", "\\211", "\\212", "\\213", "\\214", "\\215", "\\216", "\\217", + "\220", "\221", "\222", "\223", "\224", "\225", "\226", "\227", + "\230", "\\231", "\232", "\233", "\\234", "\235", "\236", "\237", + "\240", "\241", "\242", "\243", "\244", "\245", "\246", "\247", + "\250", "\251", "\252", "\253", "\254", "\255", "\256", "\257", + "\260", "\261", "\262", "\263", "\264", "\265", "\266", "\267", + "\270", "\271", "\272", "\273", "\274", "\275", "\276", "\277", + "\300", "\301", "\302", "\303", "\304", "\305", "\306", "\307", + "\310", "\311", "\312", "\313", "\314", "\315", "\316", "\317", + "\320", "\321", "\322", "\323", "\324", "\325", "\326", "\327", + "\330", "\331", "\332", "\333", "\334", "\335", "\336", "\337", + "\340", "\341", "\342", "\343", "\344", "\345", "\346", "\347", + "\350", "\351", "\352", "\353", "\354", "\355", "\356", "\357", + "\360", "\361", "\362", "\363", "\364", "\365", "\366", "\367", + "\370", "\371", "\372", "\373", "\374", "\375", "\376", "\377" +#else +If you are trying to compile this you have the wrong CHAR_OUT value! +#endif +#endif +}; + + +/*****************************************************************************/ +/* */ +/* PrintInit(file_ptr) */ +/* */ +/* Initialise this module. Output is to go to FILE file_ptr. */ +/* */ +/*****************************************************************************/ + +void PrintInit(FILE *file_ptr) +{ debug0(DGP, DD, "PrintInit()"); + out_fp = file_ptr; prologue_done = FALSE; + gs_stack_top = -1; + currentfont = NO_FONT; + currentcolour = NO_COLOUR; + cpexists = FALSE; + wordcount = pagecount = 0; + New(needs, ACAT); + New(supplied, ACAT); + debug0(DGP, DD, "PrintInit returning."); +} + + +/*@::PrintBeforeFirst@********************************************************/ +/* */ +/* PrintBeforeFirst(h, v, label) */ +/* */ +/* This procedure is called just before starting to print the first */ +/* component of the output. Its size is h, v, and label is the page */ +/* label to attach to the %%Page comment. */ +/* */ +/* If BackEnd is PLAINTEXT, this procedure obtains a two-dimensional array */ +/* of characters large enough to hold the first component, and clears it. */ +/* */ +/* If BackEnd is POSTSCRIPT, this procedure generates the PostScript */ +/* prologue, augmented with any @PrependGraphic or @SysPrependGraphic */ +/* files specified by the user. The following PostScript operators are */ +/* defined: */ +/* */ +/* scale_factor fnt scale and set font */ +/* x_coordinate x move to x_coordinate, current y coordinate */ +/* string s show string */ +/* number in result is number inches */ +/* number cm result is number centimetres */ +/* number pt result is number points */ +/* number sp result is number spaces */ +/* number vs result is number vspaces */ +/* number ft result is number font-sizes */ +/* */ +/* as well as LoutGraphic, for use with the @Graphic operator: */ +/* */ +/* xsize ysize xmark ymark fr vs sp LoutGraphic - */ +/* */ +/* Define xmark, ymark, xsize, ysize to be the positions of */ +/* these features of x, and define symbols ft, vs and sp */ +/* to be the current font size, line separation, and space width. */ +/* */ +/*****************************************************************************/ + +void PrintBeforeFirst(FULL_LENGTH h, FULL_LENGTH v, FULL_CHAR *label) +{ FILE_NUM fnum; int i, j; FULL_CHAR *p; + debug2(DGP, DD, "PrintBeforeFirst(%d, %d)", h, v); + + switch( BackEnd ) + { + case PLAINTEXT: + + /* get a new page[] and clear it */ + hsize = ceiling(h, PlainCharWidth); + vsize = ceiling(v, PlainCharHeight); + debug2(DGP, DD, " PlainCharWidth: %d; PlainCharHeight: %d", + PlainCharWidth, PlainCharHeight); + ifdebug(DMA, D, DebugRegisterUsage(MEM_PAGES, 1, + hsize * vsize * sizeof(FULL_CHAR))); + debug2(DGP, DD, " PrintBeforeFirst allocating %d by %d", hsize, vsize); + page = (FULL_CHAR *) malloc(hsize * vsize * sizeof(FULL_CHAR)); + for( i = 0; i < vsize; i++ ) + for( j = 0; j < hsize; j++ ) + page[i*hsize + j] = ' '; + break; + + + case POSTSCRIPT: + + /* print header comments for PostScript DSC 3.0 output */ + if( Encapsulated ) + fprintf(out_fp, "%%!PS-Adobe-3.0 EPSF-3.0\n"); + else + fprintf(out_fp, "%%!PS-Adobe-3.0\n"); + fprintf(out_fp, "%%%%Creator: %s\n", LOUT_VERSION); + fprintf(out_fp, "%%%%CreationDate: %s", TimeString()); + fprintf(out_fp, "%%%%DocumentData: Binary\n"); + fprintf(out_fp, "%%%%DocumentNeededResources: (atend)\n"); + fprintf(out_fp, "%%%%DocumentMedia: Plain %d %d 0 white ()\n", h/PT, v/PT); + fprintf(out_fp, "%%%%DocumentSuppliedResources: (atend)\n"); + fprintf(out_fp, "%%%%Pages: (atend)\n"); + fprintf(out_fp, "%%%%BoundingBox: 0 0 %d %d\n", h/PT, v/PT); + fprintf(out_fp, "%%%%EndComments\n\n"); + + /* print procedure definitions part of header */ + fprintf(out_fp, "%%%%BeginProlog\n"); + fprintf(out_fp, "%%%%BeginResource: procset %s\n", StartUpResource); + fprintf(out_fp, "/m { 3 1 roll moveto show } bind def\n"); + fprintf(out_fp, "/s { exch currentpoint exch pop moveto show } bind def\n"); + fprintf(out_fp, "/k { exch neg 0 rmoveto show } bind def\n"); + fprintf(out_fp, "/ul { gsave setlinewidth dup 3 1 roll\n"); + fprintf(out_fp, " moveto lineto stroke grestore } bind def\n"); + fprintf(out_fp, "/in { %d mul } def\n", IN); + fprintf(out_fp, "/cm { %d mul } def\n", CM); + fprintf(out_fp, "/pt { %d mul } def\n", PT); + fprintf(out_fp, "/em { %d mul } def\n", EM); + fprintf(out_fp, "/sp { louts mul } def\n"); + fprintf(out_fp, "/vs { loutv mul } def\n"); + fprintf(out_fp, "/ft { loutf mul } def\n"); + fprintf(out_fp, "/dg { } def\n\n"); + + fputs("/LoutGraphic {\n", out_fp); + fputs(" /louts exch def\n", out_fp); + fputs(" /loutv exch def\n", out_fp); + fputs(" /loutf exch def\n", out_fp); + fputs(" /ymark exch def\n", out_fp); + fputs(" /xmark exch def\n", out_fp); + fputs(" /ysize exch def\n", out_fp); + fputs(" /xsize exch def\n} def\n\n", out_fp); + + fputs("/LoutGr2 { gsave translate LoutGraphic gsave } def\n\n", out_fp); + + /* print definition used by Lout output to recode fonts */ + /* adapted from PostScript Language Reference Manual (2nd Ed), p. 275 */ + /* usage: /<fullname> <encodingvector> /<originalname> LoutRecode - */ + + fputs("/LoutFont\n", out_fp); + fputs("{ findfont exch scalefont setfont\n", out_fp); + fputs("} bind def\n\n", out_fp); + + fputs("/LoutRecode {\n", out_fp); + fputs(" { findfont dup length dict begin\n", out_fp); + fputs(" {1 index /FID ne {def} {pop pop} ifelse} forall\n", out_fp); + fputs(" /Encoding exch def\n", out_fp); + fputs(" currentdict end definefont pop\n", out_fp); + fputs(" }\n", out_fp); + fputs(" stopped pop\n", out_fp); + fputs("} bind def\n\n", out_fp); + + /* print definitions used by Lout output when including EPSF files */ + /* copied from PostScript Language Reference Manual (2nd Ed.), p. 726 */ + + fputs("/BeginEPSF {\n", out_fp); + fputs(" /LoutEPSFState save def\n", out_fp); + fputs(" /dict_count countdictstack def\n", out_fp); + fputs(" /op_count count 1 sub def\n", out_fp); + fputs(" userdict begin\n", out_fp); + fputs(" /showpage { } def\n", out_fp); + fputs(" 0 setgray 0 setlinecap\n", out_fp); + fputs(" 1 setlinewidth 0 setlinejoin\n", out_fp); + fputs(" 10 setmiterlimit [] 0 setdash newpath\n", out_fp); + fputs(" /languagelevel where\n", out_fp); + fputs(" { pop languagelevel\n", out_fp); + fputs(" 1 ne\n", out_fp); + fputs(" { false setstrokeadjust false setoverprint\n", out_fp); + fputs(" } if\n", out_fp); + fputs(" } if\n", out_fp); + fputs("} bind def\n\n", out_fp); + + fputs("/EndEPSF {\n", out_fp); + fputs(" count op_count sub { pop } repeat\n", out_fp); + fputs(" countdictstack dict_count sub { end } repeat\n", out_fp); + fputs(" LoutEPSFState restore\n", out_fp); + fputs("} bind def\n", out_fp); + + fputs("%%EndResource\n\n", out_fp); + + /* print encoding vectors as resources */ + MapPrintEncodings(out_fp); + + /* print prepend files (assumed to be organized as DSC 3.0 Resources) */ + for( fnum=FirstFile(PREPEND_FILE); fnum!=NO_FILE; fnum=NextFile(fnum) ) + { FULL_CHAR buff[MAX_BUFF]; FILE *fp; + if( (fp = OpenFile(fnum, FALSE, FALSE)) == null ) + Error(24, 1, "cannot open %s file %s", + WARN, PosOfFile(fnum), KW_PREPEND, FileName(fnum)); + else if( StringFGets(buff, MAX_BUFF, fp) == NULL ) + Error(24, 2, "%s file %s is empty", + WARN, PosOfFile(fnum), KW_PREPEND, FileName(fnum)); + else + { + if( StringBeginsWith(buff, AsciiToFull("%%BeginResource:")) ) + { OBJECT tmp; + tmp = MakeWord(WORD, &buff[strlen("%%BeginResource:")], no_fpos); + Link(supplied, tmp); + } + else + Error(24, 3, "%s file %s lacks PostScript BeginResource comment", + WARN, PosOfFile(fnum), KW_PREPEND, FileName(fnum)); + StringFPuts(buff, out_fp); + fprintf(out_fp, "%% %s file %s\n", KW_PREPEND, FileName(fnum)); + while( StringFGets(buff, MAX_BUFF, fp) != NULL ) + StringFPuts(buff, out_fp); + fprintf(out_fp, "\n"); + fclose(fp); + } + } + + fputs("%%EndProlog\n\n", out_fp); + fputs("%%BeginSetup\n", out_fp); + FontPrintPageSetup(out_fp); + fputs("%%EndSetup\n\n", out_fp); + fprintf(out_fp, "%%%%Page: "); + for( p = label; *p != '\0'; p++ ) + fputs(EightBitToPrintForm[*p], out_fp); + fprintf(out_fp, " %d\n", ++pagecount); + fprintf(out_fp, "%%%%BeginPageSetup\n"); + FontPrintPageResources(out_fp); + FontAdvanceCurrentPage(); + fprintf(out_fp, "/pgsave save def\n"); + fprintf(out_fp, "%.4f dup scale %d setlinewidth\n", 1.0 / PT, PT/2); + fprintf(out_fp, "%%%%EndPageSetup\n\n"); + break; + + case PDF: + + PDFFile_Init(out_fp, h/PT, v/PT, IN, CM, PT, EM); + + /* print encoding vectors as resources */ + MapPrintEncodings(out_fp); + + FontPrintPageSetup(out_fp); + + PDFPage_Init(out_fp, 1.0 / PT, PT/2); + + FontPrintPageResources(out_fp); /* write out font objects */ + FontAdvanceCurrentPage(); + break; + + } /* end switch */ + prologue_done = TRUE; +} /* end PrintBeforeFirst */ + + +/*@::PrintBetween()@**********************************************************/ +/* */ +/* PrintBetween(h, v, label) */ +/* */ +/* Start a new output component, of size h by v; label is the page label */ +/* to attach to the %%Page comment. */ +/* */ +/*****************************************************************************/ + +void PrintBetween(FULL_LENGTH h, FULL_LENGTH v, FULL_CHAR *label) +{ int new_hsize, new_vsize, i, j, jmax; FULL_CHAR *p; + debug2(DGP, DD, "PrintBetween(%d, %d)", h, v); + + switch( BackEnd ) + { + case PLAINTEXT: + + /* print the page that has just ended */ + ifdebug(DGP, D, + putc('+', out_fp); + for( j = 0; j < hsize; j++ ) putc('-', out_fp); + putc('+', out_fp); + putc('\n', out_fp); + ); + for( i = vsize - 1; i >= 0; i-- ) + { ifdebug(DGP, D, putc('|', out_fp)); + for( jmax = hsize-1; jmax >= 0 && page[i*hsize+jmax] == ' '; jmax--); + ifdebug(DGP, D, jmax = hsize - 1); + for( j = 0; j <= jmax; j++ ) + putc(page[i*hsize + j], out_fp); + ifdebug(DGP, D, putc('|', out_fp)); + putc('\n', out_fp); + } + ifdebug(DGP, D, + putc('+', out_fp); + for( j = 0; j < hsize; j++ ) putc('-', out_fp); + putc('+', out_fp); + putc('\n', out_fp); + ); + + /* separate the page from the next one with a form-feed if required */ + if( PlainFormFeed ) putc('\f', out_fp); + + /* if page size has changed, get a new page[] array */ + new_hsize = ceiling(h, PlainCharWidth); + new_vsize = ceiling(v, PlainCharHeight); + if( new_hsize != hsize || new_vsize != vsize ) + { + ifdebug(DMA, D, DebugRegisterUsage(MEM_PAGES, -1, + -hsize * vsize * sizeof(FULL_CHAR))); + free(page); + hsize = new_hsize; + vsize = new_vsize; + debug2(DGP, DD, " PrintBetween allocating %d by %d", hsize, vsize); + ifdebug(DMA, D, DebugRegisterUsage(MEM_PAGES, 1, + hsize * vsize * sizeof(FULL_CHAR))); + page = (FULL_CHAR *) malloc(hsize * vsize * sizeof(FULL_CHAR)); + } + + /* clear page[] for the new page just beginning */ + for( i = 0; i < vsize; i++ ) + for( j = 0; j < hsize; j++ ) + page[i*hsize + j] = ' '; + break; + + + case POSTSCRIPT: + + fprintf(out_fp, "\npgsave restore\nshowpage\n"); + gs_stack_top = 0; + cpexists = FALSE; + currentfont = NO_FONT; + currentcolour = NO_COLOUR; + if( Encapsulated ) + { PrintAfterLast(); + Error(24, 4, "truncating -EPS document at end of first page", + FATAL, no_fpos); + } + fprintf(out_fp, "\n%%%%Page: "); + for( p = label; *p != '\0'; p++ ) + fputs(EightBitToPrintForm[*p], out_fp); + fprintf(out_fp, " %d\n", ++pagecount); + fprintf(out_fp, "%%%%BeginPageSetup\n"); + FontPrintPageResources(out_fp); + fprintf(out_fp, "/pgsave save def\n"); + FontPrintPageSetup(out_fp); + FontAdvanceCurrentPage(); + fprintf(out_fp, "%.4f dup scale %d setlinewidth\n", 1.0 / PT, PT/2); + fprintf(out_fp, "%%%%EndPageSetup\n"); + wordcount = 0; + break; + + case PDF: + + /* write out page objects */ + PDFPage_Cleanup(out_fp); + PDFPage_Init(out_fp, 1.0 / PT, PT/2); + + /* write out font objects */ + FontPrintPageResources(out_fp); + FontPrintPageSetup(out_fp); + FontAdvanceCurrentPage(); + break; + + } /* end switch */ +} /* end PrintBetween */ + + +/*****************************************************************************/ +/* */ +/* KernLength(fnum, ch1, ch2, res) */ +/* */ +/* Set res to the kern length between ch1 and ch2 in font fnum, or 0 if */ +/* none. */ +/* */ +/*****************************************************************************/ + +#define KernLength(fnum, mp, ch1, ch2, res) \ +{ int ua_ch1 = mp[ch1]; \ + int ua_ch2 = mp[ch2]; \ + int i = finfo[fnum].kern_table[ua_ch1], j; \ + if( i == 0 ) res = 0; \ + else \ + { FULL_CHAR *kc = finfo[fnum].kern_chars; \ + for( j = i; kc[j] > ua_ch2; j++ ); \ + res = (kc[j] == ua_ch2) ? \ + finfo[fnum].kern_sizes[finfo[fnum].kern_value[j]] : 0; \ + } \ +} /* end KernLength */ + + +/*@::PrintWord()@*************************************************************/ +/* */ +/* PrintWord(x, hpos, vpos) */ +/* */ +/* Print non-empty word x; its marks cross at the point (hpos, vpos). */ +/* */ +/*****************************************************************************/ + +void PrintWord(OBJECT x, int hpos, int vpos) +{ FULL_CHAR *p, *q, *a, *b, *lig, *unacc; + int i, h, v, ksize; char command; MAPPING m; + + debug5(DGP, DD, "PrintWord( %s, %d, %d ) font %d colour %d", string(x), + hpos, vpos, word_font(x), word_colour(x)); + TotalWordCount++; + + switch( BackEnd ) + { + case PLAINTEXT: + + h = ((float) hpos / PlainCharWidth) + 0.5; + v = ((float) vpos / PlainCharHeight); + debug3(DGP, DD, "PrintWord(%s at h = %d, v = %d)", string(x), h, v); + if( h >= 0 && h + StringLength(string(x)) < hsize && v >= 0 && v < vsize ) + { + assert( h >= 0, "PrintWord: h < 0!" ); + assert( h < hsize, "PrintWord: h >= hsize!" ); + assert( v >= 0, "PrintWord: v < 0!" ); + assert( v < vsize, "PrintWord: v >= vsize!" ); + p = &page[v*hsize + h]; + for( i = 0; string(x)[i] != '\0'; i++ ) + *p++ = string(x)[i]; + } + else + { + Error(24, 11, "word %s deleted (internal error, off page at %d,%d)", + WARN, &fpos(x), string(x), h, v); + } + break; + + + case POSTSCRIPT: + + /* if font is different to previous word then print change */ + if( word_font(x) != currentfont ) + { currentfont = word_font(x); + currentxheight2 = FontHalfXHeight(currentfont); + fprintf(out_fp, "%hd %s", FontSize(currentfont, x), + FontName(currentfont)); + if( ++wordcount >= 5 ) + { fputs("\n", out_fp); + wordcount = 0; + } + else fputs(" ", out_fp); + } + + /* if colour is different to previous word then print change */ + if( word_colour(x) != currentcolour ) + { currentcolour = word_colour(x); + if( currentcolour > 0 ) + { fprintf(out_fp, "%s", ColourCommand(currentcolour)); + if( ++wordcount >= 5 ) + { fputs("\n", out_fp); + wordcount = 0; + } + else fputs(" ", out_fp); + } + } + + /* move to coordinate of x */ + debug1(DGP, DDD, " currentxheight2 = %d", currentxheight2); + vpos = vpos - currentxheight2; + if( cpexists && currenty == vpos ) + { printnum(hpos, out_fp); + command = 's'; + } + else + { currenty = vpos; + printnum(hpos, out_fp); + fputs(" ", out_fp); + printnum(currenty, out_fp); + command = 'm'; + cpexists = TRUE; + } + + /* convert ligature sequences into ligature characters */ + lig = finfo[word_font(x)].lig_table; + p = q = string(x); + do + { + /* check for missing glyph (lig[] == 1) or ligatures (lig[] > 1) */ + if( lig[*q++ = *p++] ) + { + if( lig[*(q-1)] == 1 ) continue; + else + { a = &lig[ lig[*(p-1)] + MAX_CHARS ]; + while( *a++ == *(p-1) ) + { b = p; + while( *a == *b && *(a+1) != '\0' && *b != '\0' ) a++, b++; + if( *(a+1) == '\0' ) + { *(q-1) = *a; + p = b; + break; + } + else + { while( *++a ); + a++; + } + } + } + } + } while( *p ); + *q = '\0'; + + /* show string(x) */ + fputs("(", out_fp); + p = string(x); + fputs(EightBitToPrintForm[*p], out_fp); + m = font_mapping(finfo[word_font(x)].font_table); + unacc = MapTable[m]->map[MAP_UNACCENTED]; + /* acc = MapTable[m]->map[MAP_ACCENT]; */ + for( p++; *p; p++ ) + { KernLength(word_font(x), unacc, *(p-1), *p, ksize); + if( ksize != 0 ) + { fprintf(out_fp, ")%c %d(", command, -ksize); + ++wordcount; + command = 'k'; + } + fputs(EightBitToPrintForm[*p], out_fp); + } + if( ++wordcount >= 5 ) + { fprintf(out_fp, ")%c\n", command); + wordcount = 0; + } + else fprintf(out_fp, ")%c ", command); + break; + + + + case PDF: + { + + static int last_hpos; /* does not need to be initialised */ + static int next_hpos = -1; +#if 0 + struct metrics *fnt; +#endif + /* if font is different to previous word then print change */ + if( word_font(x) != currentfont ) + { currentfont = word_font(x); + currentxheight2 = FontHalfXHeight(currentfont); + PDFFont_Set(out_fp, FontSize(currentfont, x), FontName(currentfont)); + } + + /* if colour is different to previous word then print change */ + if( word_colour(x) != currentcolour ) + { + currentcolour = word_colour(x); + if( currentcolour > 0 ) + { + char str[256]; + + sprintf(str, "%s ", ColourCommand(currentcolour)); + PDFPage_Write(out_fp, str); + } + } + + /* move to coordinate of x */ + debug1(DGP, DDD, " currentxheight2 = %d", currentxheight2); + vpos = vpos - currentxheight2; + if( cpexists && (currenty == vpos) && PDFHasValidTextMatrix() ) + { /* printnum(hpos, out_fp); */ + command = 's'; +/* + Note: I calculate the width of the space char here in case the font has + changed. This prevents subtle spacing errors from occurring. + */ +#if 0 + fnt = finfo[currentfont].size_table; + + if ( (next_hpos + fnt[' '].right /* width of space char */ ) == hpos ) + command = ' '; +#endif + } + else + { currenty = vpos; + /* printnum(hpos, out_fp); + fputs(" ", out_fp); + printnum(currenty, out_fp); */ + command = 'm'; + cpexists = TRUE; + } + + /* convert ligature sequences into ligature characters */ + lig = finfo[word_font(x)].lig_table; + p = q = string(x); + do + { + /* check for missing glyph (lig[] == 1) or ligatures (lig[] > 1) */ + if( lig[*q++ = *p++] ) + { + if( lig[*(q-1)] == 1 ) continue; + else + { a = &lig[ lig[*(p-1)] + MAX_CHARS ]; + while( *a++ == *(p-1) ) + { b = p; + while( *a == *b && *(a+1) != '\0' && *b != '\0' ) a++, b++; + if( *(a+1) == '\0' ) + { *(q-1) = *a; + p = b; + break; + } + else + { while( *++a ); + a++; + } + } + } + } + } while( *p ); + *q = '\0'; + + /* show string(x) */ + /* FontWordSize(x); - this should not be necessary */ + + switch (command) + { + case 'm': + + PDFText_OpenXY(out_fp, hpos, vpos); + last_hpos = hpos; + next_hpos = hpos + fwd(x, COLM); /* fwd(x, COLM) = width of wd */ + break; + + case 's': +#if 0 + PDFText_Open(out_fp); + PDFText_Kern(out_fp, hpos - next_hpos); +#else + PDFText_OpenX(out_fp, hpos - last_hpos); +#endif + last_hpos = hpos; + next_hpos = hpos + fwd(x, COLM); /* fwd(x, COLM) = width of wd */ + break; +#if 0 + case ' ': + + PDFText_Open(out_fp); +#if 1 + /* try kerning to get correct position */ + PDFText_Kern(out_fp, fnt[' '].right); +#else + PDFPage_Write(out_fp, EightBitToPrintForm[' ']); +#endif + next_hpos += fwd(x, COLM) + fnt[' '].right; /* width of space ch */ + break; +#endif + } + + p = string(x); + PDFPage_Write(out_fp, EightBitToPrintForm[*p]); + + m = font_mapping(finfo[word_font(x)].font_table); + unacc = MapTable[m]->map[MAP_UNACCENTED]; + /* acc = MapTable[m]->map[MAP_ACCENT]; */ + for( p++; *p; p++ ) + { + KernLength(word_font(x), unacc, *(p-1), *p, ksize); + KernLength(font_num(finfo[word_font(x)].original_font), + unacc, *(p-1), *p, ksize); + if ( ksize != 0 ) + { + PDFText_Kern(out_fp, ksize); + } + PDFPage_Write(out_fp, EightBitToPrintForm[*p]); + } + PDFText_Close(out_fp); + break; + } + + + } /* end switch */ + debug0(DGP, DDD, "PrintWord returning"); +} /* end PrintWord */ + + +/*****************************************************************************/ +/* */ +/* PrintPlainGraphicObject(x, xmk, ymk, z) */ +/* */ +/* Print plain graphic object x at xmk, ymk with the size of z. */ +/* */ +/*****************************************************************************/ + +void PrintPlainGraphicObject(OBJECT x, FULL_LENGTH xmk,FULL_LENGTH ymk,OBJECT z) +{ int i, len, starth, startv, stoph, stopv, h, v; + debug2(DGP, D, "PrintPlainGraphicObject(x, xmk %s, ymk %s)", + EchoLength(xmk), EchoLength(ymk)); + + assert( BackEnd == PLAINTEXT, "PrintPlainGraphicObject: back end!" ); + if( type(x) != WORD && type(x) != QWORD ) + { + Error(24, 12, "left parameter of %s must be a simple word", + WARN, &fpos(x), KW_PLAINGRAPHIC); + return; + } + len = StringLength(string(x)); + if( StringLength(string(x)) == 0 ) + { + Error(24, 13, "left parameter of %s must be a non-empty word", + WARN, &fpos(x), KW_PLAINGRAPHIC); + return; + } + starth = (((float) xmk ) / PlainCharWidth) + 0.5; + startv = (((float) ymk ) / PlainCharHeight); + stoph = (((float) xmk + size(z, COLM)) / PlainCharWidth) + 0.5; + stopv = (((float) ymk - size(z, ROWM)) / PlainCharHeight); /* NB - not + */ + SetLengthDim(COLM); + debug5(DGP, D, " xmk %s bk %s fwd %s -> %d,%d", + EchoLength(xmk), EchoLength(back(z, COLM)), EchoLength(fwd(z, COLM)), + starth, stoph); + SetLengthDim(ROWM); + debug5(DGP, D, " ymk %s bk %s fwd %s -> %d,%d", + EchoLength(ymk), EchoLength(back(z, ROWM)), EchoLength(fwd(z, ROWM)), + startv, stopv); + if( starth >= 0 && stoph < hsize && startv >= 0 && stopv < vsize ) + { i = 0; + for( v = startv-1; v >= stopv; v-- ) + { + for( h = starth; h < stoph; h++ ) + { + if( i == len ) i = 0; + page[v*hsize + h] = string(x)[i++]; + } + } + } + else + { + Error(24, 14, "fill %s deleted (internal error, off page at %d,%d)", + WARN, &fpos(x), string(x), h, v); + } +} /* end PrintPlainGraphicObject */ + + +/*****************************************************************************/ +/* */ +/* PrintUnderline(fnum, xstart, xstop, ymk) */ +/* */ +/* Draw an underline suitable for font fnum, from xstart to xstop at the */ +/* appropriate distance below mark ymk. */ +/* */ +/*****************************************************************************/ + +void PrintUnderline(FONT_NUM fnum, FULL_LENGTH xstart, FULL_LENGTH xstop, + FULL_LENGTH ymk) +{ + + debug4(DGP, DD, "PrintUnderline(fnum %d, xstart %s, xstop %s, ymk %s )", + fnum, EchoLength(xstart), EchoLength(xstop), EchoLength(ymk)); + + switch( BackEnd ) + { + case PLAINTEXT: + + /* do nothing */ + break; + + + case POSTSCRIPT: + + fprintf(out_fp, "%d %d %d %d ul\n", xstart, xstop, + ymk - finfo[fnum].underline_pos, finfo[fnum].underline_thick); + break; + + case PDF: + PDFPage_PrintUnderline(out_fp, xstart, xstop, + ymk - finfo[fnum].underline_pos, finfo[fnum].underline_thick); + break; + } + debug0(DGP, DD, "PrintUnderline returning."); +} /* end PrintUnderline */ + + +/*@::PrintAfterLast(), CoordTranslate()@**************************************/ +/* */ +/* PrintAfterLast() */ +/* */ +/* Clean up this module and close output stream. */ +/* */ +/*****************************************************************************/ + +void PrintAfterLast(void) +{ OBJECT x, link; BOOLEAN first_need; int i, j, jmax; + if( prologue_done ) + { + switch( BackEnd ) + { + case PLAINTEXT: + + /* print the page that has just ended (exists since prologue_done) */ + ifdebug(DGP, D, + putc('+', out_fp); + for( j = 0; j < hsize; j++ ) putc('-', out_fp); + putc('+', out_fp); + putc('\n', out_fp); + ); + for( i = vsize - 1; i >= 0; i-- ) + { ifdebug(DGP, D, putc('|', out_fp)); + for( jmax = hsize-1; jmax >= 0 && page[i*hsize+jmax] == ' '; jmax--); + ifdebug(DGP, D, jmax = hsize - 1); + for( j = 0; j <= jmax; j++ ) + putc(page[i*hsize + j], out_fp); + ifdebug(DGP, D, putc('|', out_fp)); + putc('\n', out_fp); + } + ifdebug(DGP, D, + putc('+', out_fp); + for( j = 0; j < hsize; j++ ) putc('-', out_fp); + putc('+', out_fp); + putc('\n', out_fp); + ); + break; + + + case POSTSCRIPT: + + fprintf(out_fp, "\npgsave restore\nshowpage\n"); + fprintf(out_fp, "\n%%%%Trailer\n"); + + /* print resource requirements (DSC 3.0 version) - fonts */ + first_need = FontNeeded(out_fp); + + /* print resource requirements (DSC 3.0 version) - included EPSFs */ + for( link = Down(needs); link != needs; link = NextDown(link) ) + { Child(x, link); + assert(is_word(type(x)), "PrintAfterLast: needs!" ); + fprintf(out_fp, "%s %s", + first_need ? "%%DocumentNeededResources:" : "%%+", string(x)); + first_need = FALSE; + } + + /* print resources supplied */ + fprintf(out_fp, + "%%%%DocumentSuppliedResources: procset %s\n", StartUpResource); + for( link = Down(supplied); link != supplied; link = NextDown(link) ) + { Child(x, link); + fprintf(out_fp, "%%%%+ %s", string(x)); + } + MapPrintResources(out_fp); + + fprintf(out_fp, "%%%%Pages: %d\n", pagecount); + fprintf(out_fp, "%%%%EOF\n"); + break; + + case PDF: + + PDFPage_Cleanup(out_fp); /* write out page objects */ + /* MapPrintResources(out_fp); not needed */ + PDFFile_Cleanup(out_fp); + break; + + } /* end switch */ + } /* end if prologue_done */ +} /* end PrintAfterLast */ + + +/*****************************************************************************/ +/* */ +/* CoordTranslate(xdist, ydist) */ +/* */ +/* Translate coordinate system by the given x and y distances. */ +/* */ +/*****************************************************************************/ + +void CoordTranslate(FULL_LENGTH xdist, FULL_LENGTH ydist) +{ debug2(DRS,D,"CoordTranslate(%s, %s)", + EchoLength(xdist), EchoLength(ydist)); + assert( BackEnd != PLAINTEXT, "CoordTranslate: BackEnd!" ); + if (BackEnd == POSTSCRIPT) + fprintf(out_fp, "%d %d translate\n", xdist, ydist); + else if (BackEnd == PDF) + { + if ((xdist != 0) || (ydist != 0)) + { +#if 1 + PDFPage_Translate(out_fp, xdist, ydist); +#else + char temp_str[64]; + sprintf(temp_str, "1 0 0 1 %d %d cm\n", xdist, ydist); + PDFPage_Write(out_fp, temp_str); +#endif + } + } + cpexists = FALSE; + /*** + currentfont = NO_FONT; + currentcolour = NO_COLOUR; + ***/ + debug0(DRS, D, "CoordTranslate returning."); +} /* end CoordTranslate */ + + +/*@::CoordRotate(), CoordScale(), SaveGraphicsState(), etc.@******************/ +/* */ +/* CoordRotate(amount) */ +/* */ +/* Rotate coordinate system by given amount (in internal DG units) */ +/* */ +/*****************************************************************************/ + +void CoordRotate(FULL_LENGTH amount) +{ debug1(DRS, D, "CoordRotate(%.1f degrees)", (float) amount / DG); + assert( BackEnd != PLAINTEXT, "CoordRotate: BackEnd!" ); + if (BackEnd == POSTSCRIPT) + fprintf(out_fp, "%.4f rotate\n", (float) amount / DG); + else if (BackEnd == PDF) + { + int theAmount = ((amount / DG) % 360); + if ( theAmount != 0 ) + { + #define PI 3.1415926535897931160 + + PDFPage_Rotate(out_fp, (double) theAmount * (double) PI / (double) 180.0); + } + } + cpexists = FALSE; + /*** + currentfont = NO_FONT; + currentcolour = NO_COLOUR; + ***/ + debug0(DRS, D, "CoordRotate returning."); +} /* end CoordRotate */ + + +/*****************************************************************************/ +/* */ +/* CoordScale(ratio, dim) */ +/* */ +/* Scale coordinate system by ratio in the given dimension. */ +/* */ +/*****************************************************************************/ + +void CoordScale(float hfactor, float vfactor) +{ +#if DEBUG_ON + char buff[20]; +#endif + assert( BackEnd != PLAINTEXT, "CoordScale: BackEnd!" ); + ifdebug(DRS, D, sprintf(buff, "%.3f, %.3f", hfactor, vfactor)); + debug1(DRS, D, "CoordScale(%s)", buff); + if (BackEnd == POSTSCRIPT) + fprintf(out_fp, "%.4f %.4f scale\n", hfactor, vfactor); + else if (BackEnd == PDF) + { + if ( (fabs(hfactor - 1.0) > 0.01) || (fabs(vfactor - 1.0) > 0.01) ) + { +#if 1 + PDFPage_Scale(out_fp, hfactor, vfactor); +#else + char temp_str[64]; + sprintf(temp_str, "%.2f 0 0 %.2f 0 0 cm\n", hfactor, vfactor); + PDFPage_Write(out_fp, temp_str); +#endif + } + } + cpexists = FALSE; + /*** + currentfont = NO_FONT; + currentcolour = NO_COLOUR; + ***/ + debug0(DRS, D, "CoordScale returning."); +} /* end CoordScale */ + + +/*****************************************************************************/ +/* */ +/* SaveGraphicState(x) */ +/* */ +/* Save current coord system on stack for later restoration. */ +/* Object x is just for error reporting, not really used at all. */ +/* */ +/*****************************************************************************/ + +void SaveGraphicState(OBJECT x) +{ debug0(DRS, D, "SaveGraphicState()"); + assert( BackEnd != PLAINTEXT, "SaveGraphicState: BackEnd!" ); + if (BackEnd == POSTSCRIPT) + fprintf(out_fp, "gsave\n"); + else if (BackEnd == PDF) + PDFPage_Push(out_fp); + gs_stack_top++; + if( gs_stack_top >= MAX_GS ) + Error(24, 5, "rotations, graphics etc. too deeply nested (max is %d)", + FATAL, &fpos(x), MAX_GS); + gs_stack[gs_stack_top].gs_font = currentfont; + gs_stack[gs_stack_top].gs_colour = currentcolour; + gs_stack[gs_stack_top].gs_cpexists = cpexists; + gs_stack[gs_stack_top].gs_currenty = currenty; + gs_stack[gs_stack_top].gs_xheight2 = currentxheight2; + debug0(DRS, D, "SaveGraphicState returning."); +} /* end SaveGraphicState */ + + +/*****************************************************************************/ +/* */ +/* RestoreGraphicState() */ +/* */ +/* Restore previously saved coordinate system. NB we normally assume that */ +/* no white space is needed before any item of output, but since this */ +/* procedure is sometimes called immediately after PrintGraphicObject(), */ +/* which does not append a concluding space, we prepend one here. */ +/* */ +/*****************************************************************************/ + +void RestoreGraphicState(void) +{ debug0(DRS, D, "RestoreGraphicState()"); + assert( BackEnd != PLAINTEXT, "RestoreGraphicState: BackEnd!" ); + if( BackEnd == POSTSCRIPT ) + fprintf(out_fp, "\ngrestore\n"); + else if( BackEnd == PDF ) + PDFPage_Pop(out_fp); + currentfont = gs_stack[gs_stack_top].gs_font; + currentcolour = gs_stack[gs_stack_top].gs_colour; + cpexists = gs_stack[gs_stack_top].gs_cpexists; + currenty = gs_stack[gs_stack_top].gs_currenty; + currentxheight2 = gs_stack[gs_stack_top].gs_xheight2; + gs_stack_top--; + /* *** + cpexists = FALSE; + currentfont = NO_FONT; + currentcolour = NO_COLOUR; + *** */ + debug0(DRS, D, "RestoreGraphicState returning."); +} /* end RestoreGraphicState */ + + +/*@::PrintGraphicObject(), DefineGraphicNames()@******************************/ +/* */ +/* PrintGraphicObject(x) */ +/* */ +/* Print object x on out_fp */ +/* */ +/*****************************************************************************/ + +void PrintGraphicObject(OBJECT x) +{ OBJECT y, link; + assert( BackEnd != PLAINTEXT, "PrintGraphicObject: BackEnd!" ); + debug3(DPS, D, "PrintGraphicObject(%s %s %s)", + EchoFilePos(&fpos(x)), Image(type(x)), EchoObject(x)); + switch( type(x) ) + { + case WORD: + case QWORD: +#if 1 + if (BackEnd == POSTSCRIPT) + StringFPuts(string(x), out_fp); + else if (BackEnd == PDF) + { + PDFPage_WriteGraphic(out_fp, string(x)); + } +#else + StringFPuts(string(x), out_fp); +#endif + break; + + + case ACAT: + + for( link = Down(x); link != x; link = NextDown(link) ) + { Child(y, link); + if( type(y) == GAP_OBJ ) + { + if( BackEnd == POSTSCRIPT ) + { + if( vspace(y) > 0 ) fputs("\n", out_fp); + else if( hspace(y) > 0 ) fputs(" ", out_fp); + } + else if( BackEnd == PDF ) + { + if( vspace(y) > 0 ) PDFPage_Write(out_fp, "\n"); + else if( hspace(y) > 0 ) PDFPage_Write(out_fp, " "); + } + } + else if( is_word(type(y)) || type(y) == ACAT ) + PrintGraphicObject(y); + else if( type(y) != WIDE && !is_index(type(y)) ) + /* @Wide, indexes are sometimes inserted by Manifest */ + { Error(24, 6, "error in left parameter of %s", + WARN, &fpos(x), KW_GRAPHIC); + debug1(DGP, D, " type(y) = %s, y =", Image(type(y))); + ifdebug(DGP, D, DebugObject(y)); + } + } + break; + + + default: + + Error(24, 7, "error in left parameter of %s", WARN, &fpos(x), KW_GRAPHIC); + debug1(DGP, D, " type(x) = %s, x =", Image(type(x))); + ifdebug(DGP, D, DebugObject(x)); + break; + + } + debug0(DPS, D, "PrintGraphicObject returning"); +} /* end PrintGraphicObject */ + + +/*****************************************************************************/ +/* */ +/* DefineGraphicNames(x) */ +/* */ +/* Generate PostScript for xsize, ysize etc. names of graphic object. */ +/* */ +/*****************************************************************************/ + +void DefineGraphicNames(OBJECT x) +{ assert( type(x) == GRAPHIC, "PrintGraphic: type(x) != GRAPHIC!" ); + assert( BackEnd != PLAINTEXT, "DefineGraphicNames: BackEnd!" ); + debug1(DRS, D, "DefineGraphicNames( %s )", EchoObject(x)); + debug1(DRS, DD, " style = %s", EchoStyle(&save_style(x))); + + /* if font is different to previous word then print change */ + if( font(save_style(x)) != currentfont ) + { currentfont = font(save_style(x)); + if( currentfont > 0 ) + { currentxheight2 = FontHalfXHeight(currentfont); +#if 1 /* VT 98/01/04: modified for PDF */ + if (BackEnd == POSTSCRIPT) + fprintf(out_fp, "%hd %s ", FontSize(currentfont, x), FontName(currentfont)); + else if (BackEnd == PDF) + PDFFont_Set(out_fp, FontSize(currentfont, x), FontName(currentfont)); +#else + fprintf(out_fp, "%hd %s ", FontSize(currentfont, x), + FontName(currentfont)); +#endif + } + } + + /* if colour is different to previous word then print change */ + if( colour(save_style(x)) != currentcolour ) + { currentcolour = colour(save_style(x)); + if( currentcolour > 0 ) + { +#if 1 + if( BackEnd == POSTSCRIPT ) + fprintf(out_fp, "%s ", ColourCommand(currentcolour)); + else if (BackEnd == PDF) + { + char str[256]; + sprintf(str, "%s ", ColourCommand(currentcolour)); + PDFPage_Write(out_fp, str); + } +#else + fprintf(out_fp, "%s ", ColourCommand(currentcolour)); +#endif + } + } + + if (BackEnd == POSTSCRIPT) + fprintf(out_fp, "%d %d %d %d %d %d %d LoutGraphic\n", + size(x, COLM), size(x, ROWM), back(x, COLM), fwd(x, ROWM), + currentfont <= 0 ? 12*PT : FontSize(currentfont, x), + width(line_gap(save_style(x))), width(space_gap(save_style(x)))); + else if( BackEnd == PDF ) + { + PDFPage_SetVars(size(x, COLM), size(x, ROWM), back(x, COLM), fwd(x, ROWM), + currentfont <= 0 ? 12*PT : FontSize(currentfont, x), + width(line_gap(save_style(x))), width(space_gap(save_style(x)))); + } + + debug0(DRS, D, "DefineGraphicNames returning."); +} /* end DefineGraphicNames */ + + +/*****************************************************************************/ +/* */ +/* SaveTranslateDefineSave(x, xdist, ydist) */ +/* */ +/* Equivalent to the sequence of calls */ +/* */ +/* SaveGraphicState(x) */ +/* CoordTranslate(xdist, ydist) */ +/* DefineGraphicNames(x) */ +/* SaveGraphicState(x) */ +/* */ +/* but generates less PostScript. */ +/* */ +/*****************************************************************************/ + +void SaveTranslateDefineSave(OBJECT x, FULL_LENGTH xdist, FULL_LENGTH ydist) +{ + if( BackEnd == PDF ) + { + /* do it bit by bit */ + SaveGraphicState(x); + CoordTranslate(xdist, ydist); + DefineGraphicNames(x); + SaveGraphicState(x); + return; + } + + assert( BackEnd == POSTSCRIPT, "SaveTranslateDefineSave: BackEnd!" ); + if( gs_stack_top >= MAX_GS - 1 || font(save_style(x)) != currentfont || + colour(save_style(x))!=currentcolour ) + { + /* do it bit by bit, will be rare anyway */ + SaveGraphicState(x); + CoordTranslate(xdist, ydist); + DefineGraphicNames(x); + SaveGraphicState(x); + } + else + { + /* no font or colour changes, no stack overflow, so can optimize */ + + /* from Save */ + gs_stack_top++; + gs_stack[gs_stack_top].gs_font = currentfont; + gs_stack[gs_stack_top].gs_colour = currentcolour; + gs_stack[gs_stack_top].gs_cpexists = cpexists; + gs_stack[gs_stack_top].gs_currenty = currenty; + gs_stack[gs_stack_top].gs_xheight2 = currentxheight2; + + /* from CoordTranslate */ + cpexists = FALSE; + + /* from Save */ + gs_stack_top++; + gs_stack[gs_stack_top].gs_font = currentfont; + gs_stack[gs_stack_top].gs_colour = currentcolour; + gs_stack[gs_stack_top].gs_cpexists = cpexists; + gs_stack[gs_stack_top].gs_currenty = currenty; + gs_stack[gs_stack_top].gs_xheight2 = currentxheight2; + + /* accumulated output from all four calls, repackaged */ + fprintf(out_fp, "%d %d %d %d %d %d %d %d %d LoutGr2\n", + size(x, COLM), size(x, ROWM), back(x, COLM), fwd(x, ROWM), + currentfont <= 0 ? 12*PT : FontSize(currentfont, x), + width(line_gap(save_style(x))), width(space_gap(save_style(x))), + xdist, ydist); + + } +} /* end SaveTranslateDefineSave */ + + +/*@::PrintGraphicInclude()@***************************************************/ +/* */ +/* PrintGraphicInclude(x, colmark, rowmark) */ +/* */ +/* Print graphic include file, with appropriate surrounds. This code */ +/* closely follows the PostScript Language Reference Manual, 2n ed., */ +/* pages 733-5, except we do not clip the included EPSF. */ +/* */ +/* Note to porters: Version 3.0 of the EPSF standard is not compatible */ +/* with previous versions. Thus, this output may crash your system. */ +/* If you can find out which comment line(s) are causing the trouble, */ +/* you can add to procedure strip_out to strip them out during the */ +/* file inclusion step. e.g. on my system %%EOF causes problems, so I */ +/* strip it out. */ +/* */ +/* May 1994: I've just discovered that %%Trailer causes problems for */ +/* the mpage Unix utility, so now I'm stripping it out as well. */ +/* */ +/*****************************************************************************/ +#define SKIPPING 0 +#define READING_DNR 1 +#define FINISHED 2 + +static BOOLEAN strip_out(FULL_CHAR *buff) +{ if( StringBeginsWith(buff, AsciiToFull("%%EOF")) ) return TRUE; + if( StringBeginsWith(buff, AsciiToFull("%%Trailer")) ) return TRUE; + return FALSE; +} /* end strip_out */ + +void PrintGraphicInclude(OBJECT x, FULL_LENGTH colmark, FULL_LENGTH rowmark) +{ OBJECT y, full_name; FULL_CHAR buff[MAX_BUFF]; + FILE *fp; int state; BOOLEAN compressed; + debug0(DRS, D, "PrintGraphicInclude(x)"); + + if (BackEnd == PDF) + { + Error(24, 8, "PrintGraphicInclude: cannot include EPSF in a PDF file. File ignored.", + WARN, &fpos(x)); + return; + } + + assert( BackEnd == POSTSCRIPT, "PrintGraphicInclude: BackEnd!" ); + assert(type(x)==INCGRAPHIC || type(x)==SINCGRAPHIC, "PrintGraphicInclude!"); + assert(incgraphic_ok(x), "PrintGraphicInclude: !incgraphic_ok(x)!"); + + /* open the include file and get its full path name */ + Child(y, Down(x)); + fp = OpenIncGraphicFile(string(y), type(x), &full_name,&fpos(y),&compressed); + assert( fp != NULL, "PrintGraphicInclude: fp!" ); + + /* if font is different to previous word then print change */ + if( font(save_style(x)) != currentfont ) + { currentfont = font(save_style(x)); + currentxheight2 = FontHalfXHeight(currentfont); + fprintf(out_fp, "%hd %s\n", FontSize(currentfont,x), FontName(currentfont)); + } + + /* if colour is different to previous word then print change */ + if( colour(save_style(x)) != currentcolour ) + { currentcolour = colour(save_style(x)); + if( currentcolour > 0 ) + { + fprintf(out_fp, "%s\n", ColourCommand(currentcolour)); + } + } + + /* generate appropriate header code */ + fprintf(out_fp, "BeginEPSF\n"); + CoordTranslate(colmark - back(x, COLM), rowmark - fwd(x, ROWM)); + CoordScale( (float) PT, (float) PT ); + CoordTranslate(-back(y, COLM), -back(y, ROWM)); + fprintf(out_fp, "%%%%BeginDocument: %s\n", string(full_name)); + + /* copy through the include file, except divert resources lines to needs */ + /* and strip out some comment lines that cause problems */ + state = (StringFGets(buff, MAX_BUFF, fp) == NULL) ? FINISHED : SKIPPING; + while( state != FINISHED ) switch(state) + { + case SKIPPING: + + if( StringBeginsWith(buff, AsciiToFull("%%DocumentNeededResources:")) && + !StringContains(buff, AsciiToFull("(atend)")) ) + { y = MakeWord(WORD, &buff[StringLength("%%DocumentNeededResources:")], + no_fpos); + Link(needs, y); + state = (StringFGets(buff,MAX_BUFF,fp)==NULL) ? FINISHED : READING_DNR; + } + else + { if( StringBeginsWith(buff, AsciiToFull("%%LanguageLevel:")) ) + Error(24, 9, "ignoring LanguageLevel comment in %s file %s", + WARN, &fpos(x), KW_INCGRAPHIC, string(full_name)); + if( StringBeginsWith(buff, AsciiToFull("%%Extensions:")) ) + Error(24, 10, "ignoring Extensions comment in %s file %s", + WARN, &fpos(x), KW_INCGRAPHIC, string(full_name)); + if( !strip_out(buff) ) StringFPuts(buff, out_fp); + state = (StringFGets(buff, MAX_BUFF, fp) == NULL) ? FINISHED : SKIPPING; + } + break; + + case READING_DNR: + + if( StringBeginsWith(buff, AsciiToFull("%%+")) ) + { x = MakeWord(WORD, &buff[StringLength(AsciiToFull("%%+"))], no_fpos); + Link(needs, x); + state = (StringFGets(buff,MAX_BUFF,fp)==NULL) ? FINISHED : READING_DNR; + } + else + { if( !strip_out(buff) ) StringFPuts(buff, out_fp); + state = (StringFGets(buff, MAX_BUFF, fp) == NULL) ? FINISHED : SKIPPING; + } + break; + } + + /* wrapup */ + DisposeObject(full_name); + fclose(fp); + if( compressed ) StringRemove(AsciiToFull(LOUT_EPS)); + fprintf(out_fp, "\n%%%%EndDocument\nEndEPSF\n"); + wordcount = 0; + debug0(DRS, D, "PrintGraphicInclude returning."); +} /* end PrintGraphicInclude */ |