From a8a427597fadc87d74484492fe3816354f3417a6 Mon Sep 17 00:00:00 2001 From: Matt Heffron Date: Sun, 30 Nov 2025 17:46:12 -0800 Subject: [PATCH] Significant restructuring: Removed WRITE-BDF-TO-DISPLAYFONT-FILE (i.e., no STRIKE format files). No multiple-values returned. Instead, use LIST when appropriate. BDF-TO-CHARSETINFO is now IDEMPOTENT w.r.t. the GLYPHS. Move resolution and defaulting of FAMILY, FACE, SIZE, ROTATION, DEVICE from WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE to BDF-TO-FONTDESCRIPTOR. Keep the MCCS chars present BITMAP in the BDF-FONT structure, instead of needing to schlepping it around separately. Abstracted testing/setting the MCCS chars present bits to CHAR-PRESENT-BIT (mimicking BITMAPBIT). Added COUNT-MCHARS to know how many MCCS chars are marked in the BITMAP as present. READ-BDF now handles when UTOMCODE? returns multiple mappings, and creates the appropriate duplicate GLYPHS with different MCCS char codes. READ-GLYPH doesn't create an empty BITMAP for spacing glyphs. Use font code changes: Set (CHARSETINFO CHARSETNO). Set (FONTDESCRIPTOR FONTSLUGWIDTH). --- lispusers/READ-BDF | 1070 +++++++---------- lispusers/READ-BDF.DFASL | Bin 27572 -> 24256 bytes lispusers/READ-BDF.TEDIT | Bin 22202 -> 12137 bytes obsolete/lispusers/READ-BDF-old/READ-BDF | 857 +++++++++++++ .../lispusers/READ-BDF-old/READ-BDF.DFASL | Bin 0 -> 21485 bytes .../lispusers/READ-BDF-old/READ-BDF.TEDIT | Bin 0 -> 9819 bytes 6 files changed, 1316 insertions(+), 611 deletions(-) create mode 100644 obsolete/lispusers/READ-BDF-old/READ-BDF create mode 100644 obsolete/lispusers/READ-BDF-old/READ-BDF.DFASL create mode 100644 obsolete/lispusers/READ-BDF-old/READ-BDF.TEDIT diff --git a/lispusers/READ-BDF b/lispusers/READ-BDF index a6855618..77bf8c04 100644 --- a/lispusers/READ-BDF +++ b/lispusers/READ-BDF @@ -1,21 +1,19 @@ (DEFINE-FILE-INFO PACKAGE (DEFPACKAGE "BDF" (USE "XCL" "LISP") (EXPORT "READ-BDF" "BUILD-COMPOSITE" - "WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE") (IMPORT-FROM "IL" "BITBLT" "BITMAPCREATE" "BITMAPHEIGHT" -"BITMAPWIDTH" "BLACKSHADE" "BLTSHADE" "BOLD" "COMPRESSED" "CHARSETINFO" "DISPLAY" "FONTDESCRIPTOR" -"FONTP" "FONTPROP" "INPUT" "ITALIC" "LIGHT" "LRSH" "MEDIUM" "REGULAR" "TCONC" "UTOMCODE" "UTOMCODE?" -"WRITESTRIKEFONTFILE" "MEDLEYFONT.FILENAME" "MEDLEYFONT.WRITE.FONT")) READTABLE "XCL" BASE 10) + "WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE") (IMPORT-FROM "IL" "BITBLT" "BITMAPBIT" "BITMAPCREATE" +"BITMAPHEIGHT" "BITMAPWIDTH" "BLACKSHADE" "BLTSHADE" "BOLD" "COMPRESSED" "CHARSETINFO" "DISPLAY" +"FONTDESCRIPTOR" "FONTP" "FONTPROP" "INPUT" "ITALIC" "LIGHT" "LRSH" "MEDIUM" "REGULAR" "TCONC" +"UTOMCODE?" "MEDLEYFONT.FILENAME" "MEDLEYFONT.WRITE.FONT")) READTABLE "XCL" BASE 10) -(IL:FILECREATED "19-Nov-2025 22:01:49" IL:|{DSK}matt>Interlisp>medley>lispusers>READ-BDF.;37| 59108 +(IL:FILECREATED "30-Nov-2025 17:43:25" IL:|{DSK}matt>Interlisp>medley>lispusers>READ-BDF.;75| 50310 :EDIT-BY "mth" - :CHANGES-TO (FILE-ENVIRONMENTS "READ-BDF") - (IL:FUNCTIONS BUILD-COMPOSITE READ-BDF WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE - WRITE-BDF-TO-DISPLAYFONT-FILES GET-FAMILY-FACE-SIZE-FROM-NAME READ-GLYPH - GET-CHARS-PRESENT) - (IL:STRUCTURES BDF-FONT XLFD) + :CHANGES-TO (IL:FUNCTIONS GLYPHS-BY-CHARSET BDF-TO-FONTDESCRIPTOR + WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE BUILD-COMPOSITE READ-BDF + BDF-TO-CHARSETINFO COUNT-MCHARS) (IL:VARS IL:READ-BDFCOMS) - :PREVIOUS-DATE "18-Nov-2025 21:22:35" IL:|{DSK}matt>Interlisp>medley>lispusers>READ-BDF.;36| + :PREVIOUS-DATE "30-Nov-2025 16:05:42" IL:|{DSK}matt>Interlisp>medley>lispusers>READ-BDF.;74| ) @@ -24,10 +22,10 @@ (IL:RPAQQ IL:READ-BDFCOMS ((IL:STRUCTURES BDF-FONT GLYPH XLFD) (IL:VARIABLES MAXCHARSET MAXTHINCHAR NOMAPPINGCHARSET) - (IL:FUNCTIONS BDF-TO-CHARSETINFO BDF-TO-FONTDESCRIPTOR BUILD-COMPOSITE GET-CHARS-PRESENT - GET-FAMILY-FACE-SIZE-FROM-NAME GLYPHS-BY-CHARSET PACKFILENAME.STRING READ-BDF - READ-DELIMITED-LIST-FROM-STRING READ-GLYPH SPLIT-FONT-NAME - WRITE-BDF-TO-DISPLAYFONT-FILES WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE) + (IL:FUNCTIONS BDF-TO-CHARSETINFO BDF-TO-FONTDESCRIPTOR BUILD-COMPOSITE CHAR-PRESENT-BIT + COUNT-MCHARS GLYPHS-BY-CHARSET PACKFILENAME.STRING READ-BDF + READ-DELIMITED-LIST-FROM-STRING READ-GLYPH WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE + XLFD-SPLIT-FONT-NAME XLFD-TO-FACE) (IL:DECLARE\: IL:EVAL@COMPILE IL:DONTCOPY (IL:FILES (IL:SYSLOAD) IL:SYSEDIT) (IL:FILES (IL:LOADCOMP) @@ -44,7 +42,9 @@ (METRICSSET 0 :TYPE (INTEGER 0 2)) (PROPERTIES NIL :TYPE LIST) SWIDTH DWIDTH SWIDTH1 DWIDTH1 VVECTOR (GLYPHS NIL :TYPE LIST) - (XLFD NIL :TYPE XLFD)) + (UNMAPPED¬GLYPHS NIL :TYPE LIST) + (XLFD NIL :TYPE XLFD) + (MCHAR-PRESENT NIL :TYPE IL:BITMAP)) (DEFSTRUCT GLYPH "This is an individual BDF glyph. Includes some values calculated for creating CHARSETINFO" @@ -61,7 +61,7 @@ (FAMILY NIL :TYPE STRING) (WEIGHT NIL :TYPE STRING) (SLANT NIL :TYPE STRING) - (EXPANSION NIL :TYPE STRING) + (SETWIDTH¬NAME NIL :TYPE STRING) (ADD¬STYLE¬NAME NIL :TYPE STRING) (PIXEL¬SIZE 0 :TYPE INTEGER) (POINT¬SIZE 0 :TYPE INTEGER) @@ -78,81 +78,70 @@ (DEFCONSTANT NOMAPPINGCHARSET (1+ MAXCHARSET)) -(DEFUN BDF-TO-CHARSETINFO (FONT CSET SLUG-OR-WIDTH &OPTIONAL MAP-UNKNOWN-TO-PRIVATE) +(DEFUN BDF-TO-CHARSETINFO (FONT CSET SLUGWIDTH) (IL:* IL:\; "Edited 30-Nov-2025 00:12 by mth") + (IL:* IL:\; "Edited 28-Nov-2025 16:37 by mth") + (IL:* IL:\; "Edited 26-Nov-2025 21:18 by mth") + (IL:* IL:\; "Edited 20-Nov-2025 12:19 by mth") (IL:* IL:\; "Edited 15-Nov-2025 14:26 by mth") (IL:* IL:\; "Edited 6-Nov-2025 17:30 by mth") (IL:* IL:\; "Edited 23-Apr-2025 17:53 by mth") (IL:* IL:\; "Edited 21-Apr-2025 16:23 by mth") (IL:* IL:\; "Edited 30-Jan-2025 16:40 by mth") - (LET (GBCS CSGLYPHS CSLIMITS) + (LET (GBCS CSGLYPHS CSLIMITS SW) (UNLESS (AND (INTEGERP CSET) (<= 0 CSET MAXCHARSET)) (ERROR "Invalid Character set: ~S" CSET) - (IL:* IL:|;;| "Can we get here? I think not!") + (IL:* IL:|;;| "Can we get here? I think not!!") (SETQ CSET 0)) - (SETQ GBCS (COND - ((LISTP FONT) + (COND + ((LISTP FONT) - (IL:* IL:|;;| - "Assuming that FONT is already the LIST of ALIST form of result from GLYPHS-BY-CHARSET") + (IL:* IL:|;;| + "Assuming that FONT is already the LIST of ALIST form of result from GLYPHS-BY-CHARSET") - FONT) - ((BDF-FONT-P FONT) + (SETQ GBCS FONT)) + ((BDF-FONT-P FONT) - (IL:* IL:|;;| - "If passed a BDF-FONT, look only at glyphs in the mapped charsets") + (IL:* IL:|;;| "If passed a BDF-FONT, look only at glyphs in the mapped charsets") - (FIRST (GLYPHS-BY-CHARSET FONT MAP-UNKNOWN-TO-PRIVATE))) - (T (ERROR "Invalid FONT: ~S" FONT)))) + (DESTRUCTURING-SETQ (GBCS SW) + (GLYPHS-BY-CHARSET FONT))) + (T (ERROR "Invalid FONT: ~S" FONT))) + (UNLESS (AND (INTEGERP SLUGWIDTH) + (PLUSP SLUGWIDTH)) + (IF (AND (INTEGERP SW) + (PLUSP SW)) + (SETQ SLUGWIDTH SW) + (ERROR "Invalid SLUGWIDTH: ~D" SLUGWIDTH))) (WHEN (SETQ CSGLYPHS (SECOND (ASSOC CSET GBCS))) (LET ((TOTAL-WIDTH 0) (ASCENT 0) (DESCENT 0) (FIRSTCHAR MOST-POSITIVE-FIXNUM) (LASTCHAR MOST-NEGATIVE-FIXNUM) - (CSINFO (IL:|create| CHARSETINFO)) + (CSINFO (IL:|create| CHARSETINFO + IL:CHARSETNO IL:_ CSET)) (IMAGEWIDTHS (IL:\\CREATECSINFOELEMENT)) (DLEFT 0) - SLUG SLUGWIDTH GLYPHS-LIMITS BMAP OFFSETS HEIGHT WIDTHS) - (COND - ((GLYPH-P SLUG-OR-WIDTH) - (SETQ SLUG SLUG-OR-WIDTH) - (SETQ SLUGWIDTH (1+ (GLYPH-WIDTH SLUG))) - (SETQ ASCENT (MAX ASCENT (GLYPH-ASCENT SLUG))) - (SETQ DESCENT (MAX DESCENT (GLYPH-DESCENT SLUG)))) - ((INTEGERP SLUG-OR-WIDTH) - (SETQ SLUGWIDTH SLUG-OR-WIDTH)) - (T (ERROR "Invalid SLUG-OR-WIDTH: ~S" SLUG-OR-WIDTH))) - (SETQ CSGLYPHS (LOOP :FOR XGL :IN CSGLYPHS :COLLECT (LET* ((MCODE (CAR XGL)) - (GL (CDR XGL)) - (GWIDTH (GLYPH-WIDTH - GL)) - (ASC (GLYPH-ASCENT GL)) - (DSC (GLYPH-DESCENT - GL))) + GLYPHS-LIMITS BMAP OFFSETS HEIGHT WIDTHS) + (LOOP :FOR XGL :IN CSGLYPHS :DO (LET* ((MCODE (CAR XGL)) + (GL (CDR XGL)) + (GWIDTH (GLYPH-WIDTH GL)) + (ASC (GLYPH-ASCENT GL)) + (DSC (GLYPH-DESCENT GL))) (IL:* IL:|;;| "It's possible that ALL glyphs in the character set are above the baseline. In that case, the GLYPH-DESCENT calculated by READ-GLYPH will not give a useful value, since it is >= 0. Investigate correcting this.") - (IL:* IL:|;;| -  - "Is the above statement actually true?") + (IL:* IL:|;;| + "Is the above statement actually true?") - (SETF (GLYPH-MCODE GL) - MCODE) - (SETQ FIRSTCHAR - (MIN FIRSTCHAR MCODE - )) - (SETQ LASTCHAR - (MAX LASTCHAR MCODE) - ) - (INCF TOTAL-WIDTH GWIDTH) - (SETQ ASCENT - (MAX ASCENT ASC)) - (SETQ DESCENT - (MAX DESCENT DSC)) - GL))) + (SETQ FIRSTCHAR (MIN FIRSTCHAR MCODE)) + (SETQ LASTCHAR (MAX LASTCHAR MCODE)) + (INCF TOTAL-WIDTH GWIDTH) + (SETQ ASCENT (MAX ASCENT ASC)) + (SETQ DESCENT (MAX DESCENT DSC)))) (IL:|replace| (CHARSETINFO IL:CHARSETASCENT) IL:|of| CSINFO IL:|with| ASCENT) (IL:|replace| (CHARSETINFO IL:CHARSETDESCENT) IL:|of| CSINFO IL:|with| DESCENT) (SETQ OFFSETS (IL:|fetch| (CHARSETINFO IL:OFFSETS) IL:|of| CSINFO)) @@ -182,175 +171,179 @@ (SETQ BMAP (BITMAPCREATE (+ TOTAL-WIDTH SLUGWIDTH) HEIGHT 1)) (IL:|replace| (CHARSETINFO IL:CHARSETBITMAP) IL:|of| CSINFO IL:|with| BMAP) - (LOOP :FOR GL :IN CSGLYPHS :WITH GLBM :WITH GLW :WITH MCODE :DO (SETQ GLBM - (GLYPH-BITMAP - GL)) + (LOOP :FOR XGL :IN CSGLYPHS :WITH GL :WITH GLBM :WITH GLW :WITH MCODE :DO + (SETQ MCODE (CAR XGL)) + (SETQ GL (CDR XGL)) + (SETQ GLBM (GLYPH-BITMAP GL)) (SETQ GLW (GLYPH-WIDTH GL)) - (SETQ MCODE (GLYPH-MCODE GL)) - (BITBLT GLBM 0 0 BMAP (+ DLEFT (MAX 0 (GLYPH-BBXOFF0 GL))) - (+ DESCENT (GLYPH-BBYOFF0 GL)) - (BITMAPWIDTH GLBM) - (BITMAPHEIGHT GLBM) - 'INPUT - 'IL:REPLACE) + (WHEN GLBM + + (IL:* IL:|;;| "Empty bitmap, nothing to copy.") + + (BITBLT GLBM 0 0 BMAP (+ DLEFT (MAX 0 (GLYPH-BBXOFF0 GL))) + (+ DESCENT (GLYPH-BBYOFF0 GL)) + (BITMAPWIDTH GLBM) + (BITMAPHEIGHT GLBM) + 'INPUT + 'IL:REPLACE)) (IL:\\FSETOFFSET OFFSETS MCODE DLEFT) (IL:\\FSETOFFSET IMAGEWIDTHS MCODE GLW) (IL:\\FSETOFFSET WIDTHS MCODE (FIRST (GLYPH-DWIDTH GL))) (INCF DLEFT GLW)) - (IL:* IL:|;;| "Now insert the SLUG glyph into the BMAP, or make a slug (block)") + (IL:* IL:|;;| "Now make a slug (block)") - (IF SLUG - (LET ((GLBM (GLYPH-BITMAP SLUG))) - (BITBLT GLBM 0 0 BMAP (+ TOTAL-WIDTH (MAX 0 (GLYPH-BBXOFF0 SLUG))) - (+ DESCENT (GLYPH-BBYOFF0 SLUG)) - (BITMAPWIDTH GLBM) - (BITMAPHEIGHT GLBM) - 'INPUT - 'IL:REPLACE)) - (BLTSHADE BLACKSHADE BMAP (1+ TOTAL-WIDTH) - 0 - (1- SLUGWIDTH) - (+ ASCENT DESCENT) - 'IL:REPLACE)) + (BLTSHADE BLACKSHADE BMAP (1+ TOTAL-WIDTH) + 0 + (1- SLUGWIDTH) + (+ ASCENT DESCENT) + 'IL:REPLACE) CSINFO)))) -(DEFUN BDF-TO-FONTDESCRIPTOR (BDFONT FAMILY SIZE FACE ROTATION DEVICE &OPTIONAL - MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING) +(DEFUN BDF-TO-FONTDESCRIPTOR (BDFONT FAMILY SIZE FACE ROTATION DEVICE) + (IL:* IL:\; "Edited 30-Nov-2025 15:59 by mth") + (IL:* IL:\; "Edited 28-Nov-2025 18:03 by mth") + (IL:* IL:\; "Edited 20-Nov-2025 12:46 by mth") (IL:* IL:\; "Edited 5-Nov-2025 16:09 by mth") (IL:* IL:\; "Edited 21-Apr-2025 16:03 by mth") (IL:* IL:\; "Edited 30-Jan-2025 21:27 by mth") + + (IL:* IL:|;;| "Check valid required arguments") + (WHEN (AND (BDF-FONT-P BDFONT) - FAMILY) (IL:* IL:\; "FAMILY Cannot be NIL") - (PROG* ((SLUG (BF-SLUG BDFONT)) - (SLUGWIDTH (AND SLUG (GLYPH-WIDTH SLUG))) - FONTDESC DEV GBCSL CHARSETS) - (WHEN (FONTP FAMILY) - (RETURN (BDF-TO-FONTDESCRIPTOR BDFONT (FONTPROP FAMILY 'IL:FAMILY) - (OR SIZE (FONTPROP FAMILY 'IL:SIZE)) - (OR FACE (FONTPROP FAMILY 'IL:FACE)) - (OR ROTATION (FONTPROP FAMILY 'IL:ROTATION)) - (OR DEVICE (FONTPROP FAMILY 'IL:DEVICE)) - MAP-UNKNOWN-TO-PRIVATE))) - (WHEN (LISTP FAMILY) + FAMILY) + (WHEN (FONTP FAMILY) + (RETURN-FROM BDF-TO-FONTDESCRIPTOR (BDF-TO-FONTDESCRIPTOR BDFONT (FONTPROP FAMILY + 'IL:FAMILY) + (OR SIZE (FONTPROP FAMILY 'IL:SIZE)) + (OR FACE (FONTPROP FAMILY 'IL:FACE)) + (OR ROTATION (FONTPROP FAMILY 'IL:ROTATION)) + (OR DEVICE (FONTPROP FAMILY 'IL:DEVICE))))) + (WHEN (LISTP FAMILY) - (IL:* IL:|;;| "Assume this is a FONTSPEC") + (IL:* IL:|;;| "Assume this is a FONTSPEC.") - (RETURN (BDF-TO-FONTDESCRIPTOR BDFONT (IL:|fetch| (IL:FONTSPEC IL:FSFAMILY) - IL:|of| FAMILY) - (OR (IL:|fetch| (IL:FONTSPEC IL:FSSIZE) IL:|of| FAMILY) - SIZE) - (OR (IL:|fetch| (IL:FONTSPEC IL:FSFACE) IL:|of| FAMILY) - FACE "MRR") - (OR (IL:|fetch| (IL:FONTSPEC IL:FSROTATION) IL:|of| FAMILY) - ROTATION 0) - (OR (IL:|fetch| (IL:FONTSPEC IL:FSDEVICE) IL:|of| FAMILY) - DEVICE - 'DISPLAY) - MAP-UNKNOWN-TO-PRIVATE))) - (SETQ FAMILY (IL:\\FONTSYMBOL FAMILY)) - (UNLESS (AND (INTEGERP SIZE) - (PLUSP SIZE)) - (ERROR "Invalid SIZE: ~S~%" SIZE)) - (COND - ((NULL ROTATION) - (SETQ ROTATION 0)) - ((NOT (AND (INTEGERP ROTATION) - (>= ROTATION 0))) - (IL:\\ILLEGAL.ARG ROTATION))) - (SETQ DEV DEVICE) - (SETQ DEV (COND - ((NULL DEVICE) - 'DISPLAY) - ((AND (SYMBOLP DEVICE) - (NOT (EQ DEVICE T))) + (RETURN-FROM BDF-TO-FONTDESCRIPTOR (BDF-TO-FONTDESCRIPTOR BDFONT (IL:|fetch| (IL:FONTSPEC + IL:FSFAMILY) + IL:|of| FAMILY) + (OR SIZE (IL:|fetch| (IL:FONTSPEC IL:FSSIZE) + IL:|of| FAMILY)) + (OR FACE (IL:|fetch| (IL:FONTSPEC IL:FSFACE) + IL:|of| FAMILY) + 'IL:MRR) + (OR ROTATION (IL:|fetch| (IL:FONTSPEC + IL:FSROTATION) + IL:|of| FAMILY) + 0) + (OR DEVICE (IL:|fetch| (IL:FONTSPEC IL:FSDEVICE) + IL:|of| FAMILY) + 'DISPLAY)))) + (LET ((XLFD (BF-XLFD BDFONT)) + FONTDESC GBCSL CHARSETS SLUGWIDTH) + (SETQ FAMILY (IL:\\FONTSYMBOL (OR FAMILY (XLFD-FAMILY XLFD)))) + (SETQ FACE (OR FACE (XLFD-TO-FACE XLFD))) + (SETQ SIZE (OR SIZE (AND (>= (XLFD-PIXEL¬SIZE XLFD) + 0) + (XLFD-PIXEL¬SIZE XLFD)) + (AND (>= (XLFD-POINT¬SIZE XLFD) + 0) + (CEILING (XLFD-POINT¬SIZE XLFD) + 10)) + (FIRST (BF-SIZE BDFONT)))) + (COND + ((NULL ROTATION) + (SETQ ROTATION 0)) + ((NOT (AND (IL:SMALLP ROTATION) + (>= ROTATION 0))) + (IL:\\ILLEGAL.ARG ROTATION))) + (SETQ DEVICE (COND + ((OR (NULL DEVICE) + (EQ DEVICE T)) + 'DISPLAY) + ((SYMBOLP DEVICE) - (IL:* IL:|;;| + (IL:* IL:|;;| + "This PROBABLY isn't a good assumption... BUT it's a very unlikely case.") + + (IL:* IL:|;;|  "Maybe wrong case or package, but we bet it's OK and defer expensive coercion until we've failed.") - DEVICE) - ((STRINGP DEVICE) - (INTERN (STRING-UPCASE DEVICE) - "IL")) - (T (IL:\\ILLEGAL.ARG DEVICE)))) - (SETQ FACE (IL:\\FONTFACE FACE NIL DEV)) - (SETQ GBCSL (GLYPHS-BY-CHARSET BDFONT MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING)) - (UNLESS SLUGWIDTH + DEVICE) + ((STRINGP DEVICE) + (INTERN (STRING-UPCASE DEVICE) + "IL")) + (T (IL:\\ILLEGAL.ARG DEVICE)))) + (SETQ FACE (IL:\\FONTFACE (OR FACE (XLFD-TO-FACE XLFD) + 'IL:MRR) + NIL DEVICE)) + (DESTRUCTURING-SETQ (GBCSL SLUGWIDTH) + (GLYPHS-BY-CHARSET BDFONT)) + (UNLESS SLUGWIDTH - (IL:* IL:|;;| - "If GLYPHS-BY-CHARSET didn't determine the SLUG width, use 60% of the SIZE, at least 1") + (IL:* IL:|;;| + "If GLYPHS-BY-CHARSET didn't determine the SLUGWIDTH, use 60% of the SIZE, at least 1") - (SETQ SLUGWIDTH (OR (THIRD GBCSL) - (MAX 1 (ROUND (* 0.6 SIZE)))))) - (FLET ((GBCS-TO-FONTDESC - (GBCS FAMILY) - (LET (FONTDESC CHARSETS) - (WHEN GBCS - (SETQ FONTDESC - (IL:|create| FONTDESCRIPTOR - IL:FONTDEVICE IL:_ DEV - IL:FONTFAMILY IL:_ FAMILY - IL:FONTSIZE IL:_ SIZE - IL:FONTFACE IL:_ FACE - IL:|\\SFAscent| IL:_ 0 - IL:|\\SFDescent| IL:_ 0 - IL:|\\SFHeight| IL:_ 0 - IL:ROTATION IL:_ ROTATION - IL:FONTDEVICESPEC IL:_ (LIST FAMILY SIZE FACE ROTATION - DEV))) - (SETQ CHARSETS (LOOP :FOR CS :IN GBCS :WITH CSET :WITH CSINFO :NCONC - (WHEN (<= 0 (SETQ CSET (FIRST CS)) - MAXCHARSET) - (SETQ CSINFO (BDF-TO-CHARSETINFO - GBCS CSET (OR SLUG (1+ - SLUGWIDTH - )))) - (IL:\\INSTALLCHARSETINFO FONTDESC CSINFO CSET - ) - (LIST CSET))))) - (LIST FONTDESC CHARSETS)))) - (RETURN (VALUES-LIST (NCONC (GBCS-TO-FONTDESC (FIRST GBCSL) - FAMILY) - (GBCS-TO-FONTDESC (SECOND GBCSL) - (IL:\\FONTSYMBOL (CONCATENATE 'STRING - (SYMBOL-NAME FAMILY) - "-UNMAPPED"))) - (LIST (ASSOC NOMAPPINGCHARSET (FIRST GBCSL) - :TEST - #'EQL))))))))) + (SETQ SLUGWIDTH (MAX 1 (ROUND (* 0.6 SIZE))))) + (WHEN GBCSL + (SETQ FONTDESC + (IL:|create| FONTDESCRIPTOR + IL:FONTDEVICE IL:_ DEVICE + IL:FONTFAMILY IL:_ FAMILY + IL:FONTSIZE IL:_ SIZE + IL:FONTFACE IL:_ FACE + IL:|\\SFAscent| IL:_ 0 + IL:|\\SFDescent| IL:_ 0 + IL:|\\SFHeight| IL:_ 0 + IL:ROTATION IL:_ ROTATION + IL:FONTDEVICESPEC IL:_ (LIST FAMILY SIZE FACE ROTATION DEVICE) + IL:FONTSLUGWIDTH IL:_ SLUGWIDTH)) + (SETQ CHARSETS (LOOP :FOR CS :IN GBCSL :WITH CSET :WITH CSINFO :NCONC + (WHEN (<= 0 (SETQ CSET (FIRST CS)) + MAXCHARSET) + (SETQ CSINFO (BDF-TO-CHARSETINFO GBCSL CSET (1+ SLUGWIDTH))) + (IL:\\INSTALLCHARSETINFO FONTDESC CSINFO CSET) + (LIST CSET))))) + (LIST FONTDESC CHARSETS)))) -(DEFUN BUILD-COMPOSITE (BASE-FONT &REST FILL-FROM) (IL:* IL:\; "Edited 18-Nov-2025 21:22 by mth") +(DEFUN BUILD-COMPOSITE (BASE-FONT &REST FILL-FROM) (IL:* IL:\; "Edited 30-Nov-2025 12:32 by mth") + (IL:* IL:\; "Edited 26-Nov-2025 21:23 by mth") + (IL:* IL:\; "Edited 18-Nov-2025 21:22 by mth") (IL:* IL:\; "Edited 16-Nov-2025 18:25 by mth") (IL:* IL:\; "Edited 14-Nov-2025 17:04 by mth") - (LET (UCHAR-PRESENT FONT FAMILY WEIGHT SLANT EXPANSION SIZE UC-PRESENT) + (LET (MCHAR-PRESENT FONT) (UNLESS (AND FILL-FROM (LISTP FILL-FROM)) (ERROR "FILL-FROM is not a list.")) + (WHEN (LISTP BASE-FONT) + + (IL:* IL:|;;| "Allow specifying both BASE-FONT and FILL-FROM in a single LIST.") + + (SETQ FONT (FIRST BASE-FONT)) + (SETQ FILL-FROM (APPEND (REST BASE-FONT) + FILL-FROM)) + (SETQ BASE-FONT FONT)) (COND ((OR (STRINGP BASE-FONT) (PATHNAMEP BASE-FONT)) (UNLESS (IL:INFILEP BASE-FONT) (ERROR "BASE-FONT ~S doesn't exist or is unreadable." BASE-FONT)) - (MULTIPLE-VALUE-SETQ (FONT FAMILY WEIGHT SLANT EXPANSION SIZE UC-PRESENT) - (READ-BDF BASE-FONT :MCCS-ONLY T)) - (SETQ BASE-FONT FONT) - (SETQ UCHAR-PRESENT UC-PRESENT)) - ((TYPEP BASE-FONT 'BDF-FONT) - (SETQ UCHAR-PRESENT (GET-CHARS-PRESENT BASE-FONT))) - (T (ERROR "BASE-FONT is not a BDF-FONT, nor string, nor pathname."))) - (UNLESS UCHAR-PRESENT) - (LOOP :FOR FILL-FONT :IN FILL-FROM :WHEN FILL-FONT :DO - (COND - ((OR (STRINGP FILL-FONT) - (PATHNAMEP FILL-FONT)) - (UNLESS (IL:INFILEP FILL-FONT) - (ERROR "Element of FILL-FROM (~S) doesn't exist or is unreadable." FILL-FONT - )) - (MULTIPLE-VALUE-SETQ (FONT FAMILY WEIGHT SLANT EXPANSION SIZE UC-PRESENT) - (READ-BDF FILL-FONT :MCCS-ONLY T)) - (SETQ FILL-FONT FONT)) - ((NOT (TYPEP FILL-FONT 'BDF-FONT)) - (ERROR "Element of FILL-FROM (~S) is not a BDF-FONT, nor string, nor pathname." - FILL-FONT))) + (SETQ BASE-FONT (READ-BDF BASE-FONT :MCCS-ONLY T))) + ((NOT (TYPEP BASE-FONT 'BDF-FONT)) + (ERROR "BASE-FONT is not a BDF-FONT, nor string, nor pathname."))) + (SETQ MCHAR-PRESENT (BF-MCHAR-PRESENT BASE-FONT)) + (LOOP :FOR FILL-FONT :IN FILL-FROM :WHEN FILL-FONT :DO (COND + ((OR (STRINGP FILL-FONT) + (PATHNAMEP FILL-FONT)) + (UNLESS (IL:INFILEP FILL-FONT) + (ERROR + "Element of FILL-FROM (~S) doesn't exist or is unreadable." + FILL-FONT)) + (SETQ FILL-FONT + (READ-BDF FILL-FONT + :MCCS-ONLY T))) + ((NOT (BDF-FONT-P FILL-FONT)) + (ERROR + "Element of FILL-FROM (~S) is not a BDF-FONT, nor string, nor pathname." + FILL-FONT))) (LOOP :FOR GL :IN (BF-GLYPHS FILL-FONT) :WITH V :DO (SETQ V (GLYPH-ENCODING GL)) (WHEN (AND (LISTP V) @@ -363,11 +356,8 @@  "Need to change this use of UTOMCODE? based on the CHARSET¬REGISTRY of the XLFD of FILL-FONT") (WHEN (AND (UTOMCODE? V) - (ZEROP (BIT (AREF UCHAR-PRESENT (LRSH V 8)) - (LOGAND V 255)))) - (SETF (BIT (AREF UCHAR-PRESENT (LRSH V 8)) - (LOGAND V 255)) - 1) + (ZEROP (CHAR-PRESENT-BIT MCHAR-PRESENT V))) + (CHAR-PRESENT-BIT MCHAR-PRESENT V 1) (IL:* IL:|;;|  "What other bookkeping of BASE-FONT needs to be done when adding a glyph? Any?") @@ -375,226 +365,80 @@ (PUSH GL (BF-GLYPHS BASE-FONT))))) BASE-FONT)) -(DEFUN GET-CHARS-PRESENT (BFONT) (IL:* IL:\; "Edited 16-Nov-2025 17:52 by mth") - (IL:* IL:\; "Edited 14-Nov-2025 16:40 by mth") - (UNLESS (TYPEP BFONT 'BDF-FONT) - (ERROR "BFONT is not a BDF-FONT.")) - (LET ((UCHAR-PRESENT (MAKE-ARRAY 256 :INITIAL-CONTENTS (LOOP :FOR I :FROM 0 :TO 255 :COLLECT - (MAKE-ARRAY 256 :ELEMENT-TYPE - 'BIT :INITIAL-ELEMENT 0))))) - (LOOP :FOR GL :IN (BF-GLYPHS BFONT) - :WITH V :DO (SETQ V (GLYPH-ENCODING GL)) - (WHEN (AND (LISTP V) - (EQ (FIRST V) - -1)) - (SETQ V (OR (SECOND V) - -1))) - (WHEN (UTOMCODE? V) - (SETF (BIT (AREF UCHAR-PRESENT (LRSH V 8)) - (LOGAND V 255)) - 1))) - UCHAR-PRESENT)) +(DEFUN CHAR-PRESENT-BIT (BM MCODE &OPTIONAL (NEWBIT -1 SBIT) + &AUX CS CC) (IL:* IL:\; "Edited 26-Nov-2025 09:29 by mth") + (COND + ((NOT (TYPEP BM 'IL:BITMAP)) + (ERROR "BM is not a BITMAP")) + ((NOT (AND (INTEGERP MCODE) + (<= 0 MCODE 65535))) + (ERROR "Invalid MCODE")) + (SBIT (COND + ((OR (EQL NEWBIT 1) + (EQ NEWBIT T)) + (SETQ NEWBIT 1)) + ((OR (EQL NEWBIT 0) + (NULL NEWBIT)) + (SETQ NEWBIT 0)) + (T (ERROR "Invalid NEWBIT"))))) + (LET ((CS (- 255 (LRSH MCODE 8))) + (CC (LOGAND MCODE 255))) + (BITMAPBIT BM CC CS (AND SBIT NEWBIT)))) -(DEFUN GET-FAMILY-FACE-SIZE-FROM-NAME (FONTNAME) (IL:* IL:\; "Edited 18-Nov-2025 15:15 by mth") - (IL:* IL:\; "Edited 30-Apr-2025 13:18 by mth") - (IL:* IL:\; "Edited 23-Apr-2025 16:20 by mth") - (IL:* IL:\; "Edited 5-Feb-2025 12:56 by mth") - (UNLESS (STRINGP FONTNAME) - (IL:\\ILLEGAL.ARG FONTNAME)) - (FLET ((PARSE-P-SIZE (SZSTR) - (COND - ((ZEROP (LENGTH SZSTR)) - -1) - ((PARSE-INTEGER SZSTR :JUNK-ALLOWED T)) - (T -1)))) - (DESTRUCTURING-BIND (FOUNDRY FAMILY WEIGHT SLANT EXPANSION ADD¬STYLE¬NAME PIXEL¬SIZE - POINT¬SIZE RESOLUTION¬X RESOLUTION¬Y SPACING AVERAGE¬WIDTH - CHARSET¬REGISTRY CHARSET¬ENCODING) - (SPLIT-FONT-NAME FONTNAME) +(DEFUN COUNT-MCHARS (BDFONT) (IL:* IL:\; "Edited 29-Nov-2025 23:52 by mth") + (WHEN (BDF-FONT-P BDFONT) + (LET ((MCPBM (BF-MCHAR-PRESENT BDFONT))) + (LOOP :FOR MC :FROM 0 :TO 65535 :COUNT (PLUSP (CHAR-PRESENT-BIT MCPBM MC)))))) - (IL:* IL:|;;| "Now, parse pieces as XLFD format") - - (SETQ FAMILY (REMOVE #\Space FAMILY :TEST #'CHAR=)) - (SETQ WEIGHT (OR (AND WEIGHT (CDR (ASSOC (CHAR-UPCASE (ELT WEIGHT 0)) - '((#\R . MEDIUM) - (#\M . MEDIUM) - (#\N . MEDIUM) - (#\B . BOLD) - (#\D . BOLD) - (#\L . LIGHT))))) - 'MEDIUM)) (IL:* IL:\; "DemiBold => BOLD") - (SETQ SLANT (OR (AND SLANT (CDR (ASSOC (CHAR-UPCASE (ELT SLANT 0)) - '((REGULAR) - (#\R . REGULAR) - (#\I . ITALIC) - (#\O . ITALIC))))) - 'REGULAR)) (IL:* IL:\; "Oblique => ITALIC") - (IL:* IL:\; "Ignore others") - (SETQ EXPANSION (OR (AND EXPANSION (CDR (ASSOC (CHAR-UPCASE (ELT EXPANSION 0)) - '((#\R . REGULAR) - (#\N . REGULAR) - (#\B . BOLD) - (#\S . COMPRESSED) - (#\C . COMPRESSED))))) - 'REGULAR)) (IL:* IL:\; - "S is for \"SemiCondensed\", Assuming \"Condensed\"") - - (IL:* IL:|;;| - "Now check for WEIGHT and EXPANSION both BOLD. If so, change Expansion to REGULAR") - - (WHEN (AND (EQ WEIGHT EXPANSION) - (EQ EXPANSION 'BOLD)) - (SETQ EXPANSION 'REGULAR)) - (SETQ PIXEL¬SIZE (PARSE-P-SIZE PIXEL¬SIZE)) - (SETQ POINT¬SIZE (PARSE-P-SIZE POINT¬SIZE)) - (MAKE-XLFD :FOUNDRY FOUNDRY :FAMILY FAMILY :WEIGHT WEIGHT :SLANT SLANT :EXPANSION - EXPANSION :ADD¬STYLE¬NAME ADD¬STYLE¬NAME :PIXEL¬SIZE :POINT¬SIZE :RESOLUTION¬X - RESOLUTION¬X :RESOLUTION¬Y RESOLUTION¬Y :SPACING SPACING :AVERAGE¬WIDTH - AVERAGE¬WIDTH :CHARSET¬REGISTRY CHARSET¬REGISTRY :CHARSET¬ENCODING - CHARSET¬ENCODING)))) - -(DEFUN GLYPHS-BY-CHARSET (FONT &OPTIONAL MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING) +(DEFUN GLYPHS-BY-CHARSET (FONT) (IL:* IL:\; "Edited 30-Nov-2025 17:36 by mth") + (IL:* IL:\; "Edited 28-Nov-2025 17:24 by mth") + (IL:* IL:\; "Edited 26-Nov-2025 20:50 by mth") + (IL:* IL:\; "Edited 20-Nov-2025 12:01 by mth") (IL:* IL:\; "Edited 6-Nov-2025 18:11 by mth") (IL:* IL:\; "Edited 5-Nov-2025 16:18 by mth") (IL:* IL:\; "Edited 21-Apr-2025 15:48 by mth") (IL:* IL:\; "Edited 9-Jan-2025 11:23 by mth") (LET* ((NCSETS (+ MAXCHARSET 2)) (CSETS (MAKE-ARRAY NCSETS :INITIAL-CONTENTS (LOOP :REPEAT NCSETS :COLLECT (CONS NIL)))) - (UTOMFN (COND - (RAW-UNICODE-MAPPING #'IDENTITY) - (MAP-UNKNOWN-TO-PRIVATE #'UTOMCODE) - (T #'UTOMCODE?))) - (SLUG (BF-SLUG FONT)) - (SLUGWIDTH (AND SLUG (GLYPH-WIDTH SLUG))) - NOMAPPINGCSETS ENC MCODE MCS) - (UNLESS (OR MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING) - (SETQ NOMAPPINGCSETS (MAKE-ARRAY NCSETS :INITIAL-CONTENTS (LOOP :REPEAT NCSETS :COLLECT - (CONS NIL))))) - (FLET ((PUT-GLYPH-IN-CHARSET-ARRAY (CODE GLYPH CSARRAY) - (TCONC (AREF CSARRAY (LRSH CODE 8)) + SLUGWIDTH ENC MCODE CS-USED) + (FLET ((PUT-GLYPH-IN-CHARSET-ARRAY (CODE GLYPH CSARRAY &AUX CS) + (TCONC (AREF CSARRAY (SETQ CS (LRSH CODE 8))) (CONS (LOGAND CODE 255) - GLYPH)))) + GLYPH)) + (PUSHNEW CS CS-USED :TEST #'EQL))) (LOOP :FOR GL :IN (BF-GLYPHS FONT) - :UNLESS - (EQ GL SLUG) :DO - (SETQ MCS NIL) - (SETQ ENC (GLYPH-ENCODING GL)) - (WHEN (LISTP ENC) + (SETQ MCODE (GLYPH-MCODE GL)) + (COND + ((AND (INTEGERP MCODE) + (<= 0 MCODE 65535)) - (IL:* IL:|;;| - "Should happen only if -1 is first on ENCODING line in BDF file") + (IL:* IL:|;;| "These assoc with the 8 bit character code within the charset") - (SETQ ENC (OR (SECOND ENC) - -1)) + (PUT-GLYPH-IN-CHARSET-ARRAY MCODE GL CSETS) - (IL:* IL:|;;| - "The -1 case of the (OR ...) shouldn't happen. The (EQ GL SLUG) test above should have caught it") + (IL:* IL:|;;| "Default SLUG width is width of A, in charset 0") - ) - (SETQ MCODE (AND (INTEGERP ENC) - (PLUSP ENC) - (FUNCALL UTOMFN ENC))) - (IF RAW-UNICODE-MAPPING - (COND - ((> ENC 65535) - (WARN "~&Unicode encoding is beyond 16 bits: ~5X" ENC) - (TCONC (AREF CSETS NOMAPPINGCHARSET) - (CONS ENC GL))) - ((AND NIL (= 255 (LOGAND ENC 255))) + (WHEN (AND (NOT SLUGWIDTH) + (ZEROP (LRSH MCODE 8)) + (EQL MCODE (CHAR-CODE #\A))) + (SETQ SLUGWIDTH (GLYPH-WIDTH GL)))) + (T + (IL:* IL:|;;| "Shouldn't happen!") - (IL:* IL:|;;| - "Temporarily? disable this warning in RAW-UNICODE-MAPPING mode") + (ERROR "Invalid MCODE: ~A~%"))))) + (SETQ CSETS (LOOP :FOR I :IN CS-USED :NCONC (LET ((CS (CAR (AREF CSETS I)))) - (WARN - "~&Unicode encoding char byte (~2X,FF)=(~O,377) may not =FF in FONTDESCRIPTOR" - (LRSH ENC 8) - (LRSH ENC 8)) - (TCONC (AREF CSETS NOMAPPINGCHARSET) - (CONS ENC GL))) - (T (PUT-GLYPH-IN-CHARSET-ARRAY ENC GL CSETS))) - (COND - ((AND (ZEROP (GLYPH-BBW GL)) - (ZEROP (FIRST (GLYPH-DWIDTH GL)))) + (IL:* IL:|;;| + "Extract the lists from the TCONC pointers") - (IL:* IL:|;;| - "This has zero-width \"image\" with zero-width \"escapement\", put it in the NOMAPPINGCHARSET") - - (TCONC (AREF CSETS NOMAPPINGCHARSET) - (CONS ENC GL))) - ((NULL MCODE) - - (IL:* IL:|;;| "These assoc with the Unicode encoding") - - (COND - ((OR (> ENC 65535) - (= 255 (LOGAND ENC 255))) - - (IL:* IL:|;;| - "Unicode encoding is > xFFFF, or encoding low byte is FF, put it in the NOMAPPINGCHARSET") - - (TCONC (AREF CSETS NOMAPPINGCHARSET) - (CONS ENC GL))) - (T (PUT-GLYPH-IN-CHARSET-ARRAY ENC GL NOMAPPINGCSETS)))) - ((AND (INTEGERP MCODE) - (<= 0 MCODE 65535)) - - (IL:* IL:|;;| - "These assoc with the 8 bit character code within the charset") - - (PUT-GLYPH-IN-CHARSET-ARRAY MCODE GL CSETS) - - (IL:* IL:|;;| "Default SLUG width is width of A.") - - (WHEN (AND (NOT SLUGWIDTH) - (= ENC (CHAR-CODE #\A))) - - (IL:* IL:|;;| "A is the same code in MCCS and UNICODE ") - - (IL:* IL:|;;| - "Comparing with ENC, not MCODE, to look only in charset 0") - - (SETQ SLUGWIDTH (GLYPH-WIDTH GL)))) - ((LISTP MCODE) - - (IL:* IL:|;;| - "These assoc with the 8 bit character code within the charset (like above)") - - (LOOP :FOR MC :IN MCODE :WITH CS :UNLESS (MEMBER (SETQ CS - (LRSH MC 8)) - MCS) - :DO - (PUSH CS MCS) - (PUT-GLYPH-IN-CHARSET-ARRAY MC GL CSETS))) - (T (ERROR "Invalid MCODE: ~A~%")))))) - - (IL:* IL:|;;| "Extract the lists from the TCONC pointers") - - (LOOP :FOR I :FROM 0 :TO NOMAPPINGCHARSET :DO (SETF (AREF CSETS I) - (SORT (REMOVE-DUPLICATES - (CAR (AREF CSETS I)) - :TEST - #'EQUAL) - #'< :KEY #'CAR))) - (SETQ CSETS (LOOP :FOR I :FROM 0 :TO NOMAPPINGCHARSET :NCONC - (LET ((CS (AREF CSETS I))) - (WHEN CS - (LIST (LIST I CS)))))) - - (IL:* IL:|;;| "Likewise for the NOMAPPINGCSETS, if any.") - - (WHEN NOMAPPINGCSETS - (LOOP :FOR I :FROM 0 :TO NOMAPPINGCHARSET :DO - (SETF (AREF NOMAPPINGCSETS I) - (SORT (REMOVE-DUPLICATES (CAR (AREF NOMAPPINGCSETS I)) - :TEST - #'EQUAL) - #'< :KEY #'CAR))) - (SETQ NOMAPPINGCSETS (LOOP :FOR I :FROM 0 :TO NOMAPPINGCHARSET :NCONC - (LET ((CS (AREF NOMAPPINGCSETS I))) - (WHEN CS - (LIST (LIST I CS))))))) - (LIST CSETS NOMAPPINGCSETS SLUGWIDTH))) + (SETQ CS (SORT (REMOVE-DUPLICATES + CS :TEST #'EQUAL) + #'< :KEY #'CAR)) + (WHEN CS + (LIST (LIST I CS)))))) + (LIST (SORT CSETS #'< :KEY #'CAR) + SLUGWIDTH))) (DEFMACRO PACKFILENAME.STRING (&WHOLE WHOLE) (IL:* IL:\; "Edited 1-Feb-2025 23:17 by mth") `(IL:PACKFILENAME.STRING ,@(LOOP :FOR X :IN (CDR WHOLE) @@ -617,19 +461,22 @@ Y)))) (DEFUN READ-BDF (PATH &KEY VERBOSE MCCS-ONLY (EXTERNAL-FORMAT :ISO8859/1)) - (IL:* IL:\; "Edited 18-Nov-2025 19:39 by mth") + (IL:* IL:\; "Edited 30-Nov-2025 11:59 by mth") + (IL:* IL:\; "Edited 28-Nov-2025 17:39 by mth") + (IL:* IL:\; "Edited 26-Nov-2025 22:47 by mth") + (IL:* IL:\; "Edited 19-Nov-2025 23:15 by mth") (IL:* IL:\; "Edited 14-Nov-2025 16:35 by mth") (IL:* IL:\; "Edited 30-Apr-2025 13:37 by mth") (IL:* IL:\; "Edited 24-Apr-2025 00:44 by mth") (IL:* IL:\; "Edited 17-Apr-2025 15:10 by mth") (IL:* IL:\; "Edited 12-Jul-2024 23:02 by mth") (LET - (PROPS PROPS-COMPLETE CHARS-COUNT FONT-COMPLETE FONT POS KEY V VV LINE ITEMS GL XLFD (NGLYPHS - 0) - (UCHAR-PRESENT (MAKE-ARRAY 256 :INITIAL-CONTENTS (LOOP :FOR I :FROM 0 :TO 255 :COLLECT - (MAKE-ARRAY 256 :ELEMENT-TYPE - 'BIT :INITIAL-ELEMENT 0)))) - (*PACKAGE* (FIND-PACKAGE "BDF"))) + ((NGLYPHS 0) + (MCHAR-PRESENT (BITMAPCREATE 256 256 1)) + (*PACKAGE* (FIND-PACKAGE "BDF")) + (MAPPED-GLYPHS (LIST NIL)) + (UNMAPPED-GLYPHS (LIST NIL)) + PROPS PROPS-COMPLETE CHARS-COUNT FONT-COMPLETE FONT POS KEY V VV LINE ITEMS GL XLFD) (IL:* IL:|;;| "Note: The EXTERNAL-FORMAT *ought* to be :UTF-8 for the BDF files from otf2bdf, but I'm seeing :ISO8859/1. I don't know why! But I'm setting the default :EXTERNAL-FORMAT appropriately for this.") @@ -647,7 +494,7 @@ (IL:* IL:|;;| "ignore the file format version number") (READ-LINE FILE-STREAM) - (SETQ FONT (MAKE-BDF-FONT)) + (SETQ FONT (MAKE-BDF-FONT :MCHAR-PRESENT MCHAR-PRESENT)) (LOOP :UNTIL FONT-COMPLETE :DO (SETQ LINE (READ-LINE FILE-STREAM)) (WHEN LINE (IL:* IL:\; "Ignore blank lines") @@ -661,7 +508,7 @@ (SETF (BF-NAME FONT) LINE) (SETF (BF-XLFD FONT) - (GET-FAMILY-FACE-SIZE-FROM-NAME LINE))) + (SETQ XLFD (XLFD-SPLIT-FONT-NAME LINE)))) (T (SETQ ITEMS (READ-DELIMITED-LIST-FROM-STRING LINE)) (CASE KEY @@ -727,32 +574,42 @@ (PLUSP NGLYPHS)) (ERROR "Invalid BDF file - CHARS count (~A) is invalid or missing." NGLYPHS)) + (LOOP :REPEAT NGLYPHS :WITH ENC :WITH MC :DO (SETQ GL (READ-GLYPH + FILE-STREAM + FONT)) + (SETQ ENC (GLYPH-ENCODING GL)) + (WHEN (AND (LISTP ENC) + (EQ (FIRST ENC) + -1)) + (SETQ ENC (OR (SECOND ENC) + -1))) + (COND + ((AND (OR (PLUSP (GLYPH-BBW GL)) + (PLUSP (FIRST (GLYPH-DWIDTH GL)))) + (SETQ MC (UTOMCODE? ENC))) + + (IL:* IL:|;;| "This glyph must have either a non-zero-width \"image\" or a non-zero-width \"escapement\", otherwise it cannot be mapped, no matter the UTOMCODE? value.") + + (LOOP :FOR CC :IN (IL:MKLIST MC) + :WITH CGL :DO + + (IL:* IL:|;;| "Copy GL if multiple MCODEs") + + (SETQ CGL (IF (LISTP MC) + (COPY-GLYPH GL) + GL)) + (SETF (GLYPH-MCODE CGL) + CC) + + (IL:* IL:|;;| "It ought to be safe to share the bitmap") + + (TCONC MAPPED-GLYPHS CGL) + (CHAR-PRESENT-BIT MCHAR-PRESENT CC 1))) + (T (TCONC UNMAPPED-GLYPHS GL)))) (SETF (BF-GLYPHS FONT) - (LOOP :REPEAT NGLYPHS :NCONC - (PROGN (SETQ GL (READ-GLYPH FILE-STREAM FONT)) - (SETQ V (GLYPH-ENCODING GL)) - (WHEN (AND (LISTP V) - (EQ (FIRST V) - -1)) - (SETQ V (OR (SECOND V) - -1))) - (COND - ((EQ V -1) - - (IL:* IL:|;;| - "Any GLYPH with ENCODING of -1 will be ignored.") - - NIL) - ((UTOMCODE? V) - - (IL:* IL:|;;| - "Need to change this based on the CHARSET¬REGISTRY of the XLFD") - - (SETF (BIT (AREF UCHAR-PRESENT (LRSH V 8)) - (LOGAND V 255)) - 1) - (LIST GL)) - (T NIL)))))) + (CAR MAPPED-GLYPHS)) + (SETF (BF-UNMAPPED¬GLYPHS FONT) + (CAR UNMAPPED-GLYPHS))) (ENDFONT (SETQ FONT-COMPLETE T)))))))) (WHEN VERBOSE @@ -766,22 +623,16 @@ (XLFD-POINT¬SIZE XLFD) (XLFD-WEIGHT XLFD) (XLFD-SLANT XLFD) - (XLFD-EXPANSION XLFD))) - (VALUES FONT (XLFD-FAMILY XLFD) - (XLFD-WEIGHT XLFD) - (XLFD-SLANT XLFD) - (XLFD-EXPANSION XLFD) - (LIST (FIRST (BF-SIZE FONT)) - (XLFD-PIXEL¬SIZE XLFD) - (XLFD-POINT¬SIZE XLFD)) - UCHAR-PRESENT)))) + (XLFD-SETWIDTH¬NAME XLFD))) + FONT))) (DEFUN READ-DELIMITED-LIST-FROM-STRING (INPUT-STRING &OPTIONAL (DELIMIT #\])) (IL:* IL:\; "Edited 20-Aug-2024 16:46 by mth") (WITH-INPUT-FROM-STRING (SI (CONCATENATE 'STRING INPUT-STRING " " (STRING DELIMIT))) (READ-DELIMITED-LIST DELIMIT SI))) -(DEFUN READ-GLYPH (FILE-STREAM FONT) (IL:* IL:\; "Edited 17-Nov-2025 20:03 by mth") +(DEFUN READ-GLYPH (FILE-STREAM FONT) (IL:* IL:\; "Edited 26-Nov-2025 23:32 by mth") + (IL:* IL:\; "Edited 17-Nov-2025 20:03 by mth") (IL:* IL:\; "Edited 23-Apr-2025 17:53 by mth") (IL:* IL:\; "Edited 21-Apr-2025 13:37 by mth") (IL:* IL:\; "Edited 19-Apr-2025 09:32 by mth") @@ -840,37 +691,41 @@ (THIRD ITEMS) (GLYPH-BBYOFF0 GLYPH) (FOURTH ITEMS))) - (BITMAP (LET* ((BM (BITMAPCREATE BBW BBH 1)) - (BM.BASE (IL:|fetch| IL:BITMAPBASE IL:|of| BM)) - (BM.RASTERWIDTH (IL:|fetch| IL:BITMAPRASTERWIDTH - IL:|of| BM)) - (NBYTES (CEILING BBW 8)) - (NCHARS (* 2 NBYTES)) - (NWORDS (CEILING BBW 16)) - BITS BYTEPOS WORDINDEX) - (LOOP :WITH BITROW = 0 :REPEAT BBH :DO - (SETQ LINE (STRING-TRIM '(#\Space #\Tab) - (READ-LINE FILE-STREAM))) - (UNLESS (AND (EQUAL NCHARS (LENGTH LINE)) - (SETQ BITS - (PARSE-INTEGER LINE :RADIX 16 - :JUNK-ALLOWED T))) - (ERROR + (BITMAP (UNLESS (ZEROP (* BBW BBH)) + + (IL:* IL:|;;| "Don't bother creating a BITMAP with no area") + + (LET* ((BM (BITMAPCREATE BBW BBH 1)) + (BM.BASE (IL:|fetch| IL:BITMAPBASE IL:|of| BM)) + (BM.RASTERWIDTH (IL:|fetch| IL:BITMAPRASTERWIDTH + IL:|of| BM)) + (NBYTES (CEILING BBW 8)) + (NCHARS (* 2 NBYTES)) + (NWORDS (CEILING BBW 16)) + BITS BYTEPOS WORDINDEX) + (LOOP :WITH BITROW = 0 :REPEAT BBH :DO + (SETQ LINE (STRING-TRIM '(#\Space #\Tab) + (READ-LINE FILE-STREAM))) + (UNLESS (AND (EQUAL NCHARS (LENGTH LINE)) + (SETQ BITS + (PARSE-INTEGER LINE :RADIX 16 + :JUNK-ALLOWED T))) + (ERROR "Invalid BDF file - bad line in BITMAP: ~A" - LINE)) - (WHEN (ODDP NBYTES) - (SETQ BITS (ASH BITS 8))) - (SETQ WORDINDEX (* BITROW BM.RASTERWIDTH)) - (SETQ BYTEPOS (* 16 (1- NWORDS))) - (LOOP :REPEAT NWORDS :DO - (IL:\\PUTBASE BM.BASE WORDINDEX - (LDB (BYTE 16 BYTEPOS) - BITS)) - (INCF WORDINDEX) - (DECF BYTEPOS 16)) - (INCF BITROW)) - (SETF (GLYPH-BITMAP GLYPH) - BM))) + LINE)) + (WHEN (ODDP NBYTES) + (SETQ BITS (ASH BITS 8))) + (SETQ WORDINDEX (* BITROW BM.RASTERWIDTH)) + (SETQ BYTEPOS (* 16 (1- NWORDS))) + (LOOP :REPEAT NWORDS :DO + (IL:\\PUTBASE BM.BASE WORDINDEX + (LDB (BYTE 16 BYTEPOS) + BITS)) + (INCF WORDINDEX) + (DECF BYTEPOS 16)) + (INCF BITROW)) + (SETF (GLYPH-BITMAP GLYPH) + BM)))) (ENDCHAR (SETQ CHAR-COMPLETE T))))))) (SETF (GLYPH-ASCENT GLYPH) (+ (GLYPH-BBH GLYPH) @@ -883,123 +738,118 @@ (FIRST (GLYPH-DWIDTH GLYPH)))) GLYPH)) -(DEFUN SPLIT-FONT-NAME (NAME) (IL:* IL:\; "Edited 23-Apr-2025 16:22 by mth") - (IL:* IL:\; "Edited 31-Jan-2025 22:20 by mth") - - (IL:* IL:|;;| "First, check if it COULD be in XLFD format") - - (COND - ((POSITION #\- NAME :TEST #'CHAR=) - (LOOP :FOR I = (IF (CHAR= #\- (ELT NAME 0)) - 1 - 0) - THEN - (1+ J) - :AS J = (POSITION #\- NAME :START I :TEST #'CHAR=) - :COLLECT - (SUBSEQ NAME I J) - :WHILE J)) - (T - (IL:* IL:|;;| "Return the NAME as FAMILY with a NIL FOUNDRY") - - (LIST NIL NAME)))) - -(DEFUN WRITE-BDF-TO-DISPLAYFONT-FILES (BDFONT DEST-DIR &KEY FAMILY SIZE FACE ROTATION DEVICE - MAP-UNKNOWN-TO-PRIVATE WRITE-UNMAPPED - RAW-UNICODE-MAPPING (CHAR-SETS T)) - (IL:* IL:\; "Edited 18-Nov-2025 15:37 by mth") - (IL:* IL:\; "Edited 5-Nov-2025 23:06 by mth") - (IL:* IL:\; "Edited 25-Apr-2025 10:08 by mth") - (IL:* IL:\; "Edited 24-Apr-2025 00:09 by mth") - (IL:* IL:\; "Edited 21-Apr-2025 16:03 by mth") - (IL:* IL:\; "Edited 3-Feb-2025 23:18 by mth") - (UNLESS (TYPEP BDFONT 'BDF-FONT) - (ERROR "Not a BDF-FONT: ~S ~%" BDFONT)) - (COND - ((EQ CHAR-SETS T) (IL:* IL:\; "This means ALL charsets") - ) - ((NULL CHAR-SETS) - (SETQ CHAR-SETS '(0)) (IL:* IL:\; "Only charset 0") - ) - ((AND (INTEGERP CHAR-SETS) - (<= 0 CHAR-SETS MAXCHARSET)) (IL:* IL:\; "A single integer charset") - (SETQ CHAR-SETS (LIST CHAR-SETS))) - ((AND (LISTP CHAR-SETS) - (EVERY #'(LAMBDA (CS) - (AND (INTEGERP CS) - (<= 0 CS MAXCHARSET))) - CHAR-SETS))) - (T (ERROR "Invalid specification of :CHAR-SETS ~S~%" CHAR-SETS))) - (LET ((XLFD (BF-XLFD BDFONT))) - (SETQ FAMILY (OR FAMILY (XLFD-FAMILY XLFD))) - (WHEN RAW-UNICODE-MAPPING - (SETQ FAMILY (IL:\\FONTSYMBOL (CONCATENATE 'STRING "RAW-" (STRING FAMILY))))) - (SETQ FACE (OR FACE (LIST (XLFD-WEIGHT XLFD) - (XLFD-SLANT XLFD) - (XLFD-EXPANSION XLFD)))) - (SETQ SIZE (OR SIZE (AND (>= (XLFD-PIXEL¬SIZE XLFD) - 0) - (XLFD-PIXEL¬SIZE XLFD)) - (AND (>= (XLFD-POINT¬SIZE XLFD) - 0) - (CEILING (XLFD-POINT¬SIZE XLFD) - 10)) - (FIRST (BF-SIZE BDFONT)))) - (MULTIPLE-VALUE-BIND (FONTDESC CSETS UNMAPPED-FONTDESC UNICODE-CSETS UNMAPPEDGLYPHS) - (BDF-TO-FONTDESCRIPTOR BDFONT FAMILY SIZE FACE ROTATION DEVICE MAP-UNKNOWN-TO-PRIVATE - RAW-UNICODE-MAPPING) - (UNLESS (EQ CHAR-SETS T) - (SETQ CSETS (INTERSECTION CHAR-SETS CSETS)) - (SETQ UNICODE-CSETS (INTERSECTION CHAR-SETS UNICODE-CSETS))) - (LOOP :FOR CS :IN CSETS :DO (WRITESTRIKEFONTFILE FONTDESC CS - (PACKFILENAME.STRING :BODY DEST-DIR :NAME - (IL:\\FONTFILENAME FAMILY SIZE FACE - "DISPLAYFONT" CS)))) - (IF WRITE-UNMAPPED - (LOOP :FOR CS :IN UNICODE-CSETS :DO (WRITESTRIKEFONTFILE - UNMAPPED-FONTDESC CS - (PACKFILENAME.STRING - :BODY DEST-DIR :NAME - (IL:\\FONTFILENAME (FONTPROP - UNMAPPED-FONTDESC - 'IL:FAMILY) - SIZE FACE "DISPLAYFONT" CS)))) - (SETQ UNICODE-CSETS NIL)) - - (IL:* IL:|;;| "These correspond to the charsets ACTUALLY written.") - - (IL:* IL:|;;| - "UNMAPPEDGLYPHS are never written. (Unicode encoding is > xFFFF, or encoding low byte is FF)") - - (VALUES FONTDESC CSETS UNMAPPED-FONTDESC UNICODE-CSETS UNMAPPEDGLYPHS)))) - (DEFUN WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE (BDFONT DEST-DIR &KEY FAMILY SIZE FACE ROTATION DEVICE &AUX FULLFILENAME) - (IL:* IL:\; "Edited 18-Nov-2025 15:37 by mth") + (IL:* IL:\; "Edited 30-Nov-2025 16:03 by mth") + (IL:* IL:\; "Edited 28-Nov-2025 17:56 by mth") + (IL:* IL:\; "Edited 26-Nov-2025 21:07 by mth") (IL:* IL:\; "Edited 16-Nov-2025 17:32 by mth") (UNLESS (TYPEP BDFONT 'BDF-FONT) (ERROR "Not a BDF-FONT: ~S ~%" BDFONT)) - (LET ((XLFD (BF-XLFD BDFONT))) - (SETQ FAMILY (OR FAMILY (XLFD-FAMILY XLFD))) - (SETQ FACE (OR FACE (LIST (XLFD-WEIGHT XLFD) - (XLFD-SLANT XLFD) - (XLFD-EXPANSION XLFD)))) - (SETQ SIZE (OR SIZE (AND (>= (XLFD-PIXEL¬SIZE XLFD) - 0) - (XLFD-PIXEL¬SIZE XLFD)) - (AND (>= (XLFD-POINT¬SIZE XLFD) - 0) - (CEILING (XLFD-POINT¬SIZE XLFD) - 10)) - (FIRST (BF-SIZE BDFONT)))) - (MULTIPLE-VALUE-BIND (FONTDESC CSETS) - (BDF-TO-FONTDESCRIPTOR BDFONT FAMILY SIZE FACE ROTATION DEVICE) - (SETQ FULLFILENAME (MEDLEYFONT.WRITE.FONT FONTDESC (MEDLEYFONT.FILENAME FONTDESC NIL - NIL DEST-DIR))) + (DESTRUCTURING-BIND (FONTDESC CSETS) + (BDF-TO-FONTDESCRIPTOR BDFONT FAMILY SIZE FACE ROTATION DEVICE) + (UNLESS FONTDESC - (IL:* IL:|;;| "These correspond to the charsets ACTUALLY written.") + (IL:* IL:|;;| "Creation of the FONTDESCRIPTOR failed!") - (VALUES FULLFILENAME FONTDESC CSETS)))) + (HELP "FONTDESC IS NIL")) + + (IL:* IL:|;;| "CSETS correspond to the charsets actually present in the FONTDESC.") + + (SETQ FULLFILENAME (MEDLEYFONT.WRITE.FONT FONTDESC (MEDLEYFONT.FILENAME FONTDESC NIL NIL + DEST-DIR))) + (LIST FULLFILENAME FONTDESC CSETS))) + +(DEFUN XLFD-SPLIT-FONT-NAME (NAME) (IL:* IL:\; "Edited 26-Nov-2025 09:43 by mth") + (IL:* IL:\; "Edited 23-Apr-2025 16:22 by mth") + (IL:* IL:\; "Edited 31-Jan-2025 22:20 by mth") + (LET (PARTS (XLFD (MAKE-XLFD))) + + (IL:* IL:|;;| "First, check if it COULD be in XLFD format") + + (SETQ PARTS (IF (POSITION #\- NAME :TEST #'CHAR=) + (LOOP :FOR I = (IF (CHAR= #\- (ELT NAME 0)) + 1 + 0) + THEN + (1+ J) + :AS J = (POSITION #\- NAME :START I :TEST #'CHAR=) + :COLLECT + (SUBSEQ NAME I J) + :WHILE J) + (PROGN + (IL:* IL:|;;| + "There are no -'s, so use the NAME as the FAMILY with a NIL FOUNDRY") + + (LIST NIL NAME)))) + (FLET ((PARSE-P-SIZE (SZSTR) + (COND + ((ZEROP (LENGTH SZSTR)) + -1) + ((PARSE-INTEGER SZSTR :JUNK-ALLOWED T)) + (T -1)))) + (DESTRUCTURING-BIND (FOUNDRY FAMILY WEIGHT SLANT SETWIDTH¬NAME ADD¬STYLE¬NAME + PIXEL¬SIZE POINT¬SIZE RESOLUTION¬X RESOLUTION¬Y SPACING + AVERAGE¬WIDTH CHARSET¬REGISTRY CHARSET¬ENCODING) + PARTS + (SETQ FAMILY (REMOVE #\Space FAMILY :TEST #'CHAR=)) + (SETQ PIXEL¬SIZE (PARSE-P-SIZE PIXEL¬SIZE)) + (SETQ POINT¬SIZE (PARSE-P-SIZE POINT¬SIZE)) + (MAKE-XLFD :FOUNDRY FOUNDRY :FAMILY FAMILY :WEIGHT WEIGHT :SLANT SLANT + :SETWIDTH¬NAME SETWIDTH¬NAME :ADD¬STYLE¬NAME ADD¬STYLE¬NAME :PIXEL¬SIZE + PIXEL¬SIZE :POINT¬SIZE POINT¬SIZE :RESOLUTION¬X RESOLUTION¬X + :RESOLUTION¬Y RESOLUTION¬Y :SPACING SPACING :AVERAGE¬WIDTH AVERAGE¬WIDTH + :CHARSET¬REGISTRY CHARSET¬REGISTRY :CHARSET¬ENCODING CHARSET¬ENCODING))))) + +(DEFUN XLFD-TO-FACE (XLFD) (IL:* IL:\; "Edited 25-Nov-2025 17:50 by mth") + (UNLESS (TYPEP XLFD 'XLFD) + (ERROR "Not an XLFD object: ~S ~%" XLFD)) + (LET ((WEIGHT (XLFD-WEIGHT XLFD)) + (SLANT (XLFD-SLANT XLFD)) + (EXPANSION (XLFD-SETWIDTH¬NAME XLFD))) + + (IL:* IL:|;;| "mth 11-25-2025 Brute force hackery now. This needs to be made smarter.") + + (SETQ WEIGHT (OR (AND WEIGHT (CADR (ASSOC (CHAR-UPCASE (ELT WEIGHT 0)) + '((#\R MEDIUM) + (#\M MEDIUM) + (#\N MEDIUM) + (#\B BOLD) + (#\D BOLD + (IL:* IL:\; "DemiBold => BOLD")) + (#\L LIGHT))))) + 'MEDIUM)) + (SETQ SLANT (OR (AND SLANT (CADR (ASSOC (CHAR-UPCASE (ELT SLANT 0)) + '((REGULAR) + (#\R REGULAR) + (#\I ITALIC) + (#\O ITALIC + (IL:* IL:\; "Oblique => ITALIC")))))) + 'REGULAR)) (IL:* IL:\; "Ignore other SLANTs") + + (IL:* IL:|;;| "Expansion (SETWIDTH¬NAME) has many more options than these, and they aren't 1st character unique! Apparently, there's no set of (semi-)standard names.") + + (SETQ EXPANSION (OR (AND EXPANSION (CADR (ASSOC (CHAR-UPCASE (ELT EXPANSION 0)) + '((#\R REGULAR) + (#\N REGULAR) + (#\E EXPANDED + (IL:* IL:\; + "E could be ExtraCondensed, Expanded, ExtraExpanded!!!") + ) + (#\S COMPRESSED + (IL:* IL:\; + "S is for \"SemiCompressed\", Using \"Condensed\"") + ) + (#\C COMPRESSED))))) + 'REGULAR)) + + (IL:* IL:|;;| + "Now check for WEIGHT and EXPANSION both BOLD. If so, change Expansion to REGULAR") + + (WHEN (AND (EQ WEIGHT EXPANSION) + (EQ EXPANSION 'BOLD)) + (SETQ EXPANSION 'REGULAR)) + (LIST WEIGHT SLANT EXPANSION))) (IL:DECLARE\: IL:EVAL@COMPILE IL:DONTCOPY (IL:FILESLOAD (IL:SYSLOAD) @@ -1013,27 +863,25 @@ (DEFINE-FILE-ENVIRONMENT "READ-BDF" :PACKAGE (DEFPACKAGE "BDF" (:USE "XCL" "LISP") (:EXPORT "READ-BDF" "BUILD-COMPOSITE" "WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE") - (:IMPORT-FROM "IL" "BITBLT" "BITMAPCREATE" - "BITMAPHEIGHT" "BITMAPWIDTH" "BLACKSHADE" - "BLTSHADE" "BOLD" "COMPRESSED" - "CHARSETINFO" "DISPLAY" "FONTDESCRIPTOR" - "FONTP" "FONTPROP" "INPUT" "ITALIC" - "LIGHT" "LRSH" "MEDIUM" "REGULAR" "TCONC" - "UTOMCODE" "UTOMCODE?" - "WRITESTRIKEFONTFILE" + (:IMPORT-FROM "IL" "BITBLT" "BITMAPBIT" + "BITMAPCREATE" "BITMAPHEIGHT" + "BITMAPWIDTH" "BLACKSHADE" "BLTSHADE" + "BOLD" "COMPRESSED" "CHARSETINFO" + "DISPLAY" "FONTDESCRIPTOR" "FONTP" + "FONTPROP" "INPUT" "ITALIC" "LIGHT" "LRSH" + "MEDIUM" "REGULAR" "TCONC" "UTOMCODE?" "MEDLEYFONT.FILENAME" "MEDLEYFONT.WRITE.FONT")) :READTABLE "XCL" :COMPILER :COMPILE-FILE) (IL:PUTPROPS IL:READ-BDF IL:DATABASE IL:NO) -(IL:PUTPROPS IL:READ-BDF IL:COPYRIGHT (IL:NONE)) (IL:DECLARE\: IL:DONTCOPY - (IL:FILEMAP (NIL (3325 11890 (BDF-TO-CHARSETINFO 3325 . 11890)) (11892 18310 (BDF-TO-FONTDESCRIPTOR -11892 . 18310)) (18312 21261 (BUILD-COMPOSITE 18312 . 21261)) (21263 22332 (GET-CHARS-PRESENT 21263 . -22332)) (22334 26224 (GET-FAMILY-FACE-SIZE-FROM-NAME 22334 . 26224)) (26226 33656 (GLYPHS-BY-CHARSET -26226 . 33656)) (33658 35083 (PACKFILENAME.STRING 33658 . 35083)) (35085 44000 (READ-BDF 35085 . 44000 -)) (44002 44325 (READ-DELIMITED-LIST-FROM-STRING 44002 . 44325)) (44327 50925 (READ-GLYPH 44327 . -50925)) (50927 51668 (SPLIT-FONT-NAME 50927 . 51668)) (51670 56008 (WRITE-BDF-TO-DISPLAYFONT-FILES -51670 . 56008)) (56010 57596 (WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE 56010 . 57596))))) + (IL:FILEMAP (NIL (3235 10173 (BDF-TO-CHARSETINFO 3235 . 10173)) (10175 16397 (BDF-TO-FONTDESCRIPTOR +10175 . 16397)) (16399 20017 (BUILD-COMPOSITE 16399 . 20017)) (20019 20768 (CHAR-PRESENT-BIT 20019 . +20768)) (20770 21054 (COUNT-MCHARS 20770 . 21054)) (21056 24091 (GLYPHS-BY-CHARSET 21056 . 24091)) ( +24093 25518 (PACKFILENAME.STRING 24093 . 25518)) (25520 34886 (READ-BDF 25520 . 34886)) (34888 35211 ( +READ-DELIMITED-LIST-FROM-STRING 34888 . 35211)) (35213 42211 (READ-GLYPH 35213 . 42211)) (42213 43494 +(WRITE-BDF-TO-MEDLEYDISPLAYFONT-FILE 42213 . 43494)) (43496 45913 (XLFD-SPLIT-FONT-NAME 43496 . 45913) +) (45915 48927 (XLFD-TO-FACE 45915 . 48927))))) IL:STOP diff --git a/lispusers/READ-BDF.DFASL b/lispusers/READ-BDF.DFASL index 9fd699bcf7f9f5751c2edbca2774d4593cd6ef00..faa31f3d52c8e8996ca08918d24cf61612c2c854 100644 GIT binary patch literal 24256 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 literal 27572 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.;13| 49101 + + :EDIT-BY "mth" + + :CHANGES-TO (IL:FUNCTIONS BDF-TO-FONTDESCRIPTOR BDF-TO-CHARSETINFO READ-GLYPH + WRITE-BDF-TO-DISPLAYFONT-FILES) + (FILE-ENVIRONMENTS "READ-BDF") + (IL:VARS IL:READ-BDFCOMS) + + :PREVIOUS-DATE " 6-Nov-2025 22:43:21" IL:|{DSK}matt>Interlisp>medley>lispusers>READ-BDF.;9| +) + + +(IL:PRETTYCOMPRINT IL:READ-BDFCOMS) + +(IL:RPAQQ IL:READ-BDFCOMS + ((IL:STRUCTURES BDF-FONT GLYPH) + (IL:VARIABLES MAXCHARSET MAXTHINCHAR NOMAPPINGCHARSET) + (IL:FUNCTIONS BDF-TO-CHARSETINFO BDF-TO-FONTDESCRIPTOR GET-FAMILY-FACE-SIZE-FROM-NAME + GLYPHS-BY-CHARSET PACKFILENAME.STRING READ-BDF READ-DELIMITED-LIST-FROM-STRING + READ-GLYPH SPLIT-FONT-NAME WRITE-BDF-TO-DISPLAYFONT-FILES) + (IL:DECLARE\: IL:EVAL@COMPILE IL:DONTCOPY (IL:FILES (IL:SYSLOAD) + IL:SYSEDIT) + (IL:FILES (IL:LOADCOMP) + IL:FONT)) + (FILE-ENVIRONMENTS "READ-BDF") + (IL:PROP (IL:DATABASE) + IL:READ-BDF))) + +(DEFSTRUCT (BDF-FONT (:CONC-NAME "BF-")) + "Main structure to hold a parsed BDF font file" + (NAME NIL :TYPE STRING) + (SIZE NIL :TYPE LIST) + (BOUNDINGBOX NIL :TYPE LIST) + (METRICSSET 0 :TYPE (INTEGER 0 2)) + (PROPERTIES NIL :TYPE LIST) + SWIDTH DWIDTH SWIDTH1 DWIDTH1 VVECTOR (GLYPHS NIL :TYPE LIST) + (SLUG NIL :TYPE GLYPH)) + +(DEFSTRUCT GLYPH + "This is an individual BDF glyph. Includes some values calculated for creating CHARSETINFO" + (NAME NIL :TYPE STRING) + ENCODING SWIDTH DWIDTH SWIDTH1 DWIDTH1 VVECTOR BBW BBH BBXOFF0 BBYOFF0 BITMAP + (MCODE 0 :TYPE INTEGER) + (WIDTH 0 :TYPE INTEGER) + (ASCENT 0 :TYPE INTEGER) + (DESCENT 0 :TYPE INTEGER)) + +(DEFCONSTANT MAXCHARSET 255) + +(DEFCONSTANT MAXTHINCHAR 255) + +(DEFCONSTANT NOMAPPINGCHARSET (1+ MAXCHARSET)) + +(DEFUN BDF-TO-CHARSETINFO (FONT CSET SLUG-OR-WIDTH &OPTIONAL MAP-UNKNOWN-TO-PRIVATE) + (IL:* IL:\; "Edited 6-Nov-2025 17:30 by mth") + (IL:* IL:\; "Edited 23-Apr-2025 17:53 by mth") + (IL:* IL:\; "Edited 21-Apr-2025 16:23 by mth") + (IL:* IL:\; "Edited 30-Jan-2025 16:40 by mth") + (LET (GBCS CSGLYPHS CSLIMITS) + (UNLESS (AND (INTEGERP CSET) + (<= 0 CSET MAXCHARSET)) + (ERROR "Invalid Character set: ~S" CSET) + + (IL:* IL:|;;| "Can we get here? I think not!") + + (SETQ CSET 0)) + (SETQ GBCS (COND + ((LISTP FONT) + + (IL:* IL:|;;| + "Assuming that FONT is already the LIST of ALIST form of result from GLYPHS-BY-CHARSET") + + FONT) + ((BDF-FONT-P FONT) + + (IL:* IL:|;;| + "If passed a BDF-FONT, look only at glyphs in the mapped charsets") + + (FIRST (GLYPHS-BY-CHARSET FONT MAP-UNKNOWN-TO-PRIVATE))) + (T (ERROR "Invalid FONT: ~S" FONT)))) + (WHEN (SETQ CSGLYPHS (SECOND (ASSOC CSET GBCS))) + (LET ((TOTAL-WIDTH 0) + (ASCENT 0) + (DESCENT 0) + (FIRSTCHAR MOST-POSITIVE-FIXNUM) + (LASTCHAR MOST-NEGATIVE-FIXNUM) + (CSINFO (IL:|create| CHARSETINFO)) + (DLEFT 0) + SLUG SLUGWIDTH GLYPHS-LIMITS BMAP OFFSETS HEIGHT WIDTHS) + (COND + ((GLYPH-P SLUG-OR-WIDTH) + (SETQ SLUG SLUG-OR-WIDTH) + (SETQ SLUGWIDTH (1+ (GLYPH-WIDTH SLUG))) + (SETQ ASCENT (MAX ASCENT (GLYPH-ASCENT SLUG))) + (SETQ DESCENT (MAX DESCENT (GLYPH-DESCENT SLUG)))) + ((INTEGERP SLUG-OR-WIDTH) + (SETQ SLUGWIDTH SLUG-OR-WIDTH)) + (T (ERROR "Invalid SLUG-OR-WIDTH: ~S" SLUG-OR-WIDTH))) + (SETQ CSGLYPHS (LOOP :FOR XGL :IN CSGLYPHS :COLLECT (LET* ((MCODE (CAR XGL)) + (GL (CDR XGL)) + (GWIDTH (GLYPH-WIDTH + GL)) + (ASC (GLYPH-ASCENT GL)) + (DSC (GLYPH-DESCENT + GL))) + + (IL:* IL:|;;| "It's possible that ALL glyphs in the character set are above the baseline. In that case, the GLYPH-DESCENT calculated by READ-GLYPH will not give a useful value, since it is >= 0. Investigate correcting this.") + + (IL:* IL:|;;| +  + "Is the above statement actually true?") + + (SETF (GLYPH-MCODE GL) + MCODE) + (SETQ FIRSTCHAR + (MIN FIRSTCHAR MCODE + )) + (SETQ LASTCHAR + (MAX LASTCHAR MCODE) + ) + (INCF TOTAL-WIDTH GWIDTH) + (SETQ ASCENT + (MAX ASCENT ASC)) + (SETQ DESCENT + (MAX DESCENT DSC)) + GL))) + (IL:|replace| (CHARSETINFO IL:CHARSETASCENT) IL:|of| CSINFO IL:|with| ASCENT) + (IL:|replace| (CHARSETINFO IL:CHARSETDESCENT) IL:|of| CSINFO IL:|with| DESCENT) + (SETQ OFFSETS (IL:|fetch| (CHARSETINFO IL:OFFSETS) IL:|of| CSINFO)) + + (IL:* IL:|;;| + "Initialize the offsets to the TOTAL-WIDTH (without the SLUG. It will be added later)") + + (IL:|for| I IL:|from| 0 IL:|to| (+ MAXTHINCHAR 2) IL:|do| (IL:\\FSETOFFSET OFFSETS I + TOTAL-WIDTH)) + (SETQ WIDTHS (IL:|fetch| (CHARSETINFO IL:WIDTHS) IL:|of| CSINFO)) + + (IL:* IL:|;;| "Initialize the widths to SLUGWIDTH") + + (IL:|for| I IL:|from| 0 IL:|to| (+ MAXTHINCHAR 2) IL:|do| (IL:\\FSETWIDTH WIDTHS I + SLUGWIDTH)) + (IL:|replace| (CHARSETINFO IL:IMAGEWIDTHS) IL:|of| CSINFO IL:|with| WIDTHS) + + (IL:* IL:|;;| "JDS 12/4/92: Apparently, these fields can be signed values, if all chars, e.g., ride above the base line. ") + + (IL:* IL:|;;| " From \\READSTRIKEFONTFILE, so -ve DESCENT is possible?") + + (SETQ HEIGHT (+ ASCENT DESCENT)) + (SETQ BMAP (BITMAPCREATE (+ TOTAL-WIDTH SLUGWIDTH) + HEIGHT 1)) + (IL:|replace| (CHARSETINFO IL:CHARSETBITMAP) IL:|of| CSINFO IL:|with| BMAP) + (LOOP :FOR GL :IN CSGLYPHS :WITH GLBM :WITH GLW :WITH MCODE :DO (SETQ GLBM + (GLYPH-BITMAP + GL)) + (SETQ GLW (GLYPH-WIDTH GL)) + (SETQ MCODE (GLYPH-MCODE GL)) + (BITBLT GLBM 0 0 BMAP (+ DLEFT (MAX 0 (GLYPH-BBXOFF0 GL))) + (+ DESCENT (GLYPH-BBYOFF0 GL)) + (BITMAPWIDTH GLBM) + (BITMAPHEIGHT GLBM) + 'INPUT + 'IL:REPLACE) + (IL:\\FSETOFFSET OFFSETS MCODE DLEFT) + (IL:\\FSETOFFSET WIDTHS MCODE GLW) + (INCF DLEFT GLW)) + + (IL:* IL:|;;| "Now insert the SLUG glyph into the BMAP, or make a slug (block)") + + (IF SLUG + (LET ((GLBM (GLYPH-BITMAP SLUG))) + (BITBLT GLBM 0 0 BMAP (+ TOTAL-WIDTH (MAX 0 (GLYPH-BBXOFF0 SLUG))) + (+ DESCENT (GLYPH-BBYOFF0 SLUG)) + (BITMAPWIDTH GLBM) + (BITMAPHEIGHT GLBM) + 'INPUT + 'IL:REPLACE)) + (BLTSHADE BLACKSHADE BMAP (1+ TOTAL-WIDTH) + 0 + (1- SLUGWIDTH) + (+ ASCENT DESCENT) + 'IL:REPLACE)) + CSINFO)))) + +(DEFUN BDF-TO-FONTDESCRIPTOR (BDFONT FAMILY SIZE FACE ROTATION DEVICE &OPTIONAL + MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING) + (IL:* IL:\; "Edited 5-Nov-2025 16:09 by mth") + (IL:* IL:\; "Edited 21-Apr-2025 16:03 by mth") + (IL:* IL:\; "Edited 30-Jan-2025 21:27 by mth") + (WHEN (AND (BDF-FONT-P BDFONT) + FAMILY) (IL:* IL:\; "FAMILY Cannot be NIL") + (PROG* ((SLUG (BF-SLUG BDFONT)) + (SLUGWIDTH (AND SLUG (GLYPH-WIDTH SLUG))) + FONTDESC DEV GBCSL CHARSETS) + (WHEN (FONTP FAMILY) + (RETURN (BDF-TO-FONTDESCRIPTOR BDFONT (FONTPROP FAMILY 'IL:FAMILY) + (OR SIZE (FONTPROP FAMILY 'IL:SIZE)) + (OR FACE (FONTPROP FAMILY 'IL:FACE)) + (OR ROTATION (FONTPROP FAMILY 'IL:ROTATION)) + (OR DEVICE (FONTPROP FAMILY 'IL:DEVICE)) + MAP-UNKNOWN-TO-PRIVATE))) + (WHEN (LISTP FAMILY) + + (IL:* IL:|;;| "Assume this is a FONTSPEC") + + (RETURN (BDF-TO-FONTDESCRIPTOR BDFONT (IL:|fetch| (IL:FONTSPEC IL:FSFAMILY) + IL:|of| FAMILY) + (OR (IL:|fetch| (IL:FONTSPEC IL:FSSIZE) IL:|of| FAMILY) + SIZE) + (OR (IL:|fetch| (IL:FONTSPEC IL:FSFACE) IL:|of| FAMILY) + FACE "MRR") + (OR (IL:|fetch| (IL:FONTSPEC IL:FSROTATION) IL:|of| FAMILY) + ROTATION 0) + (OR (IL:|fetch| (IL:FONTSPEC IL:FSDEVICE) IL:|of| FAMILY) + DEVICE + 'DISPLAY) + MAP-UNKNOWN-TO-PRIVATE))) + (SETQ FAMILY (IL:\\FONTSYMBOL FAMILY)) + (UNLESS (AND (INTEGERP SIZE) + (PLUSP SIZE)) + (ERROR "Invalid SIZE: ~S~%" SIZE)) + (COND + ((NULL ROTATION) + (SETQ ROTATION 0)) + ((NOT (AND (INTEGERP ROTATION) + (>= ROTATION 0))) + (IL:\\ILLEGAL.ARG ROTATION))) + (SETQ DEV DEVICE) + (SETQ DEV (COND + ((NULL DEVICE) + 'DISPLAY) + ((AND (SYMBOLP DEVICE) + (NOT (EQ DEVICE T))) + + (IL:* IL:|;;| + "Maybe wrong case or package, but we bet it's OK and defer expensive coercion until we've failed.") + + DEVICE) + ((STRINGP DEVICE) + (INTERN (STRING-UPCASE DEVICE) + "IL")) + (T (IL:\\ILLEGAL.ARG DEVICE)))) + (SETQ FACE (IL:\\FONTFACE FACE NIL DEV)) + (SETQ GBCSL (GLYPHS-BY-CHARSET BDFONT MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING)) + (UNLESS SLUGWIDTH + + (IL:* IL:|;;| + "If GLYPHS-BY-CHARSET didn't determine the SLUG width, use 60% of the SIZE, at least 1") + + (SETQ SLUGWIDTH (OR (THIRD GBCSL) + (MAX 1 (ROUND (* 0.6 SIZE)))))) + (FLET ((GBCS-TO-FONTDESC + (GBCS FAMILY) + (LET (FONTDESC CHARSETS) + (WHEN GBCS + (SETQ FONTDESC + (IL:|create| FONTDESCRIPTOR + IL:FONTDEVICE IL:_ DEV + IL:FONTFAMILY IL:_ FAMILY + IL:FONTSIZE IL:_ SIZE + IL:FONTFACE IL:_ FACE + IL:|\\SFAscent| IL:_ 0 + IL:|\\SFDescent| IL:_ 0 + IL:|\\SFHeight| IL:_ 0 + IL:ROTATION IL:_ ROTATION + IL:FONTDEVICESPEC IL:_ (LIST FAMILY SIZE FACE ROTATION + DEV))) + (SETQ CHARSETS (LOOP :FOR CS :IN GBCS :WITH CSET :WITH CSINFO :NCONC + (WHEN (<= 0 (SETQ CSET (FIRST CS)) + MAXCHARSET) + (SETQ CSINFO (BDF-TO-CHARSETINFO + GBCS CSET (OR SLUG (1+ + SLUGWIDTH + )))) + (IL:\\INSTALLCHARSETINFO FONTDESC CSINFO CSET + ) + (LIST CSET))))) + (LIST FONTDESC CHARSETS)))) + (RETURN (VALUES-LIST (NCONC (GBCS-TO-FONTDESC (FIRST GBCSL) + FAMILY) + (GBCS-TO-FONTDESC (SECOND GBCSL) + (IL:\\FONTSYMBOL (CONCATENATE 'STRING + (SYMBOL-NAME FAMILY) + "-UNMAPPED"))) + (LIST (ASSOC NOMAPPINGCHARSET (FIRST GBCSL) + :TEST + #'EQL))))))))) + +(DEFUN GET-FAMILY-FACE-SIZE-FROM-NAME (BDFONT) (IL:* IL:\; "Edited 30-Apr-2025 13:18 by mth") + (IL:* IL:\; "Edited 23-Apr-2025 16:20 by mth") + (IL:* IL:\; "Edited 5-Feb-2025 12:56 by mth") + (UNLESS (TYPEP BDFONT 'BDF-FONT) + (ERROR "Not a BDF-FONT: ~S~%" BDFONT)) + (DESTRUCTURING-BIND (FOUNDRY FAMILY WEIGHT SLANT EXPANSION ADD_STYLE_NAME + PIXEL-SIZE POINT-SIZE) + (SPLIT-FONT-NAME (BF-NAME BDFONT)) (IL:* IL:\; "Parse as XLFD format") + (DECLARE (IGNORE FOUNDRY ADD_STYLE_NAME)) (IL:* IL:\; + "Don't need FOUNDRY or ADD_STYLE_NAME") + (SETQ FAMILY (REMOVE #\Space FAMILY :TEST #'CHAR=)) + (SETQ WEIGHT (OR (AND WEIGHT (CDR (ASSOC (CHAR-UPCASE (ELT WEIGHT 0)) + '((#\R . MEDIUM) + (#\M . MEDIUM) + (#\N . MEDIUM) + (#\B . BOLD) + (#\D . BOLD) + (#\L . LIGHT))))) + 'MEDIUM)) (IL:* IL:\; "DemiBold => BOLD") + (SETQ SLANT (OR (AND SLANT (CDR (ASSOC (CHAR-UPCASE (ELT SLANT 0)) + '((REGULAR) + (#\R . REGULAR) + (#\I . ITALIC) + (#\O . ITALIC))))) + 'REGULAR)) (IL:* IL:\; "Oblique => ITALIC") + (IL:* IL:\; "Ignore others") + (SETQ EXPANSION (OR (AND EXPANSION (CDR (ASSOC (CHAR-UPCASE (ELT EXPANSION 0)) + '((#\R . REGULAR) + (#\N . REGULAR) + (#\B . BOLD) + (#\S . COMPRESSED) + (#\C . COMPRESSED))))) + 'REGULAR)) (IL:* IL:\; + "S is for \"SemiCondensed\", Assuming \"Condensed\"") + + (IL:* IL:|;;| + "Now check for WEIGHT and EXPANSION both BOLD. If so, change Expansion to REGULAR") + + (WHEN (AND (EQ WEIGHT EXPANSION) + (EQ EXPANSION 'BOLD)) + (SETQ EXPANSION 'REGULAR)) + (WHEN (ZEROP (LENGTH PIXEL-SIZE)) + (SETQ PIXEL-SIZE NIL)) + (SETQ POINT-SIZE (COND + ((ZEROP (LENGTH POINT-SIZE)) + NIL) + ((SETQ POINT-SIZE (PARSE-INTEGER POINT-SIZE :JUNK-ALLOWED T)) + (CEILING POINT-SIZE 10)) + (T NIL))) + (LIST FAMILY (LIST WEIGHT SLANT EXPANSION) + (OR (AND PIXEL-SIZE (PARSE-INTEGER PIXEL-SIZE :JUNK-ALLOWED T)) + POINT-SIZE + (FIRST (BF-SIZE BDFONT)))))) + +(DEFUN GLYPHS-BY-CHARSET (FONT &OPTIONAL MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING) + (IL:* IL:\; "Edited 6-Nov-2025 18:11 by mth") + (IL:* IL:\; "Edited 5-Nov-2025 16:18 by mth") + (IL:* IL:\; "Edited 21-Apr-2025 15:48 by mth") + (IL:* IL:\; "Edited 9-Jan-2025 11:23 by mth") + (LET* ((NCSETS (+ MAXCHARSET 2)) + (CSETS (MAKE-ARRAY NCSETS :INITIAL-CONTENTS (LOOP :REPEAT NCSETS :COLLECT (CONS NIL)))) + (UTOMFN (COND + (RAW-UNICODE-MAPPING #'IDENTITY) + (MAP-UNKNOWN-TO-PRIVATE #'UTOMCODE) + (T #'UTOMCODE?))) + (SLUG (BF-SLUG FONT)) + (SLUGWIDTH (AND SLUG (GLYPH-WIDTH SLUG))) + NOMAPPINGCSETS ENC MCODE MCS) + (UNLESS (OR MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING) + (SETQ NOMAPPINGCSETS (MAKE-ARRAY NCSETS :INITIAL-CONTENTS (LOOP :REPEAT NCSETS :COLLECT + (CONS NIL))))) + (FLET ((PUT-GLYPH-IN-CHARSET-ARRAY (CODE GLYPH CSARRAY) + (TCONC (AREF CSARRAY (LRSH CODE 8)) + (CONS (LOGAND CODE 255) + GLYPH)))) + (LOOP :FOR GL :IN (BF-GLYPHS FONT) + :UNLESS + (EQ GL SLUG) + :DO + (SETQ MCS NIL) + (SETQ ENC (GLYPH-ENCODING GL)) + (WHEN (LISTP ENC) + + (IL:* IL:|;;| + "Should happen only if -1 is first on ENCODING line in BDF file") + + (SETQ ENC (OR (SECOND ENC) + -1)) + + (IL:* IL:|;;| + "The -1 case of the (OR ...) shouldn't happen. The (EQ GL SLUG) test above should have caught it") + + ) + (SETQ MCODE (AND (INTEGERP ENC) + (PLUSP ENC) + (FUNCALL UTOMFN ENC))) + (IF RAW-UNICODE-MAPPING + (COND + ((> ENC 65535) + (WARN "~&Unicode encoding is beyond 16 bits: ~5X" ENC) + (TCONC (AREF CSETS NOMAPPINGCHARSET) + (CONS ENC GL))) + ((AND NIL (= 255 (LOGAND ENC 255))) + + (IL:* IL:|;;| + "Temporarily? disable this warning in RAW-UNICODE-MAPPING mode") + + (WARN + "~&Unicode encoding char byte (~2X,FF)=(~O,377) may not =FF in FONTDESCRIPTOR" + (LRSH ENC 8) + (LRSH ENC 8)) + (TCONC (AREF CSETS NOMAPPINGCHARSET) + (CONS ENC GL))) + (T (PUT-GLYPH-IN-CHARSET-ARRAY ENC GL CSETS))) + (COND + ((AND (ZEROP (GLYPH-BBW GL)) + (ZEROP (FIRST (GLYPH-DWIDTH GL)))) + + (IL:* IL:|;;| + "This has zero-width \"image\" with zero-width \"escapement\", put it in the NOMAPPINGCHARSET") + + (TCONC (AREF CSETS NOMAPPINGCHARSET) + (CONS ENC GL))) + ((NULL MCODE) + + (IL:* IL:|;;| "These assoc with the Unicode encoding") + + (COND + ((OR (> ENC 65535) + (= 255 (LOGAND ENC 255))) + + (IL:* IL:|;;| + "Unicode encoding is > xFFFF, or encoding low byte is FF, put it in the NOMAPPINGCHARSET") + + (TCONC (AREF CSETS NOMAPPINGCHARSET) + (CONS ENC GL))) + (T (PUT-GLYPH-IN-CHARSET-ARRAY ENC GL NOMAPPINGCSETS)))) + ((AND (INTEGERP MCODE) + (<= 0 MCODE 65535)) + + (IL:* IL:|;;| + "These assoc with the 8 bit character code within the charset") + + (PUT-GLYPH-IN-CHARSET-ARRAY MCODE GL CSETS) + + (IL:* IL:|;;| "Default SLUG width is width of A.") + + (WHEN (AND (NOT SLUGWIDTH) + (= ENC (CHAR-CODE #\A))) + + (IL:* IL:|;;| "A is the same code in MCCS and UNICODE ") + + (IL:* IL:|;;| + "Comparing with ENC, not MCODE, to look only in charset 0") + + (SETQ SLUGWIDTH (GLYPH-WIDTH GL)))) + ((LISTP MCODE) + + (IL:* IL:|;;| + "These assoc with the 8 bit character code within the charset (like above)") + + (LOOP :FOR MC :IN MCODE :WITH CS :UNLESS (MEMBER (SETQ CS + (LRSH MC 8)) + MCS) + :DO + (PUSH CS MCS) + (PUT-GLYPH-IN-CHARSET-ARRAY MC GL CSETS))) + (T (ERROR "Invalid MCODE: ~A~%")))))) + + (IL:* IL:|;;| "Extract the lists from the TCONC pointers") + + (LOOP :FOR I :FROM 0 :TO NOMAPPINGCHARSET :DO (SETF (AREF CSETS I) + (SORT (REMOVE-DUPLICATES + (CAR (AREF CSETS I)) + :TEST + #'EQUAL) + #'< :KEY #'CAR))) + (SETQ CSETS (LOOP :FOR I :FROM 0 :TO NOMAPPINGCHARSET :NCONC + (LET ((CS (AREF CSETS I))) + (WHEN CS + (LIST (LIST I CS)))))) + + (IL:* IL:|;;| "Likewise for the NOMAPPINGCSETS, if any.") + + (WHEN NOMAPPINGCSETS + (LOOP :FOR I :FROM 0 :TO NOMAPPINGCHARSET :DO + (SETF (AREF NOMAPPINGCSETS I) + (SORT (REMOVE-DUPLICATES (CAR (AREF NOMAPPINGCSETS I)) + :TEST + #'EQUAL) + #'< :KEY #'CAR))) + (SETQ NOMAPPINGCSETS (LOOP :FOR I :FROM 0 :TO NOMAPPINGCHARSET :NCONC + (LET ((CS (AREF NOMAPPINGCSETS I))) + (WHEN CS + (LIST (LIST I CS))))))) + (LIST CSETS NOMAPPINGCSETS SLUGWIDTH))) + +(DEFMACRO PACKFILENAME.STRING (&WHOLE WHOLE) (IL:* IL:\; "Edited 1-Feb-2025 23:17 by mth") + `(IL:PACKFILENAME.STRING ,@(LOOP :FOR X :IN (CDR WHOLE) + :BY + #'CDDR :AS Y :IN (CDDR WHOLE) + :BY + #'CDDR :NCONC (LIST (COND + ((KEYWORDP X) + (LIST 'QUOTE (INTERN (STRING X) + "IL"))) + ((AND (LISTP X) + (EQ (FIRST X) + 'QUOTE) + (SYMBOLP (CADR X))) + (LIST 'QUOTE (INTERN (STRING (CADR X)) + "IL"))) + (T + (IL:* IL:\; "Hope for the best!") + X)) + Y)))) + +(DEFUN READ-BDF (PATH &OPTIONAL VERBOSE) (IL:* IL:\; "Edited 30-Apr-2025 13:37 by mth") + (IL:* IL:\; "Edited 24-Apr-2025 00:44 by mth") + (IL:* IL:\; "Edited 17-Apr-2025 15:10 by mth") + (IL:* IL:\; "Edited 12-Jul-2024 23:02 by mth") + (LET + (PROPS PROPS-COMPLETE CHARS-COUNT FONT-COMPLETE FONT POS KEY V VV LINE ITEMS GL (NGLYPHS 0) + (*PACKAGE* (FIND-PACKAGE "BDF"))) + (WITH-OPEN-FILE + (FILE-STREAM PATH :ELEMENT-TYPE 'CHARACTER :DIRECTION :INPUT) + (LOOP :WHILE (STRING-EQUAL "COMMENT" (SETQ KEY (READ FILE-STREAM))) + :DO + + (IL:* IL:|;;| "Ignore initial COMMENT lines.") + + (READ-LINE FILE-STREAM)) + (UNLESS (STRING-EQUAL "STARTFONT" KEY) + (ERROR "Invalid BDF file - must begin with STARTFONT.")) + + (IL:* IL:|;;| "ignore the file format version number") + + (READ-LINE FILE-STREAM) + (SETQ FONT (MAKE-BDF-FONT)) + (LOOP + :UNTIL FONT-COMPLETE :DO (SETQ LINE (READ-LINE FILE-STREAM)) + (WHEN LINE (IL:* IL:\; "Ignore blank lines") + (MULTIPLE-VALUE-SETQ (KEY POS) + (READ-FROM-STRING LINE)) + (UNLESS (MEMBER KEY '(COMMENT CONTENTVERSION)) + (WHEN (<= POS (LENGTH LINE)) + (SETQ LINE (SUBSEQ LINE POS))) + (COND + ((EQ KEY 'FONT) + (SETF (BF-NAME FONT) + LINE)) + (T + (SETQ ITEMS (READ-DELIMITED-LIST-FROM-STRING LINE)) + (CASE KEY + (METRICSSET (IF (AND (INTEGERP (SETQ V (FIRST ITEMS))) + (<= 0 V 2)) + (SETF (BF-METRICSSET FONT) + V) + (ERROR + "Invalid BDF file - METRICSSET (~A) is invalid or out of range." + V))) + (SIZE (SETF (BF-SIZE FONT) + ITEMS)) + (FONTBOUNDINGBOX (SETF (BF-BOUNDINGBOX FONT) + ITEMS)) + (SWIDTH (SETF (BF-SWIDTH FONT) + ITEMS)) + (DWIDTH (SETF (BF-DWIDTH FONT) + ITEMS)) + (SWIDTH1 (SETF (BF-SWIDTH1 FONT) + ITEMS)) + (DWIDTH1 (SETF (BF-DWIDTH1 FONT) + ITEMS)) + (VVECTOR (SETF (BF-VVECTOR FONT) + ITEMS)) + (STARTPROPERTIES + (IF (AND (INTEGERP (SETQ V (FIRST ITEMS))) + (PLUSP V)) + (SETQ PROPS + (LOOP :UNTIL PROPS-COMPLETE :APPEND + (WITH-INPUT-FROM-STRING + (SI (SETQ LINE (READ-LINE FILE-STREAM))) + + (IL:* IL:|;;| "As of now, COMMENTS not allowed here.") + + (UNLESS (SETQ PROPS-COMPLETE + (STRING-EQUAL "ENDPROPERTIES" + (STRING-TRIM '(#\Space #\Tab) + LINE))) + (SETQ KEY (READ SI)) + (IF (AND KEY (SYMBOLP KEY) + (SETQ VV (READ SI)) + (OR (STRINGP VV) + (INTEGERP VV))) + (LIST (INTERN (STRING KEY) + "KEYWORD") + VV) + (ERROR + "Invalid BDF file - malformed PROPERTY (~A)." + LINE)))))) + (ERROR + "Invalid BDF file - STARTPROPERTIES count (~A) is invalid or missing." + V)) + (IF (EQL V (SETQ VV (/ (LENGTH PROPS) + 2))) + (SETF (BF-PROPERTIES FONT) + PROPS) + (ERROR + "Invalid BDF file - STARTPROPERTIES count (~D) does not match actual (~D)." + V VV))) + (CHARS + (SETQ NGLYPHS (FIRST ITEMS)) + (UNLESS (AND NGLYPHS (INTEGERP NGLYPHS) + (PLUSP NGLYPHS)) + (ERROR "Invalid BDF file - CHARS count (~A) is invalid or missing." + NGLYPHS)) + (SETF (BF-GLYPHS FONT) + (LOOP :REPEAT NGLYPHS :COLLECT + (PROG1 (SETQ GL (READ-GLYPH FILE-STREAM FONT)) + + (IL:* IL:|;;| + "Any GLYPH with ENCODING of -1 is taken as the SLUG glyph. If multiple, the last applies.") + + (SETQ V (GLYPH-ENCODING GL)) + (WHEN (AND (LISTP V) + (EQ (FIRST V) + -1)) + (SETQ V (OR (SECOND V) + -1))) + (WHEN (EQ V -1) + (SETF (BF-SLUG FONT) + GL)))))) + (ENDFONT (SETQ FONT-COMPLETE T)))))))) + (DESTRUCTURING-BIND (FAMILY (WEIGHT SLANT EXPANSION) + SIZE) + (GET-FAMILY-FACE-SIZE-FROM-NAME FONT) + (WHEN VERBOSE + (FORMAT *STANDARD-OUTPUT* + "Name: ~A~%Family: ~A~%Size: ~A~%Weight: ~A~%Slant: ~A~%Expansion: ~A~%" + (BF-NAME FONT) + FAMILY SIZE WEIGHT SLANT EXPANSION)) + (VALUES FONT FAMILY WEIGHT SLANT EXPANSION SIZE))))) + +(DEFUN READ-DELIMITED-LIST-FROM-STRING (INPUT-STRING &OPTIONAL (DELIMIT #\])) + (IL:* IL:\; "Edited 20-Aug-2024 16:46 by mth") + (WITH-INPUT-FROM-STRING (SI (CONCATENATE 'STRING INPUT-STRING " " (STRING DELIMIT))) + (READ-DELIMITED-LIST DELIMIT SI))) + +(DEFUN READ-GLYPH (FILE-STREAM FONT) (IL:* IL:\; "Edited 23-Apr-2025 17:53 by mth") + (IL:* IL:\; "Edited 21-Apr-2025 13:37 by mth") + (IL:* IL:\; "Edited 19-Apr-2025 09:32 by mth") + (IL:* IL:\; "Edited 17-Apr-2025 18:14 by mth") + (IL:* IL:\; "Edited 21-Aug-2024 01:10 by mth") + (LET ((GLYPH (MAKE-GLYPH :SWIDTH (COPY-LIST (BF-SWIDTH FONT)) + :DWIDTH + (COPY-LIST (BF-DWIDTH FONT)) + :SWIDTH1 + (COPY-LIST (BF-SWIDTH1 FONT)) + :DWIDTH1 + (COPY-LIST (BF-DWIDTH1 FONT)) + :VVECTOR + (COPY-LIST (BF-VVECTOR FONT)))) + CHAR-COMPLETE LINE ITEMS V KEY POS STARTED BBW BBH) + (LOOP :UNTIL CHAR-COMPLETE :DO (SETQ LINE (READ-LINE FILE-STREAM)) + (WHEN LINE (IL:* IL:\; "Ignore blank lines") + (MULTIPLE-VALUE-SETQ (KEY POS) + (READ-FROM-STRING LINE)) + (WHEN (<= POS (LENGTH LINE)) + (SETQ LINE (SUBSEQ LINE POS))) + (COND + ((EQ KEY 'COMMENT) (IL:* IL:\; "Ignore COMMENT lines") + (IL:* IL:\; + "Probably aren't \"legal\" here, anyway.") + ) + ((EQ KEY 'STARTCHAR) + (WHEN STARTED (ERROR "Invalid BDF file - STARTCHAR inside glyph.")) + (SETF STARTED T) + (SETF (GLYPH-NAME GLYPH) + (STRING LINE))) + (T (UNLESS STARTED (ERROR + "Invalid BDF file - glyph has not been started. STARTCHAR missing." + )) + (SETQ ITEMS (READ-DELIMITED-LIST-FROM-STRING LINE)) + (CASE KEY + (ENCODING (SETF (GLYPH-ENCODING GLYPH) + (IF (EQUAL -1 (FIRST ITEMS)) + ITEMS + (FIRST ITEMS)))) + (SWIDTH (SETF (GLYPH-SWIDTH GLYPH) + ITEMS)) + (DWIDTH (SETF (GLYPH-DWIDTH GLYPH) + ITEMS)) + (SWIDTH1 (SETF (GLYPH-SWIDTH1 GLYPH) + ITEMS)) + (DWIDTH1 (SETF (GLYPH-DWIDTH1 GLYPH) + ITEMS)) + (VVECTOR (SETF (GLYPH-VVECTOR GLYPH) + ITEMS)) + (BBX (SETF (GLYPH-BBW GLYPH) + (SETQ BBW (FIRST ITEMS)) + (GLYPH-BBH GLYPH) + (SETQ BBH (SECOND ITEMS)) + (GLYPH-BBXOFF0 GLYPH) + (THIRD ITEMS) + (GLYPH-BBYOFF0 GLYPH) + (FOURTH ITEMS))) + (BITMAP (LET* ((BM (BITMAPCREATE BBW BBH 1)) + (BM.BASE (IL:|fetch| IL:BITMAPBASE IL:|of| BM)) + (BM.RASTERWIDTH (IL:|fetch| IL:BITMAPRASTERWIDTH + IL:|of| BM)) + (NBYTES (CEILING BBW 8)) + (NCHARS (* 2 NBYTES)) + (NWORDS (CEILING BBW 16)) + BITS BYTEPOS WORDINDEX) + (LOOP :WITH BITROW = 0 :REPEAT BBH :DO + (SETQ LINE (STRING-TRIM '(#\Space #\Tab) + (READ-LINE FILE-STREAM))) + (UNLESS (AND (EQUAL NCHARS (LENGTH LINE)) + (SETQ BITS + (PARSE-INTEGER LINE :RADIX 16 + :JUNK-ALLOWED T))) + (ERROR + "Invalid BDF file - bad line in BITMAP: ~A" + LINE)) + (WHEN (ODDP NBYTES) + (SETQ BITS (ASH BITS 8))) + (SETQ WORDINDEX (* BITROW BM.RASTERWIDTH)) + (SETQ BYTEPOS (* 16 (1- NWORDS))) + (LOOP :REPEAT NWORDS :DO + (IL:\\PUTBASE BM.BASE WORDINDEX + (LDB (BYTE 16 BYTEPOS) + BITS)) + (INCF WORDINDEX) + (DECF BYTEPOS 16)) + (INCF BITROW)) + (SETF (GLYPH-BITMAP GLYPH) + BM))) + (ENDCHAR (SETQ CHAR-COMPLETE T))))))) + (SETF (GLYPH-ASCENT GLYPH) + (+ (GLYPH-BBH GLYPH) + (GLYPH-BBYOFF0 GLYPH))) + (SETF (GLYPH-DESCENT GLYPH) + (ABS (MIN 0 (GLYPH-BBYOFF0 GLYPH)))) + (SETF (GLYPH-WIDTH GLYPH) + (MAX (+ (MAX 0 (GLYPH-BBXOFF0 GLYPH)) + (GLYPH-BBW GLYPH)) + (FIRST (GLYPH-DWIDTH GLYPH)))) + GLYPH)) + +(DEFUN SPLIT-FONT-NAME (NAME) (IL:* IL:\; "Edited 23-Apr-2025 16:22 by mth") + (IL:* IL:\; "Edited 31-Jan-2025 22:20 by mth") + + (IL:* IL:|;;| "First, check if it COULD be in XLFD format") + + (COND + ((POSITION #\- NAME :TEST #'CHAR=) + (LOOP :FOR I = (IF (CHAR= #\- (ELT NAME 0)) + 1 + 0) + THEN + (1+ J) + :AS J = (POSITION #\- NAME :START I :TEST #'CHAR=) + :COLLECT + (SUBSEQ NAME I J) + :WHILE J)) + (T + (IL:* IL:|;;| "Return the NAME as FAMILY with a NIL FOUNDRY") + + (LIST NIL NAME)))) + +(DEFUN WRITE-BDF-TO-DISPLAYFONT-FILES (BDFONT DEST-DIR &KEY FAMILY SIZE FACE ROTATION DEVICE + (CHAR-SETS T) + MAP-UNKNOWN-TO-PRIVATE WRITE-UNMAPPED + RAW-UNICODE-MAPPING) + (IL:* IL:\; "Edited 5-Nov-2025 23:06 by mth") + (IL:* IL:\; "Edited 25-Apr-2025 10:08 by mth") + (IL:* IL:\; "Edited 24-Apr-2025 00:09 by mth") + (IL:* IL:\; "Edited 21-Apr-2025 16:03 by mth") + (IL:* IL:\; "Edited 3-Feb-2025 23:18 by mth") + (UNLESS (TYPEP BDFONT 'BDF-FONT) + (ERROR "Not a BDF-FONT: ~S ~%" BDFONT)) + (COND + ((EQ CHAR-SETS T) (IL:* IL:\; "This means ALL charsets") + ) + ((NULL CHAR-SETS) + (SETQ CHAR-SETS '(0)) (IL:* IL:\; "Only charset 0") + ) + ((AND (INTEGERP CHAR-SETS) + (<= 0 CHAR-SETS MAXCHARSET)) (IL:* IL:\; "A single integer charset") + (SETQ CHAR-SETS (LIST CHAR-SETS))) + ((AND (LISTP CHAR-SETS) + (EVERY #'(LAMBDA (CS) + (AND (INTEGERP CS) + (<= 0 CS MAXCHARSET))) + CHAR-SETS))) + (T (ERROR "Invalid specification of :CHAR-SETS ~S~%" CHAR-SETS))) + (DESTRUCTURING-BIND (FN-FAMILY FN-FACE FN-SIZE) + (GET-FAMILY-FACE-SIZE-FROM-NAME BDFONT) + (SETQ FAMILY (OR FAMILY FN-FAMILY)) + (WHEN RAW-UNICODE-MAPPING + (SETQ FAMILY (IL:\\FONTSYMBOL (CONCATENATE 'STRING "RAW-" (STRING FAMILY))))) + (SETQ FACE (OR FACE FN-FACE)) + (SETQ SIZE (OR SIZE FN-SIZE)) + (MULTIPLE-VALUE-BIND (FONTDESC CSETS UNMAPPED-FONTDESC UNICODE-CSETS UNMAPPEDGLYPHS) + (BDF-TO-FONTDESCRIPTOR BDFONT FAMILY SIZE FACE ROTATION DEVICE + MAP-UNKNOWN-TO-PRIVATE RAW-UNICODE-MAPPING) + (UNLESS (EQ CHAR-SETS T) + (SETQ CSETS (INTERSECTION CHAR-SETS CSETS)) + (SETQ UNICODE-CSETS (INTERSECTION CHAR-SETS UNICODE-CSETS))) + (LOOP :FOR CS :IN CSETS :DO (WRITESTRIKEFONTFILE FONTDESC CS + (PACKFILENAME.STRING :BODY DEST-DIR :NAME + (IL:\\FONTFILENAME FAMILY SIZE FACE + "DISPLAYFONT" CS)))) + (IF WRITE-UNMAPPED + (LOOP :FOR CS :IN UNICODE-CSETS :DO (WRITESTRIKEFONTFILE + UNMAPPED-FONTDESC CS + (PACKFILENAME.STRING + :BODY DEST-DIR :NAME + (IL:\\FONTFILENAME (FONTPROP + UNMAPPED-FONTDESC + 'IL:FAMILY) + SIZE FACE "DISPLAYFONT" CS)))) + (SETQ UNICODE-CSETS NIL)) + + (IL:* IL:|;;| "These correspond to the charsets ACTUALLY written.") + + (IL:* IL:|;;| + "UNMAPPEDGLYPHS are never written. (Unicode encoding is > xFFFF, or encoding low byte is FF)") + + (VALUES FONTDESC CSETS UNMAPPED-FONTDESC UNICODE-CSETS UNMAPPEDGLYPHS)))) +(IL:DECLARE\: IL:EVAL@COMPILE IL:DONTCOPY + +(IL:FILESLOAD (IL:SYSLOAD) + IL:SYSEDIT) + + +(IL:FILESLOAD (IL:LOADCOMP) + IL:FONT) +) + +(DEFINE-FILE-ENVIRONMENT "READ-BDF" :PACKAGE (DEFPACKAGE "BDF" (:USE "XCL" "LISP") + (:EXPORT "READ-BDF" + "WRITE-BDF-TO-DISPLAYFONT-FILES") + (:IMPORT-FROM "IL" "BITBLT" "BITMAPCREATE" + "BITMAPHEIGHT" "BITMAPWIDTH" "BLACKSHADE" + "BLTSHADE" "BOLD" "COMPRESSED" + "CHARSETINFO" "DISPLAY" "FONTDESCRIPTOR" + "FONTP" "FONTPROP" "INPUT" "ITALIC" + "LIGHT" "LRSH" "MEDIUM" "REGULAR" "TCONC" + "UTOMCODE" "UTOMCODE?" + "WRITESTRIKEFONTFILE")) + :READTABLE "XCL" + :COMPILER :COMPILE-FILE) + +(IL:PUTPROPS IL:READ-BDF IL:DATABASE IL:NO) +(IL:DECLARE\: IL:DONTCOPY + (IL:FILEMAP (NIL (2497 10576 (BDF-TO-CHARSETINFO 2497 . 10576)) (10578 16996 (BDF-TO-FONTDESCRIPTOR +10578 . 16996)) (16998 20538 (GET-FAMILY-FACE-SIZE-FROM-NAME 16998 . 20538)) (20540 27970 ( +GLYPHS-BY-CHARSET 20540 . 27970)) (27972 29397 (PACKFILENAME.STRING 27972 . 29397)) (29399 36358 ( +READ-BDF 29399 . 36358)) (36360 36683 (READ-DELIMITED-LIST-FROM-STRING 36360 . 36683)) (36685 43176 ( +READ-GLYPH 36685 . 43176)) (43178 43919 (SPLIT-FONT-NAME 43178 . 43919)) (43921 47827 ( +WRITE-BDF-TO-DISPLAYFONT-FILES 43921 . 47827))))) +IL:STOP diff --git a/obsolete/lispusers/READ-BDF-old/READ-BDF.DFASL b/obsolete/lispusers/READ-BDF-old/READ-BDF.DFASL new file mode 100644 index 0000000000000000000000000000000000000000..927778eaf9838aafa5ba0d1b7cc9d57d42e6156d GIT binary patch literal 21485 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 Saf3MktQIpAJ{269pZ~w)MlIO@ literal 0 HcmV?d00001 diff --git a/obsolete/lispusers/READ-BDF-old/READ-BDF.TEDIT b/obsolete/lispusers/READ-BDF-old/READ-BDF.TEDIT new file mode 100644 index 0000000000000000000000000000000000000000..891c14cc161b6a178923a02d5d7af4e2a55e0467 GIT binary patch literal 9819 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 literal 0 HcmV?d00001