def unparseMarkToMark(self, lookup): """Turn a GPOS6 (mark to mark) subtable into a fontFeatures Routine.""" b = fontFeatures.Routine(name=self.getname("MarkToMark" + self.gensym())) self._fix_flags(b, lookup) for subtable in lookup.SubTable: # fontTools.ttLib.tables.otTables.MarkBasePos assert subtable.Format == 1 for classId in range(0, subtable.ClassCount): anchorClassPrefix = "Anchor" + self.gensym() marks = self._formatMarkArray( subtable.Mark1Array, subtable.Mark1Coverage, classId ) bases = self._formatMark2Array( subtable.Mark2Array, subtable.Mark2Coverage, classId ) b.addRule( fontFeatures.Attachment( anchorClassPrefix, anchorClassPrefix + "_", bases, marks, font=self.font, address=self.currentLookup, flags=lookup.LookupFlag, force_markmark=True ) ) return b, []
def action(self, parser, aFrom, aTo, attachtype): bases = {} marks = {} def _category(k): return parser.fontfeatures.glyphclasses.get( k, parser.font[k].category) for k, v in parser.fontfeatures.anchors.items(): if aFrom in v: bases[k] = v[aFrom] if aTo in v: marks[k] = v[aTo] if attachtype == "marks": bases = { k: v for k, v in bases.items() if _category(k) == "mark" } else: bases = { k: v for k, v in bases.items() if _category(k) == "base" } if attachtype != "cursive": marks = { k: v for k, v in marks.items() if _category(k) == "mark" } return [ fontFeatures.Routine(rules=[ fontFeatures.Attachment( aFrom, aTo, bases, marks, font=parser.font) ]) ]
def unparseCursiveAttachment(self, lookup): """Turn a GPOS3 (cursive attachment) subtable into a fontFeatures Routine.""" b = fontFeatures.Routine(name=self.getname("CursiveAttachment" + self.gensym())) self._fix_flags(b, lookup) entries = {} exits = {} for s in lookup.SubTable: assert s.Format == 1 for glyph, record in zip(s.Coverage.glyphs, s.EntryExitRecord): if record.EntryAnchor: entries[glyph] = ( record.EntryAnchor.XCoordinate, record.EntryAnchor.YCoordinate, ) if record.ExitAnchor: exits[glyph] = ( record.ExitAnchor.XCoordinate, record.ExitAnchor.YCoordinate, ) b.addRule( fontFeatures.Attachment( "cursive_entry", "cursive_exit", entries, exits, flags=lookup.LookupFlag, address=self.currentLookup, ) ) return b, []
def add_cursive_pos(self, location, glyphclass, entryAnchor, exitAnchor): self._start_routine_if_necessary(location) location = "%s:%i:%i" % (location) basedict, markdict = {}, {} if entryAnchor: basedict = {g: (entryAnchor.x, entryAnchor.y) for g in glyphclass} if exitAnchor: markdict = {g: (exitAnchor.x, exitAnchor.y) for g in glyphclass} s = fontFeatures.Attachment(base_name="cursive_entry", mark_name="cursive_exit", bases=basedict, marks=markdict, address=location, languages=self.currentLanguage) self.currentRoutine.addRule(s)
def add_mark_base_pos(self, location, bases, marks): location = "%s:%i:%i" % (location) for baseanchor, markclass in marks: assert len(markclass.definitions) == 1 markanchor = markclass.definitions[0].anchor s = fontFeatures.Attachment( base_name=markclass.name, mark_name=markclass.name, bases={g: (baseanchor.x, baseanchor.y) for g in bases}, marks={ g: (markanchor.x, markanchor.y) for g in markclass.glyphs.keys() }, address=location, ) self.currentRoutine.addRule(s)
def add_mark_base_pos(self, location, bases, marks): self._start_routine_if_necessary(location) location = "%s:%i:%i" % (location) for baseanchor, markclass in marks: assert len(markclass.definitions) == 1 markanchor = markclass.definitions[0].anchor s = fontFeatures.Attachment( base_name=markclass.name, mark_name=markclass.name, bases={g: (baseanchor.x, baseanchor.y) for g in bases}, marks={ g: (markanchor.x, markanchor.y) for g in markclass.glyphs.keys() }, address=location, languages=self.currentLanguage) s.fontfeatures = self.ff self.currentRoutine.addRule(s)
def action(self, args): (aFrom, aTo, attachtype) = args bases = {} marks = {} catcache = {} def _category(k): if k not in catcache: catcache[k] = self.parser.fontfeatures.glyphclasses.get( k, self.parser.font[k].category) return catcache[k] for k, v in self.parser.fontfeatures.anchors.items(): if aFrom in v: bases[k] = v[aFrom] if aTo in v: marks[k] = v[aTo] if attachtype == "marks": bases = { k: v for k, v in bases.items() if _category(k) == "mark" } else: bases = { k: v for k, v in bases.items() if _category(k) == "base" } if attachtype != "cursive": marks = { k: v for k, v in marks.items() if _category(k) == "mark" } return [ fontFeatures.Routine(rules=[ fontFeatures.Attachment( aFrom, aTo, bases, marks, font=self.parser.font) ]) ]
def unparseMarkToBase(self, lookup): b = fontFeatures.Routine(name=self.getname("MarkToBase" + self.gensym())) self._fix_flags(b, lookup) for subtable in lookup.SubTable: # fontTools.ttLib.tables.otTables.MarkBasePos assert subtable.Format == 1 for classId in range(0, subtable.ClassCount): anchorClassPrefix = "Anchor" + self.gensym() marks = self.formatMarkArray(subtable.MarkArray, subtable.MarkCoverage, classId) bases = self.formatBaseArray(subtable.BaseArray, subtable.BaseCoverage, classId) b.addRule( fontFeatures.Attachment( anchorClassPrefix, anchorClassPrefix + "_", bases, marks, font=self.font, address=self.currentLookup, flags=lookup.LookupFlag, )) return b, []
def accept(self): glyphnames = self.project.font.keys() isol_re = self.isol_re.text() init_re = self.init_re.text() medi_re = self.medi_re.text() fina_re = self.fina_re.text() init_class = [] medi_class = [] fina_class = [] init_rules = fontFeatures.Routine(name="Init") medi_rules = fontFeatures.Routine(name="Medi") fina_rules = fontFeatures.Routine(name="Fina") # We know these are valid REs arabic_glyphs = [ g for g in glyphnames if re.search(init_re, g) or re.search(medi_re, g) or re.search(fina_re, g) ] for g in glyphnames: m = re.search(isol_re, g) if not m: continue if m.groups(): base_name = g.replace(m[1], "") else: base_name = g for g2 in arabic_glyphs: m = re.search(init_re, g2) if not m or not m.groups(): continue base_init = g2.replace(m[1], "") if base_init == base_name: init_class.append(g2) init_rules.addRule(fontFeatures.Substitution([[g]], [[g2]])) break for g2 in arabic_glyphs: m = re.search(medi_re, g2) if not m or not m.groups(): continue base_medi = g2.replace(m[1], "") if base_medi == base_name: medi_class.append(g2) medi_rules.addRule(fontFeatures.Substitution([[g]], [[g2]])) break for g2 in arabic_glyphs: m = re.search(fina_re, g2) if not m or not m.groups(): continue base_fina = g2.replace(m[1], "") if base_fina == base_name: fina_class.append(g2) fina_rules.addRule(fontFeatures.Substitution([[g]], [[g2]])) break warnings = [] if len(init_class) < 10 or len(init_class) > len(glyphnames) / 2: warnings.append( f"Init regexp '{init_re} matched a surprising number of glyphs ({len(init_class)})" ) if len(medi_class) < 10 or len(medi_class) > len(glyphnames) / 2: warnings.append( f"Medi regexp '{medi_re} matched a surprising number of glyphs ({len(medi_class)})" ) if len(fina_class) < 10 or len(fina_class) > len(glyphnames) / 2: warnings.append( f"Fina regexp '{fina_re} matched a surprising number of glyphs ({len(fina_class)})" ) if len(warnings) and self.show_warnings( warnings) == QMessageBox.Cancel: return self.project.fontfeatures.routines.extend( [init_rules, medi_rules, fina_rules]) self.project.fontfeatures.addFeature("init", [init_rules]) self.project.fontfeatures.addFeature("medi", [medi_rules]) self.project.fontfeatures.addFeature("fina", [fina_rules]) if not "init" in self.project.glyphclasses: self.project.glyphclasses["init"] = { "type": "automatic", "predicates": [{ "type": "name", "comparator": "matches", "value": init_re }], } if not "medi" in self.project.glyphclasses: self.project.glyphclasses["medi"] = { "type": "automatic", "predicates": [{ "type": "name", "comparator": "matches", "value": medi_re }], } if not "fina" in self.project.glyphclasses: self.project.glyphclasses["fina"] = { "type": "automatic", "predicates": [{ "type": "name", "comparator": "matches", "value": fina_re }], } if self.doCursive.isChecked(): exitdict = {} entrydict = {} for g in glyphnames: anchors = self.project.font[g].anchors if not anchors: continue entry = [a for a in anchors if a.name == "entry"] exit = [a for a in anchors if a.name == "exit"] if len(entry): entrydict[g] = (entry[0].x, entry[0].y) if len(exit): exitdict[g] = (exit[0].x, exit[0].y) s = fontFeatures.Attachment( base_name="entry", mark_name="exit", bases=entrydict, marks=exitdict, ) r = fontFeatures.Routine(name="CursiveAttachment", rules=[s]) self.project.fontfeatures.routines.extend([r]) self.project.fontfeatures.addFeature("curs", [r]) return super().accept()