Commit 6a22eaa
cff table
Changed files (2)
Diff
@@ -228,6 +228,18 @@ class FontData : Object { rp = i; wp = i; } + + public void seek_relative (uint i) { + rp += i; + wp += i; + } + + /** Returns true if next byte is a CFF operator */ + public bool next_is_operator () { + uint8 o = read (); + seek_relative (-1); + return (0 <= o <=21); + } public uint8 read () { if (unlikely (rp >= len)) { @@ -302,6 +314,44 @@ class FontData : Object { public char read_char () throws Error { return (char) read_byte (); } + + public string read_string (uint length) throws Error { + StringBuilder str = new StringBuilder (); + char c; + for (int i = 0; i < length; i++) { + c = read_char (); + str.append_c (c); + } + return str.str; + } + + public int read_charstring_value () throws Error { + uint8 a, b; + a = read (); + + if (32 <= a <= 246) { + return a - 139; + } + + b = read (); + + if (247 <= a <= 250) { + return (a - 247) * 256 + b + 108; + } + + if (251 <= a <= 254) { + return -((a - 251) * 256) - b - 108; + } + + if (a == 255) { + // Implement it + warning ("fractions not implemented yet."); + } + + stderr.printf (@"unexpected value: $a\n"); + warn_if_reached (); + return 0; + } public void add_fixed (Fixed f) throws Error { add_u32 (f); @@ -426,6 +476,40 @@ class FontData : Object { requires (s.length == 4 && s.data.length == 4) { add_str (s); } + + public void add_charstring_value (int v) throws Error { + int w; + uint8 t; + + if (unlikely (!(-1131 <= v <= 1131))) { + warning ("charstring value out of range"); + v = 0; + } + + if (-107 <= v <= 107) { + add_byte ((uint8) (v + 139)); + } else if (107 < v <= 1131) { + // positive value + w = v; + v -= 108; + + t = 0; + while (v >= 256) { + v -= 256; + t++; + } + + add_byte (t + 247); + add_byte ((uint8) (w - 108 - (t * 256))); + } else if (-1131 <= v < -107) { + // negative value + v = -v - 108; + add_byte ((uint8) ((v >> 8) + 251)); + add_byte ((uint8) (v & 0xFF)); + } else { + // Todo add fraction + } + } } class Coordinate { @@ -4058,6 +4142,192 @@ class PostTable : Table { } +/** Type2, PostScript outlines */ +class CffTable : Table { + + static const uint8 HSTEM = 1; + static const uint8 VSTEM = 3; + static const uint8 VMOVETO = 4; + static const uint8 HLINETO = 6; + static const uint8 VLINETO = 7; + static const uint8 ENDCHAR = 14; + static const uint8 HMOVETO = 22; + static const uint8 RMOVETO = 21; + + static const uint8 CHARSET = 15; + static const uint8 ENCODING = 16; + + static const uint8 VERSION = 0; + + public int version; + + FontData dis; + + public CffTable () { + id = "CFF "; + } + + uint32 read_offset (uint size) throws GLib.Error { + switch (size) { + case 0: + warning ("offset size is zero"); + return dis.read_byte (); + case 1: + return dis.read_byte (); + case 2: + return dis.read_ushort (); + case 4: + return dis.read_ulong (); + default: + warn_if_reached (); + break; + } + + warning ("offset size is zero"); + return 0; + } + + List<uint32> read_index () { + uint32 offset_size, off; + int entries, len; + string data; + List<uint32> offsets = new List<uint32> (); + + entries = dis.read_ushort (); + printd (@"number of entries $(entries)\n"); + + if (entries == 0) { + printd ("skip index"); + return offsets; + } + + offset_size = dis.read (); + printd (@"Offset size $(offset_size)\n"); + + // read the end offset as well + for (int i = 0; i <= entries; i++) { + off = read_offset (offset_size); + printd (@"offset $(off)\n"); + offsets.append (off); + } + + return offsets; + } + + public override void parse (FontData dis) throws Error { + uint v1, v2, offset_size, entries, header_size, len; + string data; + List<uint32> offsets, dict_index; + int id, val; + int off; // offset relative to table position + + dis.seek (offset); + this.dis = dis; + + printd ("Parse CFF.\n"); + v1 = dis.read (); + v2 = dis.read (); + printd (@"Version $v1.$v2\n"); + header_size = dis.read (); + printd (@"Header size $(header_size)\n"); + offset_size = dis.read (); + printd (@"Offset size $(offset_size)\n"); + + // name index + offsets = read_index (); + + // name data + for (int i = 0; i < offsets.length () - 1; i++) { + off = (int) offsets.nth (i).data; + len = offsets.nth (i + 1).data - off; + //dis.seek (offset + off + header_size); + data = dis.read_string (len); + print (@"Found name $data\n"); + } + + // dict index + print (@"dict index\n"); + dict_index = read_index (); + + // dict data + id = 0; + val = 0; + for (int i = 0; i < dict_index.length () - 1; i++) { + off = (int) offsets.nth (i).data; + len = dict_index.nth (i + 1).data - dict_index.nth (i).data; + //dis.seek (offset + off + header_size); + + //for (int j = 0; j < len; j++) { + + if (dis.next_is_operator ()) { + id = dis.read (); + + if (id == 12) { + id = dis.read (); + } else { + switch (id) { + case 0: + version = val; + break; + default: + stderr.printf ("unknown operator"); + break; + } + } + } else { + val = dis.read_charstring_value (); + } + + printd (@"$i: id $(id)\n"); + printd (@"val $(val)\n"); + //printd (@"B $(dis.read ())\n"); + //} + } + + // string index + read_index (); + } + + public void process () throws GLib.Error { + FontData fd = new FontData (); + string name = "typeface"; + uint8 dict_length; + + // header + fd.add_byte (1); // format version (1.0) + fd.add_byte (0); + + fd.add_byte (4); // header size + fd.add_byte (2); // offset field size - ushort + + // name index: + fd.add_ushort (1); // number of entries + fd.add_byte (2); // offset field size + fd.add_ushort (1); // offset + fd.add ((uint8) name.length); // length of string + fd.add_str (name); + + // top dict index + fd.add_ushort (1); // number of entries + fd.add_byte (2); // offset field size + fd.add_ushort (1); // offset + fd.add_ushort (2); // offset + + fd.add_charstring_value (0); + fd.add_byte (CHARSET); + + // string index + fd.add_byte (0); + + // TODO: glyph gid to cid map + fd.add_byte (0); + + fd.pad (); + + this.font_data = fd; + } +} + class GaspTable : Table { public GaspTable () { @@ -626,7 +626,8 @@ class TestCases { public static void test_data_reader () { FontData fd = new FontData (); uint len;-+ int v;+ try { fd.add (7); fd.add_ulong (0x5F0F3CF5);@@ -654,11 +655,25 @@ class TestCases { len = fd.length (); fd.add (0); warn_if_fail (len + 1 == fd.length ());+ + fd.seek_end ();+ for (int i = -1131; i < 1131; i++) {+ fd.add_charstring_value (i);+ }++ for (int i = -1131; i < 1131; i++) {+ v = fd.read_charstring_value ();+ if (v != i) {+ warning (@"expecting $i got $v\n");+ }+ }+ } catch (GLib.Error e) { warning (e.message); } } + public static void test_argument () { Argument arg = new Argument ("supplement -t \"Argument list\" --unknown -unknown --help -s");