summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/omegafonts/ligkern_routines.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/omegafonts/ligkern_routines.c')
-rw-r--r--Build/source/texk/web2c/omegafonts/ligkern_routines.c576
1 files changed, 576 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/omegafonts/ligkern_routines.c b/Build/source/texk/web2c/omegafonts/ligkern_routines.c
new file mode 100644
index 00000000000..6f8fbf3d76b
--- /dev/null
+++ b/Build/source/texk/web2c/omegafonts/ligkern_routines.c
@@ -0,0 +1,576 @@
+/* ligkern_routines.c: The ligature/kerning table.
+
+This file is part of Omega,
+which is based on the web2c distribution of TeX,
+
+Copyright (c) 1994--2001 John Plaice and Yannis Haralambous
+
+Omega is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+Omega is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Omega; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "cpascal.h"
+#include "manifests.h"
+#include "list_routines.h"
+#include "ligkern_routines.h"
+#include "char_routines.h"
+#include "out_routines.h"
+#include "print_routines.h"
+#include "error_routines.h"
+#include "header_routines.h"
+#include "out_ofm.h"
+
+unsigned nk=0;
+unsigned nl=0;
+
+fix *kern_table;
+av_list kern_list = NULL;
+unsigned no_kerns = 0;
+
+unsigned min_nl=0;
+unsigned bchar = CHAR_BOUNDARY;
+unsigned bchar_label = 0;
+unsigned bchar_remainder;
+unsigned lk_step_ended=FALSE;
+
+four_entries lig_kern_table[100000];
+
+void
+set_boundary_character(unsigned c)
+{
+ /* What checks are required ? */
+ bchar = c;
+}
+
+void
+init_ligkern(void)
+{
+ lk_step_ended = FALSE;
+ nl = 0;
+ min_nl = 0;
+}
+
+void
+set_label_command(unsigned c)
+{
+ if (c==CHAR_BOUNDARY) { /* BOUNDARYCHAR */
+ bchar_label = nl;
+ } else {
+ check_char_tag(c);
+ set_char_tag(c, TAG_LIG);
+ if (nl==0) set_char_remainder(c, 0);
+ else set_char_remainder(c, nl);
+ }
+ if (min_nl <= nl) { min_nl = nl+1; }
+ lk_step_ended = FALSE;
+ no_labels++;
+}
+
+void
+set_stop_command(void)
+{
+ if (lk_step_ended == TRUE) {
+ lig_kern_table[nl-1].entries[0] =
+ lig_kern_table[nl-1].entries[0] / 256 * 256 + STOP_FLAG;
+ } else {
+ warning_0("STOP must follow LIG or KRN; ignored");
+ }
+ lk_step_ended = FALSE;
+}
+
+void
+set_skip_command(unsigned val)
+{
+ if (lk_step_ended == TRUE) {
+ if (val>128) {
+ warning_0("Maximum SKIP amount is 127; ignored");
+ } else {
+ lig_kern_table[nl-1].entries[0] = val;
+ if (min_nl <= (nl+val)) { min_nl = nl+val+1; }
+ }
+ } else {
+ warning_0("SKIP must follow LIG or KRN; ignored");
+ }
+ lk_step_ended = FALSE;
+}
+
+void
+set_ligature_command(unsigned lig, unsigned c, unsigned val)
+{
+ lig_kern_table[nl].entries[0] = 0;
+ lig_kern_table[nl].entries[1] = c;
+ lig_kern_table[nl].entries[2] = lig;
+ lig_kern_table[nl].entries[3] = val;
+ nl++;
+ lk_step_ended = TRUE;
+
+}
+
+void
+set_kerning_command(unsigned c, fix fval)
+{
+ unsigned k = set_new_kern(fval);
+
+ lig_kern_table[nl].entries[0] = 0;
+ lig_kern_table[nl].entries[1] = c;
+ if (ofm_level==OFM_TFM) {
+ lig_kern_table[nl].entries[2] = KERN_FLAG + (k/256);
+ lig_kern_table[nl].entries[3] = k % 256;
+ } else {
+ lig_kern_table[nl].entries[2] = KERN_FLAG + (k/65536);
+ lig_kern_table[nl].entries[3] = k % 65536;
+ }
+ nl++;
+ lk_step_ended = TRUE;
+}
+
+void
+set_c_label_command(unsigned new_class)
+{
+ fatal_error_0("CLABEL not currently supported");
+}
+
+void
+set_c_kerning_command(unsigned new_class, fix fval)
+{
+ fatal_error_0("CKRN not currently supported");
+}
+
+void
+set_c_glue_command(unsigned new_class, unsigned glue_index)
+{
+ fatal_error_0("CGLUE not currently supported");
+}
+
+void
+set_c_penalty_command(unsigned new_class, unsigned pen_index)
+{
+ fatal_error_0("CPEN not currently supported");
+}
+
+void
+set_c_penglue_command(unsigned new_class, unsigned pen_index, unsigned glue_index)
+{
+ fatal_error_0("CPENGLUE not currently supported");
+}
+
+int
+set_new_kern(fix fval)
+{
+ unsigned index;
+ av_list L1, L2;
+
+ L1 = kern_list;
+ if (L1 == NULL) {
+ index = nk++;
+ kern_list = av_list1(index, fval);
+ } else {
+ L2 = L1->ptr;
+ while ((lval(L1) != fval) && (L2 != NULL)) {
+ L1 = L2;
+ L2 = L2->ptr;
+ }
+ if (fval == lval(L1)) {
+ index = lattr(L1);
+ } else {
+ index = nk++;
+ L2 = av_list1(index, fval);
+ L1->ptr = L2;
+ }
+ }
+ return index;
+}
+
+
+void
+build_kern_table(void)
+{
+ av_list L1 = kern_list, L2;
+ unsigned i = 0;
+
+ kern_table = (fix *) xmalloc((nk+1)*sizeof(int));
+ while (L1 != NULL) {
+ kern_table[i] = lval(L1);
+ L2 = L1->ptr;
+ free(L1); L1 = L2;
+ i++;
+ }
+}
+
+void
+print_kerns(void)
+{
+ unsigned i;
+
+ if (nk>0) {
+ left(); out("COMMENT"); out_ln();
+ for (i=0; i<nk; i++) {
+ left(); out("KERN_ENTRY");
+ out(" "); out_int(i,10);
+ out(" "); out_fix(kern_table[i]);
+ right();
+ }
+ right();
+ }
+}
+
+void
+print_ligkern_table(void)
+{
+ unsigned i;
+ four_entries *entry;
+
+ sort_ptr = 1;
+ if (nl>0) {
+ left(); out("LIGTABLE"); out_ln();
+ for (i=0; i<nl; i++) {
+ while ((sort_ptr<=label_ptr) && (i==label_table[sort_ptr].rr)) {
+ print_label_command(label_table[sort_ptr].cc);
+ sort_ptr++;
+ }
+ entry = lig_kern_table+i;
+ print_one_lig_kern_entry(lig_kern_table+i, TRUE);
+ }
+ right();
+ }
+}
+
+void
+print_one_lig_kern_entry(four_entries *lentry, boolean show_stop)
+{
+ if (lentry->entries[2] >= KERN_FLAG) {
+ if (ofm_level==OFM_TFM) {
+ print_kerning_command(lentry->entries[1],
+ kern_table[256*(lentry->entries[2]-KERN_FLAG)+lentry->entries[3]]);
+ } else {
+ print_kerning_command(lentry->entries[1],
+ kern_table[65536*(lentry->entries[2]-KERN_FLAG)+lentry->entries[3]]);
+ }
+ } else {
+ print_ligature_command(lentry->entries[2],
+ lentry->entries[1],
+ lentry->entries[3]);
+ }
+ if ((show_stop == TRUE) && (lentry->entries[0] > 0)) {
+ if (lentry->entries[0] >= STOP_FLAG) {
+ print_stop_command();
+ } else {
+ print_skip_command(0);
+ }
+ }
+}
+
+hash_list hash_table[PRIME];
+
+unsigned x_lig_cycle;
+unsigned y_lig_cycle = CHAR_BOUNDARY;
+
+int
+l_f(hash_list h, unsigned x, unsigned y)
+{
+ switch(h->new_class) {
+ case LIG_SIMPLE: {break;}
+ case LIG_LEFT_Z: {
+ h->new_class = LIG_PENDING;
+ h->lig_z = l_eval(h->lig_z, y);
+ h->new_class = LIG_SIMPLE;
+ break;
+ }
+ case LIG_RIGHT_Z: {
+ h->new_class = LIG_PENDING;
+ h->lig_z = l_eval(x, h->lig_z);
+ h->new_class = LIG_SIMPLE;
+ break;
+ }
+ case LIG_BOTH_Z: {
+ h->new_class = LIG_PENDING;
+ h->lig_z = l_eval(l_eval(x,h->lig_z), y);
+ h->new_class = LIG_SIMPLE;
+ break;
+ }
+ case LIG_PENDING: {
+ x_lig_cycle = x;
+ y_lig_cycle = y;
+ h->lig_z = CHAR_ERROR;
+ h->new_class = LIG_SIMPLE;
+ break;
+ }
+ default: {
+ internal_error_1("f (new_class=%d)", h->new_class);
+ }
+ }
+ return (h->lig_z);
+}
+
+int
+l_eval(unsigned x, unsigned y)
+{
+ hash_list h;
+
+ if ((x==CHAR_ERROR) || (y==CHAR_ERROR)) return CHAR_ERROR;
+ h = l_hash_lookup(x, y);
+ if (h == NULL) return y;
+ return l_f(h, x, y);
+}
+
+queue hash_entries;
+
+int
+l_hash_input(unsigned p, unsigned c)
+{
+
+ four_entries *entry = lig_kern_table+p;
+ unsigned y = entry->entries[1];
+ unsigned t = entry->entries[2];
+ unsigned cc = LIG_SIMPLE;
+ unsigned zz = entry->entries[3];
+ unsigned key;
+ hash_list L1, L2;
+
+ if (t >= KERN_FLAG) zz = y;
+ else {
+ switch(t) {
+ case L_0:
+ case L_Ax: { break; }
+ case L_Bx:
+ case L_ABxx: { zz = y; break; }
+ case L_B:
+ case L_ABx: { cc = LIG_LEFT_Z; break; }
+ case L_A: { cc = LIG_RIGHT_Z; break; }
+ case L_AB: { cc = LIG_BOTH_Z; break; }
+ default: {
+ internal_error_1("l_hash_input (case=%d)", t);
+ }
+ }
+ }
+ key = (c & 0x7fff)*(y & 0x7fff) % PRIME;
+ if (hash_table[key] == NULL) {
+ hash_table[key] = hash_list1(c,y,cc,zz);
+ append_to_queue(&hash_entries, hash_table[key]);
+ } else {
+ L1 = hash_table[key];
+ L2 = L1->ptr;
+ while ((L2 != NULL) &&
+ ((L2->x <= c) || ((L2->x == c) && (L2->y <= y)))) {
+ L1 = L2;
+ L2 = L2->ptr;
+ }
+ if (L2 == NULL) {
+ L2 = hash_list1(c,y,cc,zz);
+ append_to_queue(&hash_entries, L2);
+ L2->ptr = L1->ptr;
+ L1->ptr = L2;
+ } else if ((c < L2->x) || ((c == L2->x) && (y < L2->y))) {
+ hash_table[key] = hash_list1(c,y,cc,zz);
+ hash_table[key]->ptr = L1;
+ append_to_queue(&hash_entries, hash_table[key]);
+ } else if ((c == L2->x) && (y < L2->y)) {
+ return FALSE; /* unused ligature command */
+ } else {
+ L2 = hash_list1(c,y,cc,zz);
+ append_to_queue(&hash_entries, L2);
+ L2->ptr = L1->ptr;
+ L1->ptr = L2;
+ }
+ }
+ return TRUE;
+}
+
+hash_list
+l_hash_lookup(unsigned x, unsigned y)
+{
+ unsigned key = (x & 0x7fff)*(y & 0x7fff) % PRIME;
+ hash_list L = hash_table[key];
+
+ if (L==NULL) return NULL;
+ while (L->x < x) L = L->ptr;
+ if (L->x != x) return NULL;
+ while ((L->x == x) && (L->y < y)) L = L->ptr;
+ if (L->y != y) return NULL;
+ return L;
+}
+
+void
+check_ligature_ends_properly(void)
+{
+ if (nl>0) {
+ if (bchar_label != 0) {
+ /* make room for it; the actual label will be stored later */
+ nl++;
+ }
+ while (min_nl > nl) {
+ nl++;
+ }
+ if (lig_kern_table[nl].entries[0] == 0) {
+ lig_kern_table[nl].entries[0] = STOP_FLAG;
+ }
+ }
+}
+
+void
+check_ligature_program(unsigned c, unsigned lab)
+{
+ unsigned lig_ptr = lab;
+ four_entries *entry;
+
+ while (lig_ptr < nl) {
+ entry = lig_kern_table+lig_ptr;
+ if (l_hash_input(lig_ptr,c)) {
+ if (entry->entries[2] < KERN_FLAG) {
+ if (entry->entries[1] != bchar)
+ check_existence_and_safety(c, entry->entries[1],
+ ligature_commands[entry->entries[2]],
+ "%s character examined by (H %X)");
+ if (entry->entries[3] >= 128)
+/* Needs fixing */
+ if ((c < 128) || (c == -1))
+ if ((entry->entries[1] < 128) ||
+ (entry->entries[1] == bchar))
+ seven_bit_calculated = 0;
+ check_existence_and_safety(c, entry->entries[3],
+ ligature_commands[entry->entries[2]],
+ "%s character generated by (H %X)");
+ } else {
+ check_existence_and_safety(c, entry->entries[1],
+ "KRN", "%s character examined by (H %X)");
+ }
+ }
+ if (entry->entries[0] >= STOP_FLAG) lig_ptr = nl;
+ else lig_ptr = lig_ptr + 1 + entry->entries[0];
+ }
+}
+
+void
+check_ligature_infinite_loops(void)
+{
+ list entry = hash_entries.front;
+ hash_list tt;
+ unsigned new_class;
+
+ while (entry != NULL) {
+ tt = (hash_list) entry->contents;
+ if (tt->new_class > LIG_SIMPLE)
+ new_class = l_f(tt, tt->x, tt->y);
+ entry = entry->ptr;
+ }
+ if (y_lig_cycle != 0x80000000) {
+ if (x_lig_cycle == CHAR_BOUNDARY) {
+ warning_1("Infinite ligature loop starting with boundary and %d",
+ y_lig_cycle);
+ } else {
+ warning_2("Infinite ligature loop starting with %d and %d",
+ x_lig_cycle, y_lig_cycle);
+ }
+ clear_ligature_entries();
+ nl = 0; bchar = CHAR_BOUNDARY; bchar_label = 0;
+ }
+}
+
+void
+doublecheck_ligatures(void)
+{
+ unsigned i;
+
+ if (nl>0) {
+ for (i=0; i<nl; i++) {
+ if (lig_kern_table[i].entries[2] < KERN_FLAG) {
+ if (lig_kern_table[i].entries[0] != CHAR_BOUNDARY) {
+ doublecheck_existence(
+ lig_kern_table[i].entries[1],
+ ligature_commands[lig_kern_table[i].entries[2]],
+ "Unused %s step refers to nonexistent character (H %X)");
+ doublecheck_existence(
+ lig_kern_table[i].entries[3],
+ ligature_commands[lig_kern_table[i].entries[2]],
+ "Unused %s step refers to nonexistent character (H %X)");
+ }
+ } else {
+ doublecheck_existence(
+ lig_kern_table[i].entries[1],
+ "KRN",
+ "Unused %s step refers to nonexistent character (H %X)");
+ }
+ }
+ }
+}
+
+void
+output_ofm_ligkern(void)
+{
+ unsigned i;
+ four_entries *entry;
+
+ if (ofm_level == OFM_TFM) {
+ for (i=0; i<nl; i++) {
+ entry = lig_kern_table+i;
+ out_ofm(entry->entries[0] & 0xff);
+ out_ofm(entry->entries[1] & 0xff);
+ out_ofm(entry->entries[2] & 0xff);
+ out_ofm(entry->entries[3] & 0xff);
+ }
+ } else {
+ for (i=0; i<nl; i++) {
+ entry = lig_kern_table+i;
+ out_ofm_2(entry->entries[0] & 0xffff);
+ out_ofm_2(entry->entries[1] & 0xffff);
+ out_ofm_2(entry->entries[2] & 0xffff);
+ out_ofm_2(entry->entries[3] & 0xffff);
+ }
+ }
+ for (i=0; i<nk; i++) {
+ out_ofm_4(kern_table[i]);
+ }
+}
+
+void
+retrieve_ligkern_table(unsigned char *ofm_lig_table,
+ unsigned char *ofm_kern_table)
+{
+ unsigned i;
+ four_entries *entry;
+ unsigned char *table_entry;
+
+ if (ofm_level == OFM_TFM) {
+ for (i=0; i<nl; i++) {
+ entry = lig_kern_table+i;
+ table_entry = ofm_lig_table+(4*i);
+ entry->entries[0] = (*table_entry) & 0xff;
+ entry->entries[1] = (*(table_entry+1)) & 0xff;
+ entry->entries[2] = (*(table_entry+2)) & 0xff;
+ entry->entries[3] = (*(table_entry+3)) & 0xff;
+ }
+ } else {
+ for (i=0; i<nl; i++) {
+ entry = lig_kern_table+i;
+ table_entry = ofm_lig_table+(8*i);
+ entry->entries[0] = (((*table_entry) & 0xff) * 0x100)
+ + ((*(table_entry+1)) & 0xff);
+ entry->entries[1] = (((*(table_entry+2)) & 0xff) * 0x100)
+ + ((*(table_entry+3)) & 0xff);
+ entry->entries[2] = (((*(table_entry+4)) & 0xff) * 0x100)
+ + ((*(table_entry+5)) & 0xff);
+ entry->entries[3] = (((*(table_entry+6)) & 0xff) * 0x100)
+ + ((*(table_entry+7)) & 0xff);
+ }
+ }
+ kern_table = (fix *) xmalloc((nk+1)*sizeof(int));
+ for (i=0; i<nk; i++) {
+ table_entry = ofm_kern_table+(4*i);
+ kern_table[i] = (((*table_entry) & 0xff) << 24) |
+ (((*(table_entry+1)) & 0xff) << 16) |
+ (((*(table_entry+2)) & 0xff) << 8) |
+ ((*(table_entry+3)) & 0xff);
+ }
+}