aboutsummaryrefslogtreecommitdiffstats
path: root/z50.c
diff options
context:
space:
mode:
authorJeffrey H. Kingston <jeff@it.usyd.edu.au>2010-09-14 20:37:03 +0000
committerJeffrey H. Kingston <jeff@it.usyd.edu.au>2010-09-14 20:37:03 +0000
commitae5e320497a180f1af743d716e9ac3ea11f01463 (patch)
treea52e523ace2e98b57c761a8319f45b8aee208fce /z50.c
parentb10d39aec443165093f8f28bc6f940530b89cdaf (diff)
downloadlout-ae5e320497a180f1af743d716e9ac3ea11f01463.tar.gz
Lout 3.22 tag.3.22
git-svn-id: http://svn.savannah.nongnu.org/svn/lout/tags/3.22@14 9365b830-b601-4143-9ba8-b4a8e2c3339c
Diffstat (limited to 'z50.c')
-rw-r--r--z50.c804
1 files changed, 804 insertions, 0 deletions
diff --git a/z50.c b/z50.c
new file mode 100644
index 0000000..379f94a
--- /dev/null
+++ b/z50.c
@@ -0,0 +1,804 @@
+/*@z50.c:PDF Back End:PDF_BackEnd@********************************************/
+/* */
+/* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.22) */
+/* COPYRIGHT (C) 1991, 2000 Jeffrey H. Kingston */
+/* */
+/* Jeffrey H. Kingston (jeff@cs.usyd.edu.au) */
+/* Basser Department of Computer Science */
+/* The University of Sydney 2006 */
+/* AUSTRALIA */
+/* */
+/* 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: z49.c */
+/* MODULE: PDF Back End */
+/* EXTERNS: PDF_BackEnd */
+/* */
+/*****************************************************************************/
+#include <math.h> /* for fabs() */
+#include "externs.h"
+
+
+/*****************************************************************************/
+/* */
+/* State variables for this module */
+/* */
+/*****************************************************************************/
+#define NO_FONT 0 /* actually stolen from z37.c */
+#define NO_COLOUR 0
+#define MAX_GS 50 /* maximum depth of graphics states */
+
+static FILE *out_fp; /* file to print PDF on */
+
+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 */
+
+
+/*****************************************************************************/
+/* */
+/* Print a number x on file fp. */
+/* */
+/*****************************************************************************/
+
+#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 ); \
+}
+
+
+/*****************************************************************************/
+/* */
+/* PDF_PrintInitialize(FILE *fp) */
+/* */
+/* Initialize this module; fp is the output file. */
+/* */
+/*****************************************************************************/
+
+static void PDF_PrintInitialize(FILE *fp)
+{
+ debug0(DPF, DD, "PDF_PrintInitialize(fp)");
+ out_fp = fp;
+ 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(DPF, DD, "PDF_PrintInitialize returning.");
+} /* end PDF_PrintInitialize */
+
+
+/*****************************************************************************/
+/* */
+/* void PDF_PrintLength(FULL_CHAR *buff, int length, int length_dim) */
+/* */
+/* Print a length (debugging only) */
+/* */
+/*****************************************************************************/
+
+static void PDF_PrintLength(FULL_CHAR *buff, int length, int length_dim)
+{
+ sprintf( (char *) buff, "%.3fc", (float) length/CM);
+}
+
+
+/*****************************************************************************/
+/* */
+/* void PDF_PrintPageSetupForFont(OBJECT face, int font_curr_page, */
+/* FULL_CHAR *font_name, FULL_CHAR *first_size_str) */
+/* */
+/* Print the page setup commands required to use a font on some page: */
+/* */
+/* face The font face record, defining which font we need */
+/* font_curr_page The current page number */
+/* fp The file to print the command(s) on */
+/* font_name The name of the font */
+/* first_size_str No idea, have to check */
+/* */
+/*****************************************************************************/
+
+static void PDF_PrintPageSetupForFont(OBJECT face, int font_curr_page,
+ FULL_CHAR *font_name, FULL_CHAR *first_size_str)
+{
+ fprintf(out_fp, "%%%%IncludeResource: font %s\n", font_name);
+ PDFFont_AddFont(out_fp, first_size_str, font_name,
+ MapEncodingName(font_mapping(face)));
+} /* end PDF_PrintPageSetupForFont */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_PrintPageResourceForFont(FULL_CHAR *font_name, BOOLEAN first) */
+/* */
+/* Print page resource info on file fp for font font_name; first is true */
+/* if this is the first resource on this page. */
+/* */
+/*****************************************************************************/
+
+static void PDF_PrintPageResourceForFont(FULL_CHAR *font_name, BOOLEAN first)
+{
+ /* JK: this was always commented out */
+ /* PDFWriteFontResource(out_fp, font_name); */
+} /* end PDF_PrintPageResourceForFont */
+
+
+/*****************************************************************************/
+/* */
+/* static void PDF_PrintMapping(MAPPING m) */
+/* */
+/* Print mapping m. */
+/* */
+/*****************************************************************************/
+
+static void PDF_PrintMapping(MAPPING m)
+{ MAP_VEC map = MapTable[m]; int i;
+ PDFFile_BeginFontEncoding(out_fp, (char*) string(map->name));
+ for( i = 0; i < MAX_CHARS; i++ )
+ fprintf(out_fp, "/%s%c", string(map->vector[i]), (i+1)%8 != 0 ? ' ' : '\n');
+ PDFFile_EndFontEncoding(out_fp);
+} /* end PDF_PrintMapping */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_PrintBeforeFirstPage(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. */
+/* */
+/*****************************************************************************/
+
+static void PDF_PrintBeforeFirstPage(FULL_LENGTH h, FULL_LENGTH v,
+ FULL_CHAR *label)
+{
+ debug2(DPF, DD, "PrintBeforeFirst(%d, %d)", h, v);
+ PDFFile_Init(out_fp, h/PT, v/PT, IN, CM, PT, EM);
+ FontPrintPageSetup(out_fp);
+ PDFPage_Init(out_fp, 1.0 / PT, PT/2);
+ FontPrintPageResources(out_fp); /* write out font objects */
+ FontAdvanceCurrentPage();
+ prologue_done = TRUE;
+} /* end PDF_PrintBeforeFirstPage */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_PrintBetweenPages(h, v, label) */
+/* */
+/* Start a new output component, of size h by v; label is the page label */
+/* to attach to the %%Page comment. */
+/* */
+/*****************************************************************************/
+
+static void PDF_PrintBetweenPages(FULL_LENGTH h, FULL_LENGTH v,
+ FULL_CHAR *label)
+{
+ debug2(DPF, DD, "PrintBetween(%d, %d)", h, v);
+
+ /* 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();
+} /* end PDF_PrintBetweenPages */
+
+
+/*****************************************************************************/
+/* */
+/* 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, j; \
+ 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 */
+
+
+/*****************************************************************************/
+/* */
+/* static void PrintComposite(COMPOSITE *cp, BOOLEAN outline, FILE *fp) */
+/* */
+/* This routine is unused in this module because it is the PostScript */
+/* version and no PDF version has been written so far. JeffK 2/5/00. */
+/* */
+/* Print composite character cp, assuming that the current point is */
+/* set to the correct origin. If outline is true, we want to print the */
+/* composite character in outline. */
+/* */
+/*****************************************************************************/
+
+static void PrintComposite(COMPOSITE *cp, BOOLEAN outline, FILE *fp)
+{ debug1(DPF, D, "PrintComposite(cp, %s, fp)", bool(outline));
+ while( cp->char_code != '\0' )
+ {
+ debug4(DPF, D, " cp = %d printing code %d (%d, %d)", (int) cp,
+ cp->char_code, cp->x_offset, cp->y_offset);
+ fprintf(fp, "%d %d (%c)%s ", cp->x_offset, cp->y_offset,
+ cp->char_code, outline ? "co" : "c");
+ cp++;
+ }
+} /* end PrintComposite */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_PrintWord(x, hpos, vpos) */
+/* */
+/* Print non-empty word x; its marks cross at the point (hpos, vpos). */
+/* */
+/*****************************************************************************/
+
+static void PDF_PrintWord(OBJECT x, int hpos, int vpos)
+{ FULL_CHAR *p, *q, *a, *b, *lig, *unacc;
+ int ksize; char *command; MAPPING m;
+ unsigned short *composite; COMPOSITE *cmp; /* currently unused - JeffK */
+ static int last_hpos; /* does not need to be initialised */
+ static int next_hpos = -1;
+#if 0
+ struct metrics *fnt;
+#endif
+
+ debug6(DPF, DD, "PrintWord( %s, %d, %d ) font %d colour %d%s", string(x),
+ hpos, vpos, word_font(x), word_colour(x),
+ word_outline(x) ? " outline" : "");
+ TotalWordCount++;
+
+ /* 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(DPF, 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. */
+#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';
+
+ switch (command[0])
+ {
+ 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++ )
+ {
+ /* *** this seems right but is actually wrong for PDF,
+ which according to Uwe uses original units for kerning
+ KernLength(word_font(x), unacc, *(p-1), *p, ksize);
+ *** */
+ KernLength(font_num(finfo[word_font(x)].original_face),
+ unacc, *(p-1), *p, ksize);
+ if ( ksize != 0 )
+ {
+ PDFText_Kern(out_fp, ksize);
+ }
+ PDFPage_Write(out_fp, EightBitToPrintForm[*p]);
+ }
+ PDFText_Close(out_fp);
+
+ debug0(DPF, DDD, "PDF_PrintWord returning");
+} /* end PDF_PrintWord */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_PrintPlainGraphic(OBJECT x, FULL_LENGTH xmk, ymk, OBJECT z) */
+/* */
+/* Print a plain graphic object */
+/* */
+/*****************************************************************************/
+
+static void PDF_PrintPlainGraphic(OBJECT x, FULL_LENGTH xmk,
+ FULL_LENGTH ymk, OBJECT z)
+{
+ assert(FALSE, "PDF_PrintPlainGraphic: this routine should never be called!");
+} /* end PDF_PrintPlainGraphic */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_PrintUnderline(fnum, xstart, xstop, ymk) */
+/* */
+/* Draw an underline suitable for font fnum, from xstart to xstop at the */
+/* appropriate distance below mark ymk. */
+/* */
+/*****************************************************************************/
+
+static void PDF_PrintUnderline(FONT_NUM fnum, FULL_LENGTH xstart,
+ FULL_LENGTH xstop, FULL_LENGTH ymk)
+{
+ debug4(DPF, DD, "PDF_PrintUnderline(fnum %d, xstart %s, xstop %s, ymk %s )",
+ fnum, EchoLength(xstart), EchoLength(xstop), EchoLength(ymk));
+ PDFPage_PrintUnderline(out_fp, xstart, xstop,
+ ymk - finfo[fnum].underline_pos, finfo[fnum].underline_thick);
+ debug0(DPF, DD, "PrintUnderline returning.");
+} /* end PDF_PrintUnderline */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_PrintAfterLastPage() */
+/* */
+/* Clean up this module and close output stream. */
+/* */
+/*****************************************************************************/
+
+void PDF_PrintAfterLastPage(void)
+{
+ if( prologue_done )
+ {
+ PDFPage_Cleanup(out_fp); /* write out page objects */
+ /* MapPrintResources(out_fp); not needed */
+ PDFFile_Cleanup(out_fp);
+ }
+} /* end PDF_PrintAfterLastPage */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_CoordTranslate(xdist, ydist) */
+/* */
+/* Translate coordinate system by the given x and y distances. */
+/* */
+/*****************************************************************************/
+
+static void PDF_CoordTranslate(FULL_LENGTH xdist, FULL_LENGTH ydist)
+{ debug2(DPF, D, "CoordTranslate(%s, %s)",
+ EchoLength(xdist), EchoLength(ydist));
+ 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;
+ debug0(DPF, D, "PDF_CoordTranslate returning.");
+} /* end PDF_CoordTranslate */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_CoordRotate(amount) */
+/* */
+/* Rotate coordinate system by given amount (in internal DG units) */
+/* */
+/*****************************************************************************/
+#define PI 3.1415926535897931160
+
+static void PDF_CoordRotate(FULL_LENGTH amount)
+{ int theAmount;
+ debug1(DPF, D, "PDF_CoordRotate(%.1f degrees)", (float) amount / DG);
+ theAmount = ((amount / DG) % 360);
+ if( theAmount != 0 )
+ PDFPage_Rotate(out_fp, (double) theAmount * (double) PI / (double) 180.0);
+ cpexists = FALSE;
+ debug0(DPF, D, "CoordRotate returning.");
+} /* end PDF_CoordRotate */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_CoordScale(ratio, dim) */
+/* */
+/* Scale coordinate system by ratio in the given dimension. */
+/* */
+/*****************************************************************************/
+
+static void PDF_CoordScale(float hfactor, float vfactor)
+{
+#if DEBUG_ON
+ char buff[20];
+#endif
+ ifdebug(DPF, D, sprintf(buff, "%.3f, %.3f", hfactor, vfactor));
+ debug1(DPF, D, "CoordScale(%s)", buff);
+ 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;
+ debug0(DPF, D, "CoordScale returning.");
+} /* end PDF_CoordScale */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_SaveGraphicState(x) */
+/* */
+/* Save current coord system on stack for later restoration. */
+/* Object x is just for error reporting, not really used at all. */
+/* */
+/*****************************************************************************/
+
+void PDF_SaveGraphicState(OBJECT x)
+{ debug0(DPF, D, "PDF_SaveGraphicState()");
+ PDFPage_Push(out_fp);
+ gs_stack_top++;
+ if( gs_stack_top >= MAX_GS )
+ Error(50, 1, "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(DPF, D, "PDF_SaveGraphicState returning.");
+} /* end PDF_SaveGraphicState */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_RestoreGraphicState() */
+/* */
+/* Restore previously saved coordinate system. */
+/* */
+/* The following note probably only applies to the PostScript back end */
+/* but I have not looked into this issue myself: */
+/* */
+/* 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 PDF_RestoreGraphicState(void)
+{ debug0(DPF, D, "PDF_RestoreGraphicState()");
+ 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--;
+ debug0(DPF, D, "PDF_RestoreGraphicState returning.");
+} /* end PDF_RestoreGraphicState */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_PrintGraphicObject(x) */
+/* */
+/* Print object x on out_fp */
+/* */
+/*****************************************************************************/
+
+void PDF_PrintGraphicObject(OBJECT x)
+{ OBJECT y, link;
+ debug3(DPF, D, "PDF_PrintGraphicObject(%s %s %s)",
+ EchoFilePos(&fpos(x)), Image(type(x)), EchoObject(x));
+ switch( type(x) )
+ {
+ case WORD:
+ case QWORD:
+
+ PDFPage_WriteGraphic(out_fp, string(x));
+ break;
+
+
+ case ACAT:
+
+ for( link = Down(x); link != x; link = NextDown(link) )
+ { Child(y, link);
+ if( type(y) == GAP_OBJ )
+ {
+ 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 )
+ PDF_PrintGraphicObject(y);
+ else if( type(y) == WIDE || is_index(type(y)) )
+ {
+ /* ignore: @Wide, indexes are sometimes inserted by Manifest */
+ }
+ else
+ { Error(50, 2, "error in left parameter of %s",
+ WARN, &fpos(x), KW_GRAPHIC);
+ debug1(DPF, D, " type(y) = %s, y =", Image(type(y)));
+ ifdebug(DPF, D, DebugObject(y));
+ }
+ }
+ break;
+
+
+ default:
+
+ Error(50, 3, "error in left parameter of %s", WARN, &fpos(x), KW_GRAPHIC);
+ debug1(DPF, D, " type(x) = %s, x =", Image(type(x)));
+ ifdebug(DPF, D, DebugObject(x));
+ break;
+
+ }
+ debug0(DPF, D, "PDF_PrintGraphicObject returning");
+} /* end PDF_PrintGraphicObject */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_DefineGraphicNames(x) */
+/* */
+/* Generate PostScript for xsize, ysize etc. names of graphic object. */
+/* */
+/*****************************************************************************/
+
+void PDF_DefineGraphicNames(OBJECT x)
+{ assert( type(x) == GRAPHIC, "PrintGraphic: type(x) != GRAPHIC!" );
+ debug1(DPF, D, "DefineGraphicNames( %s )", EchoObject(x));
+ debug1(DPF, 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);
+ PDFFont_Set(out_fp, 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 )
+ { char str[256];
+ sprintf(str, "%s ", ColourCommand(currentcolour));
+ PDFPage_Write(out_fp, str);
+ }
+ }
+
+ 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(DPF, D, "PDF_DefineGraphicNames returning.");
+} /* end PDF_DefineGraphicNames */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_SaveTranslateDefineSave(x, xdist, ydist) */
+/* */
+/* Equivalent to the sequence of calls */
+/* */
+/* SaveGraphicState(x) */
+/* CoordTranslate(xdist, ydist) */
+/* DefineGraphicNames(x) */
+/* SaveGraphicState(x) */
+/* */
+/* but offers prospects for optimization (not taken up in PDF). */
+/* */
+/*****************************************************************************/
+
+void PDF_SaveTranslateDefineSave(OBJECT x, FULL_LENGTH xdist, FULL_LENGTH ydist)
+{
+ PDF_SaveGraphicState(x);
+ PDF_CoordTranslate(xdist, ydist);
+ PDF_DefineGraphicNames(x);
+ PDF_SaveGraphicState(x);
+} /* end PDF_SaveTranslateDefineSave */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_PrintGraphicInclude(x, colmark, rowmark) */
+/* */
+/* Print graphic include file, with appropriate surrounds. */
+/* */
+/*****************************************************************************/
+
+void PDF_PrintGraphicInclude(OBJECT x, FULL_LENGTH colmark, FULL_LENGTH rowmark)
+{ OBJECT y;
+ debug0(DPF, D, "PDF_PrintGraphicInclude(x)");
+ Child(y, Down(x));
+ Error(50, 4, "cannot include EPS file in PDF output; EPS file %s ignored",
+ WARN, &fpos(x), string(y));
+ debug0(DPF, D, "PDF_PrintGraphicInclude returning.");
+} /* end PDF_PrintGraphicInclude */
+
+
+/*****************************************************************************/
+/* */
+/* PDF_BackEnd */
+/* */
+/* The record into which all of these functions are packaged. */
+/* */
+/*****************************************************************************/
+
+static struct back_end_rec pdf_back = {
+ PDF, /* the code number of the back end */
+ STR_PDF, /* string name of the back end */
+ TRUE, /* TRUE if @Scale is available */
+ TRUE, /* TRUE if @Rotate is available */
+ TRUE, /* TRUE if @Graphic is available */
+ TRUE, /* TRUE if @IncludeGraphic is avail. */
+ FALSE, /* TRUE if @PlainGraphic is avail. */
+ TRUE, /* TRUE if fractional spacing avail. */
+ TRUE, /* TRUE if actual font metrics used */
+ TRUE, /* TRUE if colour is available */
+ PDF_PrintInitialize,
+ PDF_PrintLength,
+ PDF_PrintPageSetupForFont,
+ PDF_PrintPageResourceForFont,
+ PDF_PrintMapping,
+ PDF_PrintBeforeFirstPage,
+ PDF_PrintBetweenPages,
+ PDF_PrintAfterLastPage,
+ PDF_PrintWord,
+ PDF_PrintPlainGraphic,
+ PDF_PrintUnderline,
+ PDF_CoordTranslate,
+ PDF_CoordRotate,
+ PDF_CoordScale,
+ PDF_SaveGraphicState,
+ PDF_RestoreGraphicState,
+ PDF_PrintGraphicObject,
+ PDF_DefineGraphicNames,
+ PDF_SaveTranslateDefineSave,
+ PDF_PrintGraphicInclude,
+};
+
+BACK_END PDF_BackEnd = &pdf_back;