Commit 0d36240
Efficient parsing of the kern table
Changed files (28)
modifiedlibbirdfont/BirdFontFile.valamodifiedlibbirdfont/GlyphRange.valamodifiedlibbirdfont/OpenFontFormat/CffTable.valamodifiedlibbirdfont/OpenFontFormat/Cmap.valamodifiedlibbirdfont/OpenFontFormat/CvtTable.valamodifiedlibbirdfont/OpenFontFormat/DirectoryTable.valamodifiedlibbirdfont/OpenFontFormat/FontData.valamodifiedlibbirdfont/OpenFontFormat/GaspTable.valamodifiedlibbirdfont/OpenFontFormat/GdefTable.valamodifiedlibbirdfont/OpenFontFormat/GlyfData.valamodifiedlibbirdfont/OpenFontFormat/GlyfTable.valamodifiedlibbirdfont/OpenFontFormat/GposTable.valamodifiedlibbirdfont/OpenFontFormat/Gsub.valamodifiedlibbirdfont/OpenFontFormat/HeadTable.valamodifiedlibbirdfont/OpenFontFormat/HheaTable.valamodifiedlibbirdfont/OpenFontFormat/HmtxTable.valamodifiedlibbirdfont/OpenFontFormat/Kern.valamodifiedlibbirdfont/OpenFontFormat/LocaTable.valamodifiedlibbirdfont/OpenFontFormat/MaxpTable.valamodifiedlibbirdfont/OpenFontFormat/NameTable.valamodifiedlibbirdfont/OpenFontFormat/OffsetTable.valamodifiedlibbirdfont/OpenFontFormat/OpenFontFormatReader.valamodifiedlibbirdfont/OpenFontFormat/OpenFontFormatWriter.valamodifiedlibbirdfont/OpenFontFormat/Os2Table.valamodifiedlibbirdfont/OpenFontFormat/OtfInputStream.valamodifiedlibbirdfont/OpenFontFormat/PostTable.valamodifiedlibbirdfont/OpenFontFormat/Table.valamodifiedlibbirdfont/OpenFontFormat/load_font.c
Diff
@@ -36,6 +36,7 @@ class BirdFontFile { Parser.init (); + font.font_file = path; tr = new TextReader.filename (path); ok = load_xml (tr); @@ -53,6 +54,8 @@ class BirdFontFile { Parser.init (); + font.font_file = "typeface.bf";+ printd ("Load data:\n"); printd (xml_data); @@ -71,9 +74,7 @@ class BirdFontFile { tr.read (); root = tr.expand ();- - font.font_file = "typeface.bf";- + if (is_null (root)) { warning ("No root element"); tr.close ();@@ -88,41 +89,12 @@ class BirdFontFile { return ok; } - private string get_attribute (TextReader tr, string attribute_name) {- string? c = tr.get_attribute (attribute_name);- - if (c == null) {- return "";- }- - return (!) c;- }- - private string get_value (TextReader tr) {- string? v = tr.value ();- - if (v == null) {- return "";- }- - return (!) v;- }-- private string get_name (TextReader tr) {- string? n = tr.name ();- - if (n == null) {- return "";- }- - return (!) n;- }- public bool write_font_file (string path, bool backup = false) { try { File file = File.new_for_path (path); uint num_kerning_pairs; uint progress;+ string range; if (file.query_file_type (0) == FileType.DIRECTORY) { warning (@"Can not save font. $path is a directory.");@@ -239,13 +211,20 @@ class BirdFontFile { progress = num_kerning_pairs; ProgressBar.set_progress (1); for (uint i = 0; i < num_kerning_pairs; i++) {+ + range = KerningClasses.get_instance ().classes_first.nth (i).data.get_all_ranges ();+ range = serialize (range);+ os.put_string ("<kerning "); os.put_string ("left=\"");- os.put_string (KerningClasses.get_instance ().classes_first.nth (i).data.get_all_ranges ().replace ("\"", "quote"));+ os.put_string (range); os.put_string ("\" "); + range = KerningClasses.get_instance ().classes_last.nth (i).data.get_all_ranges ();+ range = serialize (range);+ os.put_string ("right=\"");- os.put_string (KerningClasses.get_instance ().classes_last.nth (i).data.get_all_ranges ().replace ("\"", "quote"));+ os.put_string (range); os.put_string ("\" "); os.put_string ("hadjustment=\"");@@ -600,10 +579,11 @@ class BirdFontFile { } } - private string unserialize (string s) {+ public static string unserialize (string s) { StringBuilder b; string r; r = s.replace ("quote", "\"");+ r = r.replace ("ampersand", "&"); if (s.has_prefix ("U+")) { b = new StringBuilder ();@@ -613,6 +593,17 @@ class BirdFontFile { return r; }++ public static string serialize (string s) {+ string r = s;+ r = r.replace ("\"", "quote");+ r = r.replace ("&", "ampersand");+ return r;+ }+ + public static string serialize_unichar (unichar c) {+ return serialize (GlyphRange.get_serialized_char (c));+ } private void parse_kerning (Xml.Node* node) { string attr_name;@@ -172,7 +172,7 @@ public class GlyphRange { return s.str; } - private string get_serialized_char (unichar c) {+ public static string get_serialized_char (unichar c) { StringBuilder s = new StringBuilder (); if (c == ' ') {@@ -191,7 +191,7 @@ public class GlyphRange { return s.str; } - private string unserialize (string c) {+ public static string unserialize (string c) { if (c == "space") { return " "; }@@ -15,7 +15,7 @@ namespace BirdFont { /** Type2, PostScript outlines */-class CffTable : Table {+public class CffTable : Table { static const uint8 HSTEM = 1; static const uint8 VSTEM = 3;@@ -14,7 +14,7 @@ namespace BirdFont { -class CmapSubtable : Table {+public class CmapSubtable : Table { // Override these methods in subtables for each format. @@ -43,7 +43,7 @@ class CmapSubtable : Table { } /** Format 4 cmap subtable */-class CmapSubtableWindowsUnicode : CmapSubtable {+public class CmapSubtableWindowsUnicode : CmapSubtable { uint16 format = 0; HashTable <uint64?, unichar> table = new HashTable <uint64?, unichar> (int64_hash, int_equal); @@ -303,7 +303,7 @@ class CmapSubtableWindowsUnicode : CmapSubtable { } } -class CmapTable : Table { +public class CmapTable : Table { GlyfTable glyf_table; List<CmapSubtable> subtables;@@ -14,7 +14,7 @@ namespace BirdFont { -class CvtTable : Table {+public class CvtTable : Table { public CvtTable () { id = "cvt ";@@ -1,5 +1,5 @@ /*- Copyright (C) 2012, 2013 Johan Mattsson+ 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 @@ -15,7 +15,7 @@ namespace BirdFont { /** Table with list of tables sorted by table tag. */-class DirectoryTable : Table {+public class DirectoryTable : Table { public CmapTable cmap_table; public CvtTable cvt_table;@@ -118,7 +118,7 @@ class DirectoryTable : Table { offset_table = ot; } - public new void parse (FontData dis, File file, OpenFontFormatReader reader_callback) throws Error {+ public new void parse (FontData dis, OpenFontFormatReader reader_callback) throws Error { StringBuilder tag = new StringBuilder (); uint32 checksum; uint32 offset;@@ -217,13 +217,11 @@ class DirectoryTable : Table { gpos_table.length = length; } }-+ }+ + public void parse_all_tables (FontData dis, OpenFontFormatReader reader_callback) { head_table.parse (dis); - if (!validate_tables (dis, file)) {- warning ("Missing required table or bad checksum.");- }- hhea_table.parse (dis); reader_callback.set_limits (); @@ -251,6 +249,30 @@ class DirectoryTable : Table { } } + public void parse_kern_table (FontData dis) {+ if (kern_table.has_data ()) {+ kern_table.parse (dis);+ } else {+ warning ("Kern table is empty.");+ }+ }++ public void parse_cmap_table (FontData dis) {+ if (cmap_table.has_data ()) {+ cmap_table.parse (dis);+ } else {+ warning ("Cmap table is empty.");+ }+ }++ public void parse_head_table (FontData dis) {+ if (head_table.has_data ()) {+ head_table.parse (dis);+ } else {+ warning ("Head table is empty.");+ }+ }+ public bool validate_tables (FontData dis, File file) { bool valid = true; @@ -14,7 +14,7 @@ namespace BirdFont { -class FontData : Object {+public class FontData : Object { // Read pointer uint rp = 0;@@ -14,7 +14,7 @@ namespace BirdFont { -class GaspTable : Table {+public class GaspTable : Table { public GaspTable () { id = "gasp";@@ -14,7 +14,7 @@ namespace BirdFont { -class GdefTable : Table {+public class GdefTable : Table { public GdefTable () { id = "GDEF";@@ -16,7 +16,7 @@ using Math; namespace BirdFont { -class Coordinate {+public class Coordinate { /** TTF coordinate flags. */ public static const uint8 NONE = 0;@@ -14,7 +14,7 @@ namespace BirdFont { -class GlyfTable : Table {+public class GlyfTable : Table { // Flags for composite glyph static const uint16 BOTH_ARE_WORDS = 1 << 0; static const uint16 BOTH_ARE_XY_VALUES = 1 << 1;@@ -15,12 +15,12 @@ using Math; namespace BirdFont { -class PairFormat1 : GLib.Object {+public class PairFormat1 : GLib.Object { public uint16 left = -1; public List<Kern> pairs = new List<Kern> (); } -class GposTable : Table {+public class GposTable : Table { GlyfTable glyf_table; List<Kern> kerning_pairs = new List<Kern> ();@@ -15,7 +15,7 @@ using Math; namespace BirdFont { -class GsubTable : Table {+public class GsubTable : Table { public GsubTable () { id = "GPOS";@@ -14,7 +14,7 @@ namespace BirdFont { -class HeadTable : Table {+public class HeadTable : Table { public int16 xmin = int16.MIN; public int16 ymin = int16.MIN;@@ -39,8 +39,7 @@ class HeadTable : Table { uint64 created; uint64 modified;- - // public static uint16 units_per_em = 4096; FIXME: windows testing+ public static uint16 units_per_em; public static double UNITS; @@ -57,14 +56,17 @@ class HeadTable : Table { /** Set default value for unit. */ public static void init () {- units_per_em = 1024; // FIXME:- UNITS = 10 * (units_per_em / 1000);+ units_per_em = 1024;+ UNITS = 10 * (units_per_em / 1000.0); } public uint32 get_adjusted_checksum () { return adjusted_checksum; } + /** Get the units per em for generated fonts, not for fonts parsed + * with this library.+ */ public double get_units_per_em () { return units_per_em * 10; }@@ -87,7 +89,7 @@ class HeadTable : Table { magic_number = dis.read_ulong (); if (magic_number != 0x5F0F3CF5) {- warning (@"Magic number is invalid. Got $(magic_number).");+ warning (@"Magic number is invalid ($(magic_number))."); return; } @@ -14,7 +14,7 @@ namespace BirdFont { -class HheaTable : Table {+public class HheaTable : Table { Fixed version; int16 ascender;@@ -14,7 +14,7 @@ namespace BirdFont { -class HmtxTable : Table {+public class HmtxTable : Table { uint32 nmetrics; uint32 nmonospaced;@@ -14,7 +14,7 @@ namespace BirdFont { -class Kern : GLib.Object {+public class Kern : GLib.Object { public uint16 left; public uint16 right; public int16 kerning;@@ -26,15 +26,7 @@ class Kern : GLib.Object { } } -class KernList : GLib.Object {- public List<Kern> kernings;- - public KernList () {- kernings = new List<Kern> ();- }-}--class KernTable : Table {+public class KernTable : Table { public static const uint16 HORIZONTAL = 1; public static const uint16 MINIMUM = 1 << 1;@@ -44,7 +36,7 @@ class KernTable : Table { GlyfTable glyf_table; - public List<Kern> kernings = new List<Kern> ();+ public List<Kern> kerning = new List<Kern> (); public int kerning_pairs = 0; public KernTable (GlyfTable gt) {@@ -92,14 +84,14 @@ class KernTable : Table { public void parse_pairs (FontData dis, uint16 n_pairs) throws Error { uint16 left; uint16 right;- int16 kerning;+ int16 k; for (int i = 0; i < n_pairs; i++) { left = dis.read_ushort (); right = dis.read_ushort ();- kerning = dis.read_short ();+ k = dis.read_short (); - kernings.append (new Kern (left, right, kerning));+ kerning.append (new Kern (left, right, k)); } } @@ -14,7 +14,7 @@ namespace BirdFont { -class LocaTable : Table {+public class LocaTable : Table { uint32* glyph_offsets = null; public uint32 size = 0;@@ -126,7 +126,6 @@ class LocaTable : Table { last = o; }- } else if (head_table.loca_offset_size == 1) { foreach (uint32 o in glyf_table.location_offsets) { fd.add_u32 (o);@@ -137,7 +136,6 @@ class LocaTable : Table { last = o; }- } else { warn_if_reached (); }@@ -14,7 +14,7 @@ namespace BirdFont { -class MaxpTable : Table {+public class MaxpTable : Table { GlyfTable glyf_table; @@ -14,7 +14,7 @@ namespace BirdFont { -class NameTable : Table {+public class NameTable : Table { public static const uint16 COPYRIGHT_NOTICE = 0; public static const uint16 FONT_NAME = 1;@@ -14,7 +14,7 @@ namespace BirdFont { -class OffsetTable : Table {+public class OffsetTable : Table { DirectoryTable directory_table; public uint16 num_tables = 0;@@ -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 @@ -22,7 +22,7 @@ namespace BirdFont { [SimpleType] [CCode (has_type_id = false)] // Vala bug-internal struct Fixed : uint32 {+public struct Fixed : uint32 { public bool @equals (uint16 upper, uint16 lower) { uint32 t = (upper << 16) + lower;@@ -37,16 +37,17 @@ internal struct Fixed : uint32 { [SimpleType] [CCode (has_type_id = false)] // same as above-internal struct F2Dot14 : uint32 {+public struct F2Dot14 : uint32 { } errordomain BadFormat { PARSE } -class OpenFontFormatReader : Object {+public class OpenFontFormatReader : Object { public DirectoryTable directory_table;+ public FontData font_data = new FontData (); OtfInputStream dis; File file;@@ -82,25 +83,44 @@ class OpenFontFormatReader : Object { void parse_index_tables () throws Error { OffsetTable offset_table;- FontData fd = new FontData (); FileInfo file_info = file.query_info ("*", FileQueryInfoFlags.NONE); uint32 file_size = (uint32) file_info.get_size (); try {- fd.write_table (dis, 0, file_size);+ font_data.write_table (dis, 0, file_size); } catch (GLib.Error e) { warning (@"Failed to read font data. $(e.message)"); } offset_table = new OffsetTable (directory_table);- offset_table.parse (fd);+ offset_table.parse (font_data); directory_table = new DirectoryTable (); directory_table.set_offset_table (offset_table);- directory_table.parse (fd, file, this);+ directory_table.parse (font_data, this); } + public void parse_all_tables () {+ directory_table.parse_all_tables (font_data, this);+ + if (!directory_table.validate_tables (font_data, file)) {+ warning ("Missing required table or bad checksum.");+ }+ }++ public void parse_kern_table () {+ directory_table.parse_kern_table (font_data);+ }++ public void parse_cmap_table () {+ directory_table.parse_cmap_table (font_data);+ }++ public void parse_head_table () {+ directory_table.parse_head_table (font_data);+ }+ public void set_limits () { Font f = OpenFontFormatWriter.font; @@ -126,5 +146,60 @@ class OpenFontFormatReader : Object { public uint32 get_head_checksum () { return directory_table.head_table.get_adjusted_checksum (); }+ + public static StringBuilder parse_kerning (string file_name) {+ KernTable kern_table;+ CmapTable cmap_table;+ HeadTable head_table;+ OpenFontFormatReader reader = new OpenFontFormatReader ();+ StringBuilder bf_kerning = new StringBuilder ();+ unichar left, right;+ double kerning, units_per_em;+ uint npairs = 0;+ uint i = 0;+ + try {+ reader.parse_index (file_name);+ reader.parse_kern_table ();+ reader.parse_cmap_table ();+ reader.parse_head_table ();+ + kern_table = reader.directory_table.kern_table;+ cmap_table = reader.directory_table.cmap_table;+ head_table = reader.directory_table.head_table;+ + npairs = kern_table.kerning.length ();+ + units_per_em = HeadTable.units_per_em;+ + foreach (Kern k in kern_table.kerning) {+ left = cmap_table.get_char (k.left);+ right = cmap_table.get_char (k.right);+ kerning = 100 * (k.kerning / units_per_em);+ + if (left <= 0x1F || right <= 0x1F) {+ warning ("Ignoring kerning of control character.");+ } else {+ bf_kerning.append ("<kerning left=\"");+ bf_kerning.append (BirdFontFile.serialize_unichar (left));+ bf_kerning.append ("\" ");+ bf_kerning.append ("right=\"");+ bf_kerning.append (BirdFontFile.serialize_unichar (right));+ bf_kerning.append ("\" ");+ bf_kerning.append ("hadjustment=\"");+ bf_kerning.append (@"$kerning".replace (",", "."));+ bf_kerning.append ("\" />\n");+ }+ + ++i;+ ProgressBar.set_progress ((npairs - i) / (double) npairs);+ Tool.yield ();+ }+ } catch (GLib.Error e) {+ warning (@"Failed to parse font. $(e.message)");+ }+ + return bf_kerning;+ } } }@@ -14,7 +14,7 @@ namespace BirdFont { -class OpenFontFormatWriter : Object {+public class OpenFontFormatWriter : Object { DataOutputStream os; DirectoryTable directory_table;@@ -14,7 +14,7 @@ namespace BirdFont { -class Os2Table : Table {+public class Os2Table : Table { public static const uint16 ITALIC = 1; public static const uint16 UNDERSCORE = 1 << 1;@@ -15,7 +15,7 @@ namespace BirdFont { /** Reader for otf data types. */-class OtfInputStream : Object {+public class OtfInputStream : Object { public FileInputStream fin; public DataInputStream din;@@ -14,7 +14,7 @@ namespace BirdFont { -class PostTable : Table {+public class PostTable : Table { GlyfTable glyf_table; @@ -15,7 +15,7 @@ namespace BirdFont { -class Table : Object {+public class Table : Object { public string id = "NO_ID"; @@ -573,53 +573,6 @@ FT_ULong get_charcode (FT_Face face, FT_UInt gid) { return 0; } -/** Obtain kerning data in .bf format for one glyph.- * @param gid glyph id- */-// FIXME:-GString* get_kerning_data (FT_Face face, FT_Long gid, double units) {- FT_Error error;- FT_Vector kerning;- GString* bf = g_string_new ("");- FT_ULong char_left;- FT_ULong char_right;- FT_Long right;- gchar kern[80];- - char_left = get_charcode (face, gid);- - if (char_left <= 31) {- g_warning ("Ignoring kerning for control character.\n");- return bf;- }- - if (char_left == 0) {- g_warning ("No character code could be found for left kerning value.\n");- return bf;- }- - for (right = 0; right < face->num_glyphs; right++) {- error = FT_Get_Kerning (face, gid, right, FT_KERNING_UNSCALED, &kerning);- if (error) {- g_warning ("Failed to obtain kerning value.\n");- break;- }- - char_right = get_charcode (face, right);- if (char_left == 0) {- g_warning ("No character code could be found for right kerning value.\n");- return bf;- }-- if (kerning.x != 0 && char_left > 31 && char_right > 31) {- g_ascii_formatd (&kern, 80, "%f", kerning.x * units);- g_string_append_printf (bf, "<kerning left=\"U+%x\" right=\"U+%x\" hadjustment=\"%s\"/>\n", char_left, char_right, kern);- }- }- - return bf;-}- /** Height of letter. */ int get_height (FT_Face face, guint unichar) { int error;@@ -703,7 +656,7 @@ void append_description (GString* str, FT_SfntName* name_table_data) { GString* get_bf_font (FT_Face face, char* file, int* err) { GString* bf = g_string_new (""); GString* bf_data;- GString* hkern;+ GString* kerning; GString* glyph; FT_Error error; FT_Long i;@@ -803,20 +756,13 @@ GString* get_bf_font (FT_Face face, char* file, int* err) { } g_string_append (bf, glyph->str);- g_string_free (glyph, 0); + g_string_free (glyph, 0); bird_font_progress_bar_set_progress ((double)i / face->num_glyphs); }-- // kerning- // FIXME- /*- for (i = 0; i < face->num_glyphs; i++) {- hkern = get_kerning_data (face, i, units);- g_string_append (bf, hkern->str);- g_string_free (hkern, 0);- bird_font_progress_bar_set_progress ((double)(face->num_glyphs - i) / face->num_glyphs);- }- */+ + kerning = bird_font_open_font_format_reader_parse_kerning (file); + g_string_append (bf, kerning->str);+ g_string_free (kerning, 0); g_string_append (bf, "</font>\n");