Commit a76d9a8
parse ligatures from svg font
Changed files (7)
deletedlibbirdfont/Context.valamodifiedlibbirdfont/Font.valamodifiedlibbirdfont/Glyph.valaaddedlibbirdfont/KerningDisplay.valamodifiedlibbirdfont/MenuTab.valamodifiedlibbirdfont/OpenFontFormatWriter.valamodifiedlibbirdfont/SvgFont.vala
Diff
deleted file mode 100644@@ -1,335 +0,0 @@-/*- Copyright (C) 2012 Johan Mattsson-- This program is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- This program 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 General Public License for more details.-- You should have received a copy of the GNU General Public License- along with this program. If not, see <http://www.gnu.org/licenses/>.-*/--using Cairo;--namespace BirdFont {--/** Kerning context. */-public class ContextDisplay : FontDisplay {-- List <Word> row;- int active_handle = -1;- int selected_handle = -1;- - double begin_handle_x = 0;- double begin_handle_y = 0;- - double last_handle_x = 0;- - public ContextDisplay () {- Word w = new Word ();- row = new List <Word> ();- row.append (w);- }-- public override string get_name () {- return "Kerning";- }- - public override void draw (Allocation allocation, Context cr) {- Glyph? g;- Glyph glyph;- double x, y, w, kern, alpha;- double x2;- int i, wi;- string prev;- - i = 0;- - // bg color- cr.save ();- cr.set_source_rgba (1, 1, 1, 1);- cr.rectangle (0, 0, allocation.width, allocation.height);- cr.fill ();- cr.restore ();- - alpha = 1;- y = 100;- x = 20;- w = 0;- prev = "";- - foreach (Word word in row) {- wi = 0;- - foreach (string s in word.glyph) { - g = (!) BirdFont.get_current_font ().get_glyph_by_name (s); - - if (s == "") {- continue;- }- - kern = (prev != "") ? get_kerning (prev, s) : 0;- - // draw glyph - if (g == null) {- w = 50;- alpha = 1;- } else {- alpha = 0;- glyph = (!) g;- Svg.draw_svg_path (cr, glyph.get_svg_data (), x + kern, y);- w = glyph.get_width ();- }-- // handle- if (active_handle == i) {- //x2 = x + kern;- x2 = x + kern / 2.0;- - cr.save ();- cr.set_source_rgba (153/255.0, 153/255.0, 173/255.0, 1);- cr.move_to (x2 - 5, y + 20);- cr.line_to (x2 + 0, y + 20 - 5);- cr.line_to (x2 + 5, y + 20);- cr.fill ();- - cr.set_font_size (10);- cr.show_text (s);- cr.restore ();- } - - x += w + kern;- - // caption- if (g == null || ((!)g).is_empty ()) {- cr.save ();- cr.set_source_rgba (153/255.0, 153/255.0, 153/255.0, alpha);- cr.move_to (x - w / 2.0 - 5, y + 20);- cr.set_font_size (10);- cr.show_text (s);- cr.restore ();- }- - prev = s;- - wi++;- i++;- }- - if (y > allocation.height && i > 10) {- row.remove (word);- }- - y += MainWindow.get_current_glyph ().get_height () + 20;- x = 20; - }- }- - private void set_kerning (int handle, double val) {- string a, b;- Font font;- int wi = 0;- double kern;- - font = BirdFont.get_current_font ();-- font.touch ();-- a = "";- b = "";-- foreach (Word word in row) {- foreach (string s in word.glyph) {- - if (s == "") {- continue;- }- - b = s;- - if (handle == wi) {- kern = font.get_kerning_by_name (a, b) + val;- font.set_kerning_by_name (a, b, kern);- }- - wi++;- - a = b;- }- }- - - }- - private double get_kerning (string a, string b) {- Font font = BirdFont.get_current_font ();- return font.get_kerning_by_name (a, b);- }- - public override void selected_canvas () {- Glyph g;- Word w;- unowned List<Word>? r;- unowned List<string>? rw;- StringBuilder s = new StringBuilder ();- bool append_char = false;- - KeyBindings.singleton.set_require_modifier (true);- - g = MainWindow.get_current_glyph ();- s.append_unichar (g.get_unichar ());-- r = row;- return_if_fail (r != null);-- if (row.length () == 0) {- append_char = true;- }- - if (row.length () > 0) {- rw = row.first ().data.glyph;- return_if_fail (rw != null);- append_char = (row.first ().data.glyph.data.index_of (s.str) == -1);- }- - if (append_char) {- w = new Word ();- row.append (w);- w.glyph.prepend (s.str);- } - }- - public override void key_press (uint keyval) {- unichar c = (unichar) keyval;- Font f = BirdFont.get_current_font ();- string name;- - if (KeyBindings.modifier == NONE || KeyBindings.modifier == SHIFT) {- - if (keyval == Key.BACK_SPACE && row.length () > 0) { - row.first ().data.glyph.remove_link (row.first ().data.glyph.last ());- }- - if (row.length () == 0 || c == Key.ENTER) {- row.prepend (new Word ());- }- - if (!is_modifier_key (c) && c.validate ()) {- name = f.get_name_for_character (c);- row.first ().data.glyph.append (name);- }- }- - MainWindow.get_glyph_canvas ().redraw ();- }- - public override void motion_notify (double ex, double ey) {- double k, y;- - if (selected_handle == -1) {- set_active_handle (ex, ey);- } else {- y = 1;- - if (Math.fabs (ey - begin_handle_y) > 20) {- y = ((Math.fabs (ey - begin_handle_y) / 100) + 1);- }- - k = (ex - last_handle_x) / y; // y-axis is variable precision- set_kerning (selected_handle, k);- MainWindow.get_glyph_canvas ().redraw ();- }- - last_handle_x = ex;- }- - public void set_active_handle (double ex, double ey) {- double y = 100;- double x = 20;- double w = 0;- double d, kern;- double min = double.MAX;- int i = 0;- int row_index = 0;- int col_index = 0;- Glyph? g;- Glyph glyph = new Glyph.no_lines ("");- - string prev = "";- string gl_name = "";- - foreach (Word word in row) {- col_index = 0;- foreach (string s in word.glyph) {- - // draw glyph- g = (!) BirdFont.get_current_font ().get_glyph_by_name (s); - kern = (prev != "") ? get_kerning (prev, s) : 0;- - if (g == null) {- w = 50; - } else {- glyph = (!) g;- w = glyph.get_width ();- - }- - d = Math.pow (x + kern - ex, 2) + Math.pow (y - ey, 2);- - if (d < min) {- min = d;- gl_name = glyph.get_name ();- - if (active_handle != i - row_index) {- active_handle = i - row_index;- MainWindow.get_glyph_canvas ().redraw ();- }-- if (col_index == word.glyph.length () || col_index == 0) {- active_handle = -1;- }- }- - prev = s;- x += w + kern;- i++;- col_index++;- }- - row_index++;- y += MainWindow.get_current_glyph ().get_height () + 20;- x = 20;- }- }- - public override void button_release (int button, double ex, double ey) {- set_active_handle (ex, ey);- selected_handle = -1;- }- - public override void button_press (uint button, double ex, double ey) {- set_active_handle (ex, ey);- selected_handle = active_handle;- begin_handle_x = ex;- begin_handle_y = ey;- last_handle_x = ex;- }--}--class Word {- public List <string> glyph;- - public Word () {- glyph = new List <string> ();- glyph.append ("");- }-}--}@@ -28,13 +28,13 @@ public enum FontFormat { public class Font : GLib.Object { /** Table with glyphs sorted by their unicode value. */- GlyphTable glyph_cache = new GlyphTable ();+ GlyphTable glyph_unicode = new GlyphTable (); /** Table with glyphs sorted by their name. */ GlyphTable glyph_name = new GlyphTable (); - /** Last unassigned index */- int next_unindexed = 0;+ /** Ligatures */+ GlyphTable ligature = new GlyphTable (); public List <string> background_images = new List <string> (); public string background_scale = "1";@@ -174,7 +174,7 @@ public class Font : GLib.Object { public void print_all () { stdout.printf ("Unicode:\n"); - glyph_cache.for_each((g) => {+ glyph_unicode.for_each((g) => { stdout.printf (@"$(g.get_unicode ())\n"); }); @@ -196,7 +196,7 @@ public class Font : GLib.Object { } ret = new Glyph ("nonmarkingreturn", '\r');- ret.set_unassigned (false);+ ret.left_limit = 0; ret.right_limit = 0; ret.remove_empty_paths ();@@ -214,7 +214,7 @@ public class Font : GLib.Object { } n = new Glyph ("null", '\0');- n.set_unassigned (false);+ n.left_limit = 0; n.right_limit = 0; n.remove_empty_paths ();@@ -236,7 +236,7 @@ public class Font : GLib.Object { } n = new Glyph ("space", ' ');- n.set_unassigned (false);+ n.left_limit = 0; n.right_limit = 27; n.remove_empty_paths ();@@ -260,7 +260,6 @@ public class Font : GLib.Object { p = new Path (); i = new Path (); - g.set_unassigned (true); g.left_limit = -33; g.right_limit = 33; @@ -306,10 +305,10 @@ public class Font : GLib.Object { } if (glyph_collection.get_unicode () != "") {- glyph_name.insert (glyph_collection.get_name (), glyph_collection); + glyph_unicode.insert (glyph_collection.get_unicode (), glyph_collection); } - glyph_cache.insert (glyph_collection.get_unicode (), glyph_collection);+ glyph_name.insert (glyph_collection.get_name (), glyph_collection); } public string get_name_for_character (unichar c) {@@ -342,9 +341,9 @@ public class Font : GLib.Object { } public void delete_glyph (GlyphCollection glyph) {- glyph_cache.remove (glyph.get_unicode ());+ glyph_unicode.remove (glyph.get_unicode ()); glyph_name.remove (glyph.get_name ());- // FIXME: DELETE: glyph_cache.remove (glyph);+ // FIXME: DELETE: glyph_unicode.remove (glyph); } /** Obtain all versions and alterntes for this glyph. */@@ -368,7 +367,7 @@ public class Font : GLib.Object { /** Get glyph collection by unichar code. */ public GlyphCollection? get_cached_glyph_collection (string unichar_code) { GlyphCollection? gc = null;- gc = glyph_cache.get (unichar_code);+ gc = glyph_unicode.get (unichar_code); return gc; } @@ -393,7 +392,7 @@ public class Font : GLib.Object { public Glyph? get_glyph (string name) { GlyphCollection? gc = null;- gc = glyph_cache.get (name);+ gc = glyph_unicode.get (name); if (gc == null) { return null;@@ -422,6 +421,19 @@ public class Font : GLib.Object { background_images.append (file); } + public string get_name_from_unicode (string unicode) {+ string v = "";+ Glyph? g = get_glyph (unicode);+ + if (g != null) {+ v = ((!)g).get_name ();+ } else {+ warning (@"no name for \"$unicode\"");+ }+ + return v;+ }+ /** Obtain kerning for pair with name a and b. * @param a name of left glyph kerning pair * @param b name of right glyph kerning pair@@ -619,7 +631,7 @@ public class Font : GLib.Object { os.put_string ("\n"); } - glyph_cache.for_each ((gc) => {+ glyph_unicode.for_each ((gc) => { bool selected; if (is_null (gc)) {@@ -637,7 +649,7 @@ public class Font : GLib.Object { } }); - glyph_cache.for_each ((gc) => {+ glyph_unicode.for_each ((gc) => { Glyph glyph; try {@@ -665,7 +677,7 @@ public class Font : GLib.Object { } }); - glyph_cache.for_each ((gc) => {+ glyph_unicode.for_each ((gc) => { GlyphBackgroundImage bg; try {@@ -811,7 +823,7 @@ public class Font : GLib.Object { grid_width.remove_link (grid_width.first ()); } - glyph_cache.remove_all ();+ glyph_unicode.remove_all (); glyph_name.remove_all (); if (path.has_suffix (".svg")) {@@ -904,27 +916,17 @@ public class Font : GLib.Object { if (gcl != null) { warning (@"glyph \"$(g.get_name ())\" does already exist");+ return; }- - if (g.is_unassigned ()) {- gc = new GlyphCollection (g); - if (g.name == "") {- warning ("refusing to insert glyph without name");- g.name = @"($(++next_unindexed))";- return;+ gc = new GlyphCollection (g);+ add_glyph_collection (gc);++ if (g.is_ligature ()) {+ foreach (string s in g.substitution) {+ ligature.insert (s, gc); }- - add_glyph_collection ((!) gc);- } else if (gcl == null) {- gc = new GlyphCollection (g);- add_glyph_collection ((!) gc);- } else {- stderr.printf (@"Glyph collection does already have an entry for $(g.get_name ()) char $((uint64) g.unichar_code).\n"); }- - // take xheight from appropriate lower case letter- // xheight_position = estimate_xheight (); } public bool parse_otf_file (string path) throws GLib.Error {@@ -945,7 +947,7 @@ public class Font : GLib.Object { font_file = path; // empty cache and fill it with new glyphs from disk- glyph_cache.remove_all ();+ glyph_unicode.remove_all (); glyph_name.remove_all (); while (background_images.length () > 0) {@@ -75,7 +75,6 @@ public class Glyph : FontDisplay { bool xheight_lines_visible = false; bool margin_boundries_visible = false; - bool unassigned = false; public unichar unichar_code = 0; List<Glyph> undo_list = new List<Glyph> ();@@ -85,6 +84,9 @@ public class Glyph : FontDisplay { string glyph_sequence = ""; bool open = true; + bool ligature = false;+ public List<string> substitution = new List<string> ();+ public Glyph (string name, unichar unichar_code = 0) { this.name = name; this.unichar_code = unichar_code;@@ -103,6 +105,15 @@ public class Glyph : FontDisplay { path_list.append (new Path ()); }+ + public void add_ligature_substitution (string glyph_sequence) {+ ligature = true;+ substitution.append (glyph_sequence);+ }+ + public bool is_ligature () {+ return ligature;+ } public void select_all_paths () { clear_active_paths ();@@ -167,14 +178,6 @@ public class Glyph : FontDisplay { return 0; }- - public void set_unassigned (bool u) {- unassigned = u;- }- - public bool is_unassigned () {- return unassigned;- } public void boundries (out double x1, out double y1, out double x2, out double y2) { if (path_list.length () == 0) {@@ -1445,6 +1448,11 @@ public class Glyph : FontDisplay { g.background_image = ((!) background_image).copy (); } + g.ligature = ligature;+ foreach (string s in substitution) {+ g.substitution.append (s);+ }+ return g; } new file mode 100644@@ -0,0 +1,335 @@+/*+ Copyright (C) 2012 Johan Mattsson++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program 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 General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+*/++using Cairo;++namespace BirdFont {++/** Kerning context. */+public class KerningDisplay : FontDisplay {++ List <Word> row;+ int active_handle = -1;+ int selected_handle = -1;+ + double begin_handle_x = 0;+ double begin_handle_y = 0;+ + double last_handle_x = 0;+ + public KerningDisplay () {+ Word w = new Word ();+ row = new List <Word> ();+ row.append (w);+ }++ public override string get_name () {+ return "Kerning";+ }+ + public override void draw (Allocation allocation, Context cr) {+ Glyph? g;+ Glyph glyph;+ double x, y, w, kern, alpha;+ double x2;+ int i, wi;+ string prev;+ + i = 0;+ + // bg color+ cr.save ();+ cr.set_source_rgba (1, 1, 1, 1);+ cr.rectangle (0, 0, allocation.width, allocation.height);+ cr.fill ();+ cr.restore ();+ + alpha = 1;+ y = 100;+ x = 20;+ w = 0;+ prev = "";+ + foreach (Word word in row) {+ wi = 0;+ + foreach (string s in word.glyph) { + g = (!) BirdFont.get_current_font ().get_glyph_by_name (s); + + if (s == "") {+ continue;+ }+ + kern = (prev != "") ? get_kerning (prev, s) : 0;+ + // draw glyph + if (g == null) {+ w = 50;+ alpha = 1;+ } else {+ alpha = 0;+ glyph = (!) g;+ Svg.draw_svg_path (cr, glyph.get_svg_data (), x + kern, y);+ w = glyph.get_width ();+ }++ // handle+ if (active_handle == i) {+ //x2 = x + kern;+ x2 = x + kern / 2.0;+ + cr.save ();+ cr.set_source_rgba (153/255.0, 153/255.0, 173/255.0, 1);+ cr.move_to (x2 - 5, y + 20);+ cr.line_to (x2 + 0, y + 20 - 5);+ cr.line_to (x2 + 5, y + 20);+ cr.fill ();+ + cr.set_font_size (10);+ cr.show_text (s);+ cr.restore ();+ } + + x += w + kern;+ + // caption+ if (g == null || ((!)g).is_empty ()) {+ cr.save ();+ cr.set_source_rgba (153/255.0, 153/255.0, 153/255.0, alpha);+ cr.move_to (x - w / 2.0 - 5, y + 20);+ cr.set_font_size (10);+ cr.show_text (s);+ cr.restore ();+ }+ + prev = s;+ + wi++;+ i++;+ }+ + if (y > allocation.height && i > 10) {+ row.remove (word);+ }+ + y += MainWindow.get_current_glyph ().get_height () + 20;+ x = 20; + }+ }+ + private void set_kerning (int handle, double val) {+ string a, b;+ Font font;+ int wi = 0;+ double kern;+ + font = BirdFont.get_current_font ();++ font.touch ();++ a = "";+ b = "";++ foreach (Word word in row) {+ foreach (string s in word.glyph) {+ + if (s == "") {+ continue;+ }+ + b = s;+ + if (handle == wi) {+ kern = font.get_kerning_by_name (a, b) + val;+ font.set_kerning_by_name (a, b, kern);+ }+ + wi++;+ + a = b;+ }+ }+ + + }+ + private double get_kerning (string a, string b) {+ Font font = BirdFont.get_current_font ();+ return font.get_kerning_by_name (a, b);+ }+ + public override void selected_canvas () {+ Glyph g;+ Word w;+ unowned List<Word>? r;+ unowned List<string>? rw;+ StringBuilder s = new StringBuilder ();+ bool append_char = false;+ + KeyBindings.singleton.set_require_modifier (true);+ + g = MainWindow.get_current_glyph ();+ s.append_unichar (g.get_unichar ());++ r = row;+ return_if_fail (r != null);++ if (row.length () == 0) {+ append_char = true;+ }+ + if (row.length () > 0) {+ rw = row.first ().data.glyph;+ return_if_fail (rw != null);+ append_char = (row.first ().data.glyph.data.index_of (s.str) == -1);+ }+ + if (append_char) {+ w = new Word ();+ row.append (w);+ w.glyph.prepend (s.str);+ } + }+ + public override void key_press (uint keyval) {+ unichar c = (unichar) keyval;+ Font f = BirdFont.get_current_font ();+ string name;+ + if (KeyBindings.modifier == NONE || KeyBindings.modifier == SHIFT) {+ + if (keyval == Key.BACK_SPACE && row.length () > 0) { + row.first ().data.glyph.remove_link (row.first ().data.glyph.last ());+ }+ + if (row.length () == 0 || c == Key.ENTER) {+ row.prepend (new Word ());+ }+ + if (!is_modifier_key (c) && c.validate ()) {+ name = f.get_name_for_character (c);+ row.first ().data.glyph.append (name);+ }+ }+ + MainWindow.get_glyph_canvas ().redraw ();+ }+ + public override void motion_notify (double ex, double ey) {+ double k, y;+ + if (selected_handle == -1) {+ set_active_handle (ex, ey);+ } else {+ y = 1;+ + if (Math.fabs (ey - begin_handle_y) > 20) {+ y = ((Math.fabs (ey - begin_handle_y) / 100) + 1);+ }+ + k = (ex - last_handle_x) / y; // y-axis is variable precision+ set_kerning (selected_handle, k);+ MainWindow.get_glyph_canvas ().redraw ();+ }+ + last_handle_x = ex;+ }+ + public void set_active_handle (double ex, double ey) {+ double y = 100;+ double x = 20;+ double w = 0;+ double d, kern;+ double min = double.MAX;+ int i = 0;+ int row_index = 0;+ int col_index = 0;+ Glyph? g;+ Glyph glyph = new Glyph.no_lines ("");+ + string prev = "";+ string gl_name = "";+ + foreach (Word word in row) {+ col_index = 0;+ foreach (string s in word.glyph) {+ + // draw glyph+ g = (!) BirdFont.get_current_font ().get_glyph_by_name (s); + kern = (prev != "") ? get_kerning (prev, s) : 0;+ + if (g == null) {+ w = 50; + } else {+ glyph = (!) g;+ w = glyph.get_width ();+ + }+ + d = Math.pow (x + kern - ex, 2) + Math.pow (y - ey, 2);+ + if (d < min) {+ min = d;+ gl_name = glyph.get_name ();+ + if (active_handle != i - row_index) {+ active_handle = i - row_index;+ MainWindow.get_glyph_canvas ().redraw ();+ }++ if (col_index == word.glyph.length () || col_index == 0) {+ active_handle = -1;+ }+ }+ + prev = s;+ x += w + kern;+ i++;+ col_index++;+ }+ + row_index++;+ y += MainWindow.get_current_glyph ().get_height () + 20;+ x = 20;+ }+ }+ + public override void button_release (int button, double ex, double ey) {+ set_active_handle (ex, ey);+ selected_handle = -1;+ }+ + public override void button_press (uint button, double ex, double ey) {+ set_active_handle (ex, ey);+ selected_handle = active_handle;+ begin_handle_x = ex;+ begin_handle_y = ey;+ last_handle_x = ex;+ }++}++class Word {+ public List <string> glyph;+ + public Word () {+ glyph = new List <string> ();+ glyph.append ("");+ }+}++}@@ -408,7 +408,7 @@ c.append (""" } public static void show_kerning_context () {- MainWindow.get_tab_bar ().add_unique_tab (new ContextDisplay (), 85, false);+ MainWindow.get_tab_bar ().add_unique_tab (new KerningDisplay (), 85, false); } public static void preview () {@@ -759,11 +759,6 @@ class GlyfTable : Table { while (gl != glyphs.first ()) { g = (!) gl.data; - - if (!g.is_unassigned ()) { - break; - } - gl = gl.prev; } @@ -845,10 +840,6 @@ class GlyfTable : Table { glyph.name = name; - if (character == 0) { - glyph.set_unassigned (true); - } - if (character == 0 && name != "") { stderr.printf (@"Got null character\n"); stderr.printf (@"gid: $index\n"); @@ -1560,11 +1551,7 @@ class GlyfTable : Table { g.remove_empty_paths (); - if (!g.is_unassigned ()) { - glyphs.append (g); - } else { - unassigned_glyphs.append (g); - } + glyphs.append (g); } foreach (Glyph ug in unassigned_glyphs) { @@ -1809,9 +1796,7 @@ class CmapSubtableWindowsUnicode : CmapSubtable { uint32 first_assigned = 1; foreach (Glyph g in glyf_table.glyphs) { - if (!g.is_unassigned ()) { - glyph_range.add_single (g.unichar_code); - } + glyph_range.add_single (g.unichar_code); } // glyph_range.print_all (); @@ -78,6 +78,7 @@ class SvgFont : GLib.Object { StringBuilder sl, sr; string attr_name = ""; string attr_content;+ string ln, rn; for (Xml.Attr* prop = node->properties; prop != null; prop = prop->next) { attr_name = prop->name;@@ -107,22 +108,52 @@ class SvgFont : GLib.Object { } } + // , is used as separator+ if (left == ",") {+ left = ",";+ }++ if (right == ",") {+ right = ",";+ } - // TODO: ranges and sequences for u1 & u2 + g1 & g2+ // TODO: ranges for u1 & u2 + g1 & g2+ + // u1 + u2 or g2 foreach (string lk in left.split (",")) {+ l = get_unichar (lk);+ sl = new StringBuilder ();+ sl.append_unichar (l);+ ln = font.get_name_from_unicode (sl.str);+ foreach (string rk in right.split (",")) {- l = get_unichar (lk); r = get_unichar (rk);- - sl = new StringBuilder ();- sl.append_unichar (l);- sr = new StringBuilder (); sr.append_unichar (r);- - font.set_kerning (sl.str, sr.str, -kerning); + rn = font.get_name_from_unicode (sr.str);+ font.set_kerning_by_name (ln, rn, -kerning);+ }++ foreach (string rk in right_name.split (",")) {+ font.set_kerning_by_name (ln, rk, -kerning);+ }+ }++ // g1 + u2 or g2+ foreach (string lk in left_name.split (",")) {+ foreach (string rk in right.split (",")) {+ r = get_unichar (rk);+ sr = new StringBuilder ();+ sr.append_unichar (r);+ rn = font.get_name_from_unicode (sr.str);+ font.set_kerning_by_name (lk, rn, -kerning);+ }++ foreach (string rk in right_name.split (",")) {+ font.set_kerning_by_name (lk, rk, -kerning); } }+ } void parse_font_limits (Xml.Node* node) {@@ -176,14 +207,18 @@ class SvgFont : GLib.Object { /** Obtain unichar value from either a character, a hex representation of * a character or series of characters (f, m or ffi). */- static unichar get_unichar (string val) {+ unichar get_unichar (string val) { string v = val; unichar unicode_value;- + if (val == "&") { return '&'; }- ++ if (val == ",") {+ return ',';+ }+ // TODO: parse ligatures if (v.has_prefix ("&")) { // parse hex value@@ -192,19 +227,27 @@ class SvgFont : GLib.Object { v = v.replace (";", ""); unicode_value = Font.to_unichar (v); } else {- // obtain unicode value - if (v.char_count () > 1) {- warning ("font contains ligatures");+ // don't assign ligatures to any code point+ if (is_ligature (val)) { return '\0'; } + // obtain unicode value unicode_value = v.get_char (0); } return unicode_value; } + bool is_ligature (string v) {+ if (v.has_prefix ("&")) {+ return false;+ }+ + return v.char_count () > 1; + }+ void parse_glyph (Xml.Node* node) { string attr_name = ""; string attr_content;@@ -213,6 +256,7 @@ class SvgFont : GLib.Object { string svg = ""; Glyph glyph; double advance = font_advance;+ string ligature = ""; for (Xml.Attr* prop = node->properties; prop != null; prop = prop->next) { attr_name = prop->name;@@ -224,6 +268,10 @@ class SvgFont : GLib.Object { if (glyph_name == "") { glyph_name = attr_content; }+ + if (is_ligature (attr_content)) {+ ligature = attr_content;+ } } // svg data@@ -240,15 +288,15 @@ class SvgFont : GLib.Object { } } - // FIXME: this code will ignore characters that are mapped several glyphs- if (unicode_value != '\0') {- glyph = new Glyph (glyph_name, unicode_value);- ImportSvg.parse_svg_data (svg, glyph, true, units); - glyph.right_limit = glyph.left_limit + advance * units;- font.add_glyph_callback (glyph);- } else {- warning ("ignoring glyph");+ glyph = new Glyph (glyph_name, unicode_value);+ ImportSvg.parse_svg_data (svg, glyph, true, units); + glyph.right_limit = glyph.left_limit + advance * units;+ + if (ligature != "") {+ glyph.add_ligature_substitution (ligature); }+ + font.add_glyph_callback (glyph); } }