The Birdfont Source Code


All Repositories / birdfont.git / commitdiff – RSS feed

Add unassigned glyphs (ligatures) to ttf fonts and kerning tab.

These changes was commited to the Birdfont repository Wed, 01 Oct 2014 19:53:24 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
[Wed, 01 Oct 2014 19:53:24 +0000]

Updated Files

libbirdfont/Font.vala
libbirdfont/Glyph.vala
libbirdfont/GlyphCollection.vala
libbirdfont/GlyphRange.vala
libbirdfont/GlyphSequence.vala
libbirdfont/KerningClasses.vala
libbirdfont/KerningDisplay.vala
libbirdfont/KerningList.vala
libbirdfont/LigatureList.vala
libbirdfont/Ligatures.vala
libbirdfont/OpenFontFormat/CmapSubtableFormat0.vala
libbirdfont/OpenFontFormat/CmapSubtableFormat12.vala
libbirdfont/OpenFontFormat/CmapSubtableFormat4.vala
libbirdfont/OpenFontFormat/DirectoryTable.vala
libbirdfont/OpenFontFormat/GlyfTable.vala
libbirdfont/OpenFontFormat/Gsub.vala
libbirdfont/OpenFontFormat/LocaTable.vala
libbirdfont/SvgFont.vala
libbirdxml/Xml.vala
--- a/libbirdfont/Font.vala +++ b/libbirdfont/Font.vala @@ -93,6 +93,8 @@ BirdFontPart bfp_file; public Gee.ArrayList<Glyph> deleted_glyphs; + + Ligatures ligatures_substitution; public Font () { postscript_name = "Typeface"; @@ -122,6 +124,11 @@ bfp_file = new BirdFontPart (this); deleted_glyphs = new Gee.ArrayList<Glyph> (); + ligatures_substitution = new Ligatures (); + } + + public Ligatures get_ligatures () { + return ligatures_substitution; } public void set_weight (string w) { @@ -391,9 +398,7 @@ return; } - if (glyph_collection.get_name () != "") { - glyph_name.insert (glyph_collection.get_name (), glyph_collection); - } + glyph_name.insert (glyph_collection.get_name (), glyph_collection); if (glyph_collection.get_unicode () != "") { glyph_cache.insert ((!) glyph_collection.get_unicode (), glyph_collection); @@ -424,11 +429,9 @@ public void delete_glyph (GlyphCollection glyph) { glyph_cache.remove (glyph.get_unicode ()); + glyph_cache.remove (glyph.get_name ()); glyph_name.remove (glyph.get_name ()); - - if (glyph.length () > 0) { - ligature.remove (glyph.get_current ().get_ligature_string ()); - } + ligature.remove (glyph.get_current ().get_name ()); foreach (Glyph g in glyph.get_version_list ().glyphs) { deleted_glyphs.add (g);
--- a/libbirdfont/Glyph.vala +++ b/libbirdfont/Glyph.vala @@ -82,9 +82,6 @@ string glyph_sequence = ""; bool open = true; - - bool ligature = false; - string substitution = ""; public static Glyph? background_glyph = null; @@ -139,33 +136,6 @@ public override void close () { undo_list.clear (); redo_list.clear (); - } - - public string get_ligature_string () { - return substitution; - } - - public GlyphSequence get_ligature () { - int index = 0; - unichar c; - GlyphSequence gs = new GlyphSequence (); - Font font = BirdFont.get_current_font (); - StringBuilder s; - Glyph? g; - - while (substitution.get_next_char (ref index, out c)) { - s = new StringBuilder (); - s.append_unichar (c); - g = font.get_glyph (s.str); - - if (g == null) { - warning ("Glyph for $(s.str) does not exsist."); - } else { - gs.glyph.add (g); - } - } - - return gs; } public void set_empty_ttf (bool e) { @@ -174,15 +144,6 @@ public bool is_empty_ttf () { return empty; - } - - public void set_ligature_substitution (string glyph_sequence) { - ligature = true; - substitution = glyph_sequence; - } - - public bool is_ligature () { - return ligature; } public void clear_active_paths () { @@ -1645,10 +1606,7 @@ g.background_image = ((!) background_image).copy (); } - g.ligature = ligature; - g.substitution = substitution; g.empty = empty; - g.open = open; return g;
--- a/libbirdfont/GlyphCollection.vala +++ b/libbirdfont/GlyphCollection.vala @@ -114,6 +114,7 @@ } n.versions.set_selected_version (versions.current_version_id); + n.unassigned = unassigned; return n; }
--- a/libbirdfont/GlyphRange.vala +++ b/libbirdfont/GlyphRange.vala @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Johan Mattsson + Copyright (C) 2012 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 @@ -28,6 +28,11 @@ public GlyphRange () { ranges = new Gee.ArrayList<UniRange> (); unassigned = new Gee.ArrayList<string> (); + } + + public void add_unassigned (string glyph_name) { + unassigned.add (glyph_name); + len++; } public bool is_class () { @@ -157,7 +162,7 @@ } else if (w == "ampersand") { add_single ('&'); } else { - throw new MarkupError.PARSE (@"$w is not a single letter or a unicode range."); + unassigned.add (w); } } } @@ -169,7 +174,6 @@ bool first = true; StringBuilder s = new StringBuilder (); foreach (UniRange u in ranges) { - if (!first) { s.append (" "); } @@ -181,6 +185,16 @@ s.append ("-"); s.append (get_serialized_char (u.stop)); } + + first = false; + } + + foreach (string ur in unassigned) { + if (!first) { + s.append (" "); + } + + s.append (ur); first = false; } @@ -226,8 +240,7 @@ } if (s.char_count () > 1) { - warning (@"Expecting a single glyph ($s)"); - return s; + return s; // ligature } return get_serialized_char (s.get_char (0)); @@ -424,7 +437,13 @@ public bool has_character (string c) { unichar s; - string uns = unserialize (c); + string uns; + + if (unassigned.index_of (c) != -1) { + return true; + } + + uns = unserialize (c); if (uns.char_count () != 1) { warning (@"Expecting a single character got $c");
--- a/libbirdfont/GlyphSequence.vala +++ b/libbirdfont/GlyphSequence.vala @@ -31,43 +31,38 @@ */ public GlyphSequence process_ligatures () { // FIXME add range to ligature - GlyphSequence ligatures = new GlyphSequence (); + GlyphSequence ligature_sequence = new GlyphSequence (); Font font = BirdFont.get_current_font (); - Glyph liga; - GlyphCollection? gc; bool has_range = false; + Ligatures ligatures; foreach (Glyph? g in glyph) { - ligatures.glyph.add (g); + ligature_sequence.glyph.add (g); } foreach (GlyphRange? r in ranges) { - ligatures.ranges.add (r); + ligature_sequence.ranges.add (r); if (r != null) { has_range = true; } } - // FIXME: ligatures make this list invalid // skip ligature substitution if this sequence contains ranges if (has_range) { - return ligatures; + return ligature_sequence; } - - for (uint i = 0; ; i++) { - gc = font.get_ligature (i); - - if (gc == null) { - break; - } - - liga = ((!) gc).get_current (); - ligatures.replace (liga.get_ligature (), liga); - i++; + ligatures = font.get_ligatures (); + ligatures.get_single_substitution_ligatures ((substitute, ligature) => { + ligature_sequence.replace (substitute, ligature.get_current ()); + }); + + ligature_sequence.ranges.clear (); + foreach (Glyph? g in ligature_sequence.glyph) { + ligature_sequence.ranges.add (null); } - return ligatures; + return ligature_sequence; } void replace (GlyphSequence old, Glyph replacement) { @@ -118,10 +113,9 @@ i++; } - glyph = new_list; - + glyph = new_list; } } }
--- a/libbirdfont/KerningClasses.vala +++ b/libbirdfont/KerningClasses.vala @@ -89,8 +89,8 @@ public void set_kerning_for_single_glyphs (string le, string ri, double k) { string left = GlyphRange.serialize (le); string right = GlyphRange.serialize (ri); - string cleft = (!)GlyphRange.unserialize (left).get_char ().to_string (); - string cright = (!)GlyphRange.unserialize (right).get_char ().to_string (); + string cleft = (!)GlyphRange.unserialize (left); + string cright = (!)GlyphRange.unserialize (right); // FIXME: get_char? if (protect_map) { warning ("Map is protected."); @@ -258,7 +258,7 @@ return classes_kerning.get (i).val; } } - + return 0; }
--- a/libbirdfont/KerningDisplay.vala +++ b/libbirdfont/KerningDisplay.vala @@ -319,13 +319,11 @@ if (handle == wi && row_index == 0) { if (wi >= word_with_ligatures.ranges.size) { - warning (@"$wi > $(word_with_ligatures.ranges.size) Number of glyphs: $(word_with_ligatures.glyph.size)"); return false; } return_val_if_fail (wi - 1 >= 0, false); if (word_with_ligatures.ranges.size != word_with_ligatures.glyph.size) { - warning (@"ranges and glyphs does not match. $(word_with_ligatures.ranges.size) != $(word_with_ligatures.glyph.size)"); return false; } @@ -423,7 +421,6 @@ n = grr.get_all_ranges (); has_kerning = classes.has_kerning (f, n); undo_items.add (new UndoItem (f, n, kern, has_kerning)); - redo_items.clear (); first_update = false; } @@ -438,6 +435,7 @@ /** Class based gpos kerning. */ public double get_kerning_for_pair (string a, string b, GlyphRange? gr_left, GlyphRange? gr_right) { + double k; GlyphRange grl, grr; try { if (gr_left == null) { @@ -467,10 +465,10 @@ } if (gr_left == null && gr_right == null) { - return KerningClasses.get_instance ().get_kerning (a, b); + k = KerningClasses.get_instance ().get_kerning (a, b); + return k; } } catch (MarkupError e) { - // FIXME: unassigned glyphs and ligatures warning (e.message); } @@ -889,14 +887,14 @@ r = GlyphRange.unserialize (ui.next); try { + glyph_range_first = new GlyphRange (); + glyph_range_next = new GlyphRange (); + + glyph_range_first.parse_ranges (ui.first); + glyph_range_next.parse_ranges (ui.next); + if (!ui.has_kerning) { - if (l.char_count () > 1 || r.char_count () > 1) { - glyph_range_first = new GlyphRange (); - glyph_range_next = new GlyphRange (); - - glyph_range_first.parse_ranges (ui.first); - glyph_range_next.parse_ranges (ui.next); - + if (glyph_range_first.is_class () || glyph_range_next.is_class ()) { redo_state.first = glyph_range_first.get_all_ranges (); redo_state.next = glyph_range_next.get_all_ranges (); redo_state.has_kerning = true; @@ -918,7 +916,7 @@ classes.delete_kerning_for_pair (ui.first, ui.next); } - } else if (ui.first.char_count () > 1 || ui.next.char_count () > 1) { + } else if (glyph_range_first.is_class () || glyph_range_next.is_class ()) { glyph_range_first = new GlyphRange (); glyph_range_next = new GlyphRange (); @@ -938,7 +936,6 @@ classes.set_kerning (glyph_range_first, glyph_range_next, ui.kerning); } else { - redo_state.first = ui.first; redo_state.next = ui.next; redo_state.has_kerning = true;
--- a/libbirdfont/KerningList.vala +++ b/libbirdfont/KerningList.vala @@ -173,16 +173,16 @@ l = GlyphRange.unserialize (left); r = GlyphRange.unserialize (right); + + glyph_range_first = new GlyphRange (); + glyph_range_next = new GlyphRange (); + glyph_range_first.parse_ranges (left); + glyph_range_next.parse_ranges (right); + try { if (left != "" && right != "") { - - if (l.char_count () > 1 || r.char_count () > 1) { - glyph_range_first = new GlyphRange (); - glyph_range_next = new GlyphRange (); - - glyph_range_first.parse_ranges (left); - glyph_range_next.parse_ranges (right); + if (glyph_range_first.is_class () || glyph_range_next.is_class ()) { kerning = classes.get_kerning_for_range (glyph_range_first, glyph_range_next); class_index = classes.get_kerning_item_index (glyph_range_first, glyph_range_next); @@ -280,14 +280,14 @@ } ui = undo_items.get (undo_items.size - 1); + + glyph_range_first = new GlyphRange (); + glyph_range_next = new GlyphRange (); - if (ui.first.char_count () > 1 || ui.next.char_count () > 1) { - glyph_range_first = new GlyphRange (); - glyph_range_next = new GlyphRange (); - - glyph_range_first.parse_ranges (ui.first); - glyph_range_next.parse_ranges (ui.next); - + glyph_range_first.parse_ranges (ui.first); + glyph_range_next.parse_ranges (ui.next); + + if (glyph_range_first.is_class () || glyph_range_next.is_class ()) { classes.set_kerning (glyph_range_first, glyph_range_next, ui.kerning, ui.class_priority); } else { classes.set_kerning_for_single_glyphs (ui.first, ui.next, ui.kerning);
--- a/libbirdfont/LigatureList.vala +++ b/libbirdfont/LigatureList.vala @@ -18,8 +18,6 @@ namespace BirdFont { public class LigatureList : FontDisplay { - - Ligatures ligatures; int scroll = 0; int visible_rows = 0; @@ -27,10 +25,10 @@ public LigatureList () { allocation = new WidgetAllocation (); - ligatures = new Ligatures (); } public override void draw (WidgetAllocation allocation, Context cr) { + Ligatures ligatures = BirdFont.get_current_font ().get_ligatures (); int y = 20; int s = 0; bool color = (scroll % 2) == 0; @@ -90,6 +88,7 @@ } public override void scroll_wheel_down (double x, double y) { + Ligatures ligatures = BirdFont.get_current_font ().get_ligatures (); uint liga = ligatures.count (); scroll += 3; @@ -122,6 +121,7 @@ } public void update_scrollbar () { + Ligatures ligatures = BirdFont.get_current_font ().get_ligatures (); uint rows = ligatures.count (); if (rows == 0 || visible_rows == 0) { @@ -134,6 +134,7 @@ } public override void scroll_to (double percent) { + Ligatures ligatures = BirdFont.get_current_font ().get_ligatures (); uint liga = ligatures.count (); scroll = (int) (percent * liga);
--- a/libbirdfont/Ligatures.vala +++ b/libbirdfont/Ligatures.vala @@ -20,6 +20,7 @@ public class Ligatures : GLib.Object { public delegate void LigatureIterator (string substitution, string ligature); + public delegate void SingleLigatureIterator (GlyphSequence substitution, GlyphCollection ligature); public Ligatures () { } @@ -27,11 +28,44 @@ public void get_ligatures (LigatureIterator iter) { iter ("f i", "fi"); } - + + public void get_single_substitution_ligatures (SingleLigatureIterator iter) { + get_ligatures ((substitution, ligature) => { + Font font = BirdFont.get_current_font (); + GlyphCollection? gc; + GlyphCollection li; + GlyphSequence gs; + string[] subst_names = substitution.split (" "); + + gc = font.get_glyph_collection_by_name (ligature); + + if (gc == null) { + return; + } + + li = (!) gc; + + gs = new GlyphSequence (); + foreach (string s in subst_names) { + gc = font.get_glyph_collection_by_name (s); + + if (gc == null) { + return; + } + + gs.glyph.add (((!) gc).get_current ()); + } + + iter (gs, li); + }); + } + public int count () { return 1; } + + } }
--- a/libbirdfont/OpenFontFormat/CmapSubtableFormat0.vala +++ b/libbirdfont/OpenFontFormat/CmapSubtableFormat0.vala @@ -37,7 +37,7 @@ uint8 get_gid_for_unichar (unichar c, GlyfTable glyf_table) { uint32 indice = 0; foreach (GlyphCollection g in glyf_table.glyphs) { - if (g.get_unicode_character () == c) { + if (g.get_unicode_character () == c && !g.is_unassigned ()) { return (indice <= uint8.MAX) ? (uint8) indice : 0; } indice++;
--- a/libbirdfont/OpenFontFormat/CmapSubtableFormat12.vala +++ b/libbirdfont/OpenFontFormat/CmapSubtableFormat12.vala @@ -24,7 +24,7 @@ GlyphRange glyph_range = new GlyphRange (); Gee.ArrayList<UniRange> ranges; FontData fd = new FontData (); - uint32 first_assigned = 1; + uint32 first_assigned = 1 + glyf_table.number_of_unassigned_glyphs; uint32 indice; foreach (GlyphCollection g in glyf_table.glyphs) {
--- a/libbirdfont/OpenFontFormat/CmapSubtableFormat4.vala +++ b/libbirdfont/OpenFontFormat/CmapSubtableFormat4.vala @@ -188,7 +188,7 @@ uint16 gid_length = 0; uint32 indice; - uint32 first_assigned = 1; + uint32 first_assigned = 1 + glyf_table.number_of_unassigned_glyphs; foreach (GlyphCollection g in glyf_table.glyphs) { if (!g.is_unassigned () && g.get_unicode_character () < 0xFFFF) {
--- a/libbirdfont/OpenFontFormat/DirectoryTable.vala +++ b/libbirdfont/OpenFontFormat/DirectoryTable.vala @@ -66,9 +66,9 @@ public void process () throws GLib.Error { // generate font data glyf_table.process (); + gsub_table.process (); gasp_table.process (); gdef_table.process (); - // FIXME: implement gsub_table.process (); cmap_table.process (glyf_table); cvt_table.process (); hmtx_table.process (); @@ -92,9 +92,7 @@ tables.add (this); tables.add (gpos_table); - - // FIXME: implement it - // tables.append (gsub_table); + //tables.add (gsub_table); tables.add (os_2_table); @@ -109,7 +107,6 @@ tables.add (hhea_table); tables.add (hmtx_table); - // FIXME: Remove the kern table. // It looks like the old kerning table is no longer needed // since the most browsers uses the GPOS table // but Windows does not accept fonts without a kern table.
--- a/libbirdfont/OpenFontFormat/GlyfTable.vala +++ b/libbirdfont/OpenFontFormat/GlyfTable.vala @@ -41,11 +41,9 @@ public Gee.ArrayList<uint32> location_offsets; - // a list of glyphs sorted in the order we expect to find them in a - // ttf font. notdef is the firs glyph followed by null and nonmarkingreturn. - // after that will all assigned glyphs appear in sorted (unicode) order, all - // remaining unassigned glyphs will be added in the last section of the file. + // sorted array of glyphs public Gee.ArrayList<GlyphCollection> glyphs; + public uint number_of_unassigned_glyphs = 0; uint16 max_points = 0; uint16 max_contours = 0; @@ -141,7 +139,8 @@ GlyphCollection? gcn; Font font = OpenFontFormatWriter.get_current_font (); uint32 indice; - Gee.ArrayList<Glyph> unassigned_glyphs; + Gee.ArrayList<GlyphCollection> unassigned_glyphs; + bool unassigned; // add notdef character and other special chars first glyphs.add (font.get_not_def_character ()); @@ -149,16 +148,25 @@ glyphs.add (font.get_nonmarking_return ()); glyphs.add (font.get_space ()); - unassigned_glyphs = new Gee.ArrayList<Glyph> (); + unassigned_glyphs = new Gee.ArrayList<GlyphCollection> (); if (font.get_glyph_indice (0) == null) { warning ("No glyphs in font."); } - + // add glyphs, first all assigned then the unassigned ones for (indice = 0; (gcn = font.get_glyph_collection_indice (indice)) != null; indice++) { gc = (!) gcn; g = gc.get_current ().copy (); + g.remove_empty_paths (); + unassigned = gc.is_unassigned (); + + gc = new GlyphCollection (gc.get_unicode_character (), gc.get_name ()); + gc.add_glyph (g); + + if (unassigned) { + unassigned_glyphs.add (gc); + } if (g.unichar_code <= 27) { // skip control characters continue; @@ -171,24 +179,16 @@ if (g.name == ".notdef") { continue; } - - g.remove_empty_paths (); if (!gc.is_unassigned ()) { glyphs.add (gc); - } else { - printd ("Adding unassigned glyph."); - unassigned_glyphs.add (g); } } - // FIXME: ligatures - /* - foreach (Glyph ug in unassigned_glyphs) { - glyphs.append (ug); + foreach (GlyphCollection ug in unassigned_glyphs) { + glyphs.insert (1, ug); + number_of_unassigned_glyphs++; } - */ - } public void process_glyph (Glyph g, FontData fd) throws GLib.Error { @@ -342,7 +342,7 @@ Glyph parse_index (int index, FontData dis, LocaTable loca, HmtxTable hmtx_table, HeadTable head_table, PostTable post_table) throws GLib.Error { - // FIXME: DELETE done by freetype + // FIXME: DELETE parse with freetype Glyph glyph = new Glyph (""); /* double xmin, xmax;
--- a/libbirdfont/OpenFontFormat/Gsub.vala +++ b/libbirdfont/OpenFontFormat/Gsub.vala @@ -21,6 +21,7 @@ public GsubTable (GlyfTable glyf_table) { this.glyf_table = glyf_table; + id = "GSUB"; } public override void parse (FontData dis) throws Error { @@ -83,7 +84,6 @@ fd.add_ushort (1); // format fd.add_ushort (1); // num glyphs fd.add_ushort ((uint16) glyf_table.get_gid ("f")); // gid - fd.pad (); this.font_data = fd;
--- a/libbirdfont/OpenFontFormat/LocaTable.vala +++ b/libbirdfont/OpenFontFormat/LocaTable.vala @@ -24,7 +24,9 @@ } ~LocaTable () { - if (glyph_offsets != null) delete glyph_offsets; + if (glyph_offsets != null) { + delete glyph_offsets; + } } public uint32 get_offset (uint32 i) {
--- a/libbirdfont/SvgFont.vala +++ b/libbirdfont/SvgFont.vala @@ -251,9 +251,12 @@ parser.add_path_to_glyph (svg, glyph, true, units); glyph.right_limit = glyph.left_limit + advance * units; + // FIXME: add svg font ligatures + /* if (ligature != "") { glyph.set_ligature_substitution (ligature); } + */ glyph_collection = new GlyphCollection (unicode_value, glyph_name); glyph_collection.insert_glyph (glyph, true);
--- a/libbirdxml/Xml.vala +++ b/libbirdxml/Xml.vala @@ -25,13 +25,11 @@ * Example: * {{{ * - * /* Print all tags and attributes in an XML document. - * * - * * Expected output: - * * tag1 - * * tag2 - * * attribute1 - * */ + * // Print all tags and attributes in an XML document. + * // Expected output: + * // tag1 + * // tag2 + * // attribute1 * public static int main (string[] arg) { * Tag root; * XmlParser parser; @@ -102,7 +100,7 @@ Attributes attributes = tag.get_attributes (); foreach (Attribute a in attributes) { - if (tag.has_failed ()) { + if (tag.has_failed () || a.get_name () == "") { error = true; return; }