summaryrefslogtreecommitdiff
path: root/Build/source/texk/ttf2pk2/ligkern.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/ttf2pk2/ligkern.c')
-rw-r--r--Build/source/texk/ttf2pk2/ligkern.c275
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 */