diff options
Diffstat (limited to 'lib/libpbmfont.c')
-rw-r--r-- | lib/libpbmfont.c | 1155 |
1 files changed, 0 insertions, 1155 deletions
diff --git a/lib/libpbmfont.c b/lib/libpbmfont.c deleted file mode 100644 index 8f308eda..00000000 --- a/lib/libpbmfont.c +++ /dev/null @@ -1,1155 +0,0 @@ -/* -** -** Font routines. -** -** BDF font code Copyright 1993 by George Phillips. -** -** Copyright (C) 1991 by Jef Poskanzer. -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. -** -** BDF font specs available from: -** https://partners.adobe.com/public/developer/en/font/5005.BDF_Spec.pdf -** Glyph Bitmap Distribution Format (BDF) Specification -** Version 2.2 -** 22 March 1993 -** Adobe Developer Support -*/ - -#include <assert.h> -#include <string.h> -#include <ctype.h> - -#include "netpbm/pm_c_util.h" -#include "netpbm/mallocvar.h" -#include "netpbm/nstring.h" - -#include "pbmfont.h" -#include "pbm.h" - -static unsigned int const firstCodePoint = 32; - /* This is the code point of the first character in a pbmfont font. - In ASCII, it is a space. - */ - -static unsigned int const nCharsInFont = 96; - /* The number of characters in a pbmfont font. A pbmfont font defines - characters at position 32 (ASCII space) through 127, so that's 96. - */ - - -struct font * -pbm_defaultfont(const char * const name) { -/*---------------------------------------------------------------------------- - Generate the built-in font with name 'name'. ------------------------------------------------------------------------------*/ - struct font * retval; - - if (streq(name, "bdf")) - retval = &pbm_defaultBdffont; - else if (streq(name, "fixed")) - retval = &pbm_defaultFixedfont; - else - pm_error( "built-in font name unknown, try 'bdf' or 'fixed'"); - - return retval; -} - - - -static void -findFirstBlankRow(const bit ** const font, - unsigned int const fcols, - unsigned int const frows, - unsigned int * const browP) { - - unsigned int row; - bool foundBlank; - - for (row = 0, foundBlank = false; row < frows / 6 && !foundBlank; ++row) { - unsigned int col; - bit col0Value = font[row][0]; - bool rowIsBlank; - rowIsBlank = true; /* initial assumption */ - for (col = 1; col < fcols; ++col) - if (font[row][col] != col0Value) - rowIsBlank = false; - - if (rowIsBlank) { - foundBlank = true; - *browP = row; - } - } - - if (!foundBlank) - pm_error("couldn't find blank pixel row in font"); -} - - - -static void -findFirstBlankCol(const bit ** const font, - unsigned int const fcols, - unsigned int const frows, - unsigned int * const bcolP) { - - unsigned int col; - bool foundBlank; - - for (col = 0, foundBlank = false; col < fcols / 6 && !foundBlank; ++col) { - unsigned int row; - bit row0Value = font[0][col]; - bool colIsBlank; - colIsBlank = true; /* initial assumption */ - for (row = 1; row < frows; ++row) - if (font[row][col] != row0Value) - colIsBlank = false; - - if (colIsBlank) { - foundBlank = true; - *bcolP = col; - } - } - - if (!foundBlank) - pm_error("couldn't find blank pixel column in font"); -} - - - -static void -computeCharacterSize(const bit ** const font, - unsigned int const fcols, - unsigned int const frows, - unsigned int * const cellWidthP, - unsigned int * const cellHeightP, - unsigned int * const charWidthP, - unsigned int * const charHeightP) { - - unsigned int firstBlankRow; - unsigned int firstBlankCol; - unsigned int heightLast11Rows; - - findFirstBlankRow(font, fcols, frows, &firstBlankRow); - - findFirstBlankCol(font, fcols, frows, &firstBlankCol); - - heightLast11Rows = frows - firstBlankRow; - - if (heightLast11Rows % 11 != 0) - pm_error("The rows of characters in the font do not appear to " - "be all the same height. The last 11 rows are %u pixel " - "rows high (from pixel row %u up to %u), " - "which is not a multiple of 11.", - heightLast11Rows, firstBlankRow, frows); - else { - unsigned int widthLast15Cols; - - *cellHeightP = heightLast11Rows / 11; - - widthLast15Cols = fcols - firstBlankCol; - - if (widthLast15Cols % 15 != 0) - pm_error("The columns of characters in the font do not appear to " - "be all the same width. " - "The last 15 columns are %u pixel " - "columns wide (from pixel col %u up to %u), " - "which is not a multiple of 15.", - widthLast15Cols, firstBlankCol, fcols); - else { - *cellWidthP = widthLast15Cols / 15; - - *charWidthP = firstBlankCol; - *charHeightP = firstBlankRow; - } - } -} - - - -struct font* -pbm_dissectfont(const bit ** const font, - unsigned int const frows, - unsigned int const fcols) { - /* - This routine expects a font bitmap representing the following text: - - (0,0) - M ",/^_[`jpqy| M - - / !"#$%&'()*+ / - < ,-./01234567 < - > 89:;<=>?@ABC > - @ DEFGHIJKLMNO @ - _ PQRSTUVWXYZ[ _ - { \]^_`abcdefg { - } hijklmnopqrs } - ~ tuvwxyz{|}~ ~ - - M ",/^_[`jpqy| M - - The bitmap must be cropped exactly to the edges. - - The characters in the border you see are irrelevant except for - character size compuations. The 12 x 8 array in the center is - the font. The top left character there belongs to code point - 0, and the code points increase in standard reading order, so - the bottom right character is code point 127. You can't define - code points < 32 or > 127 with this font format. - - The characters in the top and bottom border rows must include a - character with the lowest reach of any in the font (e.g. "y", - "_") and one with the highest reach (e.g. '"'). The characters - in the left and right border columns must include characters - with the rightmost and leftmost reach of any in the font - (e.g. "M" for both). - - The border must be separated from the font by one blank text - row or text column. - - The dissection works by finding the first blank row and column; - i.e the lower right corner of the "M" in the upper left corner - of the matrix. That gives the height and width of the - maximum-sized character, which is not too useful. But the - distance from there to the opposite side is an integral - multiple of the cell size, and that's what we need. Then it's - just a matter of filling in all the coordinates. */ - - unsigned int cellWidth, cellHeight; - /* Dimensions in pixels of each cell of the font -- that - includes the glyph and the white space above and to the - right of it. Each cell is a tile of the font image. The - top character row and left character row don't count -- - those cells are smaller because they are missing the white - space. - */ - unsigned int charWidth, charHeight; - /* Maximum dimensions of glyph itself, inside its cell */ - - int row, col, ch, r, c, i; - struct font * fn; - struct glyph * glyph; - char* bmap; - - computeCharacterSize(font, fcols, frows, - &cellWidth, &cellHeight, &charWidth, &charHeight); - - /* Now convert to a general font */ - - MALLOCVAR(fn); - if (fn == NULL) - pm_error("out of memory allocating font structure"); - - fn->maxwidth = charWidth; - fn->maxheight = charHeight; - fn->x = fn->y = 0; - - fn->oldfont = font; - fn->frows = frows; - fn->fcols = fcols; - - /* Initialize all character positions to "undefined." Those that - are defined in the font will be filled in below. - */ - for (i = 0; i < PM_FONT_MAXGLYPH + 1; i++) - fn->glyph[i] = NULL; - - MALLOCARRAY(glyph, nCharsInFont); - if ( glyph == NULL ) - pm_error( "out of memory allocating glyphs" ); - - bmap = (char*) malloc( fn->maxwidth * fn->maxheight * nCharsInFont ); - if ( bmap == (char*) 0) - pm_error( "out of memory allocating glyph data" ); - - /* Now fill in the 0,0 coords. */ - row = cellHeight * 2; - col = cellWidth * 2; - for (i = 0; i < firstCodePoint; ++i) - fn->glyph[i] = NULL; - - for ( ch = 0; ch < nCharsInFont; ++ch ) { - glyph[ch].width = fn->maxwidth; - glyph[ch].height = fn->maxheight; - glyph[ch].x = glyph[ch].y = 0; - glyph[ch].xadd = cellWidth; - - for ( r = 0; r < glyph[ch].height; ++r ) - for ( c = 0; c < glyph[ch].width; ++c ) - bmap[r * glyph[ch].width + c] = font[row + r][col + c]; - - glyph[ch].bmap = bmap; - bmap += glyph[ch].width * glyph[ch].height; - - fn->glyph[firstCodePoint + ch] = &glyph[ch]; - - col += cellWidth; - if ( col >= cellWidth * 14 ) { - col = cellWidth * 2; - row += cellHeight; - } - } - for (i = firstCodePoint + nCharsInFont; i < PM_FONT_MAXGLYPH + 1; ++i) - fn->glyph[i] = NULL; - - return fn; -} - - - -struct font * -pbm_loadfont(const char * const filename) { - - FILE * fileP; - struct font * fontP; - char line[10] = "\0\0\0\0\0\0\0\0\0\0"; - /* Initialize to suppress Valgrind error which is reported when file - is empty or very small. - */ - - fileP = pm_openr(filename); - fgets(line, 10, fileP); - pm_close(fileP); - - if (line[0] == PBM_MAGIC1 && - (line[1] == PBM_MAGIC2 || line[1] == RPBM_MAGIC2)) { - fontP = pbm_loadpbmfont(filename); - } else if (!strncmp(line, "STARTFONT", 9)) { - fontP = pbm_loadbdffont(filename); - if (!fontP) - pm_error("could not load BDF font file"); - } else { - pm_error("font file not in a recognized format. Does not start " - "with the signature of a PBM file or BDF font file"); - assert(false); - fontP = NULL; /* defeat compiler warning */ - } - return fontP; -} - - - -struct font * -pbm_loadpbmfont(const char * const filename) { - - FILE * ifP; - bit ** font; - int fcols, frows; - - ifP = pm_openr(filename); - - font = pbm_readpbm(ifP, &fcols, &frows); - - if ((fcols - 1) / 16 >= pbm_maxfontwidth() || - (frows - 1) / 12 >= pbm_maxfontheight()) - pm_error("Absurdly large PBM font file: %s", filename); - else if (fcols < 31 || frows < 23) { - /* Need at least one pixel per character, and this is too small to - have that. - */ - pm_error("PBM font file '%s' too small to be a font file: %u x %u. " - "Minimum sensible size is 31 x 23", - filename, fcols, frows); - } - - pm_close(ifP); - - return pbm_dissectfont((const bit **)font, frows, fcols); -} - - - -void -pbm_dumpfont(struct font * const fontP, - FILE * const ofP) { -/*---------------------------------------------------------------------------- - Dump out font as C source code. ------------------------------------------------------------------------------*/ - unsigned int i; - unsigned int ng; - - if (fontP->oldfont) - pm_message("Netpbm no longer has the capability to generate " - "a font in long hexadecimal data format"); - - for (i = 0, ng = 0; i < PM_FONT_MAXGLYPH +1; ++i) { - if (fontP->glyph[i]) - ++ng; - } - - printf("static struct glyph _g[%d] = {\n", ng); - - for (i = 0; i < PM_FONT_MAXGLYPH + 1; ++i) { - struct glyph * const glyphP = fontP->glyph[i]; - if (glyphP) { - unsigned int j; - printf(" { %d, %d, %d, %d, %d, \"", glyphP->width, glyphP->height, - glyphP->x, glyphP->y, glyphP->xadd); - - for (j = 0; j < glyphP->width * glyphP->height; ++j) { - if (glyphP->bmap[j]) - printf("\\1"); - else - printf("\\0"); - } - --ng; - printf("\" }%s\n", ng ? "," : ""); - } - } - printf("};\n"); - - printf("struct font XXX_font = { %d, %d, %d, %d, {\n", - fontP->maxwidth, fontP->maxheight, fontP->x, fontP->y); - - { - unsigned int i; - - for (i = 0; i < PM_FONT_MAXGLYPH + 1; ++i) { - if (fontP->glyph[i]) - printf(" _g + %d", ng++); - else - printf(" NULL"); - - if (i != PM_FONT_MAXGLYPH) printf(","); - printf("\n"); - } - } - - printf(" }\n};\n"); -} - - -/*---------------------------------------------------------------------------- - Routines for loading a BDF font file ------------------------------------------------------------------------------*/ - - -/* The following are not recognized in individual glyph data; library - routines do a pm_error if they see one: - - Vertical writing systems: DWIDTH1, SWIDTH1, VVECTOR, METRICSET, - CONTENTVERSION. - - The following is not recognized and is thus ignored at the global level: - DWIDTH -*/ - - -#define MAXBDFLINE 1024 - -/* Official Adobe document says max length of string is 65535 characters. - However the value 1024 is sufficient for practical uses. -*/ - -typedef struct { -/*---------------------------------------------------------------------------- - This is an object for reading lines of a font file. It reads and tokenizes - them into words. ------------------------------------------------------------------------------*/ - FILE * ifP; - - char line[MAXBDFLINE+1]; - /* This is the storage space for the words of the line. The - words go in here, one after another, separated by NULs. - - It also functions as a work area for readline_read(). - */ - const char * arg[6]; - /* These are the words; each entry is a pointer into line[] (above) */ -} Readline; - - - -static void -readline_init(Readline * const readlineP, - FILE * const ifP) { - - readlineP->ifP = ifP; - - readlineP->arg[0] = NULL; -} - - - -static void -tokenize(char * const s, - const char ** const words, - unsigned int const wordsSz) { -/*---------------------------------------------------------------------------- - Chop up 's' into words by changing space characters to NUL. Return as - 'words' an array of pointers to the beginnings of those words in 's'. - Terminate the words[] list with a null pointer. - - 'wordsSz' is the number of elements of space in 'words'. If there are more - words in 's' than will fit in that space (including the terminating null - pointer), ignore the excess on the right. ------------------------------------------------------------------------------*/ - unsigned int n; /* Number of words in words[] so far */ - char * p; - - p = &s[0]; - n = 0; - - while (*p) { - if (ISSPACE(*p)) - *p++ = '\0'; - else { - words[n++] = p; - if (n >= wordsSz - 1) - break; - while (*p && !ISSPACE(*p)) - ++p; - } - } - assert(n <= wordsSz - 1); - words[n] = NULL; -} - - - -static void -readline_read(Readline * const readlineP, - bool * const eofP) { -/*---------------------------------------------------------------------------- - Read a nonblank line from the file. Make its contents available - as readlineP->arg[]. - - Return *eofP == true iff there is no nonblank line before EOF or we - are unable to read the file. ------------------------------------------------------------------------------*/ - bool gotLine; - bool error; - - for (gotLine = false, error = false; !gotLine && !error; ) { - char * rc; - - rc = fgets(readlineP->line, MAXBDFLINE+1, readlineP->ifP); - if (rc == NULL) - error = true; - else { - tokenize(readlineP->line, - readlineP->arg, ARRAY_SIZE(readlineP->arg)); - if (readlineP->arg[0] != NULL) - gotLine = true; - } - } - *eofP = error; -} - - - -static void -parseBitmapRow(const char * const hex, - unsigned int const glyphWidth, - unsigned char * const bmap, - unsigned int const origBmapIndex, - unsigned int * const newBmapIndexP, - const char ** const errorP) { -/*---------------------------------------------------------------------------- - Parse one row of the bitmap for a glyph, from the hexadecimal string - for that row in the font file, 'hex'. The glyph is 'glyphWidth' - pixels wide. - - We place our result in 'bmap' at *bmapIndexP and advanced *bmapIndexP. ------------------------------------------------------------------------------*/ - unsigned int bmapIndex; - int i; /* dot counter */ - const char * p; - - bmapIndex = origBmapIndex; - - for (i = glyphWidth, p = &hex[0], *errorP = NULL; - i > 0 && !*errorP; - i -= 4) { - - if (*p == '\0') - pm_asprintf(errorP, "Not enough hexadecimal digits for glyph " - "of width %u in '%s'", - glyphWidth, hex); - else { - char const hdig = *p++; - unsigned int hdigValue; - - if (hdig >= '0' && hdig <= '9') - hdigValue = hdig - '0'; - else if (hdig >= 'a' && hdig <= 'f') - hdigValue = 10 + (hdig - 'a'); - else if (hdig >= 'A' && hdig <= 'F') - hdigValue = 10 + (hdig - 'A'); - else - pm_asprintf(errorP, - "Invalid hex digit x%02x (%c) in bitmap data '%s'", - (unsigned int)(unsigned char)hdig, - isprint(hdig) ? hdig : '.', - hex); - - if (!*errorP) { - if (i > 0) - bmap[bmapIndex++] = hdigValue & 0x8 ? 1 : 0; - if (i > 1) - bmap[bmapIndex++] = hdigValue & 0x4 ? 1 : 0; - if (i > 2) - bmap[bmapIndex++] = hdigValue & 0x2 ? 1 : 0; - if (i > 3) - bmap[bmapIndex++] = hdigValue & 0x1 ? 1 : 0; - } - } - } - *newBmapIndexP = bmapIndex; -} - - - -static void -readBitmap(Readline * const readlineP, - unsigned int const glyphWidth, - unsigned int const glyphHeight, - const char * const charName, - unsigned char * const bmap) { - - int n; - unsigned int bmapIndex; - - bmapIndex = 0; - - for (n = glyphHeight; n > 0; --n) { - bool eof; - const char * error; - - readline_read(readlineP, &eof); - - if (eof) - pm_error("End of file in bitmap for character '%s' in BDF " - "font file.", charName); - - if (!readlineP->arg[0]) - pm_error("A line that is supposed to contain bitmap data, " - "in hexadecimal, for character '%s' is empty", charName); - - parseBitmapRow(readlineP->arg[0], glyphWidth, bmap, bmapIndex, - &bmapIndex, &error); - - if (error) { - pm_error("Error in line %d of bitmap for character '%s': %s", - n, charName, error); - pm_strfree(error); - } - } -} - - - -static void -createBmap(unsigned int const glyphWidth, - unsigned int const glyphHeight, - Readline * const readlineP, - const char * const charName, - const char ** const bmapP) { - - unsigned char * bmap; - bool eof; - - if (glyphWidth > 0 && UINT_MAX / glyphWidth < glyphHeight) - pm_error("Ridiculously large glyph"); - - MALLOCARRAY(bmap, glyphWidth * glyphHeight); - - if (!bmap) - pm_error("no memory for font glyph byte map"); - - readline_read(readlineP, &eof); - if (eof) - pm_error("End of file encountered reading font glyph byte map from " - "BDF font file."); - - if (streq(readlineP->arg[0], "ATTRIBUTES")) { - /* ATTRIBUTES is defined in Glyph Bitmap Distribution Format (BDF) - Specification Version 2.1, but not in Version 2.2. - */ - bool eof; - readline_read(readlineP, &eof); - if (eof) - pm_error("End of file encountered after ATTRIBUTES in BDF " - "font file."); - } - if (!streq(readlineP->arg[0], "BITMAP")) - pm_error("'%s' found where BITMAP expected in definition of " - "character '%s' in BDF font file.", - readlineP->arg[0], charName); - - assert(streq(readlineP->arg[0], "BITMAP")); - - readBitmap(readlineP, glyphWidth, glyphHeight, charName, bmap); - - *bmapP = (char *)bmap; -} - - - -static void -readExpectedStatement(Readline * const readlineP, - const char * const expected) { -/*---------------------------------------------------------------------------- - Have the readline object *readlineP read the next line from the file, but - expect it to be a line of type 'expected' (i.e. the verb token at the - beginning of the line is that, e.g. "STARTFONT"). If it isn't, fail the - program. ------------------------------------------------------------------------------*/ - bool eof; - - readline_read(readlineP, &eof); - - if (eof) - pm_error("EOF in BDF font file where '%s' expected", expected); - else if (!streq(readlineP->arg[0], expected)) - pm_error("Statement of type '%s' where '%s' expected in BDF font file", - readlineP->arg[0], expected); -} - - - -static void -skipCharacter(Readline * const readlineP) { -/*---------------------------------------------------------------------------- - In the BDF font file being read by readline object *readlineP, skip through - the end of the character we are presently in. ------------------------------------------------------------------------------*/ - bool endChar; - - endChar = FALSE; - - while (!endChar) { - bool eof; - readline_read(readlineP, &eof); - if (eof) - pm_error("End of file in the middle of a character (before " - "ENDCHAR) in BDF font file."); - endChar = streq(readlineP->arg[0], "ENDCHAR"); - } -} - - - -static void -interpEncoding(const char ** const arg, - unsigned int * const codepointP, - bool * const badCodepointP, - PM_WCHAR const maxglyph) { -/*---------------------------------------------------------------------------- - With arg[] being the ENCODING statement from the font, return as - *codepointP the codepoint that it indicates (code point is the character - code, e.g. in ASCII, 48 is '0'). - - But if the statement doesn't give an acceptable codepoint return - *badCodepointP == TRUE. - - 'maxglyph' is the maximum codepoint in the font. ------------------------------------------------------------------------------*/ - bool gotCodepoint; - bool badCodepoint; - unsigned int codepoint; - - if (atoi(arg[1]) >= 0) { - codepoint = atoi(arg[1]); - gotCodepoint = true; - } else { - if (atoi(arg[1]) == -1 && arg[2] != NULL) { - codepoint = atoi(arg[2]); - gotCodepoint = true; - } else - gotCodepoint = false; - } - if (gotCodepoint) { - if (codepoint > maxglyph) - badCodepoint = true; - else - badCodepoint = false; - } else - badCodepoint = true; - - *badCodepointP = badCodepoint; - *codepointP = codepoint; -} - - - -static void -readEncoding(Readline * const readlineP, - unsigned int * const codepointP, - bool * const badCodepointP, - PM_WCHAR const maxglyph) { - - readExpectedStatement(readlineP, "ENCODING"); - - interpEncoding(readlineP->arg, codepointP, badCodepointP, maxglyph); -} - - - -static void -validateFontLimits(const struct font2 * const fontP) { - - assert(pbm_maxfontheight() > 0 && pbm_maxfontwidth() > 0); - - if (fontP->maxwidth <= 0 || - fontP->maxheight <= 0 || - fontP->maxwidth > pbm_maxfontwidth() || - fontP->maxheight > pbm_maxfontheight() || - -fontP->x + 1 > fontP->maxwidth || - -fontP->y + 1 > fontP->maxheight || - fontP->x > fontP->maxwidth || - fontP->y > fontP->maxheight || - fontP->x + fontP->maxwidth > pbm_maxfontwidth() || - fontP->y + fontP->maxheight > pbm_maxfontheight() - ) { - - pm_error("Global font metric(s) out of bounds."); - } - - if (fontP->maxglyph > PM_FONT2_MAXGLYPH) - pm_error("Internal error. Glyph table too large: %u glyphs; " - "Maximum possible in Netpbm is %u", - fontP->maxglyph, PM_FONT2_MAXGLYPH); -} - - - -static void -validateGlyphLimits(const struct font2 * const fontP, - const struct glyph * const glyphP, - const char * const charName) { - - /* Some BDF files code space with zero width and height, - no bitmap data and just the xadd value. - We allow zero width and height, iff both are zero. - */ - - if (((glyphP->width == 0 || glyphP->height == 0) && - !(glyphP->width == 0 && glyphP->height == 0)) || - glyphP->width > fontP->maxwidth || - glyphP->height > fontP->maxheight || - glyphP->x < fontP->x || - glyphP->y < fontP->y || - glyphP->x + (int) glyphP->width > fontP->x + fontP->maxwidth || - glyphP->y + (int) glyphP->height > fontP->y + fontP->maxheight || - glyphP->xadd > pbm_maxfontwidth() || - glyphP->xadd + MAX(glyphP->x,0) + (int) glyphP->width > - pbm_maxfontwidth() - ) { - - pm_error("Font metric(s) for char '%s' out of bounds.\n", charName); - } -} - - - -static void -processChars(Readline * const readlineP, - struct font2 * const fontP, - PM_WCHAR const maxglyph ) { -/*---------------------------------------------------------------------------- - Process the CHARS block in a BDF font file, assuming the file is positioned - just after the CHARS line. Read the rest of the block and apply its - contents to *fontP. ------------------------------------------------------------------------------*/ - unsigned int const nCharacters = atoi(readlineP->arg[1]); - - unsigned int nCharsDone; - - nCharsDone = 0; - - while (nCharsDone < nCharacters) { - bool eof; - - readline_read(readlineP, &eof); - if (eof) - pm_error("End of file after CHARS reading BDF font file"); - - if (streq(readlineP->arg[0], "COMMENT")) { - /* ignore */ - } else if (!streq(readlineP->arg[0], "STARTCHAR")) - pm_error("no STARTCHAR after CHARS in BDF font file"); - else { - const char * const charName = pm_strdup(readlineP->arg[1]); - - struct glyph * glyphP; - unsigned int codepoint; - bool badCodepoint; - - assert(streq(readlineP->arg[0], "STARTCHAR")); - - MALLOCVAR(glyphP); - - if (glyphP == NULL) - pm_error("no memory for font glyph for '%s' character", - charName); - - readEncoding(readlineP, &codepoint, &badCodepoint, maxglyph); - - if (badCodepoint) - skipCharacter(readlineP); - else if (fontP->glyph[codepoint] != NULL) - pm_error("Multiple definition of code point %d " - "in font file", (unsigned int) codepoint); - else { - readExpectedStatement(readlineP, "SWIDTH"); - - readExpectedStatement(readlineP, "DWIDTH"); - glyphP->xadd = atoi(readlineP->arg[1]); - - readExpectedStatement(readlineP, "BBX"); - glyphP->width = atoi(readlineP->arg[1]); - glyphP->height = atoi(readlineP->arg[2]); - glyphP->x = atoi(readlineP->arg[3]); - glyphP->y = atoi(readlineP->arg[4]); - - validateGlyphLimits(fontP, glyphP, charName); - - createBmap(glyphP->width, glyphP->height, readlineP, charName, - &glyphP->bmap); - - - readExpectedStatement(readlineP, "ENDCHAR"); - - assert(codepoint <= maxglyph); /* Ensured by readEncoding() */ - - fontP->glyph[codepoint] = glyphP; - pm_strfree(charName); - } - ++nCharsDone; - } - } -} - - - -static void -processBdfFontLine(Readline * const readlineP, - struct font2 * const fontP, - bool * const endOfFontP, - PM_WCHAR const maxglyph) { -/*---------------------------------------------------------------------------- - Process a nonblank line just read from a BDF font file. - - This processing may involve reading more lines. ------------------------------------------------------------------------------*/ - *endOfFontP = FALSE; /* initial assumption */ - - assert(readlineP->arg[0] != NULL); /* Entry condition */ - - if (streq(readlineP->arg[0], "COMMENT")) { - /* ignore */ - } else if (streq(readlineP->arg[0], "SIZE")) { - /* ignore */ - } else if (streq(readlineP->arg[0], "STARTPROPERTIES")) { - /* Read off the properties and ignore them all */ - unsigned int const propCount = atoi(readlineP->arg[1]); - - unsigned int i; - for (i = 0; i < propCount; ++i) { - bool eof; - readline_read(readlineP, &eof); - if (eof) - pm_error("End of file after STARTPROPERTIES in BDF font file"); - } - } else if (streq(readlineP->arg[0], "FONTBOUNDINGBOX")) { - fontP->maxwidth = atoi(readlineP->arg[1]); - fontP->maxheight = atoi(readlineP->arg[2]); - fontP->x = atoi(readlineP->arg[3]); - fontP->y = atoi(readlineP->arg[4]); - validateFontLimits(fontP); - } else if (streq(readlineP->arg[0], "ENDPROPERTIES")) { - if (fontP->maxwidth ==0) - pm_error("Encountered ENDPROPERTIES before FONTBOUNDINGBOX " - "in BDF font file"); - } else if (streq(readlineP->arg[0], "ENDFONT")) { - *endOfFontP = true; - } else if (streq(readlineP->arg[0], "CHARS")) { - if (fontP->maxwidth ==0) - pm_error("Encountered CHARS before FONTBOUNDINGBOX " - "in BDF font file"); - else - processChars(readlineP, fontP, maxglyph); - } else { - /* ignore */ - } -} - - - -struct font2 * -pbm_loadbdffont2(const char * const filename, - PM_WCHAR const maxglyph) { -/*---------------------------------------------------------------------------- - Read a BDF font file "filename" as a 'font2' structure. A 'font2' - structure is more expressive than a 'font' structure, most notably in that - it can handle wide code points and many more glyphs. - - Codepoints up to maxglyph inclusive are valid in the file. - - The returned object is in new malloc'ed storage, in many pieces, and - cannot be destroyed. ------------------------------------------------------------------------------*/ - /* For our return object to be destroyable, we need to supply a destroy - function, and it needs to return glyph and raster memory, and - struct font needs to manage glyph memory separately from mapping - code points to glyphs. - */ - FILE * ifP; - Readline readline; - struct font2 * font2P; - bool endOfFont; - - ifP = fopen(filename, "rb"); - if (!ifP) - pm_error("Unable to open BDF font file name '%s'. errno=%d (%s)", - filename, errno, strerror(errno)); - - readline_init(&readline, ifP); - - MALLOCVAR(font2P); - if (font2P == NULL) - pm_error("no memory for font"); - - MALLOCARRAY(font2P->glyph, maxglyph + 1); - if (font2P->glyph == NULL) - pm_error("no memory for font glyphs"); - - font2P->maxglyph = maxglyph; - - font2P->oldfont = NULL; - { - /* Initialize all characters to nonexistent; we will fill the ones we - find in the bdf file later. - */ - PM_WCHAR i; - for (i = 0; i <= maxglyph; ++i) - font2P->glyph[i] = NULL; - } - - font2P->maxwidth = font2P->maxheight = font2P->x = font2P->y = 0; - - readExpectedStatement(&readline, "STARTFONT"); - - endOfFont = FALSE; - - while (!endOfFont) { - bool eof; - readline_read(&readline, &eof); - if (eof) - pm_error("End of file before ENDFONT statement in BDF font file"); - - processBdfFontLine(&readline, font2P, &endOfFont, maxglyph); - } - return font2P; -} - - - -struct font * -pbm_loadbdffont(const char * const filename) { -/*---------------------------------------------------------------------------- - Read a BDF font file "filename" into a traditional font structure. - - Codepoints up to 255 (PM_FONT_MAXGLYPH) are valid. - - Can handle ASCII, ISO-8859-1, ISO-8859-2, ISO-8859-15, etc. - - The returned object is in new malloc'ed storage, in many pieces, and - cannot be destroyed. ------------------------------------------------------------------------------*/ - /* For our return object to deep copy the glyphs and fonts from - the struct font2be destroyable, we need to supply a destroy - function, and it needs to return glyph and raster memory, and - struct font needs to manage glyph memory separately from mapping - code points to glyphs. - */ - struct font * fontP; - struct font2 * font2P; - unsigned int codePoint; - - MALLOCVAR(fontP); - if (fontP == NULL) - pm_error("no memory for font"); - - font2P = pbm_loadbdffont2(filename, PM_FONT_MAXGLYPH); - - fontP->maxwidth = font2P->maxwidth; - fontP->maxheight = font2P->maxheight; - - fontP->x = font2P->x; - fontP->y = font2P->y; - - for (codePoint = 0; codePoint < PM_FONT_MAXGLYPH + 1; ++codePoint) - fontP->glyph[codePoint] = font2P->glyph[codePoint]; - - fontP->oldfont = NULL; - - fontP->fcols = 0; - fontP->frows = 0; - - /* Note that *fontP2 is unfreeable. See pbm_loadbdffont2. And even if it - were, we hooked *fontP into it above, so that would have to turn into a - deep copy before we could free *fontP2. - */ - - return fontP; -} - - - -struct font2 * -pbm_expandbdffont(const struct font * const fontP) { -/*---------------------------------------------------------------------------- - Convert a traditional font structure into an expanded font2 structure. - - This function depends upon the fact that *fontP, like any struct font, - cannot be destroyed. The returned object refers to memory that belongs - to *fontP. - - The returned object is in new malloc'ed storage, in many pieces, and - cannot be destroyed. ------------------------------------------------------------------------------*/ - /* If we ever make struct font destroyable, this function needs to - copy the glyphs and rasters, and struct font and struct font2 need - to manage glyph memory separately from mapping code points to the - glyphs. - */ - PM_WCHAR const maxglyph = PM_FONT_MAXGLYPH; - - struct font2 * font2P; - unsigned int codePoint; - - MALLOCVAR(font2P); - if (font2P == NULL) - pm_error("no memory for font"); - - MALLOCARRAY(font2P->glyph, maxglyph + 1); - if (font2P->glyph == NULL) - pm_error("no memory for font glyphs"); - - font2P->maxwidth = fontP->maxwidth; - font2P->maxheight = fontP->maxheight; - - font2P->x = fontP->x; - font2P->y = fontP->y; - - font2P->maxglyph = maxglyph; - - for (codePoint = 0; codePoint < maxglyph + 1; ++codePoint) - font2P->glyph[codePoint] = fontP->glyph[codePoint]; - - font2P->oldfont = fontP->oldfont; - - font2P->fcols = fontP->fcols; - font2P->frows = fontP->frows; - - return font2P; -} - - |