/*@z50.c:PDF Back End:PDF_BackEnd@********************************************/ /* */ /* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.41) */ /* COPYRIGHT (C) 1991, 2023 Jeffrey H. Kingston */ /* */ /* Jeffrey H. Kingston (jeff@it.usyd.edu.au) */ /* School of Information Technologies */ /* 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 3, 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: z50.c */ /* MODULE: PDF Back End (in addition to z48.c) */ /* EXTERNS: PDF_BackEnd */ /* */ /*****************************************************************************/ #include /* for fabs() */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #include "externs.h" #include "child.h" /*****************************************************************************/ /* */ /* State variables for this module */ /* */ /*****************************************************************************/ #define NO_FONT 0 /* actually stolen from z37.c */ #define NO_COLOUR 0 #define NO_TEXTURE 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 */ BOOLEAN gs_baselinemark; /* TRUE if baseline mark */ COLOUR_NUM gs_colour; /* colour number of this state */ TEXTURE_NUM gs_texture; /* texture 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 BOOLEAN currentbaselinemark; /* baseline mark in use */ static COLOUR_NUM currentcolour; /* colour of most recent atom */ static TEXTURE_NUM currenttexture; /* texture 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 ); \ } /*****************************************************************************/ /* */ /* void PDF_PrintInitialize(FILE *fp, BOOLEAN enc) */ /* */ /* Initialize this module; fp is the output file. */ /* */ /*****************************************************************************/ static void PDF_PrintInitialize(FILE *fp, BOOLEAN enc) { debug0(DPF, DD, "PDF_PrintInitialize(fp)"); assert(!enc, "PDF_PrintInitialize"); out_fp = fp; prologue_done = FALSE; gs_stack_top = -1; currentfont = NO_FONT; currentbaselinemark = FALSE; currentcolour = NO_COLOUR; currentcolour = NO_TEXTURE; 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) { FULL_CHAR *enc = NULL; fprintf(out_fp, "%%%%IncludeResource: font %s%s", font_name, STR_NEWLINE); /*** PDFFont_AddFont(out_fp, first_size_str, font_name, MapEncodingName(font_mapping(face))); ***/ if (font_recoded(face)) { MAPPING m = font_mapping(face); /* This is a NASTY hack. Need to rework the interface Since PDF is random-access format - we don't care which page this encoding is for and we need to only print it once -- Uwe */ MapEnsurePrinted(m, 1); enc = MapEncodingName(m); } PDFFont_AddFont(out_fp, first_size_str, font_name, enc); } /* 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%s", string(map->vector[i]), (i+1)%8 != 0 ? STR_SPACE : STR_NEWLINE); 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 */ /*****************************************************************************/ /* */ /* 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; /* *** currently unused unsigned short *composite; COMPOSITE *cmp; *** */ 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 baselinemark is different to previous word then record change */ if( word_baselinemark(x) != currentbaselinemark ) { currentbaselinemark = word_baselinemark(x); currentxheight2 = currentbaselinemark ? 0 : FontHalfXHeight(currentfont); } /* if font is different to previous word then print change */ if( word_font(x) != currentfont ) { currentfont = word_font(x); currentxheight2 = currentbaselinemark ? 0 : FontHalfXHeight(currentfont); PDFFont_Set(out_fp, FontSize(currentfont, x), FontName(currentfont)); } /* PDF textures not implemented */ /* 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); } } /* PDF textures not implemented */ /* 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 || !word_ligatures(x) ) 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 ) { /* this empty statement added by JeffK 17/6/23 */ } 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 ksize = FontKernLength(word_font(x), unacc, *(p-1), *p); *** */ ksize = FontKernLength(font_num(finfo[word_font(x)].original_face), unacc, *(p-1), *p); 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, col, xstart, xstop, ymk) */ /* */ /* Draw an underline suitable for font fnum, in colour col from xstart to */ /* xstop at the appropriate distance below mark ymk. */ /* */ /*****************************************************************************/ static void PDF_PrintUnderline(FONT_NUM fnum, COLOUR_NUM col, TEXTURE_NUM pat, FULL_LENGTH xstart, FULL_LENGTH xstop, FULL_LENGTH ymk) { debug5(DPF, DD, "PDF_PrintUnderline(ft %d, co %d, xstrt %s, xstp %s, ymk %s)", fnum, col, 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%s", xdist, ydist, STR_NEWLINE); 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) */ /* */ /*****************************************************************************/ 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) M_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%s", hfactor, vfactor, STR_NEWLINE); 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_baselinemark = currentbaselinemark; gs_stack[gs_stack_top].gs_colour = currentcolour; gs_stack[gs_stack_top].gs_texture = currenttexture; 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; currentbaselinemark = gs_stack[gs_stack_top].gs_baselinemark; currentcolour = gs_stack[gs_stack_top].gs_colour; currenttexture = gs_stack[gs_stack_top].gs_texture; 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, (char *) STR_NEWLINE); 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 baselinemark is different to previous word then record change */ if( baselinemark(save_style(x)) != currentbaselinemark ) { currentbaselinemark = baselinemark(save_style(x)); currentxheight2 = currentbaselinemark ? 0 : FontHalfXHeight(currentfont); } /* 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 = currentbaselinemark ? 0 : FontHalfXHeight(currentfont); PDFFont_Set(out_fp, FontSize(currentfont, x), FontName(currentfont)); } } /* PDF textures not implemented */ /* 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_LinkSource(name, llx, lly, urx, ury) */ /* */ /* Print a link source point. */ /* */ /*****************************************************************************/ static void PDF_LinkSource(OBJECT name, FULL_LENGTH llx, FULL_LENGTH lly, FULL_LENGTH urx, FULL_LENGTH ury) { debug5(DPF, D, "PDF_LinkSource(%s, %d, %d, %d, %d)", EchoObject(name), llx, lly, urx, ury); /* still to do */ debug0(DPF, D, "PDF_LinkSource returning."); } /* end PDF_LinkSource */ /*****************************************************************************/ /* */ /* PDF_LinkDest(name, llx, lly, urx, ury) */ /* */ /* Print a link dest point. */ /* */ /* Still to do: check that the name has not been used by a previous */ /* dest point. */ /* */ /*****************************************************************************/ static void PDF_LinkDest(OBJECT name, FULL_LENGTH llx, FULL_LENGTH lly, FULL_LENGTH urx, FULL_LENGTH ury) { debug5(DPF, D, "PDF_LinkDest(%s, %d, %d, %d, %d)", EchoObject(name), llx, lly, urx, ury); /* still to do */ debug0(DPF, D, "PDF_LinkDest returning."); } /* end PDF_LinkDest */ /*****************************************************************************/ /* */ /* PDF_LinkURL(url, llx, lly, urx, ury) */ /* */ /* Print a URL link. */ /* */ /*****************************************************************************/ static void PDF_LinkURL(OBJECT url, FULL_LENGTH llx, FULL_LENGTH lly, FULL_LENGTH urx, FULL_LENGTH ury) { debug5(DPF, D, "PDF_LinkURL(%s, %d, %d, %d, %d)", EchoObject(url), llx, lly, urx, ury); /* still to do */ debug0(DPF, D, "PDF_LinkURL returning."); } /* end PDF_LinkURL */ /*****************************************************************************/ /* */ /* PDF_LinkCheck(void) */ /* */ /* Called at end of run; will check that for every link source point there */ /* is a link dest point. */ /* */ /*****************************************************************************/ static void PDF_LinkCheck(void) { debug0(DPF, D, "PDF_LinkCheck()"); /* still to do */ debug0(DPF, D, "PDF_LinkCheck returning."); } /* end PDF_LinkCheck */ /*****************************************************************************/ /* */ /* 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 */ FALSE, /* TRUE if @VMirror, @HMirror avail. */ 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, NULL, NULL, PDF_SaveGraphicState, PDF_RestoreGraphicState, PDF_PrintGraphicObject, PDF_DefineGraphicNames, PDF_SaveTranslateDefineSave, PDF_PrintGraphicInclude, PDF_LinkSource, PDF_LinkDest, PDF_LinkURL, PDF_LinkCheck, }; BACK_END PDF_BackEnd = &pdf_back;