From: handa Date: Sat, 11 Oct 2003 02:31:16 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: REL-0-9-1~94 X-Git-Url: http://git.chise.org/gitweb/?a=commitdiff_plain;h=13f797a00cc517a04a0f9286950bcc80b4321226;p=m17n%2Flibotf.git *** empty log message *** --- diff --git a/example/otfdump.c b/example/otfdump.c index 71531ca..8d5eca6 100644 --- a/example/otfdump.c +++ b/example/otfdump.c @@ -84,10 +84,11 @@ dump_glyph_ids (int indent, char *title, OTF_GlyphID *ids, unsigned count) printf (")"); } -static void +static int * dump_coverage (int indent, char *title, OTF_Coverage *coverage) { int i; + int *char_list; IPRINT ("(%sCoverage (CoverageFormat %d)", (title ? title : ""), coverage->CoverageFormat); @@ -96,12 +97,18 @@ dump_coverage (int indent, char *title, OTF_Coverage *coverage) { dump_glyph_ids (indent, "GlyphArray", coverage->table.GlyphArray, coverage->Count); + char_list = malloc (sizeof (int) * (coverage->Count + 1)); + for (i = 0; i < coverage->Count; i++) + char_list[i] = coverage->table.GlyphArray[i]; + char_list[i] = -1; } else { + int n, c; + IPRINT ("(RangeCount %d)", coverage->Count); indent++; - for (i = 0; i < coverage->Count; i++) + for (i = n = 0; i < coverage->Count; i++) { IPRINT ("(Range (%d) (Start #x%04X) (End #x%04X)", i, coverage->table.RangeRecord[i].Start, @@ -110,9 +117,19 @@ dump_coverage (int indent, char *title, OTF_Coverage *coverage) IPRINT ("(StartCoverageIndex %d))", coverage->table.RangeRecord[i].StartCoverageIndex); indent--; + n += (coverage->table.RangeRecord[i].End + - coverage->table.RangeRecord[i].Start + 1); } + char_list = malloc (sizeof (int) * (n + 1)); + for (i = n = 0; i < coverage->Count; i++) + for (c = coverage->table.RangeRecord[i].Start; + c <= coverage->table.RangeRecord[i].End; + c++) + char_list[n++] = c; + char_list[n] = -1; } printf (")"); + return char_list; } static void @@ -123,7 +140,7 @@ dump_coverage_list (int indent, char *title, IPRINT ("(%s %d)", title, num); for (i = 0; i < num; i++) - dump_coverage (indent, NULL, coverage + i); + free (dump_coverage (indent, NULL, coverage + i)); } @@ -324,9 +341,10 @@ dump_alternate_set_list (int indent, OTF_AlternateSet *altset, unsigned num) static void -dump_ligature_set_list (int indent, OTF_LigatureSet *ligset, unsigned num) +dump_ligature_set_list (int indent, int *char_list, + OTF_LigatureSet *ligset, unsigned num) { - int i, j; + int i, j, k; IPRINT ("(LigSetCount %d)", num); for (i = 0; i < num; i++) @@ -343,6 +361,10 @@ dump_ligature_set_list (int indent, OTF_LigatureSet *ligset, unsigned num) ligset[i].Ligature[j].LigGlyph); dump_glyph_ids (indent, "Component", ligset[i].Ligature[j].Component, ligset[i].Ligature[j].CompCount - 1); + IPRINT ("(i.e. #x%04X", char_list[i]); + for (k = 0; k < ligset[i].Ligature[j].CompCount - 1; k++) + printf (" #x%04X", ligset[i].Ligature[j].Component[k]); + printf (" = #x%04X)", ligset[i].Ligature[j].LigGlyph); printf (")"); indent--; } @@ -352,6 +374,33 @@ dump_ligature_set_list (int indent, OTF_LigatureSet *ligset, unsigned num) } static void +dump_pair_set_list (int indent, unsigned count, OTF_PairSet *set) +{ + int i, j; + + for (i = 0; i < count; i++) + { + IPRINT ("(PairSet (%d)", i); + indent++; + for (j = 0; j < set[i].PairValueCount; j++) + { + IPRINT ("(PairValueRecord (%d)", j); + indent++; + IPRINT ("(SecondGlyph #x%04X)", + set[i].PairValueRecord[j].SecondGlyph); + dump_value_record (indent, "Value1", + &set[i].PairValueRecord[j].Value1); + dump_value_record (indent, "Value2", + &set[i].PairValueRecord[j].Value2); + printf (")"); + indent--; + } + printf (")"); + indent--; + } +} + +static void dump_class1_record_list (int indent, unsigned Class1Count, unsigned Class2Count, OTF_Class1Record *rec) @@ -397,6 +446,22 @@ dump_anchor (int indent, OTF_Anchor *anchor) } static void +dump_entry_exit_list (int indent, unsigned count, OTF_EntryExitRecord *rec) +{ + int i; + + for (i = 0; i < count; i++) + { + IPRINT ("(EntryExitRecord (%d)", i); + indent++; + dump_anchor (indent, &rec[i].EntryAnchor); + dump_anchor (indent, &rec[i].EntryAnchor); + printf (")"); + indent--; + } +} + +static void dump_mark_array (int indent, OTF_MarkArray *array) { int i; @@ -647,13 +712,13 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type, case 1: if (subtable->Format == 1) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); IPRINT ("(DeltaGlyhpID #x%04X)", subtable->u.single1.DeltaGlyphID); } else if (subtable->Format == 2) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_glyph_ids (indent, "Substitute", subtable->u.single2.Substitute, subtable->u.single2.GlyphCount); } @@ -664,7 +729,7 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type, case 2: if (subtable->Format == 1) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_sequence_list (indent, subtable->u.multiple1.Sequence, subtable->u.multiple1.SequenceCount); @@ -676,7 +741,7 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type, case 3: if (subtable->Format == 1) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_alternate_set_list (indent, subtable->u.alternate1.AlternateSet, subtable->u.alternate1.AlternateSetCount); } @@ -687,10 +752,11 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type, case 4: if (subtable->Format == 1) { - dump_coverage (indent, NULL, &subtable->Coverage); - dump_ligature_set_list (indent, + int *char_list = dump_coverage (indent, NULL, &subtable->Coverage); + dump_ligature_set_list (indent, char_list, subtable->u.ligature1.LigatureSet, subtable->u.ligature1.LigSetCount); + free (char_list); } else printf (" invalid"); @@ -699,13 +765,13 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type, case 5: if (subtable->Format == 1) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_rule_set_list (indent, subtable->u.context1.RuleSet, subtable->u.context1.RuleSetCount); } else if (subtable->Format == 2) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_class_def (indent, NULL, &subtable->u.context2.ClassDef); dump_class_set_list (indent, subtable->u.context2.ClassSet, subtable->u.context2.ClassSetCnt); @@ -726,7 +792,7 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type, case 6: if (subtable->Format == 1) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_chain_rule_set_list (indent, subtable->u.chain_context1.ChainRuleSet, @@ -734,7 +800,7 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type, } else if (subtable->Format == 2) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_class_def (indent, "BacktrackClassDef", &subtable->u.chain_context2.BacktrackClassDef); dump_class_def (indent, "InputClassDef", @@ -781,7 +847,7 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type, break; case 8: - printf (" not-yet-substcount"); + printf (" not-yet-supported"); break; default: @@ -822,7 +888,7 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type, case 1: if (subtable->Format == 1) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); IPRINT ("(ValueFormat #x%04X)", subtable->u.single1.ValueFormat); dump_value_record (indent, "Value", &subtable->u.single1.Value); @@ -831,7 +897,7 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type, { int i; - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); IPRINT ("(ValueFormat #x%04X)", subtable->u.single2.ValueFormat); IPRINT ("(ValueCount %d)", @@ -846,11 +912,17 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type, case 2: if (subtable->Format == 1) { - printf (" not-yet-supported"); + free (dump_coverage (indent, NULL, &subtable->Coverage)); + IPRINT ("(ValueFormat1 #x%04X)", + subtable->u.pair1.ValueFormat1); + IPRINT ("(ValueFormat2 #x%04X)", + subtable->u.pair1.ValueFormat2); + dump_pair_set_list (indent, subtable->u.pair1.PairSetCount, + subtable->u.pair1.PairSet); } else if (subtable->Format == 2) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); IPRINT ("(ValueFormat1 #x%04X)", subtable->u.pair2.ValueFormat1); IPRINT ("(ValueFormat2 #x%04X)", @@ -875,7 +947,9 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type, case 3: if (subtable->Format == 1) { - printf (" not-yet-supported"); + free (dump_coverage (indent, NULL, &subtable->Coverage)); + dump_entry_exit_list (indent, subtable->u.cursive1.EntryExitCount, + subtable->u.cursive1.EntryExitRecord); } else printf (" invalid"); @@ -884,9 +958,9 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type, case 4: if (subtable->Format == 1) { - dump_coverage (indent, "Mark", &subtable->Coverage); - dump_coverage (indent, "Base", - &subtable->u.mark_base1.BaseCoverage); + free (dump_coverage (indent, "Mark", &subtable->Coverage)); + free (dump_coverage (indent, "Base", + &subtable->u.mark_base1.BaseCoverage)); IPRINT ("(ClassCount %d)", subtable->u.mark_base1.ClassCount); dump_mark_array (indent, &subtable->u.mark_base1.MarkArray); @@ -907,9 +981,9 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type, case 6: if (subtable->Format == 1) { - dump_coverage (indent, "Mark1", &subtable->Coverage); - dump_coverage (indent, "Mark2", - &subtable->u.mark_mark1.Mark2Coverage); + free (dump_coverage (indent, "Mark1", &subtable->Coverage)); + free (dump_coverage (indent, "Mark2", + &subtable->u.mark_mark1.Mark2Coverage)); IPRINT ("(ClassCount %d)", subtable->u.mark_mark1.ClassCount); dump_mark_array (indent, &subtable->u.mark_mark1.Mark1Array); @@ -923,13 +997,13 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type, case 7: if (subtable->Format == 1) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_rule_set_list (indent, subtable->u.context1.RuleSet, subtable->u.context1.RuleSetCount); } else if (subtable->Format == 2) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_class_def (indent, NULL, &subtable->u.context2.ClassDef); dump_class_set_list (indent, subtable->u.context2.ClassSet, subtable->u.context2.ClassSetCnt); @@ -950,7 +1024,7 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type, case 8: if (subtable->Format == 1) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_chain_rule_set_list (indent, subtable->u.chain_context1.ChainRuleSet, @@ -958,7 +1032,7 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type, } else if (subtable->Format == 2) { - dump_coverage (indent, NULL, &subtable->Coverage); + free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_class_def (indent, "BacktrackClassDef", &subtable->u.chain_context2.BacktrackClassDef); dump_class_def (indent, "InputClassDef", @@ -1057,7 +1131,7 @@ dump_lig_caret_list (int indent, OTF_LigCaretList *list) IPRINT ("(LigCaretList"); indent++; - dump_coverage (indent, NULL, &list->Coverage); + free (dump_coverage (indent, NULL, &list->Coverage)); IPRINT ("(LigGlyphCount %d)", list->LigGlyphCount); for (i = 0; i < list->LigGlyphCount; i++) { diff --git a/src/otf.h b/src/otf.h index 3dd6ed5..6232dca 100644 --- a/src/otf.h +++ b/src/otf.h @@ -812,7 +812,24 @@ typedef struct typedef struct { - int dummy; + OTF_GlyphID SecondGlyph; + OTF_ValueRecord Value1; + OTF_ValueRecord Value2; +} OTF_PairValueRecord; + +typedef struct +{ + OTF_Offset offset; + unsigned PairValueCount; + OTF_PairValueRecord *PairValueRecord; +} OTF_PairSet; + +typedef struct +{ + unsigned ValueFormat1; + unsigned ValueFormat2; + unsigned PairSetCount; + OTF_PairSet *PairSet; } OTF_GPOS_Pair1; typedef struct @@ -839,7 +856,14 @@ typedef struct typedef struct { - int dummy; + OTF_Anchor EntryAnchor; + OTF_Anchor ExitAnchor; +} OTF_EntryExitRecord; + +typedef struct +{ + unsigned EntryExitCount; + OTF_EntryExitRecord *EntryExitRecord; } OTF_GPOS_Cursive1; typedef struct @@ -864,7 +888,29 @@ typedef struct typedef struct { - int dummy; + OTF_Anchor *LigatureAnchor; /* [] */ +} OTF_ComponentRecord; + +typedef struct +{ + OTF_Offset offset; + unsigned ComponentCount; + OTF_ComponentRecord *ComponentRecord; /* [] */ +} OTF_LigatureAttach; + +typedef struct +{ + OTF_Offset offset; + unsigned LigatureCount; + OTF_LigatureAttach *LigatureAttach; /* [] */ +} OTF_LigatureArray; + +typedef struct +{ + OTF_Coverage LigatureCoverage; + unsigned ClassCount; + OTF_MarkArray MarkArray; + OTF_LigatureArray LigatureArray; } OTF_GPOS_MarkLig1; typedef struct @@ -889,7 +935,9 @@ typedef OTF_ChainContext3 OTF_GPOS_ChainContext3; typedef struct { - int dummy; + unsigned ExtensionLookupType; + unsigned ExtensionOffset; + OTF_LookupSubTableGPOS *ExtensionSubtable; } OTF_GPOS_Extension1; @@ -1149,7 +1197,7 @@ extern int OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring); font $OTF, and by using features the font has for script $SCRIPT and language system $LANGSYS, update member of the glyph string $GSTRING. It may substitute, delete, insert glyphs in that - array. */ + array. $FEATURES is a list of features to apply. */ extern int OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring, char *script, char *language, char *features); @@ -1163,7 +1211,7 @@ extern int OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring, OpenType font $OTF, and by using features the font has for script $SCRIPT and language system $LANGSYS, setup members and of all glhphs in the glyph string - $GSTRING. */ + $GSTRING. $FEATURES is a list of features to apply. */ extern int OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring, char *script, char *language, char *features); diff --git a/src/otfdrive.c b/src/otfdrive.c index 7b9be26..7fc59b6 100644 --- a/src/otfdrive.c +++ b/src/otfdrive.c @@ -146,62 +146,85 @@ setup_lookup_indices (OTF_LangSys *LangSys, OTF_FeatureList *FeatureList, { int i, j, n = 0; OTF_Feature *feature; + int *feature_table = alloca (sizeof (int) * FeatureList->FeatureCount); - if (features) - { - char *p0, *p1; - int len = strlen (features) + 1; + for (i = 0; i < FeatureList->FeatureCount; i++) + feature_table[i] = 0; - p0 = alloca (len); - for (p1 = p0; *p1; p1++) - if (*p1 == ',') - *p1 = '\0'; + while (*features) + { + char tagname[4]; + OTF_Tag tag; - while (p0 < p1) + if (*features == '*') { - int this_len = strlen (p0) + 1; - OTF_Tag tag = OTF_tag (p0); - - if (tag) - for (i = 0; i < FeatureList->FeatureCount; i++) + /* Consume all remaining features. */ + for (i = 0; i < FeatureList->FeatureCount; i++) + if (! feature_table[i]) { feature = FeatureList->Feature + i; - if (tag == feature->FeatureTag) - for (j = 0; j < feature->LookupCount; j++) - { - lookup_indices[feature->LookupListIndex[j]] = 1; - n++; - } + for (j = 0; j < feature->LookupCount; j++) + lookup_indices[n++] = feature->LookupListIndex[j]; } - p0 += this_len; + break; } - } - else - { - for (i = 0; i < LangSys->FeatureCount; i++) + + for (i = 0; *features && *features != ','; i++, features++) + tagname[i] = *features; + if (*features) + /* Skip ',' */ + features++; + for (; i < 4; i++) + tagname[i] = '\0'; + tag = OTF_tag (tagname); + for (i = 0; i < FeatureList->FeatureCount; i++) { - feature = FeatureList->Feature + LangSys->FeatureIndex[i]; - for (j = 0; j < feature->LookupCount; j++) + feature = FeatureList->Feature + i; + if (tag == feature->FeatureTag) { - lookup_indices[feature->LookupListIndex[j]] = 1; - n++; + for (j = 0; j < feature->LookupCount; j++) + lookup_indices[n++] = feature->LookupListIndex[j]; + feature_table[i] = 1; + break; } } } - return (n > 0); + return n; } static int match_ids (OTF_GlyphString *gstring, int gidx, int count, OTF_GlyphID *ids) { - int i; + int i, j; if (gstring->used - gidx < count) return -1; - for (i = 0; i < count; i++) - if (gstring->glyphs[gidx + i].glyph_id != ids[i]) - return -1; + for (i = j = 0; i < count; i++, j++) + { + if (! gstring->glyphs[gidx + j].glyph_id) + /* Skip this glyph. */ + i--; + else if (ids[i] && gstring->glyphs[gidx + i].glyph_id != ids[i]) + return -1; + } + return j; +} + +static int +match_chain_ids (OTF_GlyphString *gstring, int gidx, OTF_ChainRule *rule) +{ + if (match_ids (gstring, gidx, rule->BacktrackGlyphCount, rule->Backtrack) + < 0) + return -1; + gidx += rule->BacktrackGlyphCount + 1; + if (match_ids (gstring, gidx, rule->InputGlyphCount - 1, rule->Input) + < 0) + return -1; + gidx += rule->InputGlyphCount; + if (match_ids (gstring, gidx, rule->LookaheadGlyphCount - 1, rule->LookAhead) + < 0) + return -1; return 0; } @@ -405,12 +428,28 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, { OTF_GSUB_ChainContext1 *context1 = &subtable->u.chain_context1; OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx; - OTF_ChainRule *rule; + int orig_used; int j, k; for (j = 0; j < set->ChainRuleCount; j++) { - rule = set->ChainRule + j; + OTF_ChainRule *rule = set->ChainRule + j; + int backs = rule->BacktrackGlyphCount; + int inputs = rule->InputGlyphCount; + int aheads = rule->LookaheadGlyphCount; + + if (gidx < backs || gidx + inputs + aheads > gstring->used) + continue; + if (match_chain_ids (gstring, gidx - backs, rule) < 0) + continue; + orig_used = gstring->used; + for (k = 0; k < rule->LookupCount; k++) + lookup_gsub (lookup_list, + rule->LookupRecord[k].LookupListIndex, + gstring, + gidx + rule->LookupRecord[k].SequenceIndex); + gidx += rule->InputGlyphCount + (gstring->used - orig_used); + break; } } else if (subtable->Format == 2) @@ -486,7 +525,7 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, if (j < context3->BacktrackGlyphCount) continue; - /* Start from the secode coverage_idx because the first + /* Start from the second coverage_idx because the first one is the same as subtable->Coverage and thus already tested */ for (j = 1; j < context3->InputGlyphCount; j++) @@ -620,13 +659,49 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, switch (lookup->LookupType) { case 1: - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + g->positioning_type = lookup->LookupType; + if (subtable->Format == 1) + { + OTF_GPOS_Single1 *single1 = &subtable->u.single1; + + g->f.f1.format = single1->ValueFormat; + g->f.f1.value = &single1->Value; + } + else if (subtable->Format == 2) + { + OTF_GPOS_Single2 *single2 = &subtable->u.single2; + + g->f.f1.format = single2->ValueFormat; + g->f.f1.value = single2->Value + coverage_idx; + } + break; case 2: if (gidx + 1 >= gstring->used) continue; if (subtable->Format == 1) - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + { + OTF_GPOS_Pair1 *pair1 = &subtable->u.pair1; + OTF_PairSet *set = pair1->PairSet + coverage_idx; + int j; + + for (j = 0; j < set->PairValueCount; j++) + { + if (set->PairValueRecord[j].SecondGlyph != g[1].glyph_id) + continue; + gidx++; + g->positioning_type = lookup->LookupType; + g->f.f2.format = pair1->ValueFormat1; + g->f.f2.value = &set->PairValueRecord[j].Value1; + if (pair1->ValueFormat2) + { + g++, gidx++; + g->positioning_type = lookup->LookupType; + g->f.f2.format = pair1->ValueFormat2; + g->f.f2.value = &set->PairValueRecord[j].Value2; + } + } + } else if (subtable->Format == 2) { OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2; @@ -652,7 +727,16 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, break; case 3: - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + { + OTF_GPOS_Cursive1 *cursive1 = &subtable->u.cursive1; + + g->positioning_type = lookup->LookupType; + g->f.f3.entry_anchor + = &cursive1->EntryExitRecord[coverage_idx].EntryAnchor; + g->f.f3.exit_anchor + = &cursive1->EntryExitRecord[coverage_idx].ExitAnchor; + } + break; case 4: if (gidx < 1) @@ -678,12 +762,18 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, g->positioning_type = lookup->LookupType; break; } - else - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); break; case 5: - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + if (gidx < 1) + continue; + if (subtable->Format == 1) + { + /* As the document of this lookup type is quite + ambiguous, and we can't know the exact procedure to + handle it?!? */ + OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + } break; case 6: @@ -710,8 +800,6 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, g->positioning_type = lookup->LookupType; break; } - else - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); break; case 7: @@ -900,52 +988,57 @@ OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring, OTF_GSUB *gsub; OTF_LangSys *LangSys; int *lookup_indices; - int i; + int i, n; if (! otf->gsub && 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; - i = gsub->LookupList.LookupCount; - lookup_indices = alloca (sizeof (int) * i); + /* One lookup may be used by multiple features. */ + lookup_indices = alloca (sizeof (int) + * gsub->LookupList.LookupCount + * gsub->FeatureList.FeatureCount); if (! lookup_indices) OTF_ERROR (OTF_ERROR_MEMORY, " feature list"); - memset (lookup_indices, 0, sizeof (int) * i); - if (setup_lookup_indices (LangSys, &gsub->FeatureList, - features, lookup_indices) < 0) - OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " no lookups"); + n = setup_lookup_indices (LangSys, &gsub->FeatureList, + features, lookup_indices); + if (n < 0) + return errret; - for (i = 0; i < gsub->LookupList.LookupCount; i++) - if (lookup_indices[i]) - { - int gidx; + for (i = 0; i < n; i++) + { + int index = lookup_indices[i]; + int gidx; - if (gsub->LookupList.Lookup[i].LookupType != 8) - { - gidx = 0; - while (gidx < gstring->used) - { - gidx = lookup_gsub (&gsub->LookupList, i, gstring, gidx); - if (gidx < 0) - return errret; - } - } - else - { - gidx = gstring->used - 1; - while (gidx >= 0) - { - gidx = lookup_gsub (&gsub->LookupList, i, gstring, gidx); - if (gidx < 0) - return errret; - } - } - } + if (gsub->LookupList.Lookup[index].LookupType != 8) + { + gidx = 0; + while (gidx < gstring->used) + { + gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx); + if (gidx < 0) + return errret; + } + } + else + { + gidx = gstring->used - 1; + while (gidx >= 0) + { + gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx); + if (gidx < 0) + return errret; + } + } + } return 0; } @@ -959,38 +1052,43 @@ OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring, OTF_GPOS *gpos; OTF_LangSys *LangSys; int *lookup_indices; - int i; + int i, n; if (! otf->gpos && OTF_get_table (otf, "GPOS") < 0) return errret; gpos = otf->gpos; + if (gpos->FeatureList.FeatureCount == 0 + || gpos->LookupList.LookupCount == 0) + return 0; LangSys = get_langsys (&gpos->ScriptList, script, language); if (! LangSys) return errret; - i = gpos->LookupList.LookupCount; - lookup_indices = alloca (sizeof (int) * i); + /* One lookup may be used by multiple features. */ + lookup_indices = alloca (sizeof (int) + * gpos->LookupList.LookupCount + * gpos->FeatureList.FeatureCount); if (! lookup_indices) OTF_ERROR (OTF_ERROR_MEMORY, " feature list"); - memset (lookup_indices, 0, sizeof (int) * i); - if (setup_lookup_indices (LangSys, &gpos->FeatureList, - features, lookup_indices) < 0) - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " no lookups"); + n = setup_lookup_indices (LangSys, &gpos->FeatureList, + features, lookup_indices); + if (n < 0) + return errret; - for (i = 0; i < gpos->LookupList.LookupCount; i++) - if (lookup_indices[i]) - { - int gidx = 0; + for (i = 0; i < n; i++) + { + int index = lookup_indices[i]; + int gidx = 0; - while (gidx < gstring->used) - { - gidx = lookup_gpos (&gpos->LookupList, i, gstring, gidx); - if (gidx < 0) - return errret; - } - } + while (gidx < gstring->used) + { + gidx = lookup_gpos (&gpos->LookupList, index, gstring, gidx); + if (gidx < 0) + return errret; + } + } return 0; } @@ -1004,10 +1102,10 @@ OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring, return -1; if (OTF_drive_gdef (otf, gstring) < 0) return -1; - if ((! gsub_features || gsub_features[0]) + if (gsub_features && OTF_drive_gsub (otf, gstring, script, language, gsub_features) < 0) return -1; - if ((! gpos_features || gpos_features[0]) + if (gpos_features && OTF_drive_gpos (otf, gstring, script, language, gpos_features) < 0) return -1; return 0; diff --git a/src/otfopen.c b/src/otfopen.c index c50b32c..4182137 100644 --- a/src/otfopen.c +++ b/src/otfopen.c @@ -1595,7 +1595,7 @@ read_alternate_set_list (OTF *otf, OTF_Stream *stream, long offset, OTF_AlternateSet **altset) { char *errfmt = "AlternateSet%s"; - int errret = -1; + int errret = 0; unsigned count; int i; @@ -1964,6 +1964,37 @@ read_anchor_array (OTF *otf, OTF_Stream *stream, long offset, return 0; } +static OTF_PairSet * +read_pair_set_list (OTF *otf, OTF_Stream *stream, long offset, unsigned num, + enum OTF_ValueFormat bit1, enum OTF_ValueFormat bit2) +{ + char *errfmt = "PairSet%s"; + void *errret = NULL; + OTF_StreamState state; + OTF_PairSet *set; + int i, j; + + OTF_MALLOC (set, num, ""); + for (i = 0; i < num; i++) + READ_OFFSET (stream, set[i].offset); + SAVE_STREAM (stream, state); + for (i = 0; i < num; i++) + { + SEEK_STREAM (stream, offset + set[i].offset); + READ_UINT16 (stream, set[i].PairValueCount); + OTF_MALLOC (set[i].PairValueRecord, set[i].PairValueCount, ""); + for (j = 0; j < set[i].PairValueCount; j++) + { + OTF_PairValueRecord *rec = set[i].PairValueRecord + j; + + READ_UINT16 (stream, rec->SecondGlyph); + read_value_record (otf, stream, offset, bit1, &rec->Value1); + read_value_record (otf, stream, offset, bit2, &rec->Value2); + } + } + RESTORE_STREAM (stream, state); + return set; +} static OTF_Class1Record * read_class1_record_list (OTF *otf, OTF_Stream *stream, long offset, @@ -1991,6 +2022,87 @@ read_class1_record_list (OTF *otf, OTF_Stream *stream, long offset, return rec; } +static unsigned +read_entry_exit_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_EntryExitRecord **rec) +{ + char *errfmt = "EntryExitSet%s"; + int errret = 0; + unsigned count; + int i; + OTF_StreamState state; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*rec, count, ""); + for (i = 0; i < count; i++) + { + READ_OFFSET (stream, (*rec)[i].EntryAnchor.offset); + READ_OFFSET (stream, (*rec)[i].ExitAnchor.offset); + } + SAVE_STREAM (stream, state); + for (i = 0; i < count; i++) + { + if (read_anchor (otf, stream, offset, &(*rec)[i].EntryAnchor) < 0) + return -1; + if (read_anchor (otf, stream, offset, &(*rec)[i].ExitAnchor) < 0) + return -1; + } + RESTORE_STREAM (stream, state); + return count; +} + +static int +read_ligature_attach (OTF *otf, OTF_Stream *stream, long offset, + unsigned ClassCount, OTF_LigatureAttach *attach) +{ + char *errfmt = "LigatureAttach%s"; + int errret = 1; + int i, j; + + SEEK_STREAM (stream, offset + attach->offset); + READ_UINT16 (stream, attach->ComponentCount); + OTF_MALLOC (attach->ComponentRecord, attach->ComponentCount, ""); + for (i = 0; i < attach->ComponentCount; i++) + { + OTF_MALLOC (attach->ComponentRecord[i].LigatureAnchor, ClassCount, + " (ComponentRecord)"); + for (j = 0; j < ClassCount; j++) + READ_OFFSET (stream, + attach->ComponentRecord[i].LigatureAnchor[j].offset); + } + for (i = 0; i < attach->ComponentCount; i++) + for (j = 0; j < ClassCount; j++) + if (read_anchor (otf, stream, offset + attach->offset, + &attach->ComponentRecord[i].LigatureAnchor[j]) < 0) + return -1; + return 0; +} + +static int +read_ligature_array (OTF *otf, OTF_Stream *stream, long offset, + unsigned class_count, OTF_LigatureArray *array) +{ + char *errfmt = "LigatureArray%s"; + int errret = -1; + OTF_StreamState state; + int i; + + READ_OFFSET (stream, array->offset); + SAVE_STREAM (stream, state); + SEEK_STREAM (stream, offset + array->offset); + READ_UINT16 (stream, array->LigatureCount); + OTF_MALLOC (array->LigatureAttach, array->LigatureCount, ""); + for (i = 0; i < array->LigatureCount; i++) + READ_OFFSET (stream, array->LigatureAttach[i].offset); + for (i = 0; i < array->LigatureCount; i++) + read_ligature_attach (otf, stream, offset + array->offset, + class_count, array->LigatureAttach + i); + RESTORE_STREAM (stream, state); + return 0; +} + static int read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, long offset, unsigned type, @@ -2031,18 +2143,30 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, case 2: if (subtable->Format == 1) { - OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)"); + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; + READ_UINT16 (stream, subtable->u.pair1.ValueFormat1); + READ_UINT16 (stream, subtable->u.pair1.ValueFormat2); + READ_UINT16 (stream, subtable->u.pair1.PairSetCount); + subtable->u.pair1.PairSet + = read_pair_set_list (otf, stream, offset, + subtable->u.pair1.PairSetCount, + subtable->u.pair1.ValueFormat1, + subtable->u.pair1.ValueFormat2); + if (! subtable->u.pair1.PairSet) + return -1; } else if (subtable->Format == 2) { - SEEK_STREAM (stream, offset + 2); - read_coverage (otf, stream, offset, &subtable->Coverage); + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; READ_UINT16 (stream, subtable->u.pair2.ValueFormat1); READ_UINT16 (stream, subtable->u.pair2.ValueFormat2); - read_class_def (otf, stream, offset, - &subtable->u.pair2.ClassDef1); - read_class_def (otf, stream, offset, - &subtable->u.pair2.ClassDef2); + if (read_class_def (otf, stream, offset, + &subtable->u.pair2.ClassDef1) < 0 + || read_class_def (otf, stream, offset, + &subtable->u.pair2.ClassDef2) < 0) + return -1; READ_UINT16 (stream, subtable->u.pair2.Class1Count); READ_UINT16 (stream, subtable->u.pair2.Class2Count); subtable->u.pair2.Class1Record @@ -2051,13 +2175,26 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, subtable->u.pair2.ValueFormat1, subtable->u.pair2.Class2Count, subtable->u.pair2.ValueFormat2); + if (! subtable->u.pair2.Class1Record) + return -1; } else OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); break; case 3: - OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)"); + if (subtable->Format == 1) + { + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; + subtable->u.cursive1.EntryExitCount + = read_entry_exit_list (otf, stream, offset, + &subtable->u.cursive1.EntryExitRecord); + if (! subtable->u.cursive1.EntryExitCount) + return -1; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); break; case 4: @@ -2078,7 +2215,18 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, break; case 5: - OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)"); + if (subtable->Format == 1) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + read_coverage (otf, stream, offset, + &subtable->u.mark_lig1.LigatureCoverage); + READ_UINT16 (stream, subtable->u.mark_lig1.ClassCount); + read_mark_array (otf, stream, offset, + &subtable->u.mark_lig1.MarkArray); + read_ligature_array (otf, stream, offset, + subtable->u.mark_lig1.ClassCount, + &subtable->u.mark_lig1.LigatureArray); + } break; case 6: @@ -2145,7 +2293,24 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, break; case 9: - OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)"); + if (subtable->Format == 1) + { + unsigned ex_type; + long ex_offset; + OTF_LookupSubTableGPOS *ex_subtable; + + READ_USHORT (stream, ex_type); + READ_ULONG (stream, ex_offset); + OTF_CALLOC (ex_subtable, 1, " (SubTable)"); + if (read_lookup_subtable_gpos (otf, stream, offset + ex_offset, + ex_type, ex_subtable) < 0) + return errret; + subtable->u.extension1.ExtensionLookupType = ex_type; + subtable->u.extension1.ExtensionOffset = ex_offset; + subtable->u.extension1.ExtensionSubtable = ex_subtable; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); break; default: @@ -2331,7 +2496,7 @@ get_table_info (OTF *otf, char *name) else if (tag == OTF_tag ("GPOS")) table_info = internal_data->table_info + OTF_TABLE_TYPE_GPOS; else - OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported table name)"); + OTF_ERROR (OTF_ERROR_TABLE, " (unsupported table name)"); if (*table_info->address) /* Already read. */