From 0b27e2eda226e2fb208f7efaef6e3a34cea5b959 Mon Sep 17 00:00:00 2001 From: JCorson Date: Sun, 8 Sep 2019 20:04:30 -0500 Subject: [PATCH 01/19] FIX: No bare exceptions --- kiva/fonttools/font_manager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index c5832dedc..2f20c4f0b 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -220,7 +220,7 @@ def is_string_like(obj): return False try: obj + '' - except: + except Exception: return False return True @@ -528,11 +528,11 @@ def ttfFontProperty(fpath, font): try: sfnt2 = props[(1, 0, 0, 2)] - except: + except Exception: sfnt2 = None try: sfnt4 = props[(1, 0, 0, 4)] - except: + except Exception: sfnt4 = None if sfnt2: sfnt2 = sfnt2.lower().decode() @@ -685,7 +685,7 @@ def createFontList(fontfiles, fontext='ttf'): if fontext == 'afm': try: fh = open(fpath, 'r') - except: + except Exception: logger.error( "Could not open font file %s", fpath, exc_info=True) continue @@ -1444,7 +1444,7 @@ def findfont(prop, fontext='ttf'): else: fontManager.default_size = None logger.debug("Using fontManager instance from %s", _fmcache) - except: + except Exception: _rebuild() def findfont(prop, **kw): From 5b82bb9f479fec7cb8b6547777266f089b64c145 Mon Sep 17 00:00:00 2001 From: JCorson Date: Sun, 8 Sep 2019 20:04:47 -0500 Subject: [PATCH 02/19] FLK: Extra blank line --- kiva/fonttools/font_manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index 2f20c4f0b..9af8b6e48 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -665,6 +665,7 @@ def afmFontProperty(fontpath, font): return FontEntry(fontpath, name, style, variant, weight, stretch, size) + def createFontList(fontfiles, fontext='ttf'): """ A function to create a font lookup list. The default is to create From a03e5eec4bdf74c7e1c47bb4cd55b922aeb8d6d3 Mon Sep 17 00:00:00 2001 From: JCorson Date: Sun, 8 Sep 2019 20:05:03 -0500 Subject: [PATCH 03/19] FLK: Better variable name --- kiva/fonttools/font_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index 9af8b6e48..f3aa9446a 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -842,8 +842,8 @@ def __init__(self, family=None, style=None, variant=None, weight=None, self.set_size(size) def __hash__(self): - l = [(k, getattr(self, "get" + k)()) for k in sorted(self.__dict__)] - return hash(repr(l)) + lst = [(k, getattr(self, "get" + k)()) for k in sorted(self.__dict__)] + return hash(repr(lst)) def __str__(self): return str((self._family, self._slant, self._variant, From 2f3680b369f33123d4b996d2f4352db40fc8bab2 Mon Sep 17 00:00:00 2001 From: JCorson Date: Sun, 8 Sep 2019 20:05:30 -0500 Subject: [PATCH 04/19] FLK: Extra blank line TST: Add test font file from matplotlib --- .../tests/data/matplotlib_LICENSE.txt | 99 ++++++++++++++++++ kiva/fonttools/tests/data/mpltest.ttf | Bin 0 -> 2264 bytes kiva/fonttools/tests/data/source.txt | 2 + kiva/fonttools/tests/test_font_manager.py | 1 + 4 files changed, 102 insertions(+) create mode 100644 kiva/fonttools/tests/data/matplotlib_LICENSE.txt create mode 100644 kiva/fonttools/tests/data/mpltest.ttf diff --git a/kiva/fonttools/tests/data/matplotlib_LICENSE.txt b/kiva/fonttools/tests/data/matplotlib_LICENSE.txt new file mode 100644 index 000000000..0752df48e --- /dev/null +++ b/kiva/fonttools/tests/data/matplotlib_LICENSE.txt @@ -0,0 +1,99 @@ +License agreement for matplotlib versions 1.3.0 and later +========================================================= + +1. This LICENSE AGREEMENT is between the Matplotlib Development Team +("MDT"), and the Individual or Organization ("Licensee") accessing and +otherwise using matplotlib software in source or binary form and its +associated documentation. + +2. Subject to the terms and conditions of this License Agreement, MDT +hereby grants Licensee a nonexclusive, royalty-free, world-wide license +to reproduce, analyze, test, perform and/or display publicly, prepare +derivative works, distribute, and otherwise use matplotlib +alone or in any derivative version, provided, however, that MDT's +License Agreement and MDT's notice of copyright, i.e., "Copyright (c) +2012- Matplotlib Development Team; All Rights Reserved" are retained in +matplotlib alone or in any derivative version prepared by +Licensee. + +3. In the event Licensee prepares a derivative work that is based on or +incorporates matplotlib or any part thereof, and wants to +make the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to matplotlib . + +4. MDT is making matplotlib available to Licensee on an "AS +IS" basis. MDT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, MDT MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB +WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR +LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING +MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF +THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between MDT and +Licensee. This License Agreement does not grant permission to use MDT +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using matplotlib , +Licensee agrees to be bound by the terms and conditions of this License +Agreement. + +License agreement for matplotlib versions prior to 1.3.0 +======================================================== + +1. This LICENSE AGREEMENT is between John D. Hunter ("JDH"), and the +Individual or Organization ("Licensee") accessing and otherwise using +matplotlib software in source or binary form and its associated +documentation. + +2. Subject to the terms and conditions of this License Agreement, JDH +hereby grants Licensee a nonexclusive, royalty-free, world-wide license +to reproduce, analyze, test, perform and/or display publicly, prepare +derivative works, distribute, and otherwise use matplotlib +alone or in any derivative version, provided, however, that JDH's +License Agreement and JDH's notice of copyright, i.e., "Copyright (c) +2002-2011 John D. Hunter; All Rights Reserved" are retained in +matplotlib alone or in any derivative version prepared by +Licensee. + +3. In the event Licensee prepares a derivative work that is based on or +incorporates matplotlib or any part thereof, and wants to +make the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to matplotlib. + +4. JDH is making matplotlib available to Licensee on an "AS +IS" basis. JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB +WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR +LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING +MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF +THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between JDH and +Licensee. This License Agreement does not grant permission to use JDH +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using matplotlib, +Licensee agrees to be bound by the terms and conditions of this License +Agreement. diff --git a/kiva/fonttools/tests/data/mpltest.ttf b/kiva/fonttools/tests/data/mpltest.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b8133a6c7baf8e5359c5c431a23c21c42304b254 GIT binary patch literal 2264 zcmd5;O>C4!7=C7UySuGesI4uDO_*(=TL|oK7uZT|B0p`_R-y#c5HN*p_iJ}$|J?mr z=tU8|)HKn92@w*LHmSz=6Ix6FF~)e1A_qO_1&n$?LmKgf9;)5-nc1&ZOpvSJ?99CH z^Zw2|GvBum0IG2UE*$CUd1h~H;M+Lh`-EuYV_n@nXvcc;Z;)?&YJVtl;QZiKKqSZ? z8A``;?z+lF@;|cg9vZV1{Bj&{(FX33SRq#`(KCFLQ5%DSbTBz z;|9upVUH#Vc)oVsqD1hpkR zm1S4Pa)kt*9`26gGwedQOO+nRL6eEeNh`_MI4B5a#>|;JSHyl1Q#g#XIHMt_H=2Ba zP9j_p8sVlTi^Zn-ZtfMZt5hm|?r1`IRsun1xl$35=FxWddR*=bkM~|m|7*E9)7WI% zP7L4`ypJ!KvD7seo8)O$)QjM(K&W%h>&C6ftf%6;&N-JPiCLG1D>OXk^@u+^=UB>H zk*ziUn!whYX1}PsdHJ$Dy)^8XJf@O+H{*IlzHNL$_-p*S%TJ58m|Xfpo?LoCb{FTx zn@c6?PGMADk?%74YUWc{ABk>jX_DKbk@`AMlZf^vdV3Q;Oy8KEz9GKK@7tH(S6p0} znOT_8aSr2zJkQhQMeX0VBH#^)_CQ1XI^h*h1fqdJRQS$~cP#(J^{!B;D^$F;Vd8`3 zAAOxg*7dCX3HNDVBG4WZ-avzQooIKjiK_ZF9wpyu>3e=dU(Srhlk=i+e!h4^Y)|#q zAMJn8jLpJx;X-lofkKitotr z(b1wcJ#9`;H9lNEx0n)L4lUpnzdJN9nOx=2E;P$S4(*1Q_o#f9E3ighbZ8IpYx=gh zc{jywMk&(*)#7J|mRKc<4(&pZtaWHNs^yCgT>&LeIkboPm)L_mEW}`Qj6-1%;~aaD z#V9gJlJ4VsLt#JVIkp&4i(TOur8W|zdZ?Wtt>-*OC|7*P1rg@lN)4MWhYp0;h8O9)*dozDR9(l*DH=2z5nujrybv^d-7Jyw&H4VT=iy0GfCAKRQs)5E|#$}>R8fF zsGe-b?#bpyEENfcRcpewa~+}3FwtR+1`ET%jAd`Es#+ z3>1{MQA63xn3XRivzg5*l^n7%1x6pu#I5|D%8raFrdj{gO7)P=rL=couUUDLD^HWL z;>l6YdK>SyogJp=|8%Cfv3k3AU<qek oeuJdZt|q@$hcrBIF;TbS%H9NN$M2PiY@24TF1+_pdA`)}7cyOpk^lez literal 0 HcmV?d00001 diff --git a/kiva/fonttools/tests/data/source.txt b/kiva/fonttools/tests/data/source.txt index c6eb3f304..5c6bc26d8 100644 --- a/kiva/fonttools/tests/data/source.txt +++ b/kiva/fonttools/tests/data/source.txt @@ -1,8 +1,10 @@ Project License File ---------------------------------------------------------------------------- fonttools MIT fonttools_LICENSE.txt +matplotlib PSF matplotlib_LICENSE.txt Files and orginal authors: ---------------------------------------------------------------------------- kiva/fonttools/tests/data: TestTTC.ttc | fonttools + mpltest.ttf | matplotlib diff --git a/kiva/fonttools/tests/test_font_manager.py b/kiva/fonttools/tests/test_font_manager.py index c180e51c9..93d148970 100644 --- a/kiva/fonttools/tests/test_font_manager.py +++ b/kiva/fonttools/tests/test_font_manager.py @@ -11,6 +11,7 @@ data_dir = resource_filename('kiva.fonttools.tests', 'data') + class TestCreateFontList(unittest.TestCase): def setUp(self): From f9597f64571ad47fb3b59425028145cd4da68f02 Mon Sep 17 00:00:00 2001 From: JCorson Date: Mon, 9 Sep 2019 09:27:00 -0500 Subject: [PATCH 05/19] TST: Use test font from fonttools --- kiva/fonttools/tests/data/TestTTF.ttf | Bin 0 -> 2336 bytes .../tests/data/matplotlib_LICENSE.txt | 99 ------------------ kiva/fonttools/tests/data/mpltest.ttf | Bin 2264 -> 0 bytes kiva/fonttools/tests/data/source.txt | 3 +- 4 files changed, 1 insertion(+), 101 deletions(-) create mode 100644 kiva/fonttools/tests/data/TestTTF.ttf delete mode 100644 kiva/fonttools/tests/data/matplotlib_LICENSE.txt delete mode 100644 kiva/fonttools/tests/data/mpltest.ttf diff --git a/kiva/fonttools/tests/data/TestTTF.ttf b/kiva/fonttools/tests/data/TestTTF.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e906d012d1b62d6dd9019d1c7513e369a1ea4d06 GIT binary patch literal 2336 zcmeHJPly{;82{dzY%+1-CMG;I?DuetShD3bOIW>&X+mvlOScqz!KdTXV2sK}lmis_IW4cn^f{ZsD)|Bn8o zRK!c{CYHj79&NOPe&Stv9r8Dj_qUviMbFb2$Cl(;@bq!U-y}I|}PG%}*r+z)ti=5V(HMH0#Zv(JdPlr)`$)M%AjC zHLwjN+kfCjfVKcEBJ2H7vSGEM?P09KuY}nTqnCj5RD@ioE}~fQ+8a5C zD7)84-H6kW18n6pS~bjbY*(g{RYsRQ1R_Yr9mJ7)x6lJHvcTG=cF67m zbPm-p?&WFxg-)JgfK&A;M<$*+as)WrF3!=w**b`80^874!%QZk56?EhJUrX~CW_3{ zLc}sM%H7C!Am59Le*#N*`-^yg%NPyl`{+BrF@q1)Zy;2EYH@sYIMZC4!7=C7UySuGesI4uDO_*(=TL|oK7uZT|B0p`_R-y#c5HN*p_iJ}$|J?mr z=tU8|)HKn92@w*LHmSz=6Ix6FF~)e1A_qO_1&n$?LmKgf9;)5-nc1&ZOpvSJ?99CH z^Zw2|GvBum0IG2UE*$CUd1h~H;M+Lh`-EuYV_n@nXvcc;Z;)?&YJVtl;QZiKKqSZ? z8A``;?z+lF@;|cg9vZV1{Bj&{(FX33SRq#`(KCFLQ5%DSbTBz z;|9upVUH#Vc)oVsqD1hpkR zm1S4Pa)kt*9`26gGwedQOO+nRL6eEeNh`_MI4B5a#>|;JSHyl1Q#g#XIHMt_H=2Ba zP9j_p8sVlTi^Zn-ZtfMZt5hm|?r1`IRsun1xl$35=FxWddR*=bkM~|m|7*E9)7WI% zP7L4`ypJ!KvD7seo8)O$)QjM(K&W%h>&C6ftf%6;&N-JPiCLG1D>OXk^@u+^=UB>H zk*ziUn!whYX1}PsdHJ$Dy)^8XJf@O+H{*IlzHNL$_-p*S%TJ58m|Xfpo?LoCb{FTx zn@c6?PGMADk?%74YUWc{ABk>jX_DKbk@`AMlZf^vdV3Q;Oy8KEz9GKK@7tH(S6p0} znOT_8aSr2zJkQhQMeX0VBH#^)_CQ1XI^h*h1fqdJRQS$~cP#(J^{!B;D^$F;Vd8`3 zAAOxg*7dCX3HNDVBG4WZ-avzQooIKjiK_ZF9wpyu>3e=dU(Srhlk=i+e!h4^Y)|#q zAMJn8jLpJx;X-lofkKitotr z(b1wcJ#9`;H9lNEx0n)L4lUpnzdJN9nOx=2E;P$S4(*1Q_o#f9E3ighbZ8IpYx=gh zc{jywMk&(*)#7J|mRKc<4(&pZtaWHNs^yCgT>&LeIkboPm)L_mEW}`Qj6-1%;~aaD z#V9gJlJ4VsLt#JVIkp&4i(TOur8W|zdZ?Wtt>-*OC|7*P1rg@lN)4MWhYp0;h8O9)*dozDR9(l*DH=2z5nujrybv^d-7Jyw&H4VT=iy0GfCAKRQs)5E|#$}>R8fF zsGe-b?#bpyEENfcRcpewa~+}3FwtR+1`ET%jAd`Es#+ z3>1{MQA63xn3XRivzg5*l^n7%1x6pu#I5|D%8raFrdj{gO7)P=rL=couUUDLD^HWL z;>l6YdK>SyogJp=|8%Cfv3k3AU<qek oeuJdZt|q@$hcrBIF;TbS%H9NN$M2PiY@24TF1+_pdA`)}7cyOpk^lez diff --git a/kiva/fonttools/tests/data/source.txt b/kiva/fonttools/tests/data/source.txt index 5c6bc26d8..fd25162a4 100644 --- a/kiva/fonttools/tests/data/source.txt +++ b/kiva/fonttools/tests/data/source.txt @@ -1,10 +1,9 @@ Project License File ---------------------------------------------------------------------------- fonttools MIT fonttools_LICENSE.txt -matplotlib PSF matplotlib_LICENSE.txt Files and orginal authors: ---------------------------------------------------------------------------- kiva/fonttools/tests/data: TestTTC.ttc | fonttools - mpltest.ttf | matplotlib + TestTTF.ttf | fonttools From 1546790a7e071dd63a6bb63ad578284addd7e4bf Mon Sep 17 00:00:00 2001 From: JCorson Date: Mon, 9 Sep 2019 13:46:49 -0500 Subject: [PATCH 06/19] TST: Add test for ttfFontProperty FIX: Correct test method name --- kiva/fonttools/font_manager.py | 35 +++++++++++------------ kiva/fonttools/tests/test_font_manager.py | 26 +++++++++++++++++ 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index f3aa9446a..e62490809 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -229,8 +229,13 @@ def getPropDict(font): n = font['name'] propdict = {} for prop in n.names: - prop_key = (prop.platformID, prop.platEncID, prop.langID, prop.nameID) - propdict[prop_key] = prop.string + if prop.nameID == 1 and 'name' not in propdict: + propdict['name'] = prop.string + elif prop.nameID == 2 and 'sfnt2' not in propdict: + propdict['sfnt2'] = prop.string + elif prop.nameID == 4 and 'sfnt4' not in propdict: + propdict['sfnt4'] = prop.string + return propdict @@ -522,25 +527,19 @@ def ttfFontProperty(fpath, font): *font* is a :class:`FT2Font` instance. """ props = getPropDict(font) - name = props[(1, 0, 0, 1)].decode() + name = props.get('name', b'') + name = decode_prop(name) # Styles are: italic, oblique, and normal (default) - - try: - sfnt2 = props[(1, 0, 0, 2)] - except Exception: - sfnt2 = None + sfnt2 = props.get('sfnt2', b'') try: - sfnt4 = props[(1, 0, 0, 4)] - except Exception: - sfnt4 = None - if sfnt2: - sfnt2 = sfnt2.lower().decode() - else: + sfnt2 = decode_prop(sfnt2) + except UnicodeDecodeError: sfnt2 = '' - if sfnt4: - sfnt4 = sfnt4.lower().decode() - else: + sfnt4 = props.get('sfnt4', b'') + try: + sfnt4 = decode_prop(sfnt4) + except UnicodeDecodeError: sfnt4 = '' if sfnt4.find('oblique') >= 0: style = 'oblique' @@ -865,7 +864,7 @@ def get_name(self): return afm.AFM(open(filename)).get_familyname() font = fontManager.findfont(self) - return getPropDict(TTFont(str(font)))[(1, 0, 0, 1)] + return getPropDict(TTFont(str(font)))['name'] def get_style(self): """ diff --git a/kiva/fonttools/tests/test_font_manager.py b/kiva/fonttools/tests/test_font_manager.py index 93d148970..d6a554d6c 100644 --- a/kiva/fonttools/tests/test_font_manager.py +++ b/kiva/fonttools/tests/test_font_manager.py @@ -45,3 +45,29 @@ def test_ttc_exception_on_TTCollection(self, m_TTCollection): # Then self.assertEqual(len(fontlist), 0) self.assertEqual(m_TTCollection.call_count, 1) + + +class TestTTFFontProperty(unittest.TestCase): + + def test_font(self): + # Given + reg_font = os.path.join(data_dir, "TestTTF.ttf") + exp_name = "Test TTF" + exp_style = "normal" + exp_variant = "normal" + exp_weight = 400 + exp_stretch = "normal" + exp_size = "scalable" + + # When + entry = ttfFontProperty(reg_font, TTFont(reg_font)) + + # Then + self.assertEqual(entry.name, exp_name) + self.assertEqual(entry.style, exp_style) + self.assertEqual(entry.variant, exp_variant) + self.assertEqual(entry.weight, exp_weight) + self.assertEqual(entry.stretch, exp_stretch) + self.assertEqual(entry.size, exp_size) + + From 2f45c8b1b06620f60b29e33d9a9e7aba7d10a4ed Mon Sep 17 00:00:00 2001 From: JCorson Date: Tue, 10 Sep 2019 21:26:28 -0500 Subject: [PATCH 07/19] FIX: Simplify decoding of font props FIX: Add missing imports --- kiva/fonttools/font_manager.py | 18 +++++------------- kiva/fonttools/tests/test_font_manager.py | 5 ++++- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index e62490809..75e5ebcbd 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -527,20 +527,12 @@ def ttfFontProperty(fpath, font): *font* is a :class:`FT2Font` instance. """ props = getPropDict(font) - name = props.get('name', b'') - name = decode_prop(name) + name = props.get('name', b'').decode() # Styles are: italic, oblique, and normal (default) - sfnt2 = props.get('sfnt2', b'') - try: - sfnt2 = decode_prop(sfnt2) - except UnicodeDecodeError: - sfnt2 = '' - sfnt4 = props.get('sfnt4', b'') - try: - sfnt4 = decode_prop(sfnt4) - except UnicodeDecodeError: - sfnt4 = '' + sfnt2 = props.get('sfnt2', b'').decode() + sfnt4 = props.get('sfnt4', b'').decode() + if sfnt4.find('oblique') >= 0: style = 'oblique' elif sfnt4.find('italic') >= 0: @@ -864,7 +856,7 @@ def get_name(self): return afm.AFM(open(filename)).get_familyname() font = fontManager.findfont(self) - return getPropDict(TTFont(str(font)))['name'] + return getPropDict(TTFont(str(font)))['name'].decode() def get_style(self): """ diff --git a/kiva/fonttools/tests/test_font_manager.py b/kiva/fonttools/tests/test_font_manager.py index d6a554d6c..74db669bd 100644 --- a/kiva/fonttools/tests/test_font_manager.py +++ b/kiva/fonttools/tests/test_font_manager.py @@ -6,8 +6,9 @@ import mock from pkg_resources import resource_filename +from fontTools.ttLib import TTFont -from ..font_manager import FontEntry, createFontList +from ..font_manager import FontEntry, createFontList, ttfFontProperty data_dir = resource_filename('kiva.fonttools.tests', 'data') @@ -71,3 +72,5 @@ def test_font(self): self.assertEqual(entry.size, exp_size) +if __name__ == "__main__": + unittest.main() From ffa41328a80dcd5e6218570b303fcb7a92af3176 Mon Sep 17 00:00:00 2001 From: JCorson Date: Tue, 10 Sep 2019 21:27:52 -0500 Subject: [PATCH 08/19] FIX: Include ttf files in manifest --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index addf07e4b..0f7ee62a0 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -10,4 +10,4 @@ include docs/kiva/agg/notes recursive-include docs *.py *.rst *.txt *.css *.png *.ico *.doc recursive-include examples *.py *.txt *.gif *.jpg *.enaml recursive-include kiva/quartz *.pyx *.pxi *.pxd mac_context*.* -recursive-include kiva/fonttools/tests/data *.txt *.ttc +recursive-include kiva/fonttools/tests/data *.txt *.ttc *.ttf From 80f93bc115e3bf8870ba536b3c06a27f69e0e169 Mon Sep 17 00:00:00 2001 From: JCorson Date: Tue, 10 Sep 2019 21:34:19 -0500 Subject: [PATCH 09/19] REF: Remove unneeded sfnt2 item --- kiva/fonttools/font_manager.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index 75e5ebcbd..e0168d118 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -231,8 +231,6 @@ def getPropDict(font): for prop in n.names: if prop.nameID == 1 and 'name' not in propdict: propdict['name'] = prop.string - elif prop.nameID == 2 and 'sfnt2' not in propdict: - propdict['sfnt2'] = prop.string elif prop.nameID == 4 and 'sfnt4' not in propdict: propdict['sfnt4'] = prop.string @@ -530,15 +528,12 @@ def ttfFontProperty(fpath, font): name = props.get('name', b'').decode() # Styles are: italic, oblique, and normal (default) - sfnt2 = props.get('sfnt2', b'').decode() sfnt4 = props.get('sfnt4', b'').decode() if sfnt4.find('oblique') >= 0: style = 'oblique' elif sfnt4.find('italic') >= 0: style = 'italic' - elif sfnt2.find('regular') >= 0: - style = 'normal' else: style = 'normal' From f20e62ecc792c0dfaa7770b7b45093ed95fec823 Mon Sep 17 00:00:00 2001 From: JCorson Date: Wed, 11 Sep 2019 08:31:16 -0500 Subject: [PATCH 10/19] ENH: Break if both name and sfnt4 are found --- kiva/fonttools/font_manager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index e0168d118..1871e93cc 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -229,7 +229,9 @@ def getPropDict(font): n = font['name'] propdict = {} for prop in n.names: - if prop.nameID == 1 and 'name' not in propdict: + if 'name' in propdict and 'sfnt4' in propdict: + break + elif prop.nameID == 1 and 'name' not in propdict: propdict['name'] = prop.string elif prop.nameID == 4 and 'sfnt4' not in propdict: propdict['sfnt4'] = prop.string From aa8d6536112db144c263b0d2021bc5f7e7e951d9 Mon Sep 17 00:00:00 2001 From: JCorson Date: Sun, 15 Sep 2019 20:44:36 -0500 Subject: [PATCH 11/19] ENH: Add function to handle utf-16 encoded font files FIX: Remove __main__ block --- kiva/fonttools/font_manager.py | 37 ++++++++++++++++++++--- kiva/fonttools/tests/test_font_manager.py | 4 --- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index 1871e93cc..de54ec6c1 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -225,6 +225,23 @@ def is_string_like(obj): return True +def decode_prop(prop): + """ Decode a prop string + + Parameters + ---------- + prop : bytestring + + Returns + ------- + string + """ + # Adpated from: https://gist.github.com/pklaus/dce37521579513c574d0 + encoding = "utf-16-be" if b"\x00" in prop else "utf-8" + + return prop.decode(encoding) + + def getPropDict(font): n = font['name'] propdict = {} @@ -232,7 +249,13 @@ def getPropDict(font): if 'name' in propdict and 'sfnt4' in propdict: break elif prop.nameID == 1 and 'name' not in propdict: - propdict['name'] = prop.string + name = prop.string + try: + # Ensure that the name can be decoded + decode_prop(name) + propdict['name'] = name + except UnicodeDecodeError: + continue elif prop.nameID == 4 and 'sfnt4' not in propdict: propdict['sfnt4'] = prop.string @@ -527,10 +550,16 @@ def ttfFontProperty(fpath, font): *font* is a :class:`FT2Font` instance. """ props = getPropDict(font) - name = props.get('name', b'').decode() + name = props.get('name') + if name is None: + raise KeyError("No name could be found for: {}".format(fpath)) + name = decode_prop(props['name']) # Styles are: italic, oblique, and normal (default) - sfnt4 = props.get('sfnt4', b'').decode() + try: + sfnt4 = decode_prop(props.get('sfnt4', b'')) + except UnicodeDecodeError: + sfnt4 = "" if sfnt4.find('oblique') >= 0: style = 'oblique' @@ -853,7 +882,7 @@ def get_name(self): return afm.AFM(open(filename)).get_familyname() font = fontManager.findfont(self) - return getPropDict(TTFont(str(font)))['name'].decode() + return decode_prop(getPropDict(TTFont(str(font))['name'])) def get_style(self): """ diff --git a/kiva/fonttools/tests/test_font_manager.py b/kiva/fonttools/tests/test_font_manager.py index 74db669bd..215703a0c 100644 --- a/kiva/fonttools/tests/test_font_manager.py +++ b/kiva/fonttools/tests/test_font_manager.py @@ -70,7 +70,3 @@ def test_font(self): self.assertEqual(entry.weight, exp_weight) self.assertEqual(entry.stretch, exp_stretch) self.assertEqual(entry.size, exp_size) - - -if __name__ == "__main__": - unittest.main() From 1ebffacbfda32b92edd7415154648bff7b94267d Mon Sep 17 00:00:00 2001 From: JCorson Date: Mon, 16 Sep 2019 08:40:37 -0500 Subject: [PATCH 12/19] REF: Decode prop when getting prop dictionary --- kiva/fonttools/font_manager.py | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index de54ec6c1..88770496f 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -246,18 +246,15 @@ def getPropDict(font): n = font['name'] propdict = {} for prop in n.names: - if 'name' in propdict and 'sfnt4' in propdict: - break - elif prop.nameID == 1 and 'name' not in propdict: - name = prop.string - try: - # Ensure that the name can be decoded - decode_prop(name) - propdict['name'] = name - except UnicodeDecodeError: - continue - elif prop.nameID == 4 and 'sfnt4' not in propdict: - propdict['sfnt4'] = prop.string + try: + if 'name' in propdict and 'sfnt4' in propdict: + break + elif prop.nameID == 1 and 'name' not in propdict: + propdict['name'] = decode_prop(prop.string) + elif prop.nameID == 4 and 'sfnt4' not in propdict: + propdict['sfnt4'] = decode_prop(prop.string) + except UnicodeDecodeError: + continue return propdict @@ -553,13 +550,9 @@ def ttfFontProperty(fpath, font): name = props.get('name') if name is None: raise KeyError("No name could be found for: {}".format(fpath)) - name = decode_prop(props['name']) # Styles are: italic, oblique, and normal (default) - try: - sfnt4 = decode_prop(props.get('sfnt4', b'')) - except UnicodeDecodeError: - sfnt4 = "" + sfnt4 = decode_prop(props.get('sfnt4', '')) if sfnt4.find('oblique') >= 0: style = 'oblique' @@ -882,7 +875,7 @@ def get_name(self): return afm.AFM(open(filename)).get_familyname() font = fontManager.findfont(self) - return decode_prop(getPropDict(TTFont(str(font))['name'])) + return getPropDict(TTFont(str(font))['name']) def get_style(self): """ From 2a17793664a7ab9c8e3ac7a6f8ea0e32a318fd3f Mon Sep 17 00:00:00 2001 From: JCorson Date: Sat, 21 Sep 2019 20:20:12 -0500 Subject: [PATCH 13/19] FIX: Typo --- kiva/fonttools/font_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index 88770496f..bf3ac5186 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -226,7 +226,7 @@ def is_string_like(obj): def decode_prop(prop): - """ Decode a prop string + """ Decode a prop string. Parameters ---------- @@ -236,7 +236,7 @@ def decode_prop(prop): ------- string """ - # Adpated from: https://gist.github.com/pklaus/dce37521579513c574d0 + # Adapted from: https://gist.github.com/pklaus/dce37521579513c574d0 encoding = "utf-16-be" if b"\x00" in prop else "utf-8" return prop.decode(encoding) From 6150fafd562d75e38d6efc67ad6a8d48728b2799 Mon Sep 17 00:00:00 2001 From: JCorson Date: Sat, 21 Sep 2019 20:26:27 -0500 Subject: [PATCH 14/19] FIX: Better variable name --- kiva/fonttools/tests/test_font_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kiva/fonttools/tests/test_font_manager.py b/kiva/fonttools/tests/test_font_manager.py index 215703a0c..25d984916 100644 --- a/kiva/fonttools/tests/test_font_manager.py +++ b/kiva/fonttools/tests/test_font_manager.py @@ -52,7 +52,7 @@ class TestTTFFontProperty(unittest.TestCase): def test_font(self): # Given - reg_font = os.path.join(data_dir, "TestTTF.ttf") + test_font = os.path.join(data_dir, "TestTTF.ttf") exp_name = "Test TTF" exp_style = "normal" exp_variant = "normal" @@ -61,7 +61,7 @@ def test_font(self): exp_size = "scalable" # When - entry = ttfFontProperty(reg_font, TTFont(reg_font)) + entry = ttfFontProperty(test_font, TTFont(test_font)) # Then self.assertEqual(entry.name, exp_name) From f7547614218e33fe2a3ae884bcc1d03a267b9b30 Mon Sep 17 00:00:00 2001 From: JCorson Date: Sat, 21 Sep 2019 20:41:09 -0500 Subject: [PATCH 15/19] FIX: Don't decode sfnt4 again --- kiva/fonttools/font_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index bf3ac5186..401edde25 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -552,7 +552,7 @@ def ttfFontProperty(fpath, font): raise KeyError("No name could be found for: {}".format(fpath)) # Styles are: italic, oblique, and normal (default) - sfnt4 = decode_prop(props.get('sfnt4', '')) + sfnt4 = props.get('sfnt4', '') if sfnt4.find('oblique') >= 0: style = 'oblique' From 35444a46bdf70d0b7153b02cded00ca7b9d34840 Mon Sep 17 00:00:00 2001 From: JCorson Date: Sun, 22 Sep 2019 20:18:21 -0500 Subject: [PATCH 16/19] FIX: Include ttf file in egg --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 3a4a9af97..c7c032a29 100644 --- a/setup.py +++ b/setup.py @@ -288,6 +288,7 @@ def run(self): 'enable.savage.trait_defs.ui.wx': ['data/*.svg'], 'kiva': ['tests/agg/doubleprom_soho_full.jpg', 'fonttools/tests/data/*.ttc', + 'fonttools/tests/data/*.ttf', 'fonttools/tests/data/*.txt'], }, platforms=["Windows", "Linux", "Mac OS-X", "Unix", "Solaris"], From f73dfba5599d5b547c77d1c6eb4dc6400665099e Mon Sep 17 00:00:00 2001 From: JCorson Date: Tue, 24 Sep 2019 11:01:47 -0500 Subject: [PATCH 17/19] FIX: Use six.texttype when converting to strings. --- kiva/fonttools/font_manager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index 401edde25..4a2717e0c 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -721,7 +721,7 @@ def createFontList(fontfiles, fontext='ttf'): _, ext = os.path.splitext(fpath) try: if ext.lower() == ".ttc": - collection = TTCollection(str(fpath)) + collection = TTCollection(six.text_type(fpath)) try: props = [] for font in collection.fonts: @@ -735,7 +735,7 @@ def createFontList(fontfiles, fontext='ttf'): ) continue else: - font = TTFont(str(fpath)) + font = TTFont(six.text_type(fpath)) except (RuntimeError, TTLibError): logger.error( "Could not open font file %s", fpath, exc_info=True) @@ -870,12 +870,12 @@ def get_name(self): Return the name of the font that best matches the font properties. """ - filename = str(fontManager.findfont(self)) + filename = six.text_type(fontManager.findfont(self)) if filename.endswith('.afm'): return afm.AFM(open(filename)).get_familyname() font = fontManager.findfont(self) - return getPropDict(TTFont(str(font))['name']) + return getPropDict(TTFont(six.text_type(font))['name']) def get_style(self): """ @@ -1099,7 +1099,7 @@ def __init__(self, size=None, weight='normal'): else: paths.append(ttfpath) - logger.debug("font search path %s", str(paths)) + logger.debug("font search path %s", six.text_type(paths)) # Load TrueType fonts and create font dictionary. self.ttffiles = findSystemFonts(paths) + findSystemFonts() From 841fbcb83d2db1dae802e4753d4028ea1ee30bfc Mon Sep 17 00:00:00 2001 From: JCorson Date: Tue, 24 Sep 2019 11:40:52 -0500 Subject: [PATCH 18/19] FIX: Get 'name' from prop dict, not TTFont. --- kiva/fonttools/font_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index 4a2717e0c..0235b942c 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -875,7 +875,7 @@ def get_name(self): return afm.AFM(open(filename)).get_familyname() font = fontManager.findfont(self) - return getPropDict(TTFont(six.text_type(font))['name']) + return getPropDict(TTFont(six.text_type(font)))['name'] def get_style(self): """ From 893273adcff7dfe135c6bf6e235f632a204ba4aa Mon Sep 17 00:00:00 2001 From: JCorson Date: Tue, 24 Sep 2019 12:15:28 -0500 Subject: [PATCH 19/19] FIX: Make getting name prop more readable --- kiva/fonttools/font_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kiva/fonttools/font_manager.py b/kiva/fonttools/font_manager.py index 0235b942c..e62e85f5b 100644 --- a/kiva/fonttools/font_manager.py +++ b/kiva/fonttools/font_manager.py @@ -875,7 +875,8 @@ def get_name(self): return afm.AFM(open(filename)).get_familyname() font = fontManager.findfont(self) - return getPropDict(TTFont(six.text_type(font)))['name'] + prop_dict = getPropDict(TTFont(six.text_type(font))) + return prop_dict['name'] def get_style(self): """