ref: 3b1dedaa9cfe9e5b78166054f829e4c36bb8e56e
parent: e6a27240e5bcb4d04ca08426f311c6fd7758989d
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sun Jun 23 12:45:35 EDT 2013
wb: pairwise kerning support The ".kn 1" enables pairwise kerning. Now the kernpairs section of font description file describes kerning pairs as "c1 c2 value", as groff does.
--- a/dev.c
+++ b/dev.c
@@ -154,7 +154,8 @@
return fn_font[n_f]->spacewid;
}
-int dev_font(char *id)
+/* return the mounted position of font */
+int dev_pos(char *id)
{
int i;
if (isdigit(id[0])) {
@@ -173,19 +174,14 @@
return dev_mnt(0, id, id);
}
-int charwid(int wid, int sz)
+/* return the font struct at pos */
+struct font *dev_font(int pos)
{
- /* the original troff rounds the widths up */
- return (wid * sz + dev_uwid / 2) / dev_uwid;
+ return pos >= 0 && pos < fn_n ? fn_font[pos] : NULL;
}
-/* return 1 if lig is a ligature in the font mounted at f */
-int dev_lig(int f, char *lig)
+int charwid(int wid, int sz)
{
- struct font *fn = fn_font[f];
- int i;
- for (i = 0; i < fn->nlig; i++)
- if (!strcmp(lig, fn->lig[i]))
- return font_find(fn, lig) != NULL;
- return 0;
+ /* the original troff rounds the widths up */
+ return (wid * sz + dev_uwid / 2) / dev_uwid;
}
--- a/font.c
+++ b/font.c
@@ -29,6 +29,8 @@
return NULL;
}
+static int font_section(struct font *fn, FILE *fin, char *name);
+
static void font_charset(struct font *fn, FILE *fin)
{
char tok[ILNLEN];
@@ -40,6 +42,8 @@
while (fn->n < NGLYPHS) {
if (fscanf(fin, "%s", name) != 1)
break;
+ if (!font_section(fn, fin, name))
+ break;
fscanf(fin, "%s", tok);
glyph = prev;
if (strcmp("\"", tok)) {
@@ -60,6 +64,57 @@
}
}
+static void font_kernpairs(struct font *fn, FILE *fin)
+{
+ char c1[ILNLEN], c2[ILNLEN];
+ int val;
+ while (fn->n < NGLYPHS) {
+ if (fscanf(fin, "%s", c1) != 1)
+ break;
+ if (!font_section(fn, fin, c1))
+ break;
+ if (fscanf(fin, "%s %d", c2, &val) != 2)
+ break;
+ strcpy(fn->kern_c1[fn->nkern], c1);
+ strcpy(fn->kern_c2[fn->nkern], c2);
+ fn->kern[fn->nkern] = val;
+ fn->nkern++;
+ }
+}
+
+static int font_section(struct font *fn, FILE *fin, char *name)
+{
+ if (!strcmp("charset", name)) {
+ font_charset(fn, fin);
+ return 0;
+ }
+ if (!strcmp("kernpairs", name)) {
+ font_kernpairs(fn, fin);
+ return 0;
+ }
+ return 1;
+}
+
+/* return 1 if lig is a ligature */
+int font_lig(struct font *fn, char *lig)
+{
+ int i;
+ for (i = 0; i < fn->nlig; i++)
+ if (!strcmp(lig, fn->lig[i]))
+ return font_find(fn, lig) != NULL;
+ return 0;
+}
+
+/* return pairwise kerning value between c1 and c2 */
+int font_kern(struct font *fn, char *c1, char *c2)
+{
+ int i;
+ for (i = 0; i < fn->nkern; i++)
+ if (!strcmp(fn->kern_c1[i], c1) && !strcmp(fn->kern_c2[i], c2))
+ return fn->kern[i];
+ return 0;
+}
+
struct font *font_open(char *path)
{
struct font *fn = malloc(sizeof(*fn));
@@ -102,10 +157,8 @@
skipline(fin);
continue;
}
- if (!strcmp("charset", tok)) {
- font_charset(fn, fin);
+ if (!font_section(fn, fin, tok))
break;
- }
}
fclose(fin);
return fn;
--- a/out.c
+++ b/out.c
@@ -215,7 +215,7 @@
out_draw(c);
break;
case 'f':
- out_ft(dev_font(c));
+ out_ft(dev_pos(c));
break;
case 'h':
outnn("h%d", eval(c, 'm'));
--- a/ren.c
+++ b/ren.c
@@ -433,7 +433,7 @@
static void ren_ft(char *s)
{
- int fn = !s || !*s || !strcmp("P", s) ? n_f0 : dev_font(s);
+ int fn = !s || !*s || !strcmp("P", s) ? n_f0 : dev_pos(s);
if (fn >= 0) {
n_f0 = n_f;
n_f = fn;
@@ -670,8 +670,11 @@
}
if (c[0] == c_ni)
nextchar(c + 1, next);
- if (!n_lg || wb_lig(wb, c))
+ if (!n_lg || wb_lig(wb, c)) {
+ if (n_kn)
+ wb_kern(wb, c);
wb_put(wb, c);
+ }
}
/* read the argument of \w and push its width */
--- a/roff.c
+++ b/roff.c
@@ -15,6 +15,7 @@
n_o = SC_IN;
n_p = SC_IN * 11;
n_lg = 1;
+ n_kn = 0;
}
static void compile(void)
--- a/roff.h
+++ b/roff.h
@@ -10,6 +10,7 @@
#define NFILES 16 /* number of input files */
#define NFONTS 32 /* number of fonts */
#define NLIGS 32 /* number of font ligatures */
+#define NKERNS 128 /* number of font pairwise kerning pairs */
#define FNLEN 32 /* font name length */
#define NGLYPHS 512 /* glyphs in fonts */
#define GNLEN 32 /* glyph name length */
@@ -94,7 +95,11 @@
struct glyph *g[NGLYPHS]; /* character glyphs in charset */
int n; /* number of characters in charset */
char lig[NLIGS][GNLEN * 4]; /* font ligatures */
- int nlig; /* number of font ligatures */
+ int nlig;
+ int kern[NKERNS]; /* font pairwise kerning */
+ char kern_c1[NKERNS][GNLEN];
+ char kern_c2[NKERNS][GNLEN];
+ int nkern;
};
/* output device functions */
@@ -101,9 +106,9 @@
int dev_open(char *path);
void dev_close(void);
int dev_mnt(int pos, char *id, char *name);
-int dev_font(char *id);
+int dev_pos(char *id);
+struct font *dev_font(int pos);
int charwid(int wid, int sz);
-int dev_lig(int f, char *c);
/* font-related functions */
struct font *font_open(char *path);
@@ -110,6 +115,8 @@
void font_close(struct font *fn);
struct glyph *font_glyph(struct font *fn, char *id);
struct glyph *font_find(struct font *fn, char *name);
+int font_lig(struct font *fn, char *c);
+int font_kern(struct font *fn, char *c1, char *c2);
/* glyph handling functions */
struct glyph *dev_glyph(char *c, int fn);
@@ -191,6 +198,7 @@
int wb_empty(struct wb *wb);
void wb_wconf(struct wb *wb, int *ct, int *st, int *sb);
int wb_lig(struct wb *wb, char *c);
+int wb_kern(struct wb *wb, char *c);
/* hyphenation flags */
#define HY_MASK 0x0f /* enable hyphenation */
@@ -314,6 +322,7 @@
#define n_lg (*nreg(REG(0, 'g'))) /* .lg mode */
#define n_hy (*nreg(REG(0, 'h'))) /* .hy mode */
#define n_i0 (*nreg(REG(0, 'i'))) /* last .i */
+#define n_kn (*nreg(REG(0, 'k'))) /* .kn mode */
#define n_l0 (*nreg(REG(0, 'l'))) /* last .l */
#define n_L0 (*nreg(REG(0, 'L'))) /* last .L */
#define n_mk (*nreg(REG(0, 'm'))) /* .mk internal register */
--- a/tr.c
+++ b/tr.c
@@ -417,6 +417,12 @@
n_lg = atoi(args[1]);
}
+static void tr_kn(char **args)
+{
+ if (args[1])
+ n_kn = atoi(args[1]);
+}
+
static char *arg_regname(char *s, int len)
{
char *e = s + 2;
@@ -618,6 +624,7 @@
{"if", tr_if, mkargs_null},
{"ig", tr_ig},
{"in", tr_in},
+ {"kn", tr_kn},
{"lg", tr_lg},
{"ll", tr_ll},
{"ls", tr_ls},
--- a/wb.c
+++ b/wb.c
@@ -97,6 +97,7 @@
sbuf_printf(&wb->sbuf, "%cC'%s'", c_ec, c);
}
if (strcmp(c_hc, c)) {
+ wb->prev_h = wb->h;
wb->h += charwid(g ? g->wid : SC_DW, R_S(wb));
wb->ct |= g ? g->type : 0;
wb_stsb(wb);
@@ -113,7 +114,7 @@
if (p[0] == c_ec && p[1] == '(')
p += 2;
sprintf(lig, "%s%s", p, c);
- if (dev_lig(R_F(wb), lig)) {
+ if (font_lig(dev_font(R_F(wb)), lig)) {
wb->h = wb->prev_h;
sbuf_pop(&wb->sbuf);
wb_put(wb, lig);
@@ -122,6 +123,17 @@
return 1;
}
+/* return 0 if pairwise kerning was done */
+int wb_kern(struct wb *wb, char *c)
+{
+ char *p = sbuf_last(&wb->sbuf);
+ int val;
+ val = p ? font_kern(dev_font(R_F(wb)), p, c) : 0;
+ if (val)
+ wb_hmov(wb, charwid(val, R_S(wb)));
+ return !val;
+}
+
int wb_part(struct wb *wb)
{
return wb->part;
@@ -274,11 +286,11 @@
char *r = NULL;
int c;
skipreqs(&s, w1);
- while ((c = out_readc(&s, d)) == 0) {
+ while ((c = out_readc(&s, d)) >= 0) {
wb_putc(w1, c, d);
if (wb_wid(w1) > w && (!any || r))
- break;
- if (!strcmp("-", d) || (!strcmp("em", d) || !strcmp("hy", d)))
+ continue;
+ if (!c && (!strcmp("-", d) || (!strcmp("em", d) || !strcmp("hy", d))))
r = s;
}
return r;
@@ -296,11 +308,11 @@
char *r = NULL;
int c;
skipreqs(&s, w1);
- while ((c = out_readc(&s, d)) == 0) {
+ while ((c = out_readc(&s, d)) >= 0) {
wb_putc(w1, c, d);
if (wb_wid(w1) + wb_dashwid(w1) > w && (!(flg & HY_ANY) || r))
- break;
- if (!strcmp(c_hc, d))
+ continue;
+ if (!c && !strcmp(c_hc, d))
r = s;
}
return r;
@@ -308,24 +320,25 @@
static char *hyphpos(char *s, int w, struct wb *w1, int flg)
{
+ char *map[ILNLEN] = {NULL}; /* mapping from word to s */
+ int fits[ILNLEN] = {0}; /* fits[i] if word[0..i]- fits w */
char word[ILNLEN];
- char *map[ILNLEN]; /* mapping from word to s */
char hyph[ILNLEN];
char d[ILNLEN];
char *prev_s = s;
char *r = NULL;
- int fit = 0;
char *wp = word, *we = word + sizeof(word);
int beg, end;
int i, c;
skipreqs(&s, w1);
- while ((c = out_readc(&s, d)) == 0 && wp + strlen(d) + 1 < we) {
+ while ((c = out_readc(&s, d)) >= 0 && wp + strlen(d) + 1 < we) {
wb_putc(w1, c, d);
- strcpy(wp, d);
- while (*wp)
- map[wp++ - word] = prev_s;
- if (wb_wid(w1) + wb_dashwid(w1) <= w)
- fit = wp - word;
+ if (c == 0) {
+ strcpy(wp, d);
+ map[wp - word] = prev_s;
+ wp = strchr(wp, '\0');
+ fits[wp - word] = wb_wid(w1) + wb_dashwid(w1) <= w;
+ }
prev_s = s;
}
if (strlen(word) < 4)
@@ -334,7 +347,7 @@
beg = flg & HY_FIRSTTWO ? 3 : 2;
end = strlen(word) - (flg & HY_FINAL ? 2 : 1);
for (i = beg; i < end; i++)
- if (hyph[i] && (i <= fit || ((flg & HY_ANY) && !r)))
+ if (map[i] && hyph[i] && (fits[i] || ((flg & HY_ANY) && !r)))
r = map[i];
return r;
}