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);
{
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,
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
IPRINT ("(%s %d)", title, num);
for (i = 0; i < num; i++)
- dump_coverage (indent, NULL, coverage + i);
+ free (dump_coverage (indent, NULL, coverage + i));
}
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++)
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--;
}
}
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)
}
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;
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);
}
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);
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);
}
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");
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);
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,
}
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",
break;
case 8:
- printf (" not-yet-substcount");
+ printf (" not-yet-supported");
break;
default:
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);
{
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)",
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)",
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");
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);
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);
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);
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,
}
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",
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++)
{
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
typedef struct
{
- int dummy;
+ OTF_Anchor EntryAnchor;
+ OTF_Anchor ExitAnchor;
+} OTF_EntryExitRecord;
+
+typedef struct
+{
+ unsigned EntryExitCount;
+ OTF_EntryExitRecord *EntryExitRecord;
} OTF_GPOS_Cursive1;
typedef struct
typedef struct
{
- int dummy;
+ OTF_Anchor *LigatureAnchor; /* [<ClassCount>] */
+} OTF_ComponentRecord;
+
+typedef struct
+{
+ OTF_Offset offset;
+ unsigned ComponentCount;
+ OTF_ComponentRecord *ComponentRecord; /* [<ComponentCount>] */
+} OTF_LigatureAttach;
+
+typedef struct
+{
+ OTF_Offset offset;
+ unsigned LigatureCount;
+ OTF_LigatureAttach *LigatureAttach; /* [<LiagureCount>] */
+} OTF_LigatureArray;
+
+typedef struct
+{
+ OTF_Coverage LigatureCoverage;
+ unsigned ClassCount;
+ OTF_MarkArray MarkArray;
+ OTF_LigatureArray LigatureArray;
} OTF_GPOS_MarkLig1;
typedef struct
typedef struct
{
- int dummy;
+ unsigned ExtensionLookupType;
+ unsigned ExtensionOffset;
+ OTF_LookupSubTableGPOS *ExtensionSubtable;
} OTF_GPOS_Extension1;
font $OTF, and by using features the font has for script $SCRIPT
and language system $LANGSYS, update member <glyphs> 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);
OpenType font $OTF, and by using features the font has for script
$SCRIPT and language system $LANGSYS, setup members
<positioning_type> and <f> 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);
{
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;
}
{
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)
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++)
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;
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)
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:
g->positioning_type = lookup->LookupType;
break;
}
- else
- OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
break;
case 7:
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;
}
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;
}
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;
OTF_AlternateSet **altset)
{
char *errfmt = "AlternateSet%s";
- int errret = -1;
+ int errret = 0;
unsigned count;
int i;
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,
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,
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
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:
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:
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:
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. */