From 780486818286799c8cce5f4e3ad3a312773e6f16 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Thu, 28 May 2020 21:04:14 +0000 Subject: From a BDF font file, load only the characters that are needed instead of the full font git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@3811 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- generator/pbmtext.c | 373 ++++++++++++++++++++++++++----------- lib/libpbmfont0.c | 83 ++++++--- lib/libpbmfont1.c | 2 +- lib/libpbmfont2.c | 515 ++++++++++++++++++++++++++++++++++++++++------------ lib/pbmfont.h | 93 ++++++++-- lib/pbmfontdata2.c | 2 +- 6 files changed, 800 insertions(+), 268 deletions(-) diff --git a/generator/pbmtext.c b/generator/pbmtext.c index a8d45837..7c7d2548 100644 --- a/generator/pbmtext.c +++ b/generator/pbmtext.c @@ -30,6 +30,7 @@ #include "pbm.h" #include "pbmfont.h" + /* Max length of input text. Valid for text which is part of the command line and also for text fed from standard input. Note that newline is counted as a character. @@ -55,6 +56,7 @@ struct CmdlineInfo { unsigned int nomargins; /* -nomargins option specified */ unsigned int dryrun; /* -dry-run option specified */ unsigned int textdump; /* -text-dump option specified */ + unsigned int entirefont; /* -load-entire-font option specified */ unsigned int verbose; /* -verbose option specified */ /* undocumented option */ unsigned int dumpsheet; /* font data sheet in PBM format for -font */ @@ -133,6 +135,7 @@ parseCommandLine(int argc, const char ** argv, OPTENT3(0, "dry-run", OPT_FLAG, NULL, &cmdlineP->dryrun, 0); OPTENT3(0, "text-dump", OPT_FLAG, NULL, &cmdlineP->textdump, 0); OPTENT3(0, "dump-sheet", OPT_FLAG, NULL, &cmdlineP->dumpsheet, 0); + OPTENT3(0, "load-entire-font", OPT_FLAG, NULL, &cmdlineP->entirefont, 0); /* Set the defaults */ cmdlineP->font = NULL; @@ -166,6 +169,8 @@ parseCommandLine(int argc, const char ** argv, if (cmdlineP->font != NULL && cmdlineP->builtin != NULL) pm_error("You cannot specify both -font and -builtin"); + else if (cmdlineP->font == NULL && cmdlineP->entirefont) + pm_error("You cannot specify -load-entire-font without -font"); if (cmdlineP->textdump) { if (cmdlineP->dryrun) @@ -206,12 +211,10 @@ reportFont(const struct font2 * const fontP) { - - - static struct font2 * -font2FromFile(const char * const fileName, - PM_WCHAR const maxmaxglyph) { +font2FromFile(const char * const fileName, + PM_WCHAR const maxmaxglyph, + const struct pm_selector * const selectorP) { struct font2 * font2P; @@ -224,7 +227,7 @@ font2FromFile(const char * const fileName, /* This is the normal program flow */ pm_setjmpbuf(&jmpbuf); - font2P = pbm_loadfont2(fileName, maxmaxglyph); + font2P = pbm_loadfont2select(fileName, maxmaxglyph, selectorP); pm_setjmpbuf(NULL); } else { @@ -241,17 +244,163 @@ font2FromFile(const char * const fileName, +static bool +codepointIsValid(struct font2 * const fontP, + PM_WCHAR const codepoint) { +/*---------------------------------------------------------------------------- + 'codepoint' is a valid entry in the font indicated by 'fontP'. +-----------------------------------------------------------------------------*/ + bool retval; + + assert(pm_selector_is_marked(fontP->selectorP, codepoint)); + + if (codepoint > fontP->maxglyph || fontP->glyph[codepoint] == NULL) + retval = false; + else retval = true; + + return (retval); + +} + + + +static const char * +charDescription(PM_WCHAR const codepoint) { +/*---------------------------------------------------------------------------- + Descriptive string for codepoint 'codepoint'. + + Certain codepoints appear frequently in text files and cause problems when + missing in the font set, so we give those descriptions. For other + codepoint, we just return a null string. +-----------------------------------------------------------------------------*/ + + const char * name; + + switch (codepoint) { + case '\r' : name="carriage return"; break; + case '\n' : name="line feed"; break; /* for future use */ + case '\t' : name="tab"; break; /* for future use */ + case ' ' : name="space"; break; + case 0xFEFF: name="byte order mark"; break; + default : name=""; break; + } + + return name; +} + + + +enum FixMode {SILENT, /* convert silently */ + WARN, /* output message to stderr */ + QUIT /* abort */ }; + + + static void -computeFont(struct CmdlineInfo const cmdline, - struct font2 ** const fontPP) { +reportAbsentGlyphs(bool const wchar, + struct font2 * const fontP, + const struct pm_selector * const textSelectorP, + unsigned int * const missingCharCtP) { +/*---------------------------------------------------------------------------- + Compare the glyph entries in *fontP with the requests in *textSelectorP. + + Note that we may need the space character as a substitute for missing + glyphs while the input text has no spaces. In rare cases the font may not + have a space character. + + Currently, this program reads the font file only once. A future version + may opt to read it a second time to load the substitute glyph. +-----------------------------------------------------------------------------*/ + PM_WCHAR codepoint; + unsigned int missingCharCt; + + for (codepoint = textSelectorP->min, missingCharCt = 0; + codepoint <= textSelectorP->max; ++codepoint) { + + if (pm_selector_is_marked(textSelectorP, codepoint) && + !codepointIsValid(fontP, codepoint)) { + ++missingCharCt; + if (missingCharCt == 1) { /* initial */ + pm_message ("%u characters found in text", + textSelectorP->count);; + pm_message ("failed to load glyph data for:"); + } + + pm_message(wchar ? "+%05X %s" : "%02X %s", + (unsigned int) codepoint, + charDescription(codepoint)); + } + } + if (missingCharCt > 0) + pm_message("total %u chararcters absent in font", missingCharCt); + + *missingCharCtP = missingCharCt; +} + + + +static void +validateFont(bool const wchar, + struct font2 * const fontP, + const struct pm_selector * const textSelectorP, + enum FixMode const fixmode, + bool * const hasAllCharsP) { +/*---------------------------------------------------------------------------- + If any glyphs required by the text indicated by *textSelectorP are missing + from font *fontP, issue a warning message or abort the program according to + 'fixmode'. + + Abort the program if one or more characters are missing and the space + character is one of them. + + Return (if we return) as *hasAllCharsP whether the font has all the glyphs. +-----------------------------------------------------------------------------*/ + unsigned int missingCharCt; + + assert (textSelectorP != NULL); + assert (textSelectorP->count >= 0); + + reportAbsentGlyphs(wchar, fontP, textSelectorP, &missingCharCt); + + if (missingCharCt > 0) { + + if (fixmode == QUIT) + pm_error("aborting"); + else if (!codepointIsValid(fontP, L' ')) + pm_error ("replacement character (space) absent; aborting"); + else + pm_message("undefined code points will be converted to space"); + } + + *hasAllCharsP = (missingCharCt == 0); +} - struct font2 * font2P; - if (cmdline.font) - font2P = font2FromFile(cmdline.font, - cmdline.wchar ? PM_FONT2_MAXGLYPH : - PM_FONT_MAXGLYPH); - else if (cmdline.builtin) + +static void +computeFont(struct CmdlineInfo const cmdline, + struct font2 ** const fontPP, + const struct pm_selector * const textSelectorP, + enum FixMode const fixmode, + bool * const fontHasAllCharsP) { + + struct font2 * font2P; + struct pm_selector * fontSelectorP; + + if (cmdline.font) { + if(cmdline.entirefont) + fontSelectorP = NULL; + else if(!pm_selector_is_marked(textSelectorP, L' ')) { + pm_selector_copy(MAX(textSelectorP->max, L' '), + textSelectorP, &fontSelectorP); + pm_selector_mark(fontSelectorP, L' '); + } else + fontSelectorP = (struct pm_selector *) textSelectorP; + + font2P = font2FromFile(cmdline.font, cmdline.wchar ? + PM_FONT2_MAXGLYPH : PM_FONT_MAXGLYPH, + fontSelectorP); + } else if (cmdline.builtin) font2P = pbm_defaultfont2(cmdline.builtin); else font2P = pbm_defaultfont2(cmdline.wchar ? "bdf" : "bdf"); @@ -259,6 +408,9 @@ computeFont(struct CmdlineInfo const cmdline, if (cmdline.verbose) reportFont(font2P); + validateFont(cmdline.wchar, font2P, textSelectorP, fixmode, + fontHasAllCharsP); + *fontPP = font2P; } @@ -266,9 +418,6 @@ computeFont(struct CmdlineInfo const cmdline, struct Text { PM_WCHAR ** textArray; /* malloc'ed */ - /* This is strictly characters that are in user's font - no control - characters, no undefined code points. - */ unsigned int allocatedLineCount; unsigned int lineCount; }; @@ -309,28 +458,19 @@ freeTextArray(struct Text const text) { -enum FixMode {SILENT, /* convert silently */ - WARN, /* output message to stderr */ - QUIT /* abort */ }; - static void -fixControlChars(const PM_WCHAR * const input, - struct font2 * const fontP, - const PM_WCHAR ** const outputP, - enum FixMode const fixMode) { +setupSelector(const PM_WCHAR * const input, + const PM_WCHAR ** const outputP, + struct pm_selector * const selectorP) { /*---------------------------------------------------------------------------- - Return a translation of input[] that can be rendered as glyphs in - the font 'fontP'. Return it as newly malloced *outputP. + Read through input[] and record the codepoints encountered. Return it as + newly malloced *outputP. Expand tabs to spaces. Remove any trailing newline. (But leave intermediate ones as line delimiters). - - Depending on value of fixMode, turn anything that isn't a code point - in the font to a single space (which isn't guaranteed to be in the - font either, of course). -----------------------------------------------------------------------------*/ /* We don't know in advance how big the output will be because of the tab expansions. So we make sure before processing each input @@ -370,33 +510,19 @@ fixControlChars(const PM_WCHAR * const input, unsigned int const nextTabStop = (outCursor + tabSize) / tabSize * tabSize; - if (fontP->glyph[L' '] == NULL) - pm_error("space character not defined in font"); - while (outCursor < nextTabStop) output[outCursor++] = L' '; - } else if (currentChar > fontP->maxglyph || - !fontP->glyph[currentChar]) { - if (currentChar > PM_FONT2_MAXGLYPH) + + pm_selector_mark(selectorP, L' '); + + } else if (currentChar > PM_FONT2_MAXGLYPH) pm_message("code point %X is beyond what this program " "can handle. Max=%X", (unsigned int)currentChar, PM_FONT2_MAXGLYPH); - - /* Turn this unknown char into a single space. */ - if (fontP->glyph[L' '] == NULL) - pm_error("space character not defined in font"); - else if (fixMode == QUIT) - pm_error("code point %X not defined in font", - (unsigned int) currentChar ); - else { - if (fixMode == WARN) - pm_message("converting code point %X to space", - (unsigned int) currentChar ); - output[outCursor++] = ' '; - } - } else + else { output[outCursor++] = input[inCursor]; - + pm_selector_mark(selectorP, currentChar); + } assert(outCursor <= outputSize); } output[outCursor++] = L'\0'; @@ -437,7 +563,8 @@ getEdges(double const currentPosition, double rightEdge; if (glyphP == NULL) - pm_error("Unrenderable char: %04X", (unsigned int) currentChar); + pm_error("encountered unrenderable char: %04X", + (unsigned int) currentChar); else { leftEdge = (int) MIN(currentPosition + glyphP->x, currLeftEdge); rightEdge = MAX(currentPosition + glyphP->x + glyphP->width, @@ -475,8 +602,8 @@ advancePosition(double const currentPosition, pm_error("Negative -space value too large"); else pm_error("Abnormal horizontal advance value %d " - "for code point 0x%lx.", - glyphP->xadd, (unsigned long int) currentChar); + "for code point +%05X", + glyphP->xadd, (unsigned int) currentChar); } else if (currentPosition + advance > INT_MAX) pm_error("Image is too wide"); @@ -535,8 +662,8 @@ getLineDimensions(PM_WCHAR const line[], for (cursor = 0; line[cursor] != L'\0'; ++cursor) { PM_WCHAR const currentChar = line[cursor]; - unsigned long int const glyphIndex = (unsigned long int) currentChar; - struct glyph * const glyphP = fontP->glyph[glyphIndex]; + unsigned int const index = (unsigned int) currentChar; + struct glyph * const glyphP = fontP->glyph[index]; getEdges(currentPosition, currentChar, glyphP, leftEdge, rightEdge, &leftEdge, &rightEdge); @@ -593,9 +720,8 @@ getCharsWithinWidth(PM_WCHAR const line[], currentWidth <= targetWidth && line[cursor] != L'\0'; ++cursor) { PM_WCHAR const currentChar = line[cursor]; - unsigned long int const glyphIndex = - (unsigned long int) currentChar; - struct glyph * const glyphP = fontP->glyph[glyphIndex]; + unsigned int const index = (unsigned int) currentChar; + struct glyph * const glyphP = fontP->glyph[index]; getEdges(currentPosition, currentChar, glyphP, leftEdge, rightEdge, &leftEdge, &rightEdge); @@ -694,9 +820,8 @@ insertCharacters(bit ** const bits, for (cursor = 0; lp.textArray[line][cursor] != '\0'; ++cursor) { PM_WCHAR const currentChar = lp.textArray[line][cursor]; - unsigned long int const glyphIndex = - (unsigned long int)currentChar; - struct glyph * const glyphP = fontP->glyph[glyphIndex]; + unsigned int const index = (unsigned int) currentChar; + struct glyph * const glyphP = fontP->glyph[index]; int const toprow = row + fontP->maxheight + fontP->y - glyphP->height - glyphP->y; /* row number in image of top row in glyph */ @@ -943,10 +1068,9 @@ fgetNarrowWideString(PM_WCHAR * const widestring, static void -getText(PM_WCHAR const cmdlineText[], - struct font2 * const fontP, - struct Text * const inputTextP, - enum FixMode const fixMode) { +getText(PM_WCHAR const cmdlineText[], + struct Text * const inputTextP, + struct pm_selector * const selectorP) { /*---------------------------------------------------------------------------- Get as *inputTextP the text to format, given that the text on the command line (one word per command line argument, separated by spaces), @@ -969,8 +1093,8 @@ getText(PM_WCHAR const cmdlineText[], MALLOCARRAY_NOFAIL(inputText.textArray, 1); inputText.allocatedLineCount = 1; inputText.lineCount = 1; - fixControlChars(cmdlineText, fontP, - (const PM_WCHAR**)&inputText.textArray[0], fixMode); + setupSelector(cmdlineText, (const PM_WCHAR**) &inputText.textArray[0], + selectorP); free((void *) cmdlineText); } else { /* Read text from stdin. */ @@ -1021,9 +1145,9 @@ getText(PM_WCHAR const cmdlineText[], if (textArray == NULL) pm_error("out of memory"); } - fixControlChars(buf, fontP, - (const PM_WCHAR **)&textArray[lineCount], - fixMode); + setupSelector(buf, + (const PM_WCHAR **) &textArray[lineCount], + selectorP); if (textArray[lineCount] == NULL) pm_error("out of memory"); ++lineCount; @@ -1063,6 +1187,33 @@ computeMargins(struct CmdlineInfo const cmdline, +static void +refineText(struct Text const inputText, + struct font2 * const fontP) { +/*---------------------------------------------------------------------------- + Replace missing characters with space + + A future version of this program may provide various alternatives + here including simply deleting the offending character, based on a + command-line option +-----------------------------------------------------------------------------*/ + PM_WCHAR ** const textArray = inputText.textArray; + + unsigned int lineNum; + + for (lineNum = 0; lineNum < inputText.lineCount; ++lineNum) { + PM_WCHAR * const line = textArray[lineNum]; + + unsigned int cursor; + + for (cursor = 0; line[cursor] != L'\0'; ++cursor) + if ( !codepointIsValid(fontP, line[cursor]) ) + line[cursor] = L' '; + } +} + + + static void formatText(struct CmdlineInfo const cmdline, struct Text const inputText, @@ -1191,7 +1342,7 @@ renderText(unsigned int const cols, space, cols, rows, lspace, fixedAdvance); /* Free all font data */ - pbm_destroybdffont2(fontP); + pbm_destroybdffont2(fontP); { unsigned int row; @@ -1224,36 +1375,32 @@ L"M \",/^_[`jpqy| M" }; static void -validateText(const PM_WCHAR ** const textArray, - struct font2 * const fontP) { -/*---------------------------------------------------------------------------- - Abort the program if there are characters in 'textArray' which cannot be - rendered in font *fontP. ------------------------------------------------------------------------------*/ - const PM_WCHAR * output; - unsigned int textRow; +renderSheet(struct CmdlineInfo const cmdline, + FILE * const ofP) { - for (textRow = 0; textRow < 12; ++textRow) - fixControlChars(textArray[textRow], fontP, &output, QUIT); - - free((PM_WCHAR *)output); -} + struct Text const sheetText = + { (PM_WCHAR ** const) sheetTextArray, 12, 12}; + static unsigned char const sheetRequestArray[16] = { + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}; + struct pm_selector * selectorP; + pm_selector_create_fixed(sheetRequestArray, 32, 126,95, &selectorP); -static void -renderSheet(struct font2 * const fontP, - FILE * const ofP) { + struct font2 * fontP; + bool fontIsComplete; - int const cols = fontP->maxwidth * 16; - int const rows = fontP->maxheight * 12; - struct Text const sheetText = - { (PM_WCHAR ** const) sheetTextArray, 12, 12}; + computeFont(cmdline, &fontP, selectorP, QUIT, &fontIsComplete); - validateText(sheetTextArray, fontP); + { + unsigned int const cols = fontP->maxwidth * 16; + unsigned int const rows = fontP->maxheight * 12; - renderText(cols, rows, fontP, 0, 0, sheetText, MAX(-(fontP->x),0), - 0.0, 0, TRUE, ofP); + renderText(cols, rows, fontP, 0, 0, sheetText, MAX(-(fontP->x),0), + 0.0, 0, TRUE, ofP); + } + pm_selector_destroy(selectorP); } @@ -1304,8 +1451,8 @@ textDumpOutput(struct Text const lp, static void pbmtext(struct CmdlineInfo const cmdline, - struct font2 * const fontP, - FILE * const ofP) { + FILE * const ofP, + bool const wchar) { unsigned int rows, cols; /* Dimensions in pixels of the output image */ @@ -1315,19 +1462,30 @@ pbmtext(struct CmdlineInfo const cmdline, unsigned int hmargin0; struct Text inputText; struct Text formattedText; + struct font2 * fontP; + struct pm_selector * selectorP; unsigned int maxleftb, maxleftb0; + bool fontIsComplete; + + pm_selector_create(wchar ? PM_FONT2_MAXGLYPH : PM_FONT_MAXGLYPH, + &selectorP); - getText(cmdline.text, fontP, &inputText, - cmdline.verbose ? WARN : SILENT); + getText(cmdline.text, &inputText, selectorP); + + if (pm_selector_marked_ct(selectorP) == 0) + pm_error("No input text. Aborting."); + + computeFont(cmdline, &fontP, selectorP, cmdline.verbose ? WARN : SILENT, + &fontIsComplete); computeMargins(cmdline, inputText, fontP, &vmargin, &hmargin0); + if (!fontIsComplete) + refineText(inputText, fontP); + formatText(cmdline, inputText, fontP, hmargin0, &formattedText, &maxleftb0); - if (formattedText.lineCount == 0) - pm_error("No input text"); - computeImageHeight(formattedText, fontP, cmdline.lspace, vmargin, &rows); computeImageWidth(formattedText, fontP, cmdline.space, @@ -1361,6 +1519,8 @@ pbmtext(struct CmdlineInfo const cmdline, maxleftb, cmdline.space, cmdline.lspace, FALSE, ofP); freeTextArray(formattedText); + + pm_selector_destroy(selectorP); } @@ -1369,7 +1529,6 @@ int main(int argc, const char *argv[]) { struct CmdlineInfo cmdline; - struct font2 * fontP; pm_proginit(&argc, argv); @@ -1389,12 +1548,10 @@ main(int argc, const char *argv[]) { if (cmdline.verbose) pm_message("LC_CTYPE is set to '%s'", setlocale(LC_CTYPE, NULL) ); - computeFont(cmdline, &fontP); - if (cmdline.dumpsheet) - renderSheet(fontP, stdout); + renderSheet(cmdline, stdout); else - pbmtext(cmdline, fontP, stdout); + pbmtext(cmdline, stdout, cmdline.wchar); pm_close(stdout); diff --git a/lib/libpbmfont0.c b/lib/libpbmfont0.c index 503c7ee7..a8027a38 100644 --- a/lib/libpbmfont0.c +++ b/lib/libpbmfont0.c @@ -27,7 +27,6 @@ #include "pbmfont.h" #include "pbmfontdata.h" - struct font * pbm_defaultfont(const char * const name) { /*---------------------------------------------------------------------------- @@ -77,11 +76,12 @@ pbm_defaultfont2(const char * const requestedFontName) { static void -selectFontType(const char * const filename, - PM_WCHAR const maxmaxglyph, - unsigned int const isWide, - struct font ** const fontPP, - struct font2 ** const font2PP) { +selectFontType(const char * const filename, + PM_WCHAR const maxmaxglyph, + unsigned int const isWide, + struct font ** const fontPP, + struct font2 ** const font2PP, + const struct pm_selector * const selectorP) { FILE * fileP; struct font * fontP = NULL; /* initial value */ @@ -106,7 +106,7 @@ selectFontType(const char * const filename, } else if (!strncmp(line, "STARTFONT", 9)) { if (isWide == TRUE) - font2P = pbm_loadbdffont2(filename, maxmaxglyph); + font2P = pbm_loadbdffont2select(filename, maxmaxglyph, selectorP); else fontP = pbm_loadbdffont(filename); if (fontP == NULL && font2P == NULL) @@ -128,25 +128,49 @@ selectFontType(const char * const filename, struct font * -pbm_loadfont(const char * const filename) { - +pbm_loadfont(const char * const filename) { +/*---------------------------------------------------------------------------- + Load font file named 'filename'. + Font file may be either a PBM sheet or BDF. + Supports 8 bit codepoints. +-----------------------------------------------------------------------------*/ struct font * fontP; struct font2 * font2P; - selectFontType(filename, PM_FONT_MAXGLYPH, FALSE, &fontP, &font2P); + selectFontType(filename, PM_FONT_MAXGLYPH, FALSE, &fontP, &font2P, NULL); return fontP; } struct font2 * -pbm_loadfont2(const char * const filename, - PM_WCHAR const maxmaxglyph) { +pbm_loadfont2(const char * const filename, + PM_WCHAR const maxmaxglyph) { +/*---------------------------------------------------------------------------- + Load font file named 'filename'. + Font file may be either a PBM sheet or BDF. + Supports codepoints above 256. +-----------------------------------------------------------------------------*/ + struct font * fontP; + struct font2 * font2P; + selectFontType(filename, maxmaxglyph, TRUE, &fontP, &font2P, NULL); + return font2P; +} + + +struct font2 * +pbm_loadfont2select(const char * const filename, + PM_WCHAR const maxmaxglyph, + const struct pm_selector * const selectorP) { +/*---------------------------------------------------------------------------- + Same as pbm_loadfont2(), but load only glyphs indicated by *selectorP +-----------------------------------------------------------------------------*/ struct font * fontP; struct font2 * font2P; - selectFontType(filename, maxmaxglyph, TRUE, &fontP, &font2P); + selectFontType(filename, maxmaxglyph, TRUE, &fontP, &font2P, selectorP); + return font2P; } @@ -173,7 +197,7 @@ pbm_createbdffont2_base(struct font2 ** const font2PP, /* Caller should overwrite following fields as necessary */ font2P->oldfont = NULL; font2P->fcols = font2P->frows = 0; - font2P->selector = NULL; + font2P->selectorP = NULL; font2P->default_char = 0; font2P->default_char_defined = FALSE; font2P->total_chars = font2P->chars = 0; @@ -187,23 +211,32 @@ pbm_createbdffont2_base(struct font2 ** const font2PP, static void -destroyGlyphData(struct glyph ** const glyph, - PM_WCHAR const maxglyph) { +destroyGlyphData(struct glyph ** const glyph, + PM_WCHAR const maxglyph, + const struct pm_selector * const selectorP) { /*---------------------------------------------------------------------------- Free glyph objects and bitmap objects. This does not work when an object is "shared" through multiple pointers referencing an identical address and thus pointing to a common glyph or bitmap object. + + If 'selectorP' is NULL, free all glyph and bitmap objects in the range + 0 ... maxglyph. If not, free only the objects which the selector + indicates as present. -----------------------------------------------------------------------------*/ + PM_WCHAR const min = (selectorP != NULL) ? selectorP->min : 0; + PM_WCHAR const max = + (selectorP != NULL) ? MIN(selectorP->max, maxglyph) : maxglyph; + PM_WCHAR i; - for(i = 0; i <= maxglyph; ++i) { - if (glyph[i]!=NULL) { + for (i = min; i <= max; ++i) { + if (pm_selector_is_marked(selectorP, i) && glyph[i]) { free((void *) (glyph[i]->bmap)); free(glyph[i]); - } + } } } @@ -214,11 +247,10 @@ pbm_destroybdffont2_base(struct font2 * const font2P) { Free font2 structure, but not the glyph data ---------------------------------------------------------------------------- */ - free(font2P->selector); - pm_strfree(font2P->name); pm_strfree(font2P->charset_string); free(font2P->glyph); + pm_selector_destroy(font2P->selectorP); if (font2P->oldfont !=NULL) pbm_freearray(font2P->oldfont, font2P->frows); @@ -239,8 +271,8 @@ pbm_destroybdffont2(struct font2 * const font2P) { ---------------------------------------------------------------------------- */ if (font2P->load_fn != FIXED_DATA) { - destroyGlyphData(font2P->glyph, font2P->maxglyph); - pbm_destroybdffont2_base(font2P); + destroyGlyphData(font2P->glyph, font2P->maxglyph, font2P->selectorP); + pbm_destroybdffont2_base(font2P); } } @@ -254,7 +286,7 @@ pbm_destroybdffont(struct font * const fontP) { For freeing a structure created by pbm_loadbdffont() or pbm_loadpbmfont(). ---------------------------------------------------------------------------- */ - destroyGlyphData(fontP->glyph, PM_FONT_MAXGLYPH); + destroyGlyphData(fontP->glyph, PM_FONT_MAXGLYPH, NULL); if (fontP->oldfont !=NULL) pbm_freearray(fontP->oldfont, fontP->frows); @@ -326,8 +358,7 @@ pbm_expandbdffont(const struct font * const fontP) { font2P->bit_format = PBM_FORMAT; font2P->total_chars = font2P->chars = nCharacters; font2P->load_fn = CONVERTED_TYPE1_FONT; - /* Caller should be overwrite the above to a more descriptive - value */ + /* Caller should overwrite the above to a more descriptive value */ return font2P; } diff --git a/lib/libpbmfont1.c b/lib/libpbmfont1.c index 4189f150..fe014150 100644 --- a/lib/libpbmfont1.c +++ b/lib/libpbmfont1.c @@ -47,7 +47,7 @@ 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 + 32, 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. diff --git a/lib/libpbmfont2.c b/lib/libpbmfont2.c index b4cf4c2a..1560b407 100644 --- a/lib/libpbmfont2.c +++ b/lib/libpbmfont2.c @@ -32,6 +32,208 @@ #include "pbmfont.h" #include "pbm.h" +/*---------------------------------------------------------------------------- + Font selector routines + + The selector is a device consisting of a bitmap, min value, max value and + count. It is used here to specify necessary fonts and record what entries + are valid in the glyph array. + + This device may be used for other purposes. In that case the code should + be put into an independent source file in the lib/util subdirectory. +-----------------------------------------------------------------------------*/ + +static void +allocRecord(struct pm_selector * const selectorP, + unsigned int const max) { + + unsigned int const size = (max + 8) / 8; + + MALLOCARRAY(selectorP->localRecord, size); + + if (!selectorP->localRecord) + pm_error("Failed to allocate %u bytes of memory for font selector " + "bitmap", size); + + selectorP->record = selectorP->localRecord; +} + + + +void +pm_selector_create(unsigned int const max, + struct pm_selector ** const selectorPP) { + + struct pm_selector * selectorP; + + MALLOCVAR_NOFAIL(selectorP); + + allocRecord(selectorP, max); + + { + unsigned int byteIndex; + for (byteIndex = 0; byteIndex <= max/8; ++byteIndex) + selectorP->localRecord[byteIndex]= 0x00; + } + + selectorP->maxmax = selectorP->min = max; + selectorP->max = 0; + selectorP->count = 0; + + *selectorPP = selectorP; +} + + + +void +pm_selector_create_fixed(const unsigned char * const record, + unsigned int const min, + unsigned int const max, + unsigned int const count, + struct pm_selector ** const selectorPP) { + + struct pm_selector * selectorP; + + MALLOCVAR_NOFAIL(selectorP); + + selectorP->localRecord = NULL; + selectorP->record = record; + selectorP->min = min; + selectorP->max = max; + selectorP->maxmax = max; + selectorP->count = count; + + *selectorPP = selectorP; +} + + + +void +pm_selector_destroy(struct pm_selector * const selectorP) { + + if (selectorP->localRecord) + free(selectorP->localRecord); + + free(selectorP); +} + + + +void +pm_selector_copy(unsigned int const max, + const struct pm_selector * const srcSelectorP, + struct pm_selector ** const destSelectorPP) { + + /* Create a new selector and copy into it the content of another */ + + struct pm_selector * destSelectorP; + + if (max < srcSelectorP->max) + pm_error("internal error: attempt to copy a selector as " + "another with a smaller max value %u -> %u", + srcSelectorP->max, max); + + MALLOCVAR_NOFAIL(destSelectorP); + + destSelectorP->maxmax = max; + destSelectorP->max = srcSelectorP->max; + destSelectorP->min = srcSelectorP->min; + destSelectorP->count = srcSelectorP->count; + + allocRecord(destSelectorP, max); + + { + unsigned int const minByteIndex = srcSelectorP->min / 8; + unsigned int const maxByteIndex = srcSelectorP->max / 8; + unsigned int const maxmaxByteIndex = max / 8; + + unsigned int byteIndex; + + for (byteIndex = 0 ; byteIndex < minByteIndex; ++byteIndex) + destSelectorP->localRecord[byteIndex] = 0x00; + for (byteIndex = maxByteIndex + 1 ; byteIndex <= maxmaxByteIndex; + ++byteIndex) + destSelectorP->localRecord[byteIndex] = 0x00; + for (byteIndex = minByteIndex; byteIndex <= maxByteIndex; ++byteIndex) + destSelectorP->localRecord[byteIndex] = + srcSelectorP->record[byteIndex]; + } + + *destSelectorPP = destSelectorP; +} + + + +void +pm_selector_mark(struct pm_selector * const selectorP, + unsigned int const index) { +/*---------------------------------------------------------------------------- + Mark index 'index'. +-----------------------------------------------------------------------------*/ + unsigned int byteIndex = index / 8; + unsigned int bitIndex = index % 8; + unsigned char mask = (0x01 <<7) >> bitIndex; + + /* set bit on to indicate presence of this index */ + + if (!selectorP->localRecord) + pm_error("INTERNAL ERROR: attempt to mark in a fixed pm_selector"); + + if ((selectorP->localRecord[byteIndex] & mask) == 0x00) { + /* if bit is not already set */ + + selectorP->localRecord[byteIndex] |= mask; + ++selectorP->count; /* increment count */ + + /* reset min and max */ + if (selectorP->min > index) + selectorP->min = index; + if (selectorP->max < index) + selectorP->max = index; + } +} + +/* There is no function for erasing a marked bit */ + + +int /* boolean */ +pm_selector_is_marked(const struct pm_selector * const selectorP, + unsigned int const index) { +/*---------------------------------------------------------------------------- + Index 'index' is marked. +-----------------------------------------------------------------------------*/ + bool retval; + + if (selectorP) { + unsigned int const byteIndex = index / 8; + unsigned int const bitIndex = index % 8; + unsigned char const mask = (0x01 <<7) >> bitIndex; + + if ( index < selectorP->min || index > selectorP->max) + retval = false; + else if ((selectorP->record[byteIndex] & mask) != 0x00) + retval = true; + else + retval = false; + } else { + /* All entries are set to "exist" */ + retval = true; + } + return retval ? 1 : 0; +} + + + +unsigned int +pm_selector_marked_ct(const struct pm_selector * const selectorP) { +/*---------------------------------------------------------------------------- + Number of indices that are marked. +-----------------------------------------------------------------------------*/ + return selectorP->count; +} + + + /*---------------------------------------------------------------------------- Routines for loading a BDF font file -----------------------------------------------------------------------------*/ @@ -354,21 +556,23 @@ readExpectedStatement(Readline * const readlineP, 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 currently in. + In the BDF font file being read by readline object *readlineP, skip + through to the end of the data for the character we are presently in. + + At entry the stream must be positioned at the end of the ENCODING line. -----------------------------------------------------------------------------*/ - bool endChar; - endChar = FALSE; + char * rc; + do { + rc = fgets(readlineP->line, MAXBDFLINE+1, readlineP->ifP); + readlineP->line[7] = '\0'; + + } while (rc != NULL && !streq(readlineP->line, "ENDCHAR")); + + if (rc == NULL) + pm_error("End of file in the middle of a character (before " + "ENDCHAR) in BDF font file."); - 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"); - } } @@ -421,7 +625,7 @@ interpEncoding(const char ** const arg, 'maxmaxglyph' is the maximum codepoint in the font. -----------------------------------------------------------------------------*/ - bool gotCodepoint; + bool gotCodepoint = false; /* initial value */ bool badCodepoint; unsigned int codepoint; @@ -429,12 +633,15 @@ interpEncoding(const char ** const arg, codepoint = wordToInt(arg[1]); gotCodepoint = true; } else { - if (wordToInt(arg[1]) == -1 && arg[2] != NULL) { - codepoint = wordToInt(arg[2]); - gotCodepoint = true; - } else - gotCodepoint = false; + if (wordToInt(arg[1]) == -1 && arg[2] != NULL) { + int const codepoint0 = wordToInt(arg[2]); + if (codepoint0 >= 0) { + codepoint = codepoint0; + gotCodepoint = true; + } + } } + if (gotCodepoint) { if (codepoint > maxmaxglyph) badCodepoint = true; @@ -538,112 +745,147 @@ validateGlyphLimits(const struct font2 * const font2P, static void -processChars(Readline * const readlineP, - struct font2 * const font2P) { -/*---------------------------------------------------------------------------- - 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 *font2P. ------------------------------------------------------------------------------*/ - unsigned int const nCharacters = wordToInt(readlineP->arg[1]); - - unsigned int nCharsDone; - unsigned int nCharsValid; - - for (nCharsDone = 0, nCharsValid = 0; - nCharsDone < nCharacters; ) { - +readStartchar(Readline * const readlineP, + const char ** charNameP) { + + const char * charName; 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")) { + while (streq(readlineP->arg[0], "COMMENT")) { + readline_read(readlineP, &eof); + if (eof) + pm_error("End of file after CHARS reading BDF font file"); /* ignore */ - } else if (!streq(readlineP->arg[0], "STARTCHAR")) + } + + if (!streq(readlineP->arg[0], "STARTCHAR")) pm_error("%s detected where \'STARTCHAR\' expected " "in BDF font file", readlineP->arg[0] ); - else { - const char * charName; - - struct glyph * glyphP; - unsigned int codepoint; - bool badCodepoint; - - if (readlineP->wordCt < 2) - pm_error("Wrong number of arguments in STARTCHAR line " - "in BDF font file"); + else if (readlineP->wordCt < 2) + pm_error("Wrong number of arguments in STARTCHAR line " + "in BDF font file"); /* Character name may contain spaces: there may be more than three words in the line. */ + else charName = pm_strdup(readlineP->arg[1]); - assert(streq(readlineP->arg[0], "STARTCHAR")); + *charNameP = charName; +} - MALLOCVAR(glyphP); - if (glyphP == NULL) - pm_error("no memory for font glyph for '%s' character", - charName); - readEncoding(readlineP, &codepoint, &badCodepoint, - font2P->maxmaxglyph); +static void +readGlyph(Readline * const readlineP, + const char * const charName, + const struct font2 * const font2P, + struct glyph ** const glyphPP) { - if (badCodepoint) - skipCharacter(readlineP); - else { - if (codepoint < font2P->maxglyph) { - if (font2P->glyph[codepoint] != NULL) - pm_error("Multiple definition of code point %u " - "in BDF font file", (unsigned int) codepoint); - else - pm_message("Reverse order detected in BDF file. " - "Code point %u defined after %u", - (unsigned int) codepoint, - (unsigned int) font2P->maxglyph); - } else { - /* Initialize all characters in the gap to nonexistent */ - unsigned int i; - unsigned int const oldMaxglyph = font2P->maxglyph; - unsigned int const newMaxglyph = codepoint; + struct glyph * glyphP; + MALLOCVAR(glyphP); + if (glyphP == NULL) + pm_error("no memory for font glyph for '%s' character", + charName); - for (i = oldMaxglyph + 1; i < newMaxglyph; ++i) - font2P->glyph[i] = NULL; + readExpectedStatement(readlineP, "SWIDTH", 3); - font2P->maxglyph = newMaxglyph; - } + readExpectedStatement(readlineP, "DWIDTH", 3); + glyphP->xadd = wordToInt(readlineP->arg[1]); - readExpectedStatement(readlineP, "SWIDTH", 3); + readExpectedStatement(readlineP, "BBX", 5); + glyphP->width = wordToInt(readlineP->arg[1]); + glyphP->height = wordToInt(readlineP->arg[2]); + glyphP->x = wordToInt(readlineP->arg[3]); + glyphP->y = wordToInt(readlineP->arg[4]); - readExpectedStatement(readlineP, "DWIDTH", 3); - glyphP->xadd = wordToInt(readlineP->arg[1]); + validateGlyphLimits(font2P, glyphP, charName); - readExpectedStatement(readlineP, "BBX", 5); - glyphP->width = wordToInt(readlineP->arg[1]); - glyphP->height = wordToInt(readlineP->arg[2]); - glyphP->x = wordToInt(readlineP->arg[3]); - glyphP->y = wordToInt(readlineP->arg[4]); + createBmap(glyphP->width, glyphP->height, readlineP, charName, + &glyphP->bmap); - validateGlyphLimits(font2P, glyphP, charName); + *glyphPP = glyphP; +} + + + +static void +processChars(Readline * const readlineP, + struct font2 * const font2P) { +/*---------------------------------------------------------------------------- + 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 *font2P. +-----------------------------------------------------------------------------*/ + unsigned int const nCharacters = wordToInt(readlineP->arg[1]); + unsigned int const nCharsWanted = (font2P->selectorP != NULL) ? + font2P->selectorP->count : nCharacters; + + unsigned int nCharsEncountered; + unsigned int nCharsLoaded; + + for (nCharsEncountered = 0, nCharsLoaded = 0; + nCharsEncountered < nCharacters && nCharsLoaded < nCharsWanted; + ++nCharsEncountered ) { + + const char * charName; + unsigned int codepoint; + bool badCodepoint; + + readStartchar(readlineP, &charName); + + readEncoding(readlineP, &codepoint, &badCodepoint, + font2P->maxmaxglyph); + + if ( badCodepoint ) { + skipCharacter(readlineP); + pm_strfree (charName); + } + else if (!pm_selector_is_marked(font2P->selectorP, codepoint) ) { + skipCharacter(readlineP); + pm_strfree (charName); + font2P->maxglyph = codepoint; + } + else { + if (codepoint < font2P->maxglyph) { + if (font2P->glyph[codepoint] != NULL ) + pm_error("Multiple definition of code point %u " + "in BDF font file", (unsigned int) codepoint); + else + pm_message("Reverse order detected in BDF file. " + "Code point %u defined after %u", + (unsigned int) codepoint, + (unsigned int) font2P->maxglyph); + } - createBmap(glyphP->width, glyphP->height, readlineP, charName, - &glyphP->bmap); + { + struct glyph * glyphP; - readExpectedStatement(readlineP, "ENDCHAR", 1); + readGlyph(readlineP, charName, font2P, &glyphP); + readExpectedStatement(readlineP, "ENDCHAR", 1); - assert(codepoint <= font2P->maxmaxglyph); - /* Ensured by readEncoding() */ + assert(codepoint <= font2P->maxmaxglyph); + /* Ensured by readEncoding() */ - font2P->glyph[codepoint] = glyphP; - pm_strfree(charName); + font2P->glyph[codepoint] = glyphP; + pm_strfree(charName); - ++nCharsValid; + font2P->maxglyph = codepoint; + ++nCharsLoaded; } - ++nCharsDone; } } - font2P->chars = nCharsValid; + + /* Note that BDF file may have reached end before the largest entry + in selector was checked. */ + /* + if (font2P->selectorP->max > font2P->maxglyph) + font2P->maxglyph = font2P->selectorP->max; + */ + font2P->chars = nCharsLoaded; font2P->total_chars = nCharacters; } @@ -717,12 +959,8 @@ loadCharsetString(const char * const registry, } - - static unsigned int const maxTokenLen = 60; - - static void doCharsetRegistry(Readline * const readlineP, bool * const gotRegistryP, @@ -904,6 +1142,9 @@ processBdfFontLine(Readline * const readlineP, else { validateWordCount(readlineP, 2); /* CHARS n */ processChars(readlineP, font2P); + if (font2P->selectorP != NULL && + font2P->selectorP->count == font2P->chars) + *endOfFontP = true; } } else { /* ignore */ @@ -913,9 +1154,39 @@ processBdfFontLine(Readline * const readlineP, +static void +initializeGlyphArray(struct font2 * const font2P, + unsigned int const maxmaxglyph) { +/*---------------------------------------------------------------------------- + Initialize glyph array based on entries in selector. + Note that only valid codepoints are set to NULL. + Entries for unused glyphs are left untouched. +-----------------------------------------------------------------------------*/ + const struct pm_selector * const selectorP = font2P->selectorP; + unsigned int const min = (selectorP == NULL) ? 0 : selectorP->min; + unsigned int const max = + (selectorP == NULL) ? font2P->maxglyph : selectorP->max; + + unsigned int codepoint; + + for (codepoint = min; codepoint <= max ; ++codepoint) + if (pm_selector_is_marked(selectorP, codepoint) == true) + font2P->glyph[codepoint] = NULL; + + font2P->glyph[L' '] = NULL; + /* Clear the slot for space character. + It may not be defined in the font, but the program may try + to use space as a substitute char + */ + +} + + + struct font2 * -pbm_loadbdffont2(const char * const filename, - PM_WCHAR const maxmaxglyph) { +pbm_loadbdffont2select(const char * const filename, + PM_WCHAR const maxmaxglyph, + const struct pm_selector * const selectorP) { /*---------------------------------------------------------------------------- Read a BDF font file "filename" as a 'font2' structure. A 'font2' structure is more expressive than a 'font' structure, most notably in that @@ -943,8 +1214,14 @@ pbm_loadbdffont2(const char * const filename, font2P->maxglyph = 0; /* Initial value. Increases as new characters are loaded */ - font2P->glyph[0] = NULL; - /* Initial value. Overwrite later if codepoint 0 is defined. */ + + if (font2P->selectorP == NULL) { + PM_WCHAR i; + + for(i = 0; i <= maxmaxglyph; ++i) + font2P->glyph[i] = NULL; + /* Initial value. Overwrite later if codepoint i is defined. */ + } font2P->maxmaxglyph = maxmaxglyph; @@ -955,6 +1232,9 @@ pbm_loadbdffont2(const char * const filename, font2P->chars = font2P->total_chars = 0; font2P->default_char = 0; font2P->default_char_defined = FALSE; + font2P->selectorP = (struct pm_selector * const) selectorP; + + initializeGlyphArray(font2P, maxmaxglyph); readExpectedStatement(&readline, "STARTFONT", 2); @@ -970,9 +1250,13 @@ pbm_loadbdffont2(const char * const filename, } fclose(ifP); - if(font2P->chars == 0) + if(font2P->total_chars == 0) pm_error("No glyphs found in BDF font file " "in codepoint range 0 - %u", (unsigned int) maxmaxglyph); + if(font2P->chars == 0) + pm_error("Not any requested glyphs found in BDF font file " + "in codepoint range 0 - %u", (unsigned int) maxmaxglyph); + REALLOCARRAY(font2P->glyph, font2P->maxglyph + 1); @@ -986,8 +1270,21 @@ pbm_loadbdffont2(const char * const filename, } +struct font2 * +pbm_loadbdffont2(const char * const filename, + PM_WCHAR const maxmaxglyph) { + + return (pbm_loadbdffont2select(filename, maxmaxglyph, NULL)); + + return(0); +} + + + + static struct font * font2ToFont(const struct font2 * const font2P) { + struct font * fontP; unsigned int codePoint; @@ -1001,18 +1298,10 @@ font2ToFont(const struct font2 * const font2P) { fontP->x = font2P->x; fontP->y = font2P->y; - for (codePoint = 0; codePoint <= font2P->maxglyph; ++codePoint) - fontP->glyph[codePoint] = font2P->glyph[codePoint]; - - /* font2P->maxglyph is typically 255 (PM_FONT_MAXGLYPH) or larger. - But in some rare cases it is smaller. - If an ASCII-only font is read, it will be 126 or 127. - - Set remaining codepoints up to PM_FONT_MAXGLYPH, if any, to NULL - */ - - for ( ; codePoint <= PM_FONT_MAXGLYPH; ++codePoint) - fontP->glyph[codePoint] = NULL; + for (codePoint = 0; codePoint <= PM_FONT_MAXGLYPH; ++codePoint) + fontP->glyph[codePoint] = + pm_selector_is_marked(font2P->selectorP, codePoint) ? + font2P->glyph[codePoint] : NULL; /* Give values to legacy fields */ fontP->oldfont = font2P->oldfont; diff --git a/lib/pbmfont.h b/lib/pbmfont.h index c8b3934b..6adbe814 100644 --- a/lib/pbmfont.h +++ b/lib/pbmfont.h @@ -115,12 +115,12 @@ struct glyph { struct font { /* This describes a combination of font and character set. Given - an code point in the range 0..255, this structure describes the + a code point in the range 0..255, this structure describes the glyph for that character. */ unsigned int maxwidth, maxheight; int x; - /* The minimum value of glyph.font. The left edge of the glyph + /* The minimum value of glyph.x . The left edge of the glyph in the glyph set which advances furthest to the left. */ int y; /* Amount of white space that should be added between lines of @@ -137,10 +137,29 @@ struct font { }; + +struct pm_selector { + unsigned int min; /* smallest index requested */ + unsigned int max; /* largest index requested */ + unsigned int maxmax; /* largest index possible */ + unsigned int count; /* number bits set to 1 in 'record' */ + const unsigned char * record; + /* Bit array 0: absent 1: existent size calculated from maxmax + This is for reading only; not updating. + Might be 'localRecord'; might be fixed object elsewhere. + */ + unsigned char * localRecord; + /* Updateable record optionally pointed to by 'record'. + Null if none. Malloc'ed storage we own otherwise. + */ +}; + + + struct font2 { /* Font structure for expanded character set. - Code points in the range 0...maxmaxglyph are loaded. - Loaded code point is in the range 0..maxglyph . + Code points in the range 0...maxmaxglyph may be loaded. + Actually loaded code point is in the range 0..maxglyph . */ /* 'size' and 'len' are necessary in order to provide forward and @@ -159,7 +178,7 @@ struct font2 { int maxwidth, maxheight; int x; - /* The minimum value of glyph.font. The left edge of the glyph in + /* The minimum value of glyph.x . The left edge of the glyph in the glyph set which advances furthest to the left. */ int y; @@ -177,14 +196,12 @@ struct font2 { */ PM_WCHAR maxglyph; - /* max code point for glyphs, including vacant slots max value of - above i + /* max code point for glyphs, including vacant slots + max value of above i */ - void * selector; - /* Reserved - - Bit array or structure indicating which code points to load. + struct pm_selector * selectorP; + /* Structure with bit array indicating which code points to load. When NULL, all available code points up to maxmaxglyph, inclusive are loaded. @@ -206,14 +223,15 @@ struct font2 { */ unsigned int bit_format; - /* PBM_FORMAT: glyph data: 1 byte per pixel (like P1, but not ASCII) - RPBM_FORMAT: glyph data: 1 bit per pixel + /* PBM_FORMAT: glyph data: 1 byte per pixel (like P1, but not ASCII) + RPBM_FORMAT: glyph data: 1 bit per pixel Currently only PBM_FORMAT is possible */ unsigned int total_chars; - /* Number of glyphs defined in font file, as stated in the CHARS line - of the BDF file PBM sheet font. Always 96 + /* Number of glyphs defined in font file. + BDF file: as stated in the CHARS line. + PBM sheet font: always 96. */ unsigned int chars; @@ -237,7 +255,7 @@ struct font2 { PM_WCHAR default_char; /* Code index of what to show when there is no glyph for a requested - code Available in many BDF fonts between STARPROPERTIES - + code. Available in many BDF fonts between STARPROPERTIES - ENDPROPERTIES. Set to value read from BDF font file. @@ -306,6 +324,11 @@ struct font2 * pbm_loadfont2(const char * const filename, PM_WCHAR const maxmaxglyph); +struct font2 * +pbm_loadfont2select(const char * const filename, + PM_WCHAR const maxmaxglyph, + const struct pm_selector * const selectorP); + struct font * pbm_loadpbmfont(const char * const filename); @@ -320,9 +343,9 @@ pbm_loadbdffont2(const char * const filename, PM_WCHAR const maxmaxglyph); struct font2 * -pbm_loadbdffont2_select(const char * const filename, - PM_WCHAR const maxmaxglyph, - const void * const selector); +pbm_loadbdffont2select(const char * const filename, + PM_WCHAR const maxmaxglyph, + const struct pm_selector * const selectorP); void pbm_createbdffont2_base(struct font2 ** const font2P, @@ -344,6 +367,38 @@ void pbm_dumpfont(struct font * const fontP, FILE * const ofP); +/* selector functions */ + +void +pm_selector_create(unsigned int const max, + struct pm_selector ** const selectorPP); + +void +pm_selector_create_fixed(const unsigned char * const record, + unsigned int const min, + unsigned int const max, + unsigned int const count, + struct pm_selector ** const selectorPP); + +void +pm_selector_destroy(struct pm_selector * const selectorP); + +void +pm_selector_copy(unsigned int const max, + const struct pm_selector * const srcSelectorP, + struct pm_selector ** const destSelectorPP); + +void +pm_selector_mark(struct pm_selector * const selectorP, + unsigned int const index); + +int /* boolean */ +pm_selector_is_marked(const struct pm_selector * const selectorP, + unsigned int const index); + +unsigned int +pm_selector_marked_ct(const struct pm_selector * const selectorP); + #ifdef __cplusplus } #endif diff --git a/lib/pbmfontdata2.c b/lib/pbmfontdata2.c index 11dd84e6..63dd36be 100644 --- a/lib/pbmfontdata2.c +++ b/lib/pbmfontdata2.c @@ -452,7 +452,7 @@ struct font2 const pbm_defaultBdffont2 = { 255, NULL, 255, /* maxglyph, selector, maxmaxglyph */ NULL, 0, 0, /* oldfont, fcols, frows */ PBM_FORMAT, /* bit_format */ - 190, 190, /* total_chars, chars */ + 191, 191, /* total_chars, chars */ FIXED_DATA, /* load_fn */ 32, 1, /* default_char, default_char_defined */ (char *) "builtin bdf", /* name */ -- cgit 1.4.1