Commit 41905a8
Process contextual ligatures in kerning and spacing tabs
Changed files (8)
modifiedlibbirdfont/BirdFontFile.valamodifiedlibbirdfont/Font.valamodifiedlibbirdfont/GlyphSequence.valamodifiedlibbirdfont/Ligatures.valamodifiedlibbirdfont/OpenFontFormat/ContextualLigature.valamodifiedlibbirdfont/OpenFontFormat/GsubTable.valamodifiedlibbirdfont/Renderer/FontCache.valamodifiedlibbirdfont/Table.vala
Diff
@@ -346,7 +346,7 @@ class BirdFontFile : GLib.Object { os.put_string (@"\t<bottom_position>$(round (font.bottom_position))</bottom_position>\n"); os.put_string (@"\t<bottom_limit>$(round (font.bottom_limit))</bottom_limit>\n"); - foreach (Line guide in BirdFont.get_current_font ().custom_guides) {+ foreach (Line guide in font.custom_guides) { os.put_string (@"\t<custom_guide label=\"$(guide.label)\">$(round (guide.pos))</custom_guide>\n"); } @@ -1050,7 +1050,7 @@ class BirdFontFile : GLib.Object { line = new Line (label, position); - BirdFont.get_current_font ().custom_guides.add (line);+ font.custom_guides.add (line); } } }@@ -834,6 +834,32 @@ public class Font : GLib.Object { read_only = r; } + /** + * @param glyphs Name of glyphs or unicode values separated by space.+ * @return glyph names+ */+ public Gee.ArrayList<string> get_names (string glyphs) {+ Gee.ArrayList<string> names = new Gee.ArrayList<string> ();+ string[] parts = glyphs.strip ().split (" ");+ + foreach (string p in parts) { + if (p.has_prefix ("U+") || p.has_prefix ("u+")) {+ p = (!) to_unichar (p).to_string ();+ }+ + if (!has_glyph (p)) {+ warning (@"The character $p does not have a glyph in " + get_file_name ());+ p = ".notdef";+ }+ + if (p != "") {+ names.add (p);+ }+ }+ + return names;+ }+ public static unichar to_unichar (string unicode) { int index = 2; int i = 0;@@ -1,5 +1,5 @@ /*- Copyright (C) 2013 Johan Mattsson+ Copyright (C) 2013 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 @@ -30,6 +30,21 @@ public class GlyphSequence : GLib.Object { return glyph.size; } + public void add (Glyph? g) {+ glyph.add (g);+ ranges.add (null);+ }+ + public void append (GlyphSequence c) {+ foreach (Glyph? g in c.glyph) {+ glyph.add (g);+ }++ foreach (GlyphRange? r in c.ranges) {+ ranges.add (r);+ }+ }+ /** Do ligature substitution. * @return a new sequence with ligatures */@@ -57,9 +72,14 @@ public class GlyphSequence : GLib.Object { ligatures = font.get_ligatures (); ligatures.get_single_substitution_ligatures ((substitute, ligature) => {- ligature_sequence.replace (substitute, ligature.get_current ());+ ligature_sequence.replace (substitute, ligature); }); + foreach (ContextualLigature c in ligatures.contextual_ligatures) {+ ligature_sequence.replace_contextual (c.get_backtrack (),+ c.get_input (), c.get_lookahead (), c.get_ligature_sequence ()); + }+ ligature_sequence.ranges.clear (); for (int i = 0; i < ligature_sequence.glyph.size; i++) { ligature_sequence.ranges.add (null);@@ -68,18 +88,35 @@ public class GlyphSequence : GLib.Object { return ligature_sequence; } - void replace (GlyphSequence old, Glyph replacement) {+ void replace (GlyphSequence old, GlyphSequence replacement) { int i = 0; while (i < glyph.size) { if (starts_with (old, i)) { substitute (i, old.glyph.size, replacement);- i = 0;+ i += replacement.length (); } else { i++; } } }- ++ void replace_contextual (GlyphSequence backtrack, GlyphSequence input, GlyphSequence lookahead, GlyphSequence replacement) {+ bool start, middle, end;+ int i = 0;+ while (i < glyph.size) {+ start = starts_with (backtrack, i);+ middle = starts_with (input, i + backtrack.length ());+ end = starts_with (lookahead, i + backtrack.length () + input.length ());+ + if (start && middle && end) {+ substitute (i + backtrack.length (), input.length (), replacement);+ i += i + backtrack.length () + input.length ();+ } else {+ i++;+ }+ }+ }+ bool starts_with (GlyphSequence old, uint index) { Glyph? gl; @@ -100,13 +137,15 @@ public class GlyphSequence : GLib.Object { return true; } - void substitute (uint index, uint length, Glyph substitute) {+ void substitute (uint index, uint length, GlyphSequence substitute) { Gee.ArrayList<Glyph?> new_list = new Gee.ArrayList<Glyph?> (); int i = 0; foreach (Glyph? g in glyph) { if (i == index) {- new_list.add (substitute);+ foreach (Glyph? gn in substitute.glyph) {+ new_list.add (gn);+ } } if (!(i >= index && i < index + length)) {@@ -23,7 +23,7 @@ public class Ligatures : GLib.Object { public Gee.ArrayList<ContextualLigature> contextual_ligatures = new Gee.ArrayList<ContextualLigature> (); public delegate void LigatureIterator (string substitution, string ligature);- public delegate void SingleLigatureIterator (GlyphSequence substitution, GlyphCollection ligature);+ public delegate void SingleLigatureIterator (GlyphSequence substitution, GlyphSequence ligature); public delegate void ContextualLigatureIterator (ContextualLigature lig); @@ -48,18 +48,21 @@ public class Ligatures : GLib.Object { public void get_single_substitution_ligatures (SingleLigatureIterator iter) { get_ligatures ((substitution, ligature) => { GlyphCollection? gc;- GlyphCollection li;+ GlyphSequence lig; GlyphSequence gs; string[] subst_names = substitution.split (" "); - gc = font.get_glyph_collection_by_name (ligature);- - if (gc == null) {- return;+ lig = new GlyphSequence ();+ foreach (string n in font.get_names (ligature)) {+ gc = font.get_glyph_collection_by_name (n);+ + if (gc == null) {+ return;+ }+ + lig.add (((!) gc).get_current ()); } - li = (!) gc;- gs = new GlyphSequence (); foreach (string s in subst_names) { gc = font.get_glyph_collection_by_name (s);@@ -71,7 +74,7 @@ public class Ligatures : GLib.Object { gs.glyph.add (((!) gc).get_current ()); } - iter (gs, li);+ iter (gs, lig); }); } @@ -206,7 +209,7 @@ public class Ligatures : GLib.Object { } public void add_contextual_ligature (string ligature, string backtrack, string input, string lookahead) {- ContextualLigature l = new ContextualLigature (ligature, backtrack, input, lookahead);+ ContextualLigature l = new ContextualLigature (font, ligature, backtrack, input, lookahead); contextual_ligatures.insert (0, l); sort_ligatures (); }@@ -21,8 +21,11 @@ public class ContextualLigature : GLib.Object { public string lookahead = ""; public string ligatures = ""; + Font font;+ /** All arguments are list of glyph names separated by space. */- public ContextualLigature (string ligatures, string backtrack, string input, string lookahead) {+ public ContextualLigature (Font font, string ligatures, string backtrack, string input, string lookahead) {+ this.font = font; this.backtrack = backtrack; this.input = input; this.lookahead = lookahead;@@ -43,10 +46,11 @@ public class ContextualLigature : GLib.Object { public FontData get_font_data (GlyfTable glyf_table, uint16 ligature_lookup_index) throws GLib.Error { FontData fd = new FontData ();+ Font font = BirdFont.get_current_font (); // FIXME: thread safety? - Gee.ArrayList<string> backtrack = GsubTable.get_names (backtrack);- Gee.ArrayList<string> input = GsubTable.get_names (input);- Gee.ArrayList<string> lookahead = GsubTable.get_names (lookahead);+ Gee.ArrayList<string> backtrack = font.get_names (backtrack);+ Gee.ArrayList<string> input = font.get_names (input);+ Gee.ArrayList<string> lookahead = font.get_names (lookahead); // FIXME: add ligatures @@ -115,6 +119,41 @@ public class ContextualLigature : GLib.Object { return fd; }+ + public GlyphSequence get_backtrack () {+ return get_sequence (backtrack);+ }++ public GlyphSequence get_input () {+ return get_sequence (input);+ }+ + public GlyphSequence get_lookahead () {+ return get_sequence (lookahead);+ }+ + public GlyphSequence get_ligature_sequence () {+ return get_sequence (ligatures);+ }+ + GlyphSequence get_sequence (string context) {+ GlyphCollection? gc;+ GlyphSequence gs;+ + gs = new GlyphSequence ();+ foreach (string s in font.get_names (context)) {+ gc = font.get_glyph_collection_by_name (s);+ + if (gc == null) {+ warning (@"No glyph found for $s");+ return new GlyphSequence ();+ }+ + gs.glyph.add (((!) gc).get_current ());+ }+ + return gs;+ } } }@@ -194,33 +194,6 @@ public class GsubTable : OtfTable { return fd; }- - /** - * @param glyphs Name of glyphs or unicode values separated by space.- * @return glyph names- */- 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.strip ().split (" ");- - foreach (string p in parts) { - if (p.has_prefix ("U+") || p.has_prefix ("u+")) {- p = (!) Font.to_unichar (p).to_string ();- }- - if (!font.has_glyph (p)) {- warning (@"The character $p does have a glyph.");- p = ".notdef";- }- - if (p != "") {- names.add (p);- }- }- - return names;- } } }@@ -38,7 +38,7 @@ public class FontCache { bool ok; if (file_name == "") {- stderr.printf ("No file name provided.\n");+ stderr.printf ("No file name.\n"); return null; } @@ -91,7 +91,6 @@ public abstract class Table : FontDisplay { Row row, double y, bool color, bool dark) { Text t;- double margin; double x; double o;