X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Fotfdrive.c;h=0b2ef60fcd967f8074201e9294465dc9c475e26f;hb=97035dfbd0a6c2ade61c1deb806383448bc61604;hp=763d84799ef222659235555b8f682a6421e08b56;hpb=e55e9b91acc2d165000c16ca7044a74822248ae2;p=m17n%2Flibotf.git diff --git a/src/otfdrive.c b/src/otfdrive.c index 763d847..0b2ef60 100644 --- a/src/otfdrive.c +++ b/src/otfdrive.c @@ -29,6 +29,8 @@ write to the Free Software Foundation, Inc., 59 Temple Place, Suite #include "otf.h" #include "otferror.h" +extern int debug_flag; + /* Return nonzero (-1 if ID is zero, 1 otherwise) if OTF_Glyph *G should be ignored according to LookupFlag FLAG. */ #define IGNORED_GLYPH(g, flag) \ @@ -771,6 +773,65 @@ gstring_insert_for_gpos (OTF_GlyphString *gstring, int gidx) return gidx; } +static void +print_anchor (char *head, OTF_Anchor *anchor) +{ + if (anchor->AnchorFormat == 1) + fprintf (stderr, " %s(X:%d Y:%d)", head, + anchor->XCoordinate, anchor->YCoordinate); + else if (anchor->AnchorFormat == 2) + fprintf (stderr, " %s(X:%d Y:%d AP:%d)", head, + anchor->XCoordinate, anchor->YCoordinate, + anchor->f.f1.AnchorPoint); + else + fprintf (stderr, " %s(X:%d Y:%d +alpha)", head, + anchor->XCoordinate, anchor->YCoordinate); +} + +static void +print_glyph_positioning (OTF_Glyph *g, int type) +{ + if (type) + fprintf (stderr, " %0X=", g->glyph_id); + switch (g->positioning_type) + { + case 1: case 2: + { + int format = g->f.f1.format; + + if (format & OTF_XPlacement) + fprintf (stderr, "X:%d", g->f.f1.value->XPlacement); + if (format & OTF_XPlaDevice) + fprintf (stderr, "+alpha"); + if (format & OTF_YPlacement) + fprintf (stderr, "Y:%d", g->f.f1.value->YPlacement); + if (format & OTF_YPlaDevice) + fprintf (stderr, "+alpha"); + if (format & OTF_XAdvance) + fprintf (stderr, "X+:%d", g->f.f1.value->XAdvance); + if (format & OTF_XAdvDevice) + fprintf (stderr, "+alpha"); + break; + } + case 3: + print_anchor ("entry", g->f.f3.entry_anchor); + print_anchor ("exit", g->f.f3.entry_anchor); + break; + case 4: + print_anchor ("mark", g->f.f4.mark_anchor); + print_anchor ("base", g->f.f4.base_anchor); + break; + case 5: + print_anchor ("mark", g->f.f5.mark_anchor); + print_anchor ("lig", g->f.f5.ligature_anchor); + break; + case 6: + print_anchor ("mark1", g->f.f6.mark1_anchor); + print_anchor ("mark2", g->f.f6.mark2_anchor); + break; + } +} + static int lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, OTF_GlyphString *gstring, int gidx, int accumulate) @@ -784,8 +845,15 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, OTF_Glyph *g = gstring->glyphs + gidx; int i; + if (debug_flag) + fprintf (stderr, "[GPOS] glyph:%04X lookup:%02d", + g->glyph_id, lookup_list_index); if (IGNORED_GLYPH (g, flag)) - return (gidx + 1); + { + if (debug_flag) + fprintf (stderr, " glyph ignored\n"); + return (gidx + 1); + } /* Try all subtables until one of them handles the current glyph. */ for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++) @@ -806,6 +874,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, subtable = extension1->ExtensionSubtable; } + if (debug_flag) + fprintf (stderr, "/%d", lookup_type); if (subtable->Coverage.offset) { coverage_idx = get_coverage_index (&subtable->Coverage, @@ -840,6 +910,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, g->positioning_type = positioning_type; g->f.f1.format = format; g->f.f1.value = value; + if (debug_flag) + print_glyph_positioning (g, 0); gidx++; break; @@ -852,8 +924,7 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, next_gidx < gstring->used && IGNORED_GLYPH (nextg, flag); next_gidx++, nextg++); - if (next_gidx >= gstring->used - || nextg->positioning_type) + if (next_gidx >= gstring->used) continue; if (subtable->Format == 1) { @@ -876,6 +947,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, g->positioning_type = lookup_type; g->f.f2.format = pair1->ValueFormat1; g->f.f2.value = &set->PairValueRecord[j].Value1; + if (debug_flag) + print_glyph_positioning (g, 1); } gidx = next_gidx; g = nextg; @@ -889,7 +962,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, g->positioning_type = lookup_type; g->f.f2.format = pair1->ValueFormat2; g->f.f2.value = &set->PairValueRecord[j].Value2; - gidx++; + if (debug_flag) + print_glyph_positioning (g, 2); } break; } @@ -914,6 +988,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, g->f.f2.format = pair2->ValueFormat1; g->f.f2.value = &pair2->Class1Record[class1].Class2Record[class2].Value1; + if (debug_flag) + print_glyph_positioning (g, 1); } gidx = next_gidx; g = nextg; @@ -928,7 +1004,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, g->f.f2.format = pair2->ValueFormat2; g->f.f2.value = &pair2->Class1Record[class1].Class2Record[class2].Value2; - gidx++; + if (debug_flag) + print_glyph_positioning (g, 2); } } } @@ -938,16 +1015,14 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, { OTF_GPOS_Cursive1 *cursive1 = &subtable->u.cursive1; - if (accumulate && g->positioning_type) - { - gidx = gstring_insert_for_gpos (gstring, gidx); - g = gstring->glyphs + gidx; - } g->positioning_type = lookup_type; g->f.f3.entry_anchor = &cursive1->EntryExitRecord[coverage_idx].EntryAnchor; g->f.f3.exit_anchor = &cursive1->EntryExitRecord[coverage_idx].ExitAnchor; + if (debug_flag) + print_glyph_positioning (g, 0); + gidx++; } break; @@ -976,15 +1051,13 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx; base_record = mark_base1->BaseArray.AnchorRecord + coverage_idx_base; - if (accumulate && g->positioning_type) - { - gidx = gstring_insert_for_gpos (gstring, gidx); - g = gstring->glyphs + gidx; - } g->f.f4.mark_anchor = &mark_record->MarkAnchor; g->f.f4.base_anchor = &base_record->Anchor[mark_record->Class]; g->positioning_type = lookup_type; + if (debug_flag) + print_glyph_positioning (g, 0); + gidx++; } break; @@ -1031,14 +1104,12 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, if (lig_anchor[mark_record->Class].AnchorFormat && num_class[mark_record->Class]-- == 0) { - if (accumulate && g->positioning_type) - { - gidx = gstring_insert_for_gpos (gstring, gidx); - g = gstring->glyphs + gidx; - } g->positioning_type = lookup_type; g->f.f5.mark_anchor = &mark_record->MarkAnchor; g->f.f5.ligature_anchor = lig_anchor + mark_record->Class; + if (debug_flag) + print_glyph_positioning (g, 0); + gidx++; break; } } @@ -1069,15 +1140,13 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx; mark2_record = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base; - if (accumulate && g->positioning_type) - { - gidx = gstring_insert_for_gpos (gstring, gidx); - g = gstring->glyphs + gidx; - } g->f.f6.mark1_anchor = &mark1_record->MarkAnchor; g->f.f6.mark2_anchor = &mark2_record->Anchor[mark1_record->Class]; g->positioning_type = lookup_type; + if (debug_flag) + print_glyph_positioning (g, 0); + gidx++; break; } break; @@ -1255,87 +1324,117 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, } } if (gidx == orig_gidx) - gidx++; + { + if (debug_flag) + fprintf (stderr, " no match\n"); + gidx++; + } + else if (debug_flag) + fprintf (stderr, "\n"); return gidx; } -static int -lookup_encoding_0 (OTF_EncodingSubtable0 *sub0, OTF_GlyphString *gstring) +static unsigned +lookup_encoding_0 (int c, OTF_EncodingSubtable *sub) { - int i, c; - - for (i = 0; i < gstring->used; i++) - { - c = gstring->glyphs[i].c; - if (c < 0 || c >= 256) - gstring->glyphs[i].glyph_id = 0; - else - gstring->glyphs[i].glyph_id = sub0->glyphIdArray[c]; - } - return 0; + return ((c < 0 || c >= 256) + ? 0 + : sub->f.f0->glyphIdArray[c]); } -static int -lookup_encoding_2 (OTF_EncodingSubtable2 *sub2, OTF_GlyphString *gstring) +static unsigned +lookup_encoding_2 (int c, OTF_EncodingSubtable *sub) { return 0; } -static int -lookup_encoding_4 (OTF_EncodingSubtable4 *sub4, OTF_GlyphString *gstring) +static unsigned +lookup_encoding_4 (int c, OTF_EncodingSubtable *sub) { - int i, j, c; - int segCount = sub4->segCountX2 / 2; + int segCount, i; + OTF_EncodingSubtable4 *sub4; - for (i = 0; i < gstring->used; i++) + if (c < 0) + return 0; + sub4 = sub->f.f4; + segCount = sub4->segCountX2 / 2; + for (i = 0; i < segCount; i++) { - c = gstring->glyphs[i].c; - if (c < 0) - gstring->glyphs[i].glyph_id = 0; - for (j = 0; j < segCount; j++) - { - OTF_cmapSegment *seg = sub4->segments + i; + OTF_cmapSegment *seg = sub4->segments + i; - if (c >= seg->startCount && c <= seg->endCount) - { - if (seg->idRangeOffset == 0xFFFF) - gstring->glyphs[i].glyph_id = c + seg->idDelta; - else - gstring->glyphs[i].glyph_id - = sub4->glyphIdArray[seg->idRangeOffset - + (c - seg->startCount)]; - break; - } + if (c >= seg->startCount && c <= seg->endCount) + { + if (seg->idRangeOffset == 0xFFFF) + return c + seg->idDelta; + else + return sub4->glyphIdArray[seg->idRangeOffset + + (c - seg->startCount)]; } } - return 0; } -static int -lookup_encoding_6 (OTF_EncodingSubtable6 *sub6, OTF_GlyphString *gstring) +static unsigned +lookup_encoding_6 (int c, OTF_EncodingSubtable *sub) { return 0; } -static int -lookup_encoding_8 (OTF_EncodingSubtable8 *sub8, OTF_GlyphString *gstring) +static unsigned +lookup_encoding_8 (int c, OTF_EncodingSubtable *sub) { return 0; } -static int -lookup_encoding_10 (OTF_EncodingSubtable10 *sub10, OTF_GlyphString *gstring) +static unsigned +lookup_encoding_10 (int c, OTF_EncodingSubtable *sub) { return 0; } -static int -lookup_encoding_12 (OTF_EncodingSubtable12 *sub12, OTF_GlyphString *gstring) +static unsigned +lookup_encoding_12 (int c, OTF_EncodingSubtable *sub) { + OTF_EncodingSubtable12 *sub12; + OTF_cmapGroup *g, *gend; + + if (c < 0) + return 0; + sub12 = sub->f.f12; + g = sub12->Groups; + gend = sub12->Groups + sub12->nGroups; + while (g < gend) + { + if (g->startCharCode <= c && c <= g->endCharCode) + return (g->startGlyphID + (c - g->startCharCode)); + g++; + } return 0; } +typedef unsigned (*lookup_cmap_func) (int, OTF_EncodingSubtable *); + +static lookup_cmap_func lookup_cmap_func_table[] = + { + lookup_encoding_0, lookup_encoding_2, lookup_encoding_4, lookup_encoding_6, + lookup_encoding_8, lookup_encoding_10, lookup_encoding_12 + }; + +static unsigned +get_GlyphID (OTF_cmap *cmap, int c) +{ + OTF_EncodingSubtable *sub; + lookup_cmap_func lookupper; + + if (c < 0x10000 && cmap->unicode_table) + return cmap->unicode_table[c]; + if (cmap->table_index < 0) + return 0; + sub = &cmap->EncodingRecord[cmap->table_index].subtable; + lookupper = lookup_cmap_func_table[sub->format / 2]; + return lookupper (c, sub); +} + static OTF_GlyphID get_uvs_glyph (OTF_cmap *cmap, OTF_EncodingSubtable14 *sub14, int c1, int c2) { @@ -1371,7 +1470,7 @@ get_uvs_glyph (OTF_cmap *cmap, OTF_EncodingSubtable14 *sub14, int c1, int c2) startUnicodeValue = uVRs[bottom].startUnicodeValue; additionalCount = uVRs[bottom].additionalCount; if (c1 <= startUnicodeValue + additionalCount) - return cmap->unicode_table[c1]; + return get_GlyphID (cmap, c1); } } if (record->nonDefaultUVSOffset) @@ -1429,6 +1528,71 @@ check_cmap_uvs (OTF_cmap *cmap, OTF_GlyphString *gstring, int idx) +/* GDEF */ +/* Table of GlyphClass and MarkAttackClass. + + For the Nth element CHAR, CHAR and the succeeding characters + (before CHAR of the next element) has GlyphClass C (= (N % 2) ? 3 : 1). + + This table is generated from the General Category (GC) property of + characters defined in the Unicode Character Database. */ + +static int glyph_class_table[] = + { 0x00000, 0x00300, 0x00370, 0x00483, 0x00487, 0x00488, 0x0048A, 0x00591, + 0x005BE, 0x005BF, 0x005C0, 0x005C1, 0x005C3, 0x005C4, 0x005C6, 0x005C7, + 0x005C8, 0x00610, 0x00616, 0x0064B, 0x0065F, 0x00670, 0x00671, 0x006D6, + 0x006DD, 0x006DE, 0x006E5, 0x006E7, 0x006E9, 0x006EA, 0x006EE, 0x00711, + 0x00712, 0x00730, 0x0074B, 0x007A6, 0x007B1, 0x007EB, 0x007F4, 0x00901, + 0x00904, 0x0093C, 0x0093D, 0x0093E, 0x0094E, 0x00951, 0x00955, 0x00962, + 0x00964, 0x00981, 0x00984, 0x009BC, 0x009BD, 0x009BE, 0x009C5, 0x009C7, + 0x009CE, 0x009D7, 0x009D8, 0x009E2, 0x009E4, 0x00A01, 0x00A04, 0x00A3C, + 0x00A3D, 0x00A3E, 0x00A4E, 0x00A70, 0x00A72, 0x00A81, 0x00A84, 0x00ABC, + 0x00ABD, 0x00ABE, 0x00ACE, 0x00AE2, 0x00AE4, 0x00B01, 0x00B04, 0x00B3C, + 0x00B3D, 0x00B3E, 0x00B44, 0x00B47, 0x00B58, 0x00B82, 0x00B83, 0x00BBE, + 0x00BCE, 0x00BD7, 0x00BD8, 0x00C01, 0x00C04, 0x00C3E, 0x00C45, 0x00C46, + 0x00C57, 0x00C82, 0x00C84, 0x00CBC, 0x00CBD, 0x00CBE, 0x00CC5, 0x00CC6, + 0x00CCE, 0x00CD5, 0x00CD7, 0x00CE2, 0x00CE4, 0x00D02, 0x00D04, 0x00D3E, + 0x00D44, 0x00D46, 0x00D4E, 0x00D57, 0x00D58, 0x00D82, 0x00D84, 0x00DCA, + 0x00DCB, 0x00DCF, 0x00DD7, 0x00DD8, 0x00DF4, 0x00E31, 0x00E32, 0x00E34, + 0x00E3B, 0x00E47, 0x00E4F, 0x00EB1, 0x00EB2, 0x00EB4, 0x00EBD, 0x00EC8, + 0x00ECE, 0x00F18, 0x00F1A, 0x00F35, 0x00F36, 0x00F37, 0x00F38, 0x00F39, + 0x00F3A, 0x00F3E, 0x00F40, 0x00F71, 0x00F85, 0x00F86, 0x00F88, 0x00F90, + 0x00FBD, 0x00FC6, 0x00FC7, 0x0102C, 0x0103A, 0x01056, 0x0105A, 0x0135F, + 0x01360, 0x01712, 0x01715, 0x01732, 0x01735, 0x01752, 0x01754, 0x01772, + 0x01774, 0x017B6, 0x017D4, 0x017DD, 0x017DE, 0x0180B, 0x0180E, 0x018A9, + 0x018AA, 0x01920, 0x0193C, 0x019B0, 0x019C1, 0x019C8, 0x019CA, 0x01A17, + 0x01A1C, 0x01B00, 0x01B05, 0x01B34, 0x01B45, 0x01B6B, 0x01B74, 0x01DC0, + 0x01E00, 0x020D0, 0x020F0, 0x0302A, 0x03030, 0x03099, 0x0309B, 0x0A802, + 0x0A803, 0x0A806, 0x0A807, 0x0A80B, 0x0A80C, 0x0A823, 0x0A828, 0x0FB1E, + 0x0FB1F, 0x0FE00, 0x0FE10, 0x0FE20, 0x0FE24, 0x10A01, 0x10A10, 0x10A38, + 0x10A40, 0x1D165, 0x1D16A, 0x1D16D, 0x1D173, 0x1D17B, 0x1D183, 0x1D185, + 0x1D18C, 0x1D1AA, 0x1D1AE, 0x1D242, 0x1D245, 0xE0100, 0xE01F0 }; + +int get_class_def_auto (int c) +{ + static int table_size + = sizeof glyph_class_table / sizeof glyph_class_table[0]; + int low, high, mid; + + if (c >= glyph_class_table[table_size - 1]) + return 0; + low = 0; + high = table_size - 1; + while (1) + { + mid = (low + high) / 2; + if (c < glyph_class_table[mid]) + high = mid - 1; + else if (c >= glyph_class_table[mid + 1]) + low = mid + 1; + else + break; + } + return ((mid % 2) ? 3 : 1); +} + + + /* API */ #define UVS_P(C) \ @@ -1439,12 +1603,21 @@ OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring) { OTF_cmap *cmap; int i; + OTF_EncodingSubtable *sub; + lookup_cmap_func lookupper; if (! otf->cmap && OTF_get_table (otf, "cmap") < 0) return -1; cmap = otf->cmap; + if (cmap->table_index < 0) + lookupper = NULL; + else + { + sub = &cmap->EncodingRecord[cmap->table_index].subtable; + lookupper = lookup_cmap_func_table[sub->format / 2]; + } for (i = 0; i < gstring->used; i++) if (! gstring->glyphs[i].glyph_id) { @@ -1453,8 +1626,10 @@ OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring) gstring->glyphs[i].glyph_id = 0; else if (UVS_P (c) && i > 0) check_cmap_uvs (cmap, gstring, i); - else + else if (c < 0x10000) gstring->glyphs[i].glyph_id = cmap->unicode_table[c]; + else if (lookupper) + gstring->glyphs[i].glyph_id = lookupper (c, sub); } return 0; } @@ -1469,6 +1644,7 @@ OTF_drive_cmap2 (OTF *otf, OTF_GlyphString *gstring, char *errfmt = "CMAP Looking up%s"; int errret = -1; OTF_EncodingRecord *enc; + lookup_cmap_func lookupper; if (! otf->cmap && OTF_get_table (otf, "cmap") < 0) @@ -1482,17 +1658,23 @@ OTF_drive_cmap2 (OTF *otf, OTF_GlyphString *gstring, if (i == cmap->numTables) OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (unknown platformID/encodingID)"); enc = cmap->EncodingRecord + i; - switch (enc->subtable.format) - { - case 0: return lookup_encoding_0 (enc->subtable.f.f0, gstring); - case 2: return lookup_encoding_2 (enc->subtable.f.f2, gstring); - case 4: return lookup_encoding_4 (enc->subtable.f.f4, gstring); - case 6: return lookup_encoding_6 (enc->subtable.f.f6, gstring); - case 8: return lookup_encoding_8 (enc->subtable.f.f8, gstring); - case 10: return lookup_encoding_10 (enc->subtable.f.f10, gstring); - case 12: return lookup_encoding_12 (enc->subtable.f.f12, gstring); - } - OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (invalid format)"); + if (enc->subtable.format > 12) + OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (invalid format)"); + lookupper = lookup_cmap_func_table[enc->subtable.format / 2]; + + for (i = 0; i < gstring->used; i++) + if (! gstring->glyphs[i].glyph_id) + { + int c = gstring->glyphs[i].c; + if (c < 32 || ! cmap->unicode_table) + gstring->glyphs[i].glyph_id = 0; + else if (UVS_P (c) && i > 0) + check_cmap_uvs (cmap, gstring, i); + else if (c < 0x10000) + gstring->glyphs[i].glyph_id = cmap->unicode_table[c]; + else + gstring->glyphs[i].glyph_id = lookupper (c, &enc->subtable); + } } @@ -1554,6 +1736,10 @@ OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring) gstring->glyphs[i].GlyphClass = get_class_def (&gdef->glyph_class_def, gstring->glyphs[i].glyph_id); + else + for (i = 0; i < gstring->used; i++) + gstring->glyphs[i].GlyphClass + = get_class_def_auto (gstring->glyphs[i].c); if (gdef->mark_attach_class_def.offset) for (i = 0; i < gstring->used; i++) @@ -1735,3 +1921,176 @@ OTF_drive_gsub_alternate (OTF *otf, OTF_GlyphString *gstring, { return OTF_drive_gsub_internal (otf, gstring, script, language, features, 1); } + +static int +iterate_coverage (OTF *otf, const char *feature, + OTF_Feature_Callback callback, + OTF_Coverage *coverage) +{ + int i; + + if (coverage->CoverageFormat == 1) + { + for (i = 0; i < coverage->Count; i++) + if (callback (otf, feature, coverage->table.GlyphArray[i]) < 0) + return -1; + } + else + { + for (i = 0; i < coverage->Count; i++) + { + OTF_RangeRecord *range = coverage->table.RangeRecord + i; + unsigned id; + for (id = range->Start; id <= range->End; id++) + if (callback (otf, feature, id) < 0) + return -1; + } + } + return 0; +} + +static int +iterate_feature (OTF *otf, const char *feature, + OTF_Feature_Callback callback, + OTF_Lookup *lookup) +{ + int i, j, k, l; + + for (i = 0; i < lookup->SubTableCount; i++) + { + unsigned lookup_type = lookup->LookupType; + OTF_LookupSubTableGSUB *subtable = lookup->SubTable.gsub + i; + + if (lookup_type == 7) + { + OTF_GSUB_Extension1 *extension1 = &subtable->u.extension1; + + lookup_type = extension1->ExtensionLookupType; + subtable = extension1->ExtensionSubtable; + } + + if ((lookup_type >= 1 && lookup_type <= 3) || lookup_type == 8) + { + if (iterate_coverage (otf, feature, callback, &subtable->Coverage) + < 0) + return -1; + } + else if (lookup_type == 4) + { + OTF_GSUB_Ligature1 *lig1; + + if (iterate_coverage (otf, feature, callback, &subtable->Coverage) + < 0) + return -1; + lig1 = &subtable->u.ligature1; + for (j = 0; j < lig1->LigSetCount; j++) + { + OTF_LigatureSet *ligset = lig1->LigatureSet + j; + + for (k = 0; k < ligset->LigatureCount; k++) + { + OTF_Ligature *lig = ligset->Ligature + k; + for (l = 0; l < lig->CompCount - 1; l++) + if (callback (otf, feature, lig->Component[l]) < 0) + return -1; + } + } + } + else if (lookup_type == 6) + { + if (subtable->Format == 1) + { + OTF_GSUB_ChainContext1 *context1 = &subtable->u.chain_context1; + for (j = 0; j < context1->ChainRuleSetCount; j++) + { + OTF_ChainRuleSet *set = context1->ChainRuleSet + j; + for (k = 0; k < set->ChainRuleCount; k++) + { + OTF_ChainRule *rule = set->ChainRule + k; + for (l = 0; l < rule->LookupCount; l++) + { + OTF_Lookup *lkup + = (otf->gsub->LookupList.Lookup + + rule->LookupRecord[l].LookupListIndex); + if (iterate_feature (otf, feature, callback, lkup) + < 0) + return -1; + } + } + } + } + else if (subtable->Format == 2) + { + OTF_GSUB_ChainContext2 *context2 = &subtable->u.chain_context2; + + for (j = 0; j < context2->ChainClassSetCnt; j++) + { + OTF_ChainClassSet *set = context2->ChainClassSet + j; + for (k = 0; k < set->ChainClassRuleCnt; j++) + { + OTF_ChainClassRule *rule = set->ChainClassRule + k; + + for (l = 0; l < rule->LookupCount; l++) + { + OTF_Lookup *lkup + = (otf->gsub->LookupList.Lookup + + rule->LookupRecord[k].LookupListIndex); + if (iterate_feature (otf, feature, callback, lkup) + < 0) + return -1; + } + } + } + } + else + { + OTF_GSUB_ChainContext3 *context3 = &subtable->u.chain_context3; + for (j = 0; j < context3->LookupCount; j++) + { + OTF_Lookup *lkup + = (otf->gsub->LookupList.Lookup + + context3->LookupRecord[j].LookupListIndex); + if (iterate_feature (otf, feature, callback, lkup) < 0) + return -1; + } + } + } + } + return 0; +} + +int +OTF_iterate_gsub_feature (OTF *otf, OTF_Feature_Callback callback, + const char *script, const char *language, + const char *feature) +{ + char *errfmt = "GSUB iterate feature%s"; + int errret = -1; + int i; + + OTF_GSUB *gsub; + OTF_LangSys *langsys; + char *lookup_flags; + + if (OTF_get_table (otf, "GSUB") < 0) + return errret; + gsub = otf->gsub; + if (gsub->FeatureList.FeatureCount == 0 + || gsub->LookupList.LookupCount == 0) + return 0; + langsys = get_langsys (&gsub->ScriptList, script, language); + if (! langsys) + return errret; + lookup_flags = alloca (gsub->LookupList.LookupCount); + if (! lookup_flags + || setup_lookup_flags (&gsub->LookupList, &gsub->FeatureList, langsys, + feature, lookup_flags) < 0) + OTF_ERROR (OTF_ERROR_MEMORY, " feature"); + + for (i = 0; i < gsub->LookupList.LookupCount; i++) + if (lookup_flags[i]) + if (iterate_feature (otf, feature, callback, gsub->LookupList.Lookup + i) + < 0) + return -1; + return 0; +}