From be4809ca0d146d5ed34f683938e44f50997f21a1 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 17 Aug 2013 11:40:00 -0400 Subject: [PATCH 01/18] Initial sketch --- pyfontview.py | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100755 pyfontview.py diff --git a/pyfontview.py b/pyfontview.py new file mode 100755 index 000000000..ad2a9e654 --- /dev/null +++ b/pyfontview.py @@ -0,0 +1,121 @@ +#!/usr/bin/python + +import pygtk +pygtk.require('2.0') +import gtk + +import fontTools.ttx + +class FontTreeStoreBuilder: + + def __init__(self, treestore): + self.ts = treestore + + def add_object(self, parent, key, value): + # Make sure item is decompiled + try: + getattr(value, "asdf") + except AttributeError: + pass + if hasattr(value, "expand"): + # Glyph type needs explicit expanding to be useful + value.expand(self.font['glyf']) + + item = self.ts.append(parent, [key, '%s' % value.__class__.__name__]) + for k,v in sorted(value.__dict__.items()): + self.add_thing (item, k, v) + + def add_dict(self, parent, key, value): + item = self.ts.append(parent, [key, '%s of %d items' % + (value.__class__.__name__, len(value))]) + for k,v in sorted(value.items()): + self.add_thing (item, k, v) + + def add_list(self, parent, key, value): + item = self.ts.append(parent, [key, '%s of %d items' % + (value.__class__.__name__, len(value))]) + for k,v in enumerate(value): + self.add_thing (item, k, v) + + def add_thing(self, parent, key, value): + if value == self.font: + return + if key == 'reader': + return + if hasattr(value, '__dict__'): + self.add_object(parent, key, value) + return + if hasattr(value, 'items'): + self.add_dict(parent, key, value) + return + if not isinstance(value, basestring): + # Sequences + try: + len(value) + iter(value) + self.add_list(parent, key, value) + return + except TypeError: + pass + except AttributeError: + pass + except KeyError: + pass + + # Everything else + item = self.ts.append(parent, [key, value]) + + def add_font(self, font): + self.font = font + for tag in font.keys(): + self.add_thing (None, tag, font[tag]) + self.font = None + +class PyFontView: + + def delete_event(self, widget, event, data=None): + gtk.main_quit() + return False + + def __init__(self): + + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.set_title("PyFontView") + self.window.connect("delete_event", self.delete_event) + self.window.set_size_request(400, 600) + + self.scrolled_window = gtk.ScrolledWindow() + self.window.add(self.scrolled_window) + + self.treestore = gtk.TreeStore(str, str) + self.treeview = gtk.TreeView(self.treestore) + #self.treeview.set_reorderable(True) + + font = fontTools.ttx.TTFont("abc.woff") + font = fontTools.ttx.TTFont("IranNastaliq2.ttf") + builder = FontTreeStoreBuilder(self.treestore) + builder.add_font (font) + + for i in range(2): + + col = gtk.TreeViewColumn('Column %d' % i) + + self.treeview.append_column(col) + + cell = gtk.CellRendererText() + col.pack_start(cell, True) + + col.add_attribute(cell, 'text', i) + + self.treeview.set_search_column(i) + col.set_sort_column_id(i) + + self.scrolled_window.add(self.treeview) + self.window.show_all() + +def main(): + gtk.main() + +if __name__ == "__main__": + viewer = PyFontView() + main() From f5d67a06de8ba2329d6ab001083687c3c9543e16 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 17 Aug 2013 12:19:05 -0400 Subject: [PATCH 02/18] Minor --- pyfontview.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index ad2a9e654..77142130a 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -17,7 +17,7 @@ class FontTreeStoreBuilder: getattr(value, "asdf") except AttributeError: pass - if hasattr(value, "expand"): + if value.__class__ == fontTools.ttLib.getTableModule('glyf').Glyph: # Glyph type needs explicit expanding to be useful value.expand(self.font['glyf']) @@ -92,7 +92,7 @@ class PyFontView: #self.treeview.set_reorderable(True) font = fontTools.ttx.TTFont("abc.woff") - font = fontTools.ttx.TTFont("IranNastaliq2.ttf") + #font = fontTools.ttx.TTFont("IranNastaliq2.ttf") builder = FontTreeStoreBuilder(self.treestore) builder.add_font (font) From 70132794228e89082e94efbd35a4e2ded8b5d3e5 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 17 Aug 2013 12:31:27 -0400 Subject: [PATCH 03/18] Improve handling of sequence types --- pyfontview.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index 77142130a..85cc03719 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -42,17 +42,14 @@ class FontTreeStoreBuilder: return if key == 'reader': return - if hasattr(value, '__dict__'): - self.add_object(parent, key, value) - return - if hasattr(value, 'items'): - self.add_dict(parent, key, value) - return if not isinstance(value, basestring): # Sequences try: len(value) iter(value) + # It's hard to differentiate list-type sequences + # from dict-type ones. Try fetching item 0. + value[0] self.add_list(parent, key, value) return except TypeError: @@ -61,6 +58,14 @@ class FontTreeStoreBuilder: pass except KeyError: pass + except IndexError: + pass + if hasattr(value, '__dict__'): + self.add_object(parent, key, value) + return + if hasattr(value, 'items'): + self.add_dict(parent, key, value) + return # Everything else item = self.ts.append(parent, [key, value]) From 8d0272aec8e7041066ed010c739b65c6c0d6f8d4 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 17 Aug 2013 12:31:52 -0400 Subject: [PATCH 04/18] Don't show protected members --- pyfontview.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyfontview.py b/pyfontview.py index 85cc03719..7e5aa573d 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -23,6 +23,8 @@ class FontTreeStoreBuilder: item = self.ts.append(parent, [key, '%s' % value.__class__.__name__]) for k,v in sorted(value.__dict__.items()): + if k[0] == '_': + continue self.add_thing (item, k, v) def add_dict(self, parent, key, value): From 051ec0c1a41415818cb6f5083f072e7734f223ef Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 17 Aug 2013 12:49:56 -0400 Subject: [PATCH 05/18] Smarter way to write out short sequences --- pyfontview.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index 7e5aa573d..3420110cd 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -34,8 +34,10 @@ class FontTreeStoreBuilder: self.add_thing (item, k, v) def add_list(self, parent, key, value): - item = self.ts.append(parent, [key, '%s of %d items' % - (value.__class__.__name__, len(value))]) + name = '%s of %d items' % (value.__class__.__name__, len(value)) + if len(value) and len(value) <= 32: + name = str(value) + item = self.ts.append(parent, [key, name]) for k,v in enumerate(value): self.add_thing (item, k, v) From aa55d75547ec285e10177e14fe2b5adfdc3adde4 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 17 Aug 2013 12:50:18 -0400 Subject: [PATCH 06/18] Wrap strings in quotes --- pyfontview.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyfontview.py b/pyfontview.py index 3420110cd..f1281140a 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -71,6 +71,10 @@ class FontTreeStoreBuilder: self.add_dict(parent, key, value) return + if isinstance(value, basestring): + item = self.ts.append(parent, [key, '"'+value+'"']) + return + # Everything else item = self.ts.append(parent, [key, value]) From 78b7494271b30b6369ac46ed07fddba4a7694476 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 17 Aug 2013 13:08:33 -0400 Subject: [PATCH 07/18] Improve sequence handling --- pyfontview.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index f1281140a..94305e675 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -48,22 +48,24 @@ class FontTreeStoreBuilder: return if not isinstance(value, basestring): # Sequences + is_sequence = True try: len(value) iter(value) # It's hard to differentiate list-type sequences # from dict-type ones. Try fetching item 0. value[0] + except TypeError: + is_sequence = False + except AttributeError: + is_sequence = False + except KeyError: + is_sequence = False + except IndexError: + is_sequence = False + if is_sequence: self.add_list(parent, key, value) return - except TypeError: - pass - except AttributeError: - pass - except KeyError: - pass - except IndexError: - pass if hasattr(value, '__dict__'): self.add_object(parent, key, value) return From 112d17e49b3548ae632262d4dda433ae2fa6f22f Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 17 Aug 2013 13:21:41 -0400 Subject: [PATCH 08/18] Minor --- pyfontview.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index 94305e675..e1228af40 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -28,8 +28,8 @@ class FontTreeStoreBuilder: self.add_thing (item, k, v) def add_dict(self, parent, key, value): - item = self.ts.append(parent, [key, '%s of %d items' % - (value.__class__.__name__, len(value))]) + name = '%s of %d items' % (value.__class__.__name__, len(value)) + item = self.ts.append(parent, [key, name]) for k,v in sorted(value.items()): self.add_thing (item, k, v) From aa736d8a7bb6841057e6299b0cd27f1300fed1ff Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 17 Aug 2013 13:21:47 -0400 Subject: [PATCH 09/18] Expand CFF Index tables --- pyfontview.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pyfontview.py b/pyfontview.py index e1228af40..582b986cb 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -5,6 +5,8 @@ pygtk.require('2.0') import gtk import fontTools.ttx +import fontTools.ttLib +import fontTools.cffLib class FontTreeStoreBuilder: @@ -17,9 +19,13 @@ class FontTreeStoreBuilder: getattr(value, "asdf") except AttributeError: pass - if value.__class__ == fontTools.ttLib.getTableModule('glyf').Glyph: + if isinstance(value, fontTools.ttLib.getTableModule('glyf').Glyph): # Glyph type needs explicit expanding to be useful value.expand(self.font['glyf']) + if isinstance(value, fontTools.cffLib.Index): + # Load all items + for i in range(len(value)): + value[i] item = self.ts.append(parent, [key, '%s' % value.__class__.__name__]) for k,v in sorted(value.__dict__.items()): From 9c64ded292f795523943453dccc61850fe773a26 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 17 Aug 2013 13:40:12 -0400 Subject: [PATCH 10/18] Minor --- pyfontview.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index 582b986cb..83c541100 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -25,7 +25,10 @@ class FontTreeStoreBuilder: if isinstance(value, fontTools.cffLib.Index): # Load all items for i in range(len(value)): - value[i] + print value[i] + # Discard offsets as should not be needed anymore + if hasattr(value, 'offsets'): + del value.offsets item = self.ts.append(parent, [key, '%s' % value.__class__.__name__]) for k,v in sorted(value.__dict__.items()): @@ -50,7 +53,7 @@ class FontTreeStoreBuilder: def add_thing(self, parent, key, value): if value == self.font: return - if key == 'reader': + if key in ['reader', 'file', 'tableTag', 'compileStatus', 'recurse']: return if not isinstance(value, basestring): # Sequences @@ -109,14 +112,17 @@ class PyFontView: self.window.add(self.scrolled_window) self.treestore = gtk.TreeStore(str, str) - self.treeview = gtk.TreeView(self.treestore) - #self.treeview.set_reorderable(True) font = fontTools.ttx.TTFont("abc.woff") #font = fontTools.ttx.TTFont("IranNastaliq2.ttf") + #font = fontTools.ttx.TTFont("KozGoPr6N-Medium.otf") + #font = fontTools.ttx.TTFont("SmaGoSS07262013-Book.otf") builder = FontTreeStoreBuilder(self.treestore) builder.add_font (font) + self.treeview = gtk.TreeView(self.treestore) + #self.treeview.set_reorderable(True) + for i in range(2): col = gtk.TreeViewColumn('Column %d' % i) From 1d6e7264fcac2701ebab9ca3f40a0f04372aefa6 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 18 Aug 2013 16:08:44 -0400 Subject: [PATCH 11/18] Rewrite using custom treemodel Fixes performance issue. --- pyfontview.py | 288 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 204 insertions(+), 84 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index 83c541100..a3fdc581d 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -3,6 +3,7 @@ import pygtk pygtk.require('2.0') import gtk +import sys import fontTools.ttx import fontTools.ttLib @@ -13,50 +14,20 @@ class FontTreeStoreBuilder: def __init__(self, treestore): self.ts = treestore - def add_object(self, parent, key, value): - # Make sure item is decompiled - try: - getattr(value, "asdf") - except AttributeError: - pass - if isinstance(value, fontTools.ttLib.getTableModule('glyf').Glyph): - # Glyph type needs explicit expanding to be useful - value.expand(self.font['glyf']) - if isinstance(value, fontTools.cffLib.Index): - # Load all items - for i in range(len(value)): - print value[i] - # Discard offsets as should not be needed anymore - if hasattr(value, 'offsets'): - del value.offsets - item = self.ts.append(parent, [key, '%s' % value.__class__.__name__]) - for k,v in sorted(value.__dict__.items()): - if k[0] == '_': - continue - self.add_thing (item, k, v) +class Row(object): + def __init__(self, parent, index, key, value): + self._parent = parent + self._index = index + self._key = key + self._value = value - def add_dict(self, parent, key, value): - name = '%s of %d items' % (value.__class__.__name__, len(value)) - item = self.ts.append(parent, [key, name]) - for k,v in sorted(value.items()): - self.add_thing (item, k, v) - - def add_list(self, parent, key, value): - name = '%s of %d items' % (value.__class__.__name__, len(value)) - if len(value) and len(value) <= 32: - name = str(value) - item = self.ts.append(parent, [key, name]) - for k,v in enumerate(value): - self.add_thing (item, k, v) - - def add_thing(self, parent, key, value): - if value == self.font: - return - if key in ['reader', 'file', 'tableTag', 'compileStatus', 'recurse']: + if isinstance(value, fontTools.ttx.TTFont): + self._add_font(value) return + if not isinstance(value, basestring): - # Sequences + # Try sequences is_sequence = True try: len(value) @@ -73,76 +44,225 @@ class FontTreeStoreBuilder: except IndexError: is_sequence = False if is_sequence: - self.add_list(parent, key, value) + self._add_list(key, value) return if hasattr(value, '__dict__'): - self.add_object(parent, key, value) + self._add_object(key, value) return if hasattr(value, 'items'): - self.add_dict(parent, key, value) + self._add_dict(key, value) return if isinstance(value, basestring): - item = self.ts.append(parent, [key, '"'+value+'"']) + self._value_str = '"'+value+'"' + self._children = [] return # Everything else - item = self.ts.append(parent, [key, value]) + self._children = [] - def add_font(self, font): + def _filter_items(self): + items = [] + for k,v in self._items: + if isinstance(v, fontTools.ttx.TTFont): + continue + if k in ['reader', 'file', 'tableTag', 'compileStatus', 'recurse']: + continue + if isinstance(k, basestring) and k[0] == '_': + continue + items.append((k,v)) + self._items = items + + def _add_font(self, font): + self._items = [(tag,font[tag]) for tag in font.keys()] + + def _add_object(self, key, value): + # Make sure item is decompiled + try: + getattr(value, "asdf") + except AttributeError: + pass + if isinstance(value, fontTools.ttLib.getTableModule('glyf').Glyph): + # Glyph type needs explicit expanding to be useful + value.expand(self.font['glyf']) + if isinstance(value, fontTools.cffLib.Index): + # Load all items + for i in range(len(value)): + value[i] + # Discard offsets as should not be needed anymore + if hasattr(value, 'offsets'): + del value.offsets + + self._value_str = value.__class__.__name__ + self._items = sorted(value.__dict__.items()) + self._filter_items() + + def _add_dict(self, key, value): + self._value_str = '%s of %d items' % (value.__class__.__name__, len(value)) + self._items = sorted(value.items()) + self._filter_items() + + def _add_list(self, key, value): + if len(value) and len(value) <= 32: + self._value_str = str(value) + else: + self._value_str = '%s of %d items' % (value.__class__.__name__, + len(value)) + self._items = enumerate(value) + self._filter_items() + + def __len__(self): + self._ensure_children() + return len(self._children) + + def get_parent(self): + return self._parent + + def _ensure_children(self): + if hasattr(self, '_children'): + return + children = [] + for i,(k,v) in enumerate(self._items): + children.append(Row(self, i, k, v)) + self._children = children + del self._items + + def get_children(self): + self._ensure_children() + return self._children + + def get_children(self): + self._ensure_children() + return self._children + + def get_nth_child(self, n): + self._ensure_children() + if n < len(self._children): + return self._children[n] + else: + return None + + def get_key(self): + return self._key + + def get_value(self): + return self._value + + def get_value_str(self): + if hasattr(self, '_value_str'): + return self._value_str + return str(self._value) + + def get_iter(self, path): + if not path: + return self + return self.get_nth_child(path[0]).get_iter(path[1:]) + + def iter_next(self): + if not self._parent: + return None + return self._parent.get_nth_child(self._index + 1) + + def get_path(self): + if not self._parent: return () + return self._parent.get_path() + (self._index,) + +class FontTreeModel(gtk.GenericTreeModel): + + __gtype_name__ = 'FontTreeModel' + + def __init__(self, font): + super(FontTreeModel, self).__init__() + self._columns = (str, str) self.font = font - for tag in font.keys(): - self.add_thing (None, tag, font[tag]) - self.font = None + self._root = Row(None, 0, "font", font) + + def on_get_flags(self): + return 0 + + def on_get_n_columns(self): + return len(self._columns) + + def on_get_column_type(self, index): + return self._columns[index] + + def on_get_iter(self, path): + return self._root.get_iter(path) + + def on_get_path(self, rowref): + return rowref.get_path() + + def on_get_value(self, rowref, column): + if column == 0: + return rowref.get_key() + else: + return rowref.get_value_str() + + def on_iter_next(self, rowref): + return rowref.iter_next() + + def on_iter_children(self, rowref): + return rowref.get_nth_child(0) + + def on_iter_has_child(self, rowref): + return bool(len(rowref)) + + def on_iter_n_children(self, rowref): + return len(rowref) + + def on_iter_nth_child(self, rowref, n): + if not rowref: rowref = self._root + return rowref.get_nth_child(n) + + def on_iter_parent(self, rowref): + return rowref.get_parent() class PyFontView: - def delete_event(self, widget, event, data=None): - gtk.main_quit() - return False + def delete_event(self, widget, event, data=None): + gtk.main_quit() + return False - def __init__(self): + def __init__(self, fontfile): - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.set_title("PyFontView") - self.window.connect("delete_event", self.delete_event) - self.window.set_size_request(400, 600) + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.set_title("%s - PyFontView" % fontfile) + self.window.connect("delete_event", self.delete_event) + self.window.set_size_request(400, 600) - self.scrolled_window = gtk.ScrolledWindow() - self.window.add(self.scrolled_window) + self.scrolled_window = gtk.ScrolledWindow() + self.window.add(self.scrolled_window) - self.treestore = gtk.TreeStore(str, str) + self.font = fontTools.ttx.TTFont(fontfile) + self.treemodel = FontTreeModel(self.font) + self.treeview = gtk.TreeView(self.treemodel) + #self.treeview.set_reorderable(True) - font = fontTools.ttx.TTFont("abc.woff") - #font = fontTools.ttx.TTFont("IranNastaliq2.ttf") - #font = fontTools.ttx.TTFont("KozGoPr6N-Medium.otf") - #font = fontTools.ttx.TTFont("SmaGoSS07262013-Book.otf") - builder = FontTreeStoreBuilder(self.treestore) - builder.add_font (font) + for i in range(2): - self.treeview = gtk.TreeView(self.treestore) - #self.treeview.set_reorderable(True) + col = gtk.TreeViewColumn('Column %d' % i) - for i in range(2): + self.treeview.append_column(col) - col = gtk.TreeViewColumn('Column %d' % i) + cell = gtk.CellRendererText() + col.pack_start(cell, True) - self.treeview.append_column(col) + col.add_attribute(cell, 'text', i) - cell = gtk.CellRendererText() - col.pack_start(cell, True) + col.set_sort_column_id(i) - col.add_attribute(cell, 'text', i) + self.treeview.set_search_column(1) + self.scrolled_window.add(self.treeview) + self.window.show_all() - self.treeview.set_search_column(i) - col.set_sort_column_id(i) - - self.scrolled_window.add(self.treeview) - self.window.show_all() - -def main(): - gtk.main() +def main(args=None): + if args == None: args = sys.argv + if len(args) < 2: + print >>sys.stderr, "usage: %s font..." % args[0] + sys.exit(1) + for arg in args[1:]: + viewer = PyFontView(arg) + gtk.main() if __name__ == "__main__": - viewer = PyFontView() - main() + main() From e33143139f8117ce8b9d75909d9e61b8dcd54945 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 18 Aug 2013 16:40:18 -0400 Subject: [PATCH 12/18] Expand BaseDicts --- pyfontview.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyfontview.py b/pyfontview.py index a3fdc581d..a4865e1e1 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -85,6 +85,9 @@ class Row(object): if isinstance(value, fontTools.ttLib.getTableModule('glyf').Glyph): # Glyph type needs explicit expanding to be useful value.expand(self.font['glyf']) + if isinstance(value, fontTools.cffLib.BaseDict): + for k in value.rawDict.keys(): + getattr(value, k) if isinstance(value, fontTools.cffLib.Index): # Load all items for i in range(len(value)): From 453ceedc8a3814ddb7b4487f77d1b096de6bbcbd Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 18 Aug 2013 16:53:57 -0400 Subject: [PATCH 13/18] Decompile T2CharStrings --- pyfontview.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyfontview.py b/pyfontview.py index a4865e1e1..ba0bf9921 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -85,6 +85,11 @@ class Row(object): if isinstance(value, fontTools.ttLib.getTableModule('glyf').Glyph): # Glyph type needs explicit expanding to be useful value.expand(self.font['glyf']) + if isinstance(value, fontTools.misc.psCharStrings.T2CharString): + try: + value.decompile() + except TypeError: # Subroutines can't be decompiled + pass if isinstance(value, fontTools.cffLib.BaseDict): for k in value.rawDict.keys(): getattr(value, k) From 8a407591f3dcd07fc981eafcdd0f56afec1c4e26 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 18 Aug 2013 16:54:44 -0400 Subject: [PATCH 14/18] Minor --- pyfontview.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index ba0bf9921..6e4441a8f 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -9,11 +9,6 @@ import fontTools.ttx import fontTools.ttLib import fontTools.cffLib -class FontTreeStoreBuilder: - - def __init__(self, treestore): - self.ts = treestore - class Row(object): def __init__(self, parent, index, key, value): From 62d1d24a14e0cc744842aa60eeac484abfee52b7 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 18 Aug 2013 17:04:59 -0400 Subject: [PATCH 15/18] Simplify things a bit --- pyfontview.py | 54 +++++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index 6e4441a8f..5fc9f7325 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -118,9 +118,6 @@ class Row(object): self._ensure_children() return len(self._children) - def get_parent(self): - return self._parent - def _ensure_children(self): if hasattr(self, '_children'): return @@ -130,21 +127,19 @@ class Row(object): self._children = children del self._items - def get_children(self): - self._ensure_children() - return self._children - - def get_children(self): - self._ensure_children() - return self._children - - def get_nth_child(self, n): + def __getitem__(self, n): self._ensure_children() if n < len(self._children): return self._children[n] else: return None + def get_parent(self): + return self._parent + + def get_index(self): + return self._index + def get_key(self): return self._key @@ -152,24 +147,10 @@ class Row(object): return self._value def get_value_str(self): - if hasattr(self, '_value_str'): + if hasattr(self,'_value_str'): return self._value_str return str(self._value) - def get_iter(self, path): - if not path: - return self - return self.get_nth_child(path[0]).get_iter(path[1:]) - - def iter_next(self): - if not self._parent: - return None - return self._parent.get_nth_child(self._index + 1) - - def get_path(self): - if not self._parent: return () - return self._parent.get_path() + (self._index,) - class FontTreeModel(gtk.GenericTreeModel): __gtype_name__ = 'FontTreeModel' @@ -190,10 +171,19 @@ class FontTreeModel(gtk.GenericTreeModel): return self._columns[index] def on_get_iter(self, path): - return self._root.get_iter(path) + rowref = self._root + while path: + rowref = rowref[path[0]] + path = path[1:] + return rowref def on_get_path(self, rowref): - return rowref.get_path() + path = [] + while rowref != self._root: + path.append(rowref.get_index()) + rowref = rowref.get_parent() + path.reverse() + return tuple(path) def on_get_value(self, rowref, column): if column == 0: @@ -202,10 +192,10 @@ class FontTreeModel(gtk.GenericTreeModel): return rowref.get_value_str() def on_iter_next(self, rowref): - return rowref.iter_next() + return rowref.get_parent()[rowref.get_index() + 1] def on_iter_children(self, rowref): - return rowref.get_nth_child(0) + return rowref[0] def on_iter_has_child(self, rowref): return bool(len(rowref)) @@ -215,7 +205,7 @@ class FontTreeModel(gtk.GenericTreeModel): def on_iter_nth_child(self, rowref, n): if not rowref: rowref = self._root - return rowref.get_nth_child(n) + return rowref[n] def on_iter_parent(self, rowref): return rowref.get_parent() From 8623d02c7cc46a273ef8a966b627af791488a01e Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 18 Aug 2013 17:19:13 -0400 Subject: [PATCH 16/18] Make things a bit lazier --- pyfontview.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index 5fc9f7325..50693c4fd 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -103,7 +103,6 @@ class Row(object): def _add_dict(self, key, value): self._value_str = '%s of %d items' % (value.__class__.__name__, len(value)) self._items = sorted(value.items()) - self._filter_items() def _add_list(self, key, value): if len(value) and len(value) <= 32: @@ -111,12 +110,14 @@ class Row(object): else: self._value_str = '%s of %d items' % (value.__class__.__name__, len(value)) - self._items = enumerate(value) - self._filter_items() + self._items = list(enumerate(value)) def __len__(self): - self._ensure_children() - return len(self._children) + if hasattr(self, '_children'): + return len(self._children) + if hasattr(self, '_items'): + return len(self._items) + assert 0 def _ensure_children(self): if hasattr(self, '_children'): @@ -128,11 +129,16 @@ class Row(object): del self._items def __getitem__(self, n): - self._ensure_children() - if n < len(self._children): - return self._children[n] - else: + if n >= len(self): return None + if not hasattr(self, '_children'): + self._children = [None] * len(self) + c = self._children[n] + if c is None: + k,v = self._items[n] + c = self._children[n] = Row(self, n, k, v) + self._items[n] = None + return c def get_parent(self): return self._parent From 75858f653ac9122cdb02375597bdeb8e0a9ed857 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 19 Aug 2013 13:01:45 -0400 Subject: [PATCH 17/18] Minor --- pyfontview.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index 50693c4fd..462915bba 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -1,5 +1,24 @@ #!/usr/bin/python +# Copyright 2013 Google, Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0(the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Google Author(s): Behdad Esfahbod + +"""Python Font Viewer. +""" + import pygtk pygtk.require('2.0') import gtk @@ -218,7 +237,7 @@ class FontTreeModel(gtk.GenericTreeModel): class PyFontView: - def delete_event(self, widget, event, data=None): + def _delete_event(self, widget, event, data=None): gtk.main_quit() return False @@ -226,7 +245,7 @@ class PyFontView: self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.set_title("%s - PyFontView" % fontfile) - self.window.connect("delete_event", self.delete_event) + self.window.connect("delete_event", self._delete_event) self.window.set_size_request(400, 600) self.scrolled_window = gtk.ScrolledWindow() From d711d4bf71c668df5527099e7ec9cba3b41fc76b Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 19 Aug 2013 14:46:08 -0400 Subject: [PATCH 18/18] Cleanup imports --- pyfontview.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pyfontview.py b/pyfontview.py index 462915bba..272e95cc6 100755 --- a/pyfontview.py +++ b/pyfontview.py @@ -24,7 +24,6 @@ pygtk.require('2.0') import gtk import sys -import fontTools.ttx import fontTools.ttLib import fontTools.cffLib @@ -36,7 +35,7 @@ class Row(object): self._key = key self._value = value - if isinstance(value, fontTools.ttx.TTFont): + if isinstance(value, fontTools.ttLib.TTFont): self._add_font(value) return @@ -78,7 +77,7 @@ class Row(object): def _filter_items(self): items = [] for k,v in self._items: - if isinstance(v, fontTools.ttx.TTFont): + if isinstance(v, fontTools.ttLib.TTFont): continue if k in ['reader', 'file', 'tableTag', 'compileStatus', 'recurse']: continue @@ -251,7 +250,7 @@ class PyFontView: self.scrolled_window = gtk.ScrolledWindow() self.window.add(self.scrolled_window) - self.font = fontTools.ttx.TTFont(fontfile) + self.font = fontTools.ttLib.TTFont(fontfile) self.treemodel = FontTreeModel(self.font) self.treeview = gtk.TreeView(self.treemodel) #self.treeview.set_reorderable(True)