diff options
Diffstat (limited to 'Build/source/texk/ttf2pk2/ligkern.c')
-rw-r--r-- | Build/source/texk/ttf2pk2/ligkern.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/Build/source/texk/ttf2pk2/ligkern.c b/Build/source/texk/ttf2pk2/ligkern.c new file mode 100644 index 00000000000..98f889f7c8b --- /dev/null +++ b/Build/source/texk/ttf2pk2/ligkern.c @@ -0,0 +1,275 @@ +/* + * ligkern.c + * + * This file is part of the ttf2pk package. + * + * Copyright 1997-1999, 2000 by + * Frederic Loyer <loyer@ensta.fr> + * Werner Lemberg <wl@gnu.org> + */ + +#include <string.h> +#include <stdlib.h> +#include <stddef.h> /* for size_t */ +#include <ctype.h> + +#include "ttf2tfm.h" +#include "ligkern.h" +#include "ttfenc.h" +#include "texenc.h" +#include "newobj.h" +#include "errormsg.h" + + +static char * +paramstring(char **curp) +{ + register char *p, *q; + + + p = *curp; + while (*p && !isspace(*p)) + p++; + q = *curp; + if (*p != '\0') + *p++ = '\0'; + while (isspace(*p)) + p++; + *curp = p; + return q; +} + + +/* + * Some routines to remove kerns that match certain patterns. + */ + +static kern * +rmkernmatch(kern *k, + char *s) +{ + kern *nk; + + + while (k && strcmp(k->succ, s) == 0) + k = k->next; + + if (k) + { + for (nk = k; nk; nk = nk->next) + while (nk->next && strcmp(nk->next->succ, s) == 0) + nk->next = nk->next->next; + } + return k; +} + + +/* + * Recursive to one level. + */ + +static void +rmkern(char *s1, char *s2, + ttfinfo *ti, + Font *fnt) +{ + if (ti == NULL) + { + if (strcmp(s1, "*") == 0) + { + for (ti = fnt->charlist; ti; ti = ti->next) + rmkern(s1, s2, ti, fnt); + return; + } + else + { + ti = findadobe(s1, fnt->charlist); + if (ti == NULL) + return; + } + } + + if (strcmp(s2, "*") == 0) + ti->kerns = NULL; /* drop them on the floor */ + else + ti->kerns = rmkernmatch(ti->kerns, s2); +} + + +/* + * Make the kerning for character S1 equivalent to that for S2. + * If either S1 or S2 do not exist, do nothing. + * If S1 already has kerning, do nothing. + */ + +static void +addkern(char *s1, char *s2, + Font *fnt) +{ + ttfinfo *ti1 = findadobe(s1, fnt->charlist); + ttfinfo *ti2 = findadobe(s2, fnt->charlist); + + + if (ti1 && ti2 && !ti1->kerns) + { + /* Put the new one at the head of the list, since order is immaterial. */ + ttfptr *ap = (ttfptr *)mymalloc(sizeof (ttfptr)); + + + ap->next = ti2->kern_equivs; + ap->ch = ti1; + ti2->kern_equivs = ap; + } +} + + +/* + * Reads a ligkern line, if this is one. Assumes the first character + * passed is `%'. + */ + +void +checkligkern(char *s, Font *fnt) +{ + char *mlist[5]; + char *os; + char *orig_s, *pos; + size_t offset[5]; + int n; + + + os = newstring(s); + orig_s = s; + + s++; + while (isspace(*s)) + s++; + if (strncmp(s, "LIGKERN", 7) == 0) + { + fnt->sawligkern = True; + s += 7; + while (isspace(*s)) + s++; + pos = s; + while (*pos) + { + for (n = 0; n < 5;) + { + if (*pos == '\0') + break; + offset[n] = pos - orig_s; + mlist[n] = paramstring(&pos); + if (strcmp(mlist[n], ";") == 0) + break; + n++; + } + + if (n > 4) + boops(os, pos - orig_s, "Too many parameters in lig kern data."); + if (n < 3) + boops(os, pos - orig_s, "Too few parameters in lig kern data."); + + if (n == 3 && strcmp(mlist[1], "{}") == 0) /* rmkern command */ + rmkern(mlist[0], mlist[2], (ttfinfo *)0, fnt); + else if (n == 3 && strcmp(mlist[1], "<>") == 0) /* addkern */ + addkern(mlist[0], mlist[2], fnt); + else if (n == 3 && strcmp(mlist[0], "||") == 0 && + strcmp(mlist[1], "=") == 0) /* bc command */ + { + ttfinfo *ti = findadobe("||", fnt->charlist); + + + if (fnt->boundarychar != -1) + boops(os, offset[0], "Multiple boundary character commands?"); + if (sscanf(mlist[2], "%d", &n) != 1) + boops(os, offset[2], + "Expected number assignment for boundary char."); + if (n < 0 || n > 0xFF) + boops(os, offset[2], "Boundary character number must be 0..0xFF."); + + fnt->boundarychar = n; + if (ti == NULL) + oops("Internal error: boundary char."); + ti->outcode = n; /* prime the pump, so to speak, for lig/kerns */ + } + else if (n == 4) + { + int op = -1; + ttfinfo *ti; + + + for (n = 0; encligops[n]; n++) + if (strcmp(mlist[2], encligops[n]) == 0) + { + op = n; + break; + } + if (op < 0) + boops(os, offset[2], "Bad ligature op specified."); + + if (NULL != (ti = findadobe(mlist[0], fnt->charlist))) + { + lig *lig; + + + if (findadobe(mlist[2], fnt->charlist)) + /* remove coincident kerns */ + rmkern(mlist[0], mlist[1], ti, fnt); + + if (strcmp(mlist[3], "||") == 0) + boops(os, offset[3], "You can't lig to the boundary character!"); + + if (!fnt->fixedpitch) /* fixed pitch fonts get *0* ligs */ + { + for (lig = ti->ligs; lig; lig = lig->next) + if (strcmp(lig->succ, mlist[1]) == 0) + break; /* we'll re-use this structure */ + + if (lig == NULL) + { + lig = newlig(); + lig->succ = newstring(mlist[1]); + lig->next = ti->ligs; + ti->ligs = lig; + } + lig->sub = newstring(mlist[3]); + lig->op = op; + + if (strcmp(mlist[1], "||") == 0) + { + lig->boundleft = 1; + if (strcmp(mlist[0], "||") == 0) + boops(os, offset[0], + "You can't lig boundarychar boundarychar!"); + } + else + lig->boundleft = 0; + } + } + } + else + boops(os, offset[0], "Bad form in LIGKERN command."); + } + } + + free(os); +} + + +void +getligkerndefaults(Font *fnt) +{ + int i; + char *buffer; + + + for (i = 0; staticligkern[i]; i++) + { + buffer = newstring(staticligkern[i]); + checkligkern(buffer, fnt); + free(buffer); + } +} + + +/* end */ |