Back to index

tetex-bin  3.0
ligkern_routines.c
Go to the documentation of this file.
00001 /* ligkern_routines.c: The ligature/kerning table.
00002 
00003 This file is part of Omega,
00004 which is based on the web2c distribution of TeX,
00005 
00006 Copyright (c) 1994--2001 John Plaice and Yannis Haralambous
00007 
00008 Omega is free software; you can redistribute it and/or modify
00009 it under the terms of the GNU General Public License as published by
00010 the Free Software Foundation; either version 2 of the License, or
00011 (at your option) any later version.
00012 
00013 Omega is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 GNU General Public License for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Omega; if not, write to the Free Software Foundation, Inc.,
00020 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
00021 
00022 */
00023 
00024 #include "cpascal.h"
00025 #include "manifests.h"
00026 #include "list_routines.h"
00027 #include "ligkern_routines.h"
00028 #include "char_routines.h"
00029 #include "out_routines.h"
00030 #include "print_routines.h"
00031 #include "error_routines.h"
00032 #include "header_routines.h"
00033 #include "out_ofm.h"
00034 
00035 unsigned nk=0;
00036 unsigned nl=0;
00037 
00038 fix *kern_table;
00039 av_list kern_list = NULL;
00040 unsigned no_kerns = 0;
00041 
00042 unsigned min_nl=0;
00043 unsigned bchar = CHAR_BOUNDARY;
00044 unsigned bchar_label = 0;
00045 unsigned bchar_remainder;
00046 unsigned lk_step_ended=FALSE;
00047 
00048 four_entries lig_kern_table[100000];
00049 
00050 void
00051 set_boundary_character(unsigned c)
00052 {
00053     /* What checks are required ? */
00054     bchar = c;
00055 }
00056 
00057 void
00058 init_ligkern(void)
00059 {
00060     lk_step_ended = FALSE;
00061     nl = 0;
00062     min_nl = 0;
00063 }
00064 
00065 void
00066 set_label_command(unsigned c)
00067 {
00068     if (c==CHAR_BOUNDARY) { /* BOUNDARYCHAR */
00069         bchar_label = nl;
00070     } else {
00071         check_char_tag(c);
00072        set_char_tag(c, TAG_LIG);
00073         if (nl==0) set_char_remainder(c, 0);
00074        else set_char_remainder(c, nl);
00075     }
00076     if (min_nl <= nl) { min_nl = nl+1; }
00077     lk_step_ended = FALSE;
00078     no_labels++;
00079 }
00080 
00081 void
00082 set_stop_command(void)
00083 {
00084     if (lk_step_ended == TRUE) {
00085         lig_kern_table[nl-1].entries[0] = 
00086         lig_kern_table[nl-1].entries[0] / 256 * 256 + STOP_FLAG;
00087     } else {
00088         warning_0("STOP must follow LIG or KRN; ignored");
00089     }
00090     lk_step_ended = FALSE;
00091 }
00092 
00093 void
00094 set_skip_command(unsigned val)
00095 {
00096     if (lk_step_ended == TRUE) {
00097         if (val>128) {
00098             warning_0("Maximum SKIP amount is 127; ignored");
00099         } else {
00100             lig_kern_table[nl-1].entries[0] = val;
00101             if (min_nl <= (nl+val)) { min_nl = nl+val+1; }
00102         }
00103     } else {
00104         warning_0("SKIP must follow LIG or KRN; ignored");
00105     }
00106     lk_step_ended = FALSE;
00107 }
00108 
00109 void
00110 set_ligature_command(unsigned lig, unsigned c, unsigned val)
00111 {
00112     lig_kern_table[nl].entries[0] = 0;
00113     lig_kern_table[nl].entries[1] = c;
00114     lig_kern_table[nl].entries[2] = lig;
00115     lig_kern_table[nl].entries[3] = val;
00116     nl++;
00117     lk_step_ended = TRUE;
00118 
00119 }
00120 
00121 void
00122 set_kerning_command(unsigned c, fix fval)
00123 {
00124     unsigned k = set_new_kern(fval);
00125 
00126     lig_kern_table[nl].entries[0] = 0;
00127     lig_kern_table[nl].entries[1] = c;
00128     if (ofm_level==OFM_TFM) {
00129         lig_kern_table[nl].entries[2] = KERN_FLAG + (k/256);
00130         lig_kern_table[nl].entries[3] = k % 256;
00131     } else {
00132         lig_kern_table[nl].entries[2] = KERN_FLAG + (k/65536);
00133         lig_kern_table[nl].entries[3] = k % 65536;
00134     }
00135     nl++;
00136     lk_step_ended = TRUE;
00137 }
00138 
00139 void
00140 set_c_label_command(unsigned new_class)
00141 {
00142     fatal_error_0("CLABEL not currently supported");
00143 }
00144 
00145 void
00146 set_c_kerning_command(unsigned new_class, fix fval)
00147 {
00148     fatal_error_0("CKRN not currently supported");
00149 }
00150 
00151 void
00152 set_c_glue_command(unsigned new_class, unsigned glue_index)
00153 {
00154     fatal_error_0("CGLUE not currently supported");
00155 }
00156 
00157 void
00158 set_c_penalty_command(unsigned new_class, unsigned pen_index)
00159 {
00160     fatal_error_0("CPEN not currently supported");
00161 }
00162 
00163 void
00164 set_c_penglue_command(unsigned new_class, unsigned pen_index, unsigned glue_index)
00165 {
00166     fatal_error_0("CPENGLUE not currently supported");
00167 }
00168 
00169 int
00170 set_new_kern(fix fval)
00171 {
00172     unsigned index;
00173     av_list L1, L2;
00174 
00175     L1 = kern_list;
00176     if (L1 == NULL) {
00177         index = nk++;
00178         kern_list = av_list1(index, fval);
00179     } else {
00180         L2 = L1->ptr;
00181         while ((lval(L1) != fval) && (L2 != NULL)) {
00182             L1 = L2;
00183             L2 = L2->ptr;
00184         }
00185         if (fval == lval(L1)) {
00186             index = lattr(L1);
00187         } else {
00188             index = nk++;
00189             L2 = av_list1(index, fval);
00190             L1->ptr = L2;
00191         }
00192     }
00193     return index;
00194 }
00195 
00196 
00197 void
00198 build_kern_table(void)
00199 {
00200     av_list L1 = kern_list, L2;
00201     unsigned i = 0;
00202 
00203     kern_table = (fix *) xmalloc((nk+1)*sizeof(int));
00204     while (L1 != NULL) {
00205         kern_table[i] = lval(L1);
00206         L2 = L1->ptr;
00207         free(L1); L1 = L2;
00208         i++;
00209     }
00210 }
00211 
00212 void
00213 print_kerns(void)
00214 {
00215     unsigned i;
00216 
00217     if (nk>0) {
00218         left(); out("COMMENT"); out_ln();
00219         for (i=0; i<nk; i++) {
00220             left(); out("KERN_ENTRY");
00221             out(" "); out_int(i,10);
00222             out(" "); out_fix(kern_table[i]);
00223             right();
00224         }
00225         right();
00226     }
00227 }
00228 
00229 void
00230 print_ligkern_table(void)
00231 {
00232     unsigned i;
00233     four_entries *entry;
00234 
00235     sort_ptr = 1;
00236     if (nl>0) {
00237         left(); out("LIGTABLE"); out_ln();
00238         for (i=0; i<nl; i++) {
00239             while ((sort_ptr<=label_ptr) && (i==label_table[sort_ptr].rr)) {
00240                 print_label_command(label_table[sort_ptr].cc);
00241                 sort_ptr++;
00242             }
00243             entry = lig_kern_table+i;
00244             print_one_lig_kern_entry(lig_kern_table+i, TRUE);
00245         }
00246         right();
00247     }
00248 }
00249 
00250 void
00251 print_one_lig_kern_entry(four_entries *lentry, boolean show_stop)
00252 {
00253     if (lentry->entries[2] >= KERN_FLAG) {
00254         if (ofm_level==OFM_TFM) {
00255         print_kerning_command(lentry->entries[1],
00256         kern_table[256*(lentry->entries[2]-KERN_FLAG)+lentry->entries[3]]);
00257         } else {
00258         print_kerning_command(lentry->entries[1],
00259         kern_table[65536*(lentry->entries[2]-KERN_FLAG)+lentry->entries[3]]);
00260         }
00261     } else {
00262         print_ligature_command(lentry->entries[2],
00263                                lentry->entries[1],
00264                                lentry->entries[3]);
00265     }
00266     if ((show_stop == TRUE) && (lentry->entries[0] > 0)) {
00267         if (lentry->entries[0] >= STOP_FLAG) {
00268             print_stop_command();
00269         } else {
00270             print_skip_command(0);
00271         }
00272     }
00273 }
00274 
00275 hash_list hash_table[PRIME];
00276 
00277 unsigned x_lig_cycle;
00278 unsigned y_lig_cycle = CHAR_BOUNDARY;
00279 
00280 int
00281 l_f(hash_list h, unsigned x, unsigned y)
00282 {
00283     switch(h->new_class) {
00284          case LIG_SIMPLE: {break;}
00285          case LIG_LEFT_Z: {
00286              h->new_class = LIG_PENDING;
00287              h->lig_z = l_eval(h->lig_z, y);
00288              h->new_class = LIG_SIMPLE;
00289              break;
00290          }
00291          case LIG_RIGHT_Z: {
00292              h->new_class = LIG_PENDING;
00293              h->lig_z = l_eval(x, h->lig_z);
00294              h->new_class = LIG_SIMPLE;
00295              break;
00296          }
00297          case LIG_BOTH_Z: {
00298              h->new_class = LIG_PENDING;
00299              h->lig_z = l_eval(l_eval(x,h->lig_z), y);
00300              h->new_class = LIG_SIMPLE;
00301              break;
00302          }
00303          case LIG_PENDING: {
00304              x_lig_cycle = x;
00305              y_lig_cycle = y;
00306              h->lig_z = CHAR_ERROR;
00307              h->new_class = LIG_SIMPLE;
00308              break;
00309          }
00310          default: {
00311              internal_error_1("f (new_class=%d)", h->new_class);
00312          }
00313     }
00314     return (h->lig_z);
00315 }
00316 
00317 int
00318 l_eval(unsigned x, unsigned y)
00319 {
00320     hash_list h;
00321     
00322     if ((x==CHAR_ERROR) || (y==CHAR_ERROR)) return CHAR_ERROR;
00323     h = l_hash_lookup(x, y);
00324     if (h == NULL) return y;
00325     return l_f(h, x, y);
00326 }
00327 
00328 queue hash_entries;
00329 
00330 int
00331 l_hash_input(unsigned p, unsigned c)
00332 {
00333 
00334     four_entries *entry = lig_kern_table+p;
00335     unsigned y = entry->entries[1];
00336     unsigned t = entry->entries[2];
00337     unsigned cc = LIG_SIMPLE;
00338     unsigned zz = entry->entries[3];
00339     unsigned key;
00340     hash_list L1, L2;
00341 
00342     if (t >= KERN_FLAG) zz = y;
00343     else {
00344         switch(t) {
00345              case L_0:
00346              case L_Ax:   { break; }
00347              case L_Bx:
00348              case L_ABxx: { zz = y; break; }
00349              case L_B:
00350              case L_ABx:  { cc = LIG_LEFT_Z;  break; }
00351              case L_A:    { cc = LIG_RIGHT_Z; break; }
00352              case L_AB:   { cc = LIG_BOTH_Z;  break; }
00353              default: {
00354                  internal_error_1("l_hash_input (case=%d)", t);
00355              }
00356         }
00357     }
00358     key = (c & 0x7fff)*(y & 0x7fff) % PRIME;
00359     if (hash_table[key] == NULL) {
00360         hash_table[key] = hash_list1(c,y,cc,zz);
00361         append_to_queue(&hash_entries, hash_table[key]);
00362     } else {
00363         L1 = hash_table[key];
00364         L2 = L1->ptr;
00365         while ((L2 != NULL) &&
00366                ((L2->x <= c) || ((L2->x == c) && (L2->y <= y)))) {
00367             L1 = L2;
00368             L2 = L2->ptr;
00369         }
00370         if (L2 == NULL) {
00371             L2 = hash_list1(c,y,cc,zz);
00372             append_to_queue(&hash_entries, L2);
00373             L2->ptr = L1->ptr;
00374             L1->ptr = L2;
00375         } else if ((c < L2->x) || ((c == L2->x) && (y < L2->y))) {
00376             hash_table[key] = hash_list1(c,y,cc,zz);
00377             hash_table[key]->ptr = L1;
00378             append_to_queue(&hash_entries, hash_table[key]);
00379         } else if ((c == L2->x) && (y < L2->y)) {
00380             return FALSE; /* unused ligature command */
00381         } else {
00382             L2 = hash_list1(c,y,cc,zz);
00383             append_to_queue(&hash_entries, L2);
00384             L2->ptr = L1->ptr;
00385             L1->ptr = L2;
00386         }
00387     }
00388     return TRUE;
00389 }
00390 
00391 hash_list
00392 l_hash_lookup(unsigned x, unsigned y)
00393 {
00394     unsigned key = (x & 0x7fff)*(y & 0x7fff) % PRIME;
00395     hash_list L = hash_table[key];
00396 
00397     if (L==NULL) return NULL;
00398     while (L->x < x) L = L->ptr;
00399     if (L->x != x) return NULL;
00400     while ((L->x == x) && (L->y < y)) L = L->ptr;
00401     if (L->y != y) return NULL;
00402     return L;
00403 }
00404 
00405 void
00406 check_ligature_ends_properly(void)
00407 {
00408     if (nl>0) {
00409         if (bchar_label != 0) {
00410             /* make room for it; the actual label will be stored later */
00411             nl++;
00412         }
00413         while (min_nl > nl) {
00414             nl++;
00415         }
00416         if (lig_kern_table[nl].entries[0] == 0) {
00417             lig_kern_table[nl].entries[0] = STOP_FLAG;
00418         }
00419     }
00420 }
00421 
00422 void
00423 check_ligature_program(unsigned c, unsigned lab)
00424 {
00425     unsigned lig_ptr = lab;
00426     four_entries *entry;
00427 
00428     while (lig_ptr < nl) {
00429         entry = lig_kern_table+lig_ptr;
00430         if (l_hash_input(lig_ptr,c)) {
00431             if (entry->entries[2] < KERN_FLAG) {
00432                 if (entry->entries[1] != bchar) 
00433                     check_existence_and_safety(c, entry->entries[1],
00434                         ligature_commands[entry->entries[2]],
00435                         "%s character examined by (H %X)");
00436                 if (entry->entries[3] >= 128)
00437 /* Needs fixing */
00438                     if ((c < 128) || (c == -1))
00439                         if ((entry->entries[1] < 128) ||
00440                             (entry->entries[1] == bchar)) 
00441                             seven_bit_calculated = 0;
00442                 check_existence_and_safety(c, entry->entries[3],
00443                     ligature_commands[entry->entries[2]],
00444                     "%s character generated by (H %X)");
00445             } else {
00446                 check_existence_and_safety(c, entry->entries[1],
00447                     "KRN", "%s character examined by (H %X)");
00448             }
00449         }
00450         if (entry->entries[0] >= STOP_FLAG) lig_ptr = nl;
00451         else lig_ptr = lig_ptr + 1 + entry->entries[0];
00452     }
00453 }
00454 
00455 void
00456 check_ligature_infinite_loops(void)
00457 {
00458     list entry = hash_entries.front;
00459     hash_list tt;
00460     unsigned new_class;
00461 
00462     while (entry != NULL) {
00463         tt = (hash_list) entry->contents;
00464         if (tt->new_class > LIG_SIMPLE)
00465              new_class = l_f(tt, tt->x, tt->y);
00466         entry = entry->ptr;
00467     }
00468     if (y_lig_cycle != 0x80000000) {
00469         if (x_lig_cycle == CHAR_BOUNDARY) {
00470             warning_1("Infinite ligature loop starting with boundary and %d",
00471                       y_lig_cycle);
00472         } else {
00473             warning_2("Infinite ligature loop starting with %d and %d",
00474                       x_lig_cycle, y_lig_cycle);
00475         }
00476         clear_ligature_entries();
00477         nl = 0; bchar = CHAR_BOUNDARY; bchar_label = 0;
00478     }
00479 }
00480 
00481 void
00482 doublecheck_ligatures(void)
00483 {
00484     unsigned i;
00485 
00486     if (nl>0) {
00487         for (i=0; i<nl; i++) {
00488             if (lig_kern_table[i].entries[2] < KERN_FLAG) {
00489                 if (lig_kern_table[i].entries[0] != CHAR_BOUNDARY) {
00490                     doublecheck_existence(
00491                         lig_kern_table[i].entries[1],
00492                         ligature_commands[lig_kern_table[i].entries[2]],
00493                         "Unused %s step refers to nonexistent character (H %X)");
00494                     doublecheck_existence(
00495                         lig_kern_table[i].entries[3],
00496                         ligature_commands[lig_kern_table[i].entries[2]],
00497                         "Unused %s step refers to nonexistent character (H %X)");
00498                 }
00499             } else {
00500                 doublecheck_existence(
00501                     lig_kern_table[i].entries[1],
00502                     "KRN",
00503                     "Unused %s step refers to nonexistent character (H %X)");
00504             }
00505         }
00506     }
00507 }
00508 
00509 void
00510 output_ofm_ligkern(void)
00511 {
00512     unsigned i;
00513     four_entries *entry;
00514 
00515     if (ofm_level == OFM_TFM) {
00516         for (i=0; i<nl; i++) {
00517             entry = lig_kern_table+i;
00518             out_ofm(entry->entries[0] & 0xff);
00519             out_ofm(entry->entries[1] & 0xff);
00520             out_ofm(entry->entries[2] & 0xff);
00521             out_ofm(entry->entries[3] & 0xff);
00522         }
00523     } else {
00524         for (i=0; i<nl; i++) {
00525             entry = lig_kern_table+i;
00526             out_ofm_2(entry->entries[0] & 0xffff);
00527             out_ofm_2(entry->entries[1] & 0xffff);
00528             out_ofm_2(entry->entries[2] & 0xffff);
00529             out_ofm_2(entry->entries[3] & 0xffff);
00530         }
00531     }
00532     for (i=0; i<nk; i++) {
00533         out_ofm_4(kern_table[i]);
00534     }
00535 }
00536 
00537 void
00538 retrieve_ligkern_table(unsigned char *ofm_lig_table,
00539                        unsigned char *ofm_kern_table)
00540 {
00541     unsigned i;
00542     four_entries *entry;
00543     unsigned char *table_entry;
00544 
00545     if (ofm_level == OFM_TFM) {
00546         for (i=0; i<nl; i++) {
00547             entry = lig_kern_table+i;
00548             table_entry = ofm_lig_table+(4*i);
00549             entry->entries[0] = (*table_entry) & 0xff;
00550             entry->entries[1] = (*(table_entry+1)) & 0xff;
00551             entry->entries[2] = (*(table_entry+2)) & 0xff;
00552             entry->entries[3] = (*(table_entry+3)) & 0xff;
00553         }
00554     } else {
00555         for (i=0; i<nl; i++) {
00556             entry = lig_kern_table+i;
00557             table_entry = ofm_lig_table+(8*i);
00558             entry->entries[0] = (((*table_entry) & 0xff) * 0x100)
00559                                 + ((*(table_entry+1)) & 0xff);
00560             entry->entries[1] = (((*(table_entry+2)) & 0xff) * 0x100)
00561                                 + ((*(table_entry+3)) & 0xff);
00562             entry->entries[2] = (((*(table_entry+4)) & 0xff) * 0x100)
00563                                 + ((*(table_entry+5)) & 0xff);
00564             entry->entries[3] = (((*(table_entry+6)) & 0xff) * 0x100)
00565                                 + ((*(table_entry+7)) & 0xff);
00566         }
00567     }
00568     kern_table = (fix *) xmalloc((nk+1)*sizeof(int));
00569     for (i=0; i<nk; i++) {
00570         table_entry = ofm_kern_table+(4*i);
00571         kern_table[i] = (((*table_entry) & 0xff) << 24) |
00572                         (((*(table_entry+1)) & 0xff) << 16) |
00573                         (((*(table_entry+2)) & 0xff) << 8) |
00574                         ((*(table_entry+3)) & 0xff);
00575     }
00576 }