Commit 9132e8e
Contextual ligatures
Changed files (4)
modifiedlibbirdfont/OpenFontFormat/ContextualLigature.valamodifiedlibbirdfont/OpenFontFormat/ContextualLigatureSet.valamodifiedlibbirdfont/OpenFontFormat/GsubTable.valamodifiedlibbirdfont/OpenFontFormat/LigatureSetList.vala
Diff
@@ -40,7 +40,7 @@ public class ContextualLigature : GLib.Object { return ligature_list; } - public FontData get_data (GlyfTable glyf_table) {+ public FontData get_data (GlyfTable glyf_table, uint16 ligature_lookup_index) { FontData fd = new FontData (); Gee.ArrayList<string> backtrack = GsubTable.get_names (backtrack);@@ -74,7 +74,7 @@ public class ContextualLigature : GLib.Object { fd.add_ushort (1); // substitute count // substitution lookup records fd.add_ushort (0); // glyph sequence index for the character that will be substituted - fd.add_ushort (1); // go to the ligature substitution via lookup table+ fd.add_ushort (ligature_lookup_index); // go to the ligature substitution via lookup table // backtrack coverage table1 if (fd.length_with_padding () != backtrack_offset) {@@ -18,24 +18,32 @@ namespace BirdFont { public class ContextualLigatureSet : GLib.Object { public Gee.ArrayList<ContextualLigature> ligature_context;- public LigatureSetList ligatures;+ public Gee.ArrayList<LigatureSetList> ligatures; public ContextualLigatureSet (GlyfTable glyf_table) { ligature_context = new Gee.ArrayList<ContextualLigature> (); - add_contextual_ligatures ();- ligatures = new LigatureSetList.contextual (glyf_table, this);+ ligatures = new Gee.ArrayList<LigatureSetList> ();+ add_contextual_ligatures (glyf_table);+ }+ + public int16 get_size () {+ if (ligatures.size != ligature_context.size) {+ warning ("Expecting one substitution table per contextual ligature");+ }+ + return (int16) ligature_context.size; } public bool has_ligatures () { return ligature_context.size > 0; } - void add_contextual_ligatures () {+ void add_contextual_ligatures (GlyfTable glyf_table) { Font font = BirdFont.get_current_font ();- Ligatures ligatures = font.ligature_substitution; - foreach (ContextualLigature c in ligatures.contextual_ligatures) {+ foreach (ContextualLigature c in font.ligature_substitution.contextual_ligatures) { ligature_context.add (c);+ ligatures.add (new LigatureSetList.contextual (glyf_table, c)); } } }@@ -1,5 +1,5 @@ /*- Copyright (C) 2012, 2013, 2014 Johan Mattsson+ Copyright (C) 2012 2013 2014 2015 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 @@ -28,20 +28,22 @@ public class GsubTable : OtfTable { } public void process () throws GLib.Error {- FontData fd = new FontData ();+ FontData fd; FontData clig_subtable;- FontData chained_context;- FontData chained_ligatures; uint16 length; LigatureSetList clig; ContextualLigatureSet contextual; uint16 feature_lookups;+ uint16 lookups_end;+ + Gee.ArrayList<FontData> chain_data; + fd = new FontData (); clig = new LigatureSetList.clig (glyf_table); contextual = new ContextualLigatureSet (glyf_table);- + fd.add_ulong (0x00010000); // table version fd.add_ushort (10); // offset to script list fd.add_ushort (30); // offset to feature list@@ -78,33 +80,51 @@ public class GsubTable : OtfTable { fd.add_ushort (feature_lookups); // number of lookups if (contextual.has_ligatures ()) {- fd.add_ushort (2); // lookup chained_context (etc.) The chained context tables are listed here but the actual ligature table is only referenced in the context table+ fd.add_ushort (1 + contextual.get_size ()); // lookup chained_context (etc.) The chained context tables are listed here but the actual ligature table is only referenced in the context table fd.add_ushort (0); // lookup clig_subtable } else { fd.add_ushort (0); // lookup clig_subtable } - clig_subtable = get_ligature_subtable (clig);- chained_ligatures = get_ligature_subtable (contextual.ligatures);- chained_context = get_chaining_contextual_substition_subtable (contextual);+ clig_subtable = clig.get_data (glyf_table);+ chain_data = get_chaining_contextual_substition_subtable (contextual); // lookup table- uint16 lookups = contextual.has_ligatures () ? 3 : 1;+ uint16 lookups;+ + if (contextual.has_ligatures ()) {+ lookups = 2 + (uint16) contextual.get_size ();+ } else {+ lookups = 1;+ }+ fd.add_ushort (lookups); // number of lookups if (contextual.has_ligatures ()) {- fd.add_ushort (8); // offset to lookup 1 - fd.add_ushort (16); // offset to lookup 2- fd.add_ushort (24); // offset to lookup 3+ uint16 offset_to_lookup;++ offset_to_lookup = 6 + 2 * contextual.get_size ();+ fd.add_ushort (offset_to_lookup); // offset to lookup 1, regular ligatures+ + for (int i = 0; i < contextual.get_size (); i++) {+ offset_to_lookup += 8;+ // offset to ligature lookups used in chaining substitution+ fd.add_ushort (offset_to_lookup);+ }++ // offset to lookup for the chain table+ offset_to_lookup += 8;+ fd.add_ushort (offset_to_lookup); } else { fd.add_ushort (4); // offset to lookup 1 } - uint16 lookups_end;+ lookups_end = 8; // regular ligatures - lookups_end = lookups * 8; if (contextual.has_ligatures ()) {- lookups_end += 2 * ((uint16) contextual.ligature_context.size - 1);+ lookups_end += 8 * contextual.get_size (); // contextual ligatures+ lookups_end += 6; // chaining table+ lookups_end += 2 * (uint16) contextual.get_size (); // chaining subtables } length = 0;@@ -115,35 +135,46 @@ public class GsubTable : OtfTable { length += (uint16) clig_subtable.length_with_padding (); lookups_end -= 8; - if (contextual.has_ligatures ()) {- fd.add_ushort (4); // lookup type - fd.add_ushort (0); // lookup flags- fd.add_ushort (1); // number of subtables- fd.add_ushort (lookups_end + length); // array of offsets to subtable- length += (uint16) chained_ligatures.length_with_padding ();- lookups_end -= 8;+ if (contextual.has_ligatures ()) { + + for (int i = 0; i < contextual.ligatures.size; i++) {+ fd.add_ushort (4); // lookup type + fd.add_ushort (0); // lookup flags+ fd.add_ushort (1); // number of subtables++ LigatureSetList ligature_set = contextual.ligatures.get (i);+ fd.add_ushort (lookups_end + length); // array of offsets to subtable+ length += (uint16) ligature_set.get_data (glyf_table).length_with_padding ();+ + lookups_end -= 8;+ } fd.add_ushort (6); // lookup type fd.add_ushort (0); // lookup flags- fd.add_ushort ((uint16) contextual.ligature_context.size); // number of subtables FIXME: 1?+ fd.add_ushort (contextual.get_size ()); // number of subtables - foreach (ContextualLigature c in contextual.ligature_context) {+ foreach (FontData d in chain_data) { fd.add_ushort (lookups_end + length); // array of offsets to subtable- length += (uint16) c.get_data (glyf_table).length_with_padding ();+ length += (uint16) d.length_with_padding (); } - lookups_end -= 7 + 2 * contextual.ligature_context.size;+ lookups_end -= 6 + 2 * chain_data.size; } - if (lookups_end == 0) {- warning ("Wring offset to end of lookups.");+ if (lookups_end != 0) {+ warning (@"Wrong offset to end of lookups, $lookups_end bytes left."); } fd.append (clig_subtable); if (contextual.has_ligatures ()) {- fd.append (chained_ligatures);- fd.append (chained_context);+ foreach (LigatureSetList s in contextual.ligatures) {+ fd.append (s.get_data (glyf_table));+ }++ foreach (FontData d in chain_data) {+ fd.append (d);+ } } fd.pad ();@@ -151,57 +182,17 @@ public class GsubTable : OtfTable { this.font_data = fd; } - FontData get_ligature_subtable (LigatureSetList liga_list) throws GLib.Error {- FontData set_data;- Gee.ArrayList<LigatureSet> ligature_sets;- uint16 ligature_pos;- uint16 table_start;- FontData fd;- - ligature_sets = liga_list.ligature_sets;- fd = new FontData ();-- // ligature substitution subtable- table_start = (uint16) fd.length_with_padding ();-- fd.add_ushort (1); // format identifier- fd.add_ushort (6 + (uint16) 2 * ligature_sets.size); // offset to coverage- fd.add_ushort ((uint16) ligature_sets.size); // number of ligature set tables-- // array of offsets to ligature sets- uint16 size = 0;- foreach (LigatureSet l in ligature_sets) {- ligature_pos = 10 + (uint16) ligature_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) ligature_sets.size);-- // coverage gid:- foreach (LigatureSet l in ligature_sets) {- fd.add_ushort ((uint16) glyf_table.get_gid (l.get_coverage_char ()));- }- - foreach (LigatureSet l in ligature_sets) {- set_data = l.get_set_data ();- fd.append (set_data);- }- - return fd;- }- // chaining contextual substitution format3- FontData get_chaining_contextual_substition_subtable (ContextualLigatureSet contexts) throws GLib.Error {- FontData fd_all = new FontData ();+ Gee.ArrayList<FontData> get_chaining_contextual_substition_subtable (ContextualLigatureSet contexts) throws GLib.Error {+ Gee.ArrayList<FontData> fd = new Gee.ArrayList<FontData> ();+ uint16 ligature_lookup_index = 1; foreach (ContextualLigature context in contexts.ligature_context) {- fd_all.append (context.get_data (glyf_table)); // FIXME: remove..+ fd.add (context.get_data (glyf_table, ligature_lookup_index)); + ligature_lookup_index++; } - return fd_all;+ return fd; } void parse_ligatures (FontData fd, int table_start) {@@ -258,7 +249,7 @@ public class GsubTable : OtfTable { public static Gee.ArrayList<string> get_names (string glyphs) { Gee.ArrayList<string> names = new Gee.ArrayList<string> (); Font font = BirdFont.get_current_font ();- string[] parts = glyphs.split (" ");+ string[] parts = glyphs.strip ().split (" "); foreach (string p in parts) { if (p.has_prefix ("U+") || p.has_prefix ("u+")) {@@ -267,10 +258,12 @@ public class GsubTable : OtfTable { if (!font.has_glyph (p)) { warning (@"The character $p does have a glyph.");- return new Gee.ArrayList<string> ();+ p = ".notdef"; } - names.add (p);+ if (p != "") {+ names.add (p);+ } } return names;@@ -30,12 +30,12 @@ public class LigatureSetList : GLib.Object { add_clig_ligatures (glyf_table); } - public LigatureSetList.contextual (GlyfTable glyf_table, ContextualLigatureSet ligatures) {+ public LigatureSetList.contextual (GlyfTable glyf_table, ContextualLigature ligature) { ligature_sets = new Gee.ArrayList<LigatureSet> (); lig_set = new LigatureSet (glyf_table); last_set = new LigatureSet (glyf_table); - add_contextual_ligatures (glyf_table, ligatures);+ add_contextual_ligatures (glyf_table, ligature); } void add_clig_ligatures (GlyfTable glyf_table) {@@ -47,11 +47,9 @@ public class LigatureSetList : GLib.Object { }); } - void add_contextual_ligatures (GlyfTable glyf_table, ContextualLigatureSet ligatures) {- foreach (ContextualLigature c in ligatures.ligature_context) {- foreach (string l in c.ligatures.strip ().split (" ")) {- add_ligatures (glyf_table, "r", l); // FIXME: parts = ""- }+ void add_contextual_ligatures (GlyfTable glyf_table, ContextualLigature cl) {+ foreach (string l in cl.ligatures.strip ().split (" ")) {+ add_ligatures (glyf_table, cl.input, l); // FIXME: DELETE parts = "r" ? } } @@ -61,7 +59,7 @@ public class LigatureSetList : GLib.Object { requires (!is_null (lig_set) && !is_null (last_set)) { Font font = BirdFont.get_current_font ();- string[] parts = characters.split (" ");+ string[] parts = characters.strip ().split (" "); string l = ligatures; if (l.has_prefix ("U+") || l.has_prefix ("u+")) {@@ -98,6 +96,46 @@ public class LigatureSetList : GLib.Object { last_set = lig_set; } }++ public FontData get_data (GlyfTable glyf_table) throws GLib.Error {+ FontData set_data;+ uint16 ligature_pos;+ uint16 table_start;+ FontData fd;+ + fd = new FontData ();++ // ligature substitution subtable+ table_start = (uint16) fd.length_with_padding ();++ fd.add_ushort (1); // format identifier+ fd.add_ushort (6 + (uint16) 2 * ligature_sets.size); // offset to coverage+ fd.add_ushort ((uint16) ligature_sets.size); // number of ligature set tables++ // array of offsets to ligature sets+ uint16 size = 0;+ foreach (LigatureSet l in ligature_sets) {+ ligature_pos = 10 + (uint16) ligature_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) ligature_sets.size);++ // coverage gid:+ foreach (LigatureSet l in ligature_sets) {+ fd.add_ushort ((uint16) glyf_table.get_gid (l.get_coverage_char ()));+ }+ + foreach (LigatureSet l in ligature_sets) {+ set_data = l.get_set_data ();+ fd.append (set_data);+ }+ + return fd;+ } } }