X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Fotfdrive.c;h=0139011dc3e0e28fc609fd6d32e6355f4fe3a19c;hb=36253256d4d13b985db72df9ec0f9ad70e44c664;hp=08b90070d5decce027c5bd0fd5f818f1559c949c;hpb=9f1c238e2a3d35a9503078c934cdf40f52476982;p=m17n%2Flibotf.git diff --git a/src/otfdrive.c b/src/otfdrive.c index 08b9007..0139011 100644 --- a/src/otfdrive.c +++ b/src/otfdrive.c @@ -1,32 +1,49 @@ /* otfdrive.c -- OpenType font driver. -Copyright (C) 2003 - by AIST (National Institute of Advanced Industrial Science and Technology) - Registration Number H15PRO??? +Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 + National Institute of Advanced Industrial Science and Technology (AIST) + Registration Number H15PRO167 -This file is part of the OTF library. +This file is part of libotf. -The OTF library is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2, or (at -your option) any later version. +Libotf is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. -The OTF library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. +Libotf is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. -You should have received a copy of the GNU General Public License -along with the OTF library; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU Lesser General Public +License along with this library, in a file named COPYING; if not, +write to the Free Software Foundation, Inc., 59 Temple Place, Suite +330, Boston, MA 02111-1307, USA. */ #include #include #include +#include #include "otf.h" -#include "otferror.h" +#include "internal.h" + +extern int debug_flag; + +#ifdef USHORT +#undef USHORT +#endif +#define USHORT unsigned short + +/* 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) \ + ((g)->glyph_id == 0 ? -1 \ + : (((flag) & (1 << (g)->GlyphClass)) \ + || (((flag) & OTF_MarkAttachmentType) \ + && (g)->GlyphClass == OTF_GlyphClassMark \ + && ((flag) >> 8) != (g)->MarkAttachClass))) #define GSTRING_DELETE(gstring, from, len) \ do { \ @@ -43,8 +60,9 @@ Boston, MA 02111-1307, USA. */ char *errfmt = "GSTRING%s"; \ \ gstring->size = gstring->used + len; \ - gstring->glyphs = (OTF_Glyph *) realloc (gstring->glyphs, \ - gstring->size); \ + gstring->glyphs \ + = (OTF_Glyph *) realloc (gstring->glyphs, \ + sizeof (OTF_Glyph) * gstring->size); \ if (! gstring->glyphs) \ OTF_ERROR (OTF_ERROR_MEMORY, ""); \ } \ @@ -54,20 +72,57 @@ Boston, MA 02111-1307, USA. */ } while (0) +static unsigned get_class_def (OTF_ClassDef *, OTF_GlyphID); + static int -gstring_subst (OTF_GlyphString *gstring, int from, int to, +gstring_subst (OTF *otf, OTF_GlyphString *gstring, int from, int to, int flag, OTF_GlyphID *ids, int num) { int errret = -1; int len = to - from; int i; + int from_idx = gstring->glyphs[from].f.index.from; + int to_idx = gstring->glyphs[to - 1].f.index.to; + int non_ignored_idx; + + for (i = non_ignored_idx = to - 1; i >= from; i--) + { + OTF_Glyph *g = gstring->glyphs + i; + + if (IGNORED_GLYPH (g, flag) == 1) + { + /* Move this glyph to the next of the current target of + substitution. */ + OTF_Glyph temp = *g; + + memmove (g, g + 1, sizeof (OTF_Glyph) * (non_ignored_idx - i)); + temp.f.index.from = from_idx; + temp.f.index.to = to_idx; + gstring->glyphs[non_ignored_idx--] = temp; + len--; + } + } if (len < num) GSTRING_INSERT (gstring, from, (num - len)); else if (len > num) GSTRING_DELETE (gstring, from, (len - num)); for (i = 0; i < num; i++) - gstring->glyphs[from + i].glyph_id = ids[i]; + { + if (gstring->glyphs[from + i].glyph_id != ids[i]) + { + gstring->glyphs[from + i].c = 0; + if (otf->gdef) + gstring->glyphs[from + i].GlyphClass + = get_class_def (&otf->gdef->glyph_class_def, ids[i]); + else + gstring->glyphs[from + i].GlyphClass = 0; + } + gstring->glyphs[from + i].glyph_id = ids[i]; + gstring->glyphs[from + i].positioning_type = 0; + gstring->glyphs[from + i].f.index.from = from_idx; + gstring->glyphs[from + i].f.index.to = to_idx; + } return 0; } @@ -117,58 +172,83 @@ get_class_def (OTF_ClassDef *class_def, OTF_GlyphID glyph_id) } static OTF_LangSys * -get_langsys (OTF_ScriptList *script_list, char *script, char *language) +get_langsys (OTF_ScriptList *script_list, + const char *script, const char *language) { OTF_Tag script_tag = OTF_tag (script); OTF_Tag langsys_tag = OTF_tag (language); int i, j; + OTF_Tag dflt_tag = OTF_tag ("DFLT"); + OTF_Script *dflt = NULL; for (i = 0; i < script_list->ScriptCount; i++) - if (script_list->Script[i].ScriptTag == script_tag) - { - OTF_Script *script = script_list->Script + i; + { + OTF_Script *script = script_list->Script + i; - if (! langsys_tag) + if (script_list->Script[i].ScriptTag == dflt_tag) + dflt = script; + if (script_list->Script[i].ScriptTag == script_tag) + { + if (! langsys_tag) + return &script->DefaultLangSys; + for (j = 0; j < script->LangSysCount; j++) + if (script->LangSysRecord[j].LangSysTag == langsys_tag) + return script->LangSys + j; return &script->DefaultLangSys; - for (j = 0; j < script->LangSysCount; j++) - if (script->LangSysRecord[j].LangSysTag == langsys_tag) - return script->LangSys + j; - return &script->DefaultLangSys; - } + } + } - return NULL; + if (! dflt) + dflt = script_list->Script; + if (! langsys_tag) + return &dflt->DefaultLangSys; + for (j = 0; j < dflt->LangSysCount; j++) + if (dflt->LangSysRecord[j].LangSysTag == langsys_tag) + return dflt->LangSys + j; + return &dflt->DefaultLangSys; } static int -setup_lookup_indices (OTF_LangSys *LangSys, OTF_FeatureList *FeatureList, - char *features, int *lookup_indices) +setup_lookup_flags (OTF_LookupList *LookupList, OTF_FeatureList *FeatureList, + OTF_LangSys *LangSys, + const char *features, USHORT *lookup_flags) { int i, j, n = 0; OTF_Feature *feature; int *feature_table = alloca (sizeof (int) * FeatureList->FeatureCount); + if (! feature_table) + return -1; for (i = 0; i < FeatureList->FeatureCount; i++) feature_table[i] = 0; + memset (lookup_flags, 0, sizeof (USHORT) * LookupList->LookupCount); while (*features) { char tagname[4]; OTF_Tag tag; + int use_it = 1; if (*features == '*') { /* Consume all remaining features. */ - for (i = 0; i < FeatureList->FeatureCount; i++) - if (! feature_table[i]) - { - feature = FeatureList->Feature + i; - for (j = 0; j < feature->LookupCount; j++) - lookup_indices[n++] = feature->LookupListIndex[j]; - } + for (i = 0; i < LangSys->FeatureCount; i++) + { + int index = LangSys->FeatureIndex[i]; + + if (! feature_table[index]) + { + feature = FeatureList->Feature + index; + for (j = 0; j < feature->LookupCount; j++) + lookup_flags[feature->LookupListIndex[j]] = i + 1; + } + } break; } + if (*features == '~') + use_it = -1, features++; for (i = 0; *features && *features != ','; i++, features++) tagname[i] = *features; if (*features) @@ -177,88 +257,167 @@ setup_lookup_indices (OTF_LangSys *LangSys, OTF_FeatureList *FeatureList, for (; i < 4; i++) tagname[i] = '\0'; tag = OTF_tag (tagname); - for (i = 0; i < FeatureList->FeatureCount; i++) + for (i = 0; i < LangSys->FeatureCount; i++) { - feature = FeatureList->Feature + i; + feature = FeatureList->Feature + LangSys->FeatureIndex[i]; if (tag == feature->FeatureTag) { - for (j = 0; j < feature->LookupCount; j++) - lookup_indices[n++] = feature->LookupListIndex[j]; - feature_table[i] = 1; + if (feature_table[i]) + break; + if (use_it > 0) + for (j = 0; j < feature->LookupCount; j++) + lookup_flags[feature->LookupListIndex[j]] = j + 1; + feature_table[i] = use_it; break; } } } - - return n; + return 0; } static int -match_ids (OTF_GlyphString *gstring, int gidx, int count, OTF_GlyphID *ids) +match_ids (OTF_GlyphString *gstring, int gidx, int flag, + int count, OTF_GlyphID *ids, int direction) { + OTF_Glyph *g = gstring->glyphs + gidx; + OTF_Glyph *gend = gstring->glyphs + (direction > 0 ? gstring->used : -1); int i, j; - if (gstring->used - gidx < count) - 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; + for (i = j = 0; i < count && g != gend; j++, g += direction) + if (! IGNORED_GLYPH (g, flag) + && g->glyph_id != ids[i++]) + return -1; + return (i < count ? -1 : j); } static int -match_chain_ids (OTF_GlyphString *gstring, int gidx, OTF_ChainRule *rule) +match_chain_ids (OTF_GlyphString *gstring, int gidx, int flag, + OTF_ChainRule *rule) { - if (match_ids (gstring, gidx, rule->BacktrackGlyphCount, rule->Backtrack) - < 0) + int i = rule->BacktrackGlyphCount; + + if (i > 0 + && (gidx < i + || match_ids (gstring, gidx - 1, flag, i, rule->Backtrack, -1) < 0)) return -1; - gidx += rule->BacktrackGlyphCount + 1; - if (match_ids (gstring, gidx, rule->InputGlyphCount - 1, rule->Input) - < 0) + gidx++; + i = match_ids (gstring, gidx, flag, + rule->InputGlyphCount - 1, rule->Input, 1); + if (i < 0) return -1; - gidx += rule->InputGlyphCount; - if (match_ids (gstring, gidx, rule->LookaheadGlyphCount - 1, rule->LookAhead) - < 0) + gidx += i; + i = match_ids (gstring, gidx, flag, + rule->LookaheadGlyphCount, rule->LookAhead, 1); + if (i < 0) return -1; return 0; } static int match_classes (OTF_ClassDef *class_def, OTF_GlyphString *gstring, int gidx, - int count, unsigned *classes) + int flag, int count, unsigned *classes, int direction) { - int i; + OTF_Glyph *g = gstring->glyphs + gidx; + OTF_Glyph *gend = gstring->glyphs + (direction > 0 ? gstring->used : -1); + int i, j; + + for (i = j = 0; i < count && g != gend; j++, g += direction) + if (! IGNORED_GLYPH (g, flag) + && get_class_def (class_def, g->glyph_id) != classes[i++]) + return -1; + return (i < count ? -1 : j); +} - if (gstring->used - gidx < count) +static int +match_chain_classes (OTF_GlyphString *gstring, int gidx, int flag, + OTF_ClassDef *BacktrackClassDef, + OTF_ClassDef *InputClassDef, + OTF_ClassDef *LookaheadClassDef, + OTF_ChainClassRule *rule) +{ + int i = rule->BacktrackGlyphCount; + + if (i > 0 + && (gidx < i + || match_classes (BacktrackClassDef, gstring, gidx - 1, flag, i, + rule->Backtrack, -1) < 0)) + return -1; + gidx++; + i = match_classes (InputClassDef, gstring, gidx, flag, + rule->InputGlyphCount - 1, rule->Input, 1); + if (i < 0) return -1; - for (i = 0; i < count; i++) - if (get_class_def (class_def, gstring->glyphs[gidx + i].glyph_id) - != classes[i]) + gidx += i; + i = match_classes (LookaheadClassDef, gstring, gidx, flag, + rule->LookaheadGlyphCount, rule->LookAhead, 1); + if (i < 0) + return -1; + return 0; +} + + +static int +match_coverages (OTF_GlyphString *gstring, int gidx, int flag, int count, + OTF_Coverage *coverages, int direction) +{ + OTF_Glyph *g = gstring->glyphs + gidx; + OTF_Glyph *gend = gstring->glyphs + (direction > 0 ? gstring->used : - 1); + int i, j; + + for (i = j = 0; i < count && g != gend; j++, g += direction) + if (! IGNORED_GLYPH (g, flag) + && get_coverage_index (coverages + i++, g->glyph_id) < 0) return -1; + return (i < count ? -1 : j); +} + +static int +match_chain_coverages (OTF_GlyphString *gstring, int gidx, int flag, + OTF_GSUB_ChainContext3 *context3) +{ + int i = context3->BacktrackGlyphCount; + + if (i > 0 + && (gidx < i + || match_coverages (gstring, gidx - 1, flag, i, + context3->Backtrack, -1) < 0)) + return -1; + gidx++; + if (context3->InputGlyphCount > 1) + { + i = match_coverages (gstring, gidx, flag, context3->InputGlyphCount - 1, + context3->Input + 1, 1); + if (i < 0) + return -1; + gidx += i; + } + if (match_coverages (gstring, gidx, flag, context3->LookaheadGlyphCount, + context3->LookAhead, 1) < 0) + return -1; return 0; } +/* Apply the lookup indexed by LOOKUP_LIST_INDEX in LOOKUP_LIST to the + glyphs indexed by GIDX in GSTRING and the followings. If + successfully applied, return the index of the next glyph to apply + the lookup. If not applied, return GIDX. If error happened, + return -1. */ + static int -lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, - OTF_GlyphString *gstring, int gidx) +lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index, + OTF_GlyphString *gstring, int gidx, int alternate_subst) { char *errfmt = "GSUB Looking up%s"; int errret = -1; OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index; - unsigned int flag = lookup->LookupFlag; + unsigned int flag = (lookup->LookupFlag + & (OTF_LookupFlagIgnoreMask | OTF_MarkAttachmentType)); int orig_gidx = gidx; OTF_Glyph *g = gstring->glyphs + gidx; int i; - if (! g->glyph_id - || (g->GlyphClass - && (flag & (1 << g->GlyphClass)))) - return (gidx + 1); + if (IGNORED_GLYPH (g, flag)) + return gidx; /* Try all subtables until one of them handles the current glyph. */ for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++) @@ -275,6 +434,11 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, subtable = extension1->ExtensionSubtable; } + if (alternate_subst + ? (lookup_type != 3 && lookup_type != 5 && lookup_type != 6) + : (lookup_type == 3)) + continue; + if (subtable->Coverage.offset) { coverage_idx = get_coverage_index (&subtable->Coverage, @@ -283,7 +447,7 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, continue; } - switch (lookup->LookupType) + switch (lookup_type) { case 1: if (subtable->Format == 1) @@ -294,14 +458,17 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, break; case 2: - { - OTF_GSUB_Multiple1 *multiple1 = &subtable->u.multiple1; - OTF_Sequence *seq = multiple1->Sequence + coverage_idx; + if (subtable->Format == 1) + { + OTF_GSUB_Multiple1 *multiple1 = &subtable->u.multiple1; + OTF_Sequence *seq = multiple1->Sequence + coverage_idx; - gstring_subst (gstring, gidx, gidx + 1, - seq->Substitute, seq->GlyphCount); - gidx += seq->GlyphCount; - } + gstring_subst (otf, gstring, gidx, gidx + 1, flag, + seq->Substitute, seq->GlyphCount); + gidx += seq->GlyphCount; + } + else + OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)"); break; case 3: @@ -310,8 +477,9 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, OTF_GSUB_Alternate1 *alt1 = &subtable->u.alternate1; OTF_AlternateSet *altset = alt1->AlternateSet + coverage_idx; - g->glyph_id = altset->Alternate[0]; - gidx++; + gstring_subst (otf, gstring, gidx, gidx + 1, flag, + altset->Alternate, altset->GlyphCount); + gidx += altset->GlyphCount;; } else OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)"); @@ -327,11 +495,14 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, for (j = 0; j < ligset->LigatureCount; j++) { + int n; + lig = ligset->Ligature + j; - if (match_ids (gstring, gidx + 1, - lig->CompCount - 1, lig->Component) < 0) + n = match_ids (gstring, gidx + 1, flag, + lig->CompCount - 1, lig->Component, 1); + if (n < 0) continue; - gstring_subst (gstring, gidx, gidx + lig->CompCount, + gstring_subst (otf, gstring, gidx, gidx + 1 + n, flag, &lig->LigGlyph, 1); gidx++; break; @@ -353,15 +524,16 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, for (j = 0; j < set->RuleCount; j++) { rule = set->Rule + j; - if (match_ids (gstring, gidx + 1, - rule->GlyphCount - 1, rule->Input) < 0) + if (match_ids (gstring, gidx + 1, flag, + rule->GlyphCount - 1, rule->Input, 1) < 0) continue; orig_used = gstring->used; for (k = 0; k < rule->LookupCount; k++) - lookup_gsub (lookup_list, + lookup_gsub (otf, lookup_list, rule->LookupRecord[k].LookupListIndex, gstring, - gidx + rule->LookupRecord[k].SequenceIndex); + gidx + rule->LookupRecord[k].SequenceIndex, + alternate_subst); gidx += rule->GlyphCount + (gstring->used - orig_used); break; } @@ -377,48 +549,43 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, class = get_class_def (&context2->ClassDef, g->glyph_id); set = context2->ClassSet + class; - for (j = 0; j < set->ClassRuleCnt; j++) - { - rule = set->ClassRule + j; - if (match_classes (&context2->ClassDef, - gstring, gidx + 1, - rule->GlyphCount - 1, rule->Class) - < 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->GlyphCount + (gstring->used - orig_used); - break; - } + if (set) + for (j = 0; j < set->ClassRuleCnt; j++) + { + rule = set->ClassRule + j; + if (match_classes (&context2->ClassDef, + gstring, gidx + 1, flag, + rule->GlyphCount - 1, rule->Class, 1) + < 0) + continue; + orig_used = gstring->used; + for (k = 0; k < rule->LookupCount; k++) + lookup_gsub (otf, lookup_list, + rule->LookupRecord[k].LookupListIndex, + gstring, + gidx + rule->LookupRecord[k].SequenceIndex, + alternate_subst); + gidx += rule->GlyphCount + (gstring->used - orig_used); + break; + } } else /* subtable->Format == 3 */ { OTF_GSUB_Context3 *context3 = &subtable->u.context3; int orig_used; - int j, k; + int j; - if (gstring->used - gidx < context3->GlyphCount) - continue; - /* Start from the secoding coverage_idx because the - first one is the same as subtable->Coverage and thus - already tested */ - for (j = 1; j < context3->GlyphCount; j++) - if (get_coverage_index (context3->Coverage + j, - gstring->glyphs[gidx + j].glyph_id) - < 0) - break; - if (j < context3->GlyphCount) + if (match_coverages (gstring, gidx + 1, flag, + context3->GlyphCount - 1, + context3->Coverage + 1, 1) < 0) continue; orig_used = gstring->used; - for (k = 0; k < context3->LookupCount; k++) - lookup_gsub (lookup_list, - context3->LookupRecord[k].LookupListIndex, + for (j = 0; j < context3->LookupCount; j++) + lookup_gsub (otf, lookup_list, + context3->LookupRecord[j].LookupListIndex, gstring, - gidx + context3->LookupRecord[k].SequenceIndex); + gidx + context3->LookupRecord[j].SequenceIndex, + alternate_subst); gidx += context3->GlyphCount + (gstring->used - orig_used); } break; @@ -430,24 +597,24 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx; int orig_used; int j, k; - + for (j = 0; j < set->ChainRuleCount; 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) + if (gidx < rule->BacktrackGlyphCount + || (gidx + rule->InputGlyphCount + + rule->LookaheadGlyphCount) > gstring->used) continue; - if (match_chain_ids (gstring, gidx - backs, rule) < 0) + if (match_chain_ids (gstring, gidx, flag, rule) < 0) continue; orig_used = gstring->used; for (k = 0; k < rule->LookupCount; k++) - lookup_gsub (lookup_list, + lookup_gsub (otf, lookup_list, rule->LookupRecord[k].LookupListIndex, gstring, - gidx + rule->LookupRecord[k].SequenceIndex); + gidx + rule->LookupRecord[k].SequenceIndex, + alternate_subst); gidx += rule->InputGlyphCount + (gstring->used - orig_used); break; } @@ -460,47 +627,30 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, int j; int orig_used; - // printf ("GSUB 6-2: c:0x%x g:0x%x\n", g->c, g->glyph_id); class = get_class_def (&context2->InputClassDef, g->glyph_id); set = context2->ChainClassSet + class; for (j = 0; j < set->ChainClassRuleCnt; j++) { OTF_ChainClassRule *rule = set->ChainClassRule + j; - int fore_idx = gidx + rule->InputGlyphCount; int k; if (gidx < rule->BacktrackGlyphCount || (gidx + rule->InputGlyphCount - + rule->LookaheadGlyphCount) >= gstring->used) - continue; - for (k = 0; k < rule->BacktrackGlyphCount; k++) - if (get_class_def (&context2->BacktrackClassDef, - gstring->glyphs[gidx - 1 - k].glyph_id) - != rule->Backtrack[k]) - break; - if (k < rule->BacktrackGlyphCount) - continue; - for (k = 1; k < rule->InputGlyphCount; k++) - if (get_class_def (&context2->InputClassDef, - gstring->glyphs[gidx + k].glyph_id) - != rule->Input[k - 1]) - break; - if (k < rule->InputGlyphCount) + + rule->LookaheadGlyphCount) > gstring->used) continue; - for (k = 0; k < rule->LookaheadGlyphCount; k++) - if (get_class_def (&context2->LookaheadClassDef, - gstring->glyphs[fore_idx + k].glyph_id) - != rule->LookAhead[k]) - break; - if (k < rule->LookaheadGlyphCount) + if (match_chain_classes (gstring, gidx, flag, + &context2->BacktrackClassDef, + &context2->InputClassDef, + &context2->LookaheadClassDef, + rule) < 0) continue; - orig_used = gstring->used; for (k = 0; k < rule->LookupCount; k++) - lookup_gsub (lookup_list, + lookup_gsub (otf, lookup_list, rule->LookupRecord[k].LookupListIndex, gstring, - gidx + rule->LookupRecord[k].SequenceIndex); + gidx + rule->LookupRecord[k].SequenceIndex, + alternate_subst); gidx += rule->InputGlyphCount + (gstring->used - orig_used); break; } @@ -508,48 +658,22 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, else { OTF_GSUB_ChainContext3 *context3 = &subtable->u.chain_context3; - int back_gidx = gidx - context3->BacktrackGlyphCount; - int fore_gidx = gidx + context3->InputGlyphCount; int orig_used; int j; - if (back_gidx < 0 - || fore_gidx + context3->LookaheadGlyphCount > gstring->used) - break; - - for (j = 0; j < context3->BacktrackGlyphCount; j++) - if (get_coverage_index (context3->Backtrack + j, - gstring->glyphs[gidx - 1 - j].glyph_id) - < 0) - break; - if (j < context3->BacktrackGlyphCount) - continue; - - /* 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++) - if (get_coverage_index (context3->Input + j, - gstring->glyphs[gidx + j].glyph_id) - < 0) - break; - if (j < context3->InputGlyphCount) + if (gidx < context3->BacktrackGlyphCount + || (gidx + context3->InputGlyphCount + + context3->LookaheadGlyphCount) > gstring->used) continue; - - for (j = 0; j < context3->LookaheadGlyphCount; j++) - if (get_coverage_index (context3->LookAhead + j, - gstring->glyphs[fore_gidx + j].glyph_id) - < 0) - break; - if (j < context3->LookaheadGlyphCount) + if (match_chain_coverages (gstring, gidx, flag, context3) < 0) continue; - orig_used = gstring->used; for (j = 0; j < context3->LookupCount; j++) - lookup_gsub (lookup_list, + lookup_gsub (otf, lookup_list, context3->LookupRecord[j].LookupListIndex, gstring, - gidx + context3->LookupRecord[j].SequenceIndex); + gidx + context3->LookupRecord[j].SequenceIndex, + alternate_subst); gidx += context3->InputGlyphCount + (gstring->used - orig_used); } break; @@ -586,155 +710,287 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index, continue; } } - if (gidx == orig_gidx) - { - //printf ("not applied\n"); - gidx++; - } - else - { - // printf ("done\n"); - } return gidx; } /* GPOS */ -unsigned -get_anchor (OTF_Anchor *anchor, OTF_ValueRecord *rec) + +static int +gstring_insert_for_gpos (OTF_GlyphString *gstring, int gidx) { - unsigned value_format = OTF_XPlacement | OTF_YPlacement; + int errret = -1; + int orig_gidx = gidx++; + + while (gidx < gstring->used + && ! gstring->glyphs[gidx].glyph_id + && (gstring->glyphs[gidx].positioning_type & 0xF)) + gidx++; + GSTRING_INSERT (gstring, gidx, 1); + gstring->glyphs[gidx] = gstring->glyphs[orig_gidx]; + gstring->glyphs[gidx].glyph_id = 0; + return gidx; +} - rec->XPlacement = anchor->XCoordinate; - rec->YPlacement = anchor->YCoordinate; +static void +print_anchor (char *head, OTF_Anchor *anchor) +{ if (anchor->AnchorFormat == 1) - /* Nothing to do */ - ; + fprintf (stderr, " %s(X:%d Y:%d)", head, + anchor->XCoordinate, anchor->YCoordinate); else if (anchor->AnchorFormat == 2) - /* Not yet implemented */ - ; - else if (anchor->AnchorFormat == 3) - /* Not yet implemented */ - ; - return value_format; + 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 & 0xF) + { + 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; + } +} + +/* See the comment of lookup_gsub. */ static int lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, - OTF_GlyphString *gstring, int gidx) + OTF_GlyphString *gstring, int gidx, int accumulate) { char *errfmt = "GPOS Looking up%s"; int errret = -1; OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index; - unsigned int flag = lookup->LookupFlag; + unsigned int flag = (lookup->LookupFlag + & (OTF_LookupFlagIgnoreMask | OTF_MarkAttachmentType)); int orig_gidx = gidx; OTF_Glyph *g = gstring->glyphs + gidx; int i; - if (! g->glyph_id - || (g->GlyphClass - && (flag & (1 << g->GlyphClass)))) - return (gidx + 1); + if (debug_flag) + fprintf (stderr, "[GPOS] glyph:%04X lookup:%02d", + g->glyph_id, lookup_list_index); + if (IGNORED_GLYPH (g, flag)) + { + if (debug_flag) + fprintf (stderr, " glyph ignored\n"); + return gidx; + } /* Try all subtables until one of them handles the current glyph. */ for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++) { + unsigned lookup_type = lookup->LookupType; OTF_LookupSubTableGPOS *subtable = lookup->SubTable.gpos + i; int coverage_idx; + int positioning_type; + enum OTF_ValueFormat format; + OTF_ValueRecord *value; + OTF_Anchor *anchor1, *anchor2; + + if (lookup_type == 9) + { + OTF_GPOS_Extension1 *extension1 = &subtable->u.extension1; + + lookup_type = extension1->ExtensionLookupType; + subtable = extension1->ExtensionSubtable; + } - // printf ("subtype:%d ", subtable->Format); + if (debug_flag) + fprintf (stderr, "/%d", lookup_type); if (subtable->Coverage.offset) { coverage_idx = get_coverage_index (&subtable->Coverage, g->glyph_id); if (coverage_idx < 0) - { - // printf ("not covererd "); - continue; - } + continue; } - switch (lookup->LookupType) + switch (lookup_type) { case 1: - g->positioning_type = lookup->LookupType; + positioning_type = lookup_type; if (subtable->Format == 1) { OTF_GPOS_Single1 *single1 = &subtable->u.single1; - g->f.f1.format = single1->ValueFormat; - g->f.f1.value = &single1->Value; + format = single1->ValueFormat; + 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; + format = single2->ValueFormat; + value = single2->Value + coverage_idx; } + if (accumulate && g->positioning_type) + { + gidx = gstring_insert_for_gpos (gstring, gidx); + g = gstring->glyphs + gidx; + } + g->positioning_type + = (g->positioning_type & 0xFFFFFFF0) | positioning_type; + g->f.f1.format = format; + g->f.f1.value = value; + if (debug_flag) + print_glyph_positioning (g, 0); + gidx++; break; case 2: - if (gidx + 1 >= gstring->used) - continue; - if (subtable->Format == 1) - { - OTF_GPOS_Pair1 *pair1 = &subtable->u.pair1; - OTF_PairSet *set = pair1->PairSet + coverage_idx; - int j; + { + int next_gidx; + OTF_Glyph *nextg; - 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) + for (next_gidx = gidx + 1, nextg = gstring->glyphs + next_gidx; + next_gidx < gstring->used && IGNORED_GLYPH (nextg, flag); + next_gidx++, nextg++); + + if (next_gidx >= gstring->used) + continue; + if (subtable->Format == 1) + { + 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 == nextg->glyph_id) { - g++, gidx++; - g->positioning_type = lookup->LookupType; - g->f.f2.format = pair1->ValueFormat2; - g->f.f2.value = &set->PairValueRecord[j].Value2; + if (pair1->ValueFormat1) + { + if (accumulate && (g->positioning_type & 0xF)) + { + gidx = gstring_insert_for_gpos (gstring, gidx); + g = gstring->glyphs + gidx; + next_gidx += gidx - orig_gidx; + nextg = gstring->glyphs + next_gidx; + } + g->positioning_type + = (g->positioning_type & 0xFFFFFFF0) | 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; + if (pair1->ValueFormat2) + { + if (accumulate && (g->positioning_type & 0xF)) + { + gidx = gstring_insert_for_gpos (gstring, gidx); + g = gstring->glyphs + gidx; + } + g->positioning_type + = (g->positioning_type & 0xFFFFFFF0) | lookup_type; + g->f.f2.format = pair1->ValueFormat2; + g->f.f2.value = &set->PairValueRecord[j].Value2; + if (debug_flag) + print_glyph_positioning (g, 2); + } + break; } - } - } - else if (subtable->Format == 2) - { - OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2; - unsigned class1, class2; - - // printf ("GPOS 2-2: c:0x%x g:0x%x\n", g->c, g->glyph_id); - gidx++; - class1 = get_class_def (&pair2->ClassDef1, g->glyph_id); - class2 = get_class_def (&pair2->ClassDef2, g[1].glyph_id); - g->positioning_type = lookup->LookupType; - g->f.f2.format = pair2->ValueFormat1; - g->f.f2.value - = &pair2->Class1Record[class1].Class2Record[class2].Value1; - if (pair2->ValueFormat2) - { - g++, gidx++; - g->positioning_type = lookup->LookupType; - g->f.f2.format = pair2->ValueFormat2; - g->f.f2.value - = &pair2->Class1Record[class1].Class2Record[class2].Value2; - } - } + } + else if (subtable->Format == 2) + { + OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2; + unsigned class1, class2; + + class1 = get_class_def (&pair2->ClassDef1, g->glyph_id); + class2 = get_class_def (&pair2->ClassDef2, nextg->glyph_id); + if (pair2->ValueFormat1) + { + if (accumulate && (g->positioning_type & 0xF)) + { + gidx = gstring_insert_for_gpos (gstring, gidx); + g = gstring->glyphs + gidx; + next_gidx += gidx - orig_gidx; + nextg = gstring->glyphs + next_gidx; + } + g->positioning_type + = (g->positioning_type & 0xFFFFFFF0) | lookup_type; + 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; + if (pair2->ValueFormat2) + { + if (accumulate && (g->positioning_type & 0xF)) + { + gidx = gstring_insert_for_gpos (gstring, gidx); + g = gstring->glyphs + gidx; + } + g->positioning_type + = (g->positioning_type & 0xFFFFFFF0) | lookup_type; + g->f.f2.format = pair2->ValueFormat2; + g->f.f2.value + = &pair2->Class1Record[class1].Class2Record[class2].Value2; + if (debug_flag) + print_glyph_positioning (g, 2); + } + } + } break; case 3: { OTF_GPOS_Cursive1 *cursive1 = &subtable->u.cursive1; - - g->positioning_type = lookup->LookupType; + + g->positioning_type + = (g->positioning_type & 0xFFFFFFF0) | 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; @@ -746,21 +1002,31 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, OTF_GPOS_MarkBase1 *mark_base1 = &subtable->u.mark_base1; OTF_MarkRecord *mark_record; OTF_AnchorRecord *base_record; - int coverage_idx_base + OTF_Glyph *baseg; + int coverage_idx_base; + unsigned int this_flag = flag | OTF_IgnoreMarks; + + for (baseg = g - 1; + baseg >= gstring->glyphs && IGNORED_GLYPH (baseg, this_flag); + baseg--); + if (baseg < gstring->glyphs) + continue; + coverage_idx_base = get_coverage_index (&mark_base1->BaseCoverage, - g[-1].glyph_id); - + baseg->glyph_id); if (coverage_idx_base < 0) continue; - // printf ("GPOS 4-1: c:0x%x g:0x%x\n", g->c, g->glyph_id); mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx; base_record = mark_base1->BaseArray.AnchorRecord + coverage_idx_base; g->f.f4.mark_anchor = &mark_record->MarkAnchor; g->f.f4.base_anchor = &base_record->Anchor[mark_record->Class]; - g->positioning_type = lookup->LookupType; - break; + g->positioning_type + = (g->positioning_type & 0xFFFFFFF0) | lookup_type; + if (debug_flag) + print_glyph_positioning (g, 0); + gidx++; } break; @@ -769,10 +1035,54 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, 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)"); + OTF_GPOS_MarkLig1 *mark_lig1 = &subtable->u.mark_lig1; + OTF_Glyph *ligg; + int coverage_idx_lig; + OTF_MarkRecord *mark_record; + OTF_LigatureAttach *attach; + int *num_class = alloca (sizeof (int) * mark_lig1->ClassCount); + int j; + + for (j = 0; j < mark_lig1->ClassCount; j++) + num_class[j] = 0; + + for (ligg = g - 1; + (ligg >= gstring->glyphs + && (IGNORED_GLYPH (ligg, flag) + || ligg->GlyphClass > OTF_GlyphClassLigature)); + ligg--) + if ((ligg->positioning_type & 0xF) == 5 + && ligg->MarkAttachClass < mark_lig1->ClassCount) + num_class[ligg->MarkAttachClass]++; + if (ligg < gstring->glyphs) + continue; + coverage_idx_lig + = get_coverage_index (&mark_lig1->LigatureCoverage, + ligg->glyph_id); + if (coverage_idx_lig < 0) + continue; + mark_record = mark_lig1->MarkArray.MarkRecord + coverage_idx; + g->MarkAttachClass = mark_record->Class; + attach = (mark_lig1->LigatureArray.LigatureAttach + + coverage_idx_lig); + for (j = 0; j < attach->ComponentCount; j++) + { + OTF_Anchor *lig_anchor + = attach->ComponentRecord[j].LigatureAnchor; + + if (lig_anchor[mark_record->Class].AnchorFormat + && num_class[mark_record->Class]-- == 0) + { + g->positioning_type + = (g->positioning_type & 0xFFFFFFF0) | 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; + } + } } break; @@ -784,140 +1094,603 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index, OTF_GPOS_MarkMark1 *mark_mark1 = &subtable->u.mark_mark1; OTF_MarkRecord *mark1_record; OTF_AnchorRecord *mark2_record; - int coverage_idx_base - = get_coverage_index (&mark_mark1->Mark2Coverage, - g[-1].glyph_id); + OTF_Glyph *prevg; + int coverage_idx_base; + for (prevg = g - 1; + prevg >= gstring->glyphs && IGNORED_GLYPH (prevg, flag); + prevg--); + if (prevg < gstring->glyphs) + continue; + coverage_idx_base + = get_coverage_index (&mark_mark1->Mark2Coverage, + prevg->glyph_id); if (coverage_idx_base < 0) continue; - // printf ("GPOS 6-1: c:0x%x g:0x%x\n", g->c, g->glyph_id); mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx; mark2_record = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base; g->f.f6.mark1_anchor = &mark1_record->MarkAnchor; g->f.f6.mark2_anchor = &mark2_record->Anchor[mark1_record->Class]; - g->positioning_type = lookup->LookupType; + g->positioning_type + = (g->positioning_type & 0xFFFFFFF0) | lookup_type; + if (debug_flag) + print_glyph_positioning (g, 0); + gidx++; break; } break; case 7: - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); - break; - - case 8: if (subtable->Format == 1) - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); - else if (subtable->Format == 2) { - OTF_GPOS_ChainContext2 *context2 = &subtable->u.chain_context2; - OTF_ChainClassSet *set; - unsigned class; - int j; + OTF_GPOS_Context1 *context1 = &subtable->u.context1; + OTF_RuleSet *set = context1->RuleSet + coverage_idx; + OTF_Rule *rule; int orig_used; + int j, k; - // printf ("GPOS 8-2: c:0x%x g:0x%x\n", g->c, g->glyph_id); - class = get_class_def (&context2->InputClassDef, g->glyph_id); - set = context2->ChainClassSet + class; - for (j = 0; j < set->ChainClassRuleCnt; j++) + for (j = 0; j < set->RuleCount; j++) { - OTF_ChainClassRule *rule = set->ChainClassRule + j; - int fore_idx = gidx + rule->InputGlyphCount; - int k; - - if (gidx < rule->BacktrackGlyphCount - || (gidx + rule->InputGlyphCount - + rule->LookaheadGlyphCount) >= gstring->used) - continue; - for (k = 0; k < rule->BacktrackGlyphCount; k++) - if (get_class_def (&context2->BacktrackClassDef, - gstring->glyphs[gidx - 1 - k].glyph_id) - != rule->Backtrack[k]) - break; - if (k < rule->BacktrackGlyphCount) - continue; - for (k = 1; k < rule->InputGlyphCount; k++) - if (get_class_def (&context2->InputClassDef, - gstring->glyphs[gidx + k].glyph_id) - != rule->Input[k - 1]) - break; - if (k < rule->InputGlyphCount) - continue; - for (k = 0; k < rule->LookaheadGlyphCount; k++) - if (get_class_def (&context2->LookaheadClassDef, - gstring->glyphs[fore_idx + k].glyph_id) - != rule->LookAhead[k]) - break; - if (k < rule->LookaheadGlyphCount) + rule = set->Rule + j; + if (match_ids (gstring, gidx + 1, flag, + rule->GlyphCount - 1, rule->Input, 1) < 0) continue; - orig_used = gstring->used; for (k = 0; k < rule->LookupCount; k++) lookup_gpos (lookup_list, rule->LookupRecord[k].LookupListIndex, gstring, - gidx + rule->LookupRecord[k].SequenceIndex); - gidx += rule->InputGlyphCount + (gstring->used - orig_used); + gidx + rule->LookupRecord[k].SequenceIndex, + accumulate); + gidx += rule->GlyphCount + (gstring->used - orig_used); break; } } - else if (subtable->Format == 3) - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); - else - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (invalid subformat)"); - break; + else if (subtable->Format == 2) + { + OTF_GPOS_Context2 *context2 = &subtable->u.context2; + OTF_ClassSet *set; + OTF_ClassRule *rule; + unsigned class; + int orig_used; + int j, k; + + class = get_class_def (&context2->ClassDef, g->glyph_id); + set = context2->ClassSet + class; + if (set) + for (j = 0; j < set->ClassRuleCnt; j++) + { + rule = set->ClassRule + j; + if (match_classes (&context2->ClassDef, + gstring, gidx + 1, flag, + rule->GlyphCount - 1, rule->Class, 1) + < 0) + continue; + orig_used = gstring->used; + for (k = 0; k < rule->LookupCount; k++) + lookup_gpos (lookup_list, + rule->LookupRecord[k].LookupListIndex, + gstring, + gidx + rule->LookupRecord[k].SequenceIndex, + accumulate); + gidx += rule->GlyphCount + (gstring->used - orig_used); + break; + } + } + else /* subtable->Format == 3 */ + { + OTF_GPOS_Context3 *context3 = &subtable->u.context3; + int orig_used; + int j; - case 9: - OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)"); + if (match_coverages (gstring, gidx + 1, flag, + context3->GlyphCount - 1, + context3->Coverage + 1, 1) < 0) + continue; + orig_used = gstring->used; + for (j = 0; j < context3->LookupCount; j++) + lookup_gpos (lookup_list, + context3->LookupRecord[j].LookupListIndex, + gstring, + gidx + context3->LookupRecord[j].SequenceIndex, + accumulate); + gidx += context3->GlyphCount + (gstring->used - orig_used); + } break; - default: - continue; - } + case 8: + if (subtable->Format == 1) + { + OTF_GPOS_ChainContext1 *context1 = &subtable->u.chain_context1; + OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx; + int orig_used; + int j, k; + + for (j = 0; j < set->ChainRuleCount; j++) + { + OTF_ChainRule *rule = set->ChainRule + j; + + if (gidx < rule->BacktrackGlyphCount + || (gidx + rule->InputGlyphCount + + rule->LookaheadGlyphCount) > gstring->used) + continue; + if (match_chain_ids (gstring, gidx, flag, rule) < 0) + continue; + orig_used = gstring->used; + for (k = 0; k < rule->LookupCount; k++) + lookup_gpos (lookup_list, + rule->LookupRecord[k].LookupListIndex, + gstring, + gidx + rule->LookupRecord[k].SequenceIndex, + accumulate); + gidx += rule->InputGlyphCount + (gstring->used - orig_used); + break; + } + } + else if (subtable->Format == 2) + { + OTF_GPOS_ChainContext2 *context2 = &subtable->u.chain_context2; + OTF_ChainClassSet *set; + unsigned class; + int j; + int orig_used; + + class = get_class_def (&context2->InputClassDef, g->glyph_id); + set = context2->ChainClassSet + class; + for (j = 0; j < set->ChainClassRuleCnt; j++) + { + OTF_ChainClassRule *rule = set->ChainClassRule + j; + int k; + + if (gidx < rule->BacktrackGlyphCount + || (gidx + rule->InputGlyphCount + + rule->LookaheadGlyphCount) > gstring->used) + continue; + if (match_chain_classes (gstring, gidx, flag, + &context2->BacktrackClassDef, + &context2->InputClassDef, + &context2->LookaheadClassDef, + rule) < 0) + continue; + orig_used = gstring->used; + for (k = 0; k < rule->LookupCount; k++) + lookup_gpos (lookup_list, + rule->LookupRecord[k].LookupListIndex, + gstring, + gidx + rule->LookupRecord[k].SequenceIndex, + accumulate); + gidx += rule->InputGlyphCount + (gstring->used - orig_used); + break; + } + } + else if (subtable->Format == 3) + { + OTF_GPOS_ChainContext3 *context3 = &subtable->u.chain_context3; + int orig_used; + int j; + + if (gidx < context3->BacktrackGlyphCount + || (gidx + context3->InputGlyphCount + + context3->LookaheadGlyphCount) > gstring->used) + continue; + if (match_chain_coverages (gstring, gidx, flag, context3) < 0) + continue; + orig_used = gstring->used; + for (j = 0; j < context3->LookupCount; j++) + lookup_gpos (lookup_list, + context3->LookupRecord[j].LookupListIndex, + gstring, + gidx + context3->LookupRecord[j].SequenceIndex, + accumulate); + gidx += context3->InputGlyphCount + (gstring->used - orig_used); + } + else + OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (invalid subformat)"); + break; + + default: + continue; + } } - if (gidx == orig_gidx) + if (debug_flag) { - // printf ("not applied\n"); - gidx++; + if (gidx == orig_gidx) + fprintf (stderr, " no match\n"); + else + fprintf (stderr, "\n"); } - else + return gidx; +} + +static unsigned +lookup_encoding_0 (int c, OTF_EncodingSubtable *sub) +{ + return ((c < 0 || c >= 256) + ? 0 + : sub->f.f0->glyphIdArray[c]); +} + +static unsigned +lookup_encoding_2 (int c, OTF_EncodingSubtable *sub) +{ + return 0; +} + +static unsigned +lookup_encoding_4 (int c, OTF_EncodingSubtable *sub) +{ + int segCount, i; + OTF_EncodingSubtable4 *sub4; + + if (c < 0) + return 0; + sub4 = sub->f.f4; + segCount = sub4->segCountX2 / 2; + for (i = 0; i < segCount; i++) { - // printf ("done\n"); + OTF_cmapSegment *seg = sub4->segments + i; + + 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 gidx; + return 0; +} + +static unsigned +lookup_encoding_6 (int c, OTF_EncodingSubtable *sub) +{ + return 0; +} + +static unsigned +lookup_encoding_8 (int c, OTF_EncodingSubtable *sub) +{ + return 0; +} + +static unsigned +lookup_encoding_10 (int c, OTF_EncodingSubtable *sub) +{ + return 0; +} + +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) +{ + unsigned nRecords = sub14->nRecords; + OTF_VariationSelectorRecord *record; + unsigned i; + + for (i = 0; i < nRecords; i++) + { + record = &sub14->Records[i]; + if (record->varSelector == c2) + { + if (record->defaultUVSOffset) + { + OTF_UnicodeValueRange *uVRs = record->unicodeValueRanges; + unsigned numUVRs = record->numUnicodeValueRanges; + unsigned top = numUVRs, bottom = 0, middle; + + if (uVRs[0].startUnicodeValue <= c1) + { + unsigned additionalCount, startUnicodeValue; + + for (;;) + { + middle = (top + bottom) / 2; + if (c1 < uVRs[middle].startUnicodeValue) + top = middle; + else if (bottom == middle) + break; + else + bottom = middle; + } + startUnicodeValue = uVRs[bottom].startUnicodeValue; + additionalCount = uVRs[bottom].additionalCount; + if (c1 <= startUnicodeValue + additionalCount) + return get_GlyphID (cmap, c1); + } + } + if (record->nonDefaultUVSOffset) + { + OTF_UVSMapping *uvsMappings = record->uvsMappings; + unsigned numUVSMs = record->numUVSMappings; + unsigned top = numUVSMs, bottom = 0, middle; + + if (uvsMappings[0].unicodeValue <= c1) + { + for (;;) + { + middle = (top + bottom) / 2; + if (c1 < uvsMappings[middle].unicodeValue) + top = middle; + else if (bottom == middle) + break; + else + bottom = middle; + } + if (uvsMappings[bottom].unicodeValue == c1) + return uvsMappings[bottom].glyphID; + } + } + return 0; + } + } + return 0; +} + +static void +check_cmap_uvs (OTF_cmap *cmap, OTF_GlyphString *gstring, int idx) +{ + OTF_EncodingSubtable14 *sub14; + int c1 = gstring->glyphs[idx - 1].c; + int c2 = gstring->glyphs[idx].c; + OTF_GlyphID code; + int i; + + gstring->glyphs[idx].glyph_id = 0; + for (i = 0; i < cmap->numTables; i++) + if (cmap->EncodingRecord[i].subtable.format == 14) + break; + if (i == cmap->numTables) + return; + code = get_uvs_glyph (cmap, cmap->EncodingRecord[i].subtable.f.f14, c1, c2); + if (code == 0) + return; + gstring->glyphs[idx - 1].glyph_id = code; + gstring->glyphs[idx - 1].f.index.to = gstring->glyphs[idx].f.index.to; + gstring->used--; + memmove (gstring->glyphs + idx, gstring->glyphs + idx + 1, + sizeof (OTF_Glyph) * (gstring->used - 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 }; + +static 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) \ + (((C) >= 0xFE00 && (C) <= 0xFE0F) || ((C) >= 0xE0100 && (C) <= 0xE01EF)) + int 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; - for (i = 0; i < gstring->used; i++) + if (cmap->table_index < 0) + lookupper = NULL; + else { - int c = gstring->glyphs[i].c; - if (c < 32 || ! cmap || ! cmap->unicode_table) - gstring->glyphs[i].glyph_id = 0; - else - gstring->glyphs[i].glyph_id = cmap->unicode_table[c]; - if (gstring->glyphs[i].glyph_id < 0) - return -1; + 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) + { + 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 if (lookupper) + gstring->glyphs[i].glyph_id = lookupper (c, sub); + } return 0; } int +OTF_drive_cmap2 (OTF *otf, OTF_GlyphString *gstring, + int platform_id, int encoding_id) +{ + OTF_cmap *cmap; + int i; + 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) + return -1; + + cmap = otf->cmap; + for (i = 0; i < cmap->numTables; i++) + if (cmap->EncodingRecord[i].platformID == platform_id + && cmap->EncodingRecord[i].encodingID == encoding_id) + break; + if (i == cmap->numTables) + OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (unknown platformID/encodingID)"); + enc = cmap->EncodingRecord + i; + 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); + } +} + + +int +OTF_get_unicode (OTF *otf, OTF_GlyphID code) +{ + if (! otf->cmap + && OTF_get_table (otf, "cmap") < 0) + return 0; + if (code == 0 + || code > otf->cmap->max_glyph_id + || ! otf->cmap->decode_table) + return 0; + return otf->cmap->decode_table[code]; +} + +int +OTF_get_variation_glyphs (OTF *otf, int c, OTF_GlyphID code[256]) +{ + int i, n; + OTF_cmap *cmap; + OTF_EncodingSubtable14 *sub14; + + memset (code, 0, sizeof (OTF_GlyphID) * 256); + if (! otf->cmap + && OTF_get_table (otf, "cmap") < 0) + return 0; + cmap = otf->cmap; + for (i = 0; i < cmap->numTables; i++) + if (cmap->EncodingRecord[i].subtable.format == 14) + break; + if (i == cmap->numTables) + return 0; + sub14 = cmap->EncodingRecord[i].subtable.f.f14; + for (i = 0, n = 0; i < 256; i++) + { + int uvs = (i < 16 ? 0xFE00 + i : 0xE0100 + (i - 16)); + + if ((code[i] = get_uvs_glyph (cmap, sub14, c, uvs))) + n++; + } + return n; +} + + +int OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring) { OTF_GDEF *gdef; @@ -933,6 +1706,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++) @@ -943,20 +1720,27 @@ OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring) return 0; } - -int -OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring, - char *script, char *language, char *features) +static int +OTF_drive_gsub_internal (OTF *otf, OTF_GlyphString *gstring, + const char *script, const char *language, + const char *features, + int alternate_subst, int with_log) { char *errfmt = "GSUB driving%s"; int errret = -1; OTF_GSUB *gsub; OTF_LangSys *LangSys; - int *lookup_indices; - int i, n; + USHORT *lookup_flags; + int i; + USHORT *log; + + for (i = 0; i < gstring->used; i++) + { + gstring->glyphs[i].f.index.from = gstring->glyphs[i].f.index.to = i; + gstring->glyphs[i].positioning_type = 0; + } - if (! otf->gsub - && OTF_get_table (otf, "GSUB") < 0) + if (OTF_get_table (otf, "GSUB") < 0) return errret; gsub = otf->gsub; if (gsub->FeatureList.FeatureCount == 0 @@ -967,30 +1751,39 @@ OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring, if (! LangSys) return errret; - /* One lookup may be used by multiple features. */ - lookup_indices = alloca (sizeof (int) - * gsub->LookupList.LookupCount - * gsub->FeatureList.FeatureCount); - if (! lookup_indices) + lookup_flags = alloca (sizeof (USHORT) * gsub->LookupList.LookupCount); + if (! lookup_flags + || setup_lookup_flags (&gsub->LookupList, &gsub->FeatureList, LangSys, + features, lookup_flags) < 0) OTF_ERROR (OTF_ERROR_MEMORY, " feature list"); - n = setup_lookup_indices (LangSys, &gsub->FeatureList, - features, lookup_indices); - if (n < 0) - return errret; - for (i = 0; i < n; i++) + for (i = 0; i < gsub->LookupList.LookupCount; i++) { - int index = lookup_indices[i]; int gidx; + int j; - if (gsub->LookupList.Lookup[index].LookupType != 8) + if (! lookup_flags[i]) continue; + + if (gsub->LookupList.Lookup[i].LookupType != 8) { gidx = 0; while (gidx < gstring->used) { - gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx); - if (gidx < 0) + int result = lookup_gsub (otf, &gsub->LookupList, i, gstring, + gidx, alternate_subst); + if (result < 0) return errret; + if (gidx < result) + { + if (with_log) + for (j = gidx; j < result; j++) + gstring->glyphs[j].positioning_type + = ((gstring->glyphs[j].positioning_type & 0xF) + | (lookup_flags[i] << 4)); + gidx = result; + } + else + gidx++; } } else @@ -998,9 +1791,21 @@ OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring, gidx = gstring->used - 1; while (gidx >= 0) { - gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx); - if (gidx < 0) + int result = lookup_gsub (otf, &gsub->LookupList, i, gstring, + gidx, alternate_subst); + if (result < 0) return errret; + if (gidx > result) + { + if (with_log) + for (j = gidx; j > result; j--) + gstring->glyphs[j].positioning_type + = ((gstring->glyphs[j].positioning_type & 0xF) + | (lookup_flags[i] << 4)); + gidx = result; + } + else + gidx--; } } } @@ -1009,18 +1814,43 @@ OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring, } int -OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring, - char *script, char *language, char *features) +OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring, + const char *script, const char *language, const char *features) +{ + if (! otf->cmap) + OTF_get_table (otf, "cmap"); + return OTF_drive_gsub_internal (otf, gstring, script, language, features, + 0, 0); +} + +int +OTF_drive_gsub_with_log (OTF *otf, OTF_GlyphString *gstring, + const char *script, const char *language, + const char *features) +{ + if (! otf->cmap) + OTF_get_table (otf, "cmap"); + return OTF_drive_gsub_internal (otf, gstring, script, language, features, + 0, 1); +} + +static int +OTF_drive_gpos_internal (OTF *otf, OTF_GlyphString *gstring, + const char *script, const char *language, + const char *features, + int accumulate, int with_log) { char *errfmt = "GPOS driving%s"; int errret = -1; OTF_GPOS *gpos; OTF_LangSys *LangSys; - int *lookup_indices; + USHORT *lookup_flags; int i, n; - if (! otf->gpos - && OTF_get_table (otf, "GPOS") < 0) + for (i = 0; i < gstring->used; i++) + gstring->glyphs[i].positioning_type = 0; + + if (OTF_get_table (otf, "GPOS") < 0) return errret; gpos = otf->gpos; if (gpos->FeatureList.FeatureCount == 0 @@ -1031,27 +1861,36 @@ OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring, if (! LangSys) return errret; - /* One lookup may be used by multiple features. */ - lookup_indices = alloca (sizeof (int) - * gpos->LookupList.LookupCount - * gpos->FeatureList.FeatureCount); - if (! lookup_indices) + lookup_flags = alloca (sizeof (USHORT) * gpos->LookupList.LookupCount); + if (! lookup_flags + || setup_lookup_flags (&gpos->LookupList, &gpos->FeatureList, LangSys, + features, lookup_flags) < 0) OTF_ERROR (OTF_ERROR_MEMORY, " feature list"); - n = setup_lookup_indices (LangSys, &gpos->FeatureList, - features, lookup_indices); - if (n < 0) - return errret; - for (i = 0; i < n; i++) + for (i = 0; i < gpos->LookupList.LookupCount; i++) { - int index = lookup_indices[i]; int gidx = 0; + int j; + + if (! lookup_flags[i]) continue; while (gidx < gstring->used) { - gidx = lookup_gpos (&gpos->LookupList, index, gstring, gidx); - if (gidx < 0) + int result = lookup_gpos (&gpos->LookupList, i, gstring, gidx, + accumulate); + if (result < 0) return errret; + if (gidx < result) + { + if (with_log) + for (j = gidx; j < result; j++) + gstring->glyphs[j].positioning_type + = ((gstring->glyphs[j].positioning_type & 0xF) + | (lookup_flags[i] << 4)); + gidx = result; + } + else + gidx++; } } @@ -1059,9 +1898,40 @@ OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring, } int +OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring, + const char *script, const char *language, const char *features) +{ + if (! otf->cmap) + OTF_get_table (otf, "cmap"); + return OTF_drive_gpos_internal (otf, gstring, script, language, features, + 0, 0); +} + +int +OTF_drive_gpos2 (OTF *otf, OTF_GlyphString *gstring, + const char *script, const char *language, const char *features) +{ + if (! otf->cmap) + OTF_get_table (otf, "cmap"); + return OTF_drive_gpos_internal (otf, gstring, script, language, features, + 1, 0); +} + +int +OTF_drive_gpos_with_log (OTF *otf, OTF_GlyphString *gstring, + const char *script, const char *language, + const char *features) +{ + if (! otf->cmap) + OTF_get_table (otf, "cmap"); + return OTF_drive_gpos_internal (otf, gstring, script, language, features, + 1, 1); +} + +int OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring, - char *script, char *language, - char *gsub_features, char *gpos_features) + const char *script, const char *language, + const char *gsub_features, const char *gpos_features) { if (OTF_drive_cmap (otf, gstring) < 0) return -1; @@ -1075,3 +1945,185 @@ OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring, return -1; return 0; } + +int +OTF_drive_gsub_alternate (OTF *otf, OTF_GlyphString *gstring, + const char *script, const char *language, + const char *features) +{ + return OTF_drive_gsub_internal (otf, gstring, script, language, features, + 1, 0); +} + +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; + USHORT *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 (sizeof (USHORT) * 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; +}