Clone in a terminal:
Commit 6a22eaa
Johan Mattsson - 2013-02-18T07:25:34+00:00
6a22eaa333b237dbec3fa5bf5119ac9dcd5a37fbjohan.mattsson.m@gmail.com

cff table

Changed files (2)

Diff

diff --git a/libbirdfont/OpenFontFormatWriter.vala b/libbirdfont/OpenFontFormatWriter.valaindex d2f3d90..0329de0 100644--- a/libbirdfont/OpenFontFormatWriter.vala+++ b/libbirdfont/OpenFontFormatWriter.vala@@ -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 () {
diff --git a/libbirdfont/TestCases.vala b/libbirdfont/TestCases.valaindex 91f871c..06317cf 100644--- a/libbirdfont/TestCases.vala+++ b/libbirdfont/TestCases.vala@@ -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"); 		

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112