Back to index

texmacs  1.0.7.15
tt_gsub.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/tt_gsub.c,v 1.14 2005/06/27 09:04:52 hirata Exp $
00002     
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007     
00008     This program 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     This program 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 this program; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00021 */
00022 
00023 /*
00024  * TrueType GSUB support: (incomplete)
00025  */
00026 
00027 #include "system.h"
00028 
00029 #include "error.h"
00030 #include "mem.h"
00031 #include "mfileio.h"
00032 
00033 #include "sfnt.h"
00034 
00035 #include "otl_opt.h"
00036 #include "tt_gsub.h"
00037 
00038 #define VERBOSE_LEVEL_MIN 0
00039 static int verbose = 0;
00040 void
00041 otl_gsub_set_verbose (void)
00042 {
00043   verbose++;
00044 }
00045 
00046 typedef USHORT Offset;
00047 typedef USHORT GlyphID;
00048 
00049 /* OpenType Common Layout Table */
00050 /* Records */
00051 struct clt_record
00052 {
00053   char   tag[5]; /* 4-byte identifier */
00054   Offset offset;
00055 };
00056 
00057 /* Ranges */
00058 /* RangeRecord */
00059 struct clt_range
00060 { 
00061   GlyphID Start; /* First GlyphID in the range */
00062   GlyphID End;   /* Last GlyphID in the range */
00063   USHORT  StartCoverageIndex; /* Converage Index of first GID */
00064 };
00065 
00066 static long
00067 clt_read_record (struct clt_record *rec, sfnt *sfont)
00068 {
00069   int i;
00070 
00071   ASSERT(rec && sfont);
00072 
00073   for (i = 0; i < 4; i++) {
00074     rec->tag[i] = sfnt_get_char(sfont);
00075   }
00076   rec->tag[4] = '\0';
00077   rec->offset = sfnt_get_ushort(sfont);
00078 
00079   return 6;
00080 }
00081 
00082 static long
00083 clt_read_range (struct clt_range *rec, sfnt *sfont)
00084 {
00085   ASSERT(rec && sfont);
00086 
00087   rec->Start = sfnt_get_ushort(sfont);
00088   rec->End   = sfnt_get_ushort(sfont);
00089   rec->StartCoverageIndex = sfnt_get_ushort(sfont);
00090 
00091   return 6;
00092 }
00093 
00094 /*
00095   List structure:
00096    ScriptRecord (records), FeatureRecord (records), Lookup (offsets)
00097 */
00098 
00099 struct clt_record_list
00100 {
00101   USHORT count;
00102   struct clt_record *record;
00103 };
00104 
00105 /* offset and index list, Offset is USHORT */
00106 struct clt_number_list
00107 {
00108   USHORT  count;
00109   USHORT *value;
00110 };
00111 
00112 static long
00113 clt_read_record_list (struct clt_record_list *list, sfnt *sfont)
00114 {
00115   long len, i;
00116 
00117   ASSERT(list && sfont);
00118 
00119   list->count = sfnt_get_ushort(sfont);
00120   len = 2;
00121 
00122   if (list->count == 0)
00123     list->record = NULL;
00124   else {
00125     list->record = NEW(list->count, struct clt_record);
00126     for (i = 0; i < list->count; i++) {
00127       len += clt_read_record(&(list->record[i]), sfont);
00128     }
00129   }
00130 
00131   return len;
00132 }
00133 
00134 static void
00135 clt_release_record_list (struct clt_record_list *list)
00136 {
00137   if (list) {
00138     if (list->record)
00139       RELEASE(list->record);
00140     list->record = NULL;
00141     list->count  = 0;
00142   }
00143 }
00144 
00145 static long
00146 clt_read_number_list (struct clt_number_list *list, sfnt *sfont)
00147 {
00148   long i;
00149 
00150   ASSERT(list && sfont);
00151 
00152   list->count = sfnt_get_ushort(sfont);
00153 
00154   if (list->count == 0)
00155     list->value = NULL;
00156   else {
00157     list->value = NEW(list->count, USHORT);
00158     for (i = 0; i < list->count; i++) {
00159       list->value[i] = sfnt_get_ushort(sfont);
00160     }
00161   }
00162 
00163   return (2 + 2 * list->count);
00164 }
00165 
00166 static void
00167 clt_release_number_list (struct clt_number_list *list)
00168 {
00169   if (list) {
00170     if (list->value)
00171       RELEASE(list->value);
00172     list->value = NULL;
00173     list->count = 0;
00174   }
00175 }
00176 
00177 /*
00178  * Tables
00179  */
00180 
00181 
00182 /* Coverage Table: format 1 and format 2 */
00183 struct clt_coverage
00184 {
00185   USHORT format; /* Format identifier: 1 (list), 2 (range) */
00186   USHORT count;  /* Glyphs/Range Count */
00187   GlyphID *list; /* Array of GlyphIDs - in numerical order */
00188   struct clt_range *range; /* Array of glyph ranges
00189                             *  - ordered by Start GlyphID
00190                             */
00191 };
00192 
00193 /* GSUB - The Glyph Substitution Table */
00194 struct otl_gsub_header
00195 {
00196   Fixed  version;     /* 0x00010000 */
00197   Offset ScriptList;  /* offset */
00198   Offset FeatureList; /* offset */
00199   Offset LookupList;  /* offset */
00200 };
00201 
00202 /* Single Substitution Format 1 */
00203 struct otl_gsub_single1
00204 {
00205   SHORT DeltaGlyphID;            /* Add to original GlyphID to get
00206                                   * substitute GlyphID */
00207   struct clt_coverage coverage; /* Coverage table */
00208 };
00209 
00210 /* Single Substitution Format 2 */
00211 struct otl_gsub_single2
00212 {
00213   USHORT   GlyphCount; /* Number of GlyphIDs in the Substitute array */
00214   GlyphID *Substitute; /* Array of substitute GlyphIDs
00215                         * - ordered by Coverage Index */
00216   struct clt_coverage coverage; /* Coverage table */
00217 };
00218 
00219 /* Alternate Subsutitution Format 1 */
00220 struct otl_gsub_altset
00221 {
00222   USHORT   GlyphCount; /* Number of GlyphIDs in the Alternate array */
00223   GlyphID *Alternate;  /* Array of alternate GlyphIDs
00224                         * - in arbitrary order
00225                         */
00226 };
00227 
00228 struct otl_gsub_alternate1
00229 {
00230   USHORT   AlternateSetCount;
00231   struct otl_gsub_altset *AlternateSet;
00232 
00233   struct clt_coverage coverage;
00234 };
00235 
00236 /* Faithfull */
00237 struct otl_gsub_ligtab
00238 {
00239   GlyphID  LigGlyph;  /* GlyphID of ligature glyph */
00240   USHORT   CompCount;
00241   GlyphID *Component; /* CompCount - 1 elements
00242                        * First component excluded.
00243                        * Ordered in writing direction...
00244                        */
00245 };
00246 
00247 struct otl_gsub_ligset
00248 {
00249   USHORT LigatureCount;
00250   struct otl_gsub_ligtab *Ligature;
00251 };
00252 
00253 struct otl_gsub_ligature1
00254 {
00255   USHORT LigSetCount;
00256   struct otl_gsub_ligset *LigatureSet;
00257 
00258   struct clt_coverage     coverage;
00259 };
00260 
00261 /* GSUB subtable (single) */
00262 struct otl_gsub_subtab
00263 {
00264   USHORT LookupType;  /* FIXME */
00265 
00266   USHORT SubstFormat;
00267   union {
00268     struct otl_gsub_single1    *single1;
00269     struct otl_gsub_single2    *single2;
00270     struct otl_gsub_alternate1 *alternate1;
00271     struct otl_gsub_ligature1  *ligature1;
00272   } table;
00273 };
00274 
00275 /* Script Table */
00276 struct clt_script_table
00277 {
00278   Offset DefaultLangSys;
00279   struct clt_record_list LangSysRecord;
00280 };
00281 
00282 static long
00283 clt_read_script_table (struct clt_script_table *tab, sfnt *sfont)
00284 {
00285   long len;
00286 
00287   ASSERT(tab && sfont);
00288 
00289   tab->DefaultLangSys = sfnt_get_ushort(sfont);
00290   len  = 2;
00291   len += clt_read_record_list(&tab->LangSysRecord, sfont);
00292 
00293   return len;
00294 }
00295 
00296 static void
00297 clt_release_script_table (struct clt_script_table *tab)
00298 {
00299   if (tab)
00300     clt_release_record_list(&tab->LangSysRecord);
00301 }
00302 
00303 /* LangSys Table */
00304 struct clt_langsys_table
00305 {
00306   Offset LookupOrder;     /* reserved */
00307   USHORT ReqFeatureIndex;
00308   struct clt_number_list FeatureIndex; /* Array of indices into the
00309                                         * FeatureList in arbitary order.
00310                                         */
00311 };
00312 
00313 static long
00314 clt_read_langsys_table (struct clt_langsys_table *tab, sfnt *sfont)
00315 {
00316   long len;
00317 
00318   ASSERT(tab && sfont);
00319 
00320   tab->LookupOrder     = sfnt_get_ushort(sfont);
00321   tab->ReqFeatureIndex = sfnt_get_ushort(sfont);
00322   len  = 4;
00323   len += clt_read_number_list(&tab->FeatureIndex, sfont);
00324 
00325   return len;
00326 }
00327 
00328 static void
00329 clt_release_langsys_table (struct clt_langsys_table *tab)
00330 {
00331   if (tab)
00332     clt_release_number_list(&tab->FeatureIndex);
00333 }
00334 
00335 
00336 /* Feature Table */
00337 struct clt_feature_table
00338 {
00339   Offset FeatureParams;
00340   struct clt_number_list LookupListIndex; /* LookupListIndex List */
00341 };
00342 
00343 static long
00344 clt_read_feature_table (struct clt_feature_table *tab, sfnt *sfont)
00345 {
00346   long len;
00347 
00348   ASSERT(tab && sfont);
00349 
00350   tab->FeatureParams = sfnt_get_ushort(sfont);
00351   len  = 2;
00352   len += clt_read_number_list(&tab->LookupListIndex, sfont);
00353 
00354   return len;
00355 }
00356 
00357 static void
00358 clt_release_feature_table (struct clt_feature_table *tab)
00359 {
00360   if (tab)
00361     clt_release_number_list(&tab->LookupListIndex);
00362 }
00363 
00364 /* Lookup Table:
00365  * Currently, only single substitution is supported.
00366  * LookupFlag is ignored.
00367  */
00368 struct clt_lookup_table
00369 {
00370   USHORT LookupType; /* Different enumerations for GSUB and GPOS */
00371   USHORT LookupFlag; /* Lookup qualifiers */
00372   struct clt_number_list SubTableList; /* offset */
00373   /* offset is from beginning of Lookup table */
00374 };
00375 
00376 static long
00377 clt_read_lookup_table (struct clt_lookup_table *tab, sfnt *sfont)
00378 {
00379   long len;
00380 
00381   ASSERT(tab && sfont);
00382 
00383   tab->LookupType = sfnt_get_ushort(sfont);
00384   tab->LookupFlag = sfnt_get_ushort(sfont);
00385   len  = 4;
00386   len += clt_read_number_list(&tab->SubTableList, sfont);
00387 
00388   return len;
00389 }
00390 
00391 static void
00392 clt_release_lookup_table (struct clt_lookup_table *tab)
00393 {
00394   if (tab)
00395     clt_release_number_list(&tab->SubTableList);
00396 }
00397 
00398 static long
00399 clt_read_coverage (struct clt_coverage *cov, sfnt *sfont)
00400 {
00401   long len, i;
00402 
00403   ASSERT(cov && sfont);
00404 
00405   cov->format = sfnt_get_ushort(sfont);
00406   cov->count  = sfnt_get_ushort(sfont);
00407   len = 4;
00408 
00409   switch (cov->format) {
00410   case 1: /* list */
00411     if (cov->count == 0)
00412       cov->list = NULL;
00413     else {
00414       cov->list = NEW(cov->count, USHORT);
00415       for (i = 0; i < cov->count; i++) {
00416         cov->list[i] = sfnt_get_ushort(sfont);
00417       }
00418     }
00419     cov->range = NULL;
00420     len += 2 * cov->count;
00421     break;
00422   case 2: /* range */
00423     if (cov->count == 0)
00424       cov->range = NULL;
00425     else {
00426       cov->range = NEW(cov->count, struct clt_range);
00427       for (i = 0; i < cov->count; i++) {
00428         len += clt_read_range(&(cov->range[i]), sfont);
00429       }
00430     }
00431     cov->list = NULL;
00432     break;
00433   default:
00434     ERROR("Unknown coverage format");
00435   }
00436 
00437   return len;
00438 }
00439 
00440 static void
00441 clt_release_coverage (struct clt_coverage *cov)
00442 {
00443   if (cov) {
00444     switch (cov->format) {
00445     case 1: /* list */
00446       if (cov->list)
00447         RELEASE(cov->list);
00448       cov->list = NULL;
00449       break;
00450     case 2: /* range */
00451       if (cov->range)
00452         RELEASE(cov->range);
00453       cov->range = NULL;
00454       break;
00455     default:
00456       ERROR("Unknown coverage format");
00457     }
00458   }
00459   cov->count = 0;
00460 }
00461 
00462 /* returns -1 if not found */
00463 static long
00464 clt_lookup_coverage (struct clt_coverage *cov, USHORT gid)
00465 {
00466   long i;
00467 
00468   ASSERT(cov);
00469 
00470   switch (cov->format) {
00471   case 1: /* list */
00472     for (i = 0; i < cov->count; i++) {
00473       if (cov->list[i] > gid) {
00474         break;
00475       } else if (cov->list[i] == gid) {
00476         return i; /* found */
00477       }
00478     }
00479     break;
00480   case 2: /* range */
00481     for (i = 0; i < cov->count; i++) {
00482       if (gid < cov->range[i].Start) {
00483         break;
00484       } else if (gid <= cov->range[i].End) { /* found */
00485         return (cov->range[i].StartCoverageIndex +
00486                 gid - cov->range[i].Start);
00487       }
00488     }
00489     break;
00490   default:
00491     ERROR("Unknown coverage format");
00492   }
00493 
00494   return -1; /* not found */
00495 }
00496 
00497 static long
00498 otl_gsub_read_single (struct otl_gsub_subtab *subtab, sfnt *sfont)
00499 {
00500   long   len;
00501   ULONG  offset;     /* not Offset which is USHORT */
00502   Offset cov_offset; /* subtable offset, offset to Coverage table */
00503 
00504   ASSERT(subtab && sfont);
00505 
00506   offset = tell_position(sfont->stream);
00507 
00508   subtab->LookupType  = OTL_GSUB_TYPE_SINGLE;
00509   subtab->SubstFormat = sfnt_get_ushort(sfont);
00510   len = 2;
00511 
00512   if (subtab->SubstFormat == 1) {
00513     struct otl_gsub_single1 *data;
00514 
00515     subtab->table.single1 = data = NEW(1, struct otl_gsub_single1);
00516     cov_offset         = sfnt_get_ushort(sfont);
00517     data->DeltaGlyphID = sfnt_get_short(sfont);
00518     len += 4;
00519 
00520     sfnt_seek_set(sfont, offset + cov_offset);
00521     len += clt_read_coverage(&data->coverage, sfont);
00522 
00523   } else if (subtab->SubstFormat == 2) {
00524     struct otl_gsub_single2 *data;
00525     USHORT count;
00526 
00527     subtab->table.single2 = data = NEW(1, struct otl_gsub_single2);
00528     cov_offset       = sfnt_get_ushort(sfont);
00529     data->GlyphCount = sfnt_get_ushort(sfont);
00530     len += 4;
00531 
00532     if (data->GlyphCount == 0)
00533       data->Substitute = NULL;
00534     else {
00535       data->Substitute = NEW(data->GlyphCount, GlyphID);
00536       for (count = 0; count < data->GlyphCount; count++) {
00537         data->Substitute[count] = sfnt_get_ushort(sfont);
00538       }
00539       len += 2 * data->GlyphCount;
00540     }
00541 
00542     sfnt_seek_set(sfont, offset + cov_offset);
00543     len += clt_read_coverage(&data->coverage, sfont);
00544 
00545   } else {
00546     ERROR("unexpected SubstFormat");
00547   }
00548   /* not implemented yet */
00549 
00550   return len;
00551 }
00552 
00553 static long
00554 otl_gsub_read_alternate (struct otl_gsub_subtab *subtab, sfnt *sfont)
00555 {
00556   long   len;
00557   USHORT i, j;
00558   ULONG  offset;     /* not Offset which is USHORT */
00559   Offset cov_offset; /* subtable offset, offset to Coverage table */
00560   struct clt_number_list      altset_offsets;
00561   struct otl_gsub_alternate1 *data;
00562 
00563   ASSERT(subtab && sfont);
00564 
00565   offset = tell_position(sfont->stream);
00566 
00567   subtab->LookupType  = OTL_GSUB_TYPE_ALTERNATE;
00568   subtab->SubstFormat = sfnt_get_ushort(sfont); /* Must be 1 */
00569   if (subtab->SubstFormat != 1) {
00570     WARN("Unknown GSUB SubstFormat for Alternate: %u",
00571          subtab->SubstFormat);
00572     return -1;
00573   }
00574 
00575   len  = 2;
00576   subtab->table.alternate1 =
00577     data = NEW(1, struct otl_gsub_alternate1);
00578 
00579   cov_offset        = sfnt_get_ushort(sfont);
00580   len += 2;
00581   len += clt_read_number_list(&altset_offsets, sfont);
00582   data->AlternateSetCount = altset_offsets.count;
00583   if (data->AlternateSetCount == 0) {
00584     data->AlternateSet    = NULL;
00585     data->coverage.count  = 0;
00586     data->coverage.format = 0;
00587     data->coverage.list   = NULL;
00588     return  len;
00589   }
00590   data->AlternateSet = NEW(data->AlternateSetCount,
00591                            struct otl_gsub_altset);
00592   for (i = 0; i < data->AlternateSetCount; i++) {
00593     struct otl_gsub_altset *altset;
00594     ULONG  altset_offset;
00595 
00596     altset = &(data->AlternateSet[i]);
00597 
00598     altset_offset = offset + altset_offsets.value[i];
00599     sfnt_seek_set(sfont, altset_offset);
00600     altset->GlyphCount = sfnt_get_ushort(sfont);
00601     len += 2;
00602     if (altset->GlyphCount == 0) {
00603       altset->Alternate = NULL;
00604       break;
00605     }
00606     altset->Alternate = NEW(altset->GlyphCount, GlyphID);
00607     for (j = 0; j < altset->GlyphCount; j++) {
00608       altset->Alternate[j] = sfnt_get_ushort(sfont);
00609       len += 2;
00610     }
00611   }
00612   clt_release_number_list(&altset_offsets);
00613 
00614   sfnt_seek_set(sfont, offset + cov_offset);
00615   len += clt_read_coverage(&data->coverage, sfont);
00616 
00617   return  len;
00618 }
00619 
00620 static long
00621 otl_gsub_read_ligature (struct otl_gsub_subtab *subtab, sfnt *sfont)
00622 {
00623   long   len;
00624   USHORT i, j;
00625   ULONG  offset;     /* not Offset which is USHORT */
00626   Offset cov_offset; /* subtable offset, offset to Coverage table */
00627   struct clt_number_list     ligset_offsets;
00628   struct otl_gsub_ligature1 *data;
00629 
00630   ASSERT(subtab && sfont);
00631 
00632   offset = tell_position(sfont->stream);
00633 
00634   subtab->LookupType  = OTL_GSUB_TYPE_LIGATURE;
00635   subtab->SubstFormat = sfnt_get_ushort(sfont); /* Must be 1 */
00636   if (subtab->SubstFormat != 1) {
00637     WARN("Unknown GSUB SubstFormat for Ligature: %u",
00638          subtab->SubstFormat);
00639     return -1;
00640   }
00641 
00642   len  = 2;
00643   subtab->table.ligature1 =
00644     data = NEW(1, struct otl_gsub_ligature1);
00645 
00646   cov_offset        = sfnt_get_ushort(sfont);
00647   len += 2;
00648   len += clt_read_number_list(&ligset_offsets, sfont);
00649   data->LigSetCount = ligset_offsets.count;
00650   if (data->LigSetCount == 0) {
00651     data->LigatureSet    = NULL;
00652     data->coverage.count  = 0;
00653     data->coverage.format = 0;
00654     data->coverage.list   = NULL;
00655     return len;
00656   }
00657   data->LigatureSet = NEW(data->LigSetCount,
00658                           struct otl_gsub_ligset);
00659   for (i = 0; i < data->LigSetCount; i++) {
00660     struct clt_number_list  ligset_tab;
00661     struct otl_gsub_ligset *ligset;
00662     ULONG  ligset_offset;
00663     USHORT count;
00664 
00665     ligset = &(data->LigatureSet[i]);
00666 
00667     ligset_offset = offset + ligset_offsets.value[i];
00668     sfnt_seek_set(sfont, ligset_offset);
00669     len += clt_read_number_list(&ligset_tab, sfont);
00670 
00671     ligset->LigatureCount = ligset_tab.count;
00672     if (ligset_tab.count == 0) {
00673       ligset->Ligature = NULL;
00674       break;
00675     }
00676     ligset->Ligature = NEW(ligset_tab.count,
00677                            struct otl_gsub_ligtab);
00678     for (j = 0; j < ligset_tab.count; j++) {
00679       sfnt_seek_set(sfont, ligset_offset + ligset_tab.value[j]);
00680       ligset->Ligature[j].LigGlyph = sfnt_get_ushort(sfont);
00681       ligset->Ligature[j].CompCount = sfnt_get_ushort(sfont);
00682       if (ligset->Ligature[j].CompCount == 0) {
00683         ligset->Ligature[j].Component = NULL;
00684         break;
00685       }
00686       ligset->Ligature[j].Component =
00687         NEW(ligset->Ligature[j].CompCount - 1, GlyphID);
00688       for (count = 0;
00689            count < ligset->Ligature[j].CompCount - 1; count++) {
00690         ligset->Ligature[j].Component[count] = sfnt_get_ushort(sfont);
00691       }
00692       len += 4 + count * 2;
00693     }
00694     clt_release_number_list(&ligset_tab);
00695   }
00696   clt_release_number_list(&ligset_offsets);
00697 
00698   sfnt_seek_set(sfont, offset + cov_offset);
00699   len += clt_read_coverage(&data->coverage, sfont);
00700 
00701   return len;
00702 }
00703 
00704 static void
00705 otl_gsub_release_single (struct otl_gsub_subtab *subtab)
00706 {
00707   if (subtab) {
00708     switch((int) subtab->SubstFormat) {
00709     case 1:
00710       {
00711         struct otl_gsub_single1 *data;
00712 
00713         data = subtab->table.single1;
00714         if (data) {
00715           clt_release_coverage(&data->coverage);
00716           RELEASE(data);
00717         }
00718         subtab->table.single1 = NULL;
00719       }
00720     break;
00721     case 2:
00722       {
00723         struct otl_gsub_single2 *data;
00724 
00725         data = subtab->table.single2;
00726         if (data) {
00727           if (data->Substitute)
00728             RELEASE(data->Substitute);
00729           clt_release_coverage(&data->coverage);
00730           RELEASE(data);
00731         }
00732         subtab->table.single2 = NULL;
00733       }
00734     break;
00735     default:
00736       ERROR("Unknown format for single substitution");
00737     }
00738   }
00739 }
00740 
00741 static void
00742 otl_gsub_release_ligature (struct otl_gsub_subtab *subtab)
00743 {
00744   if (subtab) {
00745     struct otl_gsub_ligature1 *data;
00746     USHORT i, j;
00747 
00748     data = subtab->table.ligature1;
00749     if (data && data->LigatureSet) {
00750       for (i = 0; i < data->LigSetCount; i++) {
00751         struct otl_gsub_ligset *ligset;
00752 
00753         ligset = &(data->LigatureSet[i]);
00754         for (j = 0;
00755              j < ligset->LigatureCount; j++) {
00756           if (ligset->Ligature[j].Component)
00757             RELEASE(ligset->Ligature[j].Component);
00758           ligset->Ligature[j].Component = NULL;
00759         }
00760         RELEASE(ligset->Ligature);
00761         ligset->Ligature = NULL;
00762       }
00763       RELEASE(data->LigatureSet);
00764     }
00765     clt_release_coverage(&data->coverage);
00766     data->LigatureSet = NULL;
00767     RELEASE(data);
00768     subtab->table.ligature1 = NULL;
00769   }
00770 }
00771 
00772 static void
00773 otl_gsub_release_alternate (struct otl_gsub_subtab *subtab)
00774 {
00775   if (subtab) {
00776     struct otl_gsub_alternate1 *data;
00777     USHORT i;
00778 
00779     data = subtab->table.alternate1;
00780     if (data && data->AlternateSet) {
00781       for (i = 0; i < data->AlternateSetCount; i++) {
00782         struct otl_gsub_altset *altset;
00783 
00784         altset = &(data->AlternateSet[i]);
00785         if (altset->Alternate)
00786           RELEASE(altset->Alternate);
00787         altset->Alternate = NULL;
00788       }
00789       RELEASE(data->AlternateSet);
00790     }
00791     clt_release_coverage(&data->coverage);
00792     data->AlternateSet = NULL;
00793     RELEASE(data);
00794     subtab->table.alternate1 = NULL;
00795   }
00796 }
00797 
00798 static long
00799 otl_gsub_read_header (struct otl_gsub_header *head, sfnt *sfont)
00800 {
00801   ASSERT(head && sfont);
00802 
00803   head->version     = sfnt_get_ulong (sfont);
00804   head->ScriptList  = sfnt_get_ushort(sfont);
00805   head->FeatureList = sfnt_get_ushort(sfont);
00806   head->LookupList  = sfnt_get_ushort(sfont);
00807 
00808   return 10;
00809 }
00810 
00811 /*
00812  * script -- langsys --> feature indices
00813  *        |
00814  *        +- langsys --> feature indices
00815  *
00816  * feature --> lookup indices
00817  */
00818 
00819 struct otl_gsub_tab
00820 {
00821   char *script;
00822   char *language;
00823   char *feature;
00824 
00825   int    num_subtables;
00826   struct otl_gsub_subtab *subtables;
00827 };
00828 
00829 
00830 static int
00831 otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont)
00832 {
00833   long   feat_idx, script_idx;
00834   ULONG  gsub_offset, offset;
00835   struct otl_gsub_header  head;
00836   struct otl_gsub_subtab *subtab = NULL;
00837   USHORT num_subtabs = 0;
00838   unsigned char feat_bits[8192];
00839   struct clt_record_list feature_list;
00840   struct clt_record_list script_list;
00841   struct clt_number_list lookup_list ;
00842   otl_opt *script, *language, *feature;
00843 
00844   ASSERT(gsub && sfont);
00845 
00846   gsub_offset = sfnt_find_table_pos(sfont, "GSUB");
00847   if (gsub_offset == 0)
00848     return -1; /* not found */
00849 
00850   script   = otl_new_opt();
00851   otl_parse_optstring(script,   gsub->script);
00852   language = otl_new_opt();
00853   otl_parse_optstring(language, gsub->language);
00854   feature  = otl_new_opt();
00855   otl_parse_optstring(feature,  gsub->feature);
00856 
00857   memset(feat_bits, 0, 8192);
00858 
00859   /* GSUB header */
00860   sfnt_seek_set(sfont, gsub_offset);
00861   otl_gsub_read_header(&head, sfont);
00862 
00863   /* Script */
00864   offset = gsub_offset + head.ScriptList;
00865   sfnt_seek_set(sfont, offset);
00866   clt_read_record_list(&script_list, sfont);
00867 
00868 #define SET_BIT(b,p) do {\
00869   (b)[(p)/8] |= (1<<(7-((p) % 8)));\
00870 } while (0)
00871 #define BIT_SET(b,p) (((b)[(p)/8]) & (1 << (7-((p)%8))))
00872 
00873   for (script_idx = 0;
00874        script_idx < script_list.count; script_idx++) {
00875     if (otl_match_optrule(script,
00876                           script_list.record[script_idx].tag)) {
00877       struct clt_script_table script_tab;
00878       long   langsys_idx;
00879 
00880       offset = gsub_offset +
00881         head.ScriptList + script_list.record[script_idx].offset;
00882       sfnt_seek_set(sfont, offset);
00883       clt_read_script_table(&script_tab, sfont);
00884 
00885       if (otl_match_optrule(language, "dflt") &&
00886           script_tab.DefaultLangSys != 0) { 
00887         struct clt_langsys_table langsys_tab;
00888 
00889         if(verbose > VERBOSE_LEVEL_MIN) {
00890           MESG("otl_gsub>> OTL script-language enabled: %c%c%c%c.dflt\n",
00891                script_list.record[script_idx].tag[0],
00892                script_list.record[script_idx].tag[1],
00893                script_list.record[script_idx].tag[2],
00894                script_list.record[script_idx].tag[3]);
00895         }
00896 
00897         sfnt_seek_set(sfont, offset + script_tab.DefaultLangSys);
00898         clt_read_langsys_table(&langsys_tab, sfont);
00899         if (otl_match_optrule(feature, "____") && /* _FIXME_ */
00900             langsys_tab.ReqFeatureIndex != 0xFFFF)
00901           SET_BIT(feat_bits, langsys_tab.ReqFeatureIndex);
00902         for (feat_idx = 0;
00903              feat_idx < langsys_tab.FeatureIndex.count;
00904              feat_idx++) {
00905           SET_BIT(feat_bits,
00906                   langsys_tab.FeatureIndex.value[feat_idx]);
00907         }
00908         clt_release_langsys_table(&langsys_tab);
00909       }
00910       for (langsys_idx = 0;
00911            langsys_idx < script_tab.LangSysRecord.count;
00912            langsys_idx++) {
00913         struct clt_record  *langsys_rec;
00914 
00915         langsys_rec = &(script_tab.LangSysRecord.record[langsys_idx]);
00916         if (otl_match_optrule(language, langsys_rec->tag)) {
00917           struct clt_langsys_table langsys_tab;
00918 
00919           if(verbose > VERBOSE_LEVEL_MIN) {
00920             MESG("otl_gsub>> OTL script-language enabled: %c%c%c%c.%c%c%c%c\n",
00921                  script_list.record[script_idx].tag[0],
00922                  script_list.record[script_idx].tag[1],
00923                  script_list.record[script_idx].tag[2],
00924                  script_list.record[script_idx].tag[3],
00925                  langsys_rec->tag[0], langsys_rec->tag[1],
00926                  langsys_rec->tag[2], langsys_rec->tag[3]);
00927           }
00928 
00929           sfnt_seek_set(sfont, offset + langsys_rec->offset);
00930           clt_read_langsys_table(&langsys_tab, sfont);
00931           if (otl_match_optrule(feature, "____") || /* _FIXME_ */
00932               langsys_tab.ReqFeatureIndex != 0xFFFF)
00933             SET_BIT(feat_bits, langsys_tab.ReqFeatureIndex);
00934           for (feat_idx = 0;
00935                feat_idx < langsys_tab.FeatureIndex.count;
00936                feat_idx++) {
00937             SET_BIT(feat_bits,
00938                     langsys_tab.FeatureIndex.value[feat_idx]);
00939           }
00940           clt_release_langsys_table(&langsys_tab);
00941         }
00942       }
00943       clt_release_script_table(&script_tab);
00944     }
00945   }
00946 
00947   /* Feature List */
00948   offset = gsub_offset + head.FeatureList;
00949   sfnt_seek_set(sfont, offset);
00950   clt_read_record_list(&feature_list, sfont);
00951 
00952   /* Lookup List */
00953   offset = gsub_offset + head.LookupList;
00954   sfnt_seek_set(sfont, offset);
00955   clt_read_number_list(&lookup_list, sfont);
00956 
00957   if(verbose > VERBOSE_LEVEL_MIN) {
00958     MESG("otl_gsub>> Reading OTL feature(s):");
00959   }
00960 
00961   for (feat_idx = 0;
00962        feat_idx < feature_list.count; feat_idx++) {
00963     if (BIT_SET(feat_bits, feat_idx)  &&
00964         (otl_match_optrule(feature,
00965                            feature_list.record[feat_idx].tag))) {
00966       struct clt_feature_table feature_table;
00967       long   i;
00968 
00969       if(verbose > VERBOSE_LEVEL_MIN) {
00970         MESG(" %c%c%c%c",
00971              feature_list.record[feat_idx].tag[0],
00972              feature_list.record[feat_idx].tag[1],
00973              feature_list.record[feat_idx].tag[2],
00974              feature_list.record[feat_idx].tag[3]);
00975       }
00976 
00977       /* Feature Table */
00978       offset = gsub_offset +
00979         head.FeatureList + feature_list.record[feat_idx].offset;
00980 
00981       sfnt_seek_set(sfont, offset);
00982       clt_read_feature_table(&feature_table, sfont);
00983       if (feature_table.FeatureParams != 0) {
00984         ERROR("unrecognized FeatureParams");
00985       }
00986 
00987       /* Lookup table */
00988       for (i = 0; i < feature_table.LookupListIndex.count; i++) {
00989         struct clt_lookup_table lookup_table;
00990         long ll_idx, st_idx, r, n_st;
00991 
00992         ll_idx = feature_table.LookupListIndex.value[i];
00993         if (ll_idx >= lookup_list.count)
00994           ERROR("invalid Lookup index.");
00995 
00996         offset = gsub_offset +
00997           head.LookupList + (lookup_list.value)[ll_idx];
00998         sfnt_seek_set(sfont, offset);
00999         clt_read_lookup_table(&lookup_table, sfont);
01000 
01001         if (lookup_table.LookupType != OTL_GSUB_TYPE_SINGLE    &&
01002             lookup_table.LookupType != OTL_GSUB_TYPE_ALTERNATE &&
01003             lookup_table.LookupType != OTL_GSUB_TYPE_LIGATURE  &&
01004             lookup_table.LookupType != OTL_GSUB_TYPE_ESUBST) {
01005           if (verbose > VERBOSE_LEVEL_MIN)
01006             WARN("Skipping unsupported GSUB subtable: LookupType=%d", lookup_table.LookupType);
01007           continue;
01008         }
01009 
01010         subtab = RENEW(subtab,
01011                        num_subtabs + lookup_table.SubTableList.count,
01012                        struct otl_gsub_subtab);
01013         for (n_st = 0, st_idx = 0;
01014              st_idx < lookup_table.SubTableList.count; st_idx++) {
01015 
01016           offset = gsub_offset + head.LookupList +
01017             lookup_list.value[ll_idx] +
01018             (lookup_table.SubTableList.value)[st_idx];
01019 
01020           sfnt_seek_set(sfont, offset);
01021 
01022           switch ((int) lookup_table.LookupType) {
01023           case OTL_GSUB_TYPE_SINGLE:
01024             r = otl_gsub_read_single(&subtab[num_subtabs + n_st],
01025                                      sfont);
01026             if (r <= 0)
01027               WARN("Reading GSUB subtable (single) failed...");
01028             else {
01029               if(verbose > VERBOSE_LEVEL_MIN) {
01030                 MESG("(single)");
01031               }
01032               n_st++;
01033             }
01034             break;
01035 
01036           case OTL_GSUB_TYPE_ALTERNATE:
01037             r = otl_gsub_read_alternate(&subtab[num_subtabs + n_st],
01038                                         sfont);
01039             if (r <= 0)
01040               WARN("Reading GSUB subtable (alternate) failed...");
01041             else {
01042               if(verbose > VERBOSE_LEVEL_MIN) {
01043                 MESG("(alternate)");
01044               }
01045               n_st++;
01046             }
01047             break;
01048 
01049           case OTL_GSUB_TYPE_LIGATURE:
01050             r = otl_gsub_read_ligature(&subtab[num_subtabs + n_st],
01051                                        sfont);
01052             if (r <= 0)
01053               WARN("Reading GSUB subtable (ligature) failed...");
01054             else {
01055               if(verbose > VERBOSE_LEVEL_MIN) {
01056                 MESG("(ligature)");
01057               }
01058               n_st++;
01059             }
01060             break;
01061 
01062           case OTL_GSUB_TYPE_ESUBST:
01063             {
01064               USHORT  SubstFormat;
01065               USHORT  ExtensionLookupType;
01066               ULONG   ExtensionOffset;
01067 
01068               SubstFormat = sfnt_get_ushort(sfont);
01069               if (SubstFormat != 1)
01070                 break;
01071               ExtensionLookupType = sfnt_get_ushort(sfont);
01072               ExtensionOffset     = sfnt_get_ulong (sfont);
01073 
01074               sfnt_seek_set(sfont, offset + ExtensionOffset);
01075               switch (ExtensionLookupType) {
01076               case OTL_GSUB_TYPE_SINGLE:
01077                 r = otl_gsub_read_single(&subtab[num_subtabs + n_st],
01078                                          sfont);
01079                 if (r <= 0)
01080                   WARN("Reading GSUB subtable (ext:single) failed...");
01081                 else {
01082                   if(verbose > VERBOSE_LEVEL_MIN) {
01083                     MESG("(ext:single)");
01084                   }
01085                   n_st++;
01086                 }
01087                 break;
01088 
01089               case OTL_GSUB_TYPE_ALTERNATE:
01090                 r = otl_gsub_read_alternate(&subtab[num_subtabs + n_st],
01091                                             sfont);
01092                 if (r <= 0)
01093                   WARN("Reading GSUB subtable (alternate) failed...");
01094                 else {
01095                   if(verbose > VERBOSE_LEVEL_MIN) {
01096                     MESG("(alternate)");
01097                   }
01098                   n_st++;
01099                 }
01100               break;
01101 
01102               case OTL_GSUB_TYPE_LIGATURE:
01103                 r = otl_gsub_read_ligature(&subtab[num_subtabs + n_st],
01104                                            sfont);
01105                 if (r <= 0)
01106                   WARN("Reading GSUB subtable (ext:ligature) failed...");
01107                 else {
01108                   if(verbose > VERBOSE_LEVEL_MIN) {
01109                     MESG("(ext:ligature)");
01110                   }
01111                   n_st++;
01112                 }
01113                 break;
01114 
01115               }
01116             }
01117             break;
01118 
01119           default:
01120             break;
01121           }
01122         }
01123         num_subtabs += n_st; /* lookup_table.SubTableList.count; */
01124         clt_release_lookup_table(&lookup_table);
01125       }
01126       clt_release_feature_table(&feature_table);
01127     }
01128   }
01129 
01130   if(verbose > VERBOSE_LEVEL_MIN) {
01131     MESG("\n");
01132     MESG("otl_gsub>> %ld subtable(s) read.\n", num_subtabs);
01133   }
01134 
01135   clt_release_number_list(&lookup_list);
01136   clt_release_record_list(&feature_list);
01137   clt_release_record_list(&script_list);
01138 
01139   otl_release_opt(script);
01140   otl_release_opt(language);
01141   otl_release_opt(feature);
01142 
01143   if (subtab != NULL) {
01144     gsub->num_subtables = num_subtabs;
01145     gsub->subtables     = subtab;
01146   } else {
01147     return -1;
01148   }
01149 
01150   return 0;
01151 }
01152 
01153 
01154 static int
01155 otl_gsub_apply_single (struct otl_gsub_subtab *subtab, USHORT *gid)
01156 {
01157   long idx;
01158 
01159   ASSERT(subtab && gid);
01160 
01161   if (subtab->SubstFormat == 1) {
01162     struct otl_gsub_single1 *data;
01163 
01164     data = (subtab->table).single1;
01165     idx  = clt_lookup_coverage(&data->coverage, *gid);
01166     if (idx >= 0) {
01167       *gid += data->DeltaGlyphID;
01168       return 0; /* found */
01169     }
01170   } else if (subtab->SubstFormat == 2) {
01171     struct otl_gsub_single2 *data;
01172 
01173     data = (subtab->table).single2;
01174     idx  = clt_lookup_coverage(&data->coverage, *gid);
01175     if (idx >= 0 &&
01176         idx < data->GlyphCount) {
01177       *gid = (data->Substitute)[idx];
01178       return 0; /* found */
01179     }
01180   }
01181 
01182   return -1;
01183 }
01184 
01185 static int
01186 otl_gsub_apply_alternate (struct otl_gsub_subtab *subtab,
01187                           USHORT alt_idx, USHORT *gid)
01188 {
01189   long  idx;
01190 
01191   ASSERT(subtab && gid);
01192 
01193   if (subtab->SubstFormat == 1) {
01194     struct otl_gsub_alternate1 *data;
01195 
01196     data = subtab->table.alternate1;
01197     idx  = clt_lookup_coverage(&data->coverage, *gid);
01198     if (idx < 0 || idx >= data->AlternateSetCount)
01199       return  -1;
01200     else {
01201       struct otl_gsub_altset *altset;
01202       altset = &(data->AlternateSet[idx]);
01203       if (alt_idx >= altset->GlyphCount)
01204         return  -1;
01205       else {
01206         *gid = altset->Alternate[alt_idx];
01207         return  0;
01208       }
01209     }
01210   }
01211 
01212   return -1;
01213 }
01214 
01215 /* NOTE: Ligature table is in preference order */
01216 static int
01217 glyph_seq_cmp (GlyphID *glyph_seq0, USHORT n_glyphs0,
01218                GlyphID *glyph_seq1, USHORT n_glyphs1)
01219 {
01220   USHORT i;
01221 
01222   if (n_glyphs0 != n_glyphs1)
01223     return n_glyphs0 - n_glyphs1;
01224 
01225   for (i = 0; i < n_glyphs0; i++) {
01226     if (glyph_seq0[i] != glyph_seq1[i])
01227       return glyph_seq0[i] - glyph_seq1[i];
01228   }
01229 
01230   return 0;
01231 }
01232 
01233 static int
01234 otl_gsub_apply_ligature (struct otl_gsub_subtab *subtab,
01235                          USHORT *gid_in,  USHORT num_gids,
01236                          USHORT *gid_out)
01237 {
01238   long idx;
01239 
01240   ASSERT(subtab && gid_out);
01241 
01242   if (!gid_in || num_gids < 1)
01243     return -1;
01244 
01245   if (subtab->SubstFormat == 1) {
01246     struct otl_gsub_ligature1 *data;
01247 
01248     data = subtab->table.ligature1;
01249     idx  = clt_lookup_coverage(&data->coverage, gid_in[0]);
01250     if (idx >= 0 && idx < data->LigSetCount) {
01251       struct otl_gsub_ligset *ligset;
01252       USHORT j;
01253 
01254       ligset = &(data->LigatureSet[idx]);
01255       for (j = 0; j < ligset->LigatureCount; j++) {
01256         if (!glyph_seq_cmp(&gid_in[1], num_gids - 1,
01257                            ligset->Ligature[j].Component,
01258                            ligset->Ligature[j].CompCount - 1)) {
01259           *gid_out = ligset->Ligature[j].LigGlyph;
01260           return 0; /* found */
01261         }
01262       }
01263     }
01264   }
01265 
01266   return -1;
01267 }
01268 
01269 #define GSUB_LIST_MAX 32
01270 struct otl_gsub
01271 {
01272   int num_gsubs;
01273   int select;
01274   struct otl_gsub_tab gsubs[GSUB_LIST_MAX];
01275 };
01276 
01277 otl_gsub *
01278 otl_gsub_new (void)
01279 {
01280   struct otl_gsub *gsub_list;
01281 
01282   gsub_list = NEW(1, struct otl_gsub);
01283   gsub_list->num_gsubs = 0;
01284   gsub_list->select    = -1;
01285 
01286   return (otl_gsub *) gsub_list;
01287 }
01288 
01289 int
01290 otl_gsub_add_feat (otl_gsub *gsub_list,
01291                    const char *script,
01292                    const char *language,
01293                    const char *feature,
01294                    sfnt *sfont)
01295 {
01296   int    retval = -1;
01297   int    i;
01298   struct otl_gsub_tab *gsub;
01299 
01300   if (gsub_list->num_gsubs > GSUB_LIST_MAX) {
01301     ERROR("Too many GSUB features...");
01302     return -1;
01303   }
01304   for (i = 0; i < gsub_list->num_gsubs; i++) {
01305     gsub = &(gsub_list->gsubs[i]);
01306     if (!strcmp(script,   gsub->script)   &&
01307         !strcmp(language, gsub->language) &&
01308         !strcmp(feature,  gsub->feature)) {
01309       gsub_list->select = i;
01310       return 0;
01311     }
01312   }
01313   gsub = &gsub_list->gsubs[i];
01314 
01315   gsub->script   = NEW(strlen(script)  +1, char);
01316   strcpy(gsub->script,   script);
01317   gsub->language = NEW(strlen(language)+1, char);
01318   strcpy(gsub->language, language);
01319   gsub->feature  = NEW(strlen(feature) +1, char);
01320   strcpy(gsub->feature,  feature);
01321 
01322   if(verbose > VERBOSE_LEVEL_MIN) {
01323     MESG("\n");
01324     MESG("otl_gsub>> Reading \"%s.%s.%s\"...\n", script, language, feature);
01325   }
01326 
01327   retval = otl_gsub_read_feat(gsub, sfont);
01328   if (retval >= 0) {
01329     gsub_list->select = i;
01330     gsub_list->num_gsubs++;
01331   } else {
01332     if(verbose > VERBOSE_LEVEL_MIN) {
01333       MESG("otl_gsub>> Failed\n");
01334     }
01335     RELEASE(gsub->script);
01336     RELEASE(gsub->language);
01337     RELEASE(gsub->feature);
01338   }
01339   
01340   return retval;
01341 }
01342 
01343 void
01344 otl_gsub_release (otl_gsub *gsub_list)
01345 {
01346   struct otl_gsub_tab    *gsub;
01347   struct otl_gsub_subtab *subtab;
01348   int    i, j;
01349 
01350   if (!gsub_list)
01351     return;
01352 
01353   for (i = 0; i < gsub_list->num_gsubs; i++) {
01354     gsub = &(gsub_list->gsubs[i]);
01355 
01356     if (gsub->script)
01357       RELEASE(gsub->script);
01358     if (gsub->language)
01359       RELEASE(gsub->language);
01360     if (gsub->feature)
01361       RELEASE(gsub->feature);
01362 
01363     for (j = 0; j < gsub->num_subtables; j++) {
01364       subtab = &(gsub->subtables[j]);
01365       switch ((int) subtab->LookupType) {
01366       case OTL_GSUB_TYPE_SINGLE:
01367         otl_gsub_release_single(subtab);
01368         break;
01369       case OTL_GSUB_TYPE_ALTERNATE:
01370         otl_gsub_release_alternate(subtab);
01371         break;
01372       case OTL_GSUB_TYPE_LIGATURE:
01373         otl_gsub_release_ligature(subtab);
01374         break;
01375       default:
01376         ERROR("???");
01377         break;
01378       }
01379     }
01380     RELEASE(gsub->subtables);
01381   }
01382 
01383   RELEASE(gsub_list);
01384 }
01385 
01386 int
01387 otl_gsub_apply (otl_gsub *gsub_list, USHORT *gid)
01388 {
01389   int    retval = -1;
01390   struct otl_gsub_tab    *gsub;
01391   struct otl_gsub_subtab *subtab;
01392   int    i, j;
01393 
01394   if (!gsub_list || !gid)
01395     return retval;
01396 
01397   i = gsub_list->select;
01398   if (i < 0 || i >= gsub_list->num_gsubs) {
01399     ERROR("GSUB not selected...");
01400     return -1;
01401   }
01402   gsub = &(gsub_list->gsubs[i]);
01403 
01404   for (j = 0;
01405        retval < 0 && j < gsub->num_subtables; j++) {
01406     subtab = &(gsub->subtables[j]);
01407     switch ((int) subtab->LookupType){
01408     case OTL_GSUB_TYPE_SINGLE:
01409       retval = otl_gsub_apply_single(subtab, gid);
01410       break;
01411     default:
01412       break;
01413     }
01414   }
01415 
01416   return retval;
01417 }
01418 
01419 int
01420 otl_gsub_apply_alt (otl_gsub *gsub_list, USHORT alt_idx, USHORT *gid)
01421 {
01422   int    retval = -1;
01423   struct otl_gsub_tab    *gsub;
01424   struct otl_gsub_subtab *subtab;
01425   int    i, j;
01426 
01427   if (!gsub_list || !gid)
01428     return retval;
01429 
01430   i = gsub_list->select;
01431   if (i < 0 || i >= gsub_list->num_gsubs) {
01432     ERROR("GSUB not selected...");
01433     return -1;
01434   }
01435   gsub = &(gsub_list->gsubs[i]);
01436 
01437   for (j = 0;
01438        retval < 0 && j < gsub->num_subtables; j++) {
01439     subtab = &(gsub->subtables[j]);
01440     switch ((int) subtab->LookupType){
01441     case OTL_GSUB_TYPE_ALTERNATE:
01442       retval = otl_gsub_apply_alternate(subtab, alt_idx, gid);
01443       break;
01444     default:
01445       break;
01446     }
01447   }
01448 
01449   return retval;
01450 }
01451 
01452 int
01453 otl_gsub_apply_lig (otl_gsub *gsub_list,
01454                     USHORT *gid_in, USHORT num_gids, USHORT *gid_out)
01455 {
01456   int    retval = -1;
01457   struct otl_gsub_tab    *gsub;
01458   struct otl_gsub_subtab *subtab;
01459   int    i, j;
01460 
01461   if (!gsub_list || !gid_out)
01462     return retval;
01463 
01464   i = gsub_list->select;
01465   if (i < 0 || i >= gsub_list->num_gsubs) {
01466     ERROR("GSUB not selected...");
01467     return -1;
01468   }
01469   gsub = &(gsub_list->gsubs[i]);
01470 
01471   for (j = 0;
01472        retval < 0 && j < gsub->num_subtables; j++) {
01473     subtab = &(gsub->subtables[j]);
01474     switch ((int) subtab->LookupType){
01475     case OTL_GSUB_TYPE_LIGATURE:
01476       retval = otl_gsub_apply_ligature(subtab,
01477                                        gid_in, num_gids, gid_out);
01478       break;
01479     default:
01480       break;
01481     }
01482   }
01483 
01484   return retval;
01485 }
01486 
01487 int
01488 otl_gsub_select (otl_gsub *gsub_list,
01489                  const char *script,
01490                  const char *language,
01491                  const char *feature)
01492 {
01493   int    i;
01494   struct otl_gsub_tab *gsub;
01495 
01496   for (i = 0; i < gsub_list->num_gsubs; i++) {
01497     gsub = &(gsub_list->gsubs[i]);
01498     if (!strcmp(gsub->script,   script)   &&
01499         !strcmp(gsub->language, language) &&
01500         !strcmp(gsub->feature,  feature)) {
01501       gsub_list->select = i;
01502       return i;
01503     }
01504   }
01505 
01506   gsub_list->select = -1;
01507 
01508   return -1;
01509 }
01510 
01511 #if  0
01512 static int
01513 otl_gsub_dump_single (struct otl_gsub_subtab *subtab)
01514 {
01515   long  gid, idx;
01516 
01517   ASSERT(subtab);
01518 
01519   if (subtab->SubstFormat == 1) {
01520     struct otl_gsub_single1 *data;
01521 
01522     data = (subtab->table).single1;
01523     for (gid = 0; gid < 0x10000; gid++) {
01524       idx  = clt_lookup_coverage(&data->coverage, gid);
01525       if (idx >= 0) {
01526         fprintf(stdout, "substitute \\%u by \\%u;\n",
01527                 (USHORT) gid, (USHORT) (gid + data->DeltaGlyphID));
01528       }
01529     }
01530   } else if (subtab->SubstFormat == 2) {
01531     struct otl_gsub_single2 *data;
01532 
01533     data = (subtab->table).single2;
01534     for (gid = 0; gid < 0x10000; gid++) {
01535       idx  = clt_lookup_coverage(&data->coverage, gid);
01536       if (idx >= 0 &&
01537           idx < data->GlyphCount) {
01538         fprintf(stdout, "substitute \\%u by \\%u;\n",
01539                 (USHORT) gid, (data->Substitute)[idx]);
01540       }
01541     }
01542   }
01543 
01544   return  0;
01545 }
01546 
01547 static int
01548 otl_gsub_dump_alternate (struct otl_gsub_subtab *subtab)
01549 {
01550   long  gid, idx;
01551 
01552   ASSERT(subtab);
01553 
01554   if (subtab->SubstFormat == 1) {
01555     struct otl_gsub_alternate1 *data;
01556 
01557     data = subtab->table.alternate1;
01558     for (gid = 0; gid < 0x10000; gid++) {
01559       idx  = clt_lookup_coverage(&data->coverage, gid);
01560       if (idx >= 0 && idx < data->AlternateSetCount) {
01561         struct otl_gsub_altset *altset;
01562         USHORT i;
01563         altset = &(data->AlternateSet[idx]);
01564         if (altset->GlyphCount == 0)
01565           continue;
01566         fprintf(stdout, "substitute \\%u from [", (USHORT) gid);
01567         for (i = 0; i < altset->GlyphCount; i++) {
01568           fprintf(stdout, " \\%u", altset->Alternate[i]);
01569         }
01570         fprintf(stdout, " ];\n");
01571       }
01572     }
01573   }
01574 
01575   return  0;
01576 }
01577 
01578 static int
01579 otl_gsub_dump_ligature (struct otl_gsub_subtab *subtab)
01580 {
01581   long  gid, idx;
01582 
01583   ASSERT(subtab);
01584 
01585   if (subtab->SubstFormat == 1) {
01586     struct otl_gsub_ligature1 *data;
01587 
01588     data = subtab->table.ligature1;
01589     for (gid = 0; gid < 0x10000; gid++) {
01590       idx  = clt_lookup_coverage(&data->coverage, gid);
01591       if (idx >= 0 && idx < data->LigSetCount) {
01592         struct otl_gsub_ligset *ligset;
01593         USHORT  i, j;
01594         ligset = &(data->LigatureSet[idx]); 
01595         for (j = 0; j < ligset->LigatureCount; j++) {
01596           fprintf(stdout, "substitute \\%u", (USHORT) gid);
01597           for (i = 0; i < ligset->Ligature[j].CompCount - 1; i++) {
01598             fprintf(stdout, " \\%u", ligset->Ligature[j].Component[i]);
01599           }
01600           fprintf(stdout, " by \\%u;\n", ligset->Ligature[j].LigGlyph);
01601         }
01602       }
01603     }
01604   }
01605 
01606   return  0;
01607 }
01608 
01609 int
01610 otl_gsub_dump (otl_gsub *gsub_list,
01611                const char *script, const char *language, const char *feature)
01612 {
01613   int    error = -1;
01614   struct otl_gsub_tab    *gsub;
01615   struct otl_gsub_subtab *subtab;
01616   int    sel, i, j;
01617 
01618   if (!gsub_list)
01619     return  -1;
01620 
01621   sel   = gsub_list->select;
01622   error = otl_gsub_select(gsub_list, script, language, feature);
01623   if (error < 0) {
01624     ERROR("GSUB feature %s.%s.%s not found.", script, language, feature);
01625   }
01626 
01627   i = gsub_list->select;
01628   if (i < 0 || i >= gsub_list->num_gsubs) {
01629     ERROR("GSUB not selected...");
01630     return -1;
01631   }
01632   gsub = &(gsub_list->gsubs[i]);
01633 
01634   for (j = 0;
01635        !error &&
01636        j < gsub->num_subtables; j++) {
01637     subtab = &(gsub->subtables[j]);
01638     switch ((int) subtab->LookupType){
01639     case OTL_GSUB_TYPE_SINGLE:
01640       error = otl_gsub_dump_single(subtab);
01641       break;
01642     case OTL_GSUB_TYPE_ALTERNATE:
01643       error = otl_gsub_dump_alternate(subtab);
01644       break;
01645     case OTL_GSUB_TYPE_LIGATURE:
01646       error = otl_gsub_dump_ligature(subtab);
01647       break;
01648     }
01649   }
01650   gsub_list->select = sel;
01651 
01652   return  error;
01653 }
01654 #endif