The Birdfont Source Code


All Repositories / birdfont.git / commitdiff – RSS feed

Write and parse ligature subsitutions in GPOS table

These changes was commited to the Birdfont repository Fri, 03 Oct 2014 16:44:00 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
[Fri, 03 Oct 2014 16:44:00 +0000]

Updated Files

libbirdfont/GlyphRange.vala
libbirdfont/Ligatures.vala
libbirdfont/OpenFontFormat/FontData.vala
libbirdfont/OpenFontFormat/Gsub.vala
libbirdfont/OpenFontFormat/GsubTable.vala
libbirdfont/OpenFontFormat/Ligature.vala
libbirdfont/OpenFontFormat/LigatureSet.vala
--- a/libbirdfont/GlyphRange.vala +++ b/libbirdfont/GlyphRange.vala @@ -32,7 +32,6 @@ public void add_unassigned (string glyph_name) { unassigned.add (glyph_name); - len++; } public bool is_class () {
--- a/libbirdfont/Ligatures.vala +++ b/libbirdfont/Ligatures.vala @@ -24,9 +24,12 @@ public Ligatures () { } - + + // FIXME: keep ligatures sorted, long strings first public void get_ligatures (LigatureIterator iter) { - iter ("f i", "fi"); + iter ("a f", "af"); + iter ("f f i", "ffi"); + iter ("f i", "fi"); } public void get_single_substitution_ligatures (SingleLigatureIterator iter) {
--- a/libbirdfont/OpenFontFormat/FontData.vala +++ b/libbirdfont/OpenFontFormat/FontData.vala @@ -21,8 +21,7 @@ // Write pointer uint wp = 0; - - // length without padding + uint32 len = 0; uint32 padding = 0; @@ -40,6 +39,10 @@ delete table_data; table_data = null; } + } + + public int get_read_pos () { + return (int) rp; } public void write_at (uint pos, uint8 new_data) throws GLib.Error
--- a/libbirdfont/OpenFontFormat/Gsub.vala +++ /dev/null @@ -1,109 +1,1 @@ - /* - Copyright (C) 2012, 2013, 2014 Johan Mattsson - - This library 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 3 of the - License, or (at your option) any later version. - - This 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 - Lesser General Public License for more details. - */ - using Math; - - namespace BirdFont { - - public class GsubTable : Table { - - GlyfTable glyf_table; - - public GsubTable (GlyfTable glyf_table) { - this.glyf_table = glyf_table; - id = "GSUB"; - } - - public override void parse (FontData dis) throws Error { - } - - public void process () throws GLib.Error { - FontData fd = new FontData (); - - fd.add_ulong (0x00010000); // table version - fd.add_ushort (10); // offset to script list - fd.add_ushort (30); // offset to feature list - fd.add_ushort (44); // offset to lookup list - - // script list - fd.add_ushort (1); // number of items in script list - fd.add_tag ("DFLT"); // default script - fd.add_ushort (8); // offset to script table from script list - - // script table - fd.add_ushort (4); // offset to default language system - fd.add_ushort (0); // number of languages - - // LangSys table - fd.add_ushort (0); // reserved - fd.add_ushort (0); // required features (0xFFFF is none) - fd.add_ushort (1); // number of features - fd.add_ushort (0); // feature index - - // feature table - fd.add_ushort (1); // number of features - - fd.add_tag ("clig"); // feature tag - fd.add_ushort (8); // offset to feature - - fd.add_ushort (0); // feature prameters (null) - fd.add_ushort (1); // number of lookups - fd.add_ushort (0); // lookup indice - - // lookup table - fd.add_ushort (1); // number of lookups - fd.add_ushort (4); // offset to lookup 1 - - fd.add_ushort (4); // lookup type // FIXME - fd.add_ushort (0); // lookup flags - fd.add_ushort (1); // number of subtables - fd.add_ushort (8); // array of offsets to subtable - - // ligature substitution subtable - fd.add_ushort (1); // format identifier - fd.add_ushort (8); // offset to coverage - fd.add_ushort (1); // number of ligature set tables - fd.add_ushort (18); // array of offsets to ligature sets - - // coverage - fd.add_ushort (2); // format - fd.add_ushort (1); // num ranges - fd.add_ushort ((uint16) glyf_table.get_gid ("f")); // start gid - fd.add_ushort ((uint16) glyf_table.get_gid ("f")); // end gid - fd.add_ushort (0); // coverage start index - - // ligature - fd.add_ushort (3); // number of ligatures in this set - fd.add_ushort (8); // offset to ligature - fd.add_ushort (14); // offset to ligature - fd.add_ushort (20); // offset to ligature - - fd.add_ushort ((uint16) glyf_table.get_gid ("fi")); // DELETE); - fd.add_ushort (2); // number of components - fd.add_ushort ((uint16) glyf_table.get_gid ("i")); // gid to component - - fd.add_ushort ((uint16) glyf_table.get_gid ("fi")); // DELETE); - fd.add_ushort (2); // number of components - fd.add_ushort ((uint16) glyf_table.get_gid ("i")); // gid to component - - fd.add_ushort ((uint16) glyf_table.get_gid ("fi")); // DELETE); - fd.add_ushort (2); // number of components - fd.add_ushort ((uint16) glyf_table.get_gid ("i")); // gid to component - - fd.pad (); - this.font_data = fd; - } - } - - }
--- /dev/null +++ b/libbirdfont/OpenFontFormat/GsubTable.vala @@ -1,1 +1,198 @@ + /* + Copyright (C) 2012, 2013, 2014 Johan Mattsson + + This library 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 3 of the + License, or (at your option) any later version. + + This 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 + Lesser General Public License for more details. + */ + using Math; + + namespace BirdFont { + + public class GsubTable : Table { + + GlyfTable glyf_table; + + public GsubTable (GlyfTable glyf_table) { + this.glyf_table = glyf_table; + id = "GSUB"; + } + + public override void parse (FontData dis) throws Error { + } + + public void process () throws GLib.Error { + FontData fd = new FontData (); + Font font = BirdFont.get_current_font (); + Ligatures ligatures = font.get_ligatures (); + LigatureSet lig_set; + LigatureSet last_set; + FontData set_data; + Gee.ArrayList<LigatureSet> liga_sets; + uint16 ligature_pos; + uint16 table_start; + + fd.add_ulong (0x00010000); // table version + fd.add_ushort (10); // offset to script list + fd.add_ushort (30); // offset to feature list + fd.add_ushort (44); // offset to lookup list + + // script list + fd.add_ushort (1); // number of items in script list + fd.add_tag ("DFLT"); // default script + fd.add_ushort (8); // offset to script table from script list + + // script table + fd.add_ushort (4); // offset to default language system + fd.add_ushort (0); // number of languages + + // LangSys table + fd.add_ushort (0); // reserved + fd.add_ushort (0); // required features (0xFFFF is none) + fd.add_ushort (1); // number of features + fd.add_ushort (0); // feature index + + // feature table + fd.add_ushort (1); // number of features + + fd.add_tag ("clig"); // feature tag + fd.add_ushort (8); // offset to feature + + fd.add_ushort (0); // feature prameters (null) + fd.add_ushort (1); // number of lookups + fd.add_ushort (0); // lookup indice + + // lookup table + fd.add_ushort (1); // number of lookups + fd.add_ushort (4); // offset to lookup 1 + + fd.add_ushort (4); // lookup type + fd.add_ushort (0); // lookup flags + fd.add_ushort (1); // number of subtables + fd.add_ushort (8); // array of offsets to subtable + + // add existing ligatures + liga_sets = new Gee.ArrayList<LigatureSet> (); + lig_set = new LigatureSet (glyf_table); + last_set = new LigatureSet (glyf_table); + ligatures.get_ligatures ((s, l) => { + string[] parts = s.split (" "); + + if (!font.has_glyph (l)) { + warning (@"Ligature $l does not correspond to a glyph in this font."); + return; + } + + foreach (string p in parts) { + if (!font.has_glyph (p)) { + warning (@"Ligature substitution of $p is not possible, the character does have a glyph."); + return; + } + } + + if (parts.length == 0) { + warning ("No parts."); + return; + } + + if (last_set.starts_with (parts[0])) { + last_set.add (new Ligature (l, s)); + } else { + lig_set = new LigatureSet (glyf_table); + lig_set.add (new Ligature (l, s)); + liga_sets.add (lig_set); + last_set = lig_set; + } + + }); + + // ligature substitution subtable + table_start = (uint16) fd.length_with_padding (); + + fd.add_ushort (1); // format identifier + fd.add_ushort (6 + (uint16) 2 * liga_sets.size); // offset to coverage + fd.add_ushort ((uint16) liga_sets.size); // number of ligature set tables + + // array of offsets to ligature sets + uint16 size = 0; + foreach (LigatureSet l in liga_sets) { + ligature_pos = 10 + (uint16) liga_sets.size * 4 + size; + fd.add_ushort (ligature_pos); + size += (uint16) l.get_set_data ().length_with_padding (); + } + + // coverage + fd.add_ushort (1); // format + fd.add_ushort ((uint16) liga_sets.size); + + // coverage gid: + foreach (LigatureSet l in liga_sets) { + fd.add_ushort ((uint16) glyf_table.get_gid (l.get_coverage_char ())); + } + + foreach (LigatureSet l in liga_sets) { + set_data = l.get_set_data (); + fd.append (set_data); + } + + fd.pad (); + + this.font_data = fd; + } + + void parse_ligatures (FontData fd, int table_start) { + fd.seek (table_start); + + uint16 identifier = fd.read_ushort (); + + if (identifier != 1) { + warning (@"Bad identifier expecting 1 found $identifier"); + } + + uint16 coverage_offset = fd.read_ushort (); + uint16 num_sets = fd.read_ushort (); + + Gee.ArrayList<int> liga_set_offsets = new Gee.ArrayList<int> (); + for (int i = 0; i < num_sets; i++) { + uint16 liga_set_offset = fd.read_ushort (); + liga_set_offsets.add (table_start + liga_set_offset); + } + + foreach (int liga_set_pos in liga_set_offsets) { + fd.seek (liga_set_pos); + parse_ligature_set (fd); + } + } + + /** Parse ligature set at the current position. */ + void parse_ligature_set (FontData fd) { + int liga_start = fd.get_read_pos (); + uint nliga = fd.read_ushort (); + Gee.ArrayList<int> offsets = new Gee.ArrayList<int> (); + + for (uint i = 0; i < nliga; i++) { + int off = fd.read_ushort (); + offsets.add (off); + } + + foreach (int off in offsets) { + fd.seek (liga_start); + fd.seek_relative (off); + uint16 lig = fd.read_ushort (); + uint16 nlig_comp = fd.read_ushort (); + + for (int i = 1; i < nlig_comp; i++) { + uint16 lig_comp = fd.read_ushort (); + } + } + } + } + + }
--- /dev/null +++ b/libbirdfont/OpenFontFormat/Ligature.vala @@ -1,1 +1,28 @@ + /* + Copyright (C) 2014 Johan Mattsson + + This library 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 3 of the + License, or (at your option) any later version. + + This 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 + Lesser General Public License for more details. + */ + + namespace BirdFont { + + public class Ligature : GLib.Object { + public string ligature = ""; + public string substitution = ""; + + public Ligature (string ligature, string substitution) { + this.ligature = ligature; + this.substitution = substitution; + } + } + + }
--- /dev/null +++ b/libbirdfont/OpenFontFormat/LigatureSet.vala @@ -1,1 +1,97 @@ + /* + Copyright (C) 2014 Johan Mattsson + + This library 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 3 of the + License, or (at your option) any later version. + + This 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 + Lesser General Public License for more details. + */ + + namespace BirdFont { + + public class LigatureSet : GLib.Object { + public Gee.ArrayList<Ligature> ligatures = new Gee.ArrayList<Ligature> (); + GlyfTable glyf_table; + + public LigatureSet (GlyfTable gt) { + glyf_table = gt; + } + + public void add (Ligature lig) { + ligatures.add (lig); + } + + public bool starts_with (string s) { + if (ligatures.size == 0) { + return false; + } + + return ligatures.get (0).substitution.has_prefix (s); + } + + public string get_coverage_char () { + if (ligatures.size == 0) { + warning ("No ligatures in set."); + return ""; + } + + return (!) ligatures.get (0).substitution.get (0).to_string (); + } + + public FontData get_set_data () { + FontData fd, ligature_data; + uint16 o, pos; + + fd = new FontData (); + + // number of ligatures in this set + fd.add_ushort ((uint16) ligatures.size); + + ligature_data = new FontData (); + foreach (Ligature l in ligatures) { + // offset to ligatures + o = 2 + 2 * ligatures.size; + + pos = (uint16) (o + ligature_data.length_with_padding ()); + + fd.add_ushort (pos); + add_ligature (ligature_data, l); + } + + fd.append (ligature_data); + + return fd; + } + + void add_ligature (FontData fd, Ligature ligature) throws GLib.Error { + string[] parts = ligature.substitution.split (" "); + bool first = true; + int gid = glyf_table.get_gid (ligature.ligature); + + if (gid == -1) { + warning (@"No glyph ID for ligature $(ligature.ligature)."); + gid = 0; + } + + fd.add_ushort ((uint16) gid); + + // number of components including the coverage glyph + fd.add_ushort ((uint16) parts.length); + + foreach (string p in parts) { + if (!first) { + fd.add_ushort ((uint16) glyf_table.get_gid (p)); + } + + first = false; + } + } + } + + }